Trilio Share Protection Backup and Recovery as a Service for OpenStack Manila shares
Guide

Your First Request

A minimal working example using curl or an HTTP client


Overview

This page walks you through making your first authenticated request to the Trilio Share Protection (Abacá) REST API. By the end, you will have obtained a Keystone token, listed your backup targets with curl, and made the equivalent call using the python-abacaclient SDK — giving you a working foundation for every other workflow in the product. Getting this baseline right matters because every Abacá operation, whether creating a protection policy, triggering an on-demand backup, or monitoring a job, flows through the same authentication model and base URL structure covered here.


Prerequisites

Before you begin, make sure you have the following:

  • A running Abacá deployment — either the local Docker Compose dev stack or a production control plane on OpenShift ≥ 4.12.
  • OpenStack Keystone — you need a valid project-scoped Keystone token or the credentials to obtain one (OS_AUTH_URL, OS_USERNAME, OS_PASSWORD, OS_PROJECT_NAME, and OS_USER_DOMAIN_NAME at minimum).
  • The Abacá API endpoint URL — the base URL of the abaca-api service, for example https://abaca.example.com. The /v1 prefix is appended automatically by the SDK and must not be included in the base URL you configure.
  • curl ≥ 7.x (for the raw HTTP examples) or Python ≥ 3.11 (for the SDK examples).
  • python-abacaclient installed if you want to use the SDK or the openstack share protection CLI (see Installation below).
  • Network access from your workstation to both the Keystone endpoint and the abaca-api endpoint.

Installation

If you only want to use curl, skip to the Configuration section — no installation is required.

To use the Python SDK or the openstack share protection CLI, install python-abacaclient:

Step 1 — Install from PyPI

pip install python-abacaclient

Step 2 — Verify the CLI plugin is registered

After installation, the openstack command should recognise the share protection subcommand group:

openstack share protection --help

You should see a list of subcommands including target list, backup create, job show, and others. If you see 'share protection' is not an openstack command, ensure python-abacaclient is installed into the same Python environment as python-openstackclient.

Step 3 — (Optional) Install in editable mode for development

git clone <repository-url>
cd python-abacaclient
pip install -e '.[test]'

Configuration

All configuration for your first request comes from two sources: your OpenStack authentication environment and the Abacá endpoint URL.

OpenStack authentication environment variables

Set these before running any command. They are consumed by both curl-based flows (to obtain a token) and by the openstack CLI.

VariableRequiredExamplePurpose
OS_AUTH_URLYeshttps://keystone.example.com/v3Keystone identity endpoint
OS_USERNAMEYesjsmithYour OpenStack username
OS_PASSWORDYes(your password)Your OpenStack password
OS_PROJECT_NAMEYesmy-projectProject to scope the token to
OS_USER_DOMAIN_NAMEYesDefaultDomain of your user account
OS_PROJECT_DOMAIN_NAMEYesDefaultDomain of your project

Abacá endpoint

VariableRequiredExamplePurpose
ABACA_ENDPOINTYes (for curl flows)https://abaca.example.comBase URL of the abaca-api service — without /v1

SDK constructor parameters

When constructing a Client object directly in Python, the relevant parameters are:

ParameterDefaultDescription
endpoint(required)Base URL of abaca-api. /v1 is appended automatically.
tokenNoneKeystone token sent as X-Auth-Token. Use this for simple scripts.
sessionNoneA keystoneauth1.Session. Takes precedence over token when provided — recommended for production code.
ca_certNonePath to a CA bundle for TLS verification. Set this when abaca-api is behind a private certificate authority.

When both token and session are omitted, the client will make unauthenticated requests and the API will return 401 Unauthorized. Always supply one of the two.


Usage

Step 1 — Obtain a Keystone token

Abacá authenticates every request via the X-Auth-Token header. Obtain a project-scoped token from Keystone:

export OS_TOKEN=$(openstack token issue -f value -c id)

You can verify it was set:

echo $OS_TOKEN

Step 2 — Make your first request with curl

List your backup targets. If you have not registered any yet, the response will be an empty list — that is expected and confirms the API is reachable and your token is valid.

curl -s \
  -H "X-Auth-Token: $OS_TOKEN" \
  "${ABACA_ENDPOINT}/v1/targets" | python3 -m json.tool

A successful response looks like:

{
  "targets": []
}

Step 3 — Make the same request with the Python SDK

from abacaclient.client import Client
import os

client = Client(
    endpoint=os.environ["ABACA_ENDPOINT"],
    token=os.environ["OS_TOKEN"],
)

results = client.target_list()
print(results)  # {'targets': []}

Step 4 — Make the same request with the OpenStack CLI

If you have python-abacaclient installed and your OS_* environment variables set, the CLI handles token acquisition automatically:

openstack share protection target list

Understanding the base URL

The abaca-api service exposes all tenant-facing endpoints under /v1. The SDK appends this prefix automatically — you supply only the scheme and host. When constructing curl commands directly, include /v1 in the path yourself:

https://abaca.example.com/v1/targets       ← targets collection
https://abaca.example.com/v1/policies      ← policies collection
https://abaca.example.com/v1/backups       ← backups collection
https://abaca.example.com/v1/jobs          ← jobs collection

Examples

Example 1 — List backup targets (curl)

Confirm API reachability and authentication with the simplest read-only call.

export OS_TOKEN=$(openstack token issue -f value -c id)
export ABACA_ENDPOINT=https://abaca.example.com

curl -s \
  -H "X-Auth-Token: $OS_TOKEN" \
  "${ABACA_ENDPOINT}/v1/targets" | python3 -m json.tool

Expected output (no targets registered yet):

{
  "targets": []
}

Example 2 — List backup targets (Python SDK)

The SDK raises abacaclient.exceptions.AbacaClientError on any non-2xx response, so you can handle authentication failures explicitly.

import os
from abacaclient.client import Client
from abacaclient.exceptions import AbacaClientError

client = Client(
    endpoint=os.environ["ABACA_ENDPOINT"],
    token=os.environ["OS_TOKEN"],
)

try:
    result = client.target_list()
    targets = result.get("targets", [])
    print(f"Found {len(targets)} backup target(s).")
    for t in targets:
        print(f"  {t['id']}  {t['name']}  status={t['status']}")
except AbacaClientError as exc:
    print(f"Request failed: HTTP {exc.status} — {exc}")

Expected output (no targets registered yet):

Found 0 backup target(s).

Example 3 — List backup targets (OpenStack CLI)

export ABACA_ENDPOINT=https://abaca.example.com
# OS_* variables already set from your clouds.yaml or RC file

openstack share protection target list

Expected output (no targets registered yet):

+----+------+----------+--------+--------+
| id | name | endpoint | bucket | status |
+----+------+----------+--------+--------+
+----+------+----------+--------+--------+

Example 4 — Inspect a failed request

If you supply a bad or expired token, the API returns 401. The SDK surfaces this as an AbacaClientError:

from abacaclient.client import Client
from abacaclient.exceptions import AbacaClientError

client = Client(endpoint="https://abaca.example.com", token="bad-token")

try:
    client.target_list()
except AbacaClientError as exc:
    print(f"HTTP status : {exc.status}")
    print(f"Error detail: {exc}")

Expected output:

HTTP status : 401
Error detail: ...

Example 5 — List jobs (curl)

Once you start triggering backups or restores, you will poll the jobs collection to track progress through the job state machine (queued → provisioning_network → … → available).

curl -s \
  -H "X-Auth-Token: $OS_TOKEN" \
  "${ABACA_ENDPOINT}/v1/jobs" | python3 -m json.tool

Expected output shape:

{
  "jobs": [
    {
      "id": "d4f2a1c0-...",
      "status": "available",
      "error_category": null,
      "created_at": "2024-06-01T12:00:00Z"
    }
  ]
}

Troubleshooting

401 Unauthorized on every request

Symptom: Every curl or SDK call returns HTTP 401, or the CLI prints an authentication error.

Likely cause: Your Keystone token has expired (tokens are typically valid for one hour), the X-Auth-Token header was not sent, or the OS_AUTH_URL points to the wrong Keystone endpoint.

Fix:

  1. Re-issue the token: export OS_TOKEN=$(openstack token issue -f value -c id)
  2. Confirm OS_AUTH_URL is reachable: curl -s $OS_AUTH_URL
  3. Confirm the header is being sent: add -v to your curl command and look for X-Auth-Token in the request headers.

curl: (6) Could not resolve host or connection refused

Symptom: curl fails immediately with a DNS resolution error or Connection refused.

Likely cause: ABACA_ENDPOINT is set to the wrong hostname, the abaca-api service is not running, or there is a network/firewall issue between your workstation and the API.

Fix:

  1. Verify the endpoint is correct and reachable: curl -v "${ABACA_ENDPOINT}/v1/targets"
  2. If using the local Docker Compose dev stack, confirm the containers are running: docker compose ps
  3. Check that port 443 (or whichever port abaca-api listens on) is open in your firewall or security group.

'share protection' is not an openstack command

Symptom: Running openstack share protection target list prints an error saying the subcommand is not recognised.

Likely cause: python-abacaclient is not installed in the same Python environment as python-openstackclient, or the package is installed but the entry points have not been registered.

Fix:

  1. Confirm both packages are in the same environment: pip show python-abacaclient python-openstackclient
  2. Reinstall: pip install --force-reinstall python-abacaclient
  3. Verify registration: openstack share protection --help

SDK raises AbacaClientError with HTTP 404 on /v1/targets

Symptom: The client raises an error indicating a 404 Not Found when calling client.target_list().

Likely cause: The endpoint passed to Client() already contains /v1, causing the SDK to construct the URL as /v1/v1/targets.

Fix: Pass only the scheme and host to Client(). The SDK appends /v1 automatically:

# Correct
client = Client(endpoint="https://abaca.example.com", token=token)

# Wrong — do not include /v1
# client = Client(endpoint="https://abaca.example.com/v1", token=token)

TLS certificate verification failure

Symptom: curl exits with SSL certificate problem: unable to get local issuer certificate, or the SDK raises a connection error mentioning SSL.

Likely cause: The abaca-api service is behind a private certificate authority whose root certificate is not in your system trust store.

Fix:

  • For curl: add --cacert /path/to/ca-bundle.pem
  • For the SDK: pass ca_cert="/path/to/ca-bundle.pem" to Client()
  • For the CLI: set OS_CACERT=/path/to/ca-bundle.pem in your environment

Do not use -k / --insecure in production — it disables certificate verification entirely.