diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml index fb243c290a6b3bec40026dabd5fae15ebdaa86c3..99420c7fe8b3043160c4cbc2f38bbe2d2e6b4d92 100644 --- a/.gitlab-ci.yml +++ b/.gitlab-ci.yml @@ -26,6 +26,7 @@ include: 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 "SHELL $SHELL" echo [ -d $CLUSTER_DIR ] && find $CLUSTER_DIR || echo "directory ${CLUSTER_DIR} not found" echo @@ -863,18 +864,17 @@ kube-prometheus-stack-alerts: .taiko: stage: integration-test - script: + before_script: - *debug_information - # Run the taiko tests for specific app - - python3 -m openappstack $HOSTNAME test --apps $RESOURCE - retry: 2 + script: + # Retry taiko tests 60 times until they succeed, + # with a sleep interval of 10s in between tests + - bash ./.gitlab/ci_scripts/retry_cmd_until_success.sh 60 10 unbuffer python3 -m openappstack $HOSTNAME test --apps $RESOURCE | ts -i | ts artifacts: paths: - test/taiko/Screenshot* expire_in: 1 month when: on_failure - extends: - - .ssh_setup interruptible: true grafana-taiko: @@ -906,7 +906,6 @@ rocketchat-taiko: extends: - .taiko - .rocketchat_rules - allow_failure: true wekan-taiko: variables: diff --git a/.gitlab/ci_scripts/retry_cmd_until_success.sh b/.gitlab/ci_scripts/retry_cmd_until_success.sh new file mode 100755 index 0000000000000000000000000000000000000000..e165988afe56e80b585dbbc16f93ecf25a8e31f0 --- /dev/null +++ b/.gitlab/ci_scripts/retry_cmd_until_success.sh @@ -0,0 +1,48 @@ +#!/usr/bin/env bash +# +# Executes given cms multiple times until it is successful +# +# Usage: +# +# ./retry_cmd_until_success.sh [retries] [sleep] [cmd] +# +# Example: +# +# ./retry_cmd_until_success.sh 10 20 ping ix.de + +retries=$1 +if [[ ! $retries =~ ^-?[0-9]+$ ]] +then + echo "Please specify retries count." + exit 1 +fi + +shift +sleep_secs=$1 +if [[ ! $sleep_secs =~ ^-?[0-9]+$ ]] +then + echo "Please specify sleep interval in seconds." + exit 1 +fi + +shift +cmd=$* +if [[ -z "$cmd" ]] +then + echo "Please specify a cmd." + exit 1 +fi +echo "Retrying \"$cmd\" ${retries} times." + +i=0 +until eval $cmd +do + echo -e "return code: $?\n" + if [[ $i -ge $retries ]] + then + exit 1 + fi + (( i++ )) + sleep $sleep_secs + echo "${i}. retry:" +done diff --git a/.gitlab/issue_templates/update_all_components.md b/.gitlab/issue_templates/update_all_components.md index d7628fb8e7762cde98cba41b8b7db3a64e108af0..5883f9a84637bd0a118887e87c0db0637f4a151c 100644 --- a/.gitlab/issue_templates/update_all_components.md +++ b/.gitlab/issue_templates/update_all_components.md @@ -1,21 +1,26 @@ To update all applications, check the following files: -* [ ] Docker base image in `Dockerfile` (`FROM`) -* [ ] All app versions in `Dockerfile`, especially: - * [ ] flux (Make sure the version is the same as in `ansible/group_vars/all/oas.yml`, `flux.version`) +* CI Container image in `Dockerfile`: + * [ ] Base image (`FROM`) + * [ ] All app versions in `Dockerfile`, especially: + * [ ] flux (Make sure the version is the same as in `ansible/group_vars/all/oas.yml`, `flux.version`) * [ ] `requirements.in` * [ ] Run `pip install -r requirements-dev.txt && pip-compile` -* [ ] mitogen version in `ansible/plugins` +* [ ] Mitogen version in `ansible/plugins` -In `group_vars/all/oas.yml`: +In `ansible/group_vars/all/oas.yml`: * [ ] k3s * [ ] helm +* [ ] flux * [ ] krew * [ ] velero Installed by flux: * [ ] Run `find flux2 -name '*release*.yaml'` and paste the resulting list here -* [ ] make sure to also update our [nextcloud helm chart](https://open.greenhost.net/openappstack/nextcloud) -* [ ] make sure that our wordpress chart installs the newest version +* Update our custom helm-charts and their dependencies, make sure they install + latest versions + * [ ] [nextcloud](https://open.greenhost.net/openappstack/nextcloud) + * [ ] [wordpress](https://open.greenhost.net/openappstack/wordpress-helm) + * [ ] [single-sign-on](https://open.greenhost.net/openappstack/single-sign-on) diff --git a/Dockerfile b/Dockerfile index a1ca5cbf9c2446400fbeb2ab53eb14744a28001f..7f88afb1fe134464d2ee9e7d5a27538cfde5ed98 100644 --- a/Dockerfile +++ b/Dockerfile @@ -21,10 +21,14 @@ RUN \ curl=~7.78.0-r0 \ # needed for installing pycurl python module curl-dev=~7.78.0-r0 \ + # Needed for "unbuffer" to timestamp cmds + expect=~5.45.4-r0 \ gcc=~10.3.1_git20210424-r2 \ git=~2.32.0-r0 \ libffi-dev=3.3-r2 \ make=~4.3-r0 \ + # Needed for timestamp cmd "ts" + moreutils=~0.65-r0 \ musl-dev=~1.2.2-r3 \ npm=~7.17.0-r0 \ openssh-client=~8.6_p1-r2 \ @@ -39,4 +43,4 @@ RUN \ pip install --no-cache-dir --ignore-installed six -r /requirements.txt && \ ln -s /usr/bin/python3 /usr/bin/python && \ tar -xzf /tmp/flux*.tar.gz && mv ./flux /usr/local/bin && \ - npm install -g taiko@1.2.5 + npm install -g taiko@1.2.6 diff --git a/flux2/apps/nextcloud/release.yaml b/flux2/apps/nextcloud/release.yaml index 649ed2bbc31d2e866e9ae957ec350d5d52915c1f..571b1d8d923dbab878e75149cb1a3a2b43096bf9 100644 --- a/flux2/apps/nextcloud/release.yaml +++ b/flux2/apps/nextcloud/release.yaml @@ -78,11 +78,9 @@ spec: internalDatabase: enabled: false - livenessProbe: - initialDelaySeconds: 300 - failureThreshold: 20 - readinessProbe: - initialDelaySeconds: 300 + startupProbe: + enabled: true + failureThreshold: 60 resources: limits: @@ -117,6 +115,16 @@ spec: rootUser: password: "${nextcloud_mariadb_root_password}" + apps: + - name: sociallogin + enabled: true + - name: onlyoffice + enabled: true + - name: calendar + enabled: true + - name: passwords + enabled: true + setupApps: backoffLimit: 20 diff --git a/flux2/infrastructure/sources/nextcloud.yaml b/flux2/infrastructure/sources/nextcloud.yaml index 87b730f6070e77007c78a760e98421f38ac2f761..90e5ac1579e314990131d6432b95b7325750094d 100644 --- a/flux2/infrastructure/sources/nextcloud.yaml +++ b/flux2/infrastructure/sources/nextcloud.yaml @@ -13,4 +13,4 @@ spec: # For all available options, see: # https://toolkit.fluxcd.io/components/source/api/#source.toolkit.fluxcd.io/v1beta1.GitRepositoryRef ref: - tag: 0.3.0 + tag: 0.3.2 diff --git a/test/taiko/apps.js b/test/taiko/apps.js index cd8cf45da71cdf9d4196b0d5f20ef783d38050d5..30efaaa2333683e093c7a47b02255cf0f17c1471 100644 --- a/test/taiko/apps.js +++ b/test/taiko/apps.js @@ -11,7 +11,12 @@ const assert = require('assert'); // https://docs.taiko.dev/api/setconfig/ // setConfig( { observeTime: 1000}); - setConfig( { observeTime: 0, navigationTimeout: globalTimeout }); + setConfig( { + observeTime: 0, + // Navigation timeout value in milliseconds for navigation after performing openTab, goto, reload, goBack, goForward, click, write, clear, press and evaluate. + navigationTimeout: globalTimeout, + highlightOnAction: 'true' + }); console.log('Executing these tests: ' + taikoTests) await openBrowser({ @@ -50,6 +55,7 @@ const assert = require('assert'); await write(nextcloudPassword, into(textBox('Password'))) await click('Log in') + await waitFor(async () => (await text("Set location for weather").isVisible()), globalTimeout) // Close potential nextcloud first run wizard modal // https://github.com/nextcloud/firstrunwizard/issues/488 // Unfortunately, we need to sleep a while since I haven't found a @@ -57,27 +63,45 @@ const assert = require('assert'); // tests should also work on subsequent logins. await waitFor(5000) await press('Escape') - await waitFor(async () => (await text("Set location for weather").isVisible())) + + // Test password app + await click('Passwords') + await waitFor(async () => (await text("Handbook").isVisible()), globalTimeout) + + // Test if calendar app is enabled + await click('Calendar') + await waitFor(async () => (await text("Settings & Import").isVisible()), globalTimeout) console.log('• Nextcloud Onlyoffice integration') // Open document and type some text await click('Files') - await waitFor(async () => (await link({class:'new'}).isVisible())) + // Force page reload because of random empty pages for files app + // https://open.greenhost.net/openappstack/nextcloud/-/issues/973 + await reload() + + await waitFor(async () => (await link({class:'new'}).isVisible()), globalTimeout) await click(link({class:'new'})) await click('Document') - await press('Enter') + + // Create random file name because NC20 will complain if file already + // exists + const file_rand = 'test-' + Math.random().toString(16).substr(2, 12) + await press([...file_rand, 'Enter']) let italicButtonId = '#id-toolbar-btn-italic' - await waitFor($(italicButtonId), 120000) + await waitFor(async () => (await $(italicButtonId).isVisible()), globalTimeout) // Activate italic button let buttonStateBefore = await evaluate($(italicButtonId), (elem) => {return elem.getAttribute('class')}) await assert.ok(!buttonStateBefore.includes('active')) + + await waitFor(async () => (await $('#id_target_cursor').isVisible()), globalTimeout) await click($(italicButtonId)) + let buttonStateAfter = await evaluate($(italicButtonId), (elem) => {return elem.getAttribute('class')}) await assert.ok(buttonStateAfter.includes('active')) - await press(['H', 'i', ' ', 'f', 'r', 'o', 'm', ' ', 't', 'a', 'i', 'k', 'o', '!', 'Enter']) + await press([...'Hi from taiko!', 'Enter']) // Deactivate italic finially await click($(italicButtonId))