Newer
Older
include:
- /.gitlab/ci_templates/kaniko.yml
- /.gitlab/ci_templates/ssh_setup.yml
- template: 'Workflows/MergeRequest-Pipelines.gitlab-ci.yml'
# Global templates and YAML anchors
# =================================
# Used in various stages/job definitions
# We don't use a `before_script` definition here because `extend` doesn't merge
# `before_script` but rather overwrites it.
# So we rather use [yaml anchors](https://docs.gitlab.com/ce/ci/yaml/README.html#anchors)
# here. Unfortunatly, anchors can't get included from files so we need to
# define them here.
.debug_information: &debug_information
- |
echo "Env vars:"
echo
echo "HOSTNAME: $HOSTNAME"
echo "CLUSTER_DIR: $CLUSTER_DIR"
echo "ANSIBLE_HOST_KEY_CHECKING: $ANSIBLE_HOST_KEY_CHECKING"
echo "KANIKO_BUILD_IMAGENAME: $KANIKO_BUILD_IMAGENAME"
echo "KANIKO build image ref: ${CI_REGISTRY_IMAGE}/${KANIKO_BUILD_IMAGENAME}:${CI_CONTAINER_TAG}"
echo "SSH_KEY_ID: $SSH_KEY_ID"
echo
[ -d $CLUSTER_DIR ] && find $CLUSTER_DIR || echo "directory ${CLUSTER_DIR} not found"
echo
echo
# The dotenv report requires us to report the artifacts in every job that is
# required with a `needs:` from another job.
.report_artifacts:
artifacts:
paths:
- clusters
expire_in: 1 month
when: always
reports:
dotenv:
$CLUSTER_DIR/.cluster.env
# Rules that enable the cluster to be built and are applied to most steps
# (except for application-specific steps)
.general_rules:
rules:
- changes:
- .gitlab-ci.yml
- .gitlab/ci_scripts/*
- ansible/**/*
- flux/**/*
- test/**/*
- openappstack/**/*
# Define the rules when/if app specific jobs are run.
# Just add the variable RESOURCE to the job like this:
# and import the templates with i.e.
# extends: .eventrouter_rules
# .eventrouter_rules will ensure that the job is only executed:
# - when files related to the app changed in the repo
# - A pipeline gets started from the UI and the job name is included in the
# CI variable `TRIGGER_JOBS`
# - A commit is pushed containing the pattern TRIGGER_JOBS=.*<job name>
# (i.e. TRIGGER_JOBS=ci-test-image-build,enable-nextcloud)
#
# Gitlab CI allows pushing CI vars via `git push` but a bug prevents this when
# using merge request pipelines (see https://gitlab.com/gitlab-org/gitlab/-/issues/326098)
.eventrouter_rules:
extends:
- .general_rules
.loki_rules:
extends:
- .general_rules
.promtail_rules:
extends:
- .general_rules
.nextcloud_rules:
rules:
- changes:
- flux2/apps/$RESOURCE/*.yaml
- flux2/cluster/optional/$RESOURCE/*.yaml
- flux2/infrastructure/sources/nextcloud.yaml
- if: '$TRIGGER_JOBS =~ /enable-nextcloud/'
- if: '$CI_COMMIT_MESSAGE =~ /TRIGGER_JOBS=.*enable-nextcloud/'
extends:
- .general_rules
extends:
- .general_rules

Maarten de Waard
committed
.local_path_provisioner_rules:
extends:
- .general_rules
.rocketchat_rules:
rules:
- changes:
- flux2/apps/$RESOURCE/*.yaml
- flux2/cluster/optional/$RESOURCE/*.yaml
- flux2/infrastructure/sources/helm-stable.yaml
- if: '$TRIGGER_JOBS =~ /enable-rocketchat/'
- if: '$CI_COMMIT_MESSAGE =~ /TRIGGER_JOBS=.*enable-rocketchat/'
.single_sign_on_rules:
rules:
- changes:
- flux2/infrastructure/sources/single-sign-on.yaml
- if: '$TRIGGER_JOBS =~ /enable-single-sign-on/'
- if: '$CI_COMMIT_MESSAGE =~ /TRIGGER_JOBS=.*enable-single-sign-on/'
- flux2/apps/$RESOURCE/*.yaml
- flux2/cluster/optional/$RESOURCE/*.yaml
- flux2/infrastructure/sources/wekan.yaml
- install/install-app.sh
- test/taiko/*
- if: '$TRIGGER_JOBS =~ /enable-wekan/'
- if: '$CI_COMMIT_MESSAGE =~ /TRIGGER_JOBS=.*enable-wekan/'
- if: '$CI_COMMIT_BRANCH == "master"'
.wordpress_rules:
rules:
- changes:
- flux2/apps/$RESOURCE/*.yaml
- flux2/cluster/optional/$RESOURCE/*.yaml
- flux2/infrastructure/sources/wordpress.yaml
- if: '$TRIGGER_JOBS =~ /enable-wordpress/'
- if: '$CI_COMMIT_MESSAGE =~ /TRIGGER_JOBS=.*enable-wordpress/'
# Global declarations
# ===================
# https://docs.gitlab.com/ee/ci/yaml/README.html#workflowrules-templates
- setup-cluster
- kustomization
- base-helm-release
- install-apps
- apps-helm-release
- health-test
- integration-test
KANIKO_BUILD_IMAGENAME: "openappstack-ci"
CLUSTER_DIR: "/builds/openappstack/openappstack/clusters/${CI_COMMIT_REF_SLUG}"
image: "${CI_REGISTRY_IMAGE}/${KANIKO_BUILD_IMAGENAME}:${CI_CONTAINER_TAG}"
# There are 2 moments in which we (re)build the container image. If some files are
# changed, or when the job is triggered with TRIGGER_JOBS.
stage: build
before_script:
- *debug_information
after_script:
- |
echo "CI_CONTAINER_TAG=${CI_COMMIT_REF_SLUG}" > .ci.env
artifacts:
paths:
- .ci.env
expire_in: 1 month
when: always
reports:
dotenv:
.ci.env
environment:
name: image/$CI_COMMIT_REF_SLUG
url: https://open.greenhost.net:4567/openappstack/openappstack/openappstack-ci:${CI_COMMIT_REF_SLUG}
on_stop: delete-image
auto_stop_in: 3 weeks
# Automatically rebuild the container image if this file, the Dockerfile,
# the installed requirements or the kaniko template change
- changes:
- Dockerfile
- requirements.txt
- .gitlab/ci_templates/kaniko.yml
# Also rebuild when the CI variable contain this jobs name
# or commit msg contains /TRIGGER_JOBS=.*ci-test-image-build/
- if: '$TRIGGER_JOBS =~ /ci-test-image-build/'
- if: '$CI_COMMIT_MESSAGE =~ /TRIGGER_JOBS=.*ci-test-image-build/'

Maarten de Waard
committed
interruptible: true
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
report-ci-image-tag:
stage: build
image: "curlimages/curl"
before_script:
- *debug_information
script:
- |
TAG_INFORMATION=$(curl https://open.greenhost.net/api/v4/projects/openappstack%2Fopenappstack/registry/repositories/2/tags/${CI_COMMIT_REF_SLUG});
echo "Tag information: ${TAG_INFORMATION}"
if [ "$TAG_INFORMATION" == '{"message":"404 Tag Not Found"}' ]; then
echo "CI_CONTAINER_TAG=master" > .ci.env
else
echo "CI_CONTAINER_TAG=${CI_COMMIT_REF_SLUG}" > .ci.env
fi
artifacts:
paths:
- .ci.env
expire_in: 1 month
when: always
reports:
dotenv:
.ci.env
rules:
# Make sure this job does not run if ci-test-image-build runs
- changes:
- Dockerfile
- requirements.txt
when: never # Never run on file changes that trigger ci-test-image-build
- if: '$TRIGGER_JOBS =~ /ci-test-image-build/'
when: never # Never run when ci-test-image is triggered manually
- if: '$CI_COMMIT_MESSAGE =~ /TRIGGER_JOBS=.*ci-test-image-build/'
when: never # Never run when ci-test-image is triggered manually
- when: always
interruptible: true
# Stage: create-vps
# =================
#
# Creates the vps for the pipeline
variables:
SUBDOMAIN: "${CI_COMMIT_REF_SLUG}.ci"
DOMAIN: "openappstack.net"
# Creates a VPS based on a custom CI image for which the ansible playbook
# has already run. See CONTRIBUTING.md#ci-pipeline-image for more info
- bash .gitlab/ci_scripts/create_vps.sh
# Make sure .ci.env variables are not lost
- cat .ci.env >> ${CLUSTER_DIR}/.cluster.env
- .report_artifacts
- .general_rules
environment:
name: $CI_COMMIT_REF_SLUG
url: https://$FQDN
on_stop: terminate-droplet
auto_stop_in: 1 week

Maarten de Waard
committed
interruptible: true
# Stage: setup-cluster
# ====================
#
# Installs OAS
needs:
- job: create-vps
script:
- *debug_information
- cd ansible/
- pytest -v -s -m 'dns' --connection=ansible --ansible-inventory=${CLUSTER_DIR}/inventory.yml --hosts='ansible://*'
# Copy inventory files to ansible folder for use in install-apps step
- cp ${CLUSTER_DIR}/inventory.yml ansible/
- python3 -m openappstack $HOSTNAME install
# Customize env file, remove all comments and empty lines
- sed "s/1.2.3.4/$IP_ADDRESS/; s/example.org/$FQDN/; s/acme_staging=false/acme_staging=true/; s/acme-v02/acme-staging-v02/; /^\s*#.*$/d; /^\s*$/d" install/.flux.env.example >> ${CLUSTER_DIR}/.flux.env
- cp install/kustomization.yaml ${CLUSTER_DIR}
- bash ./install/install-openappstack.sh
# - cd ansible
# - ansible master -m shell -a 'oas-version-info.sh 2>&1'
- .report_artifacts
- .general_rules
# Tests if all kustomizations are ready
.kustomization-ready:
stage: kustomization
needs:
- job: setup-openappstack
- job: test-dns
- export KUBECONFIG="${PWD}/../clusters/${HOSTNAME}/kube_config_cluster.yml"
- pytest -v -s -m 'kustomizations' --resource="$RESOURCE" --connection=ansible --ansible-inventory=${CLUSTER_DIR}/inventory.yml --hosts='ansible://*' --reruns 120 --reruns-delay 20
infrastructure-kustomizations-ready:
variables:
RESOURCE: "infrastructure"
extends:
- .kustomization-ready
monitoring-kustomizations-ready:
variables:
RESOURCE: "monitoring"
extends:
- .kustomization-ready
openappstack-kustomizations-ready:
variables:
RESOURCE: "openappstack"
extends:
- .kustomization-ready
- export KUBECONFIG="${PWD}/../clusters/${HOSTNAME}/kube_config_cluster.yml"
- pytest -v -s -m 'helmreleases' --resource="$RESOURCE" --namespace="$NAMESPACE" --connection=ansible --ansible-inventory=${CLUSTER_DIR}/inventory.yml --hosts='ansible://*' --reruns 120 --reruns-delay 20
# Stage: base-helm-release
# ==================
#
# Checks helmreleases for oas base are ready
.base-helm-release:
stage: base-helm-release
needs:
- job: core-kustomizations-ready
- job: infrastructure-kustomizations-ready
- job: openappstack-kustomizations-ready
- job: setup-openappstack
- job: test-dns
extends:
- .helm-release
cert-manager-helm-release:
variables:

Maarten de Waard
committed
local-path-provisioner-helm-release:
variables:

Maarten de Waard
committed
extends:

Maarten de Waard
committed
- .local_path_provisioner_rules
- .kube_prometheus_stack_rules
# Stage: install-apps
# ==================
#
# Checks if application needs to get installed
.enable_app_template:
stage: install-apps
script:
- *debug_information
# Add optional override values we need for the CI pipeline only
- '[ -f ./install/overrides/oas-${RESOURCE}-override.yaml ] && kubectl apply -n oas-apps -f ./install/overrides/oas-${RESOURCE}-override.yaml'
- bash ./install/install-app.sh ${RESOURCE}
extends:
- .ssh_setup
interruptible: true
enable-nextcloud:
variables:
extends:
- .enable_app_template
- .nextcloud_rules
enable-rocketchat:
extends:
- .enable_app_template
- .wordpress_rules
# Stage: apps-helm-release
# ====================
#
# Tests if all helm releases are ready
.apps-helm-release:
stage: apps-helm-release
interruptible: true
nextcloud-helm-release:
variables:
- job: core-kustomizations-ready
- job: infrastructure-kustomizations-ready
- job: openappstack-kustomizations-ready
- job: setup-openappstack
- job: test-dns
- job: enable-nextcloud
extends:
- .apps-helm-release
- .nextcloud_rules
rocketchat-helm-release:
variables:
- job: core-kustomizations-ready
- job: infrastructure-kustomizations-ready
- job: openappstack-kustomizations-ready
- job: setup-openappstack
- job: test-dns
- job: enable-rocketchat
extends:
- .apps-helm-release
- .rocketchat_rules
- job: core-kustomizations-ready
- job: infrastructure-kustomizations-ready
- job: openappstack-kustomizations-ready
- job: setup-openappstack
- job: test-dns
- job: enable-wekan
extends:
- .apps-helm-release
- .wekan_rules
- job: core-kustomizations-ready
- job: infrastructure-kustomizations-ready
- job: openappstack-kustomizations-ready
- job: setup-openappstack
- job: test-dns
- job: enable-wordpress
script:
- *debug_information
- cd ansible/
- export KUBECONFIG="${PWD}/../clusters/${HOSTNAME}/kube_config_cluster.yml"
- pytest -v -s -m 'deployments' --resource="$RESOURCE" --namespace="$NAMESPACE" --connection=ansible --ansible-inventory=${CLUSTER_DIR}/inventory.yml --hosts='ansible://*' --reruns 120 --reruns-delay 10
.apps-statefulset:
stage: apps-ready
script:
- *debug_information
- cd ansible/
- export KUBECONFIG="${PWD}/../clusters/${HOSTNAME}/kube_config_cluster.yml"
- pytest -v -s -m 'statefulsets' --resource="$RESOURCE" --namespace="$NAMESPACE" --connection=ansible --ansible-inventory=${CLUSTER_DIR}/inventory.yml --hosts='ansible://*' --reruns 120 --reruns-delay 10
extends:
- .ssh_setup
interruptible: true
.apps-daemonset:
stage: apps-ready
script:
- *debug_information
- cd ansible/
- export KUBECONFIG="${PWD}/../clusters/${HOSTNAME}/kube_config_cluster.yml"
- pytest -v -s -m 'daemonsets' --resource="$RESOURCE" --namespace="$NAMESPACE" --connection=ansible --ansible-inventory=${CLUSTER_DIR}/inventory.yml --hosts='ansible://*' --reruns 120 --reruns-delay 10
extends:
- .ssh_setup
interruptible: true
needs:
- job: cert-manager-helm-release
- job: setup-openappstack # Needs makes sure the artifacts from that job are downloaded
- job: setup-openappstack

Maarten de Waard
committed
variables:

Maarten de Waard
committed
needs:
- job: local-path-provisioner-helm-release
- job: setup-openappstack
extends:

Maarten de Waard
committed
- .local_path_provisioner_rules
needs:
- job: loki-helm-release
- job: setup-openappstack
extends:
- job: setup-openappstack
- job: setup-openappstack
- job: setup-openappstack
- .kube_prometheus_stack_rules
- job: setup-openappstack
- job: setup-openappstack
needs:
- job: wekan-helm-release
- job: setup-openappstack
extends:
- job: setup-openappstack
- pytest -v -s -m 'certs' --resource="$RESOURCE" --connection=ansible --ansible-inventory=${CLUSTER_DIR}/inventory.yml --hosts='ansible://*' --reruns 120 --reruns-delay 10
- job: setup-openappstack
extends:
- .apps-cert
- .nextcloud_rules
- job: setup-openappstack
- .kube_prometheus_stack_rules
- job: setup-openappstack
extends:
- .apps-cert
- .rocketchat_rules
- job: setup-openappstack
extends:
- .apps-cert
- .single_sign_on_rules
- job: setup-openappstack
extends:
- .apps-cert
- .wekan_rules
- job: setup-openappstack
extends:
- .apps-cert
- .wordpress_rules
# Stage: health-test
# ==================
#
# General cluster health checks
testinfra:
- pytest -v -s -m 'testinfra' --connection=ansible --ansible-inventory=${CLUSTER_DIR}/inventory.yml --hosts='ansible://*'
# RESOURCE var is used in job specific rules (i.e. .kube_prometheus_stack_rules)
RESOURCE: "kube-prometheus-stack"
# Enforce python requests using the system cert store, where LE staging
# cacert is added
REQUESTS_CA_BUNDLE: "/etc/ssl/certs/ca-certificates.crt"
- export BASIC_AUTH_PW=$(python3 -m openappstack $HOSTNAME secrets | grep oas-prometheus-basic-auth | cut -d'=' -f2)
- pytest -s -m 'prometheus' --connection=ansible --ansible-inventory=${CLUSTER_DIR}/inventory.yml --hosts='ansible://*'
- .kube_prometheus_stack_rules
- job: setup-openappstack
# Stage: integration-test
# =======================
#
- job: setup-openappstack
- .kube_prometheus_stack_rules
- job: setup-openappstack
- job: setup-openappstack
needs:
- job: wekan-cert
- job: setup-openappstack
extends:
- .taiko
- .wekan_rules
- job: setup-openappstack
# Terminates a droplet once the branch for it is deleted
terminate-droplet:
# Stage has to be the same as the step that created the VPS
# https://docs.gitlab.com/ee/ci/environments.html#automatically-stopping-an-environment
stage: create-vps
# Gets triggered by on_stop of create-vps job
when: manual
variables:
GIT_STRATEGY: none
- python3 -c "import greenhost_cloud; greenhost_cloud.terminate_droplets_by_name(\"^${CI_COMMIT_REF_SLUG}\")"
environment:
name: $CI_COMMIT_REF_SLUG
action: stop
# Careful! When you run this step manually, you might have to trigger container
stage: build
when: manual
variables:
GIT_STRATEGY: none
script:
- *debug_information
- "curl --request DELETE --header \"PRIVATE-TOKEN: ${CLEANER_TOKEN}\" https://open.greenhost.net/api/v4/projects/openappstack%2Fopenappstack/registry/repositories/2/tags/${CI_COMMIT_REF_SLUG}"
environment:
action: stop