Windows: Remove servicing mode
Signed-off-by: John Howard <jhoward@microsoft.com>
This commit is contained in:
parent
600475715e
commit
d4f37c0885
7 changed files with 32 additions and 170 deletions
|
@ -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 {
|
||||
|
|
|
@ -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
|
||||
}
|
|
@ -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
|
||||
}
|
|
@ -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
|
||||
}
|
||||
|
||||
|
|
|
@ -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)
|
||||
|
||||
|
|
|
@ -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
|
||||
}
|
||||
|
|
|
@ -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.
|
||||
|
|
Loading…
Reference in a new issue