Installation
Package install and the DevStack plugin for dev/test
This page explains how to install Trilio Share Protection for OpenStack (Abacá) in two deployment contexts: the RHOSO 18 production path (OpenStack Services on OpenShift) and the Kolla-Ansible reference environment used for development and testing. Both paths are scripted and idempotent — you can re-run them safely. After installation, your control plane (abaca-api and abaca-conductor) is registered in the Keystone service catalog and ready to accept backup target enrollment, policy creation, and backup/restore requests. A local developer workstation stack (Docker Compose, no-auth mode) is also described for contributors who do not have a full OpenStack cluster available.
Before you begin, confirm that the following are in place.
Cluster requirements (all deployment paths)
- Red Hat OpenStack Services on OpenShift (RHOSO) ≥ 18 or a Kolla-Ansible–deployed OpenStack cluster (development/reference only)
- OpenShift ≥ 4.14 (RHOSO path only)
- OpenStack services: Keystone ≥ 2023.1 (with trusts enabled and domain-scoped tokens supported), Manila, Nova, Neutron, Glance, Barbican
- Dedicated MariaDB or MySQL (Galera) instance for Abacá — do not share with the OpenStack control plane
- Dedicated RabbitMQ instance for Abacá — do not share with the platform broker
- S3-compatible object storage (Wasabi, MinIO, AWS S3, etc.) with versioning and Object Lock enabled at bucket creation time
Workstation requirements
ocCLI authenticated to the target OpenShift cluster (RHOSO path);kubeconfigis the only credential needed — the admin password and CA bundle are read from the cluster- Admin OpenStack
openrcsourced in the shell (Kolla path) - Python ≥ 3.11
kustomize(for reviewing or customising manifests)libguestfs-tools/qemu-utilsif you will build the worker VM image locally- Docker or Podman with Compose (local developer stack only)
tox≥ 4.0 (running tests; optional)
Worker VM image
- A RHEL ≥ 9 base cloud image accessible on the build host
- Kopia binary, FIPS-built, version-pinned, ≥ 0.17.0
- Glance must be available to store the finished worker image
Horizon plugin (optional)
- An existing Horizon pod into which
abaca-dashboardandpython-abacaclientwill be layered
Verify that Manila is enabled on the cluster before enrolling any backup targets. The RHOSO preflight script (00-preflight.sh) checks this automatically and reports the result without aborting.
RHOSO 18 (production)
The RHOSO install script is the primary supported path. It requires only a valid kubeconfig — it derives the admin password from osp-secret and the CA bundle from the cluster.
Step 1 — Clone the repository and review the manifests
git clone https://github.com/triliovault/abaca.git
cd abaca
export KUBECONFIG=~/.kube/config-rhoso18
Step 2 — Run the one-shot installer
bash deploy/rhoso/install.sh
The installer runs eight steps in order. Use --skip-<step> to bypass any step you have already completed:
| Flag | Step | What it does |
|---|---|---|
--skip-preflight | 00-preflight.sh | Verifies CRDs, Galera, RabbitMQ, cert-manager, and admin auth; reports Manila status |
--skip-identity | 01-identity.sh | Creates generated passwords as Secrets; provisions the KeystoneService CR (service user + catalog entry) plus the worker project and role grants |
--skip-catalog | 02-catalog.sh | Creates KeystoneEndpoint CRs for the public (Route) and internal (Service) endpoints |
--skip-db | 03-database.sh | Creates MariaDBDatabase and MariaDBAccount CRs on Abacá's own Galera instance |
--skip-mq | 04-messaging.sh | Creates a TransportURL CR on Abacá's own RabbitMQ cluster |
--skip-build | 05-build.sh | Runs an in-cluster BuildConfig → ImageStream build; no local container runtime required |
--skip-config | 06-config.sh | Renders abaca.conf and my.cnf into secret/abaca-config-data |
--skip-deploy | 07-deploy.sh | Applies kustomize manifests, runs the db_sync migration Job, and waits for /healthcheck on both pods |
All objects Abacá creates carry the label app.kubernetes.io/part-of=abaca.
Example: re-run only the config and deploy steps after editing abaca.conf:
bash deploy/rhoso/install.sh \
--skip-preflight --skip-identity --skip-catalog \
--skip-db --skip-mq --skip-build
Step 3 — Run the database migration
The migration runs automatically inside 07-deploy.sh as a Kubernetes Job (db_sync). Verify it completed successfully:
oc -n abaca get jobs
oc -n abaca logs job/abaca-db-sync
The Job has backoffLimit: 0. A failure surfaces immediately rather than being buried under retries. If it fails, fix the root cause (usually a connectivity or credentials issue) and re-run:
bash deploy/rhoso/install.sh --skip-preflight --skip-identity \
--skip-catalog --skip-db --skip-mq --skip-build --skip-config
Step 4 — Register the bootstrap Domain
01-identity.sh resolves ABACA_BOOTSTRAP_DOMAIN to a project ID and records it in configmap/abaca-domain-map. 07-deploy.sh inserts this row into the database once db_sync has created the schema. Confirm the entry was recorded:
oc -n abaca get cm abaca-domain-map -o jsonpath='{.data}'
For every additional Keystone Domain that will use Abacá, register its service project manually:
POD=$(oc -n abaca get pods -l app.kubernetes.io/component=conductor \
--field-selector=status.phase=Running -o name | head -1 | cut -d/ -f2)
oc -n abaca exec "$POD" -- abaca-manage \
--config-file /etc/abaca/abaca.conf \
domain_register \
--domain-id <domain-id> \
--service-project-id <project-id>
# Confirm
oc -n abaca exec "$POD" -- abaca-manage \
--config-file /etc/abaca/abaca.conf \
domain_list
This operation is idempotent. Re-run it to correct a value. Do not pass --key-custody-project-id or --clear-key-custody unless you intend to change key custody — doing so silently orphans all existing repository passwords stored under the previous custody project.
Step 5 — Build and upload the worker VM image
Worker VMs must not fetch packages from the internet at boot. Build the image once (or after any code change) using virt-customize and guestfish, then upload it to Glance:
bash deploy/rhoso/worker/20-worker-image.sh
This script installs Kopia, NFS utilities, and abaca-worker-agent into a base RHEL cloud image and uploads the result to Glance with the property abaca_worker_image=1. Pass --distro to target a non-default RHEL variant. Pass --force to rebuild an image that is already present in Glance.
Step 6 (optional) — Install the Horizon plugin
The dashboard plugin is a separate, gated step because it modifies the shared Horizon image:
bash deploy/rhoso/08-dashboard.sh --build-only # build only, change nothing
bash deploy/rhoso/08-dashboard.sh # build and repoint Horizon
bash deploy/rhoso/08-dashboard.sh --revert # restore the previous image
Important:
10-public-cert.shis a prerequisite for08-dashboard.sh. Horizon resolves theshare-protectionendpoint atpublicURL, and the Horizon pods must trust the public route's certificate. Run10-public-cert.shbefore the dashboard step:bash deploy/rhoso/10-public-cert.sh --dry-run # review first bash deploy/rhoso/10-public-cert.sh
Step 7 — Enable Manila (if needed, development clusters only)
In production, Manila is already present with a vendor driver. On a development cluster without Manila shares, enable the generic driver:
bash deploy/rhoso/manila/10-service-image.sh # uploads a Glance image (safe)
bash deploy/rhoso/manila/11-enable.sh --dry-run # review the patch
bash deploy/rhoso/manila/11-enable.sh # patches OpenStackControlPlane
bash deploy/rhoso/manila/12-verify.sh # creates a share end-to-end
Use --assume-yes to suppress interactive prompts in automation.
Kolla-Ansible (development/reference only)
The Kolla path targets an existing Kolla-Ansible–deployed OpenStack cluster. The admin openrc must be sourced before you begin.
Step 1 — Source your admin credentials
source /path/to/admin-openrc.sh
Step 2 — Run the one-shot installer
bash deploy/kolla/install.sh
Or target a specific controller:
bash deploy/kolla/install.sh <controller-vip> <cluster-name>
The installer runs eight steps in order:
| Flag | Step | What it does |
|---|---|---|
--skip-identity | 01-identity.sh | Keystone abaca service user (roles: service, admin) + worker project |
--skip-catalog | 02-catalog.sh | Keystone service share-protection + three endpoints (public / internal / admin) |
--skip-db | 03-database.sh | MariaDB abaca database and user with a fresh random password |
--skip-mq | 04-messaging.sh | RabbitMQ /abaca vhost and user with a fresh random password |
--skip-build | 05-build.sh | rsync source to the controller; docker build the api and conductor images |
--skip-config | 06-config.sh | Render /etc/kolla/abaca-api/abaca.conf and /etc/kolla/abaca-conductor/abaca.conf |
--skip-deploy | 07-deploy.sh | Run db_sync, (re)start containers, wait for /healthcheck |
--skip-dashboard | 08-dashboard.sh | Install abaca-dashboard into the horizon container |
Generated passwords for the database and message queue users are written to cluster1-abaca-secrets.env at the repository root (mode 0600, gitignored).
Example: rapid dev loop — rebuild and restart containers only:
bash deploy/kolla/install.sh \
--skip-identity --skip-catalog --skip-db --skip-mq \
--skip-config --skip-dashboard
Step 3 — Build and upload the worker VM image
Use the maintained builder (the Kolla-specific builder was removed on 2026-08-19):
bash deploy/rhoso/worker/20-worker-image.sh
The script runs libguestfs locally on the workstation (not on the controller). The first run downloads approximately 700 MB of base image and Kopia tarball.
Step 4 — Verify a worker registers
Boot at least one worker VM before a tenant attempts to enroll a backup target:
# Read the transport URL from the controller config:
export ABACA_TRANSPORT_URL=$(ssh <controller> \
"sudo grep '^transport_url' /etc/kolla/abaca-conductor/abaca.conf" \
| cut -d' ' -f3)
# Boot a worker:
OS_CLOUD=abaca-service abaca-dev worker-boot \
--network <tenant-network> --key-name abaca-worker
# Confirm it registered:
openstack share protection worker list
You should see one entry with state=active and a last_heartbeat_at timestamp less than one minute old.
Local developer workstation (Docker Compose, no-auth)
For contributors who do not have a full OpenStack cluster, the Docker Compose stack runs abaca-api and abaca-conductor in --noauth mode with SQLite and in-memory fakes:
docker compose -f deploy/docker-compose.dev.yml up
This mode is not suitable for production. Authentication is disabled ([api] noauth = true), and the database is SQLite rather than MariaDB. Use this path only for unit-level integration work on a developer workstation.
Teardown
RHOSO:
bash deploy/rhoso/uninstall.sh
Kolla:
bash deploy/kolla/99-teardown.sh
Both scripts are idempotent and safe to run on a partially-installed cluster. Note that operator-backed CRs (RHOSO) reverse the Keystone user, catalog, and database account, but the abaca database schema and the durable RabbitMQ queues created by oslo.messaging at runtime are removed explicitly by the uninstall script, not by CR deletion.
Abacá uses oslo.config. All options are declared in code and read from an INI-style .conf file. On RHOSO the rendered file lives in secret/abaca-config-data and is mounted read-only into the pod at /etc/abaca/abaca.conf. On Kolla it lives at /etc/kolla/abaca-api/abaca.conf and /etc/kolla/abaca-conductor/abaca.conf.
Options are grouped by section. The sections most commonly tuned during installation and day-2 operations are described below.
[DEFAULT]
Global service discovery and endpoint resolution.
| Option | Type | Default | Purpose |
|---|---|---|---|
catalog_type | string | share-protection | The Keystone service type Abacá registers under. Change only if your catalog uses a site-specific type name. |
endpoint_type | string | publicURL | Which catalog endpoint the client SDK uses. Valid values: publicURL, adminURL, internalURL. On RHOSO, publicURL is the correct value. |
[abaca]
Identity of the Abacá service account and the bootstrap worker project.
| Option | Type | Default | Purpose |
|---|---|---|---|
service_user_id | string | — | Keystone UUID of the Abacá service user. Populated automatically by 01-identity.sh. |
service_user_name | string | — | Display name of the service user (typically abaca). |
worker_project_id | string | — | ID of the project where worker VMs for the bootstrap Domain are booted. Used as a fallback when no domain_service_projects row exists for a Domain. |
worker_project_name | string | — | Human-readable name of the same project. |
For multi-Domain deployments,
worker_project_idis a single-Domain bootstrap allowance only. Register each Domain withabaca-manage domain_registerinstead of relying on this fallback.
[api]
HTTP listener configuration for abaca-api.
| Option | Type | Default | Purpose |
|---|---|---|---|
bind_host | string | 0.0.0.0 | Address the gunicorn process binds to. Restrict to a specific IP in environments where binding to all interfaces is undesirable. |
bind_port | integer | 9797 | TCP port for the API. Must match the Keystone catalog endpoints and any load-balancer rules. |
noauth | boolean | false | Disable Keystone token validation. For developer workstation use only. Never set to true in production. |
max_limit | integer | 1000 | Maximum page size for list endpoints. |
default_limit | integer | 100 | Default page size when the caller does not specify a limit parameter. |
[conductor]
Job scheduling, fleet management, and reconciliation tuning.
| Option | Type | Default | Purpose |
|---|---|---|---|
scheduler_interval | integer | 60 | Seconds between policy-driven backup scheduling sweeps. Reduce on clusters with many policies and tight schedule windows; increase on idle development clusters. |
reconciliation_interval | integer | 300 | Seconds between reconciliation sweeps. The sweep detects orphaned jobs, dead workers, and overdue maintenance. |
worker_heartbeat_deadline_seconds | integer | 60 | Seconds without a heartbeat before the conductor considers a worker dead and reassigns its jobs. |
worker_heartbeat_interval_seconds | integer | 10 | How often (in seconds) a healthy worker sends a heartbeat. Must be well below worker_heartbeat_deadline_seconds. |
sweep_command_wait_seconds | integer | 120 | How long the reconciliation sweep waits for an in-flight command to complete before flagging the job as stuck. |
worker_token_ttl_seconds | integer | 1800 | Lifetime of the short-lived token issued to a worker VM at job start. |
maintenance_interval_seconds | integer | 604800 | Seconds between scheduled repository maintenance runs (default: 7 days). |
catalogue_sync_interval_seconds | integer | 3600 | How often the conductor synchronises the backup catalogue from the Kopia repository into the database. |
usage_sample_interval_seconds | integer | 21600 | How often the conductor samples usage data for metering (default: 6 hours). |
min_workers | integer | 1 | Minimum number of healthy worker VMs the conductor will maintain. If the fleet drops below this, the conductor boots replacement workers. |
worker_boot_cooldown_seconds | integer | 180 | Minimum seconds between consecutive worker boot attempts, preventing a rapid boot loop on repeated failures. |
worker_boot_max_failures | integer | 3 | Number of consecutive boot failures within worker_boot_failure_window_seconds that cause the conductor to stop automatic boots and raise an alert. |
worker_boot_failure_window_seconds | integer | 7200 | Rolling window (seconds) for counting consecutive boot failures. |
worker_boot_grace_seconds | integer | 1200 | Seconds the conductor waits for a freshly booted VM to register before treating the boot as failed. |
worker_boot_os_cloud | string | abaca-service | Named cloud entry from clouds.yaml used to boot worker VMs. Must correspond to a project with the right quota and network access. |
worker_boot_image | string | abaca-worker-0.23.1 | Glance image name for worker VMs. Update this after uploading a new worker image with 20-worker-image.sh. |
worker_boot_flavor | string | m1.small | Nova flavor for worker VMs. |
worker_boot_network | string | — | Neutron network name or ID where worker VMs are attached. Must be routable to the Manila share export locations. |
worker_boot_key_name | string | — | Name of the Nova key pair injected into worker VMs for emergency SSH access. |
worker_api_url | string | — | URL at which the conductor reaches the worker API listener. Set when workers are on a separate network segment. |
worker_api_ca_file | string | — | Path to the CA bundle used to verify the worker API TLS certificate. |
worker_api_host_aliases | list | `` | Additional hostnames the conductor accepts in worker API TLS certificates. |
queued_job_deadline_seconds | integer | 300 | Seconds a job may sit in queued state before the reconciliation sweep flags it as stuck. |
[database]
| Option | Type | Default | Purpose |
|---|---|---|---|
connection | string | — | SQLAlchemy database URL, e.g. mysql+pymysql://abaca:<password>@<host>/abaca?read_default_file=/etc/my.cnf. On RHOSO, rendered automatically by 06-config.sh with TLS options via my.cnf. |
[enrollment]
| Option | Type | Default | Purpose |
|---|---|---|---|
dispatch | string | — | Whether target enrollment jobs are dispatched via rpc (to a worker VM) or inline (in the conductor process). Use rpc in production. |
[kopia]
Controls how the Kopia backup engine is invoked inside worker VMs.
| Option | Type | Default | Purpose |
|---|---|---|---|
binary | string | kopia | Path to the Kopia executable on the worker VM. Change if Kopia is installed outside the default PATH. |
require_fips_profile | boolean | true | Refuse to connect to repositories that were not created with the FIPS-approved algorithm profile (AES-256-GCM-HMAC-SHA256, HMAC-SHA256-128, PBKDF2). Do not disable in production. |
subprocess_timeout | integer | 3600 | Maximum seconds a single Kopia subprocess may run before the worker agent kills it. |
executor | string | — | How Kopia is invoked. Valid values: http (leased-command transport, production), ephemeral_container (Docker/Podman container per job, local dev only). |
image | string | — | Container image for the ephemeral_container executor. Not used in production. |
container_engine | string | — | docker or podman. Used only with ephemeral_container. |
container_network | string | — | Docker/Podman network for ephemeral containers. Used only with ephemeral_container. |
[worker]
Configuration read by abaca-worker-agent inside the worker VM.
| Option | Type | Default | Purpose |
|---|---|---|---|
capacity_slots | integer | — | Number of concurrent jobs this worker VM may run simultaneously. The fleet picker will not assign a new job to a worker at or above this limit. |
mount_base | string | /var/lib/abaca/mnt | Directory under which the agent mounts Manila shares. |
command_timeout_seconds | integer | 300 | Seconds before an idle command times out. |
command_lease_seconds | integer | 120 | Duration of the lease the agent holds on a claimed command. Must be renewed before expiry. |
max_command_duration_seconds | integer | 21600 | Hard upper bound (seconds) on any single command's total runtime. |
claim_poll_interval_seconds | float | 2 | How often (seconds) the agent polls for new commands when in short-poll mode. |
long_poll_seconds | integer | 20 | Duration of each long-poll request to the conductor. |
progress_interval_seconds | integer | 30 | How often (seconds) the agent reports transfer progress back to the conductor. |
listener_port | integer | 9798 | TCP port the worker agent's HTTP listener binds to. |
command_poll_interval_seconds | float | 2 | How often (seconds) the listener checks for new commands in its queue. |
id | string | — | UUID assigned to this worker VM at boot. Populated automatically; do not set manually. |
api_url | string | — | URL of the conductor's worker-facing API endpoint, injected at boot time. |
token | string | — | Short-lived token the agent uses to authenticate to the conductor, injected at boot time. |
api_ca_file | string | — | CA bundle for verifying the conductor's TLS certificate. |
Annotated sample abaca.conf
[DEFAULT]
catalog_type = share-protection
endpoint_type = publicURL
[abaca]
service_user_name = abaca
worker_project_name = abaca-service
[api]
bind_host = 0.0.0.0
bind_port = 9797
noauth = false
max_limit = 1000
default_limit = 100
[conductor]
scheduler_interval = 60
reconciliation_interval = 300
worker_heartbeat_deadline_seconds = 60
worker_heartbeat_interval_seconds = 10
min_workers = 1
worker_boot_os_cloud = abaca-service
worker_boot_image = abaca-worker-0.23.1
worker_boot_flavor = m1.small
worker_boot_network = abaca-worker-net
worker_boot_key_name = abaca-worker
worker_boot_cooldown_seconds = 180
worker_boot_grace_seconds = 1200
worker_boot_max_failures = 3
worker_boot_failure_window_seconds = 7200
maintenance_interval_seconds = 604800
[database]
connection = mysql+pymysql://abaca:<password>@<db-host>/abaca?read_default_file=/etc/my.cnf
[enrollment]
dispatch = rpc
[kopia]
binary = kopia
require_fips_profile = true
subprocess_timeout = 3600
executor = http
[worker]
capacity_slots = 4
mount_base = /var/lib/abaca/mnt
command_timeout_seconds = 300
command_lease_seconds = 120
max_command_duration_seconds = 21600
long_poll_seconds = 20
progress_interval_seconds = 30
listener_port = 9798
Once the control plane is running, you interact with Abacá through three surfaces:
- OpenStack CLI — the
openstack share protectionsubcommands provided bypython-abacaclient - REST API — versioned at
/v1, authenticated with Keystone tokens - Horizon dashboard — the
abaca-dashboardpanels in the OpenStack web UI
Verifying the installation
Confirm that abaca-api and abaca-conductor are healthy:
# RHOSO: check pod status
oc -n abaca get pods
# Confirm the service appears in the Keystone catalog
openstack catalog show share-protection
Registering a Domain (operators)
Before tenants can enroll backup targets, each Keystone Domain must be mapped to a service project. The bootstrap Domain is registered automatically during installation. For additional Domains:
POD=$(oc -n abaca get pods -l app.kubernetes.io/component=conductor \
--field-selector=status.phase=Running -o name | head -1 | cut -d/ -f2)
oc -n abaca exec "$POD" -- abaca-manage \
--config-file /etc/abaca/abaca.conf \
domain_register \
--domain-id <keystone-domain-id> \
--service-project-id <project-id>
Enrolling a backup target (Domain owners)
A Domain owner (a user holding the abaca_domain_owner Keystone role) registers an S3 bucket as a backup target. Abacá runs preflight conformance checks, generates an encryption key stored in Barbican, and initialises a Kopia repository — all as a job on a worker VM:
openstack share protection target create \
--name my-backup-target \
--template-id <template-id>
Monitor enrollment progress:
openstack share protection job show <job-id>
Creating a protection policy
A policy binds a Manila share to a backup target template, sets a cron schedule, and defines retention:
openstack share protection policy create \
--share-id <manila-share-id> \
--template-id <template-id> \
--schedule "0 2 * * *" \
--retention-days 30
Requesting an on-demand backup
openstack share protection backup create \
--share-id <manila-share-id> \
--target-id <target-id>
Restoring from a backup
Restore to a new share (or sub-path, or single file) from a completed backup:
openstack share protection restore create \
--backup-id <backup-id> \
--destination-share-id <share-id>
Checking worker fleet health (operators)
openstack share protection worker list
Workers in state=active with a recent last_heartbeat_at are healthy and accepting jobs. Workers missing heartbeats for more than worker_heartbeat_deadline_seconds seconds are considered dead and will be replaced by the conductor.
Rebuilding the catalog from a repository (disaster recovery)
If the Abacá database is lost but S3 data is intact, reconstruct the catalog:
oc -n abaca exec "$POD" -- abaca-manage \
--config-file /etc/abaca/abaca.conf \
rebuild-from-repository \
--target-id <target-id>
Example 1: Verify the service catalog entry
After installation, confirm that Abacá registered correctly with Keystone.
openstack catalog show share-protection
Expected output (RHOSO — public and internal endpoints only):
+-----------+---------------------------------------------------------------+
| Field | Value |
+-----------+---------------------------------------------------------------+
| endpoints | RegionOne |
| | publicURL: https://abaca-api.apps.example.com/v1 |
| | internalURL: http://abaca-api.abaca.svc.cluster.local:9797/v1 |
| id | 8f2c... |
| name | abaca |
| type | share-protection |
+-----------+---------------------------------------------------------------+
Example 2: Run the preflight check standalone
Before committing to a full install, run the preflight step on its own to surface any cluster issues.
bash deploy/rhoso/install.sh \
--skip-identity --skip-catalog --skip-db --skip-mq \
--skip-build --skip-config --skip-deploy
Expected output (healthy cluster):
--- 00 preflight ---
[preflight] Galera: OK
[preflight] RabbitMQ: OK
[preflight] cert-manager: OK
[preflight] Keystone: OK
[preflight] Manila: present
[preflight] All checks passed.
Example 3: Check pod readiness after deployment
oc -n abaca get pods
Expected output:
NAME READY STATUS RESTARTS AGE
abaca-api-7d9f4b8c6-xkqpz 1/1 Running 0 4m
abaca-conductor-6b5c9d7f4-mnjvr 1/1 Running 0 4m
abaca-db-sync-x4tgp 0/1 Completed 0 5m
The abaca-db-sync Job must show Completed before the other pods are considered healthy.
Example 4: Register an additional Domain's service project
POD=$(oc -n abaca get pods -l app.kubernetes.io/component=conductor \
--field-selector=status.phase=Running -o name | head -1 | cut -d/ -f2)
oc -n abaca exec "$POD" -- abaca-manage \
--config-file /etc/abaca/abaca.conf \
domain_register \
--domain-id d1e2f3a4-0000-0000-0000-000000000001 \
--service-project-id a9b8c7d6-0000-0000-0000-000000000002
Expected output:
Domain d1e2f3a4-0000-0000-0000-000000000001 registered with service project a9b8c7d6-0000-0000-0000-000000000002
List all registered Domains to confirm:
oc -n abaca exec "$POD" -- abaca-manage \
--config-file /etc/abaca/abaca.conf \
domain_list
Expected output:
+--------------------------------------+--------------------------------------+
| domain_id | service_project_id |
+--------------------------------------+--------------------------------------+
| d1e2f3a4-0000-0000-0000-000000000001 | a9b8c7d6-0000-0000-0000-000000000002 |
+--------------------------------------+--------------------------------------+
Example 5: Fast dev loop on Kolla — rebuild and restart only
After a code change, skip all setup steps and rebuild/restart the containers:
bash deploy/kolla/install.sh \
--skip-identity --skip-catalog --skip-db --skip-mq \
--skip-config --skip-dashboard
This runs only 05-build.sh (rsync + docker build) and 07-deploy.sh (db_sync + container restart).
Example 6: Confirm a worker VM registered
After booting a worker with abaca-dev worker-boot:
openstack share protection worker list
Expected output (one healthy worker):
+--------------------------------------+--------+---------------------+
| id | state | last_heartbeat_at |
+--------------------------------------+--------+---------------------+
| 7c3a1e8f-0000-0000-0000-000000000001 | active | 2026-09-01T10:23:45 |
+--------------------------------------+--------+---------------------+
If no workers appear, or state is not active, see the troubleshooting section.
Use a consistent format for each issue: Symptom describes what you observe; Likely cause explains why; Fix tells you what to do.
Symptom: abaca-db-sync Job fails with exit code 1; logs show MySQL error 1050: Table already exists.
Likely cause: The API pod started (triggered by an OpenShift image.openshift.io/triggers annotation on the Deployment) and called create_all() before the migration Job ran, creating tables without stamping alembic_version. The migration then conflicts with the pre-created tables.
Fix: Do not drop the database if it contains real data. Identify which table the migration tried to create, add any missing columns by hand to match the migration output, then set the version stamp:
UPDATE alembic_version SET version_num='<revision>';
Verify with SELECT * FROM information_schema.columns WHERE table_schema='abaca'; before and after. Then re-run the deploy step:
bash deploy/rhoso/install.sh \
--skip-preflight --skip-identity --skip-catalog \
--skip-db --skip-mq --skip-build --skip-config
Symptom: Pods are Running but kubectl logs shows connection refused or SSL handshake failed for database connections.
Likely cause: The [database] connection URL was rendered without the ?read_default_file=/etc/my.cnf suffix, or my.cnf is missing the ssl-ca directive pointing to the CA bundle.
Fix: Re-run the config step, which regenerates secret/abaca-config-data and restarts pods:
bash deploy/rhoso/install.sh \
--skip-preflight --skip-identity --skip-catalog \
--skip-db --skip-mq --skip-build
Verify the rendered connection string:
oc -n abaca get secret abaca-config-data -o jsonpath='{.data.abaca\.conf}' \
| base64 -d | grep connection
Symptom: Horizon Share Protection panels render empty (no error, just no data).
Likely cause: The public route for abaca-api is not serving a certificate that the Horizon pods trust. Horizon resolves the share-protection endpoint at publicURL, and a certificate verification failure silently returns empty results.
Fix: Run 10-public-cert.sh before or after 08-dashboard.sh:
bash deploy/rhoso/10-public-cert.sh --dry-run # review
bash deploy/rhoso/10-public-cert.sh
bash deploy/rhoso/08-dashboard.sh
Symptom: After 08-dashboard.sh, Share Protection panels are gone after a Horizon pod restart or kolla-ansible reconfigure horizon (Kolla path).
Likely cause: The dashboard plugin is installed into the running container's venv; a new container image wipes it.
Fix (Kolla): Re-run 08-dashboard.sh after any Horizon reconfigure:
bash deploy/kolla/install.sh --skip-identity --skip-catalog --skip-db \
--skip-mq --skip-build --skip-config --skip-deploy
Fix (RHOSO): Use --revert to restore the previous image, then rebuild:
bash deploy/rhoso/08-dashboard.sh --revert
bash deploy/rhoso/08-dashboard.sh
Symptom: Worker VM boots (visible in Nova) but never appears in openstack share protection worker list; state never becomes active.
Likely cause (most common): The worker VM cannot reach the conductor's RabbitMQ port or the conductor's worker API URL from inside the tenant network. A secondary cause is a mismatched transport URL between the worker agent's config and the conductor.
Fix:
- SSH into the worker VM and check the agent logs:
journalctl -u abaca-worker-agent - Confirm the worker can reach the conductor's RabbitMQ port (5672) and the
worker_api_urlfrom inside the VM. - On Kolla, verify the transport URL matches between the conductor config and the VM:
ssh <controller> "sudo grep '^transport_url' /etc/kolla/abaca-conductor/abaca.conf" - If the image predates the worker agent being baked in (the
abaca_worker_image=1property is absent from Glance), rebuild:bash deploy/rhoso/worker/20-worker-image.sh --force
Symptom: abaca-manage domain_register succeeds, but GET /v1/domain still reports is_service_project: false for all projects, and the Horizon "Register Bucket" button is hidden everywhere.
Likely cause: No domain_service_projects row exists in the database, so the API is falling back to the [abaca] worker_project_id single-Domain bootstrap value, which belongs to one Domain only.
Fix: Confirm the row was written:
oc -n abaca exec "$POD" -- abaca-manage \
--config-file /etc/abaca/abaca.conf \
domain_list
If the Domain is missing, re-run domain_register with the correct IDs. If the Domain appears but the API still returns is_service_project: false, verify that the abaca_domain_owner Keystone role is assigned to the user in the correct Domain scope.
Symptom: worker_boot attempts fail repeatedly; the conductor stops booting new workers and emits an alert.
Likely cause: The conductor hit worker_boot_max_failures (default: 3) consecutive failures within worker_boot_failure_window_seconds (default: 7200 seconds). Common causes include a wrong worker_boot_image name (the image may not exist in Glance), an incorrect worker_boot_network, or Nova quota exhaustion.
Fix:
- Check conductor logs for the boot failure reason:
oc -n abaca logs deployment/abaca-conductor | grep -i "worker boot" - Verify the image exists in Glance with the expected name:
openstack image show "$(grep worker_boot_image /etc/abaca/abaca.conf | awk '{print $3}')" - Correct the
[conductor] worker_boot_imageorworker_boot_networkinsecret/abaca-config-dataand re-run the config step:bash deploy/rhoso/install.sh --skip-preflight --skip-identity \ --skip-catalog --skip-db --skip-mq --skip-build
Symptom: Kolla deployment: container is Running but GET /healthcheck returns 502 or 500.
Likely cause: One of three issues — the db_sync migration did not complete, the RabbitMQ vhost is missing, or abaca.conf has a syntax error.
Fix:
# Check container logs on the controller:
docker logs abaca_api
docker logs abaca_conductor
# Re-run just the deploy step (which re-runs db_sync first):
bash deploy/kolla/install.sh --skip-identity --skip-catalog --skip-db \
--skip-mq --skip-build --skip-config --skip-dashboard
If the config file was edited in place, restart the containers to pick up the change:
docker restart abaca_api abaca_conductor
Symptom: RabbitMQ TLS listener never becomes ready; the conductor pod logs Peer discovery: no nodes available for auto-clustering.
Likely cause: RabbitMq.spec.tls.caSecretName was pointed at a CA bundle Secret instead of the cert-manager certificate Secret. The TLS listener fails to configure, which manifests as a clustering error rather than a TLS error.
Fix: Both caSecretName and secretName in RabbitMq.spec.tls must reference the same cert-manager certificate Secret (which carries ca.crt), not the abaca-ca-bundle Secret (which is a concatenated PEM bundle). Update the RabbitMq CR and allow the operator to reconcile.
Symptom: oc apply on the CA bundle Secret fails or silently truncates the bundle; pods cannot verify Keystone or tenant S3 endpoints.
Likely cause: oc apply stores a full copy of the object in the last-applied-configuration annotation. The platform CA bundle (~245 KB, ~160 certificates) exceeds the 256 KB annotation limit.
Fix: Always use oc create or oc replace (never oc apply) for secret/abaca-ca-bundle:
oc -n abaca replace -f abaca-ca-bundle.yaml