version: 2.1

commands:
  cache_docker_image:
    steps:
      - run:
          name: Save the docker images to a cache
          command: |
            mkdir -p docker-cache
            docker save -o docker-cache/atat.tar atat:latest
            docker save -o docker-cache/builder.tar atat:builder
      - save_cache:
          key: docker-cache-{{ .Branch }}-{{ .Revision }}
          paths:
            - docker-cache
  restore_docker_image:
    steps:
      - restore_cache:
          keys:
            - docker-cache-{{ .Branch }}-{{ .Revision }}
      - run:
          name: Restore Docker image from cache
          command: |
            docker load < docker-cache/atat.tar
            docker load < docker-cache/builder.tar
  setup_datastores:
    parameters:
      pgdatabase:
        type: string
        default: atat_test
      container_env:
        type: string
        default: -e PGHOST=postgres -e REDIS_URI=redis://redis:6379
    steps:
      - run:
          name: Set up temporary docker network
          command: docker network create atat
      - run:
          name: Start redis
          command: docker run -d --network atat --link redis:redis -p 6379:6379 --name redis circleci/redis:4-alpine3.8
      - run:
          name: Start postgres
          command: docker run -d --network atat --link postgres:postgres -p 5432:5432 --name postgres circleci/postgres:10-alpine-ram
      - run:
          name: Wait for containers
          command: sleep 3
      - run:
          name: Create database
          command: "docker exec postgres createdb -U postgres << parameters.pgdatabase >>"
      - run:
          name: Apply migrations
          command: docker run --network atat -e PGDATABASE=<< parameters.pgdatabase >> << parameters.container_env >> atat:builder .venv/bin/python .venv/bin/alembic upgrade head
      - run:
          name: Apply the default permission sets
          command: docker run --network atat -e PGDATABASE=<< parameters.pgdatabase >> << parameters.container_env >> atat:builder .venv/bin/python script/seed_roles.py

  docker-build:
    parameters:
      cdn_url:
        type: string
    steps:
      - checkout
      - setup_remote_docker:
          docker_layer_caching: true
          version: 18.06.0-ce
      - run:
          name: Build image
          command: |
            docker build . --build-arg CSP=azure --build-arg CDN_URL=<< parameters.cdn_url >> -f ./Dockerfile -t atat:builder --target builder
            docker build . --build-arg CSP=azure --build-arg CDN_URL=<< parameters.cdn_url >> -f ./Dockerfile -t atat:latest
      - cache_docker_image

  deploy:
    parameters:
      namespace:
        type: string
        default: atat
      tag:
        type: string
        default: ${AZURE_SERVER_NAME}/atat:latest
    steps:
      - checkout
      - setup_remote_docker:
          docker_layer_caching: true
          version: 18.06.0-ce
      - restore_docker_image
      - run:
          name: Install Azure CLI
          command: |
            apk update
            apk add bash py-pip
            apk add --virtual=build \
              linux-headers gcc libffi-dev musl-dev openssl-dev python-dev make
            pip --no-cache-dir install -U pip
            pip --no-cache-dir install azure-cli
            apk del --purge build
      - run:
          name: Login to Azure CLI
          command: |
            az login \
              --service-principal \
              --tenant $AZURE_SP_TENANT \
              --password $AZURE_SP_PASSWORD \
              --username $AZURE_SP
            echo "Successfully logged in to Azure CLI."
            az acr login --name $AZURE_REGISTRY
      - run:
          name: Install kubectl
          command: |
            apk add curl
            export KUBECTL_VERSION=$(curl -s https://storage.googleapis.com/kubernetes-release/release/stable.txt)
            curl -LO https://storage.googleapis.com/kubernetes-release/release/$KUBECTL_VERSION/bin/linux/amd64/kubectl
            chmod +x ./kubectl
            mv ./kubectl /usr/local/bin
      - run:
          name: Configure kubectl
          command: |
            apk add libssl1.0
            az aks get-credentials --name ${CLUSTER_NAME} --resource-group ${RESOURCE_GROUP}
      - run:
          name: Tag images
          command: |
            docker tag atat:latest << parameters.tag >>
      - run:
          name: Push image
          command: |
            docker push << parameters.tag >>
      - run:
          name: Add gettext package
          command: apk add gettext
      - run:
          command: K8S_NAMESPACE=<< parameters.namespace >> CONTAINER_IMAGE=<< parameters.tag >> /bin/sh ./script/cluster_migration
          name: Apply Migrations and Seed Roles
      - run:
          name: Update Kubernetes cluster
          command: |
            kubectl set image deployment.apps/atst atst=<< parameters.tag >> --namespace=<< parameters.namespace >>
            kubectl set image deployment.apps/atst-worker atst-worker=<< parameters.tag >> --namespace=<< parameters.namespace >>
            kubectl set image deployment.apps/atst-beat atst-beat=<< parameters.tag >> --namespace=<< parameters.namespace >>
            kubectl set image cronjobs.batch/crls crls=<< parameters.tag >> --namespace=<< parameters.namespace >>

jobs:
  docker-build:
    docker:
      - image: docker:18.06.0-ce-git
    steps:
      - checkout
      - setup_remote_docker:
          docker_layer_caching: true
          version: 18.06.0-ce
      - run:
          name: Build image
          command: |
            docker build . --build-arg CSP=azure -f ./Dockerfile -t atat:builder --target builder
            docker build . --build-arg CSP=azure -f ./Dockerfile -t atat:latest
      - cache_docker_image

  test:
    docker:
      - image: docker:18.06.0-ce-git
      - image: circleci/postgres:10-alpine-ram
      - image: circleci/redis:4-alpine3.8
    steps:
      - setup_remote_docker:
          docker_layer_caching: true
          version: 18.06.0-ce
      - restore_docker_image
      - setup_datastores:
          pgdatabase: atat_test
      - run:
          name: Run CI tests
          command: |
            docker run \
              -e PGHOST=postgres \
              -e REDIS_URI=redis://redis:6379 \
              --network atat \
              atat:builder \
              /bin/sh -c "pipenv install --dev && /bin/sh script/cibuild"

  integration-tests:
    docker:
      - image: docker:18.06.0-ce-git
      - image: circleci/postgres:10-alpine-ram
      - image: circleci/redis:4-alpine3.8
    steps:
      - setup_remote_docker:
          docker_layer_caching: true
          version: 18.06.0-ce
      - restore_docker_image
      - setup_datastores:
          pgdatabase: atat
      - run:
          name: Start application container
          command: |
            docker run -d \
            -e DISABLE_CRL_CHECK=true \
            -e PGHOST=postgres \
            -e REDIS_URI=redis://redis:6379 \
            -p 8000:8000 \
            --network atat \
            --name test-atat \
            atat:builder \
            /bin/sh -c "
              echo CLOUD_PROVIDER=mock > .env &&\
              yarn build &&\
              uwsgi \
              --callable app \
              --module app \
              --plugin python3 \
              --virtualenv /install/.venv \
              --http-socket :8000
            "
      - run:
          name: Wait for ATAT container to be available
          command: |
            docker pull curlimages/curl:latest
            docker run --network atat \
              curlimages/curl:latest \
              curl --connect-timeout 3 \
              --max-time 5 \
              --retry 120 \
              --retry-connrefused \
              --retry-delay 1 \
              --retry-max-time 120 \
              test-atat:8000
      - run:
          name: Execute Ghost Inspector test suite
          command: |
            docker pull ghostinspector/test-runner-standalone:latest
            docker run \
              -e NGROK_TOKEN=$NGROK_TOKEN \
              -e GI_API_KEY=$GI_API_KEY \
              -e GI_SUITE=$GI_SUITE \
              -e GI_PARAMS_JSON='{}' \
              -e APP_PORT="test-atat:8000" \
              --network atat \
              ghostinspector/test-runner-standalone:latest

  test-crl-parser:
    docker:
      - image: docker:18.06.0-ce-git
      - image: circleci/postgres:10-alpine-ram
      - image: circleci/redis:4-alpine3.8
    steps:
      - setup_remote_docker:
          docker_layer_caching: true
          version: 18.06.0-ce
      - restore_docker_image
      - setup_datastores:
          pgdatabase: atat_test
      - run:
          name: Sync CRLs and run CRL test
          command: |
            docker run \
              -e PGHOST=postgres \
              -e REDIS_URI=redis://redis:6379 \
              --network atat \
              atat:builder \
              /bin/sh -c "pipenv install --dev && /bin/sh script/sync-crls && pipenv run pytest --no-cov tests/check_crl_parse.py"

  deploy-staging:
    docker:
      - image: docker:18.06.0-ce-git
        environment:
          AZURE_REGISTRY: pwatat
          RESOURCE_GROUP: atat
          CLUSTER_NAME: atat-cluster
    steps:
      - deploy:
          namespace: staging
          tag: ${AZURE_SERVER_NAME}/atat:staging-${CIRCLE_SHA1}

  deploy-master:
    docker:
      - image: docker:18.06.0-ce-git
        environment:
          AZURE_REGISTRY: pwatat
          RESOURCE_GROUP: atat
          CLUSTER_NAME: atat-cluster
    steps:
      - deploy:
          namespace: atat
          tag: ${AZURE_SERVER_NAME}/atat:master-${CIRCLE_SHA1}

workflows:
  version: 2
  run-tests:
    jobs:
      - docker-build
      - test:
          requires:
            - docker-build
      - integration-tests:
          requires:
            - docker-build
      - deploy-staging:
          requires:
            - test
            - integration-tests
          filters:
            branches:
              only:
                - staging
      - deploy-master:
          requires:
            - test
            - integration-tests
          filters:
            branches:
              only:
                - master

  test-crl-parser:
    triggers:
      - schedule:
          cron: "0 4 * * *"
          filters:
            branches:
              only:
                - staging
    jobs:
      - docker-build
      - test-crl-parser:
          requires:
            - docker-build
