CLI Reference
Trilio Site Recovery implements a new OpenStack CLI plugin called dr. Users can use the DR plugin to manage the Trilio Site Recovery solution, including adding/removing sites and creating protection groups.
The openstack dr CLI plugin is the primary interface for managing Trilio Site Recovery operations. It extends the standard OpenStack client with a dr command group that covers the full DR lifecycle: registering sites, creating and populating Protection Groups, executing failover and failback, running non-disruptive DR tests, monitoring replication health, and administering tenant mappings. Install the plugin separately from the server package — it is distributed as the triliositerecovery Python package located in the client/ subdirectory of the repository.
openstack dr <resource> <action> [<positional-args>] [--flags]
All commands follow the pattern openstack dr <resource> <action>. Multi-word resources use spaces, not dashes — for example openstack dr protection group create, not openstack dr protection-group create.
Full command shapes:
openstack dr site list
openstack dr site show <site>
openstack dr site create <name> --site-type <PRIMARY|SECONDARY> --auth-url <url> [flags]
openstack dr site set <site> [flags]
openstack dr site delete [<site...>]
openstack dr site failover <site> [flags]
openstack dr failover to this site [flags]
openstack dr site operation list [flags]
openstack dr site operation show <operation>
openstack dr protection group list [--all-projects]
openstack dr protection group show <protection_group> [--all-projects]
openstack dr protection group create <name> --primary-site <site> --secondary-site <site> [flags]
openstack dr protection group set <protection_group> [flags]
openstack dr protection group delete [<protection_group...>] [--force]
openstack dr protection group member add <protection_group> --instance <id> [--boot-order <n>]
openstack dr protection group member set <protection_group> --member <id> --boot-order <n>
openstack dr protection group member remove <protection_group> --member <id>
openstack dr protection group member list <protection_group>
openstack dr protection group member validate <protection_group> --instance <id>
openstack dr protection group sync <protection_group> [flags]
openstack dr protection group mapping list <protection_group> [flags]
openstack dr protection group mapping create <protection_group> --resource-type <type> --primary-resource-id <id> --secondary-resource-id <id>
openstack dr protection group mapping delete <protection_group> <mapping>
openstack dr protection group reconcile <protection_group>
openstack dr replication health <protection_group>
openstack dr recovery point list <protection_group> [--limit <n>]
openstack dr recovery point create <protection_group> [--suffix <string>]
openstack dr failover <protection_group> [flags]
openstack dr failback <protection_group> [flags]
openstack dr test failover <protection_group> [flags]
openstack dr test failover cleanup <protection_group> [flags]
openstack dr operation list [flags]
openstack dr operation show <operation>
openstack dr operation cancel <operation>
openstack dr metadata sync <protection_group> [--force]
openstack dr tenant mapping list [flags]
openstack dr tenant mapping show <mapping>
openstack dr tenant mapping create --local-tenant <id> --remote-site <id> --remote-tenant <id> [flags]
openstack dr tenant mapping delete [<mapping...>] [--no-sync-remote]
openstack dr tenant mapping validate <mapping>
openstack dr usage summary
openstack dr usage report [flags]
Flags are grouped by command below. Standard OpenStack client output flags (-f, -c, --sort-column, --fit-width, etc.) apply to all commands and are not repeated here.
dr site create <name>
| Flag | Short | Default | Description |
|---|---|---|---|
--site-type <PRIMARY|SECONDARY> | (required) | Designates whether this site is the normal workload location (PRIMARY) or the DR target (SECONDARY). | |
--auth-url <url> | (required) | Keystone authentication URL for this site. Must exactly match keystone_authtoken.auth_url in the site's protector.conf; the engine identifies which site it is running on by comparing this value as a string. | |
--description <string> | Human-readable description. | ||
--region <string> | OpenStack region name on this site. | ||
--service-username <string> | Keystone username of the cross-site service account. Strongly recommended — without it, scheduled and engine-initiated operations that run after the requesting user's token expires will fail. | ||
--service-password <string> | Password for the service account. The API validates these credentials against the remote Keystone before saving. | ||
--service-project-name <string> | Keystone project for the service account (typically service). | ||
--service-user-domain-name <string> | Keystone user domain name (typically Default). | ||
--service-project-domain-name <string> | Keystone project domain name (typically Default). | ||
--service-user-id <string> | Keystone user ID of the service account on this site. Required for trust creation when the service account does not hold Keystone admin — without it the first tenant mapping fails with "Cannot resolve service user ID". Obtain it with openstack user show protector -f value -c id on the site being registered. | ||
--service-project-id <string> | Keystone project ID (avoids domain-name ambiguity). | ||
--service-user-domain-id <string> | Keystone user domain ID. | ||
--service-project-domain-id <string> | Keystone project domain ID. | ||
--protector-api-url <string> | Explicit Protector API URL (e.g. https://protector.example.com:8788) when the API runs on a different host than Keystone. |
Note: The
--site-type,--auth-url, and the site<name>positional argument are the only valuesargparsemarks required. All service-credential flags are optional to the parser but strongly recommended in practice — see the--service-usernamedescription above. Consultopenstack dr site create --helpfor the authoritative list.
dr site set <site>
| Flag | Short | Default | Description |
|---|---|---|---|
--name <string> | Rename the site. | ||
--description <string> | Update description. | ||
--auth-url <string> | Update Keystone URL. | ||
--region <string> | Update region name. | ||
--status <ACTIVE|MAINTENANCE|ERROR> | Override site status (admin only). | ||
--service-username <string> | Update service account username. | ||
--service-password <string> | Update service account password; triggers credential validation against the remote Keystone. | ||
--service-project-name <string> | Update service project name. | ||
--service-user-domain-name <string> | Update user domain name. | ||
--service-project-domain-name <string> | Update project domain name. | ||
--service-user-id <string> | Update service user ID. | ||
--service-project-id <string> | Update service project ID. | ||
--service-user-domain-id <string> | Update service user domain ID. | ||
--service-project-domain-id <string> | Update service project domain ID. | ||
--protector-api-url <string> | Update explicit Protector API URL. |
dr site delete [<site...>]
(No DR-specific flags. Accepts one or more site IDs or names.)
dr site failover <site>
Fails over all Protection Groups at a site simultaneously. Requires the dr_site_admin role.
| Flag | Short | Default | Description |
|---|---|---|---|
--failover-type <planned|unplanned> | planned | Failover mode. planned gracefully shuts down VMs; unplanned skips shutdown for use when the primary is already down. | |
--force | false | Force failover even if some Protection Groups have pre-check issues. | |
--yes / -y | -y | Skip confirmation prompt. |
dr failover to this site
Simplified site-level failover — fails over all Protection Groups that are not currently on this site, to this site. Requires dr_site_admin role.
| Flag | Short | Default | Description |
|---|---|---|---|
--failover-type <planned|unplanned> | planned | Failover mode. | |
--force | false | Force failover. | |
--yes / -y | -y | Skip confirmation prompt. |
dr site operation list
| Flag | Short | Default | Description |
|---|---|---|---|
--site <string> | Filter by site ID or name. | ||
--status <pending|running|completed|partial_success|failed> | Filter by operation status. | ||
--limit <number> | 50 | Maximum number of results to return. |
dr protection group list
| Flag | Short | Default | Description |
|---|---|---|---|
--all-projects | false | Show Protection Groups from all projects (admin only). |
dr protection group show <protection_group>
| Flag | Short | Default | Description |
|---|---|---|---|
--all-projects | false | Access a Protection Group from any project (admin only). |
dr protection group create <name>
| Flag | Short | Default | Description |
|---|---|---|---|
--primary-site <string> | (required) | ID or name of the primary site. | |
--secondary-site <string> | (required) | ID or name of the secondary (DR) site. | |
--replication-type <async|active_dr> | async | async uses periodic FlashArray Protection Group snapshots (RPO = replication interval). active_dr uses Pure Storage ActiveDR pod-based continuous replication (RPO ≈ 0, requires Purity//FA 6.0+). | |
--volume-type <string> | Cinder volume type ID or name. Required for async replication; the volume type must have replication_enabled='<is> True' set as an extra-spec. | ||
--description <string> | Human-readable description. |
dr protection group set <protection_group>
| Flag | Short | Default | Description |
|---|---|---|---|
--name <string> | New name for the Protection Group. | ||
--description <string> | New description. | ||
--status <active|failed_over|error> | Force-set the Protection Group status (admin only). Use only to recover from an inconsistent state. | ||
--reset-to-primary | false | Reset current_primary_site to the original primary. Use after manual failback to sync state. | |
--reset-to-secondary | false | Set current_primary_site to the secondary site. Use after manual failover to sync state. |
dr protection group delete [<protection_group...>]
| Flag | Short | Default | Description |
|---|---|---|---|
--force | false | Force delete even if the Protection Group is in a transitional state. Resources that cannot be reached during forced deletion are listed in the output as "leftovers". |
dr protection group member add <protection_group>
| Flag | Short | Default | Description |
|---|---|---|---|
--instance <string> | (required) | Nova instance UUID to add. The instance must boot from a Cinder volume; ephemeral boot disks are rejected with InstanceNotCinderBoot (HTTP 422). All attached volumes must use a Cinder volume type with replication_enabled='<is> True'; non-replicated types are rejected with VolumeTypeNotReplicated (HTTP 422). | |
--boot-order <number> | 0 | Integer boot order for sequencing VM startup and shutdown during DR operations. VMs sharing the same value are processed in parallel; lower values complete before higher values begin. |
dr protection group member set <protection_group>
| Flag | Short | Default | Description |
|---|---|---|---|
--member <string> | (required) | Member ID to update. | |
--boot-order <number> | (required) | New boot order value. |
dr protection group member remove <protection_group>
| Flag | Short | Default | Description |
|---|---|---|---|
--member <string> | (required) | Member ID to remove. Returns 202 Accepted with a pollable operation ID. |
dr protection group member validate <protection_group>
Runs the same eligibility checks as member add without side effects. Returns a structured errors array. Use this before member add to surface problems early.
| Flag | Short | Default | Description |
|---|---|---|---|
--instance <string> | (required) | Nova instance UUID to validate. |
dr protection group sync <protection_group>
| Flag | Short | Default | Description |
|---|---|---|---|
--dry-run | false | Show what would be synced without making changes. | |
--volumes | false | Sync volume metadata only. | |
--security-groups | false | Sync security group mappings only. | |
--networks | false | Sync network mappings only. |
dr protection group mapping list <protection_group>
| Flag | Short | Default | Description |
|---|---|---|---|
--type <string> | Filter to one resource type: network, subnet, security_group, or flavor. | ||
--unmapped | false | Show only resources that were considered by auto-mapping but not mapped. | |
--differing | false | Show only resources that are mapped but differ from the source. |
dr protection group mapping create <protection_group>
Creates an explicit mapping that overrides auto-mapping. Auto-mapping will not overwrite an explicit mapping.
| Flag | Short | Default | Description |
|---|---|---|---|
--resource-type <string> | (required) | network, subnet, security_group, or flavor. | |
--primary-resource-id <string> | (required) | Resource ID on the primary site. | |
--secondary-resource-id <string> | (required) | Resource ID on the secondary site. |
dr recovery point list <protection_group>
| Flag | Short | Default | Description |
|---|---|---|---|
--limit <number> | Maximum number of recovery points to return. |
dr recovery point create <protection_group>
| Flag | Short | Default | Description |
|---|---|---|---|
--suffix <string> | Optional name suffix appended to the generated recovery point name. |
dr failover <protection_group>
Moves a Protection Group's workloads from the primary site to the secondary site. A planned failover gracefully shuts down VMs and takes a final snapshot for zero data loss; an unplanned failover skips shutdown and accepts data loss up to the RPO.
| Flag | Short | Default | Description |
|---|---|---|---|
--failover-type <planned|unplanned> | planned | Failover type. | |
--recovery-point <string> | Specific recovery point (snapshot) to restore from. Accepts the full name or a suffix. If omitted, creates a new snapshot of the current state. Use openstack dr recovery point list <pg> to see available points. Useful for recovery from ransomware or accidental data corruption. | ||
--force | false | Skip validation checks and primary site operations. Use with caution. | |
--timeout <number> | 30 | Timeout in seconds for the primary site connectivity check. | |
--wait | false | Block until the failover operation completes, polling operation status. | |
--network-mapping <src-net>=<dst-net> | Map a source network ID to a target network ID on the secondary site. Repeatable. If omitted, networks are resolved by name. | ||
--subnet-mapping <src-subnet>=<dst-subnet> | Map a source subnet ID to a target subnet ID. Repeatable. | ||
--flavor-mapping <src-flavor>=<dst-flavor> | Map a source flavor ID to a target flavor ID. Repeatable. If omitted, flavors are resolved by name. | ||
--all-projects | false | Access the Protection Group from any project (admin only). |
dr failback <protection_group>
Returns a Protection Group's workloads to the original primary site after a failover.
| Flag | Short | Default | Description |
|---|---|---|---|
--resync | false | Force a full resync of data accumulated during the failover period before recreating VMs. | |
--all-projects | false | Access the Protection Group from any project (admin only). | |
--force | false | Force failback even if pre-checks fail. | |
--failback-type <planned|unplanned> | Failback type. | ||
--network-mapping <src-net>=<dst-net> | Map a network on the secondary site back to a network on the primary. Repeatable. | ||
--subnet-mapping <src-subnet>=<dst-subnet> | Map a subnet. Repeatable. | ||
--flavor-mapping <src-flavor>=<dst-flavor> | Map a flavor. Repeatable. |
dr test failover <protection_group>
Non-disruptive DR validation. Clones replicated volumes from a recovery point on the secondary site and boots isolated test VMs with a test- prefix on a separate network. Production workloads are not affected. Either --auto-network or --network-mapping is required.
| Flag | Short | Default | Description |
|---|---|---|---|
--auto-network | Automatically select an isolated network on the secondary site for test VMs. Required if --network-mapping is not provided. | ||
--network-mapping <string> | Explicit network mapping for test VMs. Required if --auto-network is not provided. | ||
--recovery-point <string> | Recovery point to clone from. Defaults to the most recent. | ||
--subnet-mapping <string> | Subnet mapping for test VMs. | ||
--flavor-mapping <string> | Flavor mapping for test VMs. | ||
--security-group-mapping <string> | Security group mapping for test VMs. | ||
--availability-zone <string> | Availability zone on the secondary site for test VMs. | ||
--instance-prefix <string> | test- | Name prefix for test VM instances. | |
--all-projects | false | Access the Protection Group from any project (admin only). |
dr test failover cleanup <protection_group>
Removes test VMs and cloned volumes created by a test failover. The required positional argument is a Protection Group ID or name, not an operation ID.
| Flag | Short | Default | Description |
|---|---|---|---|
--operation <string> | (most recent test failover for the PG) | Targets a specific test failover operation ID to clean up. | |
--force | false | Force cleanup even if some resources fail to delete. |
dr operation list
| Flag | Short | Default | Description |
|---|---|---|---|
--protection-group <string> | Filter operations by Protection Group ID. | ||
--status <string> | Filter by status (pending, running, completed, failed, etc.). | ||
--operation-type <string> | Filter by operation type (failover, failback, test_failover, test_cleanup, sync_volumes, etc.). |
dr metadata sync <protection_group>
| Flag | Short | Default | Description |
|---|---|---|---|
--force | false | Force metadata sync even if the remote site reports it is already up to date. |
dr tenant mapping list
| Flag | Short | Default | Description |
|---|---|---|---|
--all-tenants | false | List mappings from all tenants (admin only). | |
--remote-site <string> | Filter by remote site ID. | ||
--status <active|pending_validation|validation_failed|disabled> | Filter by mapping status. |
dr tenant mapping create
Creates a cross-site tenant mapping. The API validates both tenant IDs against their respective Keystone deployments before saving, then propagates the reverse mapping to the remote site. Port 8788 must be reachable bidirectionally for the sync to succeed.
| Flag | Short | Default | Description |
|---|---|---|---|
--local-tenant <string> | (required) | Project UUID on this site. | |
--remote-site <string> | (required) | Remote site ID. | |
--remote-tenant <string> | (required) | Project UUID on the remote site. | |
--description <string> | Human-readable description. | ||
--skip-validation | false | Skip Keystone tenant validation (admin only). |
dr tenant mapping delete [<mapping...>]
| Flag | Short | Default | Description |
|---|---|---|---|
--no-sync-remote | false | Delete only the local mapping record, leaving the remote site's reverse mapping in place. |
dr usage report
| Flag | Short | Default | Description |
|---|---|---|---|
--period <monthly|quarterly|annual> | monthly | Report period. | |
--start-date <YYYY-MM-DD> | Explicit start date, overrides --period. | ||
--end-date <YYYY-MM-DD> | Explicit end date, overrides --period. | ||
--format <pdf|json> | pdf | Output format. json writes to stdout unless --output is given. | |
--output <file> | (auto-named for PDF, stdout for JSON) | Output file path. |
Commands are grouped by the resource they operate on.
| Subcommand group | Description |
|---|---|
dr site … | Register, update, delete, and query OpenStack sites. Includes site-level failover (fails over all Protection Groups at once). |
dr site operation … | Query site-level DR operations spawned by dr site failover. |
dr protection group … | Create and manage Protection Groups and their members, resource mappings, and metadata sync. |
dr protection group member … | Add, remove, update, validate, and list VMs inside a Protection Group. |
dr protection group mapping … | Inspect and override the auto-derived resource mappings (networks, subnets, flavors, security groups) used during failover. |
dr replication health … | Report live replication link status, RPO compliance, and failover readiness for a Protection Group. |
dr recovery point … | List and manually create point-in-time snapshots selectable during failover or test failover. |
dr failover | Execute a planned or unplanned Protection Group failover to the secondary site. |
dr failback | Return a failed-over Protection Group to its original primary site. |
dr test failover | Run a non-disruptive DR test by booting isolated clones on the secondary site. |
dr test failover cleanup | Remove test VMs and cloned volumes left by a test failover. |
dr operation … | List, inspect, and cancel individual DR operations (failover, failback, test failover, etc.). |
dr metadata sync | Push Protection Group metadata from this site to the remote site. |
dr tenant mapping … | Create and manage cross-site project identity translations required for multi-tenant DR. |
dr protection group reconcile | Recover a Protection Group from an interrupted or partially-completed operation. |
dr failover to this site | Site-level "big red button": fail over all Protection Groups not already on this site, to this site. |
dr usage summary | Show current per-tenant usage (admin only). |
dr usage report | Generate a usage/billing report in PDF or JSON format (admin only). |
The openstack dr plugin authenticates and locates endpoints through the standard OpenStack client environment variables. No DR-specific variables are required beyond these.
| Variable | Default | Description |
|---|---|---|
OS_AUTH_URL | Keystone endpoint for the local site. The value here must match the --auth-url you register for this site, or the engine will not be able to identify which site it is running on. | |
OS_USERNAME | OpenStack username. | |
OS_PASSWORD | OpenStack password. | |
OS_PROJECT_NAME | OpenStack project (tenant). DR operations are scoped to this project unless --all-projects is given. | |
OS_PROJECT_DOMAIN_NAME | Default | Domain containing OS_PROJECT_NAME. |
OS_USER_DOMAIN_NAME | Default | Domain containing OS_USERNAME. |
OS_REGION_NAME | Region name, used when the catalog contains multiple regions. | |
OS_IDENTITY_API_VERSION | 3 | Must be 3; Keystone v2 is not supported. |
OS_PROTECTOR_API_VERSION | 1 | Selects the protector API major version. The maximum supported microversion is 1.1. |
Note: The
openstackclientsnap is incompatible with thetriliositerecoveryCLI plugin. Installpython-openstackclientviapip, not snap.
The plugin returns standard OpenStack client exit codes.
| Code | Meaning |
|---|---|
0 | Command completed successfully. |
1 | Command failed. The error message printed to stderr contains the HTTP status code and the API error body, including the type field (exception class name), code, and message. |
2 | Incorrect command usage — unknown flag, missing required argument, or invalid argument value. The OpenStack client prints usage help. |
Install the CLI plugin
The triliositerecovery CLI package is separate from the server. In a Juju charm deployment, the server package is managed by the charm. Install only the CLI on the machine where you run openstack commands.
# From the repository root — installs only the CLI, not the server
pip install -e ./client
Verify the plugin is registered:
openstack --help | grep '^ *dr'
Expected output (excerpt):
dr failover
dr failback
dr metadata sync
...
Register both sites
Run these commands from the primary site with admin credentials. Each site has its own independent Keystone, so service credentials differ between sites.
# Obtain the service user ID from the primary site's Keystone
PRIMARY_SVC_USER_ID=$(openstack user show protector -f value -c id)
# Register the primary site
openstack dr site create primary-site \
--site-type PRIMARY \
--auth-url https://keystone.primary.example.com:5000 \
--region RegionOne \
--service-username protector \
--service-password "${PRIMARY_SVC_PASS}" \
--service-project-name service \
--service-user-domain-name Default \
--service-project-domain-name Default \
--service-user-id "${PRIMARY_SVC_USER_ID}"
Expected output:
+--------------------+--------------------------------------+
| Field | Value |
+--------------------+--------------------------------------+
| id | a1b2c3d4-e5f6-7890-abcd-ef1234567890 |
| name | primary-site |
| site_type | PRIMARY |
| status | active |
| auth_url | https://keystone.primary.example.com:5000 |
| region_name | RegionOne |
| created_at | 2025-01-15T10:00:00Z |
+--------------------+--------------------------------------+
# Source secondary-site credentials to look up its service user
source secondary-site-openrc.sh
SECONDARY_SVC_USER_ID=$(openstack user show protector -f value -c id)
# Switch back to primary and register the secondary
source primary-site-openrc.sh
openstack dr site create secondary-site \
--site-type SECONDARY \
--auth-url https://keystone.secondary.example.com:5000 \
--region RegionOne \
--service-username protector \
--service-password "${SECONDARY_SVC_PASS}" \
--service-project-name service \
--service-user-domain-name Default \
--service-project-domain-name Default \
--service-user-id "${SECONDARY_SVC_USER_ID}"
openstack dr site list
Expected output:
+--------------------------------------+----------------+-----------+--------+
| ID | Name | Type | Status |
+--------------------------------------+----------------+-----------+--------+
| a1b2c3d4-... | primary-site | PRIMARY | active |
| b2c3d4e5-... | secondary-site | SECONDARY | active |
+--------------------------------------+----------------+-----------+--------+
Create a tenant mapping
Each site has an independent Keystone that assigns different UUIDs to the same tenant. Register the translation.
LOCAL_PROJECT_ID=$(openstack project show myproject -f value -c id)
# Obtain the remote project ID (requires credentials on the secondary)
REMOTE_PROJECT_ID="<uuid-of-myproject-on-secondary-site>"
SECONDARY_SITE_ID=$(openstack dr site show secondary-site -f value -c id)
openstack dr tenant mapping create \
--local-tenant "${LOCAL_PROJECT_ID}" \
--remote-site "${SECONDARY_SITE_ID}" \
--remote-tenant "${REMOTE_PROJECT_ID}" \
--description "myproject DR mapping"
Expected output:
+---------------------+--------------------------------------+
| Field | Value |
+---------------------+--------------------------------------+
| id | c3d4e5f6-... |
| local_tenant_name | myproject |
| remote_site_name | secondary-site |
| remote_tenant_name | myproject |
| status | active |
| created_at | 2025-01-15T10:05:00Z |
+---------------------+--------------------------------------+
Create a Protection Group and add VMs
Before adding VMs, verify the volume type has replication enabled:
openstack volume type show replicated-vol-type -f json | \
python3 -c "import sys,json; \
specs=json.load(sys.stdin)['extra_specs']; \
print(specs.get('replication_enabled'))"
# Should print: <is> True
Create the Protection Group:
PG_ID=$(openstack dr protection group create prod-pg \
--primary-site primary-site \
--secondary-site secondary-site \
--replication-type async \
--volume-type replicated-vol-type \
--description "Production workloads" \
-f value -c id)
echo "Protection Group ID: ${PG_ID}"
Validate a VM before adding it:
VM_ID=$(openstack server show my-app-vm -f value -c id)
openstack dr protection group member validate "${PG_ID}" \
--instance "${VM_ID}"
Expected output (eligible instance):
+------------------------+----------------------------------------+
| Field | Value |
+------------------------+----------------------------------------+
| valid | True |
| errors | [] |
| warnings | [] |
| details.volume_count | 2 |
| details.backend_name | pure |
+------------------------+----------------------------------------+
Add the VM:
openstack dr protection group member add "${PG_ID}" \
--instance "${VM_ID}" \
--boot-order 1
# Add a dependent VM that should start after the first
DB_VM_ID=$(openstack server show my-db-vm -f value -c id)
openstack dr protection group member add "${PG_ID}" \
--instance "${DB_VM_ID}" \
--boot-order 2
openstack dr protection group member list "${PG_ID}"
Check replication health
openstack dr replication health "${PG_ID}"
Expected output:
+----------------------------------------+-------------------+
| Field | Value |
+----------------------------------------+-------------------+
| protection_group_id | <pg-uuid> |
| protection_group_name | prod-pg |
| replication_health.health_report.state | healthy |
| replication_health.health_report.lag_seconds | 45 |
| replication_health.health_report.rpo_compliant | True |
| replication_health.health_report.recovery_points | 12 |
| replication_health.failover_validation.can_failover | True |
| replication_health.failover_validation.warnings | [] |
| replication_health.failover_validation.blockers | [] |
+----------------------------------------+-------------------+
Use can_failover as the programmatic readiness check before automating failover:
CAN_FAILOVER=$(openstack dr replication health "${PG_ID}" \
-f json | python3 -c \
"import sys,json; h=json.load(sys.stdin); \
print(h['replication_health']['failover_validation']['can_failover'])")
[ "${CAN_FAILOVER}" = "True" ] && echo "Ready" || echo "Not ready"
Run a non-disruptive test failover
# Start the test — use --auto-network or provide --network-mapping
TEST_OP_ID=$(openstack dr test failover "${PG_ID}" \
--auto-network \
--recovery-point "$(openstack dr recovery point list "${PG_ID}" \
--limit 1 -f value -c id)" \
-f value -c operation_id)
echo "Test failover operation: ${TEST_OP_ID}"
# Poll until complete
while true; do
STATUS=$(openstack dr operation show "${TEST_OP_ID}" -f value -c status)
PROGRESS=$(openstack dr operation show "${TEST_OP_ID}" -f value -c progress)
echo "Status: ${STATUS} (${PROGRESS})"
[ "${STATUS}" = "completed" ] || [ "${STATUS}" = "failed" ] && break
sleep 15
done
# Inspect test VMs on the secondary site, then clean up
openstack dr test failover cleanup "${PG_ID}" \
--operation "${TEST_OP_ID}"
Execute a planned failover
# Verify readiness first
openstack dr replication health "${PG_ID}"
# Trigger planned failover and wait for completion
OP_ID=$(openstack dr failover "${PG_ID}" \
--failover-type planned \
--wait \
-f value -c operation_id)
openstack dr operation show "${OP_ID}"
Expected initial response (status is pending):
+---------------------+--------------------------------------+
| Field | Value |
+---------------------+--------------------------------------+
| id | <operation-uuid> |
| protection_group_id | <pg-uuid> |
| operation_type | failover |
| failover_type | planned |
| status | pending |
| source_site | primary-site |
| target_site | secondary-site |
+---------------------+--------------------------------------+
Unplanned failover to a specific recovery point
Useful for recovering from ransomware or accidental data corruption by restoring to a known-good snapshot.
# List available recovery points on the secondary
openstack dr recovery point list "${PG_ID}"
# Fail over to a specific point
openstack dr failover "${PG_ID}" \
--failover-type unplanned \
--recovery-point "protector-pg-prod-pg-2025-01-14T08:00:00" \
--force
Execute failback
After workloads have been running on the secondary, return them to the primary:
OP_ID=$(openstack dr failback "${PG_ID}" \
--wait \
-f value -c operation_id)
openstack dr operation show "${OP_ID}"
Site-level failover (big red button)
Fail over every Protection Group at a site simultaneously. Requires the dr_site_admin role.
# Fail over all PGs at primary-site to secondary
openstack dr site failover primary-site \
--failover-type unplanned \
--yes
# Monitor site-level progress
openstack dr site operation list --status running
openstack dr site operation show <site-operation-id>
Automate DR health monitoring
#!/bin/bash
# Polls all Protection Groups and alerts if any cannot fail over
PGs=$(openstack dr protection group list -f value -c id)
for pg in ${PGs}; do
HEALTH=$(openstack dr replication health "${pg}" -f json 2>/dev/null)
CAN_FAILOVER=$(echo "${HEALTH}" | python3 -c \
"import sys,json; h=json.load(sys.stdin); \
print(h['replication_health']['failover_validation']['can_failover'])")
PG_NAME=$(openstack dr protection group show "${pg}" -f value -c name)
if [ "${CAN_FAILOVER}" != "True" ]; then
BLOCKERS=$(echo "${HEALTH}" | python3 -c \
"import sys,json; h=json.load(sys.stdin); \
print(h['replication_health']['failover_validation']['blockers'])")
echo "ALERT: ${PG_NAME} (${pg}) cannot fail over: ${BLOCKERS}"
else
echo "OK: ${PG_NAME} (${pg})"
fi
done
Output formatting and scripting
All commands support standard OpenStack client output flags.
# Extract a single value for use in scripts
PG_ID=$(openstack dr protection group create prod-pg \
--primary-site primary-site \
--secondary-site secondary-site \
--volume-type replicated-vol-type \
-f value -c id)
# JSON output for programmatic parsing
openstack dr operation show "${OP_ID}" -f json
# YAML output
openstack dr protection group show "${PG_ID}" -f yaml
# Select specific columns
openstack dr protection group list \
-c id -c name -c status
# Filter operations by type
openstack dr operation list \
--operation-type failover \
--status completed
# Debug mode
openstack --debug dr replication health "${PG_ID}"
Get help for any command
# List all dr commands
openstack help dr
# Command-specific help
openstack dr site create --help
openstack dr failover --help
openstack dr test failover cleanup --help