diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml index 79fcba7f330baca65ac81e62e4024cefde53228f..2ae11a983fe440dbbf3d58e5e7fa9ed59f3d5628 100644 --- a/.gitlab-ci.yml +++ b/.gitlab-ci.yml @@ -1,5 +1,6 @@ include: - .gitlab/ci_templates/kaniko.yml + - .gitlab/ci_templates/ssh_setup.yml stages: - build - setup-cluster @@ -36,14 +37,7 @@ ci_test_image: bootstrap: stage: setup-cluster - before_script: - - ansible --version script: - # Ensure test/ is not world-writable otherwise ansible-playbook refuses to run, see - # https://docs.ansible.com/ansible/devel/reference_appendices/config.html#cfg-in-world-writable-dir - - chmod 755 ansible/ - - eval $(ssh-agent -s) - - echo "$SSH_PRIVATE_KEY" | tr -d '\r' | ssh-add - > /dev/null - echo "hostname $HOSTNAME, subdomain $SUBDOMAIN, domain $DOMAIN, address $ADDRESS" - python3 -m openappstack $HOSTNAME create --create-droplet $DOMAIN --hostname $HOSTNAME --ssh-key-id $SSH_KEY_ID --create-domain-records --subdomain $SUBDOMAIN - python3 -m openappstack $HOSTNAME install --ansible-param='--skip-tags=helmfile' @@ -59,17 +53,11 @@ bootstrap: - helmfiles/**/* - test/**/* - openappstack/**/* + extends: .ssh_setup install: stage: install-apps - variables: - ANSIBLE_HOST_KEY_CHECKING: 'False' script: - # Ensure test/ is not world-writable otherwise ansible-playbook refuses to run, see - # https://docs.ansible.com/ansible/devel/reference_appendices/config.html#cfg-in-world-writable-dir - - chmod 755 ansible/ - - eval $(ssh-agent -s) - - echo "$SSH_PRIVATE_KEY" | tr -d '\r' | ssh-add - > /dev/null - python3 -m openappstack $HOSTNAME install --ansible-param='--tags=helmfile' # Show versions of installed apps/binaries - ansible master -m shell -a 'oas-version-info.sh 2>&1' @@ -85,14 +73,11 @@ install: - helmfiles/**/* - test/**/* - openappstack/**/* + extends: .ssh_setup testinfra: stage: health-test script: - - mkdir ~/.ssh - - eval $(ssh-agent -s) - - echo "$SSH_PRIVATE_KEY" | tr -d '\r' | ssh-add - > /dev/null - - echo -e 'Host *\n stricthostkeychecking no' > ~/.ssh/config - cd ansible/ - pytest -v -m 'testinfra' --connection=ansible --ansible-inventory=../clusters/${HOSTNAME}/inventory.yml --hosts='ansible://*' only: @@ -102,15 +87,12 @@ testinfra: - helmfiles/**/* - test/**/* - openappstack/**/* + extends: .ssh_setup certs: stage: health-test allow_failure: true script: - - mkdir ~/.ssh - - eval $(ssh-agent -s) - - echo "$SSH_PRIVATE_KEY" | tr -d '\r' | ssh-add - > /dev/null - - echo -e 'Host *\n stricthostkeychecking no' > ~/.ssh/config - cd ansible/ - pytest -s -m 'certs' --connection=ansible --ansible-inventory=../clusters/${HOSTNAME}/inventory.yml --hosts='ansible://*' only: @@ -120,6 +102,7 @@ certs: - helmfiles/**/* - test/**/* - openappstack/**/* + extends: .ssh_setup prometheus-alerts: stage: health-test @@ -127,10 +110,6 @@ prometheus-alerts: OAS_DOMAIN: 'ci-${CI_PIPELINE_ID}.ci.openappstack.net' allow_failure: true script: - - mkdir ~/.ssh - - eval $(ssh-agent -s) - - echo "$SSH_PRIVATE_KEY" | tr -d '\r' | ssh-add - > /dev/null - - echo -e 'Host *\n stricthostkeychecking no' > ~/.ssh/config - cd test/ - pytest -s -m 'prometheus' --connection=ansible --ansible-inventory=../clusters/${HOSTNAME}/inventory.yml --hosts='ansible://*' only: @@ -139,6 +118,7 @@ prometheus-alerts: - ansible/**/* - helmfiles/**/* - test/**/* + extends: .ssh_setup behave-nextcloud: stage: integration-test diff --git a/.gitlab/ci_templates/ssh_setup.yml b/.gitlab/ci_templates/ssh_setup.yml new file mode 100644 index 0000000000000000000000000000000000000000..e0d0f6104a91c44825422ec60ddbcd78929fa775 --- /dev/null +++ b/.gitlab/ci_templates/ssh_setup.yml @@ -0,0 +1,6 @@ +.ssh_setup: + before_script: + - mkdir ~/.ssh + - echo -e 'Host *\n stricthostkeychecking no' > ~/.ssh/config + - eval $(ssh-agent -s) + - echo "$SSH_PRIVATE_KEY" | tr -d '\r' | ssh-add - > /dev/null diff --git a/ansible/roles/apps/tasks/cert-manager.yml b/ansible/roles/apps/tasks/cert-manager.yml index 72e451e495d62324cb5d79c25b776aa4cfcd001d..4f08f585ce39cf25272b313973fc89197dfaf4a9 100644 --- a/ansible/roles/apps/tasks/cert-manager.yml +++ b/ansible/roles/apps/tasks/cert-manager.yml @@ -40,19 +40,16 @@ - name: production server: "https://acme-v02.api.letsencrypt.org/directory" -- name: Apply cert-manager helmfile +- name: Install cert-manager tags: - helmfile - cert-manager - shell: | - set -e -x -o pipefail - /usr/local/bin/helmfile \ - -b /usr/local/bin/helm \ - -e oas \ - -f {{ data_directory }}/source/helmfiles/helmfile.d/05-cert-manager.yaml \ - apply \ - --suppress-secrets \ - | sed 's/\x1B\[[0-9;]*[JKmsu]//g' \ - >> {{ log_directory }}/helmfile.log - args: - executable: /bin/bash + include_role: + name: "helmfile" + tasks_from: "apply" + apply: + tags: + - helmfile + - cert-manager + vars: + helmfile: '05-cert-manager' diff --git a/ansible/roles/apps/tasks/helmfiles.yml b/ansible/roles/apps/tasks/helmfiles.yml deleted file mode 100644 index ea30fda67819245c4b666202f0b4c3ab1bcee475..0000000000000000000000000000000000000000 --- a/ansible/roles/apps/tasks/helmfiles.yml +++ /dev/null @@ -1,125 +0,0 @@ ---- -- name: Clone nextcloud repo - tags: - - git - - nextcloud - git: - repo: 'https://open.greenhost.net/openappstack/nextcloud' - dest: '{{ data_directory }}/source/repos/nextcloud' - version: '{{ git_nextcloud_version }}' - -- name: Remove requirements.lock file - tags: - - git - - nextcloud - - helmfile - file: - path: '{{ data_directory }}/source/repos/nextcloud/nextcloud-onlyoffice/requirements.lock' - state: absent - -- name: Clone local-storage repo - tags: - - git - - local-storage - git: - repo: 'https://open.greenhost.net/openappstack/local-storage' - dest: '{{ data_directory }}/source/repos/local-storage' - version: '{{ git_local_storage_version }}' - -- name: Make Prometheus custom resource definitions - tags: - - helmfile - - monitoring - # NOTE: Change the commit hash in the URL when upgrading Prometheus - command: '/snap/bin/kubectl apply -f https://raw.githubusercontent.com/coreos/prometheus-operator/v0.31.1/example/prometheus-operator-crd/{{ item }}' - loop: - - alertmanager.crd.yaml - - prometheus.crd.yaml - - prometheusrule.crd.yaml - - servicemonitor.crd.yaml - - podmonitor.crd.yaml - -- name: Get prometheus PV name - tags: - - prometheus - shell: "kubectl -n oas get pvc prometheus-prometheus-oas-{{ release_name }}-prometheus-promet-prometheus-0 -o=jsonpath='{.spec.volumeName}'" - register: prometheus_pv_name - failed_when: false - changed_when: false - -# Needed because previously we ran prometheus as root -- name: Ensure prometheus volume is accessible by the prometheus pod - tags: - - prometheus - file: - dest: "{{ data_directory }}/local-storage/{{ prometheus_pv_name.stdout }}" - owner: '1000' - group: '2000' - recurse: true - when: prometheus_pv_name.stdout - -- name: Apply storage helmfile - tags: - - helmfile - shell: | - set -e -x -o pipefail - /usr/local/bin/helmfile -b /usr/local/bin/helm -e oas \ - -f {{ data_directory }}/source/helmfiles/helmfile.d/00-storage.yaml \ - apply --suppress-secrets \ - | sed 's/\x1B\[[0-9;]*[JKmsu]//g' \ - >> {{ log_directory }}/helmfile.log - args: - executable: /bin/bash - when: '"00-storage" in helmfiles' - -- name: Apply nginx helmfile - tags: - - helmfile - shell: | - set -e -x -o pipefail - /usr/local/bin/helmfile -b /usr/local/bin/helm -e oas \ - -f {{ data_directory }}/source/helmfiles/helmfile.d/10-nginx.yaml \ - apply --suppress-secrets \ - | sed 's/\x1B\[[0-9;]*[JKmsu]//g' \ - >> {{ log_directory }}/helmfile.log - args: - executable: /bin/bash - when: '"10-nginx" in helmfiles' - -# Force needed for upgrading from 5 to 6: https://github.com/helm/charts/tree/master/stable/prometheus-operator#upgrading-from-5xx-to-6xx -- name: Apply monitoring helmfile with force - tags: - - helmfile - environment: - - GRAFANA_ADMIN_PASSWORD: "{{ grafana_admin_password }}" - shell: | - set -e -x -o pipefail - /usr/local/bin/helmfile -b /usr/local/bin/helm -e oas \ - -f {{ data_directory }}/source/helmfiles/helmfile.d/15-monitoring.yaml \ - apply --suppress-secrets --args='--force' \ - | sed 's/\x1B\[[0-9;]*[JKmsu]//g' \ - >> {{ log_directory }}/helmfile.log - args: - executable: /bin/bash - when: '"15-monitoring" in helmfiles' - -- name: Apply nextcloud helmfile - tags: - - helmfile - environment: - - NEXTCLOUD_PASSWORD: "{{ nextcloud_password }}" - - NEXTCLOUD_MARIADB_PASSWORD: "{{ nextcloud_mariadb_password }}" - - NEXTCLOUD_MARIADB_ROOT_PASSWORD: "{{ nextcloud_mariadb_root_password }}" - - ONLYOFFICE_JWT_SECRET: "{{ onlyoffice_jwt_secret }}" - - ONLYOFFICE_POSTGRESQL_PASSWORD: "{{ onlyoffice_postgresql_password }}" - - ONLYOFFICE_RABBITMQ_PASSWORD: "{{ onlyoffice_rabbitmq_password }}" - shell: | - set -e -x -o pipefail - /usr/local/bin/helmfile -b /usr/local/bin/helm -e oas \ - -f {{ data_directory }}/source/helmfiles/helmfile.d/20-nextcloud.yaml \ - apply --suppress-secrets \ - | sed 's/\x1B\[[0-9;]*[JKmsu]//g' \ - >> {{ log_directory }}/helmfile.log - args: - executable: /bin/bash - when: '"20-nextcloud" in helmfiles' diff --git a/ansible/roles/apps/tasks/local-storage.yml b/ansible/roles/apps/tasks/local-storage.yml new file mode 100644 index 0000000000000000000000000000000000000000..7c5c8a86109fb7c8005aa8f81a1f105ffa032a47 --- /dev/null +++ b/ansible/roles/apps/tasks/local-storage.yml @@ -0,0 +1,24 @@ +--- +- name: Clone local-storage repo + tags: + - git + - helmfile + - local-storage + git: + repo: 'https://open.greenhost.net/openappstack/local-storage' + dest: '{{ data_directory }}/source/repos/local-storage' + version: '{{ git_local_storage_version }}' + +- name: Install local-storage provisioner + tags: + - helmfile + - local-storage + include_role: + name: "helmfile" + tasks_from: "apply" + apply: + tags: + - helmfile + - local-storage + vars: + helmfile: '00-storage' diff --git a/ansible/roles/apps/tasks/main.yml b/ansible/roles/apps/tasks/main.yml index a366c9362eafedbb90090cb7ffea89272789066d..2c1afae58ae53bd7ec8bbee5105d471b00f65380 100644 --- a/ansible/roles/apps/tasks/main.yml +++ b/ansible/roles/apps/tasks/main.yml @@ -1,4 +1,29 @@ --- -- import_tasks: init.yml -- import_tasks: cert-manager.yml -- import_tasks: helmfiles.yml +- name: Import tasks from init.yml + import_tasks: init.yml + tags: [ helmfile ] + +- name: Install local-storage + import_tasks: local-storage.yml + tags: [ helmfile ] + when: '"00-storage" in helmfiles' + +- name: Install cert-manager + import_tasks: cert-manager.yml + tags: [ helmfile ] + when: '"05-cert-manager" in helmfiles' + +- name: Install nginx + import_tasks: nginx.yml + tags: [ helmfile ] + when: '"10-nginx" in helmfiles' + +- name: Install prometheus + import_tasks: prometheus.yml + tags: [ helmfile ] + when: '"15-monitoring" in helmfiles' + +- name: Install nextcloud + import_tasks: nextcloud.yml + tags: [ helmfile ] + when: '"20-nextcloud" in helmfiles' diff --git a/ansible/roles/apps/tasks/nextcloud.yml b/ansible/roles/apps/tasks/nextcloud.yml new file mode 100644 index 0000000000000000000000000000000000000000..acb05aedd10b04940321766eafe33fb1238cda9f --- /dev/null +++ b/ansible/roles/apps/tasks/nextcloud.yml @@ -0,0 +1,42 @@ +--- +- name: Clone nextcloud repo + tags: + - git + - helmfile + - nextcloud + git: + repo: 'https://open.greenhost.net/openappstack/nextcloud' + dest: '{{ data_directory }}/source/repos/nextcloud' + version: '{{ git_nextcloud_version }}' + +- name: Remove requirements.lock file + tags: + - git + - nextcloud + - helmfile + file: + path: '{{ data_directory }}/source/repos/nextcloud/nextcloud-onlyoffice/requirements.lock' + state: absent + +- name: Install nextcloud and onlyoffice + tags: + - helmfile + - nextcloud + - onlyoffice + include_role: + name: "helmfile" + tasks_from: "apply" + apply: + tags: + - helmfile + - nextcloud + - onlyoffice + environment: + - NEXTCLOUD_PASSWORD: "{{ nextcloud_password }}" + - NEXTCLOUD_MARIADB_PASSWORD: "{{ nextcloud_mariadb_password }}" + - NEXTCLOUD_MARIADB_ROOT_PASSWORD: "{{ nextcloud_mariadb_root_password }}" + - ONLYOFFICE_JWT_SECRET: "{{ onlyoffice_jwt_secret }}" + - ONLYOFFICE_POSTGRESQL_PASSWORD: "{{ onlyoffice_postgresql_password }}" + - ONLYOFFICE_RABBITMQ_PASSWORD: "{{ onlyoffice_rabbitmq_password }}" + vars: + helmfile: '20-nextcloud' diff --git a/ansible/roles/apps/tasks/nginx.yml b/ansible/roles/apps/tasks/nginx.yml new file mode 100644 index 0000000000000000000000000000000000000000..a3a60176429f6227ee84a7b75d4b81a704b8e298 --- /dev/null +++ b/ansible/roles/apps/tasks/nginx.yml @@ -0,0 +1,14 @@ +--- +- name: Install nginx ingress controller + tags: + - helmfile + - nginx + include_role: + name: "helmfile" + tasks_from: "apply" + apply: + tags: + - helmfile + - nginx + vars: + helmfile: '10-nginx' diff --git a/ansible/roles/apps/tasks/prometheus.yml b/ansible/roles/apps/tasks/prometheus.yml new file mode 100644 index 0000000000000000000000000000000000000000..db9e49a8dd6611404832ac3de12819a4e9ff2414 --- /dev/null +++ b/ansible/roles/apps/tasks/prometheus.yml @@ -0,0 +1,52 @@ +--- + +- name: Make Prometheus custom resource definitions + tags: + - helmfile + - prometheus + # NOTE: Change the commit hash in the URL when upgrading Prometheus + command: '/snap/bin/kubectl apply -f https://raw.githubusercontent.com/coreos/prometheus-operator/v0.31.1/example/prometheus-operator-crd/{{ item }}' + loop: + - alertmanager.crd.yaml + - prometheus.crd.yaml + - prometheusrule.crd.yaml + - servicemonitor.crd.yaml + - podmonitor.crd.yaml + +- name: Get prometheus PV name + tags: + - prometheus + shell: "kubectl -n oas get pvc prometheus-prometheus-oas-{{ release_name }}-prometheus-promet-prometheus-0 -o=jsonpath='{.spec.volumeName}'" + register: prometheus_pv_name + failed_when: false + changed_when: false + +# Needed because previously we ran prometheus as root +- name: Ensure prometheus volume is accessible by the prometheus pod + tags: + - prometheus + file: + dest: "{{ data_directory }}/local-storage/{{ prometheus_pv_name.stdout }}" + owner: '1000' + group: '2000' + recurse: true + when: prometheus_pv_name.stdout + +- name: Install prometheus and graphana + include_role: + name: "helmfile" + tasks_from: "apply" + apply: + tags: + - monitoring + - prometheus + environment: + - GRAFANA_ADMIN_PASSWORD: "{{ grafana_admin_password }}" + tags: + - monitoring + - prometheus + vars: + helmfile: '15-monitoring' + # Force needed for upgrading from 5 to 6, see + # https://github.com/helm/charts/tree/master/stable/prometheus-operator#upgrading-from-5xx-to-6xx + helmfile_apply_args: '--args="--force"' diff --git a/ansible/roles/helmfile/defaults/main.yml b/ansible/roles/helmfile/defaults/main.yml new file mode 100644 index 0000000000000000000000000000000000000000..5521ff672faea62718869f8fd4e0ad18132bee09 --- /dev/null +++ b/ansible/roles/helmfile/defaults/main.yml @@ -0,0 +1,2 @@ +# Add additional helmfile apply args +helmfile_apply_args: '' diff --git a/ansible/roles/helmfile/tasks/apply.yml b/ansible/roles/helmfile/tasks/apply.yml new file mode 100644 index 0000000000000000000000000000000000000000..82957b2a68fa506c5a43d5eca1b65c0f459aeea5 --- /dev/null +++ b/ansible/roles/helmfile/tasks/apply.yml @@ -0,0 +1,13 @@ +--- +- name: Apply helmfile + tags: + - helmfile + shell: | + set -e -x -o pipefail + /usr/local/bin/helmfile -b /usr/local/bin/helm -e oas \ + -f {{ data_directory }}/source/helmfiles/helmfile.d/{{ helmfile }}.yaml \ + apply --suppress-secrets {{ helmfile_apply_args }} \ + | sed 's/\x1B\[[0-9;]*[JKmsu]//g' \ + >> {{ log_directory }}/helmfile.log + args: + executable: /bin/bash