Auto-DevOps.gitlab-ci.yml 25.5 KB
Newer Older
A
Alessio Caiazza 已提交
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
#
O
Olivier Gonzalez 已提交
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
O
Olivier Gonzalez 已提交
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 27 28 29 30
# The sast and sast_dashboard jobs are executed to guarantee full compatibility
# with the group security dashboard and the security reports with old runners.
# If you use only runners with version 11.5 or above, you can disable the sast
# job by setting the OLD_REPORTS_DISABLED environment variable. If you use only
# runners with version below 11.5, you can disable the sast_dashboard job by
# setting the NEW_REPORTS_DISABLED environment variable.
# The sast_dashboard job will be removed in the future, when the sast job will
# use the new reports syntax.
#
A
Alessio Caiazza 已提交
31 32 33 34 35
# 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.
#
F
Fabio Busatto 已提交
36
# Continuous deployment to production is enabled by default.
37 38
# 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,
T
Tripple Moon 已提交
39
# set INCREMENTAL_ROLLOUT_MODE environment variable to "manual" or "timed".
O
Olivier Gonzalez 已提交
40
# If you want to use canary deployments, set CANARY_ENABLED environment variable.
A
Alessio Caiazza 已提交
41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60
#
# 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

61
  KUBERNETES_VERSION: 1.10.9
T
Thong Kuah 已提交
62
  HELM_VERSION: 2.11.0
63

64 65
  DOCKER_DRIVER: overlay2

A
Alessio Caiazza 已提交
66 67 68 69
stages:
  - build
  - test
  - review
70
  - dast
A
Alessio Caiazza 已提交
71 72 73
  - staging
  - canary
  - production
74 75 76 77
  - incremental rollout 10%
  - incremental rollout 25%
  - incremental rollout 50%
  - incremental rollout 100%
J
Joshua Lambert 已提交
78
  - performance
A
Alessio Caiazza 已提交
79 80 81 82
  - cleanup

build:
  stage: build
83
  image: docker:stable-git
A
Alessio Caiazza 已提交
84
  services:
85
  - docker:stable-dind
A
Alessio Caiazza 已提交
86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104
  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
O
Olivier Gonzalez 已提交
105 106 107
  except:
    variables:
      - $TEST_DISABLED
A
Alessio Caiazza 已提交
108

109
code_quality:
O
Olivier Gonzalez 已提交
110
  stage: test
111
  image: docker:stable
A
Alessio Caiazza 已提交
112 113
  allow_failure: true
  services:
114
    - docker:stable-dind
A
Alessio Caiazza 已提交
115 116
  script:
    - setup_docker
117
    - code_quality
A
Alessio Caiazza 已提交
118
  artifacts:
119
    paths: [gl-code-quality-report.json]
120 121
  only:
    - branches
O
Olivier Gonzalez 已提交
122 123 124
  except:
    variables:
      - $CODE_QUALITY_DISABLED
A
Alessio Caiazza 已提交
125

126
license_management:
127
  stage: test
128 129 130
  image: 
    name: "registry.gitlab.com/gitlab-org/security-products/license-management:$CI_SERVER_VERSION_MAJOR-$CI_SERVER_VERSION_MINOR-stable"
    entrypoint: [""]
131 132 133 134 135
  allow_failure: true
  script:
    - license_management
  artifacts:
    paths: [gl-license-management-report.json]
136
  only:
137 138
    refs:
      - branches
139 140
    variables:
      - $GITLAB_FEATURES =~ /\blicense_management\b/
141 142 143 144
  except:
    variables:
      - $LICENSE_MANAGEMENT_DISABLED

J
Joshua Lambert 已提交
145 146
performance:
  stage: performance
147
  image: docker:stable
148 149
  allow_failure: true
  services:
150
    - docker:stable-dind
J
Joshua Lambert 已提交
151
  script:
152
    - setup_docker
J
Joshua Lambert 已提交
153 154 155 156
    - performance
  artifacts:
    paths:
    - performance.json
157
    - sitespeed-results/
J
Joshua Lambert 已提交
158 159 160
  only:
    refs:
      - branches
O
Olivier Gonzalez 已提交
161 162 163
  except:
    variables:
      - $PERFORMANCE_DISABLED
164
      - $KUBECONFIG == null
J
Joshua Lambert 已提交
165

166
sast:
O
Olivier Gonzalez 已提交
167
  stage: test
168
  image: docker:stable
169
  allow_failure: true
170
  services:
171
    - docker:stable-dind
172
  script:
173 174
    - setup_docker
    - sast
175 176
  artifacts:
    paths: [gl-sast-report.json]
177
  only:
178 179 180 181
    refs:
      - branches
    variables:
      - $GITLAB_FEATURES =~ /\bsast\b/
O
Olivier Gonzalez 已提交
182 183 184
  except:
    variables:
      - $SAST_DISABLED
185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207
      - $OLD_REPORTS_DISABLED

sast_dashboard:
  stage: test
  image: docker:stable
  allow_failure: true
  services:
    - docker:stable-dind
  script:
    - setup_docker
    - sast
  artifacts:
    reports:
      sast: gl-sast-report.json
  only:
    refs:
      - branches
    variables:
      - $GITLAB_FEATURES =~ /\bsast\b/
  except:
    variables:
      - $SAST_DISABLED
      - $NEW_REPORTS_DISABLED
208

209
dependency_scanning:
O
Olivier Gonzalez 已提交
210
  stage: test
211 212 213 214 215 216 217 218 219
  image: docker:stable
  allow_failure: true
  services:
    - docker:stable-dind
  script:
    - setup_docker
    - dependency_scanning
  artifacts:
    paths: [gl-dependency-scanning-report.json]
220
  only:
221 222 223 224
    refs:
      - branches
    variables:
      - $GITLAB_FEATURES =~ /\bdependency_scanning\b/
O
Olivier Gonzalez 已提交
225 226 227
  except:
    variables:
      - $DEPENDENCY_SCANNING_DISABLED
F
Fabio Busatto 已提交
228

229
container_scanning:
O
Olivier Gonzalez 已提交
230
  stage: test
231
  image: docker:stable
L
Luke Bennett 已提交
232 233
  allow_failure: true
  services:
234
    - docker:stable-dind
L
Luke Bennett 已提交
235 236
  script:
    - setup_docker
237
    - container_scanning
L
Luke Bennett 已提交
238
  artifacts:
239
    paths: [gl-container-scanning-report.json]
240
  only:
241 242 243
    refs:
      - branches
    variables:
244
      - $GITLAB_FEATURES =~ /\bcontainer_scanning\b/
O
Olivier Gonzalez 已提交
245 246 247
  except:
    variables:
      - $CONTAINER_SCANNING_DISABLED
248

249 250 251
dast:
  stage: dast
  allow_failure: true
F
Fabien Catteau 已提交
252
  image: registry.gitlab.com/gitlab-org/security-products/zaproxy
253 254 255 256 257 258 259 260 261
  variables:
    POSTGRES_DB: "false"
  script:
    - dast
  artifacts:
    paths: [gl-dast-report.json]
  only:
    refs:
      - branches
262 263
    variables:
      - $GITLAB_FEATURES =~ /\bdast\b/
264
  except:
O
Olivier Gonzalez 已提交
265 266 267 268
    refs:
      - master
    variables:
      - $DAST_DISABLED
269
      - $KUBECONFIG == null
270

A
Alessio Caiazza 已提交
271 272 273 274 275 276 277
review:
  stage: review
  script:
    - check_kube_domain
    - install_dependencies
    - download_chart
    - ensure_namespace
T
Thong Kuah 已提交
278
    - initialize_tiller
A
Alessio Caiazza 已提交
279 280
    - create_secret
    - deploy
J
Joshua Lambert 已提交
281
    - persist_environment_url
A
Alessio Caiazza 已提交
282 283 284 285
  environment:
    name: review/$CI_COMMIT_REF_NAME
    url: http://$CI_PROJECT_PATH_SLUG-$CI_ENVIRONMENT_SLUG.$AUTO_DEVOPS_DOMAIN
    on_stop: stop_review
J
Joshua Lambert 已提交
286 287
  artifacts:
    paths: [environment_url.txt]
A
Alessio Caiazza 已提交
288 289 290 291
  only:
    refs:
      - branches
  except:
O
Olivier Gonzalez 已提交
292 293 294 295
    refs:
      - master
    variables:
      - $REVIEW_DISABLED
296
      - $KUBECONFIG == null
A
Alessio Caiazza 已提交
297 298 299 300 301 302 303

stop_review:
  stage: cleanup
  variables:
    GIT_STRATEGY: none
  script:
    - install_dependencies
T
Thong Kuah 已提交
304
    - initialize_tiller
A
Alessio Caiazza 已提交
305 306 307 308 309 310 311 312 313 314
    - delete
  environment:
    name: review/$CI_COMMIT_REF_NAME
    action: stop
  when: manual
  allow_failure: true
  only:
    refs:
      - branches
  except:
O
Olivier Gonzalez 已提交
315 316 317 318
    refs:
      - master
    variables:
      - $REVIEW_DISABLED
319
      - $KUBECONFIG == null
A
Alessio Caiazza 已提交
320 321 322 323

# Staging deploys are disabled by default since
# continuous deployment to production is enabled by default
# If you prefer to automatically deploy to staging and
F
Fabio Busatto 已提交
324 325
# only manually promote to production, enable this job by setting
# STAGING_ENABLED.
A
Alessio Caiazza 已提交
326

F
Fabio Busatto 已提交
327
staging:
A
Alessio Caiazza 已提交
328 329 330 331 332 333
  stage: staging
  script:
    - check_kube_domain
    - install_dependencies
    - download_chart
    - ensure_namespace
T
Thong Kuah 已提交
334
    - initialize_tiller
A
Alessio Caiazza 已提交
335 336 337 338 339 340 341 342
    - create_secret
    - deploy
  environment:
    name: staging
    url: http://$CI_PROJECT_PATH_SLUG-staging.$AUTO_DEVOPS_DOMAIN
  only:
    refs:
      - master
F
Fabio Busatto 已提交
343 344
    variables:
      - $STAGING_ENABLED
345 346 347
  except:
    variables:
      - $KUBECONFIG == null
A
Alessio Caiazza 已提交
348

O
Olivier Gonzalez 已提交
349 350 351
# 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.
A
Alessio Caiazza 已提交
352

O
Olivier Gonzalez 已提交
353
canary:
A
Alessio Caiazza 已提交
354 355 356 357 358 359
  stage: canary
  script:
    - check_kube_domain
    - install_dependencies
    - download_chart
    - ensure_namespace
T
Thong Kuah 已提交
360
    - initialize_tiller
A
Alessio Caiazza 已提交
361 362 363 364 365 366 367 368 369
    - create_secret
    - deploy canary
  environment:
    name: production
    url: http://$CI_PROJECT_PATH_SLUG.$AUTO_DEVOPS_DOMAIN
  when: manual
  only:
    refs:
      - master
O
Olivier Gonzalez 已提交
370 371
    variables:
      - $CANARY_ENABLED
372 373 374
  except:
    variables:
      - $KUBECONFIG == null
A
Alessio Caiazza 已提交
375

F
Fabio Busatto 已提交
376
.production: &production_template
A
Alessio Caiazza 已提交
377 378 379 380 381 382
  stage: production
  script:
    - check_kube_domain
    - install_dependencies
    - download_chart
    - ensure_namespace
T
Thong Kuah 已提交
383
    - initialize_tiller
A
Alessio Caiazza 已提交
384 385 386
    - create_secret
    - deploy
    - delete canary
F
Fabio Busatto 已提交
387
    - delete rollout
J
Joshua Lambert 已提交
388
    - persist_environment_url
A
Alessio Caiazza 已提交
389 390 391
  environment:
    name: production
    url: http://$CI_PROJECT_PATH_SLUG.$AUTO_DEVOPS_DOMAIN
J
Joshua Lambert 已提交
392 393
  artifacts:
    paths: [environment_url.txt]
F
Fabio Busatto 已提交
394 395 396

production:
  <<: *production_template
A
Alessio Caiazza 已提交
397 398 399
  only:
    refs:
      - master
F
Fabio Busatto 已提交
400 401 402
  except:
    variables:
      - $STAGING_ENABLED
O
Olivier Gonzalez 已提交
403
      - $CANARY_ENABLED
F
Fabio Busatto 已提交
404
      - $INCREMENTAL_ROLLOUT_ENABLED
405
      - $INCREMENTAL_ROLLOUT_MODE
406
      - $KUBECONFIG == null
F
Fabio Busatto 已提交
407 408 409 410

production_manual:
  <<: *production_template
  when: manual
F
Fabio Busatto 已提交
411
  allow_failure: false
F
Fabio Busatto 已提交
412 413 414 415 416
  only:
    refs:
      - master
    variables:
      - $STAGING_ENABLED
417
      - $CANARY_ENABLED
F
Fabio Busatto 已提交
418 419 420
  except:
    variables:
      - $INCREMENTAL_ROLLOUT_ENABLED
421
      - $INCREMENTAL_ROLLOUT_MODE
422
      - $KUBECONFIG == null
F
Fabio Busatto 已提交
423 424 425 426 427 428 429 430 431

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

.rollout: &rollout_template
  script:
    - check_kube_domain
    - install_dependencies
    - download_chart
    - ensure_namespace
T
Thong Kuah 已提交
432
    - initialize_tiller
F
Fabio Busatto 已提交
433 434 435 436 437 438 439 440 441 442 443
    - 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]

444
.manual_rollout_template: &manual_rollout_template
F
Fabio Busatto 已提交
445
  <<: *rollout_template
446
  stage: production
F
Fabio Busatto 已提交
447
  when: manual
448
  # This selectors are backward compatible mode with $INCREMENTAL_ROLLOUT_ENABLED (before 11.4)
F
Fabio Busatto 已提交
449 450 451 452
  only:
    refs:
      - master
    variables:
453
      - $INCREMENTAL_ROLLOUT_MODE == "manual"
F
Fabio Busatto 已提交
454
      - $INCREMENTAL_ROLLOUT_ENABLED
455 456 457
  except:
    variables:
      - $INCREMENTAL_ROLLOUT_MODE == "timed"
458
      - $KUBECONFIG == null
F
Fabio Busatto 已提交
459

460
.timed_rollout_template: &timed_rollout_template
F
Fabio Busatto 已提交
461
  <<: *rollout_template
462 463
  when: delayed
  start_in: 5 minutes
F
Fabio Busatto 已提交
464 465 466 467
  only:
    refs:
      - master
    variables:
468
      - $INCREMENTAL_ROLLOUT_MODE == "timed"
469 470 471
  except:
    variables:
      - $KUBECONFIG == null
472 473 474 475 476 477 478 479 480 481 482 483 484 485 486 487 488 489 490 491 492 493 494 495 496 497 498 499 500 501 502 503 504 505 506

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
F
Fabio Busatto 已提交
507 508

rollout 50%:
509
  <<: *manual_rollout_template
F
Fabio Busatto 已提交
510 511 512 513
  variables:
    ROLLOUT_PERCENTAGE: 50

rollout 100%:
514
  <<: *manual_rollout_template
F
Fabio Busatto 已提交
515
  <<: *production_template
F
Fabio Busatto 已提交
516
  allow_failure: false
A
Alessio Caiazza 已提交
517 518 519 520 521 522 523 524 525 526 527 528

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

.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
529 530
  # 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/')
531

532
  function registry_login() {
533 534 535 536 537
    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
538 539 540 541
  }

  function container_scanning() {
    registry_login
542

L
Luke Bennett 已提交
543
    docker run -d --name db arminc/clair-db:latest
F
Fabio Busatto 已提交
544
    docker run -p 6060:6060 --link db:postgres -d --name clair --restart on-failure arminc/clair-local-scan:v2.0.1
L
Luke Bennett 已提交
545 546
    apk add -U wget ca-certificates
    docker pull ${CI_APPLICATION_REPOSITORY}:${CI_APPLICATION_TAG}
547 548
    wget https://github.com/arminc/clair-scanner/releases/download/v8/clair-scanner_linux_amd64
    mv clair-scanner_linux_amd64 clair-scanner
L
Luke Bennett 已提交
549 550
    chmod +x clair-scanner
    touch clair-whitelist.yml
551 552 553
    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
554
    ./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
L
Luke Bennett 已提交
555
  }
A
Alessio Caiazza 已提交
556

557
  function code_quality() {
558
    docker run --env SOURCE_CODE="$PWD" \
J
James Lopez 已提交
559 560
               --volume "$PWD":/code \
               --volume /var/run/docker.sock:/var/run/docker.sock \
561
               "registry.gitlab.com/gitlab-org/security-products/codequality:$SP_VERSION" /code
A
Alessio Caiazza 已提交
562 563
  }

564
  function license_management() {
565
    /run.sh analyze .
566 567
  }

568 569 570
  function sast() {
    case "$CI_SERVER_VERSION" in
      *-ee)
571

572 573 574 575 576 577 578 579
        # 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" \
580
                   --volume /var/run/docker.sock:/var/run/docker.sock \
581
                   "registry.gitlab.com/gitlab-org/security-products/sast:$SP_VERSION" /app/bin/run /code
582 583 584 585 586 587 588
        ;;
      *)
        echo "GitLab EE is required"
        ;;
    esac
  }

589 590 591 592 593 594 595 596 597 598 599 600 601 602
  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
  }

F
Fabio Busatto 已提交
603 604 605
  function get_replicas() {
    track="${1:-stable}"
    percentage="${2:-100}"
A
Alessio Caiazza 已提交
606 607 608 609

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

F
Fabio Busatto 已提交
610
    if [[ "$track" == "stable" ]] || [[ "$track" == "rollout" ]]; then
A
Alessio Caiazza 已提交
611 612
      # for stable track get number of replicas from `PRODUCTION_REPLICAS`
      eval new_replicas=\$${env_slug}_REPLICAS
613 614 615
      if [[ -z "$new_replicas" ]]; then
        new_replicas=$REPLICAS
      fi
A
Alessio Caiazza 已提交
616 617 618
    else
      # for all tracks get number of replicas from `CANARY_PRODUCTION_REPLICAS`
      eval new_replicas=\$${env_track}_${env_slug}_REPLICAS
619 620 621
      if [[ -z "$new_replicas" ]]; then
        eval new_replicas=\${env_track}_REPLICAS
      fi
A
Alessio Caiazza 已提交
622
    fi
F
Fabio Busatto 已提交
623 624 625 626 627 628 629 630 631 632 633 634 635 636 637 638 639 640 641 642 643 644 645 646 647 648 649

    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"
A
Alessio Caiazza 已提交
650 651
    fi

F
Fabio Busatto 已提交
652 653
    replicas=$(get_replicas "$track" "$percentage")

654 655 656 657 658 659
    if [[ "$CI_PROJECT_VISIBILITY" != "public" ]]; then
      secret_name='gitlab-registry'
    else
      secret_name=''
    fi

660 661 662 663 664 665 666 667 668 669 670 671 672 673 674 675 676 677 678 679 680 681 682 683 684 685 686 687 688 689 690 691 692 693 694 695 696 697 698 699 700 701 702 703 704 705 706 707 708 709 710 711 712
    if [[ -n "$DB_INITIALIZE" && -z "$(helm ls -q "^$name$")" ]]; then
      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/

      helm upgrade --reuse-values \
        --wait \
        --set application.initializeCommand="" \
        --set application.migrateCommand="$DB_MIGRATE" \
        --namespace="$KUBE_NAMESPACE" \
        "$name" \
        chart/
    else
      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
713 714

    kubectl rollout status -n "$KUBE_NAMESPACE" -w "deployment/$name"
A
Alessio Caiazza 已提交
715 716
  }

F
Fabio Busatto 已提交
717 718 719 720 721 722 723 724 725 726 727
  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")

F
Fabio Busatto 已提交
728 729 730 731 732 733 734 735
    if [[ -n "$(helm ls -q "^$name$")" ]]; then
      helm upgrade --reuse-values \
        --wait \
        --set replicaCount="$replicas" \
        --namespace="$KUBE_NAMESPACE" \
        "$name" \
        chart/
    fi
F
Fabio Busatto 已提交
736 737
  }

A
Alessio Caiazza 已提交
738 739
  function install_dependencies() {
    apk add -U openssl curl tar gzip bash ca-certificates git
740 741
    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
742 743
    apk add glibc-2.28-r0.apk
    rm glibc-2.28-r0.apk
A
Alessio Caiazza 已提交
744

745
    curl "https://kubernetes-helm.storage.googleapis.com/helm-v${HELM_VERSION}-linux-amd64.tar.gz" | tar zx
A
Alessio Caiazza 已提交
746
    mv linux-amd64/helm /usr/bin/
T
Thong Kuah 已提交
747
    mv linux-amd64/tiller /usr/bin/
A
Alessio Caiazza 已提交
748
    helm version --client
T
Thong Kuah 已提交
749 750
    tiller -version

751
    curl -L -o /usr/bin/kubectl "https://storage.googleapis.com/kubernetes-release/release/v${KUBERNETES_VERSION}/bin/linux/amd64/kubectl"
A
Alessio Caiazza 已提交
752 753 754 755 756 757 758 759 760 761 762 763 764 765 766 767 768 769 770 771 772 773 774 775 776 777
    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}
778
      auto_chart_name=${auto_chart_name%.tar.gz}
A
Alessio Caiazza 已提交
779 780 781 782 783 784 785 786 787 788 789 790 791 792 793 794 795 796 797 798 799 800 801 802
    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
A
Alessio Caiazza 已提交
803
      echo "In order to deploy or use Review Apps, AUTO_DEVOPS_DOMAIN variable must be set"
O
Olivier Gonzalez 已提交
804
      echo "You can do it in Auto DevOps project settings or defining a variable at group or project level"
A
Alessio Caiazza 已提交
805
      echo "You can also manually add it in .gitlab-ci.yml"
A
Alessio Caiazza 已提交
806 807 808 809 810 811 812
      false
    else
      true
    fi
  }

  function build() {
813
    registry_login
814

A
Alessio Caiazza 已提交
815 816
    if [[ -f Dockerfile ]]; then
      echo "Building Dockerfile-based application..."
817 818 819 820 821 822 823 824 825 826
      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" .
A
Alessio Caiazza 已提交
827 828
    else
      echo "Building Heroku-based application using gliderlabs/herokuish docker image..."
829 830 831 832 833 834 835 836 837 838 839
      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
A
Alessio Caiazza 已提交
840 841 842 843 844 845 846 847 848 849 850 851 852 853 854 855
      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 ""
  }

T
Thong Kuah 已提交
856
  function initialize_tiller() {
A
Alessio Caiazza 已提交
857
    echo "Checking Tiller..."
T
Thong Kuah 已提交
858

859
    export HELM_HOST="localhost:44134"
860
    tiller -listen ${HELM_HOST} -alsologtostderr > /dev/null 2>&1 &
T
Thong Kuah 已提交
861
    echo "Tiller is listening on ${HELM_HOST}"
T
Thong Kuah 已提交
862

A
Alessio Caiazza 已提交
863 864 865 866 867 868 869 870
    if ! helm version --debug; then
      echo "Failed to init Tiller."
      return 1
    fi
    echo ""
  }

  function create_secret() {
871
    echo "Create secret..."
872 873 874
    if [[ "$CI_PROJECT_VISIBILITY" == "public" ]]; then
      return
    fi
875

A
Alessio Caiazza 已提交
876 877 878
    kubectl create secret -n "$KUBE_NAMESPACE" \
      docker-registry gitlab-registry \
      --docker-server="$CI_REGISTRY" \
F
Fabio Busatto 已提交
879 880
      --docker-username="${CI_DEPLOY_USER:-$CI_REGISTRY_USER}" \
      --docker-password="${CI_DEPLOY_PASSWORD:-$CI_REGISTRY_PASSWORD}" \
A
Alessio Caiazza 已提交
881 882 883
      --docker-email="$GITLAB_USER_EMAIL" \
      -o yaml --dry-run | kubectl replace -n "$KUBE_NAMESPACE" --force -f -
  }
884

885 886 887 888 889 890 891 892
  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 .
  }

J
Joshua Lambert 已提交
893 894
  function performance() {
    export CI_ENVIRONMENT_URL=$(cat environment_url.txt)
895

J
Joshua Lambert 已提交
896
    mkdir gitlab-exporter
897
    wget -O gitlab-exporter/index.js https://gitlab.com/gitlab-org/gl-performance/raw/10-5/index.js
898

J
Joshua Lambert 已提交
899
    mkdir sitespeed-results
900

J
Joshua Lambert 已提交
901 902 903
    if [ -f .gitlab-urls.txt ]
    then
      sed -i -e 's@^@'"$CI_ENVIRONMENT_URL"'@' .gitlab-urls.txt
904
      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
J
Joshua Lambert 已提交
905
    else
906
      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"
J
Joshua Lambert 已提交
907
    fi
908

J
Joshua Lambert 已提交
909 910
    mv sitespeed-results/data/performance.json performance.json
  }
911

J
Joshua Lambert 已提交
912 913 914
  function persist_environment_url() {
      echo $CI_ENVIRONMENT_URL > environment_url.txt
  }
A
Alessio Caiazza 已提交
915 916 917 918 919 920 921 922 923

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

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

924
    if [[ -n "$(helm ls -q "^$name$")" ]]; then
925
      helm delete --purge "$name"
926
    fi
A
Alessio Caiazza 已提交
927 928 929 930
  }

before_script:
  - *auto_devops