Skip to main content

Deploy Enonic XP CMS

Target file: website/docs/ai-developer/plans/backlog/PLAN-enonic-xp-deployment.md

IMPLEMENTATION RULES: Before implementing this plan, read and follow:

Status: Complete

Goal: Deploy Enonic XP 7.16.2 as a UIS platform service using direct Kubernetes manifests (StatefulSet pattern), with no external database dependencies

Last Updated: 2026-03-10

Investigation: INVESTIGATE-enonic-xp-deployment.md


Overview

Enonic XP is a headless CMS used by Norwegian organizations (NAV, Gjensidige). It will be deployed as manifest 085 in the INTEGRATION category using direct YAML manifests (StatefulSet pattern like Unity Catalog — no Helm chart). Enonic has embedded Elasticsearch and NoSQL storage, so it has no external database dependencies.

Key decisions from investigation:

  • Version: Enonic XP 7.16.2 (image enonic/xp:7.16.2-ubuntu, pinned)
  • Pattern: StatefulSet + ConfigMap + PVC (direct manifests, no Helm)
  • Category: INTEGRATION, manifest 085
  • Namespace: enonic
  • Admin: User su, password set via xp.suPassword in system.properties (injected from DEFAULT_ADMIN_PASSWORD secret at container startup)
  • Ports: 8080 (web/API), 4848 (management — internal only), 2609 (statistics/health — internal only)
  • Storage: Single PVC for $XP_HOME (blobstore, index, config, deploy, snapshots)
  • No sidecar: The app deployment pipeline (#5 on roadmap) is a separate follow-up

Phase 1: Service Definition and Configuration Files — ✅ DONE

Create all static files needed before deployment.

Tasks

  • 1.1 Create service definition provision-host/uis/services/integration/service-enonic.sh
  • 1.2 Create ConfigMap manifests/085-enonic-config.yaml
  • 1.3 Create StatefulSet + Service + PVC manifests/085-enonic-statefulset.yaml
  • 1.4 Create IngressRoute manifests/085-enonic-ingressroute.yaml
  • 1.5 Add Enonic secrets to provision-host/uis/templates/secrets-templates/00-common-values.env.template
  • 1.6 Add Enonic namespace block to provision-host/uis/templates/secrets-templates/00-master-secrets.yml.template

Implementation Details

1.1 Service definition — follow the OpenMetadata pattern (service-openmetadata.sh):

SCRIPT_ID="enonic"
SCRIPT_NAME="Enonic XP"
SCRIPT_DESCRIPTION="Headless CMS platform for content management and delivery"
SCRIPT_CATEGORY="INTEGRATION"
SCRIPT_PLAYBOOK="085-setup-enonic.yml"
SCRIPT_REMOVE_PLAYBOOK="085-remove-enonic.yml"
SCRIPT_CHECK_COMMAND="kubectl get pods -n enonic -l app=enonic-xp --no-headers 2>/dev/null | grep -q Running"
SCRIPT_REQUIRES="" # No external dependencies
SCRIPT_PRIORITY="85"
SCRIPT_IMAGE="enonic/xp:7.16.2-ubuntu"
SCRIPT_NAMESPACE="enonic"
# Website metadata fields (SCRIPT_ABSTRACT, SCRIPT_LOGO, SCRIPT_WEBSITE, SCRIPT_TAGS, SCRIPT_SUMMARY, SCRIPT_DOCS)

1.2 ConfigMap — XP configuration in 085-enonic-config.yaml:

  • JVM heap settings via XP_OPTS (e.g., -Xms512m -Xmx1g for dev)
  • Any XP configuration properties needed

1.3 StatefulSet — in 085-enonic-statefulset.yaml (follow Unity Catalog pattern 320-unity-catalog-deployment.yaml):

  • ServiceAccount: enonic-xp
  • StatefulSet with image enonic/xp:7.16.2-ubuntu (pinned)
  • Single PVC for $XP_HOME (1Gi for dev, local-path storage class)
  • Ports: 8080 (web), 4848 (management), 2609 (statistics/health)
  • xp.suPassword injected into system.properties via entrypoint override (from ENONIC_ADMIN_PASSWORD secret)
  • Startup probe: GET /health on port 2609 with generous timeout (first boot creates indexes)
  • Readiness probe: GET /ready on port 2609 (validates all services operational)
  • Liveness probe: GET /health on port 2609 (validates data services available)
  • Resource requests: 500m CPU, 1Gi memory
  • Service: ClusterIP on ports 8080, 4848, 2609

1.4 IngressRoute — follow standard pattern (341-openmetadata-ingressroute.yaml):

  • HostRegexp('enonic\..+') routing to port 8080
  • Namespace: enonic
  • Label: protection: public

1.5 Secrets template — add to the OPTIONAL section in 00-common-values.env.template:

# ================================================================
# OPTIONAL - ENONIC XP
# ================================================================
# Admin password for Enonic XP superuser (user: su)
ENONIC_ADMIN_PASSWORD=${DEFAULT_ADMIN_PASSWORD}

1.6 Master secrets — add namespace block after the openmetadata block in 00-master-secrets.yml.template:

  • Namespace: enonic
  • Secret keys: ENONIC_ADMIN_PASSWORD
  • Derived from ${ENONIC_ADMIN_PASSWORD} (which defaults to ${DEFAULT_ADMIN_PASSWORD})

Validation

User reviews the created files for correctness.


Phase 2: Ansible Playbooks — ✅ DONE

Create the setup, remove, and verify playbooks.

Tasks

  • 2.1 Create setup playbook ansible/playbooks/085-setup-enonic.yml
  • 2.2 Create remove playbook ansible/playbooks/085-remove-enonic.yml
  • 2.3 Create verify playbook ansible/playbooks/085-test-enonic.yml
  • 2.4 Register enonic in VERIFY_SERVICES in provision-host/uis/lib/integration-testing.sh
  • 2.5 Add enonic verify command to provision-host/uis/manage/uis-cli.sh

Implementation Details

2.1 Setup playbook — follow Unity Catalog pattern (320-setup-unity-catalog.yml):

  1. Prerequisites: Create namespace, check secrets exist
  2. Deploy: Apply ConfigMap, StatefulSet + Service + PVC via kubernetes.core.k8s
  3. Wait: Wait for pod ready with generous timeout (first boot creates indexes and may take 2-3 minutes)
  4. Ingress: Apply IngressRoute
  5. Health check: HTTP GET to http://enonic-xp.enonic.svc:8080/ — verify XP responds
  6. Status: Display deployment status

No database setup needed — Enonic has embedded storage.

2.2 Remove playbook — follow Unity Catalog pattern (320-remove-unity-catalog.yml):

  1. Delete IngressRoute
  2. Delete StatefulSet + Service via kubernetes.core.k8s
  3. Wait for pod termination
  4. Delete PVCs
  5. Delete namespace
  6. Note: PVC data is lost (user warned)

2.3 Verify playbook (085-test-enonic.yml) — 6 tests, follow OpenMetadata test pattern (340-test-openmetadata.yml):

TestWhatHow
A. Health checkXP data services readyGET :2609/health → HTTP 200. No auth needed. Validates embedded Elasticsearch and storage are operational.
B. Readiness checkXP fully operationalGET :2609/ready → HTTP 200. No auth needed. Validates all services needed for full operation.
C. Repository listEmbedded storage works (read-back)GET :4848/repo/list with basic auth (su / ENONIC_ADMIN_PASSWORD) → HTTP 200, response contains "id":"system-repo" (default repo). Proves admin auth AND embedded storage read-back work.
D. UI via TraefikIngressRoute workscurl -H "Host: enonic.localhost" http://<traefik-clusterip> → HTTP 200
E. Admin UI accessibleAdmin console loadsGET :8080/admin with basic auth (su / ENONIC_ADMIN_PASSWORD) → HTTP 200
F. Wrong credentialsBad password rejectedGET :4848/repo/list with wrong password → HTTP 401

Uses kubectl run curlimages/curl for in-cluster testing, ansible.builtin.assert with fail_msg.

Port notes: Port 2609 (statistics) exposes /health and /ready endpoints without auth — ideal for probes. Port 4848 (management) requires basic auth with Administrator role — the repo/list endpoint lists all repositories and proves the embedded storage engine is working.

2.4 Integration test registration — add to VERIFY_SERVICES in integration-testing.sh:

enonic:enonic verify

2.5 CLI verify command — add enonic to cmd_verify() in uis-cli.sh, enabling ./uis verify enonic.

Validation

User reviews the playbook structure.


Phase 3: Registration and Documentation — ✅ DONE

Register the service and create documentation.

Tasks

  • 3.1 Add enonic to .uis.extend/enabled-services.conf
  • 3.2 Add packages/integration/enonic to website/sidebars.ts (Integration items) ✓
  • 3.3 Update website/docs/services/integration/index.md — add Enonic to services table ✓
  • 3.4 Create documentation page website/docs/services/integration/enonic.md

Implementation Details

3.1 enabled-services.conf — add enonic line (under integration section)

3.2 sidebars.ts — add to Integration items array (currently has rabbitmq and gravitee):

'packages/integration/enonic',

3.3 Integration index — add row to services table:

| [Enonic XP](./enonic.md) | Headless CMS platform | `./uis deploy enonic` |

3.4 Documentation — follow OpenMetadata docs page pattern (openmetadata.md):

  • Service info table (category, deploy/undeploy/verify commands, namespace)
  • What It Does section
  • Deploy / Verify / Undeploy sections
  • Configuration section (manifests, secrets, key files)
  • Troubleshooting section

Validation

cd website && npm run build

User confirms documentation builds and sidebar entry appears.


Phase 4: Build, Deploy, and Test — ✅ DONE

Build the provision host container, deploy, and verify with the tester.

Tasks

  • 4.1 Run ./uis build to build new provision host container ✓
  • 4.2 Write test instructions to talk/talk.md for the tester ✓
  • 4.3 Wait for tester results ✓ (6 rounds of testing)
  • 4.4 Fix any issues found during testing ✓ (5 issues fixed — see below)

Issues Fixed During Testing

RoundIssueFix
1Image enonic/xp:7.16.2 not foundChanged to enonic/xp:7.16.2-ubuntu
2Service only exposes port 8080Added ports 2609 and 4848 to Service
2XP_SU_PASSWORD env var ignoredPassword injected via system.properties (xp.suPassword) using entrypoint override
3-4Test D: 307→401 for login pageCheck response body ("Enonic XP") instead of HTTP status
5Test E: same redirect issueSame content-based fix

Implementation Details

4.2 Test instructions for the tester:

  1. Restart with new container: UIS_IMAGE=uis-provision-host:local ./uis restart
  2. Generate and apply secrets: ./uis secrets generate && ./uis secrets apply
  3. Deploy Enonic: ./uis deploy enonic
  4. Run verification: ./uis verify enonic (runs all 6 E2E tests)
  5. Check http://enonic.localhost in browser — should show XP welcome/login page
  6. Login with su / password from ./uis secrets show DEFAULT_ADMIN_PASSWORD
  7. Undeploy: ./uis undeploy enonic
  8. Confirm cleanup: kubectl get all -n enonic (should show nothing)

Validation

All 6 verify tests pass. Deploy and undeploy both succeed. Admin login works in browser.


Phase 5: Cleanup and Status Updates — ✅ DONE

Update investigation, roadmap, and complete the plan.

Tasks

  • 5.1 Update INVESTIGATE-enonic-xp-deployment.md — mark last next step as done ✓
  • 5.2 Update STATUS-platform-roadmap.md — mark #4 as Complete, add to Completed Investigations table ✓
  • 5.3 Move plan and investigation to completed/

Validation

User confirms all status updates are correct.


Acceptance Criteria

  • Enonic XP 7.16.2 pod is running in the enonic namespace ✓
  • Admin login with su / DEFAULT_ADMIN_PASSWORD works ✓ (via xp.suPassword in system.properties)
  • ./uis deploy enonic works end-to-end (no external dependencies needed) ✓
  • ./uis undeploy enonic cleans up all resources ✓
  • ./uis verify enonic passes all 6 tests ✓
  • Service appears in ./uis list
  • ./uis test-all --dry-run includes enonic with verify step ✓
  • http://enonic.localhost shows Enonic XP welcome/login page ✓
  • Documentation page exists at the correct sidebar location ✓
  • Website builds without errors ✓
  • Tester has verified the deployment ✓ (6 rounds, all 6 E2E tests pass)

Files to Create

FilePurpose
provision-host/uis/services/integration/service-enonic.shService definition
manifests/085-enonic-config.yamlConfigMap (XP configuration)
manifests/085-enonic-statefulset.yamlStatefulSet + Service + PVC + ServiceAccount
manifests/085-enonic-ingressroute.yamlTraefik IngressRoute
ansible/playbooks/085-setup-enonic.ymlDeployment playbook
ansible/playbooks/085-remove-enonic.ymlRemoval playbook
ansible/playbooks/085-test-enonic.ymlE2E verification (6 tests)
website/docs/services/integration/enonic.mdDocumentation page

Files to Modify

FileChange
provision-host/uis/templates/secrets-templates/00-common-values.env.templateAdd Enonic section (admin password)
provision-host/uis/templates/secrets-templates/00-master-secrets.yml.templateAdd enonic namespace block
provision-host/uis/lib/integration-testing.shAdd enonic to VERIFY_SERVICES
provision-host/uis/manage/uis-cli.shAdd enonic to cmd_verify()
.uis.extend/enabled-services.confAdd enonic
website/sidebars.tsAdd to Integration items
website/docs/services/integration/index.mdAdd Enonic to services table
website/docs/ai-developer/plans/backlog/INVESTIGATE-enonic-xp-deployment.mdMark last next step done
website/docs/ai-developer/plans/backlog/STATUS-platform-roadmap.mdUpdate #4 status