Getting Started
Prerequisites and steps to make your first API request
This page walks you through everything you need to make your first successful API request against Trilio Share Protection for OpenStack (codename Abacá). You will install the client library, bring up a local development stack with Docker Compose, register a backup target, attach a protection policy to a Manila share, and trigger an on-demand backup — all without requiring a real OpenStack environment. By the end, you will have end-to-end confirmation that the API is reachable and that the backup job state machine progresses from queued to available.
Before you begin, make sure you have the following:
Runtime and tools
- Python 3.11 or 3.12 (3.12 is the primary target; both are supported)
- Docker or Podman (required for the local dev stack only)
curlor any HTTP client for ad-hoc requestspipandvenvavailable on yourPATH
OpenStack services (required only when connecting to a real cluster — not needed for the local dev stack)
- OpenStack ≥ 2023.1 (Antelope) or RHOSO 18
- Keystone (Identity)
- Manila (Shared File System service)
- Barbican (Key Manager service)
- Nova and Neutron (required for DHSS=true share network attachment)
Object storage (required only for real backups)
- An S3-compatible bucket on AWS S3, MinIO, Ceph RGW, or ODF Wasabi
- Object lock enabled on the bucket at creation time (cannot be added later)
OpenShift (required only for production control-plane deployment)
- OpenShift ≥ 4.12
Database and messaging (required only for production deployment)
- MariaDB 10.x or later
- RabbitMQ
Optional but recommended
python-abacaclientinstalled (gives you theopenstack share protection …CLI)- The
abaca-dashboardHorizon plugin (gives you a graphical view in the OpenStack web UI)
The fastest path to a working API request is the local Docker Compose dev stack. It runs the API in --noauth mode on http://localhost:9797 with an SQLite database and in-memory OpenStack fakes — no real OpenStack, no S3 bucket, and no Keystone token required.
- Clone the repository and enter it
git clone <repo-url> abaca
cd abaca
- Start the dev stack
cd deploy
docker compose -f docker-compose.dev.yml up --build
Wait until you see the API ready message. The service listens on http://localhost:9797.
- Confirm the API is reachable
curl -s http://localhost:9797/healthcheck
A 200 OK response confirms the control plane is up.
- Register a backup target
curl -s -XPOST http://localhost:9797/v1/targets \
-H 'Content-Type: application/json' \
-d '{
"name": "primary",
"endpoint": "https://s3.example.com",
"bucket": "tenant-abaca",
"barbican_secret_refs": ["https://barbican/secrets/pw"],
"trust_id": "trust-1"
}'
Note the id field in the response — you need it in the next steps.
- Create a protection policy
curl -s -XPOST http://localhost:9797/v1/policies \
-H 'Content-Type: application/json' \
-d '{
"name": "nightly",
"share_id": "share-uuid-0001",
"target_id": "<TARGET_ID>",
"schedule": "0 2 * * *",
"retention": {"daily": 7}
}'
- Trigger an on-demand backup
curl -s -XPOST http://localhost:9797/v1/backups \
-H 'Content-Type: application/json' \
-d '{
"share_id": "share-uuid-0001",
"target_id": "<TARGET_ID>"
}'
The response includes a job_id. Poll it to watch the state machine advance to available.
- Poll the job until it completes
curl -s http://localhost:9797/v1/jobs/<JOB_ID>
Repeat until status is available (or error — see Troubleshooting).
These steps expand the quickstart with full context, expected output, and next-action guidance.
Step 1 — Install the Python client library (optional but recommended)
Installing python-abacaclient gives you both the openstack share protection … CLI and a Python SDK you can use in your own code. It has no dependency on the server package.
pip install python-abacaclient
Verify the plugin loaded:
openstack share protection --help
You should see a list of subcommands (target, policy, backup, restore, job, usage, worker, coverage). If the command is not found, ensure the virtualenv where you installed the package is active.
Step 2 — Start the local dev stack
The dev stack uses Docker Compose to start the abaca-api and abaca-conductor services together with a minimal set of in-process fakes. No external OpenStack services, no real S3 bucket, and no Keystone token are required in this mode.
cd deploy
docker compose -f docker-compose.dev.yml up --build
The API comes up in --noauth dev mode, meaning Keystone authentication is bypassed. This mode must never be used in production. The API listens on http://localhost:9797.
Success indicator: the terminal shows both the abaca-api and abaca-conductor containers running without error. You can also verify:
curl -s http://localhost:9797/healthcheck
# Expected: HTTP 200
Step 3 — Register a backup target
A backup target represents an S3-compatible bucket together with the Barbican secret references for its credentials. This is the destination for all encrypted backups belonging to one tenant.
In the dev stack, you supply a fake endpoint and a fake Barbican secret href — the in-memory fakes accept any well-formed values.
curl -s -XPOST http://localhost:9797/v1/targets \
-H 'Content-Type: application/json' \
-d '{
"name": "primary",
"endpoint": "https://s3.example.com",
"bucket": "tenant-abaca",
"barbican_secret_refs": ["https://barbican/secrets/pw"],
"trust_id": "trust-1"
}' | python3 -m json.tool
The response body includes an id field — copy it. Every subsequent call that references this target uses that ID as <TARGET_ID>.
Why trust_id? A Keystone trust is a delegated authorization token that lets Abacá act on your behalf — fetching secrets from Barbican and performing Manila operations — without you being logged in for every operation. In a real deployment this trust is created for you automatically during enrollment; in the dev stack any non-empty string is accepted.
Step 4 — Create a protection policy
A protection policy binds a Manila share to a backup target and defines when automated backups run (a cron schedule) and how many backups are kept (retention settings). Once a policy exists, the abaca-conductor schedules backups automatically; you do not need to trigger them manually.
curl -s -XPOST http://localhost:9797/v1/policies \
-H 'Content-Type: application/json' \
-d '{
"name": "nightly",
"share_id": "share-uuid-0001",
"target_id": "<TARGET_ID>",
"schedule": "0 2 * * *",
"retention": {"daily": 7}
}' | python3 -m json.tool
The schedule field is a standard five-field cron expression (minute hour day-of-month month day-of-week). The retention.daily: 7 setting keeps the seven most recent daily backups; the conductor's maintenance job prunes older ones from the Kopia repository automatically.
Success indicator: the response includes a policy id and status: active.
Step 5 — Trigger an on-demand backup
You can request a backup at any time, independent of the policy schedule. This is useful for one-off snapshots before a risky change.
curl -s -XPOST http://localhost:9797/v1/backups \
-H 'Content-Type: application/json' \
-d '{
"share_id": "share-uuid-0001",
"target_id": "<TARGET_ID>"
}' | python3 -m json.tool
The response includes both a backup_id and a job_id. The backup record is created immediately, but the actual data transfer is asynchronous — the job drives it through the state machine.
Step 6 — Poll the job to completion
Every asynchronous operation in Abacá is tracked as a job. The job moves through a fixed sequence of states:
queued → provisioning_network → provisioning_source → connecting_repository → transferring → finalizing → releasing → available (or error)
Each state name describes what the service is currently doing. Poll the job endpoint until you reach a terminal state:
curl -s http://localhost:9797/v1/jobs/<JOB_ID> | python3 -m json.tool
In the dev stack with in-memory fakes, the job completes almost instantly. Against a real cluster with a worker VM, allow time for network provisioning and data transfer.
Success indicator: "status": "available" in the response. If you see "status": "error", check error_category — tenant_action_required means you need to fix a configuration (for example, a bad bucket or missing credential), while operator_action_required means the infrastructure needs attention.
Step 7 — Verify using the CLI (optional)
If you installed python-abacaclient, you can also inspect resources through the OpenStack CLI. In a real cluster, source your openrc first; against the dev stack, the --noauth mode means no credentials are needed.
# List targets
openstack share protection target list
# List backups
openstack share protection backup list
# Show job detail
openstack share protection job show <JOB_ID>
Example 1 — Register a backup target and capture its ID
This pattern registers a target and captures its ID in a shell variable for use in subsequent commands.
TARGET_ID=$(curl -s -XPOST http://localhost:9797/v1/targets \
-H 'Content-Type: application/json' \
-d '{
"name": "primary",
"endpoint": "https://s3.example.com",
"bucket": "tenant-abaca",
"barbican_secret_refs": ["https://barbican/secrets/pw"],
"trust_id": "trust-1"
}' | python3 -c "import sys,json; print(json.load(sys.stdin)['id'])")
echo "Target ID: $TARGET_ID"
Expected output:
Target ID: 3f2a1b9c-0001-0002-0003-000000000001
Example 2 — Create a policy, run a backup, and poll to completion in one script
This end-to-end script mirrors exactly what the functional smoke test (abaca/tests/functional/test_smoke.py) exercises programmatically.
#!/usr/bin/env bash
set -euo pipefail
BASE=http://localhost:9797/v1
# 1. Register target
TARGET_ID=$(curl -s -XPOST "$BASE/targets" \
-H 'Content-Type: application/json' \
-d '{"name":"primary","endpoint":"https://s3.example.com",
"bucket":"tenant-abaca",
"barbican_secret_refs":["https://barbican/secrets/pw"],
"trust_id":"trust-1"}' \
| python3 -c "import sys,json; print(json.load(sys.stdin)['id'])")
echo "[1] Target: $TARGET_ID"
# 2. Attach a protection policy
curl -s -XPOST "$BASE/policies" \
-H 'Content-Type: application/json' \
-d "{\"name\":\"nightly\",\"share_id\":\"share-uuid-0001\",
\"target_id\":\"$TARGET_ID\",\"schedule\":\"0 2 * * *\",
\"retention\":{\"daily\":7}}" > /dev/null
echo "[2] Policy created"
# 3. Trigger backup
JOB_ID=$(curl -s -XPOST "$BASE/backups" \
-H 'Content-Type: application/json' \
-d "{\"share_id\":\"share-uuid-0001\",\"target_id\":\"$TARGET_ID\"}" \
| python3 -c "import sys,json; print(json.load(sys.stdin)['job_id'])")
echo "[3] Job: $JOB_ID"
# 4. Poll until terminal state
for i in $(seq 1 30); do
STATUS=$(curl -s "$BASE/jobs/$JOB_ID" \
| python3 -c "import sys,json; print(json.load(sys.stdin)['status'])")
echo " status: $STATUS"
[[ "$STATUS" == "available" || "$STATUS" == "error" ]] && break
sleep 2
done
echo "[4] Final status: $STATUS"
Expected output (dev stack with fakes — completes almost instantly):
[1] Target: 3f2a1b9c-0001-0002-0003-000000000001
[2] Policy created
[3] Job: a1b2c3d4-0001-0002-0003-000000000099
status: queued
status: transferring
status: available
[4] Final status: available
Example 3 — Using the Python SDK
The python-abacaclient package includes a thin SDK client you can use directly in Python code.
from abacaclient.client import Client
# In --noauth dev mode, any non-empty string is accepted as a token.
# Against a real cluster, supply a valid Keystone token.
client = Client("http://localhost:9797", token="dev-noauth")
# List existing targets
targets = client.target_list()
for t in targets:
print(t["id"], t["name"])
# Create a new target
target = client.target_create(
name="primary",
endpoint="https://s3.example.com",
bucket="tenant-abaca",
barbican_secret_refs=["https://barbican/secrets/pw"],
trust_id="trust-1",
)
print("Created target:", target["id"])
Non-2xx responses raise abacaclient.exceptions.AbacaClientError, which carries the HTTP status and the error envelope fields (code, title, detail, category).
Example 4 — Run the built-in functional smoke test
The smoke test drives the complete target-create → policy-create → backup flow through the full state machine using in-memory fakes and FakeKopia, with no running server required.
# From the repo root, with the dev virtualenv active:
python -m venv .venv && . .venv/bin/activate
pip install -e ".[test]" -e ./python-abacaclient -e ./abaca-dashboard
pytest abaca/tests/functional/test_smoke.py -q
Expected output:
. [100%]
1 passed in 0.42s
Issue: docker compose command not found
Symptom: Running docker compose -f docker-compose.dev.yml up --build prints docker: 'compose' is not a docker command.
Cause: Older Docker installations ship the legacy docker-compose (v1) binary instead of the built-in Compose v2 plugin.
Fix: Install Docker Compose v2 (docker compose as a subcommand) from the Docker documentation, or replace docker compose with docker-compose if you are pinned to v1.
Issue: curl to localhost:9797 returns Connection refused
Symptom: curl: (7) Failed to connect to localhost port 9797: Connection refused.
Cause: The abaca-api container has not finished starting, or it exited due to a startup error.
Fix: Run docker compose -f docker-compose.dev.yml logs abaca_api to inspect startup output. Common causes are a port conflict (another process already bound to 9797) or a missing build artifact. If the container exited, look for a Python traceback in the logs. Rebuild with --build and try again.
Issue: API returns 500 or 502 on /healthcheck
Symptom: The containers are running but curl http://localhost:9797/healthcheck returns a 500 or 502 response.
Cause: A database migration failure or misconfiguration prevented the API from initialising cleanly.
Fix: Check docker compose -f docker-compose.dev.yml logs abaca_api and abaca_conductor for the root cause. If you see a migration error, ensure abaca-manage has run db_sync. Restart both containers after fixing the underlying issue.
Issue: Backup job stalls in queued state
Symptom: Polling GET /v1/jobs/<JOB_ID> repeatedly returns "status": "queued" and never advances.
Cause: The abaca-conductor is either not running, not connected to the message bus, or — on a real cluster — there are no registered workers with available capacity slots.
Fix: Verify the conductor container is healthy: docker compose -f docker-compose.dev.yml ps. In the dev stack the conductor should pick up jobs automatically. On a real cluster, check that at least one worker VM is registered and in state=active by running openstack share protection worker list or GET /v1/admin/workers.
Issue: Backup job reaches error state with tenant_action_required
Symptom: GET /v1/jobs/<JOB_ID> returns "status": "error" and "error_category": "tenant_action_required".
Cause: Something in your configuration needs to be corrected — common causes include an unreachable or misconfigured S3 bucket, a missing or expired Barbican secret reference, or an invalid Keystone trust.
Fix: Read the detail field in the error response for the specific message. Correct the underlying configuration (for example, verify your bucket endpoint, credentials, and object-lock settings), then re-register the target or re-trigger the backup.
Issue: Backup job reaches error state with operator_action_required
Symptom: GET /v1/jobs/<JOB_ID> returns "status": "error" and "error_category": "operator_action_required".
Cause: A problem in the infrastructure or the Abacá service itself needs attention — for example, the worker VM could not be booted, the RabbitMQ connection dropped, or the conductor hit an unexpected internal error.
Fix: Report the detail and code fields from the error response to your platform operator. On a self-managed cluster, check docker compose -f docker-compose.dev.yml logs abaca_conductor for a stack trace.
Issue: openstack share protection commands are not recognised
Symptom: Running openstack share protection target list prints openstack: 'share' is not an openstack command.
Cause: python-abacaclient is not installed in the active Python environment, or the OSC plugin entry point has not been registered.
Fix: Install the package in the same environment where openstack is installed: pip install python-abacaclient. If you installed it with pip install -e ./python-abacaclient in a virtualenv, make sure that virtualenv is activated before invoking openstack.
Issue: pip install fails on Python < 3.11
Symptom: The install fails with a syntax or compatibility error referencing a Python version.
Cause: Abacá requires Python 3.11 or 3.12. Older versions are not supported.
Fix: Switch to a Python 3.11 or 3.12 interpreter. Use python3 --version to confirm, and create a fresh virtualenv with the correct version: python3.12 -m venv .venv.