Windows: Remove servicing mode

Signed-off-by: John Howard <jhoward@microsoft.com>
This commit is contained in:
John Howard 2018-02-09 10:08:47 -08:00
parent 600475715e
commit d4f37c0885
7 changed files with 32 additions and 170 deletions

View file

@ -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 {

View file

@ -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
}

View file

@ -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
}

View file

@ -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
}

View file

@ -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)

View file

@ -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
}

View file

@ -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.