Ensure CSINode is owned by node when installing CSI drivers

CSI drivers can be installed while the node is still initializing since the daemonsets usually tolerate all taints. As a result, we also need to make sure the outdated CSINode object has been removed before installing a new CSI driver.
This commit is contained in:
Baptiste Girard-Carrabin
2025-10-07 11:00:55 +02:00
parent 328f9da729
commit cb01a28df4
2 changed files with 52 additions and 8 deletions

View File

@@ -403,6 +403,10 @@ func (nim *nodeInfoManager) tryUpdateCSINode(
return err
}
if err = nim.ensureNodeOwnsCSINode(nodeInfo); err != nil {
return err
}
return nim.installDriverToCSINode(nodeInfo, driverName, driverNodeID, maxAttachLimit, topology)
}
@@ -446,14 +450,8 @@ func (nim *nodeInfoManager) tryInitializeCSINodeWithAnnotation(csiKubeClient cli
return err
}
if ok, csiNodeOwnerID := nim.nodeOwnsCSINode(nodeInfo); !ok {
klog.V(2).Infof("existing CSINode %q is owned by different node (oldNodeID=%q, newNodeID=%q), cleaning up...", nodeInfo.Name, csiNodeOwnerID, nim.nodeID)
err = nim.DeleteCSINode()
if err != nil {
return fmt.Errorf("error deleting existing CSINode %q: %w", nodeInfo.Name, err)
}
// Returning now so that the next attempt can create a new CSINode object
return fmt.Errorf("CSINode %q was owned by different node (oldNodeID=%q, newNodeID=%q), deleted it", nodeInfo.Name, csiNodeOwnerID, nim.nodeID)
if err = nim.ensureNodeOwnsCSINode(nodeInfo); err != nil {
return err
}
annotationModified := setMigrationAnnotation(nim.migratedPlugins, nodeInfo)
@@ -466,6 +464,21 @@ func (nim *nodeInfoManager) tryInitializeCSINodeWithAnnotation(csiKubeClient cli
}
// ensureNodeOwnsCSINode will ensure that the current CSINode object is owned by the node represented by this nodeInfoManager.
// If not, it will delete the existing CSINode object and return an error.
func (nim *nodeInfoManager) ensureNodeOwnsCSINode(nodeInfo *storagev1.CSINode) error {
if ok, csiNodeOwnerID := nim.nodeOwnsCSINode(nodeInfo); !ok {
klog.V(2).Infof("existing CSINode %q is owned by different node (oldNodeID=%q, newNodeID=%q), cleaning up...", nodeInfo.Name, csiNodeOwnerID, nim.nodeID)
err := nim.DeleteCSINode()
if err != nil {
return fmt.Errorf("error deleting existing CSINode %q: %w", nodeInfo.Name, err)
}
// Returning now so that the next attempt can create a new CSINode object
return fmt.Errorf("CSINode %q was owned by different node (oldNodeID=%q, newNodeID=%q), deleted it", nodeInfo.Name, csiNodeOwnerID, nim.nodeID)
}
return nil
}
// nodeOwnsCSINode checks if the CSINode object is owned by the node represented by this nodeInfoManager.
// It also returns the current owner UID.
func (nim *nodeInfoManager) nodeOwnsCSINode(nodeInfo *storagev1.CSINode) (bool, types.UID) {

View File

@@ -307,6 +307,37 @@ func TestInstallCSIDriver(t *testing.T) {
},
},
},
{
name: "pre-existing node info, but owned by previous node",
existingNode: func() *v1.Node {
node := generateNode(nil /*nodeIDs*/, nil /*labels*/, nil /*capacity*/)
node.UID = types.UID("node1")
return node
}(),
existingCSINode: func() *storage.CSINode {
csiNode := generateCSINode(nil /*nodeIDs*/, nil /*volumeLimits*/, nil /*topologyKeys*/)
csiNode.OwnerReferences[0].UID = types.UID("node2")
return csiNode
}(),
inputNodeID: "com.example.csi/csi-node1",
expectedNode: &v1.Node{
ObjectMeta: metav1.ObjectMeta{
Name: "node1",
UID: types.UID("node1"),
Annotations: map[string]string{annotationKeyNodeID: marshall(nodeIDMap{"": "com.example.csi/csi-node1"})},
},
},
expectedCSINode: &storage.CSINode{
ObjectMeta: getCSINodeObjectMeta(),
Spec: storage.CSINodeSpec{
Drivers: []storage.CSINodeDriver{
{
NodeID: "com.example.csi/csi-node1",
},
},
},
},
},
{
name: "nil topology, empty node",
driverName: "com.example.csi.driver1",