Initial commit: MetaVox loadtest playbook
Ansible playbook voor het opzetten van een MetaVox loadtest omgeving: - 50 teamfolders met 10.000 bestanden elk (500K totaal) - 100 metadata velddefinities (10 teamfolder + 90 file-level) - 3-niveau mappenstructuur (10 hoofdmappen x 3 submappen) - ~43M metadata records via directe MySQL inserts - Geoptimaliseerde database indexes (7 redundante indexes gedropt) Gebruikt directe filesystem writes en MySQL inserts i.p.v. WebDAV/API voor maximale performance. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
191
templates/setup_metadata_fields.py.j2
Normal file
191
templates/setup_metadata_fields.py.j2
Normal file
@@ -0,0 +1,191 @@
|
||||
#!/usr/bin/env python3
|
||||
"""
|
||||
MetaVox Metadata Velden Setup Script
|
||||
=====================================
|
||||
Maakt teamfolder-velden en file-metadata-velden aan via de MetaVox OCS API.
|
||||
|
||||
POST /ocs/v2.php/apps/metavox/api/v1/groupfolder-fields
|
||||
Payload: field_name, field_label, field_type, field_description,
|
||||
field_options (array), is_required, sort_order,
|
||||
applies_to_groupfolder (1=teamfolder metadata, 0=file metadata)
|
||||
|
||||
POST /ocs/v2.php/apps/metavox/api/v1/groupfolders/{id}/fields
|
||||
Payload: field_ids (array) - wijst velden toe aan een specifieke groupfolder
|
||||
"""
|
||||
|
||||
import json
|
||||
import sys
|
||||
import time
|
||||
import requests
|
||||
from requests.auth import HTTPBasicAuth
|
||||
|
||||
NC_URL = "{{ nextcloud_url }}"
|
||||
NC_USER = "{{ nextcloud_admin_user }}"
|
||||
NC_PASS = "{{ nextcloud_admin_password }}"
|
||||
TIMEOUT = {{ http_timeout }}
|
||||
MAX_RETRIES = {{ max_retries }}
|
||||
|
||||
OCS_BASE = f"{NC_URL}/ocs/v2.php/apps/metavox/api/v1"
|
||||
|
||||
AUTH = HTTPBasicAuth(NC_USER, NC_PASS)
|
||||
HEADERS = {
|
||||
"OCS-APIRequest": "true",
|
||||
"Accept": "application/json",
|
||||
"Content-Type": "application/json",
|
||||
}
|
||||
|
||||
|
||||
def api_request(method, url, data=None, retries=MAX_RETRIES):
|
||||
for attempt in range(retries):
|
||||
try:
|
||||
resp = requests.request(
|
||||
method, url, auth=AUTH, headers=HEADERS,
|
||||
json=data, timeout=TIMEOUT,
|
||||
)
|
||||
if resp.status_code in [200, 201]:
|
||||
return resp
|
||||
elif resp.status_code == 500 and "already exists" in resp.text:
|
||||
print(f" [SKIP] Veld bestaat al")
|
||||
return resp
|
||||
else:
|
||||
print(f" [WARN] HTTP {resp.status_code}: {resp.text[:200]}")
|
||||
if attempt < retries - 1:
|
||||
time.sleep(2 ** attempt)
|
||||
return resp
|
||||
except requests.exceptions.RequestException as e:
|
||||
print(f" [ERROR] Poging {attempt+1}/{retries}: {e}")
|
||||
if attempt < retries - 1:
|
||||
time.sleep(2 ** attempt)
|
||||
else:
|
||||
raise
|
||||
return None
|
||||
|
||||
|
||||
def create_field(field, applies_to_groupfolder):
|
||||
options = field.get("options", "")
|
||||
if isinstance(options, str) and options:
|
||||
options = [o.strip() for o in options.split(",")]
|
||||
elif not isinstance(options, list):
|
||||
options = []
|
||||
|
||||
payload = {
|
||||
"field_name": field["name"],
|
||||
"field_label": field.get("description", field["name"]),
|
||||
"field_type": field["type"],
|
||||
"field_description": field.get("description", ""),
|
||||
"field_options": options,
|
||||
"is_required": False,
|
||||
"sort_order": 0,
|
||||
"applies_to_groupfolder": applies_to_groupfolder,
|
||||
}
|
||||
|
||||
url = f"{OCS_BASE}/groupfolder-fields"
|
||||
return api_request("POST", url, payload)
|
||||
|
||||
|
||||
def assign_fields_to_groupfolder(groupfolder_id, field_ids):
|
||||
url = f"{OCS_BASE}/groupfolders/{groupfolder_id}/fields"
|
||||
return api_request("POST", url, {"field_ids": field_ids})
|
||||
|
||||
|
||||
def get_existing_fields():
|
||||
url = f"{OCS_BASE}/groupfolder-fields"
|
||||
resp = api_request("GET", url)
|
||||
if resp and resp.status_code == 200:
|
||||
try:
|
||||
data = resp.json()
|
||||
if "ocs" in data and "data" in data["ocs"]:
|
||||
return data["ocs"]["data"]
|
||||
except Exception:
|
||||
pass
|
||||
return []
|
||||
|
||||
|
||||
def get_groupfolders():
|
||||
url = f"{OCS_BASE}/groupfolders"
|
||||
resp = api_request("GET", url)
|
||||
if resp and resp.status_code == 200:
|
||||
try:
|
||||
data = resp.json()
|
||||
if "ocs" in data and "data" in data["ocs"]:
|
||||
return data["ocs"]["data"]
|
||||
except Exception:
|
||||
pass
|
||||
return []
|
||||
|
||||
|
||||
def main():
|
||||
print("=" * 60)
|
||||
print("MetaVox Metadata Velden Setup (OCS API)")
|
||||
print(f"Endpoint: {OCS_BASE}/groupfolder-fields")
|
||||
print("=" * 60)
|
||||
|
||||
created_field_ids = []
|
||||
|
||||
# ---- Teamfolder metadata-velden (applies_to_groupfolder=1) ----
|
||||
tf_fields = json.loads("""{{ teamfolder_metadata_fields | to_json }}""")
|
||||
print(f"\n[1/3] {len(tf_fields)} teamfolder-velden (applies_to_groupfolder=1)...")
|
||||
|
||||
tf_created = 0
|
||||
for field in tf_fields:
|
||||
print(f" Aanmaken: {field['name']} ({field['type']})")
|
||||
resp = create_field(field, applies_to_groupfolder=1)
|
||||
if resp and resp.status_code in [200, 201]:
|
||||
tf_created += 1
|
||||
try:
|
||||
fid = resp.json().get("ocs", {}).get("data", {}).get("id")
|
||||
if fid:
|
||||
created_field_ids.append(fid)
|
||||
except Exception:
|
||||
pass
|
||||
print(f" -> {tf_created} teamfolder-velden created")
|
||||
|
||||
# ---- File metadata-velden (applies_to_groupfolder=0) ----
|
||||
file_fields = json.loads("""{{ file_metadata_fields | to_json }}""")
|
||||
print(f"\n[2/3] {len(file_fields)} file-velden (applies_to_groupfolder=0)...")
|
||||
|
||||
f_created = 0
|
||||
for field in file_fields:
|
||||
print(f" Aanmaken: {field['name']} ({field['type']})")
|
||||
resp = create_field(field, applies_to_groupfolder=0)
|
||||
if resp and resp.status_code in [200, 201]:
|
||||
f_created += 1
|
||||
try:
|
||||
fid = resp.json().get("ocs", {}).get("data", {}).get("id")
|
||||
if fid:
|
||||
created_field_ids.append(fid)
|
||||
except Exception:
|
||||
pass
|
||||
print(f" -> {f_created} file-velden created")
|
||||
|
||||
# ---- Wijs alle velden toe aan alle groupfolders ----
|
||||
print(f"\n[3/3] Velden toewijzen aan groupfolders...")
|
||||
|
||||
all_fields = get_existing_fields()
|
||||
all_field_ids = [f["id"] for f in all_fields if "id" in f]
|
||||
if not all_field_ids:
|
||||
all_field_ids = created_field_ids
|
||||
|
||||
if all_field_ids:
|
||||
groupfolders = get_groupfolders()
|
||||
gf_count = 0
|
||||
for gf in groupfolders:
|
||||
gf_id = gf.get("id") or gf.get("group_folder_id")
|
||||
if gf_id:
|
||||
resp = assign_fields_to_groupfolder(gf_id, all_field_ids)
|
||||
if resp and resp.status_code == 200:
|
||||
gf_count += 1
|
||||
if gf_count % 10 == 0 and gf_count > 0:
|
||||
print(f" {gf_count} groupfolders verwerkt...")
|
||||
print(f" -> {gf_count} groupfolders hebben nu alle velden")
|
||||
else:
|
||||
print(" [WARN] Geen field IDs beschikbaar")
|
||||
|
||||
total = tf_created + f_created
|
||||
print(f"\n{'=' * 60}")
|
||||
print(f"Totaal: {total} metadata-velden created")
|
||||
print(f"{'=' * 60}")
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
||||
Reference in New Issue
Block a user