From 01cea42a034d3da9541171b52ab742bfdbb6ff3b Mon Sep 17 00:00:00 2001 From: Jelle Besseling Date: Wed, 20 Nov 2019 21:41:38 +0100 Subject: [PATCH] Add review environment --- .gitlab-ci.yml | 109 ++++++++++++++++++ Dockerfile | 1 - docs/utils.management.commands.rst | 8 ++ resources/ec2-bootstrap.sh | 34 ++++++ resources/entrypoint.sh | 13 ++- .../management/commands/createreviewuser.py | 53 +++++++++ 6 files changed, 212 insertions(+), 6 deletions(-) create mode 100644 resources/ec2-bootstrap.sh create mode 100644 website/utils/management/commands/createreviewuser.py diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml index 07c7ed02..b71b18ef 100644 --- a/.gitlab-ci.yml +++ b/.gitlab-ci.yml @@ -199,6 +199,115 @@ build docker image: DOCKER_LATEST: registry.hub.docker.com/thalia/concrexit:latest DOCKER_TAG: registry.hub.docker.com/thalia/concrexit:$CI_COMMIT_SHA +.reviewsetup: + when: manual + image: python:latest + before_script: + - apt-get update + - apt-get install -y jq + - pip install awscli + - >- + instanceids=$( + aws --region eu-west-1 ec2 describe-instances + --filters "Name=tag:Name,Values=concrexit-review-${CI_COMMIT_REF_SLUG}" + | jq --raw-output '.Reservations|map(.Instances[0].InstanceId)|join(" ")' + ) + - aws --region eu-west-1 ec2 terminate-instances --instance-ids ${instanceids} || true + +review: + stage: deploy + environment: + name: review/${CI_COMMIT_REF_NAME} + url: https://${CI_COMMIT_REF_SLUG}.review.technicie.nl/ + on_stop: review remove + extends: .reviewsetup + script: + - username=$(head /dev/urandom | tr -dc 'a-z' | head -c 10) + - password=$(head /dev/urandom | tr -dc 'a-zA-Z' | head -c 32) + - echo -e "When the deployment is done, you can login with:\n$username\n$password" + - >- + sed -i -e "s/@version@/$CI_COMMIT_SHA/g" + -e "s/@username@/$username/g" + -e "s/@password@/$password/g" + ./resources/ec2-bootstrap.sh + - >- + instanceid=$( + aws --region eu-west-1 ec2 run-instances + --count 1 + --instance-type t2.micro + --tag-specifications "ResourceType=instance,Tags=[{Key=Name,Value=concrexit-review-${CI_COMMIT_REF_SLUG}}]" + --launch-template LaunchTemplateId=lt-03762fc23450c2471,Version=1 + --user-data file://resources/ec2-bootstrap.sh + | jq --raw-output '.Instances[0].InstanceId' + ) + - aws --region eu-west-1 ec2 wait instance-running --instance-ids ${instanceid} + - ipaddress=$(aws --region eu-west-1 ec2 describe-instances --instance-ids ${instanceid} | jq --raw-output '.Reservations[0].Instances[0].PublicIpAddress') + - | + cat > add-record.json < change-record.json <- + changeinfoid=$( + ( + aws --region eu-west-1 route53 change-resource-record-sets + --hosted-zone-id Z072013523EW763CDQ8K4 + --change-batch file://add-record.json + || + aws --region eu-west-1 route53 change-resource-record-sets + --hosted-zone-id Z072013523EW763CDQ8K4 + --change-batch file://change-record.json + ) + | jq --raw-output '.ChangeInfo.Id' + ) + - aws --region eu-west-1 route53 wait resource-record-sets-changed --id ${changeinfoid} + +review remove: + stage: deploy + environment: + name: review/${CI_COMMIT_REF_NAME} + action: stop + extends: .reviewsetup + script: + - >- + aws --region eu-west-1 route53 list-resource-record-sets + --hosted-zone-id Z072013523EW763CDQ8K4 + --query "ResourceRecordSets[?Name == '${CI_COMMIT_REF_SLUG}.review.technicie.nl.']" + | + jq '{"Comment": "DELETE review deployment record", "Changes": map({"Action": "DELETE", "ResourceRecordSet": .})}' + > remove-record.json + - aws --region eu-west-1 route53 change-resource-record-sets --hosted-zone-id Z072013523EW763CDQ8K4 --change-batch file://remove-record.json || true + build production docker image: extends: build docker image only: diff --git a/Dockerfile b/Dockerfile index 1d053709..1cfbf7bb 100644 --- a/Dockerfile +++ b/Dockerfile @@ -9,7 +9,6 @@ ARG source_commit="unknown" # Try to keep static operation on top to maximise Docker cache utilisation # Disable output buffering -ENV DJANGO_PRODUCTION 1 ENV PYTHONUNBUFFERED 1 ENV DEBIAN_FRONTEND=noninteractive ENV SOURCE_COMMIT=${source_commit} diff --git a/docs/utils.management.commands.rst b/docs/utils.management.commands.rst index 64071271..633830a6 100644 --- a/docs/utils.management.commands.rst +++ b/docs/utils.management.commands.rst @@ -17,3 +17,11 @@ utils.management.commands.createfixtures module :undoc-members: :show-inheritance: +utils.management.commands.createreviewuser module +------------------------------------------------- + +.. automodule:: utils.management.commands.createreviewuser + :members: + :undoc-members: + :show-inheritance: + diff --git a/resources/ec2-bootstrap.sh b/resources/ec2-bootstrap.sh new file mode 100644 index 00000000..80838f8f --- /dev/null +++ b/resources/ec2-bootstrap.sh @@ -0,0 +1,34 @@ +#!/bin/sh + +# From https://docs.docker.com/install/linux/docker-ce/ubuntu/ +apt-get update +apt-get install -y apt-transport-https ca-certificates curl gnupg-agent software-properties-common +curl -fsSL https://download.docker.com/linux/ubuntu/gpg | apt-key add - +add-apt-repository "deb [arch=amd64] https://download.docker.com/linux/ubuntu bionic stable" +apt-get update +apt-get -y install docker-ce docker-ce-cli containerd.io + +docker volume create concrexit_data +docker run --name concrexit_migrate \ + --rm \ + --mount source=concrexit_data,target=/usr/src/app/website/ \ + thalia/concrexit:@version@ migrate + +docker run --name concrexit_superuser \ + --rm \ + --mount source=concrexit_data,target=/usr/src/app/website/ \ + thalia/concrexit:@version@ createreviewuser \ + --username @username@ --password @password@ + +docker run --name concrexit_fixtures \ + --rm \ + --mount source=concrexit_data,target=/usr/src/app/website/ \ + thalia/concrexit:@version@ createfixtures -a + +docker run --name concrexit_web \ + --detach \ + --publish 0.0.0.0:80:80 \ + --mount source=concrexit_data,target=/usr/src/app/website/ \ + thalia/concrexit:@version@ runserver 0.0.0.0:80 + +echo "shutdown now" | at now +2 days diff --git a/resources/entrypoint.sh b/resources/entrypoint.sh index a2f41172..d51cb7cd 100755 --- a/resources/entrypoint.sh +++ b/resources/entrypoint.sh @@ -2,11 +2,14 @@ set -e -until psql -h "$DJANGO_POSTGRES_HOST" -U "postgres" -c '\l'; do - >&2 echo "PostgreSQL is unavailable: Sleeping" - sleep 5 -done ->&2 echo "PostgreSQL is up" +if [[ ! -z "$DJANGO_POSTGRES_HOST" ]]; then + until psql -h "$DJANGO_POSTGRES_HOST" -U "postgres" -c '\l'; do + >&2 echo "PostgreSQL is unavailable: Sleeping" + sleep 5 + done + >&2 echo "PostgreSQL is up" +fi + cd /usr/src/app/website/ >&2 echo "Running ./manage.py $@" diff --git a/website/utils/management/commands/createreviewuser.py b/website/utils/management/commands/createreviewuser.py new file mode 100644 index 00000000..bb852b45 --- /dev/null +++ b/website/utils/management/commands/createreviewuser.py @@ -0,0 +1,53 @@ +import logging + +from django.conf import settings +from django.contrib.auth import get_user_model +from django.core.management import BaseCommand + +try: + from faker import Factory as FakerFactory +except ImportError as error: + raise Exception("Have you installed the dev-requirements? " + "Failed importing {}".format(error)) from error + +_faker = FakerFactory.create('nl_NL') +logger = logging.getLogger(__name__) + + +class Command(BaseCommand): + """Command to create a user we can use to review""" + help = "Creates a user for the a review environment" + + def add_arguments(self, parser): + parser.add_argument( + '--username', dest='username', default=None, + help='Specifies the username for the user.', + ) + parser.add_argument( + '--password', dest='password', default=None, + help='Specifies the password for the user.', + ) + + def handle(self, *args, **options): + if not settings.DEBUG: + logger.info('Cannot create review user in production mode') + return + + username = options.get('username') + password = options.get('password') + + if username is None: + username = _faker.user_name() + if password is None: + password = get_user_model().objects.make_random_password(length=15) + + get_user_model().objects.create_superuser( + username=username, + email=f'{username}@example.com', + password=password, + first_name='Riley', + last_name='Review' + ) + + logger.info(f'Username: {username}') + logger.info(f'Password: {password}') -- GitLab