diff --git a/daemon/monitor.go b/daemon/monitor.go index ce897d9397..5e740dd4fe 100644 --- a/daemon/monitor.go +++ b/daemon/monitor.go @@ -111,10 +111,7 @@ func (daemon *Daemon) ProcessEvent(id string, e libcontainerd.EventType, ei libc } daemon.setStateCounter(c) - if err := c.CheckpointTo(daemon.containersReplica); err != nil { - return err - } - return daemon.postRunProcessing(c, ei) + return c.CheckpointTo(daemon.containersReplica) } if execConfig := c.ExecCommands.Get(ei.ProcessID); execConfig != nil { diff --git a/daemon/monitor_linux.go b/daemon/monitor_linux.go deleted file mode 100644 index cb2aa72dbb..0000000000 --- a/daemon/monitor_linux.go +++ /dev/null @@ -1,11 +0,0 @@ -package daemon // import "github.com/docker/docker/daemon" - -import ( - "github.com/docker/docker/container" - "github.com/docker/docker/libcontainerd" -) - -// postRunProcessing perfoms any processing needed on the container after it has stopped. -func (daemon *Daemon) postRunProcessing(_ *container.Container, _ libcontainerd.EventInfo) error { - return nil -} diff --git a/daemon/monitor_windows.go b/daemon/monitor_windows.go deleted file mode 100644 index 5db81347c6..0000000000 --- a/daemon/monitor_windows.go +++ /dev/null @@ -1,53 +0,0 @@ -package daemon // import "github.com/docker/docker/daemon" - -import ( - "context" - - "github.com/docker/docker/container" - "github.com/docker/docker/libcontainerd" - "github.com/pkg/errors" - "github.com/sirupsen/logrus" -) - -// postRunProcessing starts a servicing container if required -func (daemon *Daemon) postRunProcessing(c *container.Container, ei libcontainerd.EventInfo) error { - if ei.ExitCode == 0 && ei.UpdatePending { - spec, err := daemon.createSpec(c) - if err != nil { - return err - } - // Turn on servicing - spec.Windows.Servicing = true - - copts, err := daemon.getLibcontainerdCreateOptions(c) - if err != nil { - return err - } - - // Create a new servicing container, which will start, complete the - // update, and merge back the results if it succeeded, all as part of - // the below function call. - ctx := context.Background() - svcID := c.ID + "_servicing" - logger := logrus.WithField("container", svcID) - if err := daemon.containerd.Create(ctx, svcID, spec, copts); err != nil { - c.SetExitCode(-1) - return errors.Wrap(err, "post-run update servicing failed") - } - _, err = daemon.containerd.Start(ctx, svcID, "", false, nil) - if err != nil { - logger.WithError(err).Warn("failed to run servicing container") - if err := daemon.containerd.Delete(ctx, svcID); err != nil { - logger.WithError(err).Warn("failed to delete servicing container") - } - } else { - if _, _, err := daemon.containerd.DeleteTask(ctx, svcID); err != nil { - logger.WithError(err).Warn("failed to delete servicing container task") - } - if err := daemon.containerd.Delete(ctx, svcID); err != nil { - logger.WithError(err).Warn("failed to delete servicing container") - } - } - } - return nil -} diff --git a/daemon/oci_windows.go b/daemon/oci_windows.go index e4b536f4e4..c6bda280da 100644 --- a/daemon/oci_windows.go +++ b/daemon/oci_windows.go @@ -326,9 +326,6 @@ func (daemon *Daemon) createSpecWindowsFields(c *container.Container, s *specs.S s.Windows.CredentialSpec = cs } - // Assume we are not starting a container for a servicing operation - s.Windows.Servicing = false - return nil } diff --git a/integration-cli/docker_cli_run_test.go b/integration-cli/docker_cli_run_test.go index 776f0e5ba5..134bcb80a9 100644 --- a/integration-cli/docker_cli_run_test.go +++ b/integration-cli/docker_cli_run_test.go @@ -4237,35 +4237,6 @@ func (s *DockerSuite) TestRunCredentialSpecWellFormed(c *check.C) { dockerCmd(c, "run", `--security-opt=credentialspec=file://valid.json`, "busybox", "true") } -// Windows specific test to ensure that a servicing app container is started -// if necessary once a container exits. It does this by forcing a no-op -// servicing event and verifying the event from Hyper-V-Compute -func (s *DockerSuite) TestRunServicingContainer(c *check.C) { - testRequires(c, DaemonIsWindows, SameHostDaemon) - - // This functionality does not exist in post-RS3 builds. - // Note we get the version number from the full build string, as Windows - // reports Windows 8 version 6.2 build 9200 from non-manifested binaries. - // Ref: https://msdn.microsoft.com/en-us/library/windows/desktop/ms724451(v=vs.85).aspx - v, err := kernel.GetKernelVersion() - c.Assert(err, checker.IsNil) - build, _ := strconv.Atoi(strings.Split(strings.SplitN(v.String(), " ", 3)[2][1:], ".")[0]) - if build > 16299 { - c.Skip("Disabled on post-RS3 builds") - } - - out := cli.DockerCmd(c, "run", "-d", testEnv.PlatformDefaults.BaseImage, "cmd", "/c", "mkdir c:\\programdata\\Microsoft\\Windows\\ContainerUpdates\\000_000_d99f45d0-ffc8-4af7-bd9c-ea6a62e035c9_200 && sc control cexecsvc 255").Combined() - containerID := strings.TrimSpace(out) - cli.WaitExited(c, containerID, 60*time.Second) - - result := icmd.RunCommand("powershell", "echo", `(Get-WinEvent -ProviderName "Microsoft-Windows-Hyper-V-Compute" -FilterXPath 'Event[System[EventID=2010]]' -MaxEvents 1).Message`) - result.Assert(c, icmd.Success) - out2 := result.Combined() - c.Assert(out2, checker.Contains, `"Servicing":true`, check.Commentf("Servicing container does not appear to have been started: %s", out2)) - c.Assert(out2, checker.Contains, `Windows Container (Servicing)`, check.Commentf("Didn't find 'Windows Container (Servicing): %s", out2)) - c.Assert(out2, checker.Contains, containerID+"_servicing", check.Commentf("Didn't find '%s_servicing': %s", containerID+"_servicing", out2)) -} - func (s *DockerSuite) TestRunDuplicateMount(c *check.C) { testRequires(c, SameHostDaemon, DaemonIsLinux, NotUserNamespace) diff --git a/libcontainerd/client_local_windows.go b/libcontainerd/client_local_windows.go index bbe127a6d7..6e3454e514 100644 --- a/libcontainerd/client_local_windows.go +++ b/libcontainerd/client_local_windows.go @@ -82,7 +82,7 @@ func (c *client) Version(ctx context.Context) (containerd.Version, error) { // | | Isolation=Process | Isolation=Hyper-V | // +-----------------+--------------------------------------------+---------------------------------------------------+ // | VolumePath | \\?\\Volume{GUIDa} | | -// | LayerFolderPath | %root%\windowsfilter\containerID | %root%\windowsfilter\containerID (servicing only) | +// | LayerFolderPath | %root%\windowsfilter\containerID | | // | Layers[] | ID=GUIDb;Path=%root%\windowsfilter\layerID | ID=GUIDb;Path=%root%\windowsfilter\layerID | // | HvRuntime | | ImagePath=%root%\BaseLayerID\UtilityVM | // +-----------------+--------------------------------------------+---------------------------------------------------+ @@ -104,7 +104,6 @@ func (c *client) Version(ctx context.Context) (containerd.Version, error) { // "MappedDirectories": [], // "HvPartition": false, // "EndpointList": ["eef2649d-bb17-4d53-9937-295a8efe6f2c"], -// "Servicing": false //} // // Isolation=Hyper-V example: @@ -126,7 +125,6 @@ func (c *client) Version(ctx context.Context) (containerd.Version, error) { // "HvRuntime": { // "ImagePath": "C:\\\\control\\\\windowsfilter\\\\65bf96e5760a09edf1790cb229e2dfb2dbd0fcdc0bf7451bae099106bfbfea0c\\\\UtilityVM" // }, -// "Servicing": false //} func (c *client) Create(_ context.Context, id string, spec *specs.Spec, runtimeOptions interface{}) error { if ctr := c.getContainer(id); ctr != nil { @@ -155,7 +153,6 @@ func (c *client) createWindows(id string, spec *specs.Spec, runtimeOptions inter IgnoreFlushesDuringBoot: spec.Windows.IgnoreFlushesDuringBoot, HostName: spec.Hostname, HvPartition: false, - Servicing: spec.Windows.Servicing, } if spec.Windows.Resources != nil { @@ -324,9 +321,6 @@ func (c *client) createWindows(id string, spec *specs.Spec, runtimeOptions inter waitCh: make(chan struct{}), } - // Start the container. If this is a servicing container, this call - // will block until the container is done with the servicing - // execution. logger.Debug("starting container") if err = hcsContainer.Start(); err != nil { c.logger.WithError(err).Error("failed to start container") @@ -525,9 +519,7 @@ func (c *client) createLinux(id string, spec *specs.Spec, runtimeOptions interfa waitCh: make(chan struct{}), } - // Start the container. If this is a servicing container, this call - // will block until the container is done with the servicing - // execution. + // Start the container. logger.Debug("starting container") if err = hcsContainer.Start(); err != nil { c.logger.WithError(err).Error("failed to start container") @@ -588,14 +580,14 @@ func (c *client) Start(_ context.Context, id, _ string, withStdin bool, attachSt ) if ctr.ociSpec.Process != nil { emulateConsole = ctr.ociSpec.Process.Terminal - createStdErrPipe = !ctr.ociSpec.Process.Terminal && !ctr.ociSpec.Windows.Servicing + createStdErrPipe = !ctr.ociSpec.Process.Terminal } createProcessParms := &hcsshim.ProcessConfig{ EmulateConsole: emulateConsole, WorkingDirectory: ctr.ociSpec.Process.Cwd, - CreateStdInPipe: !ctr.ociSpec.Windows.Servicing, - CreateStdOutPipe: !ctr.ociSpec.Windows.Servicing, + CreateStdInPipe: true, + CreateStdOutPipe: true, CreateStdErrPipe: createStdErrPipe, } @@ -655,21 +647,6 @@ func (c *client) Start(_ context.Context, id, _ string, withStdin bool, attachSt } logger.WithField("pid", p.pid).Debug("init process started") - // If this is a servicing container, wait on the process synchronously here and - // if it succeeds, wait for it cleanly shutdown and merge into the parent container. - if ctr.ociSpec.Windows.Servicing { - // reapProcess takes the lock - ctr.Unlock() - defer ctr.Lock() - exitCode := c.reapProcess(ctr, p) - - if exitCode != 0 { - return -1, errors.Errorf("libcontainerd: servicing container %s returned non-zero exit code %d", ctr.id, exitCode) - } - - return p.pid, nil - } - dio, err := newIOFromProcess(newProcess, ctr.ociSpec.Process.Terminal) if err != nil { logger.WithError(err).Error("failed to get stdio pipes") @@ -1275,7 +1252,6 @@ func (c *client) reapProcess(ctr *container, p *process) int { eventErr = fmt.Errorf("hcsProcess.Close() failed %s", err) } - var pendingUpdates bool if p.id == InitProcessName { // Update container status ctr.Lock() @@ -1285,16 +1261,6 @@ func (c *client) reapProcess(ctr *container, p *process) int { close(ctr.waitCh) ctr.Unlock() - // Handle any servicing - if exitCode == 0 && ctr.isWindows && !ctr.ociSpec.Windows.Servicing { - pendingUpdates, err = ctr.hcsContainer.HasPendingUpdates() - logger.Infof("Pending updates: %v", pendingUpdates) - if err != nil { - logger.WithError(err). - Warnf("failed to check for pending updates (container may have been killed)") - } - } - if err := c.shutdownContainer(ctr); err != nil { exitCode = -1 logger.WithError(err).Warn("failed to shutdown container") @@ -1320,37 +1286,34 @@ func (c *client) reapProcess(ctr *container, p *process) int { } } - if !(ctr.isWindows && ctr.ociSpec.Windows.Servicing) { - c.eventQ.append(ctr.id, func() { - ei := EventInfo{ - ContainerID: ctr.id, - ProcessID: p.id, - Pid: uint32(p.pid), - ExitCode: uint32(exitCode), - ExitedAt: exitedAt, - UpdatePending: pendingUpdates, - Error: eventErr, - } - c.logger.WithFields(logrus.Fields{ + c.eventQ.append(ctr.id, func() { + ei := EventInfo{ + ContainerID: ctr.id, + ProcessID: p.id, + Pid: uint32(p.pid), + ExitCode: uint32(exitCode), + ExitedAt: exitedAt, + Error: eventErr, + } + c.logger.WithFields(logrus.Fields{ + "container": ctr.id, + "event": EventExit, + "event-info": ei, + }).Info("sending event") + err := c.backend.ProcessEvent(ctr.id, EventExit, ei) + if err != nil { + c.logger.WithError(err).WithFields(logrus.Fields{ "container": ctr.id, "event": EventExit, "event-info": ei, - }).Info("sending event") - err := c.backend.ProcessEvent(ctr.id, EventExit, ei) - if err != nil { - c.logger.WithError(err).WithFields(logrus.Fields{ - "container": ctr.id, - "event": EventExit, - "event-info": ei, - }).Error("failed to process event") - } - if p.id != InitProcessName { - ctr.Lock() - delete(ctr.execs, p.id) - ctr.Unlock() - } - }) - } + }).Error("failed to process event") + } + if p.id != InitProcessName { + ctr.Lock() + delete(ctr.execs, p.id) + ctr.Unlock() + } + }) return exitCode } diff --git a/libcontainerd/types.go b/libcontainerd/types.go index 97e4fee735..96ffbe2676 100644 --- a/libcontainerd/types.go +++ b/libcontainerd/types.go @@ -71,9 +71,7 @@ type EventInfo struct { ExitCode uint32 ExitedAt time.Time OOMKilled bool - // Windows Only field - UpdatePending bool - Error error + Error error } // Backend defines callbacks that the client of the library needs to implement.