mirror of
https://github.com/kemko/nomad.git
synced 2026-01-02 00:15:43 +03:00
CSI volumes are namespaced. But the client does not include the namespace in the staging mount path. This causes CSI volumes with the same volume ID but different namespace to collide if they happen to be placed on the same host. The per-allocation paths don't need to be namespaced, because an allocation can only mount volumes from its job's own namespace. Rework the CSI hook tests to have more fine-grained control over the mock on-disk state. Add tests covering upgrades from staging paths missing namespaces. Fixes: https://github.com/hashicorp/nomad/issues/18741
74 lines
1.8 KiB
Go
74 lines
1.8 KiB
Go
// Copyright (c) HashiCorp, Inc.
|
|
// SPDX-License-Identifier: BUSL-1.1
|
|
|
|
package csimanager
|
|
|
|
import (
|
|
"sync"
|
|
)
|
|
|
|
// volumeUsageTracker tracks the allocations that depend on a given volume
|
|
type volumeUsageTracker struct {
|
|
// state is a map of volumeUsageKey to a slice of allocation ids
|
|
state map[volumeUsageKey][]string
|
|
stateMu sync.Mutex
|
|
}
|
|
|
|
func newVolumeUsageTracker() *volumeUsageTracker {
|
|
return &volumeUsageTracker{
|
|
state: make(map[volumeUsageKey][]string),
|
|
}
|
|
}
|
|
|
|
type volumeUsageKey struct {
|
|
id string
|
|
ns string
|
|
usageOpts UsageOptions
|
|
}
|
|
|
|
func (v *volumeUsageTracker) allocsForKey(key volumeUsageKey) []string {
|
|
return v.state[key]
|
|
}
|
|
|
|
func (v *volumeUsageTracker) appendAlloc(key volumeUsageKey, allocID string) {
|
|
allocs := v.allocsForKey(key)
|
|
allocs = append(allocs, allocID)
|
|
v.state[key] = allocs
|
|
}
|
|
|
|
func (v *volumeUsageTracker) removeAlloc(key volumeUsageKey, needle string) {
|
|
allocs := v.allocsForKey(key)
|
|
var newAllocs []string
|
|
for _, allocID := range allocs {
|
|
if allocID != needle {
|
|
newAllocs = append(newAllocs, allocID)
|
|
}
|
|
}
|
|
|
|
if len(newAllocs) == 0 {
|
|
delete(v.state, key)
|
|
} else {
|
|
v.state[key] = newAllocs
|
|
}
|
|
}
|
|
|
|
func (v *volumeUsageTracker) Claim(allocID, volID, volNS string, usage *UsageOptions) {
|
|
v.stateMu.Lock()
|
|
defer v.stateMu.Unlock()
|
|
|
|
key := volumeUsageKey{id: volID, ns: volNS, usageOpts: *usage}
|
|
v.appendAlloc(key, allocID)
|
|
}
|
|
|
|
// Free removes the allocation from the state list for the given alloc. If the
|
|
// alloc is the last allocation for the volume then it returns true.
|
|
func (v *volumeUsageTracker) Free(allocID, volID, volNS string, usage *UsageOptions) bool {
|
|
v.stateMu.Lock()
|
|
defer v.stateMu.Unlock()
|
|
|
|
key := volumeUsageKey{id: volID, ns: volNS, usageOpts: *usage}
|
|
v.removeAlloc(key, allocID)
|
|
allocs := v.allocsForKey(key)
|
|
return len(allocs) == 0
|
|
}
|