# SPDX-FileCopyrightText: 2024-2025 Zentrum für Digitale Souveränität der Öffentlichen Verwaltung (ZenDiS) GmbH # SPDX-FileCopyrightText: 2023 Bundesministerium des Innern und für Heimat, PG ZenDiS "Projektgruppe für Aufbau ZenDiS" # SPDX-License-Identifier: Apache-2.0 --- include: - project: "${PROJECT_PATH_GITLAB_CONFIG_TOOLING}" ref: "v2.4.17" file: - "ci/common/lint.yml" - "ci/release-automation/semantic-release.yml" - local: "/.gitlab/generate/generate-docs.yml" - local: "/.gitlab/renovate/renovate.yml" - local: "/.gitlab/release/release-common.yml" - local: "/.gitlab/release/release-generate-version.yml" - local: "/.gitlab/release/release-semantic.yml" - local: "/.gitlab/lint/lint-common.yml" - local: "/.gitlab/lint/lint-reuse.yml" - project: "${PROJECT_PATH_CUSTOM_ENVIRONMENT_CONFIG}" file: "gitlab/environments.yaml" ref: "main" - local: "/.gitlab/lint/lint-opendesk.yml" rules: - if: > $JOB_OPENDESK_LINTER_ENABLED == 'false' || $CI_PIPELINE_SOURCE =~ 'tags|merge_request_event|web|trigger|api' when: "never" - when: "always" - local: "/.gitlab/lint/lint-kyverno.yml" rules: - if: > $JOB_OPENDESK_LINTER_ENABLED == 'false' || $CI_PIPELINE_SOURCE =~ 'tags|merge_request_event|web|trigger|api' when: "never" - when: "always" stages: - ".pre" - "renovate" - "scan" - "env-cleanup" - "env" - "pre-services-deploy" - "010-migrations-pre" - "030-services" - "050-components" - "060-components" - "090-migrations-post" - "lint" - "post-prepare" - "post-execute" - "env-stop" - ".post" variables: RELEASE_BRANCH: "main" NAMESPACE: description: "The name of namespaces to deploy to." value: "" CLUSTER: description: > Which cluster to use. Cluster must be defined in `gitlab/environments.yaml` of the repo that is included above using the env var `PROJECT_PATH_CUSTOM_ENVIRONMENT_CONFIG`: ${PROJECT_PATH_CUSTOM_ENVIRONMENT_CONFIG} value: "dev" MASTER_PASSWORD_WEB_VAR: description: > Optional: Provide a seed to be used for generation of all internal secrets. Same seed will result in same secrets. value: "" ENV_STOP_BEFORE: description: "Stop environment/delete namespace for the deployment." value: "no" options: - "yes" - "no" FLUSH_EXTERNAL_SERVICES_BEFORE: description: > Recreates databases and purges objectstorage. Useful when using external services and required overrides. value: "no" options: - "yes" - "no" FLUSH_EXTERNAL_SERVICES_TYPE: description: > Select the type of external services (e.g. "RUN", or "STACKIT"), as they require different cleanup strategies. Requires `FLUSH_EXTERNAL_SERVICES_BEFORE=yes` and `ENV_STOP_BEFORE=yes`. value: "CHANGE ME" options: - "RUN" - "STACKIT" - "CHANGE ME" DEBUG_ENABLED: description: > Allows to set `debug.enabled` to true for a deployment, needs to be supported by stage specific configuration containing: `debug.enabled: {{ env "DEBUG_ENABLED" | default false }}` value: "no" options: - "yes" - "no" OPENDESK_ENTERPRISE: description: > Set to `true` if you want to deploy openDesk EE (but be sure you provide the required EE keys/tokens for the application) value: "false" options: - "true" - "false" DEPLOY_ALL_COMPONENTS: description: "Enable all component deployment (overwrites 'no' setting on component level)." value: "no" options: - "yes" - "no" DEPLOY_MIGRATIONS: description: "Deploy K8s job for migrations (pre & post)." value: "no" options: - "yes" - "no" DEPLOY_SERVICES: description: "Enable Service deployment." value: "no" options: - "yes" - "no" DEPLOY_UMS: description: "Enable Nubus deployment." value: "no" options: - "yes" - "no" DEPLOY_COLLABORA: description: "Enable Collabora deployment." value: "no" options: - "yes" - "no" DEPLOY_CRYPTPAD: description: "Enable CryptPad deployment." value: "no" options: - "yes" - "no" DEPLOY_ELEMENT: description: "Enable Element deployment." value: "no" options: - "yes" - "no" DEPLOY_OX: description: "Enable OX AppSuite8 deployment." value: "no" options: - "yes" - "no" DEPLOY_XWIKI: description: "Enable XWiki deployment." value: "no" options: - "yes" - "no" DEPLOY_NEXTCLOUD: description: "Enable Nextcloud deployment." value: "no" options: - "yes" - "no" DEPLOY_OPENPROJECT: description: "Enable OpenProject deployment." value: "no" options: - "yes" - "no" DEPLOY_JITSI: description: "Enable Jitsi deployment." value: "no" options: - "yes" - "no" DEPLOY_NOTES: description: "Enable Notes deployment." value: "no" options: - "yes" - "no" CREATE_DEFAULT_ACCOUNTS: description: > Creates `default` and `default-admin` in the instance using the password defined as CI variable `DEFAULT_ACCOUNTS_PASSWORD`. value: "no" options: - "yes" - "no" DIFF_ON_BRANCH: description: "Provide a branch to run `helmfile diff` for the specified branch." value: "" RUN_TESTS: description: "Triggers execution of E2E-tests." value: "no" options: - "yes" - "no" RUN_RENOVATE: description: "Triggers the Renovate based check for dependency updates." value: "no" options: - "yes" - "no" TESTS_BRANCH: description: "Branch of E2E-tests on which the test pipeline is triggered" value: "develop" TESTS_TESTSET: description: > Selects test set for E2E-tests (Regression, Smoke or Nightly), name multiple comma separated to trigger the sets in one launch, use semikolon to trigger the sets in different launches. value: "Smoke" TESTS_BROWSER: description: "Select the browser (engine) to use for the test run." value: "chromium" options: - "chromium" - "webkit" - "firefox" TESTS_GRACE_PERIOD: description: > A new deployment sometimes needs a few minutes to sort itself. If tested too early tests may fail. Here you can set the time in seconds that should be waited before running the tests. value: "0" TESTS_NUMBER_OF_THREADS: description: "How many threads are used for executing the tests in parallel?" value: "8" TESTS_PROJECT_URL: description: "Project url for e2e-tests (`/api/v4/projects/`)" value: "gitlab.opencode.de/api/v4/projects/1506" HELM_IMAGE_PIN: description: "The Helm image tag/checksum." value: "1.3.3@sha256:3e195942e6988b8b93c62349700c0ed8428e3a8fbe2655bd7f5378dc88bc8ccb" # Declare .environments which is in `opendesk-env` repository. In case it is not available # 'cache' is used because job as a dummy key, as the job is not allowed to be empty. .environments: cache: {} .deploy-common: cache: {} dependencies: [] extends: ".environments" environment: name: "${NAMESPACE}" image: "registry.opencode.de/bmi/opendesk/components/platform-development/images/helm:${HELM_IMAGE_PIN}" script: - "cd ${CI_PROJECT_DIR}/helmfile/apps/${COMPONENT}" # MASTER_PASSWORD_WEB_VAR as precedence for MASTER_PASSWORD - | if ! [ -z "${MASTER_PASSWORD_WEB_VAR}" ]; then export MASTER_PASSWORD="${MASTER_PASSWORD_WEB_VAR}" fi; - > echo "Installing ${COMPONENT} into ${NAMESPACE} namespace as ${HELMFILE_ENVIRONMENT} environment on ${CLUSTER}" - "helmfile --namespace ${NAMESPACE} apply --suppress-diff ${ADDITIONAL_ARGS}" tags: - "docker" - "kubernetes" - "${CLUSTER}" variables: HELMFILE_ENVIRONMENT: "dev" db-cleanup: extends: ".deploy-common" image: "registry.opencode.de/bmi/opendesk/components/platform-development/images/opendesk-ci-toolbox:1.0.0\ @sha256:8c00f96cbfca32e4a724c552143c7172980dd03c573fb097e57a2351db6421ab" needs: - job: "env-cleanup" optional: true rules: - if: > $CI_PIPELINE_SOURCE =~ "web|schedules|trigger|api" && $NAMESPACE =~ /.+/ && $ENV_STOP_BEFORE != "no" && $FLUSH_EXTERNAL_SERVICES_BEFORE != "no" when: "on_success" script: # yamllint disable-line rule:line-length rule:quoted-strings - | echo "Checking FLUSH_EXTERNAL_SERVICES_TYPE value..." case "$FLUSH_EXTERNAL_SERVICES_TYPE" in "RUN") echo " ... running flush procedure for RUN cluster." ;; "STACKIT") echo " ... running flush procedure for STACKIT provider." ;; *) echo "ERROR: FLUSH_EXTERNAL_SERVICES_TYPE is not set to valid value." echo " Expected 'RUN' or 'STACKIT', got ${FLUSH_EXTERNAL_SERVICES_TYPE}." exit 1 ;; esac # First: Gather all files that contain the "database:" keyword in the default environment - | export FILES="$(grep -r 'databases:' "${CI_PROJECT_DIR}/helmfile/environments/default" | awk -F ':' '{print $1}')" # Second: Gather all files that contain the "database:" keyword in the dev environment # where the adjustments from opendesk-env are placed - | export FILES="${FILES} $(grep -r 'databases:' "${CI_PROJECT_DIR}/helmfile/environments/dev" | awk -F ':' '{print $1}')" - "echo \"${FILES[@]}\"" # Cleanup MariaDB - "export MARIADB_HOST=\"\"" - "export MARIADB_PORT=\"\"" - "export MARIADB_USERNAME=\"\"" - "export MARIADB_PASSWORD=\"\"" - "export ENV_DATABASE=\"oxAppSuite\"" # Parse cluster values - | for FILE in ${FILES[@]}; do if [ -f "${FILE}" ]; then if [[ $(tail -n +1 "${FILE}" | grep -v '{{' | yq '.databases.[env(ENV_DATABASE)]') != "null" ]]; then MARIADB_DATABASE=$(tail -n +1 $FILE | grep -v '{{' | yq '.databases.[env(ENV_DATABASE)].name') MARIADB_USERNAME=$(tail -n +1 $FILE | grep -v '{{' | yq '.databases.[env(ENV_DATABASE)].username') MARIADB_PASSWORD=$(tail -n +1 $FILE | grep -v '{{' | yq '.databases.[env(ENV_DATABASE)].password') MARIADB_HOST=$(tail -n +1 $FILE | grep -v '{{' | yq '.databases.[env(ENV_DATABASE)].host') MARIADB_PORT=$(tail -n +1 $FILE | grep -v '{{' | yq '.databases.[env(ENV_DATABASE)].port') fi; fi; done; - | export CONNECTION=( "--host=${MARIADB_HOST}" "--port=${MARIADB_PORT}" "--user=${MARIADB_USERNAME}" "--password=${MARIADB_PASSWORD}" "--skip-ssl" ) - "echo \"[mysql] [${ENV_DATABASE}] DROP ${MARIADB_DATABASE} on ${MARIADB_HOST}\"" - "mariadb ${CONNECTION[@]} -e \"DROP DATABASE IF EXISTS ${MARIADB_DATABASE};\"" - | if [ "${ENV_DATABASE}" = "oxAppSuite" ]; then echo "[mysql] [${ENV_DATABASE}] DROP oxguard on ${MARIADB_HOST}" mariadb ${CONNECTION[@]} -e "DROP DATABASE IF EXISTS oxguard;" echo "[mysql] [${ENV_DATABASE}] DROP oxguard_1 on ${MARIADB_HOST}" mariadb ${CONNECTION[@]} -e "DROP DATABASE IF EXISTS oxguard_1;" echo "[mysql] [${ENV_DATABASE}] DROP PRIMARYDB_9 on ${MARIADB_HOST}" mariadb ${CONNECTION[@]} -e "DROP DATABASE IF EXISTS PRIMARYDB_9;" else mariadb ${CONNECTION[@]} -e "CREATE DATABASE ${MARIADB_DATABASE};" mariadb ${CONNECTION[@]} -e "GRANT ALL PRIVILEGES ON ${MARIADB_DATABASE}.* TO ${MARIADB_USERNAME}@\"%\";" mariadb ${CONNECTION[@]} -e "FLUSH PRIVILEGES;" fi; # Cleanup PostgreSQL - | export DATABASES="keycloak keycloakExtension nextcloud notes openproject synapse umsGuardianManagementApi \ umsNotificationsApi umsSelfservice xwiki" export PGDATABASE="postgres" export PGHOST="" export PGPORT="" export PGUSER="" export PGPASSWORD="" export PGPARAMS="" for DATABASE in $DATABASES; do export ENV_DATABASE=${DATABASE} # Parse cluster values for FILE in ${FILES[@]}; do if [ -f $FILE ]; then if [[ $(tail -n +1 $FILE | grep -v '{{' | yq '.databases.[env(ENV_DATABASE)]') != "null" ]]; then POSTGRES_DATABASE=$(tail -n +1 $FILE | grep -v '{{' | yq '.databases.[env(ENV_DATABASE)].name') PGUSER=$(tail -n +1 $FILE | grep -v '{{' | yq '.databases.[env(ENV_DATABASE)].username') PGPASSWORD=$(tail -n +1 $FILE | grep -v '{{' | yq '.databases.[env(ENV_DATABASE)].password') PGHOST=$(tail -n +1 $FILE | grep -v '{{' | yq '.databases.[env(ENV_DATABASE)].host') PGPORT=$(tail -n +1 $FILE | grep -v '{{' | yq '.databases.[env(ENV_DATABASE)].port') PGPARAMS=$(tail -n +1 $FILE | grep -v '{{' | yq '.databases.[env(ENV_DATABASE)].parameters') fi; fi; done; case "$FLUSH_EXTERNAL_SERVICES_TYPE" in "STACKIT") # In case of STACKIT resources the db content should just be dropped echo "[psql] [${ENV_DATABASE}] DROP OWNED BY ${PGUSER} in ${POSTGRES_DATABASE} on ${PGHOST}" PGDATABASE=${POSTGRES_DATABASE} # env var PGDATABASE is interpreted by psql psql -c "DROP OWNED BY ${PGUSER};" || true; ;; "RUN") # Usually, e.g. in "RUN" cluster, databases can simply be dropped and recreated echo "[psql] [${ENV_DATABASE}] DROP ${POSTGRES_DATABASE} on ${PGHOST}" psql -c "DROP DATABASE ${POSTGRES_DATABASE}" || true; if [ "${PGPARAMS}" = "null" ]; then psql -c "CREATE DATABASE \"${POSTGRES_DATABASE}\";" else psql -c "CREATE DATABASE \"${POSTGRES_DATABASE}\" ${PGPARAMS};" fi; psql -c "ALTER DATABASE \"${POSTGRES_DATABASE}\" OWNER TO \"${PGUSER}\""; psql -c "GRANT ALL PRIVILEGES ON DATABASE \"${POSTGRES_DATABASE}\" TO \"${PGUSER}\""; ;; esac done; # Cleanup Objectstore - | export BUCKETS="migrations nextcloud openproject nubus notes openxchange dovecot" export AWS_DEFAULT_REGION="" export AWS_ENDPOINT="" export AWS_ACCESS_KEY_ID="" export AWS_SECRET_ACCESS_KEY="" for BUCKET in $BUCKETS; do export ENV_BUCKET=${BUCKET} # Parse cluster values for FILE in ${FILES[@]}; do if [ -f $FILE ]; then if [[ $(tail -n +1 $FILE | grep -v '{{' | yq '.objectstores.[env(ENV_BUCKET)]') != "null" ]]; then AWS_BUCKET=$(tail -n +1 $FILE | grep -v '{{' | yq '.objectstores.[env(ENV_BUCKET)].bucket') AWS_ENDPOINT=$(tail -n +1 $FILE | grep -v '{{' | yq '.objectstores.[env(ENV_BUCKET)].endpoint') AWS_ACCESS_KEY_ID=$(tail -n +1 $FILE | grep -v '{{' | yq '.objectstores.[env(ENV_BUCKET)].username') AWS_SECRET_ACCESS_KEY=$(tail -n +1 $FILE | grep -v '{{' | yq '.objectstores.[env(ENV_BUCKET)].secretKey') AWS_DEFAULT_REGION=$(tail -n +1 $FILE | grep -v '{{' | yq '.objectstores.[env(ENV_BUCKET)].region') fi; fi; done; aws s3 --endpoint "https://${AWS_ENDPOINT}" rm s3://${AWS_BUCKET} --recursive done; stage: "env-cleanup" env-cleanup: extends: ".deploy-common" rules: - if: > $CI_PIPELINE_SOURCE =~ "web|schedules|trigger|api" && $NAMESPACE =~ /.+/ && $ENV_STOP_BEFORE != "no" when: "on_success" script: - | echo "Cleaning up ${NAMESPACE}" if [ "${OPENDESK_SLEDGEHAMMER_DESTROY_ENABLED}" = "yes" ]; then for OPENDESK_RELEASE in $(helm ls -n ${NAMESPACE} -aq); do helm uninstall -n ${NAMESPACE} ${OPENDESK_RELEASE}; done # if you update the section below, please also update the respective section in getting_started.md kubectl delete pvc --all --namespace ${NAMESPACE}; kubectl delete jobs --all --namespace ${NAMESPACE}; kubectl delete configmaps --all --namespace ${NAMESPACE}; else helmfile destroy --namespace ${NAMESPACE}; fi stage: "env-cleanup" env-start: extends: ".deploy-common" image: "${CI_DEPENDENCY_PROXY_DIRECT_GROUP_IMAGE_PREFIX}/alpine/k8s:1.25.6" rules: - if: > $CI_PIPELINE_SOURCE =~ "web|schedules|trigger|api" && $NAMESPACE =~ /.+/ when: "on_success" script: - "echo \"Deploying to Environment ${NAMESPACE} in ${CLUSTER} Cluster\"" - "kubectl create namespace ${NAMESPACE} --dry-run=client -o yaml | kubectl apply -f -" - "export FILENAME_CERT_SECRET=cert_to_import.yaml" # from self-signed-certificates.md: # "Copy this cert's secret into the/each namespace you want to make use of the cert." - | kubectl get secret opendesk-root-cert-secret -n cert-manager -o yaml | \ grep -v \ uid\: | \ grep -v \ resourceVersion\: | \ grep -v \ creationTimestamp\: | \ sed --expression 's/namespace\:\ cert-manager/namespace: '"${NAMESPACE}"'/g' \ >${FILENAME_CERT_SECRET} || true - | if [ -s ${FILENAME_CERT_SECRET} ]; then echo "Applying ${FILENAME_CERT_SECRET}" kubectl apply -f ${FILENAME_CERT_SECRET} fi # from self-signed-certificates.md: # "Create issuer in the/each namespace you want to make use of the cert." - | kubectl apply -f - < $CI_PIPELINE_SOURCE =~ "web|schedules|trigger|api" && $NAMESPACE =~ /.+/ && ($DEPLOY_ALL_COMPONENTS != "no" || $DEPLOY_SERVICES != "no") when: "on_success" variables: COMPONENT: "opendesk-services" ADDITIONAL_ARGS: "-l name=opendesk-otterize" migrations-pre: stage: "010-migrations-pre" extends: ".deploy-common" rules: - if: > $CI_PIPELINE_SOURCE =~ "web|schedules|trigger|api" && $NAMESPACE =~ /.+/ && ($DEPLOY_ALL_COMPONENTS != "no" || $DEPLOY_MIGRATIONS != "no") when: "on_success" variables: COMPONENT: "opendesk-migrations-pre" migrations-post: stage: "090-migrations-post" extends: ".deploy-common" rules: - if: > $CI_PIPELINE_SOURCE =~ "web|schedules|trigger|api" && $NAMESPACE =~ /.+/ && ($DEPLOY_ALL_COMPONENTS != "no" || $DEPLOY_MIGRATIONS != "no") when: "on_success" variables: COMPONENT: "opendesk-migrations-post" services-external-deploy: stage: "030-services" extends: ".deploy-common" rules: - if: > $CI_PIPELINE_SOURCE =~ "web|schedules|trigger|api" && $NAMESPACE =~ /.+/ && ($DEPLOY_ALL_COMPONENTS != "no" || $DEPLOY_SERVICES != "no") when: "on_success" variables: COMPONENT: "services-external" opendesk-services-deploy: stage: "030-services" extends: ".deploy-common" rules: - if: > $CI_PIPELINE_SOURCE =~ "web|schedules|trigger|api" && $NAMESPACE =~ /.+/ && ($DEPLOY_ALL_COMPONENTS != "no" || $DEPLOY_SERVICES != "no") when: "on_success" variables: COMPONENT: "opendesk-services" nubus-deploy: stage: "050-components" extends: ".deploy-common" rules: - if: > $CI_PIPELINE_SOURCE =~ "web|schedules|trigger|api" && $NAMESPACE =~ /.+/ && ($DEPLOY_ALL_COMPONENTS != "no" || $DEPLOY_UMS != "no") when: "on_success" variables: COMPONENT: "nubus" ox-deploy: stage: "050-components" extends: ".deploy-common" timeout: "30m" rules: - if: > $CI_PIPELINE_SOURCE =~ "web|schedules|trigger|api" && $NAMESPACE =~ /.+/ && ($DEPLOY_ALL_COMPONENTS != "no" || $DEPLOY_OX != "no") when: "on_success" variables: COMPONENT: "open-xchange" xwiki-deploy: stage: "050-components" extends: ".deploy-common" rules: - if: > $CI_PIPELINE_SOURCE =~ "web|schedules|trigger|api" && $NAMESPACE =~ /.+/ && ($DEPLOY_ALL_COMPONENTS != "no" || $DEPLOY_XWIKI != "no") when: "on_success" variables: COMPONENT: "xwiki" collabora-deploy: stage: "050-components" extends: ".deploy-common" rules: - if: > $CI_PIPELINE_SOURCE =~ "web|schedules|trigger|api" && $NAMESPACE =~ /.+/ && ($DEPLOY_ALL_COMPONENTS != "no" || $DEPLOY_NEXTCLOUD != "no" || $DEPLOY_COLLABORA != "no") when: "on_success" variables: COMPONENT: "collabora" cryptpad-deploy: stage: "050-components" extends: ".deploy-common" rules: - if: > $CI_PIPELINE_SOURCE =~ "web|schedules|trigger|api" && $NAMESPACE =~ /.+/ && ($DEPLOY_ALL_COMPONENTS != "no" || $DEPLOY_NEXTCLOUD != "no" || $DEPLOY_CRYPTPAD != "no") when: "on_success" variables: COMPONENT: "cryptpad" nextcloud-deploy: stage: "050-components" extends: ".deploy-common" rules: - if: > $CI_PIPELINE_SOURCE =~ "web|schedules|trigger|api" && $NAMESPACE =~ /.+/ && ($DEPLOY_ALL_COMPONENTS != "no" || $DEPLOY_NEXTCLOUD != "no") when: "on_success" variables: COMPONENT: "nextcloud" openproject-deploy: stage: "050-components" extends: ".deploy-common" rules: - if: > $CI_PIPELINE_SOURCE =~ "web|schedules|trigger|api" && $NAMESPACE =~ /.+/ && ($DEPLOY_ALL_COMPONENTS != "no" || $DEPLOY_OPENPROJECT != "no") when: "on_success" variables: COMPONENT: "openproject" openproject-bootstrap-deploy: stage: "060-components" extends: ".deploy-common" rules: - if: > $CI_PIPELINE_SOURCE =~ "web|schedules|trigger|api" && $NAMESPACE =~ /.+/ && ($DEPLOY_ALL_COMPONENTS != "no" || ($DEPLOY_OPENPROJECT != "no" && $DEPLOY_NEXTCLOUD != "no")) when: "on_success" variables: COMPONENT: "opendesk-openproject-bootstrap" jitsi-deploy: stage: "050-components" extends: ".deploy-common" rules: - if: > $CI_PIPELINE_SOURCE =~ "web|schedules|trigger|api" && $NAMESPACE =~ /.+/ && ($DEPLOY_ALL_COMPONENTS != "no" || $DEPLOY_JITSI != "no") when: "on_success" variables: COMPONENT: "jitsi" notes-deploy: stage: "050-components" extends: ".deploy-common" rules: - if: > $CI_PIPELINE_SOURCE =~ "web|schedules|trigger|api" && $NAMESPACE =~ /.+/ && ($DEPLOY_ALL_COMPONENTS != "no" || $DEPLOY_NOTES != "no") when: "on_success" variables: COMPONENT: "notes" element-deploy: stage: "050-components" extends: ".deploy-common" rules: - if: > $CI_PIPELINE_SOURCE =~ "web|schedules|trigger|api" && $NAMESPACE =~ /.+/ && ($DEPLOY_ALL_COMPONENTS != "no" || $DEPLOY_ELEMENT != "no") when: "on_success" variables: COMPONENT: "element" fetch-administrator-credentials: extends: ".deploy-common" stage: "post-prepare" rules: - if: > $CI_PIPELINE_SOURCE =~ "web|schedules|trigger|api" && $NAMESPACE =~ /.+/ && ($CREATE_DEFAULT_ACCOUNTS == "yes" || $RUN_TESTS == "yes") when: "on_success" script: - | echo "DEFAULT_ADMINISTRATOR_PASSWORD=$( kubectl \ -n ${NAMESPACE} \ get secret ums-nubus-credentials \ -o jsonpath='{.data.administrator_password}' | base64 -d \ )" >> .env artifacts: reports: dotenv: ".env" diff-on-branch: stage: "post-execute" cache: {} dependencies: [] extends: ".environments" environment: name: "${NAMESPACE}" image: "registry.opencode.de/bmi/opendesk/components/platform-development/images/helm:${HELM_IMAGE_PIN}" rules: - if: "$DIFF_ON_BRANCH" script: - | echo "Downloading branch ${DIFF_ON_BRANCH}" SAFE_BRANCH_NAME=$(echo "$DIFF_ON_BRANCH" | tr '/' '-') BASE_URL="https://gitlab.opencode.de/bmi/opendesk/deployment/opendesk/-/archive" FILE_NAME="opendesk-${SAFE_BRANCH_NAME}.tar.gz" curl -L "${BASE_URL}/${DIFF_ON_BRANCH}/${FILE_NAME}" -o branch.tar.gz mkdir ${DIFF_ON_BRANCH_SUBDIRECTORY} && tar -xzf branch.tar.gz -C ${DIFF_ON_BRANCH_SUBDIRECTORY} --strip-components=1 cd ${DIFF_ON_BRANCH_SUBDIRECTORY} helmfile --namespace ${NAMESPACE} diff | grep -v '^ ' || true tags: - "docker" - "kubernetes" - "${CLUSTER}" variables: HELMFILE_ENVIRONMENT: "dev" DIFF_ON_BRANCH_SUBDIRECTORY: "diff-on-branch" import-default-accounts: stage: "post-execute" extends: ".environments" dependencies: - "fetch-administrator-credentials" environment: name: "${NAMESPACE}" rules: - if: > $CI_PIPELINE_SOURCE =~ "web|schedules|trigger|api" && $NAMESPACE =~ /.+/ && $CREATE_DEFAULT_ACCOUNTS == "yes" when: "on_success" image: "registry.opencode.de/bmi/opendesk/components/platform-development/images/user-import:3.4.1" script: - "echo \"Starting default account import for ${DOMAIN}\"" - "cd /app" - | ./user_import_udm_rest_api.py \ --import_domain ${DOMAIN} \ --udm_api_password ${DEFAULT_ADMINISTRATOR_PASSWORD} \ --set_default_password ${DEFAULT_ACCOUNTS_PASSWORD} \ --import_filename ./template.ods \ --admin_enable_fileshare True \ --admin_enable_knowledgemanagement True \ --admin_enable_projectmanagement True \ --create_admin_accounts True \ --create_maildomains True \ --verify_certificate False run-tests: stage: "post-execute" extends: ".deploy-common" dependencies: - "fetch-administrator-credentials" environment: name: "${NAMESPACE}" rules: - if: > $CI_PIPELINE_SOURCE =~ "web|schedules|trigger|api" && $NAMESPACE =~ /.+/ && $RUN_TESTS == "yes" when: "on_success" parallel: matrix: - LANGUAGE: - "de" - "en" script: - | if [ "${LANGUAGE}" = "en" ]; then sleep 30 fi - | curl --request POST \ --header "Content-Type: application/json" \ --data "{ \ \"ref\": \"${TESTS_BRANCH}\", \ \"token\": \"${CI_JOB_TOKEN}\", \ \"variables\": { \ \"operator\": \"${OPERATOR}\", \ \"cluster\": \"${CLUSTER}\", \ \"namespace\": \"${NAMESPACE}\", \ \"url\": \"https://portal.${DOMAIN}/\", \ \"language\": \"${LANGUAGE}\", \ \"browser\": \"${TESTS_BROWSER}\", \ \"udm_api_username\": \"Administrator\", \ \"udm_api_password\": \"${DEFAULT_ADMINISTRATOR_PASSWORD}\", \ \"screenshot_test\": \"yes\", \ \"screenshot_before_step\": \"yes\", \ \"screenshot_after_step\": \"yes\", \ \"screenshot_redirect_step\": \"yes\", \ \"testset\": \"${TESTS_TESTSET}\", \ \"testprofile\": \"Namespace\", \ \"OPENDESK_ENTERPRISE\": \"${OPENDESK_ENTERPRISE}\", \ \"GRACE_PERIOD\": \"${TESTS_GRACE_PERIOD}\", \ \"NUMBER_OF_THREADS\": \"${TESTS_NUMBER_OF_THREADS}\" \ } \ }" \ "https://${TESTS_PROJECT_URL}/trigger/pipeline" retry: 1 avscan-prepare: stage: ".pre" rules: - if: > $JOB_AVSCAN_ENABLED != 'false' && $CI_COMMIT_BRANCH == $RELEASE_BRANCH && $CI_PIPELINE_SOURCE =~ "push|merge_request_event" when: "always" - when: "never" image: "${CI_DEPENDENCY_PROXY_DIRECT_GROUP_IMAGE_PREFIX}/mikefarah/yq" script: - | cat << 'EOF' > dynamic-scans.yml --- stages: - "scan" .container-clamav: stage: "scan" image: "registry.opencode.de/bmi/opendesk/components/platform-development/images/clamav-imagescan:1.0.0" before_script: - "mkdir -p ~/.docker" - | cat << EOF > ~/.docker/config.json { "auths": { "$CI_REGISTRY": { "auth": "$(printf %s:%s ${CI_REGISTRY_USER} ${CI_REGISTRY_PASSWORD} | base64 | tr -d '\n')" } } } EOF - "sed -i \"/^DatabaseMirror .*$/c DatabaseMirror ${DATABASE_MIRROR}\" /etc/clamav/freshclam.conf" - "freshclam" - "mkdir /scan" script: - "export IMAGE=${AV_SCAN_PROXY:-${CONTAINER_REGISTRY}}/${CONTAINER_IMAGE}:${CONTAINER_TAG}" - "echo Pulling and scanning $IMAGE..." - "crane pull $IMAGE /scan/image.tar" - "clamscan /scan" variables: CONTAINER_IMAGE: "" CONTAINER_REGISTRY: "" CONTAINER_TAG: "" DATABASE_MIRROR: "https://gitlab.opencode.de/bmi/opendesk/tooling/clamav-db-mirror/-/raw/main" EOF - > yq '.images | with_entries(.key |= "scan-" + .) | .[].extends=".container-clamav" | with(.[]; .variables.CONTAINER_IMAGE = .repository | .variables.CONTAINER_TAG = .tag | .variables.CONTAINER_REGISTRY = .registry) | del(.[].repository) | del(.[].tag) | del(.[].registry)' helmfile/environments/default/images.yaml.gotmpl >> dynamic-scans.yml artifacts: paths: - "dynamic-scans.yml" avscan-start: stage: "scan" rules: - if: > $JOB_AVSCAN_ENABLED != 'false' && $CI_COMMIT_BRANCH == $RELEASE_BRANCH && $CI_PIPELINE_SOURCE =~ "push|merge_request_event" when: "always" - when: "never" trigger: include: - artifact: "dynamic-scans.yml" job: "avscan-prepare" strategy: "depend" ...