Allow per_alloc to be used with host volumes (#15780)

Disallowing per_alloc for host volumes in some cases makes life of a nomad user much harder.
When we rely on the NOMAD_ALLOC_INDEX for any configuration that needs to be re-used across
restarts we need to make sure allocation placement is consistent. With CSI volumes we can
use the `per_alloc` feature but for some reason this is explicitly disabled for host volumes.

Ensure host volumes understand the concept of per_alloc
This commit is contained in:
Yorick Gersie
2023-01-26 15:14:47 +01:00
committed by GitHub
parent 0abadb6804
commit 24a575ab80
11 changed files with 66 additions and 28 deletions

View File

@@ -208,6 +208,8 @@ func (tr *TaskRunner) prestart() error {
joinedCtx, joinedCancel := joincontext.Join(tr.killCtx, tr.shutdownCtx)
defer joinedCancel()
alloc := tr.Alloc()
for _, hook := range tr.runnerHooks {
pre, ok := hook.(interfaces.TaskPrestartHook)
if !ok {
@@ -218,6 +220,7 @@ func (tr *TaskRunner) prestart() error {
// Build the request
req := interfaces.TaskPrestartRequest{
Alloc: alloc,
Task: tr.Task(),
TaskDir: tr.taskDir,
TaskEnv: tr.envBuilder.Build(),

View File

@@ -32,7 +32,7 @@ func (*volumeHook) Name() string {
return "volumes"
}
func validateHostVolumes(requestedByAlias map[string]*structs.VolumeRequest, clientVolumesByName map[string]*structs.ClientHostVolumeConfig) error {
func validateHostVolumes(requestedByAlias map[string]*structs.VolumeRequest, clientVolumesByName map[string]*structs.ClientHostVolumeConfig, allocName string) error {
var result error
for _, req := range requestedByAlias {
@@ -42,9 +42,14 @@ func validateHostVolumes(requestedByAlias map[string]*structs.VolumeRequest, cli
continue
}
_, ok := clientVolumesByName[req.Source]
source := req.Source
if req.PerAlloc {
source = source + structs.AllocSuffix(allocName)
}
_, ok := clientVolumesByName[source]
if !ok {
result = multierror.Append(result, fmt.Errorf("missing %s", req.Source))
result = multierror.Append(result, fmt.Errorf("missing %s", source))
}
}
@@ -54,7 +59,7 @@ func validateHostVolumes(requestedByAlias map[string]*structs.VolumeRequest, cli
// hostVolumeMountConfigurations takes the users requested volume mounts,
// volumes, and the client host volume configuration and converts them into a
// format that can be used by drivers.
func (h *volumeHook) hostVolumeMountConfigurations(taskMounts []*structs.VolumeMount, taskVolumesByAlias map[string]*structs.VolumeRequest, clientVolumesByName map[string]*structs.ClientHostVolumeConfig) ([]*drivers.MountConfig, error) {
func (h *volumeHook) hostVolumeMountConfigurations(taskMounts []*structs.VolumeMount, taskVolumesByAlias map[string]*structs.VolumeRequest, clientVolumesByName map[string]*structs.ClientHostVolumeConfig, allocName string) ([]*drivers.MountConfig, error) {
var mounts []*drivers.MountConfig
for _, m := range taskMounts {
req, ok := taskVolumesByAlias[m.Volume]
@@ -71,11 +76,15 @@ func (h *volumeHook) hostVolumeMountConfigurations(taskMounts []*structs.VolumeM
continue
}
hostVolume, ok := clientVolumesByName[req.Source]
source := req.Source
if req.PerAlloc {
source = source + structs.AllocSuffix(allocName)
}
hostVolume, ok := clientVolumesByName[source]
if !ok {
// Should never happen, but unless the client volumes were mutated during
// the execution of this hook.
return nil, fmt.Errorf("No host volume named: %s", req.Source)
return nil, fmt.Errorf("no host volume named: %s", source)
}
mcfg := &drivers.MountConfig{
@@ -110,12 +119,12 @@ func (h *volumeHook) prepareHostVolumes(req *interfaces.TaskPrestartRequest, vol
// Always validate volumes to ensure that we do not allow volumes to be used
// if a host is restarted and loses the host volume configuration.
if err := validateHostVolumes(volumes, hostVolumes); err != nil {
if err := validateHostVolumes(volumes, hostVolumes, req.Alloc.Name); err != nil {
h.logger.Error("Requested Host Volume does not exist", "existing", hostVolumes, "requested", volumes)
return nil, fmt.Errorf("host volume validation error: %v", err)
}
hostVolumeMounts, err := h.hostVolumeMountConfigurations(req.Task.VolumeMounts, volumes, hostVolumes)
hostVolumeMounts, err := h.hostVolumeMountConfigurations(req.Task.VolumeMounts, volumes, hostVolumes, req.Alloc.Name)
if err != nil {
h.logger.Error("Failed to generate host volume mounts", "error", err)
return nil, err