@@ -13,7 +13,6 @@ import (
13
13
"strings"
14
14
"time"
15
15
16
- "github.com/coreos/go-semver/semver"
17
16
hclog "github.com/hashicorp/go-hclog"
18
17
"github.com/hashicorp/nomad/client/taskenv"
19
18
"github.com/hashicorp/nomad/drivers/shared/eventer"
@@ -39,14 +38,13 @@ const (
39
38
40
39
// Represents an ACPI shutdown request to the VM (emulates pressing a physical power button)
41
40
// Reference: https://en.wikibooks.org/wiki/QEMU/Monitor
41
+ // Use a short file name since socket paths have a maximum length.
42
42
qemuGracefulShutdownMsg = "system_powerdown\n "
43
- qemuMonitorSocketName = "qemu-monitor .sock"
43
+ qemuMonitorSocketName = "qm .sock"
44
44
45
45
// Socket file enabling communication with the Qemu Guest Agent (if enabled and running)
46
- qemuGuestAgentSocketName = "qemu-guest-agent.sock"
47
-
48
- // Maximum socket path length prior to qemu 2.10.1
49
- qemuLegacyMaxMonitorPathLen = 108
46
+ // Use a short file name since socket paths have a maximum length.
47
+ qemuGuestAgentSocketName = "qa.sock"
50
48
51
49
// taskHandleVersion is the version of task handle which this driver sets
52
50
// and understands how to decode driver state
70
68
71
69
versionRegex = regexp .MustCompile (`version (\d[\.\d+]+)` )
72
70
73
- // Prior to qemu 2.10.1, monitor socket paths are truncated to 108 bytes.
74
- // We should consider this if driver.qemu.version is < 2.10.1 and the
75
- // generated monitor path is too long.
76
- //
77
- // Relevant fix is here:
78
- // https://github.com/qemu/qemu/commit/ad9579aaa16d5b385922d49edac2c96c79bcfb6
79
- qemuVersionLongSocketPathFix = semver .New ("2.10.1" )
80
-
81
71
// pluginInfo is the response returned for the PluginInfo RPC
82
72
pluginInfo = & base.PluginInfoResponse {
83
73
Type : base .PluginTypeDriver ,
@@ -307,11 +297,19 @@ func (d *Driver) RecoverTask(handle *drivers.TaskHandle) error {
307
297
308
298
// Try to restore monitor socket path.
309
299
taskDir := filepath .Join (handle .Config .AllocDir , handle .Config .Name )
310
- monitorPath := filepath .Join (taskDir , qemuMonitorSocketName )
311
- if _ , err := os .Stat (monitorPath ); err == nil {
312
- d .logger .Debug ("found existing monitor socket" , "monitor" , monitorPath )
313
- } else {
314
- monitorPath = ""
300
+ possiblePaths := []string {
301
+ filepath .Join (taskDir , qemuMonitorSocketName ),
302
+ // Support restoring tasks that used the old socket name.
303
+ filepath .Join (taskDir , "qemu-monitor.sock" ),
304
+ }
305
+
306
+ var monitorPath string
307
+ for _ , path := range possiblePaths {
308
+ if _ , err := os .Stat (path ); err == nil {
309
+ monitorPath = path
310
+ d .logger .Debug ("found existing monitor socket" , "monitor" , monitorPath )
311
+ break
312
+ }
315
313
}
316
314
317
315
h := & taskHandle {
@@ -468,21 +466,17 @@ func (d *Driver) StartTask(cfg *drivers.TaskConfig) (*drivers.TaskHandle, *drive
468
466
}
469
467
}
470
468
469
+ taskDir := filepath .Join (cfg .AllocDir , cfg .Name )
470
+
471
471
var monitorPath string
472
472
if driverConfig .GracefulShutdown {
473
473
if runtime .GOOS == "windows" {
474
474
return nil , nil , errors .New ("QEMU graceful shutdown is unsupported on the Windows platform" )
475
475
}
476
476
// This socket will be used to manage the virtual machine (for example,
477
477
// to perform graceful shutdowns)
478
- taskDir := filepath .Join (cfg .AllocDir , cfg .Name )
479
- fingerPrint := d .buildFingerprint ()
480
- if fingerPrint .Attributes == nil {
481
- return nil , nil , fmt .Errorf ("unable to get qemu driver version from fingerprinted attributes" )
482
- }
483
- monitorPath , err = d .getMonitorPath (taskDir , fingerPrint )
484
- if err != nil {
485
- d .logger .Debug ("could not get qemu monitor path" , "error" , err )
478
+ monitorPath = filepath .Join (taskDir , qemuMonitorSocketName )
479
+ if err := validateSocketPath (monitorPath ); err != nil {
486
480
return nil , nil , err
487
481
}
488
482
d .logger .Debug ("got monitor path" , "monitorPath" , monitorPath )
@@ -494,8 +488,12 @@ func (d *Driver) StartTask(cfg *drivers.TaskConfig) (*drivers.TaskHandle, *drive
494
488
return nil , nil , errors .New ("QEMU Guest Agent socket is unsupported on the Windows platform" )
495
489
}
496
490
// This socket will be used to communicate with the Guest Agent (if it's running)
497
- taskDir := filepath .Join (cfg .AllocDir , cfg .Name )
498
- args = append (args , "-chardev" , fmt .Sprintf ("socket,path=%s/%s,server,nowait,id=qga0" , taskDir , qemuGuestAgentSocketName ))
491
+ agentSocketPath := filepath .Join (taskDir , qemuGuestAgentSocketName )
492
+ if err := validateSocketPath (agentSocketPath ); err != nil {
493
+ return nil , nil , err
494
+ }
495
+
496
+ args = append (args , "-chardev" , fmt .Sprintf ("socket,path=%s,server,nowait,id=qga0" , agentSocketPath ))
499
497
args = append (args , "-device" , "virtio-serial" )
500
498
args = append (args , "-device" , "virtserialport,chardev=qga0,name=org.qemu.guest_agent.0" )
501
499
}
@@ -647,6 +645,8 @@ func (d *Driver) StopTask(taskID string, timeout time.Duration, signal string) e
647
645
if err := sendQemuShutdown (d .logger , handle .monitorPath , handle .pid ); err != nil {
648
646
d .logger .Debug ("error sending graceful shutdown " , "pid" , handle .pid , "error" , err )
649
647
}
648
+ } else {
649
+ d .logger .Debug ("monitor socket is empty, forcing shutdown" )
650
650
}
651
651
652
652
// TODO(preetha) we are calling shutdown on the executor here
@@ -748,27 +748,16 @@ func (d *Driver) handleWait(ctx context.Context, handle *taskHandle, ch chan *dr
748
748
}
749
749
}
750
750
751
- // getMonitorPath is used to determine whether a qemu monitor socket can be
752
- // safely created and accessed in the task directory by the version of qemu
753
- // present on the host. If it is safe to use, the socket's full path is
754
- // returned along with a nil error. Otherwise, an empty string is returned
755
- // along with a descriptive error.
756
- func (d * Driver ) getMonitorPath (dir string , fingerPrint * drivers.Fingerprint ) (string , error ) {
757
- var longPathSupport bool
758
- currentQemuVer := fingerPrint .Attributes [driverVersionAttr ]
759
- currentQemuSemver := semver .New (currentQemuVer .GoString ())
760
- if currentQemuSemver .LessThan (* qemuVersionLongSocketPathFix ) {
761
- longPathSupport = false
762
- d .logger .Debug ("long socket paths are not available in this version of QEMU" , "version" , currentQemuVer )
763
- } else {
764
- longPathSupport = true
765
- d .logger .Debug ("long socket paths available in this version of QEMU" , "version" , currentQemuVer )
766
- }
767
- fullSocketPath := fmt .Sprintf ("%s/%s" , dir , qemuMonitorSocketName )
768
- if len (fullSocketPath ) > qemuLegacyMaxMonitorPathLen && ! longPathSupport {
769
- return "" , fmt .Errorf ("monitor path is too long for this version of qemu" )
751
+ // validateSocketPath provides best effort validation of socket paths since
752
+ // some rules may be platform-dependant.
753
+ func validateSocketPath (path string ) error {
754
+ if maxSocketPathLen > 0 && len (path ) > maxSocketPathLen {
755
+ return fmt .Errorf (
756
+ "socket path %s is longer than the maximum length allowed (%d), try to reduce the task name or Nomad's data_dir if possible." ,
757
+ path , maxSocketPathLen )
770
758
}
771
- return fullSocketPath , nil
759
+
760
+ return nil
772
761
}
773
762
774
763
// sendQemuShutdown attempts to issue an ACPI power-off command via the qemu
0 commit comments