diff --git a/drivers/qemu/driver.go b/drivers/qemu/driver.go index 37066184c..fde8db8e1 100644 --- a/drivers/qemu/driver.go +++ b/drivers/qemu/driver.go @@ -12,7 +12,6 @@ import ( "time" "net" - "strconv" "github.com/coreos/go-semver/semver" "github.com/hashicorp/go-hclog" @@ -42,11 +41,11 @@ const ( // Represents an ACPI shutdown request to the VM (emulates pressing a physical power button) // Reference: https://en.wikibooks.org/wiki/QEMU/Monitor - gracefulShutdownMsg = "system_powerdown\n" - monitorSocketName = "qemu-monitor.sock" + qemuGracefulShutdownMsg = "system_powerdown\n" + qemuMonitorSocketName = "qemu-monitor.sock" // Maximum socket path length prior to qemu 2.10.1 - legacyMaxMonitorPathLen = 108 + qemuLegacyMaxMonitorPathLen = 108 ) var ( @@ -72,7 +71,7 @@ var ( // // Relevant fix is here: // https://github.com/qemu/qemu/commit/ad9579aaa16d5b385922d49edac2c96c79bcfb6 - versionLongSocketPathFix = semver.New("2.10.1") + qemuVersionLongSocketPathFix = semver.New("2.10.1") // pluginInfo is the response returned for the PluginInfo RPC pluginInfo = &base.PluginInfoResponse{ @@ -184,9 +183,9 @@ func (d *Driver) Capabilities() (*drivers.Capabilities, error) { return capabilities, nil } -func (r *Driver) Fingerprint(ctx context.Context) (<-chan *drivers.Fingerprint, error) { +func (d *Driver) Fingerprint(ctx context.Context) (<-chan *drivers.Fingerprint, error) { ch := make(chan *drivers.Fingerprint) - go r.handleFingerprint(ctx, ch) + go d.handleFingerprint(ctx, ch) return ch, nil } @@ -267,7 +266,7 @@ func (d *Driver) RecoverTask(handle *drivers.TaskHandle) error { return fmt.Errorf("failed to reattach to executor: %v", err) } - h := &qemuTaskHandle{ + h := &taskHandle{ exec: execImpl, pid: taskState.Pid, pluginClient: pluginClient, @@ -431,7 +430,7 @@ func (d *Driver) StartTask(cfg *drivers.TaskConfig) (*drivers.TaskHandle, *cstru } d.logger.Debug("started new QemuVM", "ID", vmID) - h := &qemuTaskHandle{ + h := &taskHandle{ exec: execImpl, pid: ps.Pid, monitorPath: monitorPath, @@ -536,22 +535,7 @@ func (d *Driver) InspectTask(taskID string) (*drivers.TaskStatus, error) { return nil, drivers.ErrTaskNotFound } - handle.stateLock.RLock() - defer handle.stateLock.RUnlock() - - status := &drivers.TaskStatus{ - ID: handle.taskConfig.ID, - Name: handle.taskConfig.Name, - State: handle.procState, - StartedAt: handle.startedAt, - CompletedAt: handle.completedAt, - ExitResult: handle.exitResult, - DriverAttributes: map[string]string{ - "pid": strconv.Itoa(handle.pid), - }, - } - - return status, nil + return handle.TaskStatus(), nil } func (d *Driver) TaskStats(taskID string) (*cstructs.TaskResourceUsage, error) { @@ -587,7 +571,7 @@ func GetAbsolutePath(bin string) (string, error) { return filepath.EvalSymlinks(lp) } -func (d *Driver) handleWait(ctx context.Context, handle *qemuTaskHandle, ch chan *drivers.ExitResult) { +func (d *Driver) handleWait(ctx context.Context, handle *taskHandle, ch chan *drivers.ExitResult) { defer close(ch) var result *drivers.ExitResult ps, err := handle.exec.Wait() @@ -618,15 +602,15 @@ func (d *Driver) getMonitorPath(dir string, fingerPrint *drivers.Fingerprint) (s var longPathSupport bool currentQemuVer := fingerPrint.Attributes[driverVersionAttr] currentQemuSemver := semver.New(currentQemuVer) - if currentQemuSemver.LessThan(*versionLongSocketPathFix) { + if currentQemuSemver.LessThan(*qemuVersionLongSocketPathFix) { longPathSupport = false d.logger.Debug("long socket paths are not available in this version of QEMU", "version", currentQemuVer) } else { longPathSupport = true d.logger.Debug("long socket paths available in this version of QEMU", "version", currentQemuVer) } - fullSocketPath := fmt.Sprintf("%s/%s", dir, monitorSocketName) - if len(fullSocketPath) > legacyMaxMonitorPathLen && longPathSupport == false { + fullSocketPath := fmt.Sprintf("%s/%s", dir, qemuMonitorSocketName) + if len(fullSocketPath) > qemuLegacyMaxMonitorPathLen && longPathSupport == false { return "", fmt.Errorf("monitor path is too long for this version of qemu") } return fullSocketPath, nil @@ -645,9 +629,9 @@ func sendQemuShutdown(logger hclog.Logger, monitorPath string, userPid int) erro } defer monitorSocket.Close() logger.Debug("sending graceful shutdown command to qemu monitor socket", "monitor_path", monitorPath, "pid", userPid) - _, err = monitorSocket.Write([]byte(gracefulShutdownMsg)) + _, err = monitorSocket.Write([]byte(qemuGracefulShutdownMsg)) if err != nil { - logger.Warn("failed to send shutdown message", "shutdown message", gracefulShutdownMsg, "monitorPath", monitorPath, "userPid", userPid, "error", err) + logger.Warn("failed to send shutdown message", "shutdown message", qemuGracefulShutdownMsg, "monitorPath", monitorPath, "userPid", userPid, "error", err) } return err } diff --git a/drivers/qemu/driver_test.go b/drivers/qemu/driver_test.go index 62b48f612..fab7b1264 100644 --- a/drivers/qemu/driver_test.go +++ b/drivers/qemu/driver_test.go @@ -124,12 +124,12 @@ func TestQemuDriver_GetMonitorPathOldQemu(t *testing.T) { _, err := qemuDriver.getMonitorPath(shortPath, fingerPrint) require.Nil(err) - longPath := strings.Repeat("x", legacyMaxMonitorPathLen+100) + longPath := strings.Repeat("x", qemuLegacyMaxMonitorPathLen+100) _, err = qemuDriver.getMonitorPath(longPath, fingerPrint) require.NotNil(err) // Max length includes the '/' separator and socket name - maxLengthCount := legacyMaxMonitorPathLen - len(monitorSocketName) - 1 + maxLengthCount := qemuLegacyMaxMonitorPathLen - len(qemuMonitorSocketName) - 1 maxLengthLegacyPath := strings.Repeat("x", maxLengthCount) _, err = qemuDriver.getMonitorPath(maxLengthLegacyPath, fingerPrint) require.Nil(err) @@ -176,12 +176,12 @@ func TestQemuDriver_GetMonitorPathNewQemu(t *testing.T) { require.Nil(err) // Should not return an error in this qemu version - longPath := strings.Repeat("x", legacyMaxMonitorPathLen+100) + longPath := strings.Repeat("x", qemuLegacyMaxMonitorPathLen+100) _, err = qemuDriver.getMonitorPath(longPath, fingerPrint) require.Nil(err) // Max length includes the '/' separator and socket name - maxLengthCount := legacyMaxMonitorPathLen - len(monitorSocketName) - 1 + maxLengthCount := qemuLegacyMaxMonitorPathLen - len(qemuMonitorSocketName) - 1 maxLengthLegacyPath := strings.Repeat("x", maxLengthCount) _, err = qemuDriver.getMonitorPath(maxLengthLegacyPath, fingerPrint) require.Nil(err) diff --git a/drivers/qemu/handle.go b/drivers/qemu/handle.go index 9bb02de14..0e8cc73ca 100644 --- a/drivers/qemu/handle.go +++ b/drivers/qemu/handle.go @@ -1,6 +1,7 @@ package qemu import ( + "strconv" "sync" "time" @@ -10,7 +11,7 @@ import ( "github.com/hashicorp/nomad/plugins/drivers" ) -type qemuTaskHandle struct { +type taskHandle struct { exec executor.Executor pid int pluginClient *plugin.Client @@ -27,17 +28,30 @@ type qemuTaskHandle struct { exitResult *drivers.ExitResult } -func (h *qemuTaskHandle) IsRunning() bool { +func (h *taskHandle) TaskStatus() *drivers.TaskStatus { + h.stateLock.RLock() + defer h.stateLock.RUnlock() + + return &drivers.TaskStatus{ + ID: h.taskConfig.ID, + Name: h.taskConfig.Name, + State: h.procState, + StartedAt: h.startedAt, + CompletedAt: h.completedAt, + ExitResult: h.exitResult, + DriverAttributes: map[string]string{ + "pid": strconv.Itoa(h.pid), + }, + } +} + +func (h *taskHandle) IsRunning() bool { h.stateLock.RLock() defer h.stateLock.RUnlock() return h.procState == drivers.TaskStateRunning } -func (h *qemuTaskHandle) run() { - - // Since run is called immediately after the handle is created this - // ensures the exitResult is initialized so we avoid a nil pointer - // thus it does not need to be included in the lock +func (h *taskHandle) run() { h.stateLock.Lock() if h.exitResult == nil { h.exitResult = &drivers.ExitResult{} diff --git a/drivers/qemu/state.go b/drivers/qemu/state.go index fd33f8ed7..dc809ef48 100644 --- a/drivers/qemu/state.go +++ b/drivers/qemu/state.go @@ -5,21 +5,21 @@ import ( ) type taskStore struct { - store map[string]*qemuTaskHandle + store map[string]*taskHandle lock sync.RWMutex } func newTaskStore() *taskStore { - return &taskStore{store: map[string]*qemuTaskHandle{}} + return &taskStore{store: map[string]*taskHandle{}} } -func (ts *taskStore) Set(id string, handle *qemuTaskHandle) { +func (ts *taskStore) Set(id string, handle *taskHandle) { ts.lock.Lock() defer ts.lock.Unlock() ts.store[id] = handle } -func (ts *taskStore) Get(id string) (*qemuTaskHandle, bool) { +func (ts *taskStore) Get(id string) (*taskHandle, bool) { ts.lock.RLock() defer ts.lock.RUnlock() t, ok := ts.store[id]