Trilio Site Recovery for OpenStackDisaster Recovery Solution for OpenStack Virtual Machines
API reference

Horizon Dashboard Plugin

Reference for horizon-plugin/protector_dashboards/protection_groups.


Description

The Protection Groups panel in the Trilio Site Recovery Horizon dashboard provides a browser-based interface for managing the full lifecycle of Protection Groups — the core unit of disaster recovery. Through this panel, tenants can create Protection Groups, add Nova VMs as members, monitor replication health, launch failover and test failover dialogs with recovery point selection, initiate failback, and track the step-by-step progress of in-flight DR operations. Use this panel when you want a visual alternative to the openstack dr CLI for everyday DR management tasks.


Parameters

The dashboard panel itself takes no configuration parameters from the user at the URL level. Individual views accept path and query parameters as follows:

ParameterTypeRequiredDescription
pg_idstring (UUID or name)Yes (detail, failover, failback, add_member, edit_member, add_mapping, test_failover, test_cleanup views)The ID of the Protection Group the view operates on. Captured from the URL path segment (?P<pg_id>[^/]+).
member_idstring (UUID)Yes (edit_member view only)The ID of the Protection Group member to edit. Captured from (?P<member_id>[^/]+).
operation_idstring (UUID)Yes (operation_detail view only)The ID of a specific DR Operation to inspect. Captured from (?P<operation_id>[^/]+).

Workflow forms within the panel expose the following user-facing fields:

FieldForm / WorkflowRequiredDescription
NameCreateProtectionGroupYesA unique display name for the new Protection Group.
DescriptionCreateProtectionGroupNoOptional free-text description.
Primary SiteCreateProtectionGroupYesThe OpenStack site where workloads normally run.
Secondary SiteCreateProtectionGroupYesThe OpenStack DR site to fail over to.
Replication TypeCreateProtectionGroupNoasync (periodic snapshot-based, configurable RPO) or active_dr (Pure Storage ActiveDR pod-based, near-zero RPO). Defaults to async.
Volume TypeCreateProtectionGroupNoThe Cinder volume type with replication_enabled='<is> True' to associate with this Protection Group.
InstanceAddMemberWorkflowYesThe Nova instance UUID to add. The instance must boot from a Cinder volume; instances using ephemeral boot disks are rejected. All attached Cinder volumes must use a volume type with replication_enabled='<is> True'.
Boot OrderAddMemberWorkflow / EditMemberWorkflowNoInteger controlling startup/shutdown sequence during failover and failback. VMs sharing the same boot order value are processed in parallel; lower values complete before higher values begin.
Failover TypeFailoverWorkflowYesplanned (graceful shutdown, zero data loss) or unplanned (skips shutdown, data loss up to RPO).
Recovery PointFailoverWorkflow / TestFailoverWorkflowNoSelects a specific point-in-time snapshot on the secondary site. Useful for recovering from ransomware or accidental corruption. Defaults to the most recent recovery point.
Network MappingFailoverWorkflow / TestFailoverWorkflowConditionalRequired unless Auto Network is selected. Maps source networks (by name) to target network UUIDs on the secondary site. The widget auto-selects a target network whose name matches the source; leave blank to match by name automatically.
Auto NetworkTestFailoverWorkflowConditionalWhen selected, the engine automatically selects a network for test VMs on the secondary site. Either Auto Network or an explicit Network Mapping is required for test failover.
Flavor MappingFailoverWorkflow / TestFailoverWorkflowNoMaps source flavor IDs to target flavor UUIDs on the secondary site. The widget pre-selects matching names.
ForceTestCleanupWorkflowNoForces cleanup of test failover resources even if some individual resources fail to delete.
OperationTestCleanupWorkflowNoTargets a specific test failover operation ID to clean up. Defaults to the most recent test failover for the Protection Group.

Returns

Each view in the panel returns an HTML response rendered by the corresponding Django template. The following summarises what each view presents:

View / URLWhat is rendered
IndexView (/)A data table (ProtectionGroupsTable) listing all Protection Groups for the current project, including name, status, replication type, failover readiness (e.g. Ready (4s lag) or Not Ready), and network readiness. A progress banner is injected when a DR operation is in flight for the current session.
DetailView (/<pg_id>/)Four sub-tables: Members (VMs in the group, their boot order, and attached volume details), Recovery Points (available snapshots on the secondary site), Resource Mappings (network and flavor mappings stored against the group), and Operations (the 10 most recent DR operations for this group). Also renders replication health metrics — lag, RPO compliance, sync state, link status, transfer throughput, and a failover_validation block indicating whether failover can proceed.
OperationDetailView (/operation/<operation_id>/)Full step-by-step progress record for a single DR Operation, including status, percentage complete (0–100), and per-step outcomes.
OperationStatusJsonView (/operation-status/)A JSON response used by the progress banner to poll in-flight operation status without reloading the page. Returns the current status, progress, and operation_id from the session-stored pending operation.
Workflow views (/create/, /<pg_id>/failover/, etc.)Modal dialogs rendered as Horizon workflows. On successful submission, the panel stores the returned operation_id in the Django session and redirects to the index page, where the progress banner begins polling.

All API-backed data is retrieved through protectormgr helpers, which call the protector-api at http://<host>:8788. The underlying API endpoints are:

  • GET /v1/{tenant_id}/protection-groups — index listing
  • GET /v1/{tenant_id}/protection-groups/{id} — detail view
  • GET /v1/{tenant_id}/protection-groups/{id}/replication-health — health metrics embedded in detail and index
  • GET /v1/{tenant_id}/protection-groups/{pg_id}/members — member sub-table
  • GET /v1/{tenant_id}/protection-groups/{pg_id}/mappings — resource mappings sub-table
  • GET /v1/{tenant_id}/protection-groups/{id}/recovery-points — recovery points sub-table
  • GET /v1/{tenant_id}/operations (filtered by pg_id) — operations sub-table
  • GET /v1/{tenant_id}/operations/{id} — operation detail and banner polling
  • POST /v1/{tenant_id}/protection-groups/{pg_id}/action — failover, failback, and test failover submission (returns HTTP 202 with operation_id)
  • POST /v1/{tenant_id}/protection-groups — Protection Group creation
  • POST /v1/{tenant_id}/protection-groups/{pg_id}/members — member add
  • PUT /v1/{tenant_id}/protection-groups/{pg_id}/members/{id} — member boot-order edit
  • DELETE /v1/{tenant_id}/protection-groups/{pg_id}/members/{id} — member removal (returns HTTP 202)
  • DELETE /v1/{tenant_id}/protection-groups/{id} — Protection Group deletion (returns HTTP 204)

Errors

The dashboard panel surfaces errors to the user through Horizon's messages and exceptions framework. The underlying protector-api errors that can appear are:

ErrorHTTP StatusWhen it occurs
InstanceNotCinderBoot422 Unprocessable EntityRaised at member-add time when the Nova instance does not boot from a Cinder volume (uses ephemeral storage instead). The Add VM dialog displays this as a validation error.
VolumeTypeNotReplicated422 Unprocessable EntityRaised at member-add time when one or more Cinder volumes attached to the instance use a volume type that does not have replication_enabled='<is> True' set as an extra-spec.
InvalidVolumeType400 Bad RequestRaised when a volume's type mismatches the Protection Group's configured volume type.
InvalidState409 ConflictRaised when the requested action (failover, failback, test failover) is not permitted in the Protection Group's current state.
ProtectionGroupFailedOver409 ConflictRaised when attempting a member add, delete, or other modification on a Protection Group that is currently in the failed_over state.
FailoverNotReady / PreflightValidationFailed422 Unprocessable EntityRaised when a failover pre-check fails — for example, the replication link is broken or can_failover is false in the replication health report.
InvalidExecutionSite400 Bad RequestRaised when the operation cannot execute on the site receiving the request — for example, initiating failback from the secondary site.
ResourceConflict409 ConflictSynthesised by the fault middleware for any database unique-constraint violation — for example, reusing the name of a recently deleted Protection Group.
ServiceUnavailable (database)503 Service UnavailableSynthesised by the fault middleware when protector-api loses connectivity to MariaDB/MySQL. Retryable; unrelated to cross-site reachability.
SiteUnreachable503 Service UnavailableRaised when the peer site's protector-api on port 8788 is unreachable during a cross-site operation.
Authentication failure401 UnauthorizedThe Horizon session token (obtained from Keystone on port 5000) has expired or is invalid. Horizon will redirect to the login page.
Unable to retrieve protection groups. (Horizon message)—Displayed on the index page if the GET /v1/{tenant_id}/protection-groups call fails for any reason. The table renders empty rather than raising an unhandled exception.
Unable to retrieve protection group "<id>". (Horizon message)—Displayed on the detail page if the GET /v1/{tenant_id}/protection-groups/{id} call fails; the view redirects to the index page.

The Failover action button is suppressed (not rendered) for Protection Groups whose status is failing_over, failing_back, deleting, error, or failed_over, so the 409/422 errors for those states are rare in normal dashboard use. Similarly, the Failback button is only shown when status is failed_over and the local site matches the original primary site.


Examples

Browsing to the Protection Groups panel

The panel is registered under the Project dashboard. Navigate to:

https://<horizon-host>/project/protection_groups/

You must be logged in as a user with the dr_operator role on your project. The index page lists all Protection Groups for your project with their replication health summary.


Creating a Protection Group

  1. On the index page, click Create Protection Group.

  2. In the dialog that opens, complete the required fields:

    FieldExample value
    Nameprod-web-tier
    Primary Sitelondon-primary
    Secondary Sitefrankfurt-dr
    Replication Typeasync
    Volume Typecinder-replicated
  3. Click Create. The panel redirects to the index page and displays a progress banner while the Protection Group is initialised.

The equivalent CLI command is:

openstack dr protection group create prod-web-tier \
  --primary-site london-primary \
  --secondary-site frankfurt-dr \
  --replication-type async \
  --volume-type cinder-replicated

Adding a VM to a Protection Group

  1. From the index page, click the name of your Protection Group to open the detail page.
  2. Click Add VM.
  3. Enter the Nova instance UUID in the Instance field.
  4. Optionally set a Boot Order integer (e.g. 1 for database VMs that must start first, 2 for application VMs).
  5. Click Add.

If the instance uses ephemeral storage instead of a Cinder-backed boot volume, the dialog returns an InstanceNotCinderBoot error. If any attached volume lacks replication_enabled='<is> True', it returns a VolumeTypeNotReplicated error. Correct the instance or volume configuration before retrying.

The equivalent CLI command is:

openstack dr protection group member add prod-web-tier \
  --instance a1b2c3d4-e5f6-7890-abcd-ef1234567890

Monitoring replication health on the detail page

Open the detail page for a Protection Group. The Replication Health section displays:

  • Failover Ready: Yes or No, derived from replication_health.failover_validation.can_failover.
  • Lag: Current replication lag in seconds (replication_health.health_report.lag.lag_seconds).
  • RPO Compliant: Whether lag is within the configured RPO target.
  • Link Status: Connected/disconnected and direction (replication_health.health_report.link).
  • Transfer Throughput: Current replication throughput in MB/s.
  • Recovery Points: Count of available point-in-time snapshots on the secondary site.

The underlying API call is:

GET /v1/{tenant_id}/protection-groups/{id}/replication-health

Example response structure (relevant excerpt):

{
  "replication_health": {
    "protection_group_id": "pg-uuid",
    "protection_group_name": "prod-web-tier",
    "failover_validation": {
      "can_failover": true,
      "warnings": [],
      "blockers": [],
      "message": "Protection group is ready for failover"
    },
    "health_report": {
      "failover_ready": true,
      "failover_ready_reason": "Replication link healthy",
      "data_at_risk_seconds": 42,
      "replication_type": "async",
      "link": {
        "connected": true,
        "status": "healthy",
        "direction": "primary_to_secondary"
      },
      "lag": {
        "lag_seconds": 42,
        "lag_bytes": null,
        "rpo_compliant": true,
        "rpo_target_seconds": 900,
        "trend": "stable"
      },
      "recovery_points": {
        "total_count": 8,
        "replicated_count": 8,
        "snapshots_missed_24h": 0
      },
      "transfer": {
        "throughput_bytes_per_sec": 5242880
      }
    }
  }
}

Running a test failover

  1. From the Protection Group detail page, click Test Failover.
  2. In the workflow dialog:
    • Select a Recovery Point (or leave blank for the most recent).
    • Choose Auto Network to let the engine select a network automatically, or configure Network Mapping to map each source network to a target network on the secondary site.
    • Optionally configure Flavor Mapping and Availability Zone.
  3. Click Run Test Failover.

The panel stores the returned operation_id in the session and displays a progress banner. Test VMs are created with a test- prefix on an isolated network on the secondary site. Production workloads are not affected.

To clean up test resources after validation, click Test Cleanup from the detail page. Check Force if you want cleanup to proceed even if some resources fail to delete.

The equivalent CLI commands are:

# Initiate test failover
openstack dr test failover prod-web-tier --auto-network

# Clean up after testing
openstack dr test failover cleanup prod-web-tier

Executing a planned failover

  1. Navigate to the Protection Groups panel on the secondary (DR) site. The Failover button is only rendered on the secondary site when the Protection Group status is active.
  2. Click Failover next to the Protection Group.
  3. Select Failover Type: planned (gracefully shuts down VMs and takes a final snapshot for zero data loss) or unplanned (skips shutdown; data loss up to the RPO applies).
  4. Optionally select a Recovery Point.
  5. Click Execute Failover.

The operation is submitted as:

POST /v1/{tenant_id}/protection-groups/{pg_id}/action

With an action body such as:

{
  "failover": {
    "failover_type": "planned"
  }
}

The API returns HTTP 202 with a body including operation_id and initial status of pending. The Horizon progress banner polls GET /v1/{tenant_id}/operations/{operation_id} until status reaches completed or failed.


Executing failback

  1. Navigate to the Protection Groups panel on the original primary site. The Failback button is only rendered on the original primary site when the Protection Group status is failed_over.
  2. Click Failback.
  3. Confirm the operation in the dialog.
  4. Click Execute Failback.

The equivalent CLI command is:

openstack dr failback prod-web-tier

Polling operation progress via the JSON endpoint

The index page injects a lightweight polling script that calls:

GET /project/protection_groups/operation-status/

This view reads the dr_pending_operation key from the Django session and fetches the current operation status from:

GET /v1/{tenant_id}/operations/{operation_id}

When status reaches completed, failed, or cancelled, the session key is cleared and the banner is dismissed. You can also inspect any operation directly at:

https://<horizon-host>/project/protection_groups/operation/<operation_id>/

Notes

Panel registration and visibility

The panel is registered under the Project dashboard (openstack_dashboard.dashboards.project) with the slug protection_groups. It becomes visible to users whose Keystone token carries the dr_operator role on their project. Users without this role will not see the panel in the sidebar. Both dr_operator and dr_site_admin roles must be pre-created on both sites before any cross-site operation can succeed — the service looks up roles rather than creating them, and trust creation fails immediately if either role is absent.

Site-aware button visibility

The Failover and Failback action buttons are site-aware:

  • Failover is shown only on the secondary site and only when Protection Group status is active. The panel checks whether the local site ID matches secondary_site_id on the Protection Group object.
  • Failback is shown only on the original primary site and only when status is failed_over. The panel uses primary_site_id (the original primary, not the post-failover current primary) for this check.
  • The panel uses the status field as the authoritative signal rather than current_primary_site_id, because cross-site sync of current_primary_site_id may be incomplete due to foreign-key constraints on the remote site's database.
  • If the local site cannot be determined (e.g. the GET /v1/{tenant_id}/sites/local call fails), both buttons default to visible and the server enforces the site check, returning HTTP 400 (InvalidExecutionSite) if the operation is submitted from the wrong site.

Member eligibility pre-checks

Before submitting an Add VM request, you can use the validate endpoint to detect problems without side effects:

POST /v1/{tenant_id}/protection-groups/{pg_id}/members/validate

This returns HTTP 200 with a structured errors array. The dashboard does not currently call this endpoint automatically, but you can call it directly or via the CLI (openstack dr protection group member validate) before using the Add VM dialog.

Recovery points and ActiveDR

The Create Recovery Point batch action in the index table (icon: camera) is only enabled for Protection Groups using replication_type: active_dr. For async Protection Groups, recovery points are created automatically on the replication interval; on-demand creation is an ActiveDR-specific feature. The underlying endpoint is:

POST /v1/{tenant_id}/protection-groups/{id}/recovery-points

Metadata sync

The Sync batch action calls:

POST /v1/{tenant_id}/protection-groups/{id}/sync-metadata

This detects VM changes — new disks, new network attachments — and replicates updated metadata to the peer site. Run sync after adding a new volume to a protected VM so the engine is aware of the new attachment before the next failover.

Resource mapping widget behaviour

The network and flavor mapping widget in the Failover and Test Failover dialogs auto-selects a target resource whose name exactly matches the source name. Where no name match exists on the target site, the widget presents a — match by name — option (empty value), which instructs the engine to resolve by name at execution time. Selecting a specific target UUID overrides name-based resolution. If the target site has no resources of that type, the dropdown shows No resources on target site and you must create the corresponding resource on the secondary site before failover.

Dashboard package name

The Horizon plugin is shipped as the Debian package python3-triliositerecovery-dashboards. The Python module installed by this package is protector_dashboards (the module retains the original product name). The Juju dashboard charm is named trilio-site-recovery-for-openstack-dashboard on Charmhub.

Direct editing of protector.conf is not supported

In Juju charm deployments, protector.conf is rendered by the charm from relation data and juju config values. Do not edit /etc/protector/protector.conf directly — the charm overwrites manual edits on every config-changed event. Use juju config trilio-site-recovery <key>=<value> with hyphenated option names instead.

openstackclient snap incompatibility

The openstack dr CLI commands shown in the examples require the python3-triliositerecovery package installed alongside python-openstackclient installed via pip, not via snap. The openstackclient snap cannot load third-party CLI plugins and will not expose openstack dr subcommands.