I’ve been implementing a custom task driver to run VMs on macOS and I wanted to make sure that you could click the ‘exec’ button from within the Nomad UI and run a quick command line invocation on that target VM.
I’ve found the docs Task Driver Plugins | Nomad | HashiCorp Developer that simply state that you should be able to implement that interface, and set your capabilities correctly, and it just works.
However, I can’t seem to get it to work at all…
My driver implementation returns the “Exec” capability, and has this implementation for the ExecTask function
// ExecTask returns the result of executing the given command inside a task.
func (d *Driver) ExecTask(taskID string, cmd []string, timeout time.Duration) (*drivers.ExecTaskResult, error) {
d.logger.Info("executing command inside task", "task_id", taskID, "cmd", cmd)
handle, ok := d.tasks.Get(taskID)
if !ok {
return nil, drivers.ErrTaskNotFound
}
var taskConfig TaskConfig
if err := handle.taskConfig.DecodeDriverConfig(&taskConfig); err != nil {
return nil, fmt.Errorf("failed to decode driver config: %v", err)
}
allocVMName := d.generateVMName(handle.taskConfig.AllocID)
output, stderr, err := d.virtualizer.SSH(d.ctx, allocVMName, taskConfig.SSHUser, taskConfig.SSHPassword, strings.Join(cmd, " "))
if err != nil {
return nil, fmt.Errorf("failed to execute SSH command on VM %s: %v (stderr: %s)",
allocVMName, err, stderr)
}
return &drivers.ExecTaskResult{
Stdout: []byte(output),
Stderr: []byte(stderr),
ExitResult: &drivers.ExitResult{
ExitCode: 0,
},
}, nil
}
Whenever I run something like nomad alloc exec 13867d0b-07c4-3bfc-0781-3f0f46be9cea /bin/echo "test"
I always get failed to exec into task: rpc error: code = Unknown desc = driver does not support exec
. The server logs seem to indicate that my ExecTask
function is never called:
2025-06-07T23:29:15.029-0400 [DEBUG] http: request complete: method=GET path=/v1/allocations?prefix=13867d0b-07c4-3bfc-0781-3f0f46be9cea duration="154.208µs"
2025-06-07T23:29:15.030-0400 [DEBUG] http: request complete: method=GET path=/v1/allocation/13867d0b-07c4-3bfc-0781-3f0f46be9cea?namespace=default duration="144.584µs"
2025-06-07T23:29:15.031-0400 [DEBUG] http: request complete: method=GET path=/v1/node/25c3fdd0-9ba7-2fef-ab52-cd83a761ac82 duration="109.542µs"
2025-06-07T23:29:15.032-0400 [INFO] client: task exec session starting: exec_id=0dee9712-73b8-4f76-08ed-2e120c04bec4 alloc_id=13867d0b-07c4-3bfc-0781-3f0f46be9cea task=vm command=["/bin/echo", "test"] tty=true action=""
2025-06-07T23:29:15.033-0400 [INFO] client.driver_mgr.nomad-driver-tart: CAPABILITIES DEBUG: driver=tart @module=tart exec=true send_signals=false timestamp=2025-06-07T23:29:15.033-0400
2025-06-07T23:29:15.033-0400 [INFO] client: task exec session ended with an error: error="rpc error: code = Unknown desc = driver does not support exec" code=0x14000559da8
2025-06-07T23:29:15.033-0400 [ERROR] http: request failed: method=GET path="/v1/client/allocation/13867d0b-07c4-3bfc-0781-3f0f46be9cea/exec?command=%5B%22%2Fbin%2Fecho%22%2C%22test%22%5D®ion=global&task=vm&tty=true" error="rpc error: code = Unknown desc = driver does not support exec" code=500
2025-06-07T23:29:15.033-0400 [DEBUG] http: request complete: method=GET path="/v1/client/allocation/13867d0b-07c4-3bfc-0781-3f0f46be9cea/exec?command=%5B%22%2Fbin%2Fecho%22%2C%22test%22%5D®ion=global&task=vm&tty=true" duration="655.208µs"
At this point I’m just scratching my head as to what I have to implement to get this working in a very minimal way. I’d love advice!