recipe-maintainer: public snapshot (secrets + deployment plans removed, single commit)
Sanitized single-commit public mirror of recipe-maintainer. - Removed test-ssh/.testenv (live creds); added test-ssh/.testenv.example placeholders. - Removed plans/ and planned-updates/ (deployment-planning docs) so no client/ deployment domains appear in the public repo. - All other secret stores were already gitignored. - docs.coopcloud.tech retained as a submodule (public upstream).
This commit is contained in:
+90
@@ -0,0 +1,90 @@
|
||||
#!/usr/bin/env python3
|
||||
"""Celery Beat WOPI scheduling test."""
|
||||
import argparse
|
||||
import json
|
||||
import os
|
||||
import sys
|
||||
import time
|
||||
|
||||
sys.path.insert(0, os.path.join(os.path.dirname(__file__), '..', '..', '..'))
|
||||
from utils.tests.helpers import run, resolve_domain, resolve_server
|
||||
|
||||
|
||||
def main():
|
||||
parser = argparse.ArgumentParser()
|
||||
parser.add_argument('--domain', default=os.environ.get('TEST_DOMAIN'))
|
||||
args = parser.parse_args()
|
||||
domain = args.domain or resolve_domain('lasuite-drive')
|
||||
server = resolve_server()
|
||||
|
||||
print("Testing Celery Beat WOPI scheduling")
|
||||
print()
|
||||
|
||||
# Step 1: Verify celery-beat service is running
|
||||
print("Step 1: Checking celery-beat service is running ...")
|
||||
result = run(f"abra app ps {domain} --chaos --no-input -m", check=False, timeout=60)
|
||||
try:
|
||||
data = json.loads(result.stdout)
|
||||
if 'celery-beat' in data:
|
||||
print(" PASS: celery-beat service is running")
|
||||
else:
|
||||
print(" FAIL: celery-beat service not found in running services")
|
||||
sys.exit(1)
|
||||
except (json.JSONDecodeError, TypeError):
|
||||
print(" FAIL: Could not parse service list")
|
||||
print(f" Output: {result.stdout}")
|
||||
sys.exit(1)
|
||||
|
||||
# Step 2: Verify old scheduler service is gone
|
||||
print("Step 2: Checking old scheduler service is removed ...")
|
||||
if 'scheduler' in data:
|
||||
print(" FAIL: old scheduler service still appears in service list")
|
||||
sys.exit(1)
|
||||
print(" PASS: old scheduler service is not running")
|
||||
|
||||
# Step 3: Wait for WOPI task to fire and check logs
|
||||
print("Step 3: Waiting for WOPI configuration task to fire (up to 90s) ...")
|
||||
print(" (test instance should have WOPI_CONFIGURATION_CRONTAB_MINUTE=* for every-minute execution)")
|
||||
|
||||
found_task = False
|
||||
beat_logs = ""
|
||||
celery_logs = ""
|
||||
|
||||
for i in range(1, 7):
|
||||
print(f" Checking logs (attempt {i}/6, waiting 15s) ...")
|
||||
time.sleep(15)
|
||||
|
||||
# Check celery-beat logs for the task being sent
|
||||
result = run(
|
||||
f"ssh {server} 'docker logs $(docker ps -q -f name=lasuite-drive.*celery-beat) 2>&1 | tail -20'",
|
||||
check=False, timeout=30,
|
||||
)
|
||||
beat_logs = result.stdout
|
||||
|
||||
if any("sending due task configure_wopi_clients" in line.lower() for line in beat_logs.split('\n')):
|
||||
print(" PASS: Celery Beat is sending the WOPI configuration task")
|
||||
found_task = True
|
||||
break
|
||||
|
||||
# Check celery worker logs for task execution
|
||||
result = run(
|
||||
f"ssh {server} 'docker logs $(docker ps -q -f name=lasuite-drive.*_celery\\.) 2>&1 | grep -i configure_wopi | tail -5'",
|
||||
check=False, timeout=30,
|
||||
)
|
||||
celery_logs = result.stdout
|
||||
|
||||
if "configure_wopi" in celery_logs.lower() and "succeeded" in celery_logs.lower():
|
||||
print(" PASS: WOPI configuration task executed successfully on celery worker")
|
||||
found_task = True
|
||||
break
|
||||
|
||||
if not found_task:
|
||||
print(" FAIL: WOPI configuration task not found in logs after 90 seconds")
|
||||
sys.exit(1)
|
||||
|
||||
print()
|
||||
print("PASS: Celery Beat WOPI scheduling test passed")
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
main()
|
||||
+28
@@ -0,0 +1,28 @@
|
||||
#!/usr/bin/env python3
|
||||
"""Health check for La Suite Drive."""
|
||||
import argparse
|
||||
import os
|
||||
import sys
|
||||
|
||||
sys.path.insert(0, os.path.join(os.path.dirname(__file__), '..', '..', '..'))
|
||||
from utils.tests.helpers import http_get, resolve_domain
|
||||
|
||||
|
||||
def main():
|
||||
parser = argparse.ArgumentParser()
|
||||
parser.add_argument('--domain', default=os.environ.get('TEST_DOMAIN'))
|
||||
args = parser.parse_args()
|
||||
domain = args.domain or resolve_domain('lasuite-drive')
|
||||
url = f"https://{domain}"
|
||||
|
||||
print(f"Checking La Suite Drive at {url} ...")
|
||||
status, _ = http_get(url)
|
||||
if status == 200:
|
||||
print(f"PASS: La Suite Drive returned HTTP {status}")
|
||||
else:
|
||||
print(f"FAIL: La Suite Drive returned HTTP {status} (expected 200)")
|
||||
sys.exit(1)
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
main()
|
||||
+102
@@ -0,0 +1,102 @@
|
||||
#!/usr/bin/env python3
|
||||
"""OIDC integration test for La Suite Drive + Keycloak."""
|
||||
import argparse
|
||||
import os
|
||||
import sys
|
||||
import urllib.request
|
||||
import urllib.error
|
||||
|
||||
sys.path.insert(0, os.path.join(os.path.dirname(__file__), '..', '..', '..'))
|
||||
from utils.tests.helpers import (
|
||||
http_get, http_post, load_toml_credentials, resolve_domain,
|
||||
)
|
||||
|
||||
|
||||
def main():
|
||||
parser = argparse.ArgumentParser()
|
||||
parser.add_argument('--domain', default=os.environ.get('TEST_DOMAIN'))
|
||||
args = parser.parse_args()
|
||||
|
||||
recipe_dir = os.path.join(os.path.dirname(__file__), '..')
|
||||
creds = load_toml_credentials(recipe_dir, 'keycloak')
|
||||
if creds is None:
|
||||
print("FAIL: Credentials file not found: keycloak-test-credentials.<domain_suffix>.toml")
|
||||
print("Run setup_keycloak_integration.py first.")
|
||||
sys.exit(1)
|
||||
|
||||
drive_domain = args.domain or resolve_domain('lasuite-drive')
|
||||
kc_domain = resolve_domain('keycloak')
|
||||
drive_url = f"https://{drive_domain}"
|
||||
kc_url = f"https://{kc_domain}"
|
||||
|
||||
print("Testing OIDC integration: La Suite Drive <-> Keycloak")
|
||||
print()
|
||||
|
||||
# Step 1: Verify Drive redirects to Keycloak
|
||||
print("Step 1: Checking Drive OIDC redirect ...")
|
||||
try:
|
||||
req = urllib.request.Request(f"{drive_url}/api/v1.0/authenticate/")
|
||||
opener = urllib.request.build_opener(NoRedirectHandler())
|
||||
resp = opener.open(req, timeout=15)
|
||||
redirect_url = resp.headers.get('Location', '')
|
||||
except urllib.error.HTTPError as e:
|
||||
redirect_url = e.headers.get('Location', '') if e.headers else ''
|
||||
|
||||
expected_prefix = f"{kc_url}/realms/{creds['kc_realm']}/protocol/openid-connect/auth"
|
||||
if expected_prefix in (redirect_url or ''):
|
||||
print(f" PASS: Drive redirects to Keycloak realm '{creds['kc_realm']}'")
|
||||
else:
|
||||
print(f" FAIL: Expected redirect to Keycloak, got: {redirect_url}")
|
||||
sys.exit(1)
|
||||
|
||||
# Step 2: Obtain token from Keycloak
|
||||
print("Step 2: Obtaining token from Keycloak ...")
|
||||
token_url = f"{kc_url}/realms/{creds['kc_realm']}/protocol/openid-connect/token"
|
||||
status, data = http_post(
|
||||
token_url,
|
||||
data={
|
||||
"grant_type": "password",
|
||||
"client_id": creds["kc_client_id"],
|
||||
"client_secret": creds["kc_client_secret"],
|
||||
"username": creds["kc_test_user"],
|
||||
"password": creds["kc_test_pass"],
|
||||
"scope": "openid email",
|
||||
},
|
||||
content_type="application/x-www-form-urlencoded",
|
||||
)
|
||||
access_token = (data or {}).get("access_token", "")
|
||||
if not access_token:
|
||||
error = (data or {}).get("error_description", (data or {}).get("error", "unknown"))
|
||||
print(f" FAIL: Could not obtain token from Keycloak: {error}")
|
||||
sys.exit(1)
|
||||
print(f" PASS: Obtained access token from Keycloak ({len(access_token)} chars)")
|
||||
|
||||
# Step 3: Use token to access Drive API
|
||||
print("Step 3: Accessing Drive API with Keycloak token ...")
|
||||
status, body = http_get(
|
||||
f"{drive_url}/api/v1.0/users/me/",
|
||||
headers={"Authorization": f"Bearer {access_token}"},
|
||||
)
|
||||
if status != 200:
|
||||
print(f" FAIL: Drive API returned HTTP {status} (expected 200)")
|
||||
sys.exit(1)
|
||||
|
||||
user_email = (body or {}).get("email", "")
|
||||
expected_email = f"{creds['kc_test_user']}@test.example.com"
|
||||
if user_email == expected_email:
|
||||
print(f" PASS: Drive API returned user with email '{user_email}'")
|
||||
else:
|
||||
print(f" FAIL: Expected email '{expected_email}', got '{user_email}'")
|
||||
sys.exit(1)
|
||||
|
||||
print()
|
||||
print("PASS: OIDC integration test passed — Drive authenticates via Keycloak")
|
||||
|
||||
|
||||
class NoRedirectHandler(urllib.request.HTTPRedirectHandler):
|
||||
def redirect_request(self, req, fp, code, msg, headers, newurl):
|
||||
raise urllib.error.HTTPError(newurl, code, msg, headers, fp)
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
main()
|
||||
+63
@@ -0,0 +1,63 @@
|
||||
#!/usr/bin/env python3
|
||||
"""WOPI configuration verification test."""
|
||||
import argparse
|
||||
import os
|
||||
import sys
|
||||
import urllib.request
|
||||
|
||||
sys.path.insert(0, os.path.join(os.path.dirname(__file__), '..', '..', '..'))
|
||||
from utils.tests.helpers import resolve_domain
|
||||
|
||||
|
||||
def main():
|
||||
parser = argparse.ArgumentParser()
|
||||
parser.add_argument('--domain', default=os.environ.get('TEST_DOMAIN'))
|
||||
args = parser.parse_args()
|
||||
domain = args.domain or resolve_domain('lasuite-drive')
|
||||
|
||||
collabora_url = f"https://collabora.{domain}/hosting/discovery"
|
||||
onlyoffice_url = f"https://onlyoffice.{domain}/hosting/discovery"
|
||||
|
||||
print("Testing WOPI configuration")
|
||||
print()
|
||||
|
||||
# Step 1: Check Collabora discovery endpoint
|
||||
print("Step 1: Checking Collabora discovery endpoint ...")
|
||||
try:
|
||||
req = urllib.request.Request(collabora_url)
|
||||
with urllib.request.urlopen(req, timeout=15) as resp:
|
||||
body = resp.read().decode('utf-8', errors='replace')
|
||||
status = resp.getcode()
|
||||
except Exception as e:
|
||||
print(f" FAIL: Collabora discovery check failed: {e}")
|
||||
sys.exit(1)
|
||||
|
||||
if status == 200 and 'wopi-discovery' in body:
|
||||
print(" PASS: Collabora discovery returns valid WOPI XML")
|
||||
else:
|
||||
print(f" FAIL: Collabora discovery check failed (HTTP {status})")
|
||||
sys.exit(1)
|
||||
|
||||
# Step 2: Check OnlyOffice discovery endpoint
|
||||
print("Step 2: Checking OnlyOffice discovery endpoint ...")
|
||||
try:
|
||||
req = urllib.request.Request(onlyoffice_url)
|
||||
with urllib.request.urlopen(req, timeout=15) as resp:
|
||||
body = resp.read().decode('utf-8', errors='replace')
|
||||
status = resp.getcode()
|
||||
except Exception as e:
|
||||
print(f" FAIL: OnlyOffice discovery check failed: {e}")
|
||||
sys.exit(1)
|
||||
|
||||
if status == 200 and 'wopi-discovery' in body:
|
||||
print(" PASS: OnlyOffice discovery returns valid WOPI XML")
|
||||
else:
|
||||
print(f" FAIL: OnlyOffice discovery check failed (HTTP {status})")
|
||||
sys.exit(1)
|
||||
|
||||
print()
|
||||
print("PASS: WOPI discovery endpoints are reachable and returning valid XML")
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
main()
|
||||
+56
@@ -0,0 +1,56 @@
|
||||
#!/usr/bin/env python3
|
||||
"""WOPI on startup test — verifies celery worker runs WOPI config on startup."""
|
||||
import argparse
|
||||
import os
|
||||
import sys
|
||||
|
||||
sys.path.insert(0, os.path.join(os.path.dirname(__file__), '..', '..', '..'))
|
||||
from utils.tests.helpers import run, resolve_server
|
||||
|
||||
|
||||
def main():
|
||||
parser = argparse.ArgumentParser()
|
||||
parser.add_argument('--domain', default=os.environ.get('TEST_DOMAIN'))
|
||||
args = parser.parse_args()
|
||||
|
||||
server = resolve_server()
|
||||
|
||||
print("Testing WOPI configuration on startup")
|
||||
print()
|
||||
|
||||
# Check celery worker logs for the entrypoint WOPI trigger message
|
||||
print("Step 1: Checking celery worker logs for WOPI startup trigger ...")
|
||||
|
||||
result = run(
|
||||
f'ssh {server} "docker ps -f name=lasuite-drive --format \'{{{{.Names}}}}\' | grep -E \'celery\\.\' | grep -v beat"',
|
||||
check=False, timeout=30,
|
||||
)
|
||||
celery_name = result.stdout.strip().split('\n')[0].strip()
|
||||
|
||||
result = run(
|
||||
f'ssh {server} "docker logs {celery_name} 2>&1 | head -5"',
|
||||
check=False, timeout=30,
|
||||
)
|
||||
celery_logs = result.stdout
|
||||
|
||||
if "running WOPI configuration on startup" in celery_logs:
|
||||
print(" PASS: Celery worker ran WOPI configuration on startup")
|
||||
else:
|
||||
print(" FAIL: WOPI startup trigger not found in celery worker logs")
|
||||
print(f" Logs: {celery_logs}")
|
||||
sys.exit(1)
|
||||
|
||||
# Verify it didn't fail
|
||||
if "WOPI configuration failed" in celery_logs:
|
||||
print(" FAIL: WOPI configuration failed on startup")
|
||||
print(f" Logs: {celery_logs}")
|
||||
sys.exit(1)
|
||||
else:
|
||||
print(" PASS: WOPI configuration completed without errors")
|
||||
|
||||
print()
|
||||
print("PASS: WOPI on startup test passed")
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
main()
|
||||
Reference in New Issue
Block a user