Kubectl Commands
Common kubectl commands for managing site recovery resources, checking status, and inspecting events
This reference covers the kubectl (and oc) commands you use every day to manage Trilio Site Recovery resources: creating protection zones, monitoring replication health, triggering failovers, and collecting diagnostics. All DR operations are driven by Custom Resources in the siterecovery.trilio.io/v1alpha1 API group; kubectl and oc are the only supported CLIs. Use oc wherever OpenShift-specific paths are required (must-gather, Routes).
kubectl [--context=<ctx>] [--kubeconfig=<path>] <verb> <resource>[/<name>] [flags]
oc [--context=<ctx>] [--kubeconfig=<path>] <verb> <resource>[/<name>] [flags]
Every command that targets the quorum cluster requires a kubeconfig or context pointing at that cluster. Commands that target a workload cluster (primary or DR) require the corresponding kubeconfig. Both are shown explicitly in every example below.
The flags below are standard kubectl/oc flags used throughout this reference. Site Recovery adds no custom flags to the CLI.
| Flag | Short | Default | Description |
|---|---|---|---|
--kubeconfig=<path> | ~/.kube/config | Path to the kubeconfig file. Use separate files for the quorum, primary, and DR clusters. | |
--context=<name> | active context | Kubeconfig context to use. | |
--namespace=<ns> | -n | active namespace | Kubernetes namespace. Quorum CRs live in dr-<name>; workload components live in trilio-site-recovery-system. |
--all-namespaces | -A | false | List resources across all namespaces. |
--output=<format> | -o | (table) | Output format: yaml, json, wide, jsonpath=<expr>. |
--watch | -w | false | Watch for changes and print updates as they arrive. |
--field-selector=<expr> | Filter on metadata.name or metadata.namespace only. Field selectors on spec.* or status.* are not supported on Site Recovery CRDs. | ||
--selector=<labels> | -l | Filter by label selector. Preferred over field selectors for CRD filtering. | |
--type=<strategy> | strategic | Patch strategy for kubectl patch: strategic, merge, or json. | |
--since=<duration> | Used with kubectl logs to limit log history, e.g. --since=1h. | ||
--previous | -p | false | Used with kubectl logs to print the previous container's logs (pre-restart). |
The table below shows the kubectl verbs most commonly used with Site Recovery resources.
| Verb | Description |
|---|---|
get | List or describe one or more resources. Supports -o yaml for full spec/status. |
apply | Create or update a resource from a manifest file. The primary way to create ProtectionZones, FailoverRequests, TestFailovers, and ProtectionRequests. |
delete | Delete a resource. For ProtectionRequests this begins the unprotection flow; do not force-delete unless you understand the data implications. |
describe | Print a human-readable summary including events and conditions. |
logs | Stream or print container logs. Used to inspect controller and node-agent output. |
exec | Execute a command inside a container. Used for DRBD kernel state inspection on node-agent pods. |
patch | Update specific fields of a resource in place. Use --type=merge or --type=json. |
edit | Open a resource in your editor. Admission webhooks will reject disallowed changes. |
wait | Block until a resource reaches a condition. Useful in scripts and CI pipelines. |
Site Recovery itself does not read environment variables, but the following shell conventions are used throughout this reference to keep examples readable.
| Variable | Default | Description |
|---|---|---|
KUBECONFIG_QUORUM | (none) | Path to the quorum cluster kubeconfig. Set this before running any quorum-side command. |
KUBECONFIG_PRIMARY | (none) | Path to the primary (cluster1) workload cluster kubeconfig. |
KUBECONFIG_DR | (none) | Path to the DR (cluster2) workload cluster kubeconfig. |
ZONE_NS | (none) | The zone namespace, always dr-<name>. Set once and reuse across commands. |
Note:
kubectldoes not readKUBE_CONTEXT. Pass--contextexplicitly when switching contexts within a single kubeconfig file.
Standard kubectl/oc exit codes apply.
| Code | Meaning |
|---|---|
0 | Success. |
1 | Generic error (API error, resource not found, admission webhook rejection, connection refused). The error message is printed to stderr. |
For oc adm must-gather (the tsr-gather diagnostics image), see the examples section for the tool's own exit codes.
All examples use shell variables defined as:
export KUBECONFIG_QUORUM=~/.kube/config-quorum
export KUBECONFIG_PRIMARY=~/.kube/config-primary
export KUBECONFIG_DR=~/.kube/config-dr
export ZONE_NS=dr-edge # replace with your zone name
Short names quick-reference
Site Recovery CRDs register the following short names:
| Kind | Short names |
|---|---|
ProtectionZone | pz |
ProtectionGroup | pg |
ProtectionRequest | pr, protect |
DRBDReplicationPolicy | drp, drbdpolicy |
FailoverRequest | fr |
TestFailover | tfo |
ReplicationGroupStatus | rgs |
RPOEvent | rpoe |
DRBDResource | dres |
Cluster placement reminder
Before running any command, confirm which cluster the resource lives on:
| Resource kind | Lives on |
|---|---|
ProtectionZone, ProtectionGroup, ProtectionRequest, DRBDReplicationPolicy, FailoverRequest, TestFailover, ReplicationGroupStatus, RPOEvent | Quorum cluster, in namespace dr-<name> |
DRBDResource | Primary and DR workload clusters, in the protected VM's namespace |
| Node-agent DaemonSet pods | Primary and DR workload clusters, in trilio-site-recovery-system |
Running kubectl get drbdresource against the quorum cluster returns server doesn't have a resource type — that is expected.
1. Inspect the ProtectionZone
The ProtectionZone CR is the root of every DR deployment. Check it first when diagnosing zone-wide problems.
# List all zones (quorum cluster)
kubectl --kubeconfig "$KUBECONFIG_QUORUM" get pz -A
Expected output:
NAMESPACE NAME DISPLAY NAME BACKEND CLUSTERS STATUS AGE
dr-edge edge Edge Zone DRBD primary,dr-site Available 12d
# Full spec and status for one zone
kubectl --kubeconfig "$KUBECONFIG_QUORUM" get pz edge -n "$ZONE_NS" -o yaml
Key fields to check:
status.phase: should beAvailablestatus.clusters[*].status: both entries should beReachable
# Describe for human-readable conditions and events
kubectl --kubeconfig "$KUBECONFIG_QUORUM" describe pz edge -n "$ZONE_NS"
2. Create a ProtectionZone
Create the dr-<name> namespace and the kubeconfig Secrets first, then apply the zone CR. The ProtectionZone controller deploys the quorum and workload control planes automatically once the zone reaches Available.
# Create the zone namespace
oc --kubeconfig "$KUBECONFIG_QUORUM" new-project "$ZONE_NS"
# Store workload cluster kubeconfigs as Secrets in the zone namespace
oc --kubeconfig "$KUBECONFIG_QUORUM" create secret generic primary-kubeconfig \
--from-file=kubeconfig="$KUBECONFIG_PRIMARY" \
-n "$ZONE_NS"
oc --kubeconfig "$KUBECONFIG_QUORUM" create secret generic dr-kubeconfig \
--from-file=kubeconfig="$KUBECONFIG_DR" \
-n "$ZONE_NS"
# Apply the ProtectionZone CR
oc --kubeconfig "$KUBECONFIG_QUORUM" apply -f - <<'EOF'
apiVersion: siterecovery.trilio.io/v1alpha1
kind: ProtectionZone
metadata:
name: edge
namespace: dr-edge
spec:
displayName: "Edge Zone"
storageBackendMode: DRBD
clusters:
- name: primary
clusterID: cluster1
distributionName: RHEL-CoreOS-9
kubeconfigSecretRef:
name: primary-kubeconfig
key: kubeconfig
- name: dr-site
clusterID: cluster2
distributionName: RHEL-CoreOS-9
kubeconfigSecretRef:
name: dr-kubeconfig
key: kubeconfig
logging:
level: info
EOF
# Watch the zone reach Available
kubectl --kubeconfig "$KUBECONFIG_QUORUM" get pz edge -n "$ZONE_NS" -w
Expected progression: Provisioning → Available.
3. List and inspect ProtectionGroups
ProtectionGroups define the VMs that fail over together.
# List all protection groups in a zone (quorum cluster)
kubectl --kubeconfig "$KUBECONFIG_QUORUM" get pg -n "$ZONE_NS"
Expected output:
NAME VMS STATE ACTIVE AGE
web-pg vm-web-1,vm-web-2 Protected cluster1 5d
# Full status
kubectl --kubeconfig "$KUBECONFIG_QUORUM" get pg web-pg -n "$ZONE_NS" -o yaml
Key fields:
status.state:Protected|Syncing|Degraded|Failedstatus.activeClusterID: which cluster currently runs the VMsstatus.protectedVMs[*].replicationStatus: per-VM replication state
4. Protect a virtual machine (ProtectionRequest)
A ProtectionRequest instructs the protection controller to set up DRBD replication for one VM's disks.
oc --kubeconfig "$KUBECONFIG_QUORUM" apply -f - <<'EOF'
apiVersion: siterecovery.trilio.io/v1alpha1
kind: ProtectionRequest
metadata:
name: protect-vm-web-1
namespace: dr-edge
spec:
sourceCluster: cluster1
virtualMachine:
name: vm-web-1
namespace: production
EOF
# Watch protection progress
kubectl --kubeconfig "$KUBECONFIG_QUORUM" get pr protect-vm-web-1 -n "$ZONE_NS" -w
Expected phase progression:
Pending → Validating → CreatingDRBD → Syncing → ReadyToActivate → Activating → Protected
# Check sync progress (percentage field)
kubectl --kubeconfig "$KUBECONFIG_QUORUM" get pr protect-vm-web-1 -n "$ZONE_NS" \
-o jsonpath='{.status.syncProgress}'
5. Check replication health (ReplicationGroupStatus)
The replication monitor auto-creates one ReplicationGroupStatus per ProtectionGroup, named <protection-group-name>-replication.
# List all replication statuses in a zone (quorum cluster)
kubectl --kubeconfig "$KUBECONFIG_QUORUM" get rgs -n "$ZONE_NS"
Expected output:
NAME PROTECTION-GROUP RPO-STATUS OUT-OF-SYNC SYNCED CONNECTION LAST-SYNC
web-pg-replication web-pg Met 0 4 Connected 2m ago
# Full detail for one group
kubectl --kubeconfig "$KUBECONFIG_QUORUM" get rgs web-pg-replication -n "$ZONE_NS" -o yaml
Key fields:
status.rpoStatus:Met|Degraded|Violated|Unknownstatus.aggregated.connectionState:Connected|Degraded|Disconnectedstatus.aggregated.outOfSyncBytes: should be0for a healthy synchronous replicationstatus.lastFullySyncedAt: timestamp of the last full syncstatus.volumeReplicationStatuses: per-volume breakdown
# Filter by protection group using the label (field selectors on spec.* are not supported)
kubectl --kubeconfig "$KUBECONFIG_QUORUM" get rgs -n "$ZONE_NS" \
-l siterecovery.trilio.io/protection-group=web-pg
6. Inspect DRBDResource on workload clusters
DRBDResource CRs live on the workload clusters (primary and DR), not on the quorum. One CR exists per VM per cluster side.
# List DRBDResources on the primary cluster
kubectl --kubeconfig "$KUBECONFIG_PRIMARY" get dres -A
Expected output:
NAMESPACE NAME SIDE ROLE NODE STATE PHASE
production drbd-production-vm-web-1-a1b2c3d4 Source Primary worker-1 Connected Consistent
# Same on the DR cluster
kubectl --kubeconfig "$KUBECONFIG_DR" get dres -A
# Full status for one resource on primary (shows per-volume sync progress)
kubectl --kubeconfig "$KUBECONFIG_PRIMARY" get dres drbd-production-vm-web-1-a1b2c3d4 \
-n production -o yaml
Key status fields:
status.phase:Consistentis the healthy state;Syncingmeans initial sync in progress;DegradedorFailedrequires attentionstatus.connectionState:Connected|Connecting|Disconnected|StandAlonestatus.role:Primaryon the active cluster,Secondaryon the standbystatus.syncProgress.percentage: 0–100 during initial syncstatus.volumes[*].replicationState: per-volume DRBD state
# Watch sync progress across all resources
kubectl --kubeconfig "$KUBECONFIG_PRIMARY" get dres -A -w
7. Identify protected VMs
The label siterecovery.trilio.io/protected-vm=true is stamped on VirtualMachine objects on the workload clusters.
# List all protected VMs on the primary cluster
kubectl --kubeconfig "$KUBECONFIG_PRIMARY" get vm -A \
-l siterecovery.trilio.io/protected-vm=true
Important: This label is on the
VirtualMachineobject only. Querying it ondresorprreturns nothing.
8. Inspect node-agent pods and DRBD state
The DRBD node-agent runs as a DaemonSet on every worker node of the primary and DR clusters, in the trilio-site-recovery-system namespace.
# List all node-agent pods on the primary cluster
kubectl --kubeconfig "$KUBECONFIG_PRIMARY" get pods -n trilio-site-recovery-system \
-l app.kubernetes.io/component=drbd-node-agent
Expected output:
NAME READY STATUS NODE
edge-site-recovery-workload-control-plane-agent-abcd1 1/1 Running worker-1
edge-site-recovery-workload-control-plane-agent-efgh2 1/1 Running worker-2
# Stream logs from a node-agent pod (two-step: get pod name for a node, then stream logs)
NODE=worker-1
POD=$(kubectl --kubeconfig "$KUBECONFIG_PRIMARY" get pods -n trilio-site-recovery-system \
--field-selector spec.nodeName="$NODE" \
-l app.kubernetes.io/component=drbd-node-agent \
-o jsonpath='{.items[0].metadata.name}')
kubectl --kubeconfig "$KUBECONFIG_PRIMARY" logs "$POD" \
-n trilio-site-recovery-system -c agent --since=1h
# View DRBD module-loader init container log (init logs are not time-bounded)
kubectl --kubeconfig "$KUBECONFIG_PRIMARY" logs "$POD" \
-n trilio-site-recovery-system -c drbd-module-loader
# Run a DRBD kernel-state command inside the agent container
kubectl --kubeconfig "$KUBECONFIG_PRIMARY" exec "$POD" \
-n trilio-site-recovery-system -c agent -- drbdsetup status --verbose
9. Inspect quorum control-plane logs
The quorum control plane runs as a single Deployment per zone namespace on the quorum cluster. The pod runs one container named manager and hosts all reconcilers (failover, protection, pg-sync, replication-monitor, test-failover).
# Get the quorum control-plane pod
kubectl --kubeconfig "$KUBECONFIG_QUORUM" get pods -n "$ZONE_NS" \
-l app.kubernetes.io/component=quorum-control-plane
Expected output (1/1 — one container named manager):
NAME READY STATUS AGE
site-recovery-quorum-control-plane-7d9f-abc 1/1 Running 12d
# Stream logs from the quorum manager
QUORUM_POD=$(kubectl --kubeconfig "$KUBECONFIG_QUORUM" get pods -n "$ZONE_NS" \
-l app.kubernetes.io/component=quorum-control-plane \
-o jsonpath='{.items[0].metadata.name}')
kubectl --kubeconfig "$KUBECONFIG_QUORUM" logs "$QUORUM_POD" \
-n "$ZONE_NS" -c manager --since=1h
# Previous container logs (if manager restarted)
kubectl --kubeconfig "$KUBECONFIG_QUORUM" logs "$QUORUM_POD" \
-n "$ZONE_NS" -c manager --previous
10. Inspect the ProtectionZone controller logs
The OLM-installed ProtectionZone controller runs in trilio-site-recovery-system on the quorum cluster.
PZ_POD=$(kubectl --kubeconfig "$KUBECONFIG_QUORUM" get pods -n trilio-site-recovery-system \
-l control-plane=protection-zone-controller \
-o jsonpath='{.items[0].metadata.name}')
kubectl --kubeconfig "$KUBECONFIG_QUORUM" logs "$PZ_POD" \
-n trilio-site-recovery-system -c manager --since=1h
11. Adjust runtime log level
Log levels are controlled per namespace via the site-recovery-logging ConfigMap. Valid levels are error, info, debug, and trace. There is no warn level.
# Set the quorum control-plane to debug for the zone namespace
kubectl --kubeconfig "$KUBECONFIG_QUORUM" patch configmap site-recovery-logging \
-n "$ZONE_NS" --type=merge \
-p '{"data":{"level":"debug"}}'
# Set only the node-agent component to debug on a workload cluster
kubectl --kubeconfig "$KUBECONFIG_PRIMARY" patch configmap site-recovery-logging \
-n trilio-site-recovery-system --type=merge \
-p '{"data":{"level.drbd-node-agent":"debug"}}'
# Reset to info
kubectl --kubeconfig "$KUBECONFIG_QUORUM" patch configmap site-recovery-logging \
-n "$ZONE_NS" --type=merge \
-p '{"data":{"level":"info"}}'
12. Run a test failover
A TestFailover validates your DR capability non-disruptively using volume snapshots. The test namespace is generated by the controller; do not try to predict or specify it.
oc --kubeconfig "$KUBECONFIG_QUORUM" apply -f - <<'EOF'
apiVersion: siterecovery.trilio.io/v1alpha1
kind: TestFailover
metadata:
name: web-pg-test
namespace: dr-edge
spec:
protectionGroupRef:
name: web-pg
cleanupPolicy: Automatic
retentionTime: 2h
EOF
# Watch phases
kubectl --kubeconfig "$KUBECONFIG_QUORUM" get tfo web-pg-test -n "$ZONE_NS" -w
Expected phase progression:
Queued → PreparingEnvironment → CreatingSnapshots → CreatingVolumes → CreatingVMs → StartingVMs → Verifying → Succeeded → CleaningUp → Cleaned
# Check the test namespace that was created (controller-generated, do not guess)
kubectl --kubeconfig "$KUBECONFIG_QUORUM" get tfo web-pg-test -n "$ZONE_NS" \
-o jsonpath='{.status.testNamespace}'
# Check verification results
kubectl --kubeconfig "$KUBECONFIG_QUORUM" get tfo web-pg-test -n "$ZONE_NS" \
-o jsonpath='{.status.verificationResults}'
# Delete a manual-cleanup test failover (removes all test resources)
kubectl --kubeconfig "$KUBECONFIG_QUORUM" delete tfo web-pg-test -n "$ZONE_NS"
13. Execute a planned failover
A planned failover gracefully stops VMs on the active cluster and starts them on the target cluster.
oc --kubeconfig "$KUBECONFIG_QUORUM" apply -f - <<'EOF'
apiVersion: siterecovery.trilio.io/v1alpha1
kind: FailoverRequest
metadata:
name: web-pg-planned-fo
namespace: dr-edge
spec:
protectionGroupRef:
name: web-pg
targetCluster: cluster2
failoverType: planned
EOF
# Watch state and phase
kubectl --kubeconfig "$KUBECONFIG_QUORUM" get fr web-pg-planned-fo -n "$ZONE_NS" -w
Expected output columns: PROTECTION GROUP, TARGET, STATE, PHASE, AGE
Expected phase progression:
Initializing → Validating → StoppingSource → WaitingForLocks → RemovingTaints → StartingTarget → Monitoring → Completed
# Check per-VM status (no .status.failedVMs field — detail is in vmStatuses)
kubectl --kubeconfig "$KUBECONFIG_QUORUM" get fr web-pg-planned-fo -n "$ZONE_NS" \
-o jsonpath='{.status.vmStatuses}'
# Full status
kubectl --kubeconfig "$KUBECONFIG_QUORUM" get fr web-pg-planned-fo -n "$ZONE_NS" -o yaml
14. Execute an unplanned failover
Use failoverType: unplanned when the primary cluster is unavailable. DRBD volumes are force-promoted on the DR cluster without waiting for the primary to shut down gracefully.
oc --kubeconfig "$KUBECONFIG_QUORUM" apply -f - <<'EOF'
apiVersion: siterecovery.trilio.io/v1alpha1
kind: FailoverRequest
metadata:
name: web-pg-emergency-fo
namespace: dr-edge
spec:
protectionGroupRef:
name: web-pg
targetCluster: cluster2
failoverType: unplanned
EOF
kubectl --kubeconfig "$KUBECONFIG_QUORUM" get fr web-pg-emergency-fo -n "$ZONE_NS" -w
Data loss note: If replication was
Consistentat the moment of failure, zero data loss occurs. If replication wasDegraded, minimal data loss may occur depending on out-of-sync bytes at failure time. CheckReplicationGroupStatushistory andRPOEventrecords after restoring quorum connectivity.
15. View RPO events
RPOEvents record replication lag violations with severity, lag duration, and affected volumes.
# List recent RPO events for a zone (quorum cluster)
kubectl --kubeconfig "$KUBECONFIG_QUORUM" get rpoe -n "$ZONE_NS"
Expected output columns: PROTECTION-GROUP, EVENT-TYPE, RPO-SECONDS, OUT-OF-SYNC, REASON, TIMESTAMP, AGE
# Filter by protection group using the label
kubectl --kubeconfig "$KUBECONFIG_QUORUM" get rpoe -n "$ZONE_NS" \
-l siterecovery.trilio.io/protection-group=web-pg
# Get full detail of one event
kubectl --kubeconfig "$KUBECONFIG_QUORUM" get rpoe <event-name> -n "$ZONE_NS" -o yaml
Key spec fields:
spec.eventType: e.g.ConnectionLost,RPOViolated,ResyncStartedspec.rpoAtEvent: RPO in seconds at the time of the eventspec.outOfSyncBytesAtEvent: bytes out of sync when the event was recordedspec.violationReason: why the RPO was violated
16. Check replication policies
The DRBDReplicationPolicy for your zone is created automatically by the ProtectionZone controller; you do not create or modify it. The policy is named <zoneName>-default and has isDefault: true.
# View the auto-created replication policy (quorum cluster)
kubectl --kubeconfig "$KUBECONFIG_QUORUM" get drp -n "$ZONE_NS"
Expected output:
NAME CLUSTERS MODE PROTOCOL DEFAULT PHASE
edge-default ... Synchronous C true Ready
# Full spec
kubectl --kubeconfig "$KUBECONFIG_QUORUM" get drp edge-default -n "$ZONE_NS" -o yaml
Note: Protocol C synchronous replication is the only supported mode. The admission webhook rejects Protocol A. RPO is always 0 and is not tunable.
17. Wait for a resource condition (scripting)
# Wait for a ProtectionRequest to reach Protected phase
kubectl --kubeconfig "$KUBECONFIG_QUORUM" wait pr/protect-vm-web-1 \
-n "$ZONE_NS" \
--for=jsonpath='{.status.phase}'=Protected \
--timeout=30m
# Wait for a FailoverRequest to complete
kubectl --kubeconfig "$KUBECONFIG_QUORUM" wait fr/web-pg-planned-fo \
-n "$ZONE_NS" \
--for=jsonpath='{.status.state}'=Completed \
--timeout=10m
# Wait for a TestFailover to succeed
kubectl --kubeconfig "$KUBECONFIG_QUORUM" wait tfo/web-pg-test \
-n "$ZONE_NS" \
--for=jsonpath='{.status.phase}'=Succeeded \
--timeout=20m
18. Collect a diagnostic bundle with tsr-gather
tsr-gather is shipped as an oc adm must-gather image. Run it against the quorum cluster; it collects the quorum and then reaches through every ProtectionZone's kubeconfig Secrets to collect each workload cluster automatically.
# Full estate — 48h of logs (default)
oc adm must-gather \
--image=quay.io/triliovault/site-recovery-must-gather:<tag>
# Narrow the log window and restrict to one zone
oc adm must-gather \
--image=quay.io/triliovault/site-recovery-must-gather:<tag> \
-- /usr/bin/gather --since 6h --zone edge
# Collect only the local cluster (no reach-through to workload clusters)
oc adm must-gather \
--image=quay.io/triliovault/site-recovery-must-gather:<tag> \
-- /usr/bin/gather --local-only
# Bound the total run time (partial bundle stays coherent on timeout)
oc adm must-gather \
--timeout=10m \
--image=quay.io/triliovault/site-recovery-must-gather:<tag> \
-- /usr/bin/gather --since 2h
# Also collect a kind not in the standard matrix
oc adm must-gather \
--image=quay.io/triliovault/site-recovery-must-gather:<tag> \
-- /usr/bin/gather --gvk apps/v1/StatefulSet:app-ns
The bundle lands in ./must-gather.local.<hash>/. Open SUMMARY.md first (what is wrong), then manifest.yaml (what was collected and what was missed).
tsr-gather exit codes:
| Code | Meaning |
|---|---|
0 | At least one cluster was collected. Partial failures are recorded in manifest.yaml, not reflected in the exit code. |
1 | Fatal startup error: unwritable output, no API config, bad flags, unknown --zone, or unreachable local cluster. |
2 | The cluster answered but runs no Site Recovery component. A successful "wrong cluster" answer. |
What is never collected: Secret values (only names, types, and key names), cloud-init payloads (userData, userDataBase64, networkData, networkDataBase64 — replaced with REDACTED-BY-TSR-GATHER), kubeconfig data, DRBD shared-secret values, and kubectl.kubernetes.io/last-applied-configuration values.
19. Selecting all Site Recovery objects in a namespace
Use the app.kubernetes.io/part-of=site-recovery label to select any Site Recovery-owned object.
# All site-recovery pods in the zone namespace (quorum cluster)
kubectl --kubeconfig "$KUBECONFIG_QUORUM" get pods -n "$ZONE_NS" \
-l app.kubernetes.io/part-of=site-recovery
# All site-recovery pods on a workload cluster
kubectl --kubeconfig "$KUBECONFIG_PRIMARY" get pods -n trilio-site-recovery-system \
-l app.kubernetes.io/part-of=site-recovery
# Quorum control-plane pods only
kubectl --kubeconfig "$KUBECONFIG_QUORUM" get pods -n "$ZONE_NS" \
-l app.kubernetes.io/component=quorum-control-plane
# Workload control-plane pods only (on a workload cluster)
kubectl --kubeconfig "$KUBECONFIG_PRIMARY" get pods -n trilio-site-recovery-system \
-l app.kubernetes.io/component=workload-control-plane
20. Node-agent taint and placement constraints
Protected VMs are pinned to one node per cluster for the lifetime of the protection. The node agent applies a siterecovery.trilio.io/not-ready:NoSchedule taint to its own node until DRBD converges.
# Check node taints on primary worker nodes
kubectl --kubeconfig "$KUBECONFIG_PRIMARY" get nodes -o \
custom-columns=NAME:.metadata.name,TAINTS:.spec.taints
# Check that a protected VM's nodeName matches the expected anchor node
kubectl --kubeconfig "$KUBECONFIG_QUORUM" get pr protect-vm-web-1 -n "$ZONE_NS" \
-o jsonpath='{.status.sourceAnchorNode}'
Important: Live migration and cold migration of a protected VM are denied by the admission webhook. Draining a node that hosts a running protected VM will not complete. To move a protected VM, you must unprotect it, drain the node, and then re-protect it — which requires a full initial resync.