Tutorial: Integrating External Remediation
This tutorial walks you through configuring NVSentinel to create an ExternalRemediationRequest for an external system. NVSentinel uses an ExternalRemediationRequest for repairs that it cannot do itself. The external system repairs the node and reports the result on the ExternalRemediationRequest.
By the end you will have:
- An
external-remediationaction that makes fault-remediation create an ExternalRemediationRequest. - The RBAC permissions that let the external system read an ExternalRemediationRequest and write the result.
- A tested handover: NVSentinel releases a node, and takes the node back when the external system reports that the repair is complete.
Who is this for? Teams that already run NVSentinel and repair some faults with an external system. Examples are a hardware repair by a cloud provider, a long workflow in other automation, or a manual repair by an operator.
Just want the AI to do it? Jump to Appendix: One-shot AI prompt.
Safety: Use a test node that has no important workloads. When NVSentinel releases a node, it stops its health monitors on that node. NVSentinel takes the node back when the external system reports that the repair is complete. NVSentinel also takes the node back when an operator deletes the ExternalRemediationRequest, or when janitor deletes it at the time limit in section 2.
Prerequisites
- NVSentinel v1.24.0 or later.
- NVSentinel with fault-quarantine, node-drainer, fault-remediation and janitor enabled. These components are disabled by default.
- Helm 3.14 or later and
kubectl. - Cluster-admin access to upgrade the NVSentinel Helm release and to create a ClusterRole.
- A test node that NVSentinel can cordon, drain and release.
You do not need a finished external system for this tutorial. In the validation step, you act as the external system with kubectl.
See the NVSentinel Helm chart guide for the complete NVSentinel prerequisites.
1. How an ExternalRemediationRequest works
An ExternalRemediationRequest is a Kubernetes custom resource that NVSentinel defines. It contains details from the health event that started the repair.
NVSentinel follows one rule for each node: exactly one system is responsible for the node at a time. An ExternalRemediationRequest moves this responsibility from NVSentinel to the external system, and later back to NVSentinel.
To release the node, janitor makes two changes to the node in one update:
The managed=false label has two results:
- The labeler removes its detection labels from the node. The NVSentinel health monitors that run on the node then stop.
- platform-connector stores each health event for the node, but NVSentinel does not act on it.
To take the node back, janitor removes the taint and the label.
NVSentinel never contacts the external system. The external system watches the cluster for new ExternalRemediationRequests. When the repair is complete, the external system writes the result on the same ExternalRemediationRequest.
For the design rationale and limitations, see ADR-040.
Note: ADR-040 was written before the release, and some details changed. The released API group is
nvsentinel.dgxc.nvidia.com/v1, the resource is cluster-scoped, and the short name isextrr.
2. The completion contract
janitor and the external system communicate only through the conditions in the ExternalRemediationRequest status. janitor writes one condition, and the external system writes the other.
The external system must do these steps:
- Wait until
NVSentinelOwnershipReleasedisTrue. Before then, janitor has not released the node. - Read the node name from
spec.healthEvent.nodeName. - Repair the node.
- Set
ExternalRemediationCompletetoTruewhen the repair succeeds, or toFalsewhen the external system stops. Set areasonand amessagethat explain the result.
The external system writes to the status subresource of the ExternalRemediationRequest. The status subresource is the part of an object where controllers write their results. The status.conditions field is a list, so a write of one condition replaces the full list. When you set ExternalRemediationComplete, keep the NVSentinelOwnershipReleased condition in the list.
The result controls what NVSentinel does next:
janitor adds a finalizer to each ExternalRemediationRequest. A finalizer stops Kubernetes from removing an object until a controller completes its cleanup. Because of this finalizer, a deletion always returns the node to NVSentinel. To take back a node after ExternalRemediationComplete=False, delete the ExternalRemediationRequest.
Note: In a default install, janitor deletes each ExternalRemediationRequest 336 hours after janitor first finds it, even if the repair is not complete. The deletion returns the node to NVSentinel. The template in section 4 disables this time limit.
3. Register the external-remediation action
fault-remediation creates an object for each action in its maintenance.actions Helm values. For a health event with recommendedAction: CUSTOM, fault-remediation uses the value of customRecommendedAction as the action name. The chart does not include an external-remediation action, so you add it.
Create a values file with this action:
Do not set impactedEntityScope for this action. The release taint applies to the full node, so only one ExternalRemediationRequest can hold a node. With impactedEntityScope, fault-remediation can create one ExternalRemediationRequest for each GPU, and their taints conflict.
RBAC: fault-remediation creates its own RBAC rules from
maintenance.actions. It can create ExternalRemediationRequests without more configuration.
4. Add the ExternalRemediationRequest template
fault-remediation builds each ExternalRemediationRequest from a template. Add the template to values-external-remediation.yaml. The complete file is:
Note: fault-remediation renders templates with the Go
text/templatepackage only. Helper functions such asquoteortoYamlare not available.printfis part oftext/template.
Apply the values file. Helm adds the new action to the default actions, so the default actions stay.
Make sure that fault-remediation loaded the action:
5. Grant RBAC to the external system
The external system needs permission to read ExternalRemediationRequests and to write their status. The NVSentinel chart does not include these permissions.
Save this file as extrr-rbac.yaml. Change repair-controller and repair to the name and namespace of the ServiceAccount that the external system uses.
Give delete only to operators. A deletion returns the node to NVSentinel, even if the repair is not complete.
Apply the file:
Make sure that the external system can write the status, and cannot delete an ExternalRemediationRequest:
6. Validate the handover
This section tests the handover between janitor and the external system. You create an ExternalRemediationRequest by hand, as the NVSentinel end-to-end tests do. Then you act as the external system. fault-remediation does not create this ExternalRemediationRequest, so NVSentinel does not cordon or drain the node in this test.
Set the name of your test node:
Create an ExternalRemediationRequest for the node:
Wait for janitor to release the node:
Make sure that the node has the release taint and the managed=false label. The command counts the lines that contain the taint key or the label key:
Act as the external system, and write ExternalRemediationComplete=True. The patch replaces only the second entry in the status.conditions list, so it keeps the NVSentinelOwnershipReleased condition. The test operation checks that the second entry is ExternalRemediationComplete. If the list has a different order, the patch fails and changes nothing.
Make sure that janitor took the node back. Run the same count as before:
janitor removed the taint and the label, so NVSentinel manages the node again. If the count is not 0, run the command again after a few seconds.
Delete the test ExternalRemediationRequest and the patch file. The repair is complete, so the deletion does not change the node.
7. Build the external system
The external system can be a Kubernetes controller, a script, or an operator who uses kubectl. In every form, it must follow the contract in section 2. A controller must obey these rules:
- Start work only after the release. Watch ExternalRemediationRequests. Start a repair only when
NVSentinelOwnershipReleasedisTrue. - Do each repair one time. A restart of the controller can run the same step again before the controller writes the result. Use the name of the ExternalRemediationRequest as a durable key for an action that must run only once, such as a support ticket.
- Write the result only at the end. Set
ExternalRemediationComplete=Trueonly when the repair is complete. SetFalseonly when the external system stops work on the node. - Change only the
ExternalRemediationCompletecondition. NVSentinel owns all other fields in the ExternalRemediationRequest. A status update replaces the fullconditionslist. Read the ExternalRemediationRequest first, replace or add only theExternalRemediationCompleteentry, and then update the status. - Ignore closed requests. When
status.completionTimeis set, janitor already took the node back. Take no action on the node. - Stop when someone deletes the request. When
metadata.deletionTimestampis set, janitor returns the node to NVSentinel before Kubernetes removes the object. Stop all work on the node when this field appears.
For a reference implementation of rule 4, see the SetExtRRComplete function in tests/helpers/kube.go. It uses the Kubernetes unstructured client, which reads and writes any object as a map. The external system then does not need NVSentinel Go types.
For a full Kubebuilder scaffold of a controller that reconciles a custom resource, see Writing a Drain Plugin.
Troubleshooting
fault-remediation does not create an ExternalRemediationRequest
fault-remediation acts only after fault-quarantine cordons the node and node-drainer drains it. First, make sure that the node shows SchedulingDisabled, and that its dgxc.nvidia.com/nvsentinel-state label is drain-succeeded.
Then search the fault-remediation logs for the reason:
NVSentinelOwnershipReleased stays Unknown
janitor did not release the node. Check these causes in order.
-
janitor is not running.
-
Another operation holds the node. janitor uses a Lease, a small Kubernetes lock object, to allow only one operation on a node at a time. The Lease has the same name as the node. Show which object holds it:
If the output shows a different object, such as a RebootNode or a MaintenanceRequest, janitor waits until that operation completes.
NVSentinelOwnershipReleased is False
Find the name of the ExternalRemediationRequest for the node. The NODE column shows the node of each ExternalRemediationRequest.
Read the conditions:
The node in spec.healthEvent.nodeName does not exist, so janitor did not release a node. This can happen when someone deletes or replaces the node before janitor acts. Delete the ExternalRemediationRequest.
janitor does not take the node back
Read the conditions with the command in the previous case. Then find the value of ExternalRemediationComplete:
Safety: Make sure that the external system stopped all work on the node before you delete the ExternalRemediationRequest. The deletion returns the node to NVSentinel, and NVSentinel can uncordon the node.
The node stays cordoned after janitor takes it back
janitor removes the taint and the label, but fault-quarantine keeps the node cordoned. fault-quarantine uncordons the node only after a health monitor publishes a healthy event. Show the health events that keep the node cordoned:
- If a new ExternalRemediationRequest exists for the node, the fault is still present.
- If the list still contains the check that started the repair, the health monitor did not publish a healthy event yet. The health monitors start again after janitor takes the node back.
- A monitor that runs outside the node, such as kubernetes-object-monitor or csp-health-monitor, can miss its first check after the node returns. ADR-040 lists this as a known limitation. To return the node to service, see Cancelling Break-Fix Workflows.
- A tripped circuit breaker also stops the uncordon. See the circuit breaker runbook.
Appendix: One-shot AI prompt
Paste this prompt into an AI coding agent that has access to your cluster. Replace the bracketed values before you run it.