diff --git a/.changelog/13880.txt b/.changelog/13880.txt new file mode 100644 index 000000000000..31cdaca0fd7c --- /dev/null +++ b/.changelog/13880.txt @@ -0,0 +1,3 @@ +```release-note:bug +namespaces: Fixed a bug that allowed deleting a namespace that contained a CSI volume +``` diff --git a/nomad/state/state_store.go b/nomad/state/state_store.go index 3542e82af4ef..2c5021351ad2 100644 --- a/nomad/state/state_store.go +++ b/nomad/state/state_store.go @@ -2316,6 +2316,11 @@ func (s *StateStore) CSIVolumesByNodeID(ws memdb.WatchSet, prefix, nodeID string func (s *StateStore) CSIVolumesByNamespace(ws memdb.WatchSet, namespace, prefix string) (memdb.ResultIterator, error) { txn := s.db.ReadTxn() + return s.csiVolumesByNamespaceImpl(txn, ws, namespace, prefix) +} + +func (s *StateStore) csiVolumesByNamespaceImpl(txn *txn, ws memdb.WatchSet, namespace, prefix string) (memdb.ResultIterator, error) { + iter, err := txn.Get("csi_volumes", "id_prefix", namespace, prefix) if err != nil { return nil, fmt.Errorf("volume lookup failed: %v", err) @@ -6002,6 +6007,17 @@ func (s *StateStore) DeleteNamespaces(index uint64, names []string) error { } } + vIter, err := s.csiVolumesByNamespaceImpl(txn, nil, name, "") + if err != nil { + return err + } + rawVol := vIter.Next() + if rawVol != nil { + vol := rawVol.(*structs.CSIVolume) + return fmt.Errorf("namespace %q contains at least one CSI volume %q. "+ + "All CSI volumes in namespace must be deleted before it can be deleted", name, vol.ID) + } + // Delete the namespace if err := txn.Delete(TableNamespaces, existing); err != nil { return fmt.Errorf("namespace deletion failed: %v", err)