From 7ca46c524e0f10ff4b3d0e5ce7d1d0a093600278 Mon Sep 17 00:00:00 2001 From: elosoman Date: Wed, 22 Jun 2016 09:40:52 -0400 Subject: [PATCH 1/8] Created rhel version of tasks --- lib/taskLists/rhel.js | 192 ++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 192 insertions(+) create mode 100644 lib/taskLists/rhel.js diff --git a/lib/taskLists/rhel.js b/lib/taskLists/rhel.js new file mode 100644 index 0000000..27dbf83 --- /dev/null +++ b/lib/taskLists/rhel.js @@ -0,0 +1,192 @@ +var nodemiral = require('nodemiral'); +var fs = require('fs'); +var path = require('path'); +var util = require('util'); +var _ = require('underscore'); + +var SCRIPT_DIR = path.resolve(__dirname, '../../scripts/linux'); +var TEMPLATES_DIR = path.resolve(__dirname, '../../templates/linux'); + +exports.setup = function(config) { + var taskList = nodemiral.taskList('Setup (linux)'); + + taskList.executeScript('Installing Docker', { + script: path.resolve(SCRIPT_DIR, 'install-docker.sh') + }); + + taskList.executeScript('Setting up Environment', { + script: path.resolve(SCRIPT_DIR, 'setup-env.sh'), + vars: { + appName: config.appName + } + }); + + if (config.setupMongo) { + taskList.copy('Copying MongoDB configuration', { + src: path.resolve(TEMPLATES_DIR, 'mongodb.conf'), + dest: '/opt/mongodb/mongodb.conf' + }); + + taskList.executeScript('Installing MongoDB', { + script: path.resolve(SCRIPT_DIR, 'install-mongodb.sh') + }); + } + + if (config.ssl) { + taskList.copy('Copying SSL certificate bundle', { + src: config.ssl.certificate, + dest: '/opt/' + config.appName + '/config/bundle.crt' + }); + + taskList.copy('Copying SSL private key', { + src: config.ssl.key, + dest: '/opt/' + config.appName + '/config/private.key' + }); + + taskList.executeScript('Verifying SSL configurations', { + script: path.resolve(SCRIPT_DIR, 'verify-ssl-configurations.sh'), + vars: { + appName: config.appName + } + }); + } + + return taskList; +}; + +exports.deploy = function(bundlePath, env, config) { + var deployCheckWaitTime = config.deployCheckWaitTime; + var appName = config.appName; + var taskList = nodemiral.taskList("Deploy app '" + appName + "' (linux)"); + + taskList.copy('Uploading bundle', { + src: bundlePath, + dest: '/opt/' + appName + '/tmp/bundle.tar.gz', + progressBar: config.enableUploadProgressBar + }); + + copyEnvVars(taskList, env, appName); + + taskList.copy('Initializing start script', { + src: path.resolve(TEMPLATES_DIR, 'start.sh'), + dest: '/opt/' + appName + '/config/start.sh', + vars: { + appName: appName, + useLocalMongo: config.setupMongo, + port: env.PORT, + sslConfig: config.ssl + } + }); + + deployAndVerify(taskList, appName, env.PORT, deployCheckWaitTime); + + return taskList; +}; + +exports.reconfig = function(env, config) { + var appName = config.appName; + var deployCheckWaitTime = config.deployCheckWaitTime; + + var taskList = nodemiral.taskList("Updating configurations (linux)"); + + copyEnvVars(taskList, env, appName); + startAndVerify(taskList, appName, env.PORT, deployCheckWaitTime); + + return taskList; +}; + +exports.restart = function(config) { + var taskList = nodemiral.taskList("Restarting Application (linux)"); + + var appName = config.appName; + var port = config.env.PORT; + var deployCheckWaitTime = config.deployCheckWaitTime; + + startAndVerify(taskList, appName, port, deployCheckWaitTime); + + return taskList; +}; + +exports.stop = function(config) { + var taskList = nodemiral.taskList("Stopping Application (linux)"); + + //stopping + taskList.executeScript('Stopping app', { + script: path.resolve(SCRIPT_DIR, 'stop.sh'), + vars: { + appName: config.appName + } + }); + + return taskList; +}; + +exports.start = function(config) { + var taskList = nodemiral.taskList("Starting Application (linux)"); + + var appName = config.appName; + var port = config.env.PORT; + var deployCheckWaitTime = config.deployCheckWaitTime; + + startAndVerify(taskList, appName, port, deployCheckWaitTime); + + return taskList; +}; + +function installStud(taskList) { + taskList.executeScript('Installing Stud', { + script: path.resolve(SCRIPT_DIR, 'install-stud.sh') + }); +} + +function copyEnvVars(taskList, env, appName) { + var env = _.clone(env); + // sending PORT to the docker container is useless. + // It'll run on PORT 80 and we can't override it + // Changing the port is done via the start.sh script + delete env.PORT; + taskList.copy('Sending environment variables', { + src: path.resolve(TEMPLATES_DIR, 'env.list'), + dest: '/opt/' + appName + '/config/env.list', + vars: { + env: env || {}, + appName: appName + } + }); +} + +function startAndVerify(taskList, appName, port, deployCheckWaitTime) { + taskList.execute('Starting app', { + command: "bash /opt/" + appName + "/config/start.sh" + }); + + // verifying deployment + taskList.executeScript('Verifying deployment', { + script: path.resolve(SCRIPT_DIR, 'verify-deployment.sh'), + vars: { + deployCheckWaitTime: deployCheckWaitTime || 10, + appName: appName, + port: port + } + }); +} + +function deployAndVerify(taskList, appName, port, deployCheckWaitTime) { + // deploying + taskList.executeScript('Invoking deployment process', { + script: path.resolve(SCRIPT_DIR, 'deploy.sh'), + vars: { + appName: appName + } + }); + + // verifying deployment + taskList.executeScript('Verifying deployment', { + script: path.resolve(SCRIPT_DIR, 'verify-deployment.sh'), + vars: { + deployCheckWaitTime: deployCheckWaitTime || 10, + appName: appName, + port: port + } + }); +} From 476a694dd3e87dcab0d8503f24eda7dbba0d0bfe Mon Sep 17 00:00:00 2001 From: benjamin Date: Wed, 22 Jun 2016 11:49:40 -0400 Subject: [PATCH 2/8] Initial commit of RHEL support files --- README.md | 4 ++ lib/taskLists/rhel.js | 14 +++--- scripts/rhel/deploy.sh | 56 ++++++++++++++++++++++++ scripts/rhel/install-docker.sh | 11 +++++ scripts/rhel/install-mongodb.sh | 20 +++++++++ scripts/rhel/setup-env.sh | 11 +++++ scripts/rhel/stop.sh | 4 ++ scripts/rhel/verify-deployment.sh | 35 +++++++++++++++ scripts/rhel/verify-ssl-configuration.sh | 21 +++++++++ 9 files changed, 169 insertions(+), 7 deletions(-) create mode 100644 scripts/rhel/deploy.sh create mode 100644 scripts/rhel/install-docker.sh create mode 100644 scripts/rhel/install-mongodb.sh create mode 100644 scripts/rhel/setup-env.sh create mode 100644 scripts/rhel/stop.sh create mode 100644 scripts/rhel/verify-deployment.sh create mode 100644 scripts/rhel/verify-ssl-configuration.sh diff --git a/README.md b/README.md index 834dc77..a668e43 100644 --- a/README.md +++ b/README.md @@ -161,6 +161,10 @@ When building the meteor app, we can invoke few options. So, you can mention the ### Additional Setup/Deploy Information +#### RHEL Support + +Set the os attribute of the server to 'rhel' to handel special conditions on RHEL7. + #### Deploy Wait Time Meteor Up checks if the deployment is successful or not just after the deployment. By default, it will wait 15 seconds before the check. You can configure the wait time with the `deployCheckWaitTime` option in the `mup.json` diff --git a/lib/taskLists/rhel.js b/lib/taskLists/rhel.js index 27dbf83..175c2b5 100644 --- a/lib/taskLists/rhel.js +++ b/lib/taskLists/rhel.js @@ -4,11 +4,11 @@ var path = require('path'); var util = require('util'); var _ = require('underscore'); -var SCRIPT_DIR = path.resolve(__dirname, '../../scripts/linux'); +var SCRIPT_DIR = path.resolve(__dirname, '../../scripts/rhel'); var TEMPLATES_DIR = path.resolve(__dirname, '../../templates/linux'); exports.setup = function(config) { - var taskList = nodemiral.taskList('Setup (linux)'); + var taskList = nodemiral.taskList('Setup (rhel)'); taskList.executeScript('Installing Docker', { script: path.resolve(SCRIPT_DIR, 'install-docker.sh') @@ -57,7 +57,7 @@ exports.setup = function(config) { exports.deploy = function(bundlePath, env, config) { var deployCheckWaitTime = config.deployCheckWaitTime; var appName = config.appName; - var taskList = nodemiral.taskList("Deploy app '" + appName + "' (linux)"); + var taskList = nodemiral.taskList("Deploy app '" + appName + "' (rhel)"); taskList.copy('Uploading bundle', { src: bundlePath, @@ -87,7 +87,7 @@ exports.reconfig = function(env, config) { var appName = config.appName; var deployCheckWaitTime = config.deployCheckWaitTime; - var taskList = nodemiral.taskList("Updating configurations (linux)"); + var taskList = nodemiral.taskList("Updating configurations (rhel)"); copyEnvVars(taskList, env, appName); startAndVerify(taskList, appName, env.PORT, deployCheckWaitTime); @@ -96,7 +96,7 @@ exports.reconfig = function(env, config) { }; exports.restart = function(config) { - var taskList = nodemiral.taskList("Restarting Application (linux)"); + var taskList = nodemiral.taskList("Restarting Application (rhel)"); var appName = config.appName; var port = config.env.PORT; @@ -108,7 +108,7 @@ exports.restart = function(config) { }; exports.stop = function(config) { - var taskList = nodemiral.taskList("Stopping Application (linux)"); + var taskList = nodemiral.taskList("Stopping Application (rhel)"); //stopping taskList.executeScript('Stopping app', { @@ -122,7 +122,7 @@ exports.stop = function(config) { }; exports.start = function(config) { - var taskList = nodemiral.taskList("Starting Application (linux)"); + var taskList = nodemiral.taskList("Starting Application (rhel)"); var appName = config.appName; var port = config.env.PORT; diff --git a/scripts/rhel/deploy.sh b/scripts/rhel/deploy.sh new file mode 100644 index 0000000..12dd110 --- /dev/null +++ b/scripts/rhel/deploy.sh @@ -0,0 +1,56 @@ +#!/bin/bash + +revert_app (){ + if [[ -d old_app ]]; then + sudo rm -rf app + sudo mv old_app app + sudo stop <%= appName %> || : + sudo start <%= appName %> || : + + echo "Latest deployment failed! Reverted back to the previous version." 1>&2 + exit 1 + else + echo "App did not pick up! Please check app logs." 1>&2 + exit 1 + fi +} + +set -e + +APP_DIR=/opt/<%=appName %> + +# save the last known version +cd $APP_DIR +if [[ -d current ]]; then + sudo rm -rf last + sudo mv current last +fi + +# setup the new version +sudo mkdir current +sudo cp tmp/bundle.tar.gz current/ + +# We temporarly stopped the binary building +# Instead we are building for linux 64 from locally +# That's just like what meteor do +# We can have option to turn binary building later on, +# but not now + +# # rebuild binary module +# cd current +# sudo tar xzf bundle.tar.gz + +# docker run \ +# --rm \ +# --volume=$APP_DIR/current/bundle/programs/server:/bundle \ +# --entrypoint="/bin/bash" \ +# meteorhacks/meteord:binbuild -c \ +# "cd /bundle && bash /opt/meteord/rebuild_npm_modules.sh" + +# sudo rm bundle.tar.gz +# sudo tar czf bundle.tar.gz bundle +# sudo rm -rf bundle +# cd .. + +# start app +sudo bash config/start.sh \ No newline at end of file diff --git a/scripts/rhel/install-docker.sh b/scripts/rhel/install-docker.sh new file mode 100644 index 0000000..d8cfdf5 --- /dev/null +++ b/scripts/rhel/install-docker.sh @@ -0,0 +1,11 @@ +#!/bin/bash + +# docker rhel install info +# https://docs.docker.com/engine/installation/linux/rhel/ + +# Required to update system +sudo yum update -y + +# Install docker +sudo yum install docker-engine -y +sudo service docker start diff --git a/scripts/rhel/install-mongodb.sh b/scripts/rhel/install-mongodb.sh new file mode 100644 index 0000000..a7ca03f --- /dev/null +++ b/scripts/rhel/install-mongodb.sh @@ -0,0 +1,20 @@ +#!/bin/bash + +set -e +# we use this data directory for the backward compatibility +# older mup uses mongodb from apt-get and they used this data directory +sudo mkdir -p /var/lib/mongodb + +sudo docker pull mongo:latest +set +e +sudo docker rm -f mongodb +set -e + +sudo docker run \ + -d \ + --restart=always \ + --publish=127.0.0.1:27017:27017 \ + --volume=/var/lib/mongodb:/data/db \ + --volume=/opt/mongodb/mongodb.conf:/mongodb.conf \ + --name=mongodb \ + mongo mongod -f /mongodb.conf \ No newline at end of file diff --git a/scripts/rhel/setup-env.sh b/scripts/rhel/setup-env.sh new file mode 100644 index 0000000..d897ada --- /dev/null +++ b/scripts/rhel/setup-env.sh @@ -0,0 +1,11 @@ +#!/bin/bash + +sudo mkdir -p /opt/<%= appName %>/ +sudo mkdir -p /opt/<%= appName %>/config +sudo mkdir -p /opt/<%= appName %>/tmp +sudo mkdir -p /opt/mongodb + +sudo chown ${USER} /opt/<%= appName %> -R +sudo chown ${USER} /opt/mongodb -R + +sudo usermod -a -G docker ${USER} diff --git a/scripts/rhel/stop.sh b/scripts/rhel/stop.sh new file mode 100644 index 0000000..5d9e9b8 --- /dev/null +++ b/scripts/rhel/stop.sh @@ -0,0 +1,4 @@ +APPNAME=<%= appName %> + +sudo docker rm -f $APPNAME || : +sudo docker rm -f $APPNAME-frontend || : \ No newline at end of file diff --git a/scripts/rhel/verify-deployment.sh b/scripts/rhel/verify-deployment.sh new file mode 100644 index 0000000..95a24b7 --- /dev/null +++ b/scripts/rhel/verify-deployment.sh @@ -0,0 +1,35 @@ +PORT=<%= port %> +APPNAME=<%= appName %> +APP_PATH=/opt/$APPNAME +START_SCRIPT=$APP_PATH/config/start.sh +DEPLOY_CHECK_WAIT_TIME=<%= deployCheckWaitTime %> + +cd $APP_PATH + +revert_app (){ + docker logs --tail=50 $APPNAME 1>&2 + if [ -d last ]; then + sudo mv last current + sudo bash $START_SCRIPT > /dev/null 2>&1 + + echo " " 1>&2 + echo "=> Redeploying previous version of the app" 1>&2 + echo " " 1>&2 + fi + + echo + echo "To see more logs type 'mup logs --tail=50'" + echo "" +} + +elaspsed=0 +while [[ true ]]; do + sleep 1 + elaspsed=$((elaspsed+1)) + curl localhost:$PORT && exit 0 + + if [ "$elaspsed" == "$DEPLOY_CHECK_WAIT_TIME" ]; then + revert_app + exit 1 + fi +done \ No newline at end of file diff --git a/scripts/rhel/verify-ssl-configuration.sh b/scripts/rhel/verify-ssl-configuration.sh new file mode 100644 index 0000000..54b2faa --- /dev/null +++ b/scripts/rhel/verify-ssl-configuration.sh @@ -0,0 +1,21 @@ +APPNAME=<%= appName %> +DUMMY_SERVER_NAME=$APPNAME-dummy-http-server-for-ssl-check + +sudo docker run \ + -d \ + --name $DUMMY_SERVER_NAME \ + --expose=80 \ + debian /bin/bash -c "while [[ true ]]; do sleep 1; done" + +sleep 3 + +set -e + +sudo docker run \ + --rm \ + --link=$DUMMY_SERVER_NAME:backend \ + --volume=/opt/$APPNAME/config/bundle.crt:/bundle.crt \ + --volume=/opt/$APPNAME/config/private.key:/private.key \ + meteorhacks/mup-frontend-server /verify.sh + +sudo docker rm -f $DUMMY_SERVER_NAME \ No newline at end of file From be57cd879855e941b32bed969fb375c887cf72fc Mon Sep 17 00:00:00 2001 From: benjamin Date: Wed, 22 Jun 2016 12:15:24 -0400 Subject: [PATCH 3/8] rhel does not require sudo to pull, stop, rm, or run --- scripts/rhel/install-mongodb.sh | 12 +++++------- 1 file changed, 5 insertions(+), 7 deletions(-) diff --git a/scripts/rhel/install-mongodb.sh b/scripts/rhel/install-mongodb.sh index a7ca03f..104568d 100644 --- a/scripts/rhel/install-mongodb.sh +++ b/scripts/rhel/install-mongodb.sh @@ -5,16 +5,14 @@ set -e # older mup uses mongodb from apt-get and they used this data directory sudo mkdir -p /var/lib/mongodb -sudo docker pull mongo:latest -set +e -sudo docker rm -f mongodb -set -e - -sudo docker run \ +docker pull mongo:latest +docker stop mongodb +docker rm -f mongodb +docker run \ -d \ --restart=always \ --publish=127.0.0.1:27017:27017 \ --volume=/var/lib/mongodb:/data/db \ --volume=/opt/mongodb/mongodb.conf:/mongodb.conf \ --name=mongodb \ - mongo mongod -f /mongodb.conf \ No newline at end of file + mongo mongod -f /mongodb.conf From 2791278d9eb4321fd6b12c9c4970065406892be8 Mon Sep 17 00:00:00 2001 From: benjamin Date: Wed, 22 Jun 2016 13:48:57 -0400 Subject: [PATCH 4/8] fix to install-mongodb when docker image exists. --- scripts/rhel/install-mongodb.sh | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) diff --git a/scripts/rhel/install-mongodb.sh b/scripts/rhel/install-mongodb.sh index 104568d..377b98f 100644 --- a/scripts/rhel/install-mongodb.sh +++ b/scripts/rhel/install-mongodb.sh @@ -5,9 +5,16 @@ set -e # older mup uses mongodb from apt-get and they used this data directory sudo mkdir -p /var/lib/mongodb +# refresh mongo docker image docker pull mongo:latest -docker stop mongodb -docker rm -f mongodb + +# remove mongodb docker image if it is present +if docker ps | grep mongodb; then + docker rm -f mongodb +fi + +# setup mongodb image for local access +# /var/lib/mongodb is preserved docker run \ -d \ --restart=always \ From 35fd95e90cd3f135575534511abdd4c14832ba1b Mon Sep 17 00:00:00 2001 From: benjamin Date: Wed, 22 Jun 2016 13:49:07 -0400 Subject: [PATCH 5/8] update to rhel support in readme --- README.md | 15 ++++++++++++++- 1 file changed, 14 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index a668e43..86fa1fb 100644 --- a/README.md +++ b/README.md @@ -163,7 +163,20 @@ When building the meteor app, we can invoke few options. So, you can mention the #### RHEL Support -Set the os attribute of the server to 'rhel' to handel special conditions on RHEL7. +By default RHEL7 disables requiretty. This presents an issue when mupx attempts to connect and do it business. Comment out Defaults !requiretty by the 'sudo visudo' command. This may be an issue with how mupx utilizes ssh. See code block below from visudo. + +~~~txt +... +# +# Disable "ssh hostname sudo ", because it will show the password in clear. +# You have to run "ssh -t hostname sudo ". +# +#Defaults requiretty +... +~~~ + +Set the 'os' attribute of the server to 'rhel' to handel special conditions on RHEL7. + #### Deploy Wait Time From e5186636a238fd547ab701f54af3900568283fa1 Mon Sep 17 00:00:00 2001 From: benjamin Date: Wed, 22 Jun 2016 13:49:07 -0400 Subject: [PATCH 6/8] update to rhel support in readme --- README.md | 22 +++++++++++++++++++++- 1 file changed, 21 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index a668e43..79e0c52 100644 --- a/README.md +++ b/README.md @@ -163,7 +163,27 @@ When building the meteor app, we can invoke few options. So, you can mention the #### RHEL Support -Set the os attribute of the server to 'rhel' to handel special conditions on RHEL7. +To install on RHEL7 (tested only on RHEL7 but may work for RHELx and/or CentOS). In addition to the sudoer changes discussed previously there may be an additional sudoer config change. + +##### Server + +The version of RHEL7 used for testing disables requiretty. This presents an issue when mupx attempts to connect and do it business. This is generally enforced by having Defaults requiretty in the /etc/sudoers. RedHat just recently removed this from Fedora and REHL, see Bug 1020147 + +Comment out 'Defaults !requiretty' using visudo. This may also be an issue with how mupx utilizes ssh. See code block below from visudo. + +~~~txt +... +# +# Disable "ssh hostname sudo ", because it will show the password in clear. +# You have to run "ssh -t hostname sudo ". +# +#Defaults requiretty +... +~~~ + +##### mup.json +Set the 'os' attribute of the server to 'rhel' to handel special conditions on RHEL7. + #### Deploy Wait Time From 0c427ddd7fe13e8101f99c0c50fe8073b24514ca Mon Sep 17 00:00:00 2001 From: elosoman Date: Thu, 23 Jun 2016 09:50:55 -0400 Subject: [PATCH 7/8] Update README.md --- README.md | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index 79e0c52..2a79092 100644 --- a/README.md +++ b/README.md @@ -21,6 +21,7 @@ This version of Meteor Up is powered by [Docker](http://www.docker.com/) and it - [Deploying an App](#deploying-an-app) - [Build Options](#build-options) - [Additional Setup/Deploy Information](#additional-setupdeploy-information) + - [RHEL Support](#rhel-support) - [Server Setup Details](#server-setup-details) - [Deploy Wait Time](#deploy-wait-time) - [Multiple Deployment Targets](#multiple-deployment-targets) @@ -182,7 +183,7 @@ Comment out 'Defaults !requiretty' using visudo. This may also be an issue with ~~~ ##### mup.json -Set the 'os' attribute of the server to 'rhel' to handel special conditions on RHEL7. +Identify the server os as RedHat by setting the 'os' attribute to 'rhel'. #### Deploy Wait Time From 69f771221d1bfc922f39dc61b3c50bdf92cd7d23 Mon Sep 17 00:00:00 2001 From: benjamin Date: Thu, 23 Jun 2016 11:29:06 -0400 Subject: [PATCH 8/8] revert to prior error handeling for docker rm mongodb --- scripts/rhel/install-mongodb.sh | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/scripts/rhel/install-mongodb.sh b/scripts/rhel/install-mongodb.sh index 377b98f..2bd2311 100644 --- a/scripts/rhel/install-mongodb.sh +++ b/scripts/rhel/install-mongodb.sh @@ -9,9 +9,9 @@ sudo mkdir -p /var/lib/mongodb docker pull mongo:latest # remove mongodb docker image if it is present -if docker ps | grep mongodb; then - docker rm -f mongodb -fi +set +e +docker rm -f mongodb +set -e # setup mongodb image for local access # /var/lib/mongodb is preserved