diff --git a/vendor.conf b/vendor.conf index 2cc7a785dd..2c80dbdac6 100644 --- a/vendor.conf +++ b/vendor.conf @@ -1,6 +1,6 @@ # the following lines are in sorted order, FYI github.com/Azure/go-ansiterm d6e3b3328b783f23731bc4d058875b0371ff8109 -github.com/Microsoft/hcsshim 44c060121b68e8bdc40b411beba551f3b4ee9e55 +github.com/Microsoft/hcsshim v0.7.3 github.com/Microsoft/go-winio v0.4.11 github.com/docker/libtrust 9cbd2a1374f46905c68a4eb3694a130610adc62a github.com/go-check/check 4ed411733c5785b40214c70bce814c3a3a689609 https://github.com/cpuguy83/check.git diff --git a/vendor/github.com/Microsoft/hcsshim/internal/guid/guid.go b/vendor/github.com/Microsoft/hcsshim/internal/guid/guid.go index c37dec8c7b..e9e45c0306 100644 --- a/vendor/github.com/Microsoft/hcsshim/internal/guid/guid.go +++ b/vendor/github.com/Microsoft/hcsshim/internal/guid/guid.go @@ -2,10 +2,16 @@ package guid import ( "crypto/rand" + "encoding/json" "fmt" "io" + "strconv" + "strings" ) +var _ = (json.Marshaler)(&GUID{}) +var _ = (json.Unmarshaler)(&GUID{}) + type GUID [16]byte func New() GUID { @@ -20,3 +26,44 @@ func New() GUID { func (g GUID) String() string { return fmt.Sprintf("%02x%02x%02x%02x-%02x%02x-%02x%02x-%02x-%02x", g[3], g[2], g[1], g[0], g[5], g[4], g[7], g[6], g[8:10], g[10:]) } + +func FromString(s string) GUID { + if len(s) != 36 { + panic(fmt.Sprintf("invalid GUID length: %d", len(s))) + } + if s[8] != '-' || s[13] != '-' || s[18] != '-' || s[23] != '-' { + panic("invalid GUID format") + } + indexOrder := [16]int{ + 0, 2, 4, 6, + 9, 11, + 14, 16, + 19, 21, + 24, 26, 28, 30, 32, 34, + } + byteOrder := [16]int{ + 3, 2, 1, 0, + 5, 4, + 7, 6, + 8, 9, + 10, 11, 12, 13, 14, 15, + } + var g GUID + for i, x := range indexOrder { + b, err := strconv.ParseInt(s[x:x+2], 16, 16) + if err != nil { + panic(err) + } + g[byteOrder[i]] = byte(b) + } + return g +} + +func (g GUID) MarshalJSON() ([]byte, error) { + return json.Marshal(g.String()) +} + +func (g *GUID) UnmarshalJSON(data []byte) error { + *g = FromString(strings.Trim(string(data), "\"")) + return nil +} diff --git a/vendor/github.com/Microsoft/hcsshim/internal/hcs/process.go b/vendor/github.com/Microsoft/hcsshim/internal/hcs/process.go index 0de4a706aa..8294d66d7b 100644 --- a/vendor/github.com/Microsoft/hcsshim/internal/hcs/process.go +++ b/vendor/github.com/Microsoft/hcsshim/internal/hcs/process.go @@ -2,6 +2,7 @@ package hcs import ( "encoding/json" + "fmt" "io" "sync" "syscall" @@ -83,7 +84,10 @@ func (process *Process) Kill() error { } var resultp *uint16 + completed := false + go syscallWatcher(fmt.Sprintf("TerminateProcess %s: %d", process.SystemID(), process.Pid()), &completed) err := hcsTerminateProcess(process.handle, &resultp) + completed = true events := processHcsResult(resultp) if err != nil { return makeProcessError(process, operation, err, events) @@ -177,7 +181,10 @@ func (process *Process) Properties() (*ProcessStatus, error) { resultp *uint16 propertiesp *uint16 ) + completed := false + go syscallWatcher(fmt.Sprintf("GetProcessProperties %s: %d", process.SystemID(), process.Pid()), &completed) err := hcsGetProcessProperties(process.handle, &propertiesp, &resultp) + completed = true events := processHcsResult(resultp) if err != nil { return nil, makeProcessError(process, operation, err, events) diff --git a/vendor/github.com/Microsoft/hcsshim/internal/hcs/system.go b/vendor/github.com/Microsoft/hcsshim/internal/hcs/system.go index 41ff2877b5..57afd5ec6b 100644 --- a/vendor/github.com/Microsoft/hcsshim/internal/hcs/system.go +++ b/vendor/github.com/Microsoft/hcsshim/internal/hcs/system.go @@ -2,6 +2,7 @@ package hcs import ( "encoding/json" + "fmt" "os" "strconv" "sync" @@ -63,7 +64,10 @@ func CreateComputeSystem(id string, hcsDocumentInterface interface{}) (*System, resultp *uint16 identity syscall.Handle ) + completed := false + go syscallWatcher(fmt.Sprintf("CreateCompleteSystem %s: %s", id, hcsDocument), &completed) createError := hcsCreateComputeSystem(id, hcsDocument, identity, &computeSystem.handle, &resultp) + completed = true if createError == nil || IsPending(createError) { if err := computeSystem.registerCallback(); err != nil { @@ -74,7 +78,7 @@ func CreateComputeSystem(id string, hcsDocumentInterface interface{}) (*System, } } - events, err := processAsyncHcsResult(createError, resultp, computeSystem.callbackNumber, hcsNotificationSystemCreateCompleted, &timeout.Duration) + events, err := processAsyncHcsResult(createError, resultp, computeSystem.callbackNumber, hcsNotificationSystemCreateCompleted, &timeout.SystemCreate) if err != nil { if err == ErrTimeout { // Terminate the compute system if it still exists. We're okay to @@ -135,7 +139,10 @@ func GetComputeSystems(q schema1.ComputeSystemQuery) ([]schema1.ContainerPropert resultp *uint16 computeSystemsp *uint16 ) + completed := false + go syscallWatcher(fmt.Sprintf("GetComputeSystems %s:", query), &completed) err = hcsEnumerateComputeSystems(query, &computeSystemsp, &resultp) + completed = true events := processHcsResult(resultp) if err != nil { return nil, &HcsError{Op: operation, Err: err, Events: events} @@ -192,8 +199,11 @@ func (computeSystem *System) Start() error { } var resultp *uint16 + completed := false + go syscallWatcher(fmt.Sprintf("StartComputeSystem %s:", computeSystem.ID()), &completed) err := hcsStartComputeSystem(computeSystem.handle, "", &resultp) - events, err := processAsyncHcsResult(err, resultp, computeSystem.callbackNumber, hcsNotificationSystemStartCompleted, &timeout.Duration) + completed = true + events, err := processAsyncHcsResult(err, resultp, computeSystem.callbackNumber, hcsNotificationSystemStartCompleted, &timeout.SystemStart) if err != nil { return makeSystemError(computeSystem, "Start", "", err, events) } @@ -219,7 +229,10 @@ func (computeSystem *System) Shutdown() error { } var resultp *uint16 + completed := false + go syscallWatcher(fmt.Sprintf("ShutdownComputeSystem %s:", computeSystem.ID()), &completed) err := hcsShutdownComputeSystem(computeSystem.handle, "", &resultp) + completed = true events := processHcsResult(resultp) if err != nil { return makeSystemError(computeSystem, "Shutdown", "", err, events) @@ -242,7 +255,10 @@ func (computeSystem *System) Terminate() error { } var resultp *uint16 + completed := false + go syscallWatcher(fmt.Sprintf("TerminateComputeSystem %s:", computeSystem.ID()), &completed) err := hcsTerminateComputeSystem(computeSystem.handle, "", &resultp) + completed = true events := processHcsResult(resultp) if err != nil { return makeSystemError(computeSystem, "Terminate", "", err, events) @@ -291,7 +307,10 @@ func (computeSystem *System) Properties(types ...schema1.PropertyType) (*schema1 } var resultp, propertiesp *uint16 + completed := false + go syscallWatcher(fmt.Sprintf("GetComputeSystemProperties %s:", computeSystem.ID()), &completed) err = hcsGetComputeSystemProperties(computeSystem.handle, string(queryj), &propertiesp, &resultp) + completed = true events := processHcsResult(resultp) if err != nil { return nil, makeSystemError(computeSystem, "Properties", "", err, events) @@ -320,8 +339,11 @@ func (computeSystem *System) Pause() error { } var resultp *uint16 + completed := false + go syscallWatcher(fmt.Sprintf("PauseComputeSystem %s:", computeSystem.ID()), &completed) err := hcsPauseComputeSystem(computeSystem.handle, "", &resultp) - events, err := processAsyncHcsResult(err, resultp, computeSystem.callbackNumber, hcsNotificationSystemPauseCompleted, &timeout.Duration) + completed = true + events, err := processAsyncHcsResult(err, resultp, computeSystem.callbackNumber, hcsNotificationSystemPauseCompleted, &timeout.SystemPause) if err != nil { return makeSystemError(computeSystem, "Pause", "", err, events) } @@ -342,8 +364,11 @@ func (computeSystem *System) Resume() error { } var resultp *uint16 + completed := false + go syscallWatcher(fmt.Sprintf("ResumeComputeSystem %s:", computeSystem.ID()), &completed) err := hcsResumeComputeSystem(computeSystem.handle, "", &resultp) - events, err := processAsyncHcsResult(err, resultp, computeSystem.callbackNumber, hcsNotificationSystemResumeCompleted, &timeout.Duration) + completed = true + events, err := processAsyncHcsResult(err, resultp, computeSystem.callbackNumber, hcsNotificationSystemResumeCompleted, &timeout.SystemResume) if err != nil { return makeSystemError(computeSystem, "Resume", "", err, events) } @@ -375,7 +400,10 @@ func (computeSystem *System) CreateProcess(c interface{}) (*Process, error) { configuration := string(configurationb) logrus.Debugf(title+" config=%s", configuration) + completed := false + go syscallWatcher(fmt.Sprintf("CreateProcess %s: %s", computeSystem.ID(), configuration), &completed) err = hcsCreateProcess(computeSystem.handle, configuration, &processInfo, &processHandle, &resultp) + completed = true events := processHcsResult(resultp) if err != nil { return nil, makeSystemError(computeSystem, "CreateProcess", configuration, err, events) @@ -415,7 +443,10 @@ func (computeSystem *System) OpenProcess(pid int) (*Process, error) { return nil, makeSystemError(computeSystem, "OpenProcess", "", ErrAlreadyClosed, nil) } + completed := false + go syscallWatcher(fmt.Sprintf("OpenProcess %s: %d", computeSystem.ID(), pid), &completed) err := hcsOpenProcess(computeSystem.handle, uint32(pid), &processHandle, &resultp) + completed = true events := processHcsResult(resultp) if err != nil { return nil, makeSystemError(computeSystem, "OpenProcess", "", err, events) @@ -451,7 +482,11 @@ func (computeSystem *System) Close() error { return makeSystemError(computeSystem, "Close", "", err, nil) } - if err := hcsCloseComputeSystem(computeSystem.handle); err != nil { + completed := false + go syscallWatcher(fmt.Sprintf("CloseComputeSystem %s:", computeSystem.ID()), &completed) + err := hcsCloseComputeSystem(computeSystem.handle) + completed = true + if err != nil { return makeSystemError(computeSystem, "Close", "", err, nil) } @@ -537,7 +572,10 @@ func (computeSystem *System) Modify(config interface{}) error { logrus.Debugf(title + " " + requestString) var resultp *uint16 + completed := false + go syscallWatcher(fmt.Sprintf("ModifyComputeSystem %s: %s", computeSystem.ID(), requestString), &completed) err = hcsModifyComputeSystem(computeSystem.handle, requestString, &resultp) + completed = true events := processHcsResult(resultp) if err != nil { return makeSystemError(computeSystem, "Modify", requestString, err, events) diff --git a/vendor/github.com/Microsoft/hcsshim/internal/hcs/watcher.go b/vendor/github.com/Microsoft/hcsshim/internal/hcs/watcher.go new file mode 100644 index 0000000000..6b94bc9ff8 --- /dev/null +++ b/vendor/github.com/Microsoft/hcsshim/internal/hcs/watcher.go @@ -0,0 +1,30 @@ +package hcs + +import ( + "time" + + "github.com/Microsoft/hcsshim/internal/timeout" + "github.com/sirupsen/logrus" +) + +// syscallWatcher is used as a very simple goroutine around calls into +// the platform. In some cases, we have seen HCS APIs not returning due to +// various bugs, and the goroutine making the syscall ends up not returning, +// prior to its async callback. By spinning up a syscallWatcher, it allows +// us to at least log a warning if a syscall doesn't complete in a reasonable +// amount of time. +// +// Usage is: +// +// completed := false +// go syscallWatcher("some description", &completed) +// +// completed = true +// +func syscallWatcher(description string, syscallCompleted *bool) { + time.Sleep(timeout.SyscallWatcher) + if *syscallCompleted { + return + } + logrus.Warnf("%s: Did not complete within %s. This may indicate a platform issue. If it appears to be making no forward progress, obtain the stacks and see is there is a syscall stuck in the platform API for a significant length of time.", description, timeout.SyscallWatcher) +} diff --git a/vendor/github.com/Microsoft/hcsshim/internal/interop/zsyscall_windows.go b/vendor/github.com/Microsoft/hcsshim/internal/interop/zsyscall_windows.go index 32f4e070c0..2f5bf8f555 100644 --- a/vendor/github.com/Microsoft/hcsshim/internal/interop/zsyscall_windows.go +++ b/vendor/github.com/Microsoft/hcsshim/internal/interop/zsyscall_windows.go @@ -1,4 +1,4 @@ -// MACHINE GENERATED BY 'go generate' COMMAND; DO NOT EDIT +// Code generated by 'go generate'; DO NOT EDIT. package interop diff --git a/vendor/github.com/Microsoft/hcsshim/internal/safefile/zsyscall_windows.go b/vendor/github.com/Microsoft/hcsshim/internal/safefile/zsyscall_windows.go index 776adbe7a0..709b9d3475 100644 --- a/vendor/github.com/Microsoft/hcsshim/internal/safefile/zsyscall_windows.go +++ b/vendor/github.com/Microsoft/hcsshim/internal/safefile/zsyscall_windows.go @@ -1,4 +1,4 @@ -// MACHINE GENERATED BY 'go generate' COMMAND; DO NOT EDIT +// Code generated by 'go generate'; DO NOT EDIT. package safefile diff --git a/vendor/github.com/Microsoft/hcsshim/internal/timeout/timeout.go b/vendor/github.com/Microsoft/hcsshim/internal/timeout/timeout.go index e4253f4000..ff3b6572e6 100644 --- a/vendor/github.com/Microsoft/hcsshim/internal/timeout/timeout.go +++ b/vendor/github.com/Microsoft/hcsshim/internal/timeout/timeout.go @@ -6,21 +6,65 @@ import ( "time" ) -// Duration is the default time to wait for various operations. -// - Waiting for async notifications from HCS -// - Waiting for processes to launch through -// - Waiting to copy data to/from a launched processes stdio pipes. -// -// This can be overridden through environment variable `HCS_TIMEOUT_SECONDS` +var ( + // defaultTimeout is the timeout for most operations that is not overridden. + defaultTimeout = 4 * time.Minute -var Duration = 4 * time.Minute + // defaultTimeoutTestdRetry is the retry loop timeout for testd to respond + // for a disk to come online in LCOW. + defaultTimeoutTestdRetry = 5 * time.Second +) + +// External variables for HCSShim consumers to use. +var ( + // SystemCreate is the timeout for creating a compute system + SystemCreate time.Duration = defaultTimeout + + // SystemStart is the timeout for starting a compute system + SystemStart time.Duration = defaultTimeout + + // SystemPause is the timeout for pausing a compute system + SystemPause time.Duration = defaultTimeout + + // SystemResume is the timeout for resuming a compute system + SystemResume time.Duration = defaultTimeout + + // SyscallWatcher is the timeout before warning of a potential stuck platform syscall. + SyscallWatcher time.Duration = defaultTimeout + + // Tar2VHD is the timeout for the tar2vhd operation to complete + Tar2VHD time.Duration = defaultTimeout + + // ExternalCommandToStart is the timeout for external commands to start + ExternalCommandToStart = defaultTimeout + + // ExternalCommandToComplete is the timeout for external commands to complete. + // Generally this means copying data from their stdio pipes. + ExternalCommandToComplete = defaultTimeout + + // TestDRetryLoop is the timeout for testd retry loop when onlining a SCSI disk in LCOW + TestDRetryLoop = defaultTimeoutTestdRetry +) func init() { - envTimeout := os.Getenv("HCSSHIM_TIMEOUT_SECONDS") + SystemCreate = durationFromEnvironment("HCSSHIM_TIMEOUT_SYSTEMCREATE", SystemCreate) + SystemStart = durationFromEnvironment("HCSSHIM_TIMEOUT_SYSTEMSTART", SystemStart) + SystemPause = durationFromEnvironment("HCSSHIM_TIMEOUT_SYSTEMPAUSE", SystemPause) + SystemResume = durationFromEnvironment("HCSSHIM_TIMEOUT_SYSTEMRESUME", SystemResume) + SyscallWatcher = durationFromEnvironment("HCSSHIM_TIMEOUT_SYSCALLWATCHER", SyscallWatcher) + Tar2VHD = durationFromEnvironment("HCSSHIM_TIMEOUT_TAR2VHD", Tar2VHD) + ExternalCommandToStart = durationFromEnvironment("HCSSHIM_TIMEOUT_EXTERNALCOMMANDSTART", ExternalCommandToStart) + ExternalCommandToComplete = durationFromEnvironment("HCSSHIM_TIMEOUT_EXTERNALCOMMANDCOMPLETE", ExternalCommandToComplete) + TestDRetryLoop = durationFromEnvironment("HCSSHIM_TIMEOUT_TESTDRETRYLOOP", TestDRetryLoop) +} + +func durationFromEnvironment(env string, defaultValue time.Duration) time.Duration { + envTimeout := os.Getenv(env) if len(envTimeout) > 0 { e, err := strconv.Atoi(envTimeout) if err == nil && e > 0 { - Duration = time.Second * time.Duration(e) + return time.Second * time.Duration(e) } } + return defaultValue }