5

In the gitlab ce omnibus 14.10.2 instance, there is a project in which it is necessary to make a pipeline in gitlab-ci.yml that would check for the existence of dynamical environment deployments and if they are not there, then do nothing, and if they are, it would update them or manually deploy by a trigger from the webui.

My example:

#...
check-review:
  variables: 
    GIT_STRATEGY: none
  stage: dev/review/check
  only:
    - /^(feature|hotfix)\/(.*)/m
  dependencies: []
  allow_failure: true
  script:
    - curl -sLf ${CI_COMMIT_REF_SLUG}.domain.io --output /dev/null
  when: always

ansible/deploy:
  stage: dev/review
  only:
    - /^(feature|hotfix)\/(.*)/m
  except:
    - master
    - staging
  environment:
    name: $CI_COMMIT_REF_NAME
    url: https://${CI_COMMIT_REF_SLUG}.domain.io
    action: start
    on_stop: ansible/undeploy
  when: on_success
  dependencies:
    - vendor # build back
  script:
    - make deploy

ansible/undeploy:
  stage: dev/review
  variables: 
    GIT_STRATEGY: none
  environment:
    name: $CI_COMMIT_REF_NAME
    url: https://${CI_COMMIT_REF_SLUG}.domain.io
    action: stop
  when: manual
  needs:
    - job: ansible/deploy
  script:
    - make delete_dev_stand

This condition need because dev teams workinig on many branches and not everyone need to be deployed on dev envs, on the other hand with manual update only - on every update/fix code qa need to go gitlab webui & trigger job to deploy/update deployment in environments https://${CI_SERVER_HOST}/${CI_PROJECT_PATH}/-/environments/

Maybe I`ve miss something in gitlab-ci ref, only solution that I found was to make failure pipline on check stage/job but this not happy to see so many failed pipelines.

1 Answers1

2

It's been two months so you probably have a solution already, but here's something you could try if it fits your use case

Approach:

Use pipeline triggers and a script that calls the Gitlab API

1. Find out if the environment exists

a. Create a script called get-deployment-strategy.sh and add it to your project

b. Create a private token in your user preferences with API read permission and add it to your CI/CD variables (GITLAB_API_PRIVATE_READ_TOKEN=token)

#!/bin/bash
# Private Token (created in user preferences) with API READ permission added to CI/CD vars
HEADER="PRIVATE-TOKEN: $GITLAB_API_PRIVATE_READ_TOKEN"
# To get the project which the environment should be read from
API_URL="https://gitlab.com/api/v4/projects/$CI_PROJECT_ID/environments"
# URL query parameter to filter for environment with specific name
QUERY_STRING="name=$DEPLOYMENT_TARGET/$DEPLOYMENT_NAME"

# Call Gitlab API (Environments API)
API_RESPONSE="$(curl -G --header "$HEADER" "$API_URL" --data-urlencode "$QUERY_STRING")"

# The response is an empty array (string) if there is no environment with the specific name
if [ "$API_RESPONSE" = "[]" ]; then
  # Deployment environment does not exist
  echo "DO_STRATEGY_A"
else
  echo "DO_STRATEGY_B"
fi

2. Use trigger pipelines within your check job

a. Create a trigger token in your CI/CD settings and add it to your CI/CD variables

b. Call the trigger pipeline in your check job and pass it a "deployment strategy variable"

Something like this:

check-job:
  before_script:
    - export DEPLOYMENT_STRATEGY=$(./get-deployment-strategy.sh)
  script:
     - |
       curl \
       --fail \
       --request POST \
       --form token=$DEPLOY_TRIGGER_TOKEN \
       --form ref=$CI_COMMIT_BRANCH \
       --form variable[DEPLOYMENT_STRATEGY]=$DEPLOYMENT_STRATEGY \
       "https://gitlab.com/api/v4/projects/$CI_PROJECT_ID/trigger/pipeline"
  

3. Make the deploy jobs activate only on specific DEPLOYMENT_STRATEGY

# Only runs for DO_STRATEGY_A (environment does not exist)
deploy/strategy-A:
  rules:
    - if: '$CI_PIPELINE_SOURCE="trigger" && $DEPLOYMENT_STRATEGY=="DO_STRATEGY_A"' 
# Only runs for DO_STRATEGY_B (environment exists)
deploy/strategy-B:
  rules:
    - if: '$CI_PIPELINE_SOURCE="trigger" && $DEPLOYMENT_STRATEGY=="DO_STRATEGY_B"' 
Beefcake
  • 305
  • 4
  • 10
  • Thanks a lot! I will implement / test this solution on the next project, the solution I found was to use two jobs and the line "before_script" that wrote / read the environment state to the file – Илья Бугримов Oct 17 '22 at 10:22