Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
235 changes: 234 additions & 1 deletion .github/workflows/tests-deploy-k8s.yml
Original file line number Diff line number Diff line change
Expand Up @@ -216,11 +216,244 @@ jobs:
path: data/nextcloud.log
if-no-files-found: warn

k8s-update-preserves-deploy-options:
runs-on: ubuntu-22.04
name: Update preserves deploy options (K8s)
# Regression test for https://github.com/nextcloud/app_api/issues/808
# on the K8s deploy path. Mirrors the Docker job in tests-deploy.yml.

services:
postgres:
image: ghcr.io/nextcloud/continuous-integration-postgres-14:latest # zizmor: ignore[unpinned-images]
ports:
- 4444:5432/tcp
env:
POSTGRES_USER: root
POSTGRES_PASSWORD: rootpassword
POSTGRES_DB: nextcloud
options: --health-cmd pg_isready --health-interval 5s --health-timeout 2s --health-retries 5

steps:
- name: Set app env
run: echo "APP_NAME=${GITHUB_REPOSITORY##*/}" >> $GITHUB_ENV

- name: Checkout server
uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
with:
persist-credentials: false
submodules: true
repository: nextcloud/server
ref: master

- name: Checkout AppAPI
uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
with:
persist-credentials: false
path: apps/${{ env.APP_NAME }}

- name: Set up php
uses: shivammathur/setup-php@accd6127cb78bee3e8082180cb391013d204ef9f # v2
with:
php-version: '8.3'
extensions: bz2, ctype, curl, dom, fileinfo, gd, iconv, intl, json, libxml, mbstring, openssl, pcntl, posix, session, simplexml, xmlreader, xmlwriter, zip, zlib, pgsql, pdo_pgsql
coverage: none
ini-file: development
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}

- name: Check composer file existence
id: check_composer
uses: andstor/file-existence-action@558493d6c74bf472d87c84eab196434afc2fa029 # v2
with:
files: apps/${{ env.APP_NAME }}/composer.json

- name: Set up dependencies
if: steps.check_composer.outputs.files_exists == 'true'
working-directory: apps/${{ env.APP_NAME }}
run: composer i

- name: Set up Nextcloud
env:
DB_PORT: 4444
run: |
mkdir data
./occ maintenance:install --verbose --database=pgsql --database-name=nextcloud --database-host=127.0.0.1 \
--database-port=$DB_PORT --database-user=root --database-pass=rootpassword \
--admin-user admin --admin-pass admin
./occ config:system:set loglevel --value=0 --type=integer
./occ config:system:set debug --value=true --type=boolean
./occ app:enable --force ${{ env.APP_NAME }}

- name: Install k3s
run: |
curl -sfL https://get.k3s.io | INSTALL_K3S_EXEC="--disable traefik --disable servicelb" sh -
sudo chmod 644 /etc/rancher/k3s/k3s.yaml
echo "KUBECONFIG=/etc/rancher/k3s/k3s.yaml" >> $GITHUB_ENV

- name: Wait for k3s and create namespace
run: |
kubectl wait --for=condition=Ready node --all --timeout=120s
kubectl create namespace nextcloud-exapps
NODE_IP=$(kubectl get node -o jsonpath='{.items[0].status.addresses[?(@.type=="InternalIP")].address}')
echo "NODE_IP=${NODE_IP}" >> $GITHUB_ENV

- name: Configure Nextcloud for k3s networking
run: |
./occ config:system:set overwrite.cli.url --value "http://${{ env.NODE_IP }}" --type=string
./occ config:system:set trusted_domains 1 --value "${{ env.NODE_IP }}"

- name: Create K8s service account for HaRP
run: |
kubectl -n nextcloud-exapps create serviceaccount harp-sa
kubectl create clusterrolebinding harp-admin \
--clusterrole=cluster-admin \
--serviceaccount=nextcloud-exapps:harp-sa
K3S_TOKEN=$(kubectl -n nextcloud-exapps create token harp-sa --duration=2h)
echo "K3S_TOKEN=${K3S_TOKEN}" >> $GITHUB_ENV

- name: Pre-pull ExApp image into k3s
run: sudo k3s ctr images pull ghcr.io/nextcloud/app-skeleton-python:latest

- name: Pull HaRP image
run: docker pull ghcr.io/nextcloud/nextcloud-appapi-harp:latest

- name: Start HaRP with K8s backend
run: |
docker run --net host --name appapi-harp \
-e HP_SHARED_KEY="${{ env.HP_SHARED_KEY }}" \
-e NC_INSTANCE_URL="http://${{ env.NODE_IP }}" \
-e HP_LOG_LEVEL="debug" \
-e HP_K8S_ENABLED="true" \
-e HP_K8S_API_SERVER="https://127.0.0.1:6443" \
-e HP_K8S_BEARER_TOKEN="${{ env.K3S_TOKEN }}" \
-e HP_K8S_NAMESPACE="nextcloud-exapps" \
-e HP_K8S_VERIFY_SSL="false" \
--restart unless-stopped \
-d ghcr.io/nextcloud/nextcloud-appapi-harp:latest

- name: Start nginx proxy
run: |
docker run --net host --name nextcloud --rm \
-v $(pwd)/apps/${{ env.APP_NAME }}/tests/simple-nginx-NOT-FOR-PRODUCTION.conf:/etc/nginx/conf.d/default.conf:ro \
-d nginx

- name: Start Nextcloud
run: PHP_CLI_SERVER_WORKERS=2 php -S 0.0.0.0:8080 &

- name: Wait for HaRP K8s readiness
run: |
for i in $(seq 1 30); do
if curl -sf http://${{ env.NODE_IP }}:8780/exapps/app_api/info \
-H "harp-shared-key: ${{ env.HP_SHARED_KEY }}" 2>/dev/null | grep -q '"kubernetes"'; then
echo "HaRP is ready"
exit 0
fi
sleep 2
done
docker logs appapi-harp
exit 1

- name: Register K8s daemon and Skeleton v1 with user env vars
run: |
./occ app_api:daemon:register \
k8s_test "K8s Test" "kubernetes-install" "http" "${{ env.NODE_IP }}:8780" "http://${{ env.NODE_IP }}" \
--harp --harp_shared_key "${{ env.HP_SHARED_KEY }}" \
--k8s --k8s_expose_type=nodeport --set-default
./occ app_api:app:register app-skeleton-python k8s_test \
--info-xml https://raw.githubusercontent.com/nextcloud/app-skeleton-python/main/appinfo/info.xml \
--env='TEST_ENV_2=user_provided_value' --wait-finish

- name: Verify env vars on the freshly registered Deployment
run: |
kubectl -n nextcloud-exapps get deploy -l app.kubernetes.io/component=exapp -o json \
| python3 -c '
import json, sys
items = json.load(sys.stdin)["items"]
env = {}
for item in items:
for c in item["spec"]["template"]["spec"].get("containers", []):
for e in c.get("env", []):
env[e["name"]] = e.get("value", "")
assert env.get("TEST_ENV_1") == "0", f"TEST_ENV_1 default missing after register: {env}"
assert env.get("TEST_ENV_2") == "user_provided_value", f"TEST_ENV_2 user value missing after register: {env}"
'

- name: Seed stray ex_deploy_options row for a second app
# Without a second appid in the table, the Update.php bug from #808 is
# latent: formatDeployOptions() with no $appId filter still produces
# the single app's rows by luck. The `zz_` prefix ensures this stray row
# iterates AFTER `app-skeleton-python`, so the last-wins flattening
# actually clobbers the skeleton's env_vars entry.
run: |
php apps/${{ env.APP_NAME }}/tests/integration_helper.php \
set-env zz_fake_second_app UNRELATED_VAR x

- name: Build v2 info.xml with bumped version
run: |
curl -sS https://raw.githubusercontent.com/nextcloud/app-skeleton-python/main/appinfo/info.xml \
| sed 's#<version>[^<]*</version>#<version>999.0.0</version>#' > /tmp/info-v2.xml
grep -q '<version>999.0.0</version>' /tmp/info-v2.xml || { echo "version bump failed"; exit 1; }

- name: Update ExApp
run: |
./occ app_api:app:update app-skeleton-python --info-xml /tmp/info-v2.xml --wait-finish

- name: After update, env vars still present on the new Deployment
run: |
kubectl -n nextcloud-exapps get deploy -l app.kubernetes.io/component=exapp -o json \
| python3 -c '
import json, sys
items = json.load(sys.stdin)["items"]
env = {}
for item in items:
for c in item["spec"]["template"]["spec"].get("containers", []):
for e in c.get("env", []):
env[e["name"]] = e.get("value", "")
assert env.get("TEST_ENV_1") == "0", f"#808 regression: TEST_ENV_1 lost on update; env={env}"
assert env.get("TEST_ENV_2") == "user_provided_value", f"#808 regression: TEST_ENV_2 user value lost on update; env={env}"
'

- name: Collect HaRP logs
if: always()
run: docker logs appapi-harp > harp.log 2>&1

- name: Collect K8s resources
if: always()
run: |
kubectl -n nextcloud-exapps get all -o wide > k8s-resources.txt 2>&1 || true
kubectl -n nextcloud-exapps describe pods > k8s-pods-describe.txt 2>&1 || true

- name: Upload HaRP logs
if: always()
uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1
with:
name: k8s_update_preserves_deploy_options_harp.log
path: harp.log
if-no-files-found: warn

- name: Upload K8s resources
if: always()
uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1
with:
name: k8s_update_preserves_deploy_options_resources.txt
path: |
k8s-resources.txt
k8s-pods-describe.txt
if-no-files-found: warn

- name: Upload NC logs
if: always()
uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1
with:
name: k8s_update_preserves_deploy_options_nextcloud.log
path: data/nextcloud.log
if-no-files-found: warn

tests-success:
permissions:
contents: none
runs-on: ubuntu-22.04
needs: [k8s-deploy-nodeport]
needs: [k8s-deploy-nodeport, k8s-update-preserves-deploy-options]
name: K8s-NodePort-Tests-OK
steps:
- run: echo "K8s NodePort tests passed successfully"
Loading
Loading