diff --git a/.elasticbeanstalk/config.yml b/.elasticbeanstalk/config.default.yml similarity index 55% rename from .elasticbeanstalk/config.yml rename to .elasticbeanstalk/config.default.yml index 8e85b810c8cac3545fb18f80c00e243605f4df3c..3fea7dfdfeeb9b954d2d1cf67f35baedbcf15d42 100644 --- a/.elasticbeanstalk/config.yml +++ b/.elasticbeanstalk/config.default.yml @@ -1,12 +1,9 @@ -branch-defaults: - $GIT_BRANCH: - environment: $EB_ENV +deploy: + artifact: deployment.zip global: - application_name: $EB_APP + application_name: Building Service default_ec2_keyname: EastCoastBPKey - default_platform: arn:aws:elasticbeanstalk:us-east-1::platform/Docker running on 64bit Amazon Linux/2.8.1 + default_platform: arn:aws:elasticbeanstalk:us-east-1::platform/Docker running on + 64bit Amazon Linux/2.8.1 default_region: us-east-1 - profile: null sc: git -deploy: - artifact: deployment.zip diff --git a/.gitignore b/.gitignore index ab3bf836d2b2bf57e11c951baa2585fbe40288ae..7c2649ca46af1797f7e8e8ee97f2b3e787ec7752 100644 --- a/.gitignore +++ b/.gitignore @@ -9,6 +9,7 @@ __pycache__ app/config/*.py !app/config/*.default.py config.json +.elasticbeanstalk/config.yml # PyCharm .idea diff --git a/Dockerfile b/Dockerfile index d607b8fe6bbc31ca7c7019d7813e7ebca0c71ede..6d4f8f3caf31b6f74906f9014103aa57437ab8b2 100644 --- a/Dockerfile +++ b/Dockerfile @@ -1,5 +1,10 @@ FROM ubuntu:18.04 +ARG GITHUB_OAUTH_TOKEN +ARG DOMAIN +ARG NUM_PROCESSES +ARG NUM_THREADS + ENV CODEROOT=/home/docker/code # Log enironment variables. @@ -8,33 +13,26 @@ ENV NGINXREQ=/var/log/app/nginx.req.log ENV UWSGIERR=/var/log/app/uwsgi.err.log ENV UWSGIREQ=/var/log/app/uwsgi.req.log -# Custom environment variables. These change from project to project. -ARG DOMAIN -ENV DOMAIN=${DOMAIN} -ARG NUM_PROCESSES -ENV NUM_PROCESSES=${NUM_PROCESSES} -ARG NUM_THREADS -ENV NUM_THREADS=${NUM_THREADS} - # Install dependencies. -RUN apt-get update && apt-get install -y \ +RUN apt-get -qq update && apt-get install -y \ build-essential \ git \ libssl-dev \ libffi-dev \ nginx \ - python-dev \ + python3-dev \ python3 \ python3-pip \ supervisor \ && rm -rf /var/lib/apt/lists/* -RUN pip3 install uwsgi +RUN pip3 install -q uwsgi COPY ./requirements.txt $CODEROOT/requirements.txt +RUN sed -i "s@git+ssh:\/\/git@git+https:\/\/$GITHUB_OAUTH_TOKEN@" $CODEROOT/requirements.txt # Install application requirements. -RUN pip3 install -r $CODEROOT/requirements.txt +RUN pip3 install -q -r $CODEROOT/requirements.txt # Put the code somewhere. ADD . $CODEROOT/ diff --git a/Dockerrun.aws.json b/Dockerrun.aws.json index e8817f3dabd01777bf3981333327a1312bd34531..125ed54048b15436152b59f06517a74b4db404f7 100644 --- a/Dockerrun.aws.json +++ b/Dockerrun.aws.json @@ -1,9 +1,5 @@ { "AWSEBDockerrunVersion": "1", - "Authentication": { - "Bucket": "dockerauth.blocpower.org", - "Key": "$DOCKER_REPO.json" - }, "Image": { "Name": "blocp/$DOCKER_REPO" }, diff --git a/Jenkinsfile b/Jenkinsfile new file mode 100644 index 0000000000000000000000000000000000000000..027bba66fe3b3ae04679d1c4914915bea88e11d9 --- /dev/null +++ b/Jenkinsfile @@ -0,0 +1,221 @@ +pipeline { + agent any + + environment { + PROJECT = '' // Value from EB_APP -- lowercase and without spaces + DEPLOY_TO = '' // User choice -- see parameters + COMMIT_HASH = '' // Short git commit hash + IMAGE = '' // "PROJECT:COMMIT_HASH" + VERSION = '' // Git version only applies to staging and prod + + EB_APP = '' // Value from .global.application_name in EB_CONFIG + EB_ENV = '' // "PROJECT-DEPLOY_TO" + EB_CONFIG = '.elasticbeanstalk/config.yml' + + NEVER_DEPLOY_ENV = 'none' + + GITHUB_CREDENTIALS = credentials('GITHUB_CREDENTIALS') + GITHUB_OAUTH_TOKEN = "${env.GITHUB_CREDENTIALS_PSW}" + } + + options { + buildDiscarder(logRotator(numToKeepStr: '60')) + } + + parameters { + choice( + name: 'DEPLOY_TO', + choices: 'none\ndev\nstaging\nprod', + description: 'Which environment do you want to deploy to?' + ) + string( + name: 'VERSION', + defaultValue: "none", + description: 'What version do you want to deploy? (Only for staging and prod)' + ) + } + + stages { + stage('Build preparations') { + steps { + sh "cp .elasticbeanstalk/config.default.yml $EB_CONFIG" + + script { + EB_APP = sh( + returnStdout: true, + script: """yq -r '.global.application_name' $EB_CONFIG""" + ).trim() + PROJECT = "${EB_APP.replaceAll("\\s", "").toLowerCase()}" + EB_ENV = "$PROJECT-${params.DEPLOY_TO}" + + if ((params.DEPLOY_TO == 'staging' && params.VERSION != 'none') || params.DEPLOY_TO == 'prod') { + git( + url: "https://${GITHUB_OAUTH_TOKEN}@github.com/Blocp/${PROJECT}.git", + branch: "${BRANCH_NAME}" + ) + gitCommitHash = sh(returnStdout: true, script: "git rev-list -n 1 ${params.VERSION} --").trim() + COMMIT_HASH = gitCommitHash.take(7) + + // set the build display name + currentBuild.displayName = "#${BUILD_ID}-${COMMIT_HASH}-${params.DEPLOY_TO}-${params.VERSION}" + } else { + gitCommitHash = sh(returnStdout: true, script: 'git rev-parse HEAD').trim() + COMMIT_HASH = gitCommitHash.take(7) + + // set the build display name + currentBuild.displayName = "#${BUILD_ID}-${COMMIT_HASH}-${params.DEPLOY_TO}" + } + IMAGE = "$PROJECT:$COMMIT_HASH" + } + + echo "\n==================ENVIRONMENT VARS==================" + echo "Environment selected: ${params.DEPLOY_TO} -- Version: ${params.VERSION}" + echo "Current branch: ${env.GIT_BRANCH}" + echo "PROJECT: ${PROJECT} -- IMAGE: ${IMAGE}" + echo "EB_APP: ${EB_APP} -- EB_ENV: ${EB_ENV}" + echo "====================================================\n" + } + } + + stage('Build') { + when { + expression { params.DEPLOY_TO == 'dev' } + } + + environment { + ECR_CRED = 'ecr:us-east-1:AWS_CREDENTIALS' + + BUILD_ARGS = + "--build-arg DOMAIN=blocpower.io " + + "--build-arg NUM_PROCESSES=4 " + + "--build-arg NUM_THREADS=4 " + + "--build-arg GITHUB_OAUTH_TOKEN=$GITHUB_OAUTH_TOKEN" + } + + steps { + echo 'Building...' + + withCredentials([[ + $class: 'AmazonWebServicesCredentialsBinding', + credentialsId: 'AWS_CREDENTIALS', + accessKeyVariable: 'AWS_ACCESS_KEY_ID', + secretKeyVariable: 'AWS_SECRET_ACCESS_KEY' + ]]) { + + sh("eval \$(aws ecr get-login --no-include-email | sed 's|https://||')") + + script { + docker.build(IMAGE, "$BUILD_ARGS .") + docker.withRegistry("https://${env.ECR_REPO_HOST}", ECR_CRED) { + docker.image(IMAGE).push() + } + } + } + + echo 'Clean up images' + sh "docker rmi $IMAGE" + sh(""" docker rmi "${env.ECR_REPO_HOST}/$IMAGE" """) + } + } + + stage('Test') { + steps { + echo "Testing comming soon" + } + } + + stage('Deploy') { + when { + expression { params.DEPLOY_TO != NEVER_DEPLOY_ENV } + } + + steps { + echo "Starting deployment to $EB_ENV" + + echo "Updating EB dockerrun image name to ${env.ECR_REPO_HOST}/$IMAGE" + sh(""" + jq '.Image.Name = "${env.ECR_REPO_HOST}/$IMAGE"' Dockerrun.aws.json | \ + sponge Dockerrun.aws.json + """) + + sh 'zip -r deployment.zip Dockerrun.aws.json .ebextensions/*' + + withCredentials([[ + $class: 'AmazonWebServicesCredentialsBinding', + credentialsId: 'AWS_CREDENTIALS', + accessKeyVariable: 'AWS_ACCESS_KEY_ID', + secretKeyVariable: 'AWS_SECRET_ACCESS_KEY' + ]]) { + sh "eb use $EB_ENV" + sh "eb deploy $EB_ENV --label HASH:${COMMIT_HASH}-VERSION:${params.VERSION}" + } + + // Update image with environment deployed to + // build( + // job: 'Retag project in ECR', + // parameters: [ + // string(name: 'REPO_NAME', value: "$PROJECT"), + // string(name: 'IMAGE_TAG', value: "$COMMIT_HASH"), + // string(name: 'NEW_IMAGE_TAG', value: "${params.DEPLOY_TO}"), + // ] + // ) + + // script { + // if (params.VERSION != "none") { + // // Update image with version number + // build( + // job: 'Retag project in ECR', + // parameters: [ + // string(name: 'REPO_NAME', value: "$PROJECT"), + // string(name: 'IMAGE_TAG', value: "$COMMIT_HASH"), + // string(name: 'NEW_IMAGE_TAG', value: "${params.VERSION}"), + // ] + // ) + // } + // } + } + } + } + + post { + success { + script { + MESSAGE = "$PROJECT test ran successfully (commit hash: $COMMIT_HASH)" + + if (params.DEPLOY_TO != 'none') { + MESSAGE = "$PROJECT built to ${params.DEPLOY_TO} (version: ${params.VERSION}, commit hash: $COMMIT_HASH)" + } + + slackSend( + color: 'good', + message: "$MESSAGE" + ) + + if (params.DEPLOY_TO == 'prod') { + slackSend( + color: 'good', + channel: '#dev', + message: "New version of $PROJECT (${params.VERSION}) in production (commit hash: $COMMIT_HASH)" + ) + } + } + } + + failure { + script { + MESSAGE = "$PROJECT test or build failed (commit hash: $COMMIT_HASH)" + + if (params.DEPLOY_TO == 'dev') { + MESSAGE = "$PROJECT build or test failed in ${params.DEPLOY_TO} (version: ${params.VERSION}, commit hash: $COMMIT_HASH)" + } else { + MESSAGE = "$PROJECT failed to build to ${params.DEPLOY_TO} (version: ${params.VERSION}, commit hash: $COMMIT_HASH)" + } + + slackSend( + color: 'danger', + message: "$MESSAGE" + ) + } + } + } +} diff --git a/app/__init__.py b/app/__init__.py index 71715dc11cf501b4cdfd070e1af3bde0761f0768..743a630fda73e3832be1fa2d54bd064f0d69c4e6 100644 --- a/app/__init__.py +++ b/app/__init__.py @@ -27,7 +27,7 @@ def create_app(config): app.logger.addHandler(handler) - app.logger.info('Setting up application...') + app.logger.debug('Setting up application...') from . import views views.register(app)