Auto-DevOps.gitlab-ci.yml 24.6 KB
Newer Older
1 2 3 4 5 6 7 8 9
# Auto DevOps
# This CI/CD configuration provides a standard pipeline for
# * building a Docker image (using a buildpack if necessary),
# * storing the image in the container registry,
# * running tests from a buildpack,
# * running code quality analysis,
# * creating a review app for each topic branch,
# * and continuous deployment to production
#
10 11 12
# Test jobs may be disabled by setting environment variables:
# * test: TEST_DISABLED
# * code_quality: CODE_QUALITY_DISABLED
13
# * license_management: LICENSE_MANAGEMENT_DISABLED
14 15 16 17 18 19 20 21
# * performance: PERFORMANCE_DISABLED
# * sast: SAST_DISABLED
# * dependency_scanning: DEPENDENCY_SCANNING_DISABLED
# * container_scanning: CONTAINER_SCANNING_DISABLED
# * dast: DAST_DISABLED
# * review: REVIEW_DISABLED
# * stop_review: REVIEW_DISABLED
#
22 23 24 25 26
# In order to deploy, you must have a Kubernetes cluster configured either
# via a project integration, or via group/project variables.
# AUTO_DEVOPS_DOMAIN must also be set as a variable at the group or project
# level, or manually added below.
#
27
# Continuous deployment to production is enabled by default.
28 29
# If you want to deploy to staging first, set STAGING_ENABLED environment variable.
# If you want to enable incremental rollout, either manual or time based,
30
# set INCREMENTAL_ROLLOUT_MODE environment variable to "manual" or "timed".
31
# If you want to use canary deployments, set CANARY_ENABLED environment variable.
32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51
#
# If Auto DevOps fails to detect the proper buildpack, or if you want to
# specify a custom buildpack, set a project variable `BUILDPACK_URL` to the
# repository URL of the buildpack.
# e.g. BUILDPACK_URL=https://github.com/heroku/heroku-buildpack-ruby.git#v142
# If you need multiple buildpacks, add a file to your project called
# `.buildpacks` that contains the URLs, one on each line, in order.
# Note: Auto CI does not work with multiple buildpacks yet

image: alpine:latest

variables:
  # AUTO_DEVOPS_DOMAIN is the application deployment domain and should be set as a variable at the group or project level.
  # AUTO_DEVOPS_DOMAIN: domain.example.com

  POSTGRES_USER: user
  POSTGRES_PASSWORD: testing-password
  POSTGRES_ENABLED: "true"
  POSTGRES_DB: $CI_ENVIRONMENT_SLUG

52
  KUBERNETES_VERSION: 1.10.9
53
  HELM_VERSION: 2.11.0
54

55 56
  DOCKER_DRIVER: overlay2

57 58 59 60
stages:
  - build
  - test
  - review
61
  - dast
62 63 64
  - staging
  - canary
  - production
65 66 67 68
  - incremental rollout 10%
  - incremental rollout 25%
  - incremental rollout 50%
  - incremental rollout 100%
69
  - performance
70 71 72 73
  - cleanup

build:
  stage: build
74
  image: docker:stable-git
75
  services:
76
  - docker:stable-dind
77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95
  script:
    - setup_docker
    - build
  only:
    - branches

test:
  services:
    - postgres:latest
  variables:
    POSTGRES_DB: test
  stage: test
  image: gliderlabs/herokuish:latest
  script:
    - setup_test_db
    - cp -R . /tmp/app
    - /bin/herokuish buildpack test
  only:
    - branches
96 97 98
  except:
    variables:
      - $TEST_DISABLED
99

100
code_quality:
101
  stage: test
102
  image: docker:stable
103 104
  allow_failure: true
  services:
105
    - docker:stable-dind
106 107
  script:
    - setup_docker
108
    - code_quality
109
  artifacts:
110
    paths: [gl-code-quality-report.json]
111 112
  only:
    - branches
113 114 115
  except:
    variables:
      - $CODE_QUALITY_DISABLED
116

117
license_management:
118
  stage: test
119 120 121
  image: 
    name: "registry.gitlab.com/gitlab-org/security-products/license-management:$CI_SERVER_VERSION_MAJOR-$CI_SERVER_VERSION_MINOR-stable"
    entrypoint: [""]
122 123 124 125 126
  allow_failure: true
  script:
    - license_management
  artifacts:
    paths: [gl-license-management-report.json]
127
  only:
128 129
    refs:
      - branches
130 131
    variables:
      - $GITLAB_FEATURES =~ /\blicense_management\b/
132 133 134 135
  except:
    variables:
      - $LICENSE_MANAGEMENT_DISABLED

136 137
performance:
  stage: performance
138
  image: docker:stable
139 140
  allow_failure: true
  services:
141
    - docker:stable-dind
142
  script:
143
    - setup_docker
144 145 146 147
    - performance
  artifacts:
    paths:
    - performance.json
148
    - sitespeed-results/
149 150 151
  only:
    refs:
      - branches
152
    kubernetes: active
153 154 155
  except:
    variables:
      - $PERFORMANCE_DISABLED
156

157
sast:
158
  stage: test
159
  image: docker:stable
160
  allow_failure: true
161
  services:
162
    - docker:stable-dind
163
  script:
164 165
    - setup_docker
    - sast
166
  artifacts:
167 168
    reports:
      sast: gl-sast-report.json
169
  only:
170 171 172 173
    refs:
      - branches
    variables:
      - $GITLAB_FEATURES =~ /\bsast\b/
174 175 176
  except:
    variables:
      - $SAST_DISABLED
177

178
dependency_scanning:
179
  stage: test
180 181 182 183 184 185 186 187 188
  image: docker:stable
  allow_failure: true
  services:
    - docker:stable-dind
  script:
    - setup_docker
    - dependency_scanning
  artifacts:
    paths: [gl-dependency-scanning-report.json]
189
  only:
190 191 192 193
    refs:
      - branches
    variables:
      - $GITLAB_FEATURES =~ /\bdependency_scanning\b/
194 195 196
  except:
    variables:
      - $DEPENDENCY_SCANNING_DISABLED
197

198
container_scanning:
199
  stage: test
200
  image: docker:stable
Luke Bennett's avatar
Luke Bennett committed
201 202
  allow_failure: true
  services:
203
    - docker:stable-dind
Luke Bennett's avatar
Luke Bennett committed
204 205
  script:
    - setup_docker
206
    - container_scanning
Luke Bennett's avatar
Luke Bennett committed
207
  artifacts:
208
    paths: [gl-container-scanning-report.json]
209
  only:
210 211 212
    refs:
      - branches
    variables:
213
      - $GITLAB_FEATURES =~ /\bcontainer_scanning\b/
214 215 216
  except:
    variables:
      - $CONTAINER_SCANNING_DISABLED
217

218 219 220
dast:
  stage: dast
  allow_failure: true
221
  image: registry.gitlab.com/gitlab-org/security-products/zaproxy
222 223 224 225 226 227 228 229 230
  variables:
    POSTGRES_DB: "false"
  script:
    - dast
  artifacts:
    paths: [gl-dast-report.json]
  only:
    refs:
      - branches
231
    kubernetes: active
232 233
    variables:
      - $GITLAB_FEATURES =~ /\bdast\b/
234
  except:
235 236 237 238
    refs:
      - master
    variables:
      - $DAST_DISABLED
239

240 241 242 243 244 245 246
review:
  stage: review
  script:
    - check_kube_domain
    - install_dependencies
    - download_chart
    - ensure_namespace
247
    - initialize_tiller
248 249
    - create_secret
    - deploy
250
    - persist_environment_url
251 252 253 254
  environment:
    name: review/$CI_COMMIT_REF_NAME
    url: http://$CI_PROJECT_PATH_SLUG-$CI_ENVIRONMENT_SLUG.$AUTO_DEVOPS_DOMAIN
    on_stop: stop_review
255 256
  artifacts:
    paths: [environment_url.txt]
257 258 259
  only:
    refs:
      - branches
260
    kubernetes: active
261
  except:
262 263 264 265
    refs:
      - master
    variables:
      - $REVIEW_DISABLED
266 267 268 269 270 271 272

stop_review:
  stage: cleanup
  variables:
    GIT_STRATEGY: none
  script:
    - install_dependencies
273
    - initialize_tiller
274 275 276 277 278 279 280 281 282
    - delete
  environment:
    name: review/$CI_COMMIT_REF_NAME
    action: stop
  when: manual
  allow_failure: true
  only:
    refs:
      - branches
283
    kubernetes: active
284
  except:
285 286 287 288
    refs:
      - master
    variables:
      - $REVIEW_DISABLED
289 290 291 292

# Staging deploys are disabled by default since
# continuous deployment to production is enabled by default
# If you prefer to automatically deploy to staging and
293 294
# only manually promote to production, enable this job by setting
# STAGING_ENABLED.
295

296
staging:
297 298 299 300 301 302
  stage: staging
  script:
    - check_kube_domain
    - install_dependencies
    - download_chart
    - ensure_namespace
303
    - initialize_tiller
304 305 306 307 308 309 310 311
    - create_secret
    - deploy
  environment:
    name: staging
    url: http://$CI_PROJECT_PATH_SLUG-staging.$AUTO_DEVOPS_DOMAIN
  only:
    refs:
      - master
312
    kubernetes: active
313 314
    variables:
      - $STAGING_ENABLED
315

316 317 318
# Canaries are also disabled by default, but if you want them,
# and know what the downsides are, you can enable this by setting
# CANARY_ENABLED.
319

320
canary:
321 322 323 324 325 326
  stage: canary
  script:
    - check_kube_domain
    - install_dependencies
    - download_chart
    - ensure_namespace
327
    - initialize_tiller
328 329 330 331 332 333 334 335 336
    - create_secret
    - deploy canary
  environment:
    name: production
    url: http://$CI_PROJECT_PATH_SLUG.$AUTO_DEVOPS_DOMAIN
  when: manual
  only:
    refs:
      - master
337
    kubernetes: active
338 339
    variables:
      - $CANARY_ENABLED
340

341
.production: &production_template
342 343 344 345 346 347
  stage: production
  script:
    - check_kube_domain
    - install_dependencies
    - download_chart
    - ensure_namespace
348
    - initialize_tiller
349 350 351
    - create_secret
    - deploy
    - delete canary
352
    - delete rollout
353
    - persist_environment_url
354 355 356
  environment:
    name: production
    url: http://$CI_PROJECT_PATH_SLUG.$AUTO_DEVOPS_DOMAIN
357 358
  artifacts:
    paths: [environment_url.txt]
359 360 361

production:
  <<: *production_template
362 363 364
  only:
    refs:
      - master
365
    kubernetes: active
366 367 368
  except:
    variables:
      - $STAGING_ENABLED
369
      - $CANARY_ENABLED
370
      - $INCREMENTAL_ROLLOUT_ENABLED
371
      - $INCREMENTAL_ROLLOUT_MODE
372 373 374 375

production_manual:
  <<: *production_template
  when: manual
376
  allow_failure: false
377 378 379
  only:
    refs:
      - master
380
    kubernetes: active
381 382
    variables:
      - $STAGING_ENABLED
383
      - $CANARY_ENABLED
384 385 386
  except:
    variables:
      - $INCREMENTAL_ROLLOUT_ENABLED
387
      - $INCREMENTAL_ROLLOUT_MODE
388 389 390 391 392 393 394 395 396

# This job implements incremental rollout on for every push to `master`.

.rollout: &rollout_template
  script:
    - check_kube_domain
    - install_dependencies
    - download_chart
    - ensure_namespace
397
    - initialize_tiller
398 399 400 401 402 403 404 405 406 407 408
    - create_secret
    - deploy rollout $ROLLOUT_PERCENTAGE
    - scale stable $((100-ROLLOUT_PERCENTAGE))
    - delete canary
    - persist_environment_url
  environment:
    name: production
    url: http://$CI_PROJECT_PATH_SLUG.$AUTO_DEVOPS_DOMAIN
  artifacts:
    paths: [environment_url.txt]

409
.manual_rollout_template: &manual_rollout_template
410
  <<: *rollout_template
411
  stage: production
412
  when: manual
413
  # This selectors are backward compatible mode with $INCREMENTAL_ROLLOUT_ENABLED (before 11.4)
414 415 416
  only:
    refs:
      - master
417
    kubernetes: active
418
    variables:
419
      - $INCREMENTAL_ROLLOUT_MODE == "manual"
420
      - $INCREMENTAL_ROLLOUT_ENABLED
421 422 423
  except:
    variables:
      - $INCREMENTAL_ROLLOUT_MODE == "timed"
424

425
.timed_rollout_template: &timed_rollout_template
426
  <<: *rollout_template
427 428
  when: delayed
  start_in: 5 minutes
429 430 431
  only:
    refs:
      - master
432
    kubernetes: active
433
    variables:
434 435 436 437 438 439 440 441 442 443 444 445 446 447 448 449 450 451 452 453 454 455 456 457 458 459 460 461 462 463 464 465 466 467 468 469
      - $INCREMENTAL_ROLLOUT_MODE == "timed"

timed rollout 10%:
  <<: *timed_rollout_template
  stage: incremental rollout 10%
  variables:
    ROLLOUT_PERCENTAGE: 10

timed rollout 25%:
  <<: *timed_rollout_template
  stage: incremental rollout 25%
  variables:
    ROLLOUT_PERCENTAGE: 25

timed rollout 50%:
  <<: *timed_rollout_template
  stage: incremental rollout 50%
  variables:
    ROLLOUT_PERCENTAGE: 50

timed rollout 100%:
  <<: *timed_rollout_template
  <<: *production_template
  stage: incremental rollout 100%
  variables:
    ROLLOUT_PERCENTAGE: 100

rollout 10%:
  <<: *manual_rollout_template
  variables:
    ROLLOUT_PERCENTAGE: 10

rollout 25%:
  <<: *manual_rollout_template
  variables:
    ROLLOUT_PERCENTAGE: 25
470 471

rollout 50%:
472
  <<: *manual_rollout_template
473 474 475 476
  variables:
    ROLLOUT_PERCENTAGE: 50

rollout 100%:
477
  <<: *manual_rollout_template
478
  <<: *production_template
479
  allow_failure: false
480 481 482 483 484 485 486 487 488 489 490 491

# ---------------------------------------------------------------------------

.auto_devops: &auto_devops |
  # Auto DevOps variables and functions
  [[ "$TRACE" ]] && set -x
  auto_database_url=postgres://${POSTGRES_USER}:${POSTGRES_PASSWORD}@${CI_ENVIRONMENT_SLUG}-postgres:5432/${POSTGRES_DB}
  export DATABASE_URL=${DATABASE_URL-$auto_database_url}
  export CI_APPLICATION_REPOSITORY=$CI_REGISTRY_IMAGE/$CI_COMMIT_REF_SLUG
  export CI_APPLICATION_TAG=$CI_COMMIT_SHA
  export CI_CONTAINER_NAME=ci_job_build_${CI_JOB_ID}
  export TILLER_NAMESPACE=$KUBE_NAMESPACE
492 493
  # Extract "MAJOR.MINOR" from CI_SERVER_VERSION and generate "MAJOR-MINOR-stable" for Security Products
  export SP_VERSION=$(echo "$CI_SERVER_VERSION" | sed 's/^\([0-9]*\)\.\([0-9]*\).*/\1-\2-stable/')
494

495
  function registry_login() {
496 497 498 499 500
    if [[ -n "$CI_REGISTRY_USER" ]]; then
      echo "Logging to GitLab Container Registry with CI credentials..."
      docker login -u "$CI_REGISTRY_USER" -p "$CI_REGISTRY_PASSWORD" "$CI_REGISTRY"
      echo ""
    fi
501 502 503 504
  }

  function container_scanning() {
    registry_login
505

Luke Bennett's avatar
Luke Bennett committed
506
    docker run -d --name db arminc/clair-db:latest
507
    docker run -p 6060:6060 --link db:postgres -d --name clair --restart on-failure arminc/clair-local-scan:v2.0.1
Luke Bennett's avatar
Luke Bennett committed
508 509
    apk add -U wget ca-certificates
    docker pull ${CI_APPLICATION_REPOSITORY}:${CI_APPLICATION_TAG}
510 511
    wget https://github.com/arminc/clair-scanner/releases/download/v8/clair-scanner_linux_amd64
    mv clair-scanner_linux_amd64 clair-scanner
Luke Bennett's avatar
Luke Bennett committed
512 513
    chmod +x clair-scanner
    touch clair-whitelist.yml
514 515 516
    retries=0
    echo "Waiting for clair daemon to start"
    while( ! wget -T 10 -q -O /dev/null http://docker:6060/v1/namespaces ) ; do sleep 1 ; echo -n "." ; if [ $retries -eq 10 ] ; then echo " Timeout, aborting." ; exit 1 ; fi ; retries=$(($retries+1)) ; done
517
    ./clair-scanner -c http://docker:6060 --ip $(hostname -i) -r gl-container-scanning-report.json -l clair.log -w clair-whitelist.yml ${CI_APPLICATION_REPOSITORY}:${CI_APPLICATION_TAG} || true
Luke Bennett's avatar
Luke Bennett committed
518
  }
519

520
  function code_quality() {
521
    docker run --env SOURCE_CODE="$PWD" \
522 523
               --volume "$PWD":/code \
               --volume /var/run/docker.sock:/var/run/docker.sock \
524
               "registry.gitlab.com/gitlab-org/security-products/codequality:$SP_VERSION" /code
525 526
  }

527
  function license_management() {
528
    /run.sh analyze .
529 530
  }

531 532 533
  function sast() {
    case "$CI_SERVER_VERSION" in
      *-ee)
534

535 536 537 538 539 540 541 542
        # Deprecation notice for CONFIDENCE_LEVEL variable
        if [ -z "$SAST_CONFIDENCE_LEVEL" -a "$CONFIDENCE_LEVEL" ]; then
          SAST_CONFIDENCE_LEVEL="$CONFIDENCE_LEVEL"
          echo "WARNING: CONFIDENCE_LEVEL is deprecated and MUST be replaced with SAST_CONFIDENCE_LEVEL"
        fi

        docker run --env SAST_CONFIDENCE_LEVEL="${SAST_CONFIDENCE_LEVEL:-3}" \
                   --volume "$PWD:/code" \
543
                   --volume /var/run/docker.sock:/var/run/docker.sock \
544
                   "registry.gitlab.com/gitlab-org/security-products/sast:$SP_VERSION" /app/bin/run /code
545 546 547 548 549 550 551
        ;;
      *)
        echo "GitLab EE is required"
        ;;
    esac
  }

552 553 554 555 556 557 558 559 560 561 562 563 564 565
  function dependency_scanning() {
    case "$CI_SERVER_VERSION" in
      *-ee)
        docker run --env DEP_SCAN_DISABLE_REMOTE_CHECKS="${DEP_SCAN_DISABLE_REMOTE_CHECKS:-false}" \
                   --volume "$PWD:/code" \
                   --volume /var/run/docker.sock:/var/run/docker.sock \
                   "registry.gitlab.com/gitlab-org/security-products/dependency-scanning:$SP_VERSION" /code
        ;;
      *)
        echo "GitLab EE is required"
        ;;
    esac
  }

566 567 568
  function get_replicas() {
    track="${1:-stable}"
    percentage="${2:-100}"
569 570 571 572

    env_track=$( echo $track | tr -s  '[:lower:]'  '[:upper:]' )
    env_slug=$( echo ${CI_ENVIRONMENT_SLUG//-/_} | tr -s  '[:lower:]'  '[:upper:]' )

573
    if [[ "$track" == "stable" ]] || [[ "$track" == "rollout" ]]; then
574 575
      # for stable track get number of replicas from `PRODUCTION_REPLICAS`
      eval new_replicas=\$${env_slug}_REPLICAS
576 577 578
      if [[ -z "$new_replicas" ]]; then
        new_replicas=$REPLICAS
      fi
579 580 581
    else
      # for all tracks get number of replicas from `CANARY_PRODUCTION_REPLICAS`
      eval new_replicas=\$${env_track}_${env_slug}_REPLICAS
582 583 584
      if [[ -z "$new_replicas" ]]; then
        eval new_replicas=\${env_track}_REPLICAS
      fi
585
    fi
586 587 588 589 590 591 592 593 594 595 596 597 598 599 600 601 602 603 604 605 606 607 608 609 610 611 612

    replicas="${new_replicas:-1}"
    replicas="$(($replicas * $percentage / 100))"

    # always return at least one replicas
    if [[ $replicas -gt 0 ]]; then
      echo "$replicas"
    else
      echo 1
    fi
  }

  function deploy() {
    track="${1-stable}"
    percentage="${2:-100}"
    name="$CI_ENVIRONMENT_SLUG"

    replicas="1"
    service_enabled="true"
    postgres_enabled="$POSTGRES_ENABLED"

    # if track is different than stable,
    # re-use all attached resources
    if [[ "$track" != "stable" ]]; then
      name="$name-$track"
      service_enabled="false"
      postgres_enabled="false"
613 614
    fi

615 616
    replicas=$(get_replicas "$track" "$percentage")

617 618 619 620 621 622
    if [[ "$CI_PROJECT_VISIBILITY" != "public" ]]; then
      secret_name='gitlab-registry'
    else
      secret_name=''
    fi

623
    if [[ -n "$DB_INITIALIZE" && -z "$(helm ls -q "^$name$")" ]]; then
624
      echo "Deploying first release with database initialization..."
625 626 627 628 629 630 631 632 633 634 635 636 637 638 639 640 641 642 643 644 645 646
      helm upgrade --install \
        --wait \
        --set service.enabled="$service_enabled" \
        --set releaseOverride="$CI_ENVIRONMENT_SLUG" \
        --set image.repository="$CI_APPLICATION_REPOSITORY" \
        --set image.tag="$CI_APPLICATION_TAG" \
        --set image.pullPolicy=IfNotPresent \
        --set image.secrets[0].name="$secret_name" \
        --set application.track="$track" \
        --set application.database_url="$DATABASE_URL" \
        --set service.url="$CI_ENVIRONMENT_URL" \
        --set replicaCount="$replicas" \
        --set postgresql.enabled="$postgres_enabled" \
        --set postgresql.nameOverride="postgres" \
        --set postgresql.postgresUser="$POSTGRES_USER" \
        --set postgresql.postgresPassword="$POSTGRES_PASSWORD" \
        --set postgresql.postgresDatabase="$POSTGRES_DB" \
        --set application.initializeCommand="$DB_INITIALIZE" \
        --namespace="$KUBE_NAMESPACE" \
        "$name" \
        chart/

647
      echo "Deploying second release..."
648 649 650 651 652 653 654 655
      helm upgrade --reuse-values \
        --wait \
        --set application.initializeCommand="" \
        --set application.migrateCommand="$DB_MIGRATE" \
        --namespace="$KUBE_NAMESPACE" \
        "$name" \
        chart/
    else
656
      echo "Deploying new release..."
657 658 659 660 661 662 663 664 665 666 667 668 669 670 671 672 673 674 675 676 677 678
      helm upgrade --install \
        --wait \
        --set service.enabled="$service_enabled" \
        --set releaseOverride="$CI_ENVIRONMENT_SLUG" \
        --set image.repository="$CI_APPLICATION_REPOSITORY" \
        --set image.tag="$CI_APPLICATION_TAG" \
        --set image.pullPolicy=IfNotPresent \
        --set image.secrets[0].name="$secret_name" \
        --set application.track="$track" \
        --set application.database_url="$DATABASE_URL" \
        --set service.url="$CI_ENVIRONMENT_URL" \
        --set replicaCount="$replicas" \
        --set postgresql.enabled="$postgres_enabled" \
        --set postgresql.nameOverride="postgres" \
        --set postgresql.postgresUser="$POSTGRES_USER" \
        --set postgresql.postgresPassword="$POSTGRES_PASSWORD" \
        --set postgresql.postgresDatabase="$POSTGRES_DB" \
        --set application.migrateCommand="$DB_MIGRATE" \
        --namespace="$KUBE_NAMESPACE" \
        "$name" \
        chart/
    fi
679 680

    kubectl rollout status -n "$KUBE_NAMESPACE" -w "deployment/$name"
681 682
  }

683 684 685 686 687 688 689 690 691 692 693
  function scale() {
    track="${1-stable}"
    percentage="${2-100}"
    name="$CI_ENVIRONMENT_SLUG"

    if [[ "$track" != "stable" ]]; then
      name="$name-$track"
    fi

    replicas=$(get_replicas "$track" "$percentage")

694 695 696 697 698 699 700 701
    if [[ -n "$(helm ls -q "^$name$")" ]]; then
      helm upgrade --reuse-values \
        --wait \
        --set replicaCount="$replicas" \
        --namespace="$KUBE_NAMESPACE" \
        "$name" \
        chart/
    fi
702 703
  }

704 705
  function install_dependencies() {
    apk add -U openssl curl tar gzip bash ca-certificates git
706 707
    curl -L -o /etc/apk/keys/sgerrand.rsa.pub https://alpine-pkgs.sgerrand.com/sgerrand.rsa.pub
    curl -L -O https://github.com/sgerrand/alpine-pkg-glibc/releases/download/2.28-r0/glibc-2.28-r0.apk
708 709
    apk add glibc-2.28-r0.apk
    rm glibc-2.28-r0.apk
710

711
    curl "https://kubernetes-helm.storage.googleapis.com/helm-v${HELM_VERSION}-linux-amd64.tar.gz" | tar zx
712
    mv linux-amd64/helm /usr/bin/
713
    mv linux-amd64/tiller /usr/bin/
714
    helm version --client
715 716
    tiller -version

717
    curl -L -o /usr/bin/kubectl "https://storage.googleapis.com/kubernetes-release/release/v${KUBERNETES_VERSION}/bin/linux/amd64/kubectl"
718 719 720 721 722 723 724 725 726 727 728 729 730 731 732 733 734 735 736 737 738 739 740 741 742 743
    chmod +x /usr/bin/kubectl
    kubectl version --client
  }

  function setup_docker() {
    if ! docker info &>/dev/null; then
      if [ -z "$DOCKER_HOST" -a "$KUBERNETES_PORT" ]; then
        export DOCKER_HOST='tcp://localhost:2375'
      fi
    fi
  }

  function setup_test_db() {
    if [ -z ${KUBERNETES_PORT+x} ]; then
      DB_HOST=postgres
    else
      DB_HOST=localhost
    fi
    export DATABASE_URL="postgres://${POSTGRES_USER}:${POSTGRES_PASSWORD}@${DB_HOST}:5432/${POSTGRES_DB}"
  }

  function download_chart() {
    if [[ ! -d chart ]]; then
      auto_chart=${AUTO_DEVOPS_CHART:-gitlab/auto-deploy-app}
      auto_chart_name=$(basename $auto_chart)
      auto_chart_name=${auto_chart_name%.tgz}
744
      auto_chart_name=${auto_chart_name%.tar.gz}
745 746 747 748 749 750 751 752 753 754 755 756 757 758 759 760 761 762 763 764 765 766 767 768
    else
      auto_chart="chart"
      auto_chart_name="chart"
    fi

    helm init --client-only
    helm repo add gitlab https://charts.gitlab.io
    if [[ ! -d "$auto_chart" ]]; then
      helm fetch ${auto_chart} --untar
    fi
    if [ "$auto_chart_name" != "chart" ]; then
      mv ${auto_chart_name} chart
    fi

    helm dependency update chart/
    helm dependency build chart/
  }

  function ensure_namespace() {
    kubectl describe namespace "$KUBE_NAMESPACE" || kubectl create namespace "$KUBE_NAMESPACE"
  }

  function check_kube_domain() {
    if [ -z ${AUTO_DEVOPS_DOMAIN+x} ]; then
769
      echo "In order to deploy or use Review Apps, AUTO_DEVOPS_DOMAIN variable must be set"
770
      echo "You can do it in Auto DevOps project settings or defining a variable at group or project level"
771
      echo "You can also manually add it in .gitlab-ci.yml"
772 773 774 775 776 777 778
      false
    else
      true
    fi
  }

  function build() {
779
    registry_login
780

781 782
    if [[ -f Dockerfile ]]; then
      echo "Building Dockerfile-based application..."
783 784 785 786 787 788 789 790 791 792
      docker build \
        --build-arg HTTP_PROXY="$HTTP_PROXY" \
        --build-arg http_proxy="$http_proxy" \
        --build-arg HTTPS_PROXY="$HTTPS_PROXY" \
        --build-arg https_proxy="$https_proxy" \
        --build-arg FTP_PROXY="$FTP_PROXY" \
        --build-arg ftp_proxy="$ftp_proxy" \
        --build-arg NO_PROXY="$NO_PROXY" \
        --build-arg no_proxy="$no_proxy" \
        -t "$CI_APPLICATION_REPOSITORY:$CI_APPLICATION_TAG" .
793 794
    else
      echo "Building Heroku-based application using gliderlabs/herokuish docker image..."
795 796 797 798 799 800 801 802 803 804 805
      docker run -i \
        -e BUILDPACK_URL \
        -e HTTP_PROXY \
        -e http_proxy \
        -e HTTPS_PROXY \
        -e https_proxy \
        -e FTP_PROXY \
        -e ftp_proxy \
        -e NO_PROXY \
        -e no_proxy \
        --name="$CI_CONTAINER_NAME" -v "$(pwd):/tmp/app:ro" gliderlabs/herokuish /bin/herokuish buildpack build
806 807 808 809 810 811 812 813 814 815 816 817 818 819 820 821
      docker commit "$CI_CONTAINER_NAME" "$CI_APPLICATION_REPOSITORY:$CI_APPLICATION_TAG"
      docker rm "$CI_CONTAINER_NAME" >/dev/null
      echo ""

      echo "Configuring $CI_APPLICATION_REPOSITORY:$CI_APPLICATION_TAG docker image..."
      docker create --expose 5000 --env PORT=5000 --name="$CI_CONTAINER_NAME" "$CI_APPLICATION_REPOSITORY:$CI_APPLICATION_TAG" /bin/herokuish procfile start web
      docker commit "$CI_CONTAINER_NAME" "$CI_APPLICATION_REPOSITORY:$CI_APPLICATION_TAG"
      docker rm "$CI_CONTAINER_NAME" >/dev/null
      echo ""
    fi

    echo "Pushing to GitLab Container Registry..."
    docker push "$CI_APPLICATION_REPOSITORY:$CI_APPLICATION_TAG"
    echo ""
  }

822
  function initialize_tiller() {
823
    echo "Checking Tiller..."
824

825
    export HELM_HOST="localhost:44134"
826
    tiller -listen ${HELM_HOST} -alsologtostderr > /dev/null 2>&1 &
827
    echo "Tiller is listening on ${HELM_HOST}"
828

829 830 831 832 833 834 835 836
    if ! helm version --debug; then
      echo "Failed to init Tiller."
      return 1
    fi
    echo ""
  }

  function create_secret() {
837
    echo "Create secret..."
838 839 840
    if [[ "$CI_PROJECT_VISIBILITY" == "public" ]]; then
      return
    fi
841

842 843 844
    kubectl create secret -n "$KUBE_NAMESPACE" \
      docker-registry gitlab-registry \
      --docker-server="$CI_REGISTRY" \
845 846
      --docker-username="${CI_DEPLOY_USER:-$CI_REGISTRY_USER}" \
      --docker-password="${CI_DEPLOY_PASSWORD:-$CI_REGISTRY_PASSWORD}" \
847 848 849
      --docker-email="$GITLAB_USER_EMAIL" \
      -o yaml --dry-run | kubectl replace -n "$KUBE_NAMESPACE" --force -f -
  }
850

851 852 853 854 855 856 857 858
  function dast() {
    export CI_ENVIRONMENT_URL=$(cat environment_url.txt)

    mkdir /zap/wrk/
    /zap/zap-baseline.py -J gl-dast-report.json -t "$CI_ENVIRONMENT_URL" || true
    cp /zap/wrk/gl-dast-report.json .
  }

859 860
  function performance() {
    export CI_ENVIRONMENT_URL=$(cat environment_url.txt)
861

862
    mkdir gitlab-exporter
863
    wget -O gitlab-exporter/index.js https://gitlab.com/gitlab-org/gl-performance/raw/10-5/index.js
864

865
    mkdir sitespeed-results
866

867 868 869
    if [ -f .gitlab-urls.txt ]
    then
      sed -i -e 's@^@'"$CI_ENVIRONMENT_URL"'@' .gitlab-urls.txt
870
      docker run --shm-size=1g --rm -v "$(pwd)":/sitespeed.io sitespeedio/sitespeed.io:6.3.1 --plugins.add ./gitlab-exporter --outputFolder sitespeed-results .gitlab-urls.txt
871
    else
872
      docker run --shm-size=1g --rm -v "$(pwd)":/sitespeed.io sitespeedio/sitespeed.io:6.3.1 --plugins.add ./gitlab-exporter --outputFolder sitespeed-results "$CI_ENVIRONMENT_URL"
873
    fi
874

875 876
    mv sitespeed-results/data/performance.json performance.json
  }
877

878 879 880
  function persist_environment_url() {
      echo $CI_ENVIRONMENT_URL > environment_url.txt
  }
881 882 883 884 885 886 887 888 889

  function delete() {
    track="${1-stable}"
    name="$CI_ENVIRONMENT_SLUG"

    if [[ "$track" != "stable" ]]; then
      name="$name-$track"
    fi

890
    if [[ -n "$(helm ls -q "^$name$")" ]]; then
891
      helm delete --purge "$name"
892
    fi
893 894 895 896
  }

before_script:
  - *auto_devops