Update containerd to 5ba368748b.

Signed-off-by: Lantao Liu <lantaol@google.com>
This commit is contained in:
Lantao Liu 2019-02-05 00:17:00 -08:00
parent f8b3450847
commit c27a12dd08
148 changed files with 3015 additions and 1235 deletions

View File

@ -1,14 +1,14 @@
github.com/beorn7/perks 4c0e84591b9aa9e6dcfdf3e020114cd81f89d5f9 github.com/beorn7/perks 4c0e84591b9aa9e6dcfdf3e020114cd81f89d5f9
github.com/blang/semver v3.1.0 github.com/blang/semver v3.1.0
github.com/BurntSushi/toml a368813c5e648fee92e5f6c30e3944ff9d5e8895 github.com/BurntSushi/toml a368813c5e648fee92e5f6c30e3944ff9d5e8895
github.com/containerd/cgroups 5e610833b72089b37d0e615de9a92dfc043757c2 github.com/containerd/cgroups 1152b960fcee041f50df15cdc67c29dbccf801ef
github.com/containerd/console c12b1e7919c14469339a5d38f2f8ed9b64a9de23 github.com/containerd/console c12b1e7919c14469339a5d38f2f8ed9b64a9de23
github.com/containerd/containerd 6937c5a3ba8280edff9e9030767e3b0cb742581c github.com/containerd/containerd 5ba368748b0275d8f45f909413d94738992f0050
github.com/containerd/continuity bd77b46c8352f74eb12c85bdc01f4b90f69d66b4 github.com/containerd/continuity bd77b46c8352f74eb12c85bdc01f4b90f69d66b4
github.com/containerd/fifo 3d5202aec260678c48179c56f40e6f38a095738c github.com/containerd/fifo 3d5202aec260678c48179c56f40e6f38a095738c
github.com/containerd/go-cni 40bcf8ec8acd7372be1d77031d585d5d8e561c90 github.com/containerd/go-cni 40bcf8ec8acd7372be1d77031d585d5d8e561c90
github.com/containerd/go-runc 5a6d9f37cfa36b15efba46dc7ea349fa9b7143c3 github.com/containerd/go-runc 5a6d9f37cfa36b15efba46dc7ea349fa9b7143c3
github.com/containerd/ttrpc 2a805f71863501300ae1976d29f0454ae003e85a github.com/containerd/ttrpc f02858b1457c5ca3aaec3a0803eb0d59f96e41d6
github.com/containerd/typeurl a93fcdb778cd272c6e9b3028b2f42d813e785d40 github.com/containerd/typeurl a93fcdb778cd272c6e9b3028b2f42d813e785d40
github.com/containernetworking/cni v0.6.0 github.com/containernetworking/cni v0.6.0
github.com/containernetworking/plugins v0.7.0 github.com/containernetworking/plugins v0.7.0
@ -32,12 +32,12 @@ github.com/hashicorp/go-multierror ed905158d87462226a13fe39ddf685ea65f1c11f
github.com/json-iterator/go 1.1.5 github.com/json-iterator/go 1.1.5
github.com/matttproud/golang_protobuf_extensions v1.0.0 github.com/matttproud/golang_protobuf_extensions v1.0.0
github.com/Microsoft/go-winio v0.4.11 github.com/Microsoft/go-winio v0.4.11
github.com/Microsoft/hcsshim v0.8.2 github.com/Microsoft/hcsshim v0.8.5
github.com/modern-go/concurrent 1.0.3 github.com/modern-go/concurrent 1.0.3
github.com/modern-go/reflect2 1.0.1 github.com/modern-go/reflect2 1.0.1
github.com/opencontainers/go-digest c9281466c8b2f606084ac71339773efd177436e7 github.com/opencontainers/go-digest c9281466c8b2f606084ac71339773efd177436e7
github.com/opencontainers/image-spec v1.0.1 github.com/opencontainers/image-spec v1.0.1
github.com/opencontainers/runc v1.0.0-rc6 github.com/opencontainers/runc 12f6a991201fdb8f82579582d5e00e28fba06d0a
github.com/opencontainers/runtime-spec eba862dc2470385a233c7507392675cbeadf7353 github.com/opencontainers/runtime-spec eba862dc2470385a233c7507392675cbeadf7353
github.com/opencontainers/runtime-tools fb101d5d42ab9c040f7d0a004e78336e5d5cb197 github.com/opencontainers/runtime-tools fb101d5d42ab9c040f7d0a004e78336e5d5cb197
github.com/opencontainers/selinux b6fa367ed7f534f9ba25391cc2d467085dbb445a github.com/opencontainers/selinux b6fa367ed7f534f9ba25391cc2d467085dbb445a
@ -60,7 +60,7 @@ go.etcd.io/bbolt v1.3.1-etcd.8
golang.org/x/crypto 49796115aa4b964c318aad4f3084fdb41e9aa067 golang.org/x/crypto 49796115aa4b964c318aad4f3084fdb41e9aa067
golang.org/x/net b3756b4b77d7b13260a0a2ec658753cf48922eac golang.org/x/net b3756b4b77d7b13260a0a2ec658753cf48922eac
golang.org/x/oauth2 a6bd8cefa1811bd24b86f8902872e4e8225f74c4 golang.org/x/oauth2 a6bd8cefa1811bd24b86f8902872e4e8225f74c4
golang.org/x/sync 450f422ab23cf9881c94e2db30cac0eb1b7cf80c golang.org/x/sync 42b317875d0fa942474b76e1b46a6060d720ae6e
golang.org/x/sys 1b2967e3c290b7c545b3db0deeda16e9be4f98a2 https://github.com/golang/sys golang.org/x/sys 1b2967e3c290b7c545b3db0deeda16e9be4f98a2 https://github.com/golang/sys
golang.org/x/text 19e51611da83d6be54ddafce4a4af510cb3e9ea4 golang.org/x/text 19e51611da83d6be54ddafce4a4af510cb3e9ea4
golang.org/x/time f51c12702a4d776e4c1fa9b0fabab841babae631 golang.org/x/time f51c12702a4d776e4c1fa9b0fabab841babae631

View File

@ -37,8 +37,8 @@ func GetPolicyListByID(policyListID string) (*PolicyList, error) {
} }
// AddLoadBalancer policy list for the specified endpoints // AddLoadBalancer policy list for the specified endpoints
func AddLoadBalancer(endpoints []HNSEndpoint, isILB bool, isDSR bool, sourceVIP, vip string, protocol uint16, internalPort uint16, externalPort uint16) (*PolicyList, error) { func AddLoadBalancer(endpoints []HNSEndpoint, isILB bool, sourceVIP, vip string, protocol uint16, internalPort uint16, externalPort uint16) (*PolicyList, error) {
return hns.AddLoadBalancer(endpoints, isILB, isDSR, sourceVIP, vip, protocol, internalPort, externalPort) return hns.AddLoadBalancer(endpoints, isILB, sourceVIP, vip, protocol, internalPort, externalPort)
} }
// AddRoute adds route policy list for the specified endpoints // AddRoute adds route policy list for the specified endpoints

View File

@ -1,6 +1,8 @@
package guestrequest package guestrequest
import "github.com/Microsoft/hcsshim/internal/schema2" import (
"github.com/Microsoft/hcsshim/internal/schema2"
)
// Arguably, many of these (at least CombinedLayers) should have been generated // Arguably, many of these (at least CombinedLayers) should have been generated
// by swagger. // by swagger.
@ -47,6 +49,19 @@ type LCOWMappedVPMemDevice struct {
MountPath string `json:"MountPath,omitempty"` // /tmp/pN MountPath string `json:"MountPath,omitempty"` // /tmp/pN
} }
type LCOWNetworkAdapter struct {
NamespaceID string `json:",omitempty"`
ID string `json:",omitempty"`
MacAddress string `json:",omitempty"`
IPAddress string `json:",omitempty"`
PrefixLength uint8 `json:",omitempty"`
GatewayAddress string `json:",omitempty"`
DNSSuffix string `json:",omitempty"`
DNSServerList string `json:",omitempty"`
EnableLowMetric bool `json:",omitempty"`
EncapOverhead uint16 `json:",omitempty"`
}
type ResourceType string type ResourceType string
const ( const (

View File

@ -5,6 +5,7 @@ import (
"syscall" "syscall"
"github.com/Microsoft/hcsshim/internal/interop" "github.com/Microsoft/hcsshim/internal/interop"
"github.com/sirupsen/logrus"
) )
var ( var (
@ -15,11 +16,20 @@ var (
notificationWatcherCallback = syscall.NewCallback(notificationWatcher) notificationWatcherCallback = syscall.NewCallback(notificationWatcher)
// Notifications for HCS_SYSTEM handles // Notifications for HCS_SYSTEM handles
hcsNotificationSystemExited hcsNotification = 0x00000001 hcsNotificationSystemExited hcsNotification = 0x00000001
hcsNotificationSystemCreateCompleted hcsNotification = 0x00000002 hcsNotificationSystemCreateCompleted hcsNotification = 0x00000002
hcsNotificationSystemStartCompleted hcsNotification = 0x00000003 hcsNotificationSystemStartCompleted hcsNotification = 0x00000003
hcsNotificationSystemPauseCompleted hcsNotification = 0x00000004 hcsNotificationSystemPauseCompleted hcsNotification = 0x00000004
hcsNotificationSystemResumeCompleted hcsNotification = 0x00000005 hcsNotificationSystemResumeCompleted hcsNotification = 0x00000005
hcsNotificationSystemCrashReport hcsNotification = 0x00000006
hcsNotificationSystemSiloJobCreated hcsNotification = 0x00000007
hcsNotificationSystemSaveCompleted hcsNotification = 0x00000008
hcsNotificationSystemRdpEnhancedModeStateChanged hcsNotification = 0x00000009
hcsNotificationSystemShutdownFailed hcsNotification = 0x0000000A
hcsNotificationSystemGetPropertiesCompleted hcsNotification = 0x0000000B
hcsNotificationSystemModifyCompleted hcsNotification = 0x0000000C
hcsNotificationSystemCrashInitiated hcsNotification = 0x0000000D
hcsNotificationSystemGuestConnectionClosed hcsNotification = 0x0000000E
// Notifications for HCS_PROCESS handles // Notifications for HCS_PROCESS handles
hcsNotificationProcessExited hcsNotification = 0x00010000 hcsNotificationProcessExited hcsNotification = 0x00010000
@ -49,16 +59,23 @@ func newChannels() notificationChannels {
channels[hcsNotificationSystemResumeCompleted] = make(notificationChannel, 1) channels[hcsNotificationSystemResumeCompleted] = make(notificationChannel, 1)
channels[hcsNotificationProcessExited] = make(notificationChannel, 1) channels[hcsNotificationProcessExited] = make(notificationChannel, 1)
channels[hcsNotificationServiceDisconnect] = make(notificationChannel, 1) channels[hcsNotificationServiceDisconnect] = make(notificationChannel, 1)
channels[hcsNotificationSystemCrashReport] = make(notificationChannel, 1)
channels[hcsNotificationSystemSiloJobCreated] = make(notificationChannel, 1)
channels[hcsNotificationSystemSaveCompleted] = make(notificationChannel, 1)
channels[hcsNotificationSystemRdpEnhancedModeStateChanged] = make(notificationChannel, 1)
channels[hcsNotificationSystemShutdownFailed] = make(notificationChannel, 1)
channels[hcsNotificationSystemGetPropertiesCompleted] = make(notificationChannel, 1)
channels[hcsNotificationSystemModifyCompleted] = make(notificationChannel, 1)
channels[hcsNotificationSystemCrashInitiated] = make(notificationChannel, 1)
channels[hcsNotificationSystemGuestConnectionClosed] = make(notificationChannel, 1)
return channels return channels
} }
func closeChannels(channels notificationChannels) { func closeChannels(channels notificationChannels) {
close(channels[hcsNotificationSystemExited]) for _, c := range channels {
close(channels[hcsNotificationSystemCreateCompleted]) close(c)
close(channels[hcsNotificationSystemStartCompleted]) }
close(channels[hcsNotificationSystemPauseCompleted])
close(channels[hcsNotificationSystemResumeCompleted])
close(channels[hcsNotificationProcessExited])
close(channels[hcsNotificationServiceDisconnect])
} }
func notificationWatcher(notificationType hcsNotification, callbackNumber uintptr, notificationStatus uintptr, notificationData *uint16) uintptr { func notificationWatcher(notificationType hcsNotification, callbackNumber uintptr, notificationStatus uintptr, notificationData *uint16) uintptr {
@ -75,7 +92,13 @@ func notificationWatcher(notificationType hcsNotification, callbackNumber uintpt
return 0 return 0
} }
context.channels[notificationType] <- result if channel, ok := context.channels[notificationType]; ok {
channel <- result
} else {
logrus.WithFields(logrus.Fields{
"notification-type": notificationType,
}).Warn("Received a callback of an unsupported type")
}
return 0 return 0
} }

View File

@ -7,6 +7,7 @@ import (
"syscall" "syscall"
"github.com/Microsoft/hcsshim/internal/interop" "github.com/Microsoft/hcsshim/internal/interop"
"github.com/Microsoft/hcsshim/internal/logfields"
"github.com/sirupsen/logrus" "github.com/sirupsen/logrus"
) )
@ -72,6 +73,9 @@ var (
// ErrVmcomputeUnknownMessage is an error encountered guest compute system doesn't support the message // ErrVmcomputeUnknownMessage is an error encountered guest compute system doesn't support the message
ErrVmcomputeUnknownMessage = syscall.Errno(0xc037010b) ErrVmcomputeUnknownMessage = syscall.Errno(0xc037010b)
// ErrVmcomputeUnexpectedExit is an error encountered when the compute system terminates unexpectedly
ErrVmcomputeUnexpectedExit = syscall.Errno(0xC0370106)
// ErrNotSupported is an error encountered when hcs doesn't support the request // ErrNotSupported is an error encountered when hcs doesn't support the request
ErrPlatformNotSupported = errors.New("unsupported platform request") ErrPlatformNotSupported = errors.New("unsupported platform request")
) )
@ -116,10 +120,14 @@ func (ev *ErrorEvent) String() string {
func processHcsResult(resultp *uint16) []ErrorEvent { func processHcsResult(resultp *uint16) []ErrorEvent {
if resultp != nil { if resultp != nil {
resultj := interop.ConvertAndFreeCoTaskMemString(resultp) resultj := interop.ConvertAndFreeCoTaskMemString(resultp)
logrus.Debugf("Result: %s", resultj) logrus.WithField(logfields.JSON, resultj).
Debug("HCS Result")
result := &hcsResult{} result := &hcsResult{}
if err := json.Unmarshal([]byte(resultj), result); err != nil { if err := json.Unmarshal([]byte(resultj), result); err != nil {
logrus.Warnf("Could not unmarshal HCS result %s: %s", resultj, err) logrus.WithFields(logrus.Fields{
logfields.JSON: resultj,
logrus.ErrorKey: err,
}).Warning("Could not unmarshal HCS result")
return nil return nil
} }
return result.ErrorEvents return result.ErrorEvents

View File

@ -0,0 +1,15 @@
package hcs
import "github.com/sirupsen/logrus"
func logOperationBegin(ctx logrus.Fields, msg string) {
logrus.WithFields(ctx).Debug(msg)
}
func logOperationEnd(ctx logrus.Fields, msg string, err error) {
if err == nil {
logrus.WithFields(ctx).Debug(msg)
} else {
logrus.WithFields(ctx).WithError(err).Error(msg)
}
}

View File

@ -2,7 +2,6 @@ package hcs
import ( import (
"encoding/json" "encoding/json"
"fmt"
"io" "io"
"sync" "sync"
"syscall" "syscall"
@ -10,6 +9,7 @@ import (
"github.com/Microsoft/hcsshim/internal/guestrequest" "github.com/Microsoft/hcsshim/internal/guestrequest"
"github.com/Microsoft/hcsshim/internal/interop" "github.com/Microsoft/hcsshim/internal/interop"
"github.com/Microsoft/hcsshim/internal/logfields"
"github.com/sirupsen/logrus" "github.com/sirupsen/logrus"
) )
@ -21,6 +21,21 @@ type Process struct {
system *System system *System
cachedPipes *cachedPipes cachedPipes *cachedPipes
callbackNumber uintptr callbackNumber uintptr
logctx logrus.Fields
}
func newProcess(process hcsProcess, processID int, computeSystem *System) *Process {
return &Process{
handle: process,
processID: processID,
system: computeSystem,
logctx: logrus.Fields{
logfields.HCSOperation: "",
logfields.ContainerID: computeSystem.ID(),
logfields.ProcessID: processID,
},
}
} }
type cachedPipes struct { type cachedPipes struct {
@ -72,13 +87,36 @@ func (process *Process) SystemID() string {
return process.system.ID() return process.system.ID()
} }
func (process *Process) logOperationBegin(operation string) {
process.logctx[logfields.HCSOperation] = operation
logOperationBegin(
process.logctx,
"hcsshim::Process - Begin Operation")
}
func (process *Process) logOperationEnd(err error) {
var result string
if err == nil {
result = "Success"
} else {
result = "Error"
}
logOperationEnd(
process.logctx,
"hcsshim::Process - End Operation - "+result,
err)
process.logctx[logfields.HCSOperation] = ""
}
// Signal signals the process with `options`. // Signal signals the process with `options`.
func (process *Process) Signal(options guestrequest.SignalProcessOptions) error { func (process *Process) Signal(options guestrequest.SignalProcessOptions) (err error) {
process.handleLock.RLock() process.handleLock.RLock()
defer process.handleLock.RUnlock() defer process.handleLock.RUnlock()
operation := "Signal"
title := "hcsshim::Process::" + operation operation := "hcsshim::Process::Signal"
logrus.Debugf(title+" processid=%d", process.processID) process.logOperationBegin(operation)
defer func() { process.logOperationEnd(err) }()
if process.handle == 0 { if process.handle == 0 {
return makeProcessError(process, operation, ErrAlreadyClosed, nil) return makeProcessError(process, operation, ErrAlreadyClosed, nil)
@ -92,83 +130,79 @@ func (process *Process) Signal(options guestrequest.SignalProcessOptions) error
optionsStr := string(optionsb) optionsStr := string(optionsb)
var resultp *uint16 var resultp *uint16
completed := false syscallWatcher(process.logctx, func() {
go syscallWatcher(fmt.Sprintf("SignalProcess %s: %d", process.SystemID(), process.Pid()), &completed) err = hcsSignalProcess(process.handle, optionsStr, &resultp)
err = hcsSignalProcess(process.handle, optionsStr, &resultp) })
completed = true
events := processHcsResult(resultp) events := processHcsResult(resultp)
if err != nil { if err != nil {
return makeProcessError(process, operation, err, events) return makeProcessError(process, operation, err, events)
} }
logrus.Debugf(title+" succeeded processid=%d", process.processID)
return nil return nil
} }
// Kill signals the process to terminate but does not wait for it to finish terminating. // Kill signals the process to terminate but does not wait for it to finish terminating.
func (process *Process) Kill() error { func (process *Process) Kill() (err error) {
process.handleLock.RLock() process.handleLock.RLock()
defer process.handleLock.RUnlock() defer process.handleLock.RUnlock()
operation := "Kill"
title := "hcsshim::Process::" + operation operation := "hcsshim::Process::Kill"
logrus.Debugf(title+" processid=%d", process.processID) process.logOperationBegin(operation)
defer func() { process.logOperationEnd(err) }()
if process.handle == 0 { if process.handle == 0 {
return makeProcessError(process, operation, ErrAlreadyClosed, nil) return makeProcessError(process, operation, ErrAlreadyClosed, nil)
} }
var resultp *uint16 var resultp *uint16
completed := false syscallWatcher(process.logctx, func() {
go syscallWatcher(fmt.Sprintf("TerminateProcess %s: %d", process.SystemID(), process.Pid()), &completed) err = hcsTerminateProcess(process.handle, &resultp)
err := hcsTerminateProcess(process.handle, &resultp) })
completed = true
events := processHcsResult(resultp) events := processHcsResult(resultp)
if err != nil { if err != nil {
return makeProcessError(process, operation, err, events) return makeProcessError(process, operation, err, events)
} }
logrus.Debugf(title+" succeeded processid=%d", process.processID)
return nil return nil
} }
// Wait waits for the process to exit. // Wait waits for the process to exit.
func (process *Process) Wait() error { func (process *Process) Wait() (err error) {
operation := "Wait" operation := "hcsshim::Process::Wait"
title := "hcsshim::Process::" + operation process.logOperationBegin(operation)
logrus.Debugf(title+" processid=%d", process.processID) defer func() { process.logOperationEnd(err) }()
err := waitForNotification(process.callbackNumber, hcsNotificationProcessExited, nil) err = waitForNotification(process.callbackNumber, hcsNotificationProcessExited, nil)
if err != nil { if err != nil {
return makeProcessError(process, operation, err, nil) return makeProcessError(process, operation, err, nil)
} }
logrus.Debugf(title+" succeeded processid=%d", process.processID)
return nil return nil
} }
// WaitTimeout waits for the process to exit or the duration to elapse. It returns // WaitTimeout waits for the process to exit or the duration to elapse. It returns
// false if timeout occurs. // false if timeout occurs.
func (process *Process) WaitTimeout(timeout time.Duration) error { func (process *Process) WaitTimeout(timeout time.Duration) (err error) {
operation := "WaitTimeout" operation := "hcssshim::Process::WaitTimeout"
title := "hcsshim::Process::" + operation process.logOperationBegin(operation)
logrus.Debugf(title+" processid=%d", process.processID) defer func() { process.logOperationEnd(err) }()
err := waitForNotification(process.callbackNumber, hcsNotificationProcessExited, &timeout) err = waitForNotification(process.callbackNumber, hcsNotificationProcessExited, &timeout)
if err != nil { if err != nil {
return makeProcessError(process, operation, err, nil) return makeProcessError(process, operation, err, nil)
} }
logrus.Debugf(title+" succeeded processid=%d", process.processID)
return nil return nil
} }
// ResizeConsole resizes the console of the process. // ResizeConsole resizes the console of the process.
func (process *Process) ResizeConsole(width, height uint16) error { func (process *Process) ResizeConsole(width, height uint16) (err error) {
process.handleLock.RLock() process.handleLock.RLock()
defer process.handleLock.RUnlock() defer process.handleLock.RUnlock()
operation := "ResizeConsole"
title := "hcsshim::Process::" + operation operation := "hcsshim::Process::ResizeConsole"
logrus.Debugf(title+" processid=%d", process.processID) process.logOperationBegin(operation)
defer func() { process.logOperationEnd(err) }()
if process.handle == 0 { if process.handle == 0 {
return makeProcessError(process, operation, ErrAlreadyClosed, nil) return makeProcessError(process, operation, ErrAlreadyClosed, nil)
@ -196,16 +230,16 @@ func (process *Process) ResizeConsole(width, height uint16) error {
return makeProcessError(process, operation, err, events) return makeProcessError(process, operation, err, events)
} }
logrus.Debugf(title+" succeeded processid=%d", process.processID)
return nil return nil
} }
func (process *Process) Properties() (*ProcessStatus, error) { func (process *Process) Properties() (_ *ProcessStatus, err error) {
process.handleLock.RLock() process.handleLock.RLock()
defer process.handleLock.RUnlock() defer process.handleLock.RUnlock()
operation := "Properties"
title := "hcsshim::Process::" + operation operation := "hcsshim::Process::Properties"
logrus.Debugf(title+" processid=%d", process.processID) process.logOperationBegin(operation)
defer func() { process.logOperationEnd(err) }()
if process.handle == 0 { if process.handle == 0 {
return nil, makeProcessError(process, operation, ErrAlreadyClosed, nil) return nil, makeProcessError(process, operation, ErrAlreadyClosed, nil)
@ -215,10 +249,9 @@ func (process *Process) Properties() (*ProcessStatus, error) {
resultp *uint16 resultp *uint16
propertiesp *uint16 propertiesp *uint16
) )
completed := false syscallWatcher(process.logctx, func() {
go syscallWatcher(fmt.Sprintf("GetProcessProperties %s: %d", process.SystemID(), process.Pid()), &completed) err = hcsGetProcessProperties(process.handle, &propertiesp, &resultp)
err := hcsGetProcessProperties(process.handle, &propertiesp, &resultp) })
completed = true
events := processHcsResult(resultp) events := processHcsResult(resultp)
if err != nil { if err != nil {
return nil, makeProcessError(process, operation, err, events) return nil, makeProcessError(process, operation, err, events)
@ -234,14 +267,16 @@ func (process *Process) Properties() (*ProcessStatus, error) {
return nil, makeProcessError(process, operation, err, nil) return nil, makeProcessError(process, operation, err, nil)
} }
logrus.Debugf(title+" succeeded processid=%d, properties=%s", process.processID, propertiesRaw)
return properties, nil return properties, nil
} }
// ExitCode returns the exit code of the process. The process must have // ExitCode returns the exit code of the process. The process must have
// already terminated. // already terminated.
func (process *Process) ExitCode() (int, error) { func (process *Process) ExitCode() (_ int, err error) {
operation := "ExitCode" operation := "hcsshim::Process::ExitCode"
process.logOperationBegin(operation)
defer func() { process.logOperationEnd(err) }()
properties, err := process.Properties() properties, err := process.Properties()
if err != nil { if err != nil {
return 0, makeProcessError(process, operation, err, nil) return 0, makeProcessError(process, operation, err, nil)
@ -261,12 +296,13 @@ func (process *Process) ExitCode() (int, error) {
// Stdio returns the stdin, stdout, and stderr pipes, respectively. Closing // Stdio returns the stdin, stdout, and stderr pipes, respectively. Closing
// these pipes does not close the underlying pipes; it should be possible to // these pipes does not close the underlying pipes; it should be possible to
// call this multiple times to get multiple interfaces. // call this multiple times to get multiple interfaces.
func (process *Process) Stdio() (io.WriteCloser, io.ReadCloser, io.ReadCloser, error) { func (process *Process) Stdio() (_ io.WriteCloser, _ io.ReadCloser, _ io.ReadCloser, err error) {
process.handleLock.RLock() process.handleLock.RLock()
defer process.handleLock.RUnlock() defer process.handleLock.RUnlock()
operation := "Stdio"
title := "hcsshim::Process::" + operation operation := "hcsshim::Process::Stdio"
logrus.Debugf(title+" processid=%d", process.processID) process.logOperationBegin(operation)
defer func() { process.logOperationEnd(err) }()
if process.handle == 0 { if process.handle == 0 {
return nil, nil, nil, makeProcessError(process, operation, ErrAlreadyClosed, nil) return nil, nil, nil, makeProcessError(process, operation, ErrAlreadyClosed, nil)
@ -279,7 +315,7 @@ func (process *Process) Stdio() (io.WriteCloser, io.ReadCloser, io.ReadCloser, e
processInfo hcsProcessInformation processInfo hcsProcessInformation
resultp *uint16 resultp *uint16
) )
err := hcsGetProcessInfo(process.handle, &processInfo, &resultp) err = hcsGetProcessInfo(process.handle, &processInfo, &resultp)
events := processHcsResult(resultp) events := processHcsResult(resultp)
if err != nil { if err != nil {
return nil, nil, nil, makeProcessError(process, operation, err, events) return nil, nil, nil, makeProcessError(process, operation, err, events)
@ -299,18 +335,18 @@ func (process *Process) Stdio() (io.WriteCloser, io.ReadCloser, io.ReadCloser, e
return nil, nil, nil, makeProcessError(process, operation, err, nil) return nil, nil, nil, makeProcessError(process, operation, err, nil)
} }
logrus.Debugf(title+" succeeded processid=%d", process.processID)
return pipes[0], pipes[1], pipes[2], nil return pipes[0], pipes[1], pipes[2], nil
} }
// CloseStdin closes the write side of the stdin pipe so that the process is // CloseStdin closes the write side of the stdin pipe so that the process is
// notified on the read side that there is no more data in stdin. // notified on the read side that there is no more data in stdin.
func (process *Process) CloseStdin() error { func (process *Process) CloseStdin() (err error) {
process.handleLock.RLock() process.handleLock.RLock()
defer process.handleLock.RUnlock() defer process.handleLock.RUnlock()
operation := "CloseStdin"
title := "hcsshim::Process::" + operation operation := "hcsshim::Process::CloseStdin"
logrus.Debugf(title+" processid=%d", process.processID) process.logOperationBegin(operation)
defer func() { process.logOperationEnd(err) }()
if process.handle == 0 { if process.handle == 0 {
return makeProcessError(process, operation, ErrAlreadyClosed, nil) return makeProcessError(process, operation, ErrAlreadyClosed, nil)
@ -337,35 +373,34 @@ func (process *Process) CloseStdin() error {
return makeProcessError(process, operation, err, events) return makeProcessError(process, operation, err, events)
} }
logrus.Debugf(title+" succeeded processid=%d", process.processID)
return nil return nil
} }
// Close cleans up any state associated with the process but does not kill // Close cleans up any state associated with the process but does not kill
// or wait on it. // or wait on it.
func (process *Process) Close() error { func (process *Process) Close() (err error) {
process.handleLock.Lock() process.handleLock.Lock()
defer process.handleLock.Unlock() defer process.handleLock.Unlock()
operation := "Close"
title := "hcsshim::Process::" + operation operation := "hcsshim::Process::Close"
logrus.Debugf(title+" processid=%d", process.processID) process.logOperationBegin(operation)
defer func() { process.logOperationEnd(err) }()
// Don't double free this // Don't double free this
if process.handle == 0 { if process.handle == 0 {
return nil return nil
} }
if err := process.unregisterCallback(); err != nil { if err = process.unregisterCallback(); err != nil {
return makeProcessError(process, operation, err, nil) return makeProcessError(process, operation, err, nil)
} }
if err := hcsCloseProcess(process.handle); err != nil { if err = hcsCloseProcess(process.handle); err != nil {
return makeProcessError(process, operation, err, nil) return makeProcessError(process, operation, err, nil)
} }
process.handle = 0 process.handle = 0
logrus.Debugf(title+" succeeded processid=%d", process.processID)
return nil return nil
} }

View File

@ -2,7 +2,6 @@ package hcs
import ( import (
"encoding/json" "encoding/json"
"fmt"
"os" "os"
"strconv" "strconv"
"sync" "sync"
@ -10,6 +9,7 @@ import (
"time" "time"
"github.com/Microsoft/hcsshim/internal/interop" "github.com/Microsoft/hcsshim/internal/interop"
"github.com/Microsoft/hcsshim/internal/logfields"
"github.com/Microsoft/hcsshim/internal/schema1" "github.com/Microsoft/hcsshim/internal/schema1"
"github.com/Microsoft/hcsshim/internal/timeout" "github.com/Microsoft/hcsshim/internal/timeout"
"github.com/sirupsen/logrus" "github.com/sirupsen/logrus"
@ -41,16 +41,49 @@ type System struct {
handle hcsSystem handle hcsSystem
id string id string
callbackNumber uintptr callbackNumber uintptr
logctx logrus.Fields
}
func newSystem(id string) *System {
return &System{
id: id,
logctx: logrus.Fields{
logfields.HCSOperation: "",
logfields.ContainerID: id,
},
}
}
func (computeSystem *System) logOperationBegin(operation string) {
computeSystem.logctx[logfields.HCSOperation] = operation
logOperationBegin(
computeSystem.logctx,
"hcsshim::ComputeSystem - Begin Operation")
}
func (computeSystem *System) logOperationEnd(err error) {
var result string
if err == nil {
result = "Success"
} else {
result = "Error"
}
logOperationEnd(
computeSystem.logctx,
"hcsshim::ComputeSystem - End Operation - "+result,
err)
computeSystem.logctx[logfields.HCSOperation] = ""
} }
// CreateComputeSystem creates a new compute system with the given configuration but does not start it. // CreateComputeSystem creates a new compute system with the given configuration but does not start it.
func CreateComputeSystem(id string, hcsDocumentInterface interface{}) (*System, error) { func CreateComputeSystem(id string, hcsDocumentInterface interface{}) (_ *System, err error) {
operation := "CreateComputeSystem" operation := "hcsshim::CreateComputeSystem"
title := "hcsshim::" + operation
computeSystem := &System{ computeSystem := newSystem(id)
id: id, computeSystem.logOperationBegin(operation)
} defer func() { computeSystem.logOperationEnd(err) }()
hcsDocumentB, err := json.Marshal(hcsDocumentInterface) hcsDocumentB, err := json.Marshal(hcsDocumentInterface)
if err != nil { if err != nil {
@ -58,19 +91,22 @@ func CreateComputeSystem(id string, hcsDocumentInterface interface{}) (*System,
} }
hcsDocument := string(hcsDocumentB) hcsDocument := string(hcsDocumentB)
logrus.Debugf(title+" ID=%s config=%s", id, hcsDocument)
logrus.WithFields(computeSystem.logctx).
WithField(logfields.JSON, hcsDocument).
Debug("HCS ComputeSystem Document")
var ( var (
resultp *uint16 resultp *uint16
identity syscall.Handle identity syscall.Handle
createError error
) )
completed := false syscallWatcher(computeSystem.logctx, func() {
go syscallWatcher(fmt.Sprintf("CreateCompleteSystem %s: %s", id, hcsDocument), &completed) createError = hcsCreateComputeSystem(id, hcsDocument, identity, &computeSystem.handle, &resultp)
createError := hcsCreateComputeSystem(id, hcsDocument, identity, &computeSystem.handle, &resultp) })
completed = true
if createError == nil || IsPending(createError) { if createError == nil || IsPending(createError) {
if err := computeSystem.registerCallback(); err != nil { if err = computeSystem.registerCallback(); err != nil {
// Terminate the compute system if it still exists. We're okay to // Terminate the compute system if it still exists. We're okay to
// ignore a failure here. // ignore a failure here.
computeSystem.Terminate() computeSystem.Terminate()
@ -88,25 +124,28 @@ func CreateComputeSystem(id string, hcsDocumentInterface interface{}) (*System,
return nil, makeSystemError(computeSystem, operation, hcsDocument, err, events) return nil, makeSystemError(computeSystem, operation, hcsDocument, err, events)
} }
logrus.Debugf(title+" succeeded id=%s handle=%d", id, computeSystem.handle)
return computeSystem, nil return computeSystem, nil
} }
// OpenComputeSystem opens an existing compute system by ID. // OpenComputeSystem opens an existing compute system by ID.
func OpenComputeSystem(id string) (*System, error) { func OpenComputeSystem(id string) (_ *System, err error) {
operation := "OpenComputeSystem" operation := "hcsshim::OpenComputeSystem"
title := "hcsshim::" + operation
logrus.Debugf(title+" ID=%s", id)
computeSystem := &System{ computeSystem := newSystem(id)
id: id, computeSystem.logOperationBegin(operation)
} defer func() {
if IsNotExist(err) {
computeSystem.logOperationEnd(nil)
} else {
computeSystem.logOperationEnd(err)
}
}()
var ( var (
handle hcsSystem handle hcsSystem
resultp *uint16 resultp *uint16
) )
err := hcsOpenComputeSystem(id, &handle, &resultp) err = hcsOpenComputeSystem(id, &handle, &resultp)
events := processHcsResult(resultp) events := processHcsResult(resultp)
if err != nil { if err != nil {
return nil, makeSystemError(computeSystem, operation, "", err, events) return nil, makeSystemError(computeSystem, operation, "", err, events)
@ -114,18 +153,36 @@ func OpenComputeSystem(id string) (*System, error) {
computeSystem.handle = handle computeSystem.handle = handle
if err := computeSystem.registerCallback(); err != nil { if err = computeSystem.registerCallback(); err != nil {
return nil, makeSystemError(computeSystem, operation, "", err, nil) return nil, makeSystemError(computeSystem, operation, "", err, nil)
} }
logrus.Debugf(title+" succeeded id=%s handle=%d", id, handle)
return computeSystem, nil return computeSystem, nil
} }
// GetComputeSystems gets a list of the compute systems on the system that match the query // GetComputeSystems gets a list of the compute systems on the system that match the query
func GetComputeSystems(q schema1.ComputeSystemQuery) ([]schema1.ContainerProperties, error) { func GetComputeSystems(q schema1.ComputeSystemQuery) (_ []schema1.ContainerProperties, err error) {
operation := "GetComputeSystems" operation := "hcsshim::GetComputeSystems"
title := "hcsshim::" + operation fields := logrus.Fields{
logfields.HCSOperation: operation,
}
logOperationBegin(
fields,
"hcsshim::ComputeSystem - Begin Operation")
defer func() {
var result string
if err == nil {
result = "Success"
} else {
result = "Error"
}
logOperationEnd(
fields,
"hcsshim::ComputeSystem - End Operation - "+result,
err)
}()
queryb, err := json.Marshal(q) queryb, err := json.Marshal(q)
if err != nil { if err != nil {
@ -133,16 +190,19 @@ func GetComputeSystems(q schema1.ComputeSystemQuery) ([]schema1.ContainerPropert
} }
query := string(queryb) query := string(queryb)
logrus.Debugf(title+" query=%s", query)
logrus.WithFields(fields).
WithField(logfields.JSON, query).
Debug("HCS ComputeSystem Query")
var ( var (
resultp *uint16 resultp *uint16
computeSystemsp *uint16 computeSystemsp *uint16
) )
completed := false
go syscallWatcher(fmt.Sprintf("GetComputeSystems %s:", query), &completed) syscallWatcher(fields, func() {
err = hcsEnumerateComputeSystems(query, &computeSystemsp, &resultp) err = hcsEnumerateComputeSystems(query, &computeSystemsp, &resultp)
completed = true })
events := processHcsResult(resultp) events := processHcsResult(resultp)
if err != nil { if err != nil {
return nil, &HcsError{Op: operation, Err: err, Events: events} return nil, &HcsError{Op: operation, Err: err, Events: events}
@ -153,20 +213,21 @@ func GetComputeSystems(q schema1.ComputeSystemQuery) ([]schema1.ContainerPropert
} }
computeSystemsRaw := interop.ConvertAndFreeCoTaskMemBytes(computeSystemsp) computeSystemsRaw := interop.ConvertAndFreeCoTaskMemBytes(computeSystemsp)
computeSystems := []schema1.ContainerProperties{} computeSystems := []schema1.ContainerProperties{}
if err := json.Unmarshal(computeSystemsRaw, &computeSystems); err != nil { if err = json.Unmarshal(computeSystemsRaw, &computeSystems); err != nil {
return nil, err return nil, err
} }
logrus.Debugf(title + " succeeded")
return computeSystems, nil return computeSystems, nil
} }
// Start synchronously starts the computeSystem. // Start synchronously starts the computeSystem.
func (computeSystem *System) Start() error { func (computeSystem *System) Start() (err error) {
computeSystem.handleLock.RLock() computeSystem.handleLock.RLock()
defer computeSystem.handleLock.RUnlock() defer computeSystem.handleLock.RUnlock()
title := "hcsshim::ComputeSystem::Start ID=" + computeSystem.ID()
logrus.Debugf(title) operation := "hcsshim::ComputeSystem::Start"
computeSystem.logOperationBegin(operation)
defer func() { computeSystem.logOperationEnd(err) }()
if computeSystem.handle == 0 { if computeSystem.handle == 0 {
return makeSystemError(computeSystem, "Start", "", ErrAlreadyClosed, nil) return makeSystemError(computeSystem, "Start", "", ErrAlreadyClosed, nil)
@ -199,16 +260,14 @@ func (computeSystem *System) Start() error {
} }
var resultp *uint16 var resultp *uint16
completed := false syscallWatcher(computeSystem.logctx, func() {
go syscallWatcher(fmt.Sprintf("StartComputeSystem %s:", computeSystem.ID()), &completed) err = hcsStartComputeSystem(computeSystem.handle, "", &resultp)
err := hcsStartComputeSystem(computeSystem.handle, "", &resultp) })
completed = true
events, err := processAsyncHcsResult(err, resultp, computeSystem.callbackNumber, hcsNotificationSystemStartCompleted, &timeout.SystemStart) events, err := processAsyncHcsResult(err, resultp, computeSystem.callbackNumber, hcsNotificationSystemStartCompleted, &timeout.SystemStart)
if err != nil { if err != nil {
return makeSystemError(computeSystem, "Start", "", err, events) return makeSystemError(computeSystem, "Start", "", err, events)
} }
logrus.Debugf(title + " succeeded")
return nil return nil
} }
@ -219,98 +278,133 @@ func (computeSystem *System) ID() string {
// Shutdown requests a compute system shutdown, if IsPending() on the error returned is true, // Shutdown requests a compute system shutdown, if IsPending() on the error returned is true,
// it may not actually be shut down until Wait() succeeds. // it may not actually be shut down until Wait() succeeds.
func (computeSystem *System) Shutdown() error { func (computeSystem *System) Shutdown() (err error) {
computeSystem.handleLock.RLock() computeSystem.handleLock.RLock()
defer computeSystem.handleLock.RUnlock() defer computeSystem.handleLock.RUnlock()
title := "hcsshim::ComputeSystem::Shutdown"
logrus.Debugf(title) operation := "hcsshim::ComputeSystem::Shutdown"
computeSystem.logOperationBegin(operation)
defer func() {
if IsAlreadyStopped(err) {
computeSystem.logOperationEnd(nil)
} else {
computeSystem.logOperationEnd(err)
}
}()
if computeSystem.handle == 0 { if computeSystem.handle == 0 {
return makeSystemError(computeSystem, "Shutdown", "", ErrAlreadyClosed, nil) return makeSystemError(computeSystem, "Shutdown", "", ErrAlreadyClosed, nil)
} }
var resultp *uint16 var resultp *uint16
completed := false syscallWatcher(computeSystem.logctx, func() {
go syscallWatcher(fmt.Sprintf("ShutdownComputeSystem %s:", computeSystem.ID()), &completed) err = hcsShutdownComputeSystem(computeSystem.handle, "", &resultp)
err := hcsShutdownComputeSystem(computeSystem.handle, "", &resultp) })
completed = true
events := processHcsResult(resultp) events := processHcsResult(resultp)
if err != nil { if err != nil {
return makeSystemError(computeSystem, "Shutdown", "", err, events) return makeSystemError(computeSystem, "Shutdown", "", err, events)
} }
logrus.Debugf(title + " succeeded")
return nil return nil
} }
// Terminate requests a compute system terminate, if IsPending() on the error returned is true, // Terminate requests a compute system terminate, if IsPending() on the error returned is true,
// it may not actually be shut down until Wait() succeeds. // it may not actually be shut down until Wait() succeeds.
func (computeSystem *System) Terminate() error { func (computeSystem *System) Terminate() (err error) {
computeSystem.handleLock.RLock() computeSystem.handleLock.RLock()
defer computeSystem.handleLock.RUnlock() defer computeSystem.handleLock.RUnlock()
title := "hcsshim::ComputeSystem::Terminate ID=" + computeSystem.ID()
logrus.Debugf(title) operation := "hcsshim::ComputeSystem::Terminate"
computeSystem.logOperationBegin(operation)
defer func() {
if IsPending(err) {
computeSystem.logOperationEnd(nil)
} else {
computeSystem.logOperationEnd(err)
}
}()
if computeSystem.handle == 0 { if computeSystem.handle == 0 {
return makeSystemError(computeSystem, "Terminate", "", ErrAlreadyClosed, nil) return makeSystemError(computeSystem, "Terminate", "", ErrAlreadyClosed, nil)
} }
var resultp *uint16 var resultp *uint16
completed := false syscallWatcher(computeSystem.logctx, func() {
go syscallWatcher(fmt.Sprintf("TerminateComputeSystem %s:", computeSystem.ID()), &completed) err = hcsTerminateComputeSystem(computeSystem.handle, "", &resultp)
err := hcsTerminateComputeSystem(computeSystem.handle, "", &resultp) })
completed = true
events := processHcsResult(resultp) events := processHcsResult(resultp)
if err != nil { if err != nil && err != ErrVmcomputeAlreadyStopped {
return makeSystemError(computeSystem, "Terminate", "", err, events) return makeSystemError(computeSystem, "Terminate", "", err, events)
} }
logrus.Debugf(title + " succeeded")
return nil return nil
} }
// Wait synchronously waits for the compute system to shutdown or terminate. // Wait synchronously waits for the compute system to shutdown or terminate.
func (computeSystem *System) Wait() error { func (computeSystem *System) Wait() (err error) {
title := "hcsshim::ComputeSystem::Wait ID=" + computeSystem.ID() operation := "hcsshim::ComputeSystem::Wait"
logrus.Debugf(title) computeSystem.logOperationBegin(operation)
defer func() { computeSystem.logOperationEnd(err) }()
err := waitForNotification(computeSystem.callbackNumber, hcsNotificationSystemExited, nil) err = waitForNotification(computeSystem.callbackNumber, hcsNotificationSystemExited, nil)
if err != nil { if err != nil {
return makeSystemError(computeSystem, "Wait", "", err, nil) return makeSystemError(computeSystem, "Wait", "", err, nil)
} }
logrus.Debugf(title + " succeeded") return nil
}
// WaitExpectedError synchronously waits for the compute system to shutdown or
// terminate, and ignores the passed error if it occurs.
func (computeSystem *System) WaitExpectedError(expected error) (err error) {
operation := "hcsshim::ComputeSystem::WaitExpectedError"
computeSystem.logOperationBegin(operation)
defer func() { computeSystem.logOperationEnd(err) }()
err = waitForNotification(computeSystem.callbackNumber, hcsNotificationSystemExited, nil)
if err != nil && err != expected {
return makeSystemError(computeSystem, "WaitExpectedError", "", err, nil)
}
return nil return nil
} }
// WaitTimeout synchronously waits for the compute system to terminate or the duration to elapse. // WaitTimeout synchronously waits for the compute system to terminate or the duration to elapse.
// If the timeout expires, IsTimeout(err) == true // If the timeout expires, IsTimeout(err) == true
func (computeSystem *System) WaitTimeout(timeout time.Duration) error { func (computeSystem *System) WaitTimeout(timeout time.Duration) (err error) {
title := "hcsshim::ComputeSystem::WaitTimeout ID=" + computeSystem.ID() operation := "hcsshim::ComputeSystem::WaitTimeout"
logrus.Debugf(title) computeSystem.logOperationBegin(operation)
defer func() { computeSystem.logOperationEnd(err) }()
err := waitForNotification(computeSystem.callbackNumber, hcsNotificationSystemExited, &timeout) err = waitForNotification(computeSystem.callbackNumber, hcsNotificationSystemExited, &timeout)
if err != nil { if err != nil {
return makeSystemError(computeSystem, "WaitTimeout", "", err, nil) return makeSystemError(computeSystem, "WaitTimeout", "", err, nil)
} }
logrus.Debugf(title + " succeeded")
return nil return nil
} }
func (computeSystem *System) Properties(types ...schema1.PropertyType) (*schema1.ContainerProperties, error) { func (computeSystem *System) Properties(types ...schema1.PropertyType) (_ *schema1.ContainerProperties, err error) {
computeSystem.handleLock.RLock() computeSystem.handleLock.RLock()
defer computeSystem.handleLock.RUnlock() defer computeSystem.handleLock.RUnlock()
operation := "hcsshim::ComputeSystem::Properties"
computeSystem.logOperationBegin(operation)
defer func() { computeSystem.logOperationEnd(err) }()
queryj, err := json.Marshal(schema1.PropertyQuery{types}) queryj, err := json.Marshal(schema1.PropertyQuery{types})
if err != nil { if err != nil {
return nil, makeSystemError(computeSystem, "Properties", "", err, nil) return nil, makeSystemError(computeSystem, "Properties", "", err, nil)
} }
logrus.WithFields(computeSystem.logctx).
WithField(logfields.JSON, queryj).
Debug("HCS ComputeSystem Properties Query")
var resultp, propertiesp *uint16 var resultp, propertiesp *uint16
completed := false syscallWatcher(computeSystem.logctx, func() {
go syscallWatcher(fmt.Sprintf("GetComputeSystemProperties %s:", computeSystem.ID()), &completed) err = hcsGetComputeSystemProperties(computeSystem.handle, string(queryj), &propertiesp, &resultp)
err = hcsGetComputeSystemProperties(computeSystem.handle, string(queryj), &propertiesp, &resultp) })
completed = true
events := processHcsResult(resultp) events := processHcsResult(resultp)
if err != nil { if err != nil {
return nil, makeSystemError(computeSystem, "Properties", "", err, events) return nil, makeSystemError(computeSystem, "Properties", "", err, events)
@ -324,64 +418,69 @@ func (computeSystem *System) Properties(types ...schema1.PropertyType) (*schema1
if err := json.Unmarshal(propertiesRaw, properties); err != nil { if err := json.Unmarshal(propertiesRaw, properties); err != nil {
return nil, makeSystemError(computeSystem, "Properties", "", err, nil) return nil, makeSystemError(computeSystem, "Properties", "", err, nil)
} }
return properties, nil return properties, nil
} }
// Pause pauses the execution of the computeSystem. This feature is not enabled in TP5. // Pause pauses the execution of the computeSystem. This feature is not enabled in TP5.
func (computeSystem *System) Pause() error { func (computeSystem *System) Pause() (err error) {
computeSystem.handleLock.RLock() computeSystem.handleLock.RLock()
defer computeSystem.handleLock.RUnlock() defer computeSystem.handleLock.RUnlock()
title := "hcsshim::ComputeSystem::Pause ID=" + computeSystem.ID()
logrus.Debugf(title) operation := "hcsshim::ComputeSystem::Pause"
computeSystem.logOperationBegin(operation)
defer func() { computeSystem.logOperationEnd(err) }()
if computeSystem.handle == 0 { if computeSystem.handle == 0 {
return makeSystemError(computeSystem, "Pause", "", ErrAlreadyClosed, nil) return makeSystemError(computeSystem, "Pause", "", ErrAlreadyClosed, nil)
} }
var resultp *uint16 var resultp *uint16
completed := false syscallWatcher(computeSystem.logctx, func() {
go syscallWatcher(fmt.Sprintf("PauseComputeSystem %s:", computeSystem.ID()), &completed) err = hcsPauseComputeSystem(computeSystem.handle, "", &resultp)
err := hcsPauseComputeSystem(computeSystem.handle, "", &resultp) })
completed = true
events, err := processAsyncHcsResult(err, resultp, computeSystem.callbackNumber, hcsNotificationSystemPauseCompleted, &timeout.SystemPause) events, err := processAsyncHcsResult(err, resultp, computeSystem.callbackNumber, hcsNotificationSystemPauseCompleted, &timeout.SystemPause)
if err != nil { if err != nil {
return makeSystemError(computeSystem, "Pause", "", err, events) return makeSystemError(computeSystem, "Pause", "", err, events)
} }
logrus.Debugf(title + " succeeded")
return nil return nil
} }
// Resume resumes the execution of the computeSystem. This feature is not enabled in TP5. // Resume resumes the execution of the computeSystem. This feature is not enabled in TP5.
func (computeSystem *System) Resume() error { func (computeSystem *System) Resume() (err error) {
computeSystem.handleLock.RLock() computeSystem.handleLock.RLock()
defer computeSystem.handleLock.RUnlock() defer computeSystem.handleLock.RUnlock()
title := "hcsshim::ComputeSystem::Resume ID=" + computeSystem.ID()
logrus.Debugf(title) operation := "hcsshim::ComputeSystem::Resume"
computeSystem.logOperationBegin(operation)
defer func() { computeSystem.logOperationEnd(err) }()
if computeSystem.handle == 0 { if computeSystem.handle == 0 {
return makeSystemError(computeSystem, "Resume", "", ErrAlreadyClosed, nil) return makeSystemError(computeSystem, "Resume", "", ErrAlreadyClosed, nil)
} }
var resultp *uint16 var resultp *uint16
completed := false syscallWatcher(computeSystem.logctx, func() {
go syscallWatcher(fmt.Sprintf("ResumeComputeSystem %s:", computeSystem.ID()), &completed) err = hcsResumeComputeSystem(computeSystem.handle, "", &resultp)
err := hcsResumeComputeSystem(computeSystem.handle, "", &resultp) })
completed = true
events, err := processAsyncHcsResult(err, resultp, computeSystem.callbackNumber, hcsNotificationSystemResumeCompleted, &timeout.SystemResume) events, err := processAsyncHcsResult(err, resultp, computeSystem.callbackNumber, hcsNotificationSystemResumeCompleted, &timeout.SystemResume)
if err != nil { if err != nil {
return makeSystemError(computeSystem, "Resume", "", err, events) return makeSystemError(computeSystem, "Resume", "", err, events)
} }
logrus.Debugf(title + " succeeded")
return nil return nil
} }
// CreateProcess launches a new process within the computeSystem. // CreateProcess launches a new process within the computeSystem.
func (computeSystem *System) CreateProcess(c interface{}) (*Process, error) { func (computeSystem *System) CreateProcess(c interface{}) (_ *Process, err error) {
computeSystem.handleLock.RLock() computeSystem.handleLock.RLock()
defer computeSystem.handleLock.RUnlock() defer computeSystem.handleLock.RUnlock()
title := "hcsshim::ComputeSystem::CreateProcess ID=" + computeSystem.ID()
operation := "hcsshim::ComputeSystem::CreateProcess"
computeSystem.logOperationBegin(operation)
defer func() { computeSystem.logOperationEnd(err) }()
var ( var (
processInfo hcsProcessInformation processInfo hcsProcessInformation
processHandle hcsProcess processHandle hcsProcess
@ -398,42 +497,50 @@ func (computeSystem *System) CreateProcess(c interface{}) (*Process, error) {
} }
configuration := string(configurationb) configuration := string(configurationb)
logrus.Debugf(title+" config=%s", configuration)
completed := false logrus.WithFields(computeSystem.logctx).
go syscallWatcher(fmt.Sprintf("CreateProcess %s: %s", computeSystem.ID(), configuration), &completed) WithField(logfields.JSON, configuration).
err = hcsCreateProcess(computeSystem.handle, configuration, &processInfo, &processHandle, &resultp) Debug("HCS ComputeSystem Process Document")
completed = true
syscallWatcher(computeSystem.logctx, func() {
err = hcsCreateProcess(computeSystem.handle, configuration, &processInfo, &processHandle, &resultp)
})
events := processHcsResult(resultp) events := processHcsResult(resultp)
if err != nil { if err != nil {
return nil, makeSystemError(computeSystem, "CreateProcess", configuration, err, events) return nil, makeSystemError(computeSystem, "CreateProcess", configuration, err, events)
} }
process := &Process{ logrus.WithFields(computeSystem.logctx).
handle: processHandle, WithField(logfields.ProcessID, processInfo.ProcessId).
processID: int(processInfo.ProcessId), Debug("HCS ComputeSystem CreateProcess PID")
system: computeSystem,
cachedPipes: &cachedPipes{ process := newProcess(processHandle, int(processInfo.ProcessId), computeSystem)
stdIn: processInfo.StdInput, process.cachedPipes = &cachedPipes{
stdOut: processInfo.StdOutput, stdIn: processInfo.StdInput,
stdErr: processInfo.StdError, stdOut: processInfo.StdOutput,
}, stdErr: processInfo.StdError,
} }
if err := process.registerCallback(); err != nil { if err = process.registerCallback(); err != nil {
return nil, makeSystemError(computeSystem, "CreateProcess", "", err, nil) return nil, makeSystemError(computeSystem, "CreateProcess", "", err, nil)
} }
logrus.Debugf(title+" succeeded processid=%d", process.processID)
return process, nil return process, nil
} }
// OpenProcess gets an interface to an existing process within the computeSystem. // OpenProcess gets an interface to an existing process within the computeSystem.
func (computeSystem *System) OpenProcess(pid int) (*Process, error) { func (computeSystem *System) OpenProcess(pid int) (_ *Process, err error) {
computeSystem.handleLock.RLock() computeSystem.handleLock.RLock()
defer computeSystem.handleLock.RUnlock() defer computeSystem.handleLock.RUnlock()
title := "hcsshim::ComputeSystem::OpenProcess ID=" + computeSystem.ID()
logrus.Debugf(title+" processid=%d", pid) // Add PID for the context of this operation
computeSystem.logctx[logfields.ProcessID] = pid
defer delete(computeSystem.logctx, logfields.ProcessID)
operation := "hcsshim::ComputeSystem::OpenProcess"
computeSystem.logOperationBegin(operation)
defer func() { computeSystem.logOperationEnd(err) }()
var ( var (
processHandle hcsProcess processHandle hcsProcess
resultp *uint16 resultp *uint16
@ -443,56 +550,49 @@ func (computeSystem *System) OpenProcess(pid int) (*Process, error) {
return nil, makeSystemError(computeSystem, "OpenProcess", "", ErrAlreadyClosed, nil) return nil, makeSystemError(computeSystem, "OpenProcess", "", ErrAlreadyClosed, nil)
} }
completed := false syscallWatcher(computeSystem.logctx, func() {
go syscallWatcher(fmt.Sprintf("OpenProcess %s: %d", computeSystem.ID(), pid), &completed) err = hcsOpenProcess(computeSystem.handle, uint32(pid), &processHandle, &resultp)
err := hcsOpenProcess(computeSystem.handle, uint32(pid), &processHandle, &resultp) })
completed = true
events := processHcsResult(resultp) events := processHcsResult(resultp)
if err != nil { if err != nil {
return nil, makeSystemError(computeSystem, "OpenProcess", "", err, events) return nil, makeSystemError(computeSystem, "OpenProcess", "", err, events)
} }
process := &Process{ process := newProcess(processHandle, pid, computeSystem)
handle: processHandle, if err = process.registerCallback(); err != nil {
processID: pid,
system: computeSystem,
}
if err := process.registerCallback(); err != nil {
return nil, makeSystemError(computeSystem, "OpenProcess", "", err, nil) return nil, makeSystemError(computeSystem, "OpenProcess", "", err, nil)
} }
logrus.Debugf(title+" succeeded processid=%s", process.processID)
return process, nil return process, nil
} }
// Close cleans up any state associated with the compute system but does not terminate or wait for it. // Close cleans up any state associated with the compute system but does not terminate or wait for it.
func (computeSystem *System) Close() error { func (computeSystem *System) Close() (err error) {
computeSystem.handleLock.Lock() computeSystem.handleLock.Lock()
defer computeSystem.handleLock.Unlock() defer computeSystem.handleLock.Unlock()
title := "hcsshim::ComputeSystem::Close ID=" + computeSystem.ID()
logrus.Debugf(title) operation := "hcsshim::ComputeSystem::Close"
computeSystem.logOperationBegin(operation)
defer func() { computeSystem.logOperationEnd(err) }()
// Don't double free this // Don't double free this
if computeSystem.handle == 0 { if computeSystem.handle == 0 {
return nil return nil
} }
if err := computeSystem.unregisterCallback(); err != nil { if err = computeSystem.unregisterCallback(); err != nil {
return makeSystemError(computeSystem, "Close", "", err, nil) return makeSystemError(computeSystem, "Close", "", err, nil)
} }
completed := false syscallWatcher(computeSystem.logctx, func() {
go syscallWatcher(fmt.Sprintf("CloseComputeSystem %s:", computeSystem.ID()), &completed) err = hcsCloseComputeSystem(computeSystem.handle)
err := hcsCloseComputeSystem(computeSystem.handle) })
completed = true
if err != nil { if err != nil {
return makeSystemError(computeSystem, "Close", "", err, nil) return makeSystemError(computeSystem, "Close", "", err, nil)
} }
computeSystem.handle = 0 computeSystem.handle = 0
logrus.Debugf(title + " succeeded")
return nil return nil
} }
@ -553,11 +653,14 @@ func (computeSystem *System) unregisterCallback() error {
return nil return nil
} }
// Modifies the System by sending a request to HCS // Modify the System by sending a request to HCS
func (computeSystem *System) Modify(config interface{}) error { func (computeSystem *System) Modify(config interface{}) (err error) {
computeSystem.handleLock.RLock() computeSystem.handleLock.RLock()
defer computeSystem.handleLock.RUnlock() defer computeSystem.handleLock.RUnlock()
title := "hcsshim::Modify ID=" + computeSystem.id
operation := "hcsshim::ComputeSystem::Modify"
computeSystem.logOperationBegin(operation)
defer func() { computeSystem.logOperationEnd(err) }()
if computeSystem.handle == 0 { if computeSystem.handle == 0 {
return makeSystemError(computeSystem, "Modify", "", ErrAlreadyClosed, nil) return makeSystemError(computeSystem, "Modify", "", ErrAlreadyClosed, nil)
@ -569,17 +672,19 @@ func (computeSystem *System) Modify(config interface{}) error {
} }
requestString := string(requestJSON) requestString := string(requestJSON)
logrus.Debugf(title + " " + requestString)
logrus.WithFields(computeSystem.logctx).
WithField(logfields.JSON, requestString).
Debug("HCS ComputeSystem Modify Document")
var resultp *uint16 var resultp *uint16
completed := false syscallWatcher(computeSystem.logctx, func() {
go syscallWatcher(fmt.Sprintf("ModifyComputeSystem %s: %s", computeSystem.ID(), requestString), &completed) err = hcsModifyComputeSystem(computeSystem.handle, requestString, &resultp)
err = hcsModifyComputeSystem(computeSystem.handle, requestString, &resultp) })
completed = true
events := processHcsResult(resultp) events := processHcsResult(resultp)
if err != nil { if err != nil {
return makeSystemError(computeSystem, "Modify", requestString, err, events) return makeSystemError(computeSystem, "Modify", requestString, err, events)
} }
logrus.Debugf(title + " succeeded ")
return nil return nil
} }

View File

@ -1,8 +1,9 @@
package hcs package hcs
import ( import (
"time" "context"
"github.com/Microsoft/hcsshim/internal/logfields"
"github.com/Microsoft/hcsshim/internal/timeout" "github.com/Microsoft/hcsshim/internal/timeout"
"github.com/sirupsen/logrus" "github.com/sirupsen/logrus"
) )
@ -16,15 +17,25 @@ import (
// //
// Usage is: // Usage is:
// //
// completed := false // syscallWatcher(logContext, func() {
// go syscallWatcher("some description", &completed) // err = <syscall>(args...)
// <syscall> // })
// completed = true
// //
func syscallWatcher(description string, syscallCompleted *bool) {
time.Sleep(timeout.SyscallWatcher) func syscallWatcher(logContext logrus.Fields, syscallLambda func()) {
if *syscallCompleted { ctx, cancel := context.WithTimeout(context.Background(), timeout.SyscallWatcher)
return defer cancel()
} go watchFunc(ctx, logContext)
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) syscallLambda()
}
func watchFunc(ctx context.Context, logContext logrus.Fields) {
select {
case <-ctx.Done():
if ctx.Err() != context.Canceled {
logrus.WithFields(logContext).
WithField(logfields.Timeout, timeout.SyscallWatcher).
Warning("Syscall did not complete within operation timeout. This may indicate a platform issue. If it appears to be making no forward progress, obtain the stacks and see if there is a syscall stuck in the platform API for a significant length of time.")
}
}
} }

View File

@ -1,4 +1,4 @@
// MACHINE GENERATED BY 'go generate' COMMAND; DO NOT EDIT // Code generated mksyscall_windows.exe DO NOT EDIT
package hcs package hcs
@ -6,7 +6,6 @@ import (
"syscall" "syscall"
"unsafe" "unsafe"
"github.com/Microsoft/hcsshim/internal/interop"
"golang.org/x/sys/windows" "golang.org/x/sys/windows"
) )
@ -81,7 +80,10 @@ func _hcsEnumerateComputeSystems(query *uint16, computeSystems **uint16, result
} }
r0, _, _ := syscall.Syscall(procHcsEnumerateComputeSystems.Addr(), 3, uintptr(unsafe.Pointer(query)), uintptr(unsafe.Pointer(computeSystems)), uintptr(unsafe.Pointer(result))) r0, _, _ := syscall.Syscall(procHcsEnumerateComputeSystems.Addr(), 3, uintptr(unsafe.Pointer(query)), uintptr(unsafe.Pointer(computeSystems)), uintptr(unsafe.Pointer(result)))
if int32(r0) < 0 { if int32(r0) < 0 {
hr = interop.Win32FromHresult(r0) if r0&0x1fff0000 == 0x00070000 {
r0 &= 0xffff
}
hr = syscall.Errno(r0)
} }
return return
} }
@ -106,7 +108,10 @@ func _hcsCreateComputeSystem(id *uint16, configuration *uint16, identity syscall
} }
r0, _, _ := syscall.Syscall6(procHcsCreateComputeSystem.Addr(), 5, uintptr(unsafe.Pointer(id)), uintptr(unsafe.Pointer(configuration)), uintptr(identity), uintptr(unsafe.Pointer(computeSystem)), uintptr(unsafe.Pointer(result)), 0) r0, _, _ := syscall.Syscall6(procHcsCreateComputeSystem.Addr(), 5, uintptr(unsafe.Pointer(id)), uintptr(unsafe.Pointer(configuration)), uintptr(identity), uintptr(unsafe.Pointer(computeSystem)), uintptr(unsafe.Pointer(result)), 0)
if int32(r0) < 0 { if int32(r0) < 0 {
hr = interop.Win32FromHresult(r0) if r0&0x1fff0000 == 0x00070000 {
r0 &= 0xffff
}
hr = syscall.Errno(r0)
} }
return return
} }
@ -126,7 +131,10 @@ func _hcsOpenComputeSystem(id *uint16, computeSystem *hcsSystem, result **uint16
} }
r0, _, _ := syscall.Syscall(procHcsOpenComputeSystem.Addr(), 3, uintptr(unsafe.Pointer(id)), uintptr(unsafe.Pointer(computeSystem)), uintptr(unsafe.Pointer(result))) r0, _, _ := syscall.Syscall(procHcsOpenComputeSystem.Addr(), 3, uintptr(unsafe.Pointer(id)), uintptr(unsafe.Pointer(computeSystem)), uintptr(unsafe.Pointer(result)))
if int32(r0) < 0 { if int32(r0) < 0 {
hr = interop.Win32FromHresult(r0) if r0&0x1fff0000 == 0x00070000 {
r0 &= 0xffff
}
hr = syscall.Errno(r0)
} }
return return
} }
@ -137,7 +145,10 @@ func hcsCloseComputeSystem(computeSystem hcsSystem) (hr error) {
} }
r0, _, _ := syscall.Syscall(procHcsCloseComputeSystem.Addr(), 1, uintptr(computeSystem), 0, 0) r0, _, _ := syscall.Syscall(procHcsCloseComputeSystem.Addr(), 1, uintptr(computeSystem), 0, 0)
if int32(r0) < 0 { if int32(r0) < 0 {
hr = interop.Win32FromHresult(r0) if r0&0x1fff0000 == 0x00070000 {
r0 &= 0xffff
}
hr = syscall.Errno(r0)
} }
return return
} }
@ -157,7 +168,10 @@ func _hcsStartComputeSystem(computeSystem hcsSystem, options *uint16, result **u
} }
r0, _, _ := syscall.Syscall(procHcsStartComputeSystem.Addr(), 3, uintptr(computeSystem), uintptr(unsafe.Pointer(options)), uintptr(unsafe.Pointer(result))) r0, _, _ := syscall.Syscall(procHcsStartComputeSystem.Addr(), 3, uintptr(computeSystem), uintptr(unsafe.Pointer(options)), uintptr(unsafe.Pointer(result)))
if int32(r0) < 0 { if int32(r0) < 0 {
hr = interop.Win32FromHresult(r0) if r0&0x1fff0000 == 0x00070000 {
r0 &= 0xffff
}
hr = syscall.Errno(r0)
} }
return return
} }
@ -177,7 +191,10 @@ func _hcsShutdownComputeSystem(computeSystem hcsSystem, options *uint16, result
} }
r0, _, _ := syscall.Syscall(procHcsShutdownComputeSystem.Addr(), 3, uintptr(computeSystem), uintptr(unsafe.Pointer(options)), uintptr(unsafe.Pointer(result))) r0, _, _ := syscall.Syscall(procHcsShutdownComputeSystem.Addr(), 3, uintptr(computeSystem), uintptr(unsafe.Pointer(options)), uintptr(unsafe.Pointer(result)))
if int32(r0) < 0 { if int32(r0) < 0 {
hr = interop.Win32FromHresult(r0) if r0&0x1fff0000 == 0x00070000 {
r0 &= 0xffff
}
hr = syscall.Errno(r0)
} }
return return
} }
@ -197,7 +214,10 @@ func _hcsTerminateComputeSystem(computeSystem hcsSystem, options *uint16, result
} }
r0, _, _ := syscall.Syscall(procHcsTerminateComputeSystem.Addr(), 3, uintptr(computeSystem), uintptr(unsafe.Pointer(options)), uintptr(unsafe.Pointer(result))) r0, _, _ := syscall.Syscall(procHcsTerminateComputeSystem.Addr(), 3, uintptr(computeSystem), uintptr(unsafe.Pointer(options)), uintptr(unsafe.Pointer(result)))
if int32(r0) < 0 { if int32(r0) < 0 {
hr = interop.Win32FromHresult(r0) if r0&0x1fff0000 == 0x00070000 {
r0 &= 0xffff
}
hr = syscall.Errno(r0)
} }
return return
} }
@ -217,7 +237,10 @@ func _hcsPauseComputeSystem(computeSystem hcsSystem, options *uint16, result **u
} }
r0, _, _ := syscall.Syscall(procHcsPauseComputeSystem.Addr(), 3, uintptr(computeSystem), uintptr(unsafe.Pointer(options)), uintptr(unsafe.Pointer(result))) r0, _, _ := syscall.Syscall(procHcsPauseComputeSystem.Addr(), 3, uintptr(computeSystem), uintptr(unsafe.Pointer(options)), uintptr(unsafe.Pointer(result)))
if int32(r0) < 0 { if int32(r0) < 0 {
hr = interop.Win32FromHresult(r0) if r0&0x1fff0000 == 0x00070000 {
r0 &= 0xffff
}
hr = syscall.Errno(r0)
} }
return return
} }
@ -237,7 +260,10 @@ func _hcsResumeComputeSystem(computeSystem hcsSystem, options *uint16, result **
} }
r0, _, _ := syscall.Syscall(procHcsResumeComputeSystem.Addr(), 3, uintptr(computeSystem), uintptr(unsafe.Pointer(options)), uintptr(unsafe.Pointer(result))) r0, _, _ := syscall.Syscall(procHcsResumeComputeSystem.Addr(), 3, uintptr(computeSystem), uintptr(unsafe.Pointer(options)), uintptr(unsafe.Pointer(result)))
if int32(r0) < 0 { if int32(r0) < 0 {
hr = interop.Win32FromHresult(r0) if r0&0x1fff0000 == 0x00070000 {
r0 &= 0xffff
}
hr = syscall.Errno(r0)
} }
return return
} }
@ -257,7 +283,10 @@ func _hcsGetComputeSystemProperties(computeSystem hcsSystem, propertyQuery *uint
} }
r0, _, _ := syscall.Syscall6(procHcsGetComputeSystemProperties.Addr(), 4, uintptr(computeSystem), uintptr(unsafe.Pointer(propertyQuery)), uintptr(unsafe.Pointer(properties)), uintptr(unsafe.Pointer(result)), 0, 0) r0, _, _ := syscall.Syscall6(procHcsGetComputeSystemProperties.Addr(), 4, uintptr(computeSystem), uintptr(unsafe.Pointer(propertyQuery)), uintptr(unsafe.Pointer(properties)), uintptr(unsafe.Pointer(result)), 0, 0)
if int32(r0) < 0 { if int32(r0) < 0 {
hr = interop.Win32FromHresult(r0) if r0&0x1fff0000 == 0x00070000 {
r0 &= 0xffff
}
hr = syscall.Errno(r0)
} }
return return
} }
@ -277,7 +306,10 @@ func _hcsModifyComputeSystem(computeSystem hcsSystem, configuration *uint16, res
} }
r0, _, _ := syscall.Syscall(procHcsModifyComputeSystem.Addr(), 3, uintptr(computeSystem), uintptr(unsafe.Pointer(configuration)), uintptr(unsafe.Pointer(result))) r0, _, _ := syscall.Syscall(procHcsModifyComputeSystem.Addr(), 3, uintptr(computeSystem), uintptr(unsafe.Pointer(configuration)), uintptr(unsafe.Pointer(result)))
if int32(r0) < 0 { if int32(r0) < 0 {
hr = interop.Win32FromHresult(r0) if r0&0x1fff0000 == 0x00070000 {
r0 &= 0xffff
}
hr = syscall.Errno(r0)
} }
return return
} }
@ -288,7 +320,10 @@ func hcsRegisterComputeSystemCallback(computeSystem hcsSystem, callback uintptr,
} }
r0, _, _ := syscall.Syscall6(procHcsRegisterComputeSystemCallback.Addr(), 4, uintptr(computeSystem), uintptr(callback), uintptr(context), uintptr(unsafe.Pointer(callbackHandle)), 0, 0) r0, _, _ := syscall.Syscall6(procHcsRegisterComputeSystemCallback.Addr(), 4, uintptr(computeSystem), uintptr(callback), uintptr(context), uintptr(unsafe.Pointer(callbackHandle)), 0, 0)
if int32(r0) < 0 { if int32(r0) < 0 {
hr = interop.Win32FromHresult(r0) if r0&0x1fff0000 == 0x00070000 {
r0 &= 0xffff
}
hr = syscall.Errno(r0)
} }
return return
} }
@ -299,7 +334,10 @@ func hcsUnregisterComputeSystemCallback(callbackHandle hcsCallback) (hr error) {
} }
r0, _, _ := syscall.Syscall(procHcsUnregisterComputeSystemCallback.Addr(), 1, uintptr(callbackHandle), 0, 0) r0, _, _ := syscall.Syscall(procHcsUnregisterComputeSystemCallback.Addr(), 1, uintptr(callbackHandle), 0, 0)
if int32(r0) < 0 { if int32(r0) < 0 {
hr = interop.Win32FromHresult(r0) if r0&0x1fff0000 == 0x00070000 {
r0 &= 0xffff
}
hr = syscall.Errno(r0)
} }
return return
} }
@ -319,7 +357,10 @@ func _hcsCreateProcess(computeSystem hcsSystem, processParameters *uint16, proce
} }
r0, _, _ := syscall.Syscall6(procHcsCreateProcess.Addr(), 5, uintptr(computeSystem), uintptr(unsafe.Pointer(processParameters)), uintptr(unsafe.Pointer(processInformation)), uintptr(unsafe.Pointer(process)), uintptr(unsafe.Pointer(result)), 0) r0, _, _ := syscall.Syscall6(procHcsCreateProcess.Addr(), 5, uintptr(computeSystem), uintptr(unsafe.Pointer(processParameters)), uintptr(unsafe.Pointer(processInformation)), uintptr(unsafe.Pointer(process)), uintptr(unsafe.Pointer(result)), 0)
if int32(r0) < 0 { if int32(r0) < 0 {
hr = interop.Win32FromHresult(r0) if r0&0x1fff0000 == 0x00070000 {
r0 &= 0xffff
}
hr = syscall.Errno(r0)
} }
return return
} }
@ -330,7 +371,10 @@ func hcsOpenProcess(computeSystem hcsSystem, pid uint32, process *hcsProcess, re
} }
r0, _, _ := syscall.Syscall6(procHcsOpenProcess.Addr(), 4, uintptr(computeSystem), uintptr(pid), uintptr(unsafe.Pointer(process)), uintptr(unsafe.Pointer(result)), 0, 0) r0, _, _ := syscall.Syscall6(procHcsOpenProcess.Addr(), 4, uintptr(computeSystem), uintptr(pid), uintptr(unsafe.Pointer(process)), uintptr(unsafe.Pointer(result)), 0, 0)
if int32(r0) < 0 { if int32(r0) < 0 {
hr = interop.Win32FromHresult(r0) if r0&0x1fff0000 == 0x00070000 {
r0 &= 0xffff
}
hr = syscall.Errno(r0)
} }
return return
} }
@ -341,7 +385,10 @@ func hcsCloseProcess(process hcsProcess) (hr error) {
} }
r0, _, _ := syscall.Syscall(procHcsCloseProcess.Addr(), 1, uintptr(process), 0, 0) r0, _, _ := syscall.Syscall(procHcsCloseProcess.Addr(), 1, uintptr(process), 0, 0)
if int32(r0) < 0 { if int32(r0) < 0 {
hr = interop.Win32FromHresult(r0) if r0&0x1fff0000 == 0x00070000 {
r0 &= 0xffff
}
hr = syscall.Errno(r0)
} }
return return
} }
@ -352,7 +399,10 @@ func hcsTerminateProcess(process hcsProcess, result **uint16) (hr error) {
} }
r0, _, _ := syscall.Syscall(procHcsTerminateProcess.Addr(), 2, uintptr(process), uintptr(unsafe.Pointer(result)), 0) r0, _, _ := syscall.Syscall(procHcsTerminateProcess.Addr(), 2, uintptr(process), uintptr(unsafe.Pointer(result)), 0)
if int32(r0) < 0 { if int32(r0) < 0 {
hr = interop.Win32FromHresult(r0) if r0&0x1fff0000 == 0x00070000 {
r0 &= 0xffff
}
hr = syscall.Errno(r0)
} }
return return
} }
@ -372,7 +422,10 @@ func _hcsSignalProcess(process hcsProcess, options *uint16, result **uint16) (hr
} }
r0, _, _ := syscall.Syscall(procHcsTerminateProcess.Addr(), 3, uintptr(process), uintptr(unsafe.Pointer(options)), uintptr(unsafe.Pointer(result))) r0, _, _ := syscall.Syscall(procHcsTerminateProcess.Addr(), 3, uintptr(process), uintptr(unsafe.Pointer(options)), uintptr(unsafe.Pointer(result)))
if int32(r0) < 0 { if int32(r0) < 0 {
hr = interop.Win32FromHresult(r0) if r0&0x1fff0000 == 0x00070000 {
r0 &= 0xffff
}
hr = syscall.Errno(r0)
} }
return return
} }
@ -383,7 +436,10 @@ func hcsGetProcessInfo(process hcsProcess, processInformation *hcsProcessInforma
} }
r0, _, _ := syscall.Syscall(procHcsGetProcessInfo.Addr(), 3, uintptr(process), uintptr(unsafe.Pointer(processInformation)), uintptr(unsafe.Pointer(result))) r0, _, _ := syscall.Syscall(procHcsGetProcessInfo.Addr(), 3, uintptr(process), uintptr(unsafe.Pointer(processInformation)), uintptr(unsafe.Pointer(result)))
if int32(r0) < 0 { if int32(r0) < 0 {
hr = interop.Win32FromHresult(r0) if r0&0x1fff0000 == 0x00070000 {
r0 &= 0xffff
}
hr = syscall.Errno(r0)
} }
return return
} }
@ -394,7 +450,10 @@ func hcsGetProcessProperties(process hcsProcess, processProperties **uint16, res
} }
r0, _, _ := syscall.Syscall(procHcsGetProcessProperties.Addr(), 3, uintptr(process), uintptr(unsafe.Pointer(processProperties)), uintptr(unsafe.Pointer(result))) r0, _, _ := syscall.Syscall(procHcsGetProcessProperties.Addr(), 3, uintptr(process), uintptr(unsafe.Pointer(processProperties)), uintptr(unsafe.Pointer(result)))
if int32(r0) < 0 { if int32(r0) < 0 {
hr = interop.Win32FromHresult(r0) if r0&0x1fff0000 == 0x00070000 {
r0 &= 0xffff
}
hr = syscall.Errno(r0)
} }
return return
} }
@ -414,7 +473,10 @@ func _hcsModifyProcess(process hcsProcess, settings *uint16, result **uint16) (h
} }
r0, _, _ := syscall.Syscall(procHcsModifyProcess.Addr(), 3, uintptr(process), uintptr(unsafe.Pointer(settings)), uintptr(unsafe.Pointer(result))) r0, _, _ := syscall.Syscall(procHcsModifyProcess.Addr(), 3, uintptr(process), uintptr(unsafe.Pointer(settings)), uintptr(unsafe.Pointer(result)))
if int32(r0) < 0 { if int32(r0) < 0 {
hr = interop.Win32FromHresult(r0) if r0&0x1fff0000 == 0x00070000 {
r0 &= 0xffff
}
hr = syscall.Errno(r0)
} }
return return
} }
@ -434,7 +496,10 @@ func _hcsGetServiceProperties(propertyQuery *uint16, properties **uint16, result
} }
r0, _, _ := syscall.Syscall(procHcsGetServiceProperties.Addr(), 3, uintptr(unsafe.Pointer(propertyQuery)), uintptr(unsafe.Pointer(properties)), uintptr(unsafe.Pointer(result))) r0, _, _ := syscall.Syscall(procHcsGetServiceProperties.Addr(), 3, uintptr(unsafe.Pointer(propertyQuery)), uintptr(unsafe.Pointer(properties)), uintptr(unsafe.Pointer(result)))
if int32(r0) < 0 { if int32(r0) < 0 {
hr = interop.Win32FromHresult(r0) if r0&0x1fff0000 == 0x00070000 {
r0 &= 0xffff
}
hr = syscall.Errno(r0)
} }
return return
} }
@ -445,7 +510,10 @@ func hcsRegisterProcessCallback(process hcsProcess, callback uintptr, context ui
} }
r0, _, _ := syscall.Syscall6(procHcsRegisterProcessCallback.Addr(), 4, uintptr(process), uintptr(callback), uintptr(context), uintptr(unsafe.Pointer(callbackHandle)), 0, 0) r0, _, _ := syscall.Syscall6(procHcsRegisterProcessCallback.Addr(), 4, uintptr(process), uintptr(callback), uintptr(context), uintptr(unsafe.Pointer(callbackHandle)), 0, 0)
if int32(r0) < 0 { if int32(r0) < 0 {
hr = interop.Win32FromHresult(r0) if r0&0x1fff0000 == 0x00070000 {
r0 &= 0xffff
}
hr = syscall.Errno(r0)
} }
return return
} }
@ -456,7 +524,10 @@ func hcsUnregisterProcessCallback(callbackHandle hcsCallback) (hr error) {
} }
r0, _, _ := syscall.Syscall(procHcsUnregisterProcessCallback.Addr(), 1, uintptr(callbackHandle), 0, 0) r0, _, _ := syscall.Syscall(procHcsUnregisterProcessCallback.Addr(), 1, uintptr(callbackHandle), 0, 0)
if int32(r0) < 0 { if int32(r0) < 0 {
hr = interop.Win32FromHresult(r0) if r0&0x1fff0000 == 0x00070000 {
r0 &= 0xffff
}
hr = syscall.Errno(r0)
} }
return return
} }

View File

@ -36,10 +36,6 @@ func New(err error, title, rest string) error {
return &HcsError{title, rest, err} return &HcsError{title, rest, err}
} }
func Errorf(err error, title, format string, a ...interface{}) error {
return New(err, title, fmt.Sprintf(format, a...))
}
func Win32FromError(err error) uint32 { func Win32FromError(err error) uint32 {
if herr, ok := err.(*HcsError); ok { if herr, ok := err.(*HcsError); ok {
return Win32FromError(herr.Err) return Win32FromError(herr.Err)

View File

@ -23,7 +23,9 @@ type HNSEndpoint struct {
DisableICC bool `json:",omitempty"` DisableICC bool `json:",omitempty"`
PrefixLength uint8 `json:",omitempty"` PrefixLength uint8 `json:",omitempty"`
IsRemoteEndpoint bool `json:",omitempty"` IsRemoteEndpoint bool `json:",omitempty"`
EnableLowMetric bool `json:",omitempty"`
Namespace *Namespace `json:",omitempty"` Namespace *Namespace `json:",omitempty"`
EncapOverhead uint16 `json:",omitempty"`
} }
//SystemType represents the type of the system on which actions are done //SystemType represents the type of the system on which actions are done

View File

@ -140,7 +140,7 @@ func (policylist *PolicyList) RemoveEndpoint(endpoint *HNSEndpoint) (*PolicyList
} }
// AddLoadBalancer policy list for the specified endpoints // AddLoadBalancer policy list for the specified endpoints
func AddLoadBalancer(endpoints []HNSEndpoint, isILB bool, isDSR bool, sourceVIP, vip string, protocol uint16, internalPort uint16, externalPort uint16) (*PolicyList, error) { func AddLoadBalancer(endpoints []HNSEndpoint, isILB bool, sourceVIP, vip string, protocol uint16, internalPort uint16, externalPort uint16) (*PolicyList, error) {
operation := "AddLoadBalancer" operation := "AddLoadBalancer"
title := "hcsshim::PolicyList::" + operation title := "hcsshim::PolicyList::" + operation
logrus.Debugf(title+" endpointId=%v, isILB=%v, sourceVIP=%s, vip=%s, protocol=%v, internalPort=%v, externalPort=%v", endpoints, isILB, sourceVIP, vip, protocol, internalPort, externalPort) logrus.Debugf(title+" endpointId=%v, isILB=%v, sourceVIP=%s, vip=%s, protocol=%v, internalPort=%v, externalPort=%v", endpoints, isILB, sourceVIP, vip, protocol, internalPort, externalPort)
@ -150,7 +150,6 @@ func AddLoadBalancer(endpoints []HNSEndpoint, isILB bool, isDSR bool, sourceVIP,
elbPolicy := &ELBPolicy{ elbPolicy := &ELBPolicy{
SourceVIP: sourceVIP, SourceVIP: sourceVIP,
ILB: isILB, ILB: isILB,
DSR: isDSR,
} }
if len(vip) > 0 { if len(vip) > 0 {

View File

@ -1,4 +1,4 @@
// MACHINE GENERATED BY 'go generate' COMMAND; DO NOT EDIT // Code generated mksyscall_windows.exe DO NOT EDIT
package hns package hns
@ -6,7 +6,6 @@ import (
"syscall" "syscall"
"unsafe" "unsafe"
"github.com/Microsoft/hcsshim/internal/interop"
"golang.org/x/sys/windows" "golang.org/x/sys/windows"
) )
@ -68,7 +67,10 @@ func __hnsCall(method *uint16, path *uint16, object *uint16, response **uint16)
} }
r0, _, _ := syscall.Syscall6(procHNSCall.Addr(), 4, uintptr(unsafe.Pointer(method)), uintptr(unsafe.Pointer(path)), uintptr(unsafe.Pointer(object)), uintptr(unsafe.Pointer(response)), 0, 0) r0, _, _ := syscall.Syscall6(procHNSCall.Addr(), 4, uintptr(unsafe.Pointer(method)), uintptr(unsafe.Pointer(path)), uintptr(unsafe.Pointer(object)), uintptr(unsafe.Pointer(response)), 0, 0)
if int32(r0) < 0 { if int32(r0) < 0 {
hr = interop.Win32FromHresult(r0) if r0&0x1fff0000 == 0x00070000 {
r0 &= 0xffff
}
hr = syscall.Errno(r0)
} }
return return
} }

View File

@ -5,9 +5,9 @@ import (
"unsafe" "unsafe"
) )
//go:generate go run $GOROOT/src/syscall/mksyscall_windows.go -output zsyscall_windows.go interop.go //go:generate go run ../../mksyscall_windows.go -output zsyscall_windows.go interop.go
//sys coTaskMemFree(buffer unsafe.Pointer) = ole32.CoTaskMemFree //sys coTaskMemFree(buffer unsafe.Pointer) = api_ms_win_core_com_l1_1_0.CoTaskMemFree
func ConvertAndFreeCoTaskMemString(buffer *uint16) string { func ConvertAndFreeCoTaskMemString(buffer *uint16) string {
str := syscall.UTF16ToString((*[1 << 29]uint16)(unsafe.Pointer(buffer))[:]) str := syscall.UTF16ToString((*[1 << 29]uint16)(unsafe.Pointer(buffer))[:])

View File

@ -1,4 +1,4 @@
// Code generated by 'go generate'; DO NOT EDIT. // Code generated mksyscall_windows.exe DO NOT EDIT
package interop package interop
@ -37,9 +37,9 @@ func errnoErr(e syscall.Errno) error {
} }
var ( var (
modole32 = windows.NewLazySystemDLL("ole32.dll") modapi_ms_win_core_com_l1_1_0 = windows.NewLazySystemDLL("api-ms-win-core-com-l1-1-0.dll")
procCoTaskMemFree = modole32.NewProc("CoTaskMemFree") procCoTaskMemFree = modapi_ms_win_core_com_l1_1_0.NewProc("CoTaskMemFree")
) )
func coTaskMemFree(buffer unsafe.Pointer) { func coTaskMemFree(buffer unsafe.Pointer) {

View File

@ -0,0 +1,37 @@
package logfields
const (
// Identifiers
ContainerID = "cid"
UVMID = "uvm-id"
ProcessID = "pid"
// Common Misc
// Timeout represents an operation timeout.
Timeout = "timeout"
JSON = "json"
// Keys/values
Field = "field"
OCIAnnotation = "oci-annotation"
Value = "value"
// Golang type's
ExpectedType = "expected-type"
Bool = "bool"
Uint32 = "uint32"
Uint64 = "uint64"
// HCS
HCSOperation = "hcs-op"
HCSOperationResult = "hcs-op-result"
// runhcs
VMShimOperation = "vmshim-op"
)

View File

@ -10,7 +10,6 @@
package hcsschema package hcsschema
type Chipset struct { type Chipset struct {
Uefi *Uefi `json:"Uefi,omitempty"` Uefi *Uefi `json:"Uefi,omitempty"`
IsNumLockDisabled bool `json:"IsNumLockDisabled,omitempty"` IsNumLockDisabled bool `json:"IsNumLockDisabled,omitempty"`
@ -22,4 +21,7 @@ type Chipset struct {
ChassisAssetTag string `json:"ChassisAssetTag,omitempty"` ChassisAssetTag string `json:"ChassisAssetTag,omitempty"`
UseUtc bool `json:"UseUtc,omitempty"` UseUtc bool `json:"UseUtc,omitempty"`
// LinuxKernelDirect - Added in v2.2 Builds >=181117
LinuxKernelDirect *LinuxKernelDirect `json:"LinuxKernelDirect,omitempty"`
} }

View File

@ -0,0 +1,18 @@
/*
* HCS API
*
* No description provided (generated by Swagger Codegen https://github.com/swagger-api/swagger-codegen)
*
* API version: 2.2
* Generated by: Swagger Codegen (https://github.com/swagger-api/swagger-codegen.git)
*/
package hcsschema
type LinuxKernelDirect struct {
KernelFilePath string `json:"KernelFilePath,omitempty"`
InitRdPath string `json:"InitRdPath,omitempty"`
KernelCmdLine string `json:"KernelCmdLine,omitempty"`
}

View File

@ -20,6 +20,13 @@ type Plan9Share struct {
Port int32 `json:"Port,omitempty"` Port int32 `json:"Port,omitempty"`
// Flags are marked private. Until they are exported correctly
//
// ReadOnly 0x00000001
// LinuxMetadata 0x00000004
// CaseSensitive 0x00000008
Flags int32 `json:"Flags,omitempty"`
ReadOnly bool `json:"ReadOnly,omitempty"` ReadOnly bool `json:"ReadOnly,omitempty"`
UseShareRootIdentity bool `json:"UseShareRootIdentity,omitempty"` UseShareRootIdentity bool `json:"UseShareRootIdentity,omitempty"`

View File

@ -11,6 +11,9 @@ package hcsschema
type VirtualMachine struct { type VirtualMachine struct {
// StopOnReset is private in the schema. If regenerated need to put back.
StopOnReset bool `json:"StopOnReset,omitempty"`
Chipset *Chipset `json:"Chipset,omitempty"` Chipset *Chipset `json:"Chipset,omitempty"`
ComputeTopology *Topology `json:"ComputeTopology,omitempty"` ComputeTopology *Topology `json:"ComputeTopology,omitempty"`

View File

@ -9,17 +9,24 @@ import (
// For a read/write layer, the mounted filesystem will appear as a volume on the // For a read/write layer, the mounted filesystem will appear as a volume on the
// host, while a read-only layer is generally expected to be a no-op. // host, while a read-only layer is generally expected to be a no-op.
// An activated layer must later be deactivated via DeactivateLayer. // An activated layer must later be deactivated via DeactivateLayer.
func ActivateLayer(path string) error { func ActivateLayer(path string) (err error) {
title := "hcsshim::ActivateLayer " title := "hcsshim::ActivateLayer"
logrus.Debugf(title+"path %s", path) fields := logrus.Fields{
"path": path,
err := activateLayer(&stdDriverInfo, path)
if err != nil {
err = hcserror.Errorf(err, title, "path=%s", path)
logrus.Error(err)
return err
} }
logrus.WithFields(fields).Debug(title)
defer func() {
if err != nil {
fields[logrus.ErrorKey] = err
logrus.WithFields(fields).Error(err)
} else {
logrus.WithFields(fields).Debug(title + " - succeeded")
}
}()
logrus.Debugf(title+" - succeeded path=%s", path) err = activateLayer(&stdDriverInfo, path)
if err != nil {
return hcserror.New(err, title+" - failed", "")
}
return nil return nil
} }

View File

@ -7,17 +7,25 @@ import (
// CreateLayer creates a new, empty, read-only layer on the filesystem based on // CreateLayer creates a new, empty, read-only layer on the filesystem based on
// the parent layer provided. // the parent layer provided.
func CreateLayer(path, parent string) error { func CreateLayer(path, parent string) (err error) {
title := "hcsshim::CreateLayer " title := "hcsshim::CreateLayer"
logrus.Debugf(title+"ID %s parent %s", path, parent) fields := logrus.Fields{
"parent": parent,
err := createLayer(&stdDriverInfo, path, parent) "path": path,
if err != nil {
err = hcserror.Errorf(err, title, "path=%s parent=%s", path, parent)
logrus.Error(err)
return err
} }
logrus.WithFields(fields).Debug(title)
defer func() {
if err != nil {
fields[logrus.ErrorKey] = err
logrus.WithFields(fields).Error(err)
} else {
logrus.WithFields(fields).Debug(title + " - succeeded")
}
}()
logrus.Debugf(title+"- succeeded path=%s parent=%s", path, parent) err = createLayer(&stdDriverInfo, path, parent)
if err != nil {
return hcserror.New(err, title+" - failed", "")
}
return nil return nil
} }

View File

@ -9,9 +9,20 @@ import (
// This requires both the id of the direct parent layer, as well as the full list // This requires both the id of the direct parent layer, as well as the full list
// of paths to all parent layers up to the base (and including the direct parent // of paths to all parent layers up to the base (and including the direct parent
// whose id was provided). // whose id was provided).
func CreateScratchLayer(path string, parentLayerPaths []string) error { func CreateScratchLayer(path string, parentLayerPaths []string) (err error) {
title := "hcsshim::CreateScratchLayer " title := "hcsshim::CreateScratchLayer"
logrus.Debugf(title+"path %s", path) fields := logrus.Fields{
"path": path,
}
logrus.WithFields(fields).Debug(title)
defer func() {
if err != nil {
fields[logrus.ErrorKey] = err
logrus.WithFields(fields).Error(err)
} else {
logrus.WithFields(fields).Debug(title + " - succeeded")
}
}()
// Generate layer descriptors // Generate layer descriptors
layers, err := layerPathsToDescriptors(parentLayerPaths) layers, err := layerPathsToDescriptors(parentLayerPaths)
@ -21,11 +32,7 @@ func CreateScratchLayer(path string, parentLayerPaths []string) error {
err = createSandboxLayer(&stdDriverInfo, path, 0, layers) err = createSandboxLayer(&stdDriverInfo, path, 0, layers)
if err != nil { if err != nil {
err = hcserror.Errorf(err, title, "path=%s", path) return hcserror.New(err, title+" - failed", "")
logrus.Error(err)
return err
} }
logrus.Debugf(title+"- succeeded path=%s", path)
return nil return nil
} }

View File

@ -6,17 +6,24 @@ import (
) )
// DeactivateLayer will dismount a layer that was mounted via ActivateLayer. // DeactivateLayer will dismount a layer that was mounted via ActivateLayer.
func DeactivateLayer(path string) error { func DeactivateLayer(path string) (err error) {
title := "hcsshim::DeactivateLayer " title := "hcsshim::DeactivateLayer"
logrus.Debugf(title+"path %s", path) fields := logrus.Fields{
"path": path,
err := deactivateLayer(&stdDriverInfo, path)
if err != nil {
err = hcserror.Errorf(err, title, "path=%s", path)
logrus.Error(err)
return err
} }
logrus.WithFields(fields).Debug(title)
defer func() {
if err != nil {
fields[logrus.ErrorKey] = err
logrus.WithFields(fields).Error(err)
} else {
logrus.WithFields(fields).Debug(title + " - succeeded")
}
}()
logrus.Debugf(title+"succeeded path=%s", path) err = deactivateLayer(&stdDriverInfo, path)
if err != nil {
return hcserror.New(err, title+"- failed", "")
}
return nil return nil
} }

View File

@ -7,17 +7,24 @@ import (
// DestroyLayer will remove the on-disk files representing the layer with the given // DestroyLayer will remove the on-disk files representing the layer with the given
// path, including that layer's containing folder, if any. // path, including that layer's containing folder, if any.
func DestroyLayer(path string) error { func DestroyLayer(path string) (err error) {
title := "hcsshim::DestroyLayer " title := "hcsshim::DestroyLayer"
logrus.Debugf(title+"path %s", path) fields := logrus.Fields{
"path": path,
err := destroyLayer(&stdDriverInfo, path)
if err != nil {
err = hcserror.Errorf(err, title, "path=%s", path)
logrus.Error(err)
return err
} }
logrus.WithFields(fields).Debug(title)
defer func() {
if err != nil {
fields[logrus.ErrorKey] = err
logrus.WithFields(fields).Error(err)
} else {
logrus.WithFields(fields).Debug(title + " - succeeded")
}
}()
logrus.Debugf(title+"succeeded path=%s", path) err = destroyLayer(&stdDriverInfo, path)
if err != nil {
return hcserror.New(err, title+" - failed", "")
}
return nil return nil
} }

View File

@ -6,17 +6,25 @@ import (
) )
// ExpandScratchSize expands the size of a layer to at least size bytes. // ExpandScratchSize expands the size of a layer to at least size bytes.
func ExpandScratchSize(path string, size uint64) error { func ExpandScratchSize(path string, size uint64) (err error) {
title := "hcsshim::ExpandScratchSize " title := "hcsshim::ExpandScratchSize"
logrus.Debugf(title+"path=%s size=%d", path, size) fields := logrus.Fields{
"path": path,
err := expandSandboxSize(&stdDriverInfo, path, size) "size": size,
if err != nil {
err = hcserror.Errorf(err, title, "path=%s size=%d", path, size)
logrus.Error(err)
return err
} }
logrus.WithFields(fields).Debug(title)
defer func() {
if err != nil {
fields[logrus.ErrorKey] = err
logrus.WithFields(fields).Error(err)
} else {
logrus.WithFields(fields).Debug(title + " - succeeded")
}
}()
logrus.Debugf(title+"- succeeded path=%s size=%d", path, size) err = expandSandboxSize(&stdDriverInfo, path, size)
if err != nil {
return hcserror.New(err, title+" - failed", "")
}
return nil return nil
} }

View File

@ -1,14 +1,11 @@
package wclayer package wclayer
import ( import (
"io"
"io/ioutil" "io/ioutil"
"os" "os"
"syscall"
"github.com/Microsoft/go-winio" "github.com/Microsoft/go-winio"
"github.com/Microsoft/hcsshim/internal/hcserror" "github.com/Microsoft/hcsshim/internal/hcserror"
"github.com/Microsoft/hcsshim/internal/interop"
"github.com/sirupsen/logrus" "github.com/sirupsen/logrus"
) )
@ -17,9 +14,21 @@ import (
// format includes any metadata required for later importing the layer (using // format includes any metadata required for later importing the layer (using
// ImportLayer), and requires the full list of parent layer paths in order to // ImportLayer), and requires the full list of parent layer paths in order to
// perform the export. // perform the export.
func ExportLayer(path string, exportFolderPath string, parentLayerPaths []string) error { func ExportLayer(path string, exportFolderPath string, parentLayerPaths []string) (err error) {
title := "hcsshim::ExportLayer " title := "hcsshim::ExportLayer"
logrus.Debugf(title+"path %s folder %s", path, exportFolderPath) fields := logrus.Fields{
"path": path,
"exportFolderPath": exportFolderPath,
}
logrus.WithFields(fields).Debug(title)
defer func() {
if err != nil {
fields[logrus.ErrorKey] = err
logrus.WithFields(fields).Error(err)
} else {
logrus.WithFields(fields).Debug(title + " - succeeded")
}
}()
// Generate layer descriptors // Generate layer descriptors
layers, err := layerPathsToDescriptors(parentLayerPaths) layers, err := layerPathsToDescriptors(parentLayerPaths)
@ -29,12 +38,8 @@ func ExportLayer(path string, exportFolderPath string, parentLayerPaths []string
err = exportLayer(&stdDriverInfo, path, exportFolderPath, layers) err = exportLayer(&stdDriverInfo, path, exportFolderPath, layers)
if err != nil { if err != nil {
err = hcserror.Errorf(err, title, "path=%s folder=%s", path, exportFolderPath) return hcserror.New(err, title+" - failed", "")
logrus.Error(err)
return err
} }
logrus.Debugf(title+"succeeded path=%s folder=%s", path, exportFolderPath)
return nil return nil
} }
@ -44,96 +49,20 @@ type LayerReader interface {
Close() error Close() error
} }
// FilterLayerReader provides an interface for extracting the contents of an on-disk layer.
type FilterLayerReader struct {
context uintptr
}
// Next reads the next available file from a layer, ensuring that parent directories are always read
// before child files and directories.
//
// Next returns the file's relative path, size, and basic file metadata. Read() should be used to
// extract a Win32 backup stream with the remainder of the metadata and the data.
func (r *FilterLayerReader) Next() (string, int64, *winio.FileBasicInfo, error) {
var fileNamep *uint16
fileInfo := &winio.FileBasicInfo{}
var deleted uint32
var fileSize int64
err := exportLayerNext(r.context, &fileNamep, fileInfo, &fileSize, &deleted)
if err != nil {
if err == syscall.ERROR_NO_MORE_FILES {
err = io.EOF
} else {
err = hcserror.New(err, "ExportLayerNext", "")
}
return "", 0, nil, err
}
fileName := interop.ConvertAndFreeCoTaskMemString(fileNamep)
if deleted != 0 {
fileInfo = nil
}
if fileName[0] == '\\' {
fileName = fileName[1:]
}
return fileName, fileSize, fileInfo, nil
}
// Read reads from the current file's Win32 backup stream.
func (r *FilterLayerReader) Read(b []byte) (int, error) {
var bytesRead uint32
err := exportLayerRead(r.context, b, &bytesRead)
if err != nil {
return 0, hcserror.New(err, "ExportLayerRead", "")
}
if bytesRead == 0 {
return 0, io.EOF
}
return int(bytesRead), nil
}
// Close frees resources associated with the layer reader. It will return an
// error if there was an error while reading the layer or of the layer was not
// completely read.
func (r *FilterLayerReader) Close() (err error) {
if r.context != 0 {
err = exportLayerEnd(r.context)
if err != nil {
err = hcserror.New(err, "ExportLayerEnd", "")
}
r.context = 0
}
return
}
// NewLayerReader returns a new layer reader for reading the contents of an on-disk layer. // NewLayerReader returns a new layer reader for reading the contents of an on-disk layer.
// The caller must have taken the SeBackupPrivilege privilege // The caller must have taken the SeBackupPrivilege privilege
// to call this and any methods on the resulting LayerReader. // to call this and any methods on the resulting LayerReader.
func NewLayerReader(path string, parentLayerPaths []string) (LayerReader, error) { func NewLayerReader(path string, parentLayerPaths []string) (LayerReader, error) {
if procExportLayerBegin.Find() != nil { exportPath, err := ioutil.TempDir("", "hcs")
// The new layer reader is not available on this Windows build. Fall back to the
// legacy export code path.
exportPath, err := ioutil.TempDir("", "hcs")
if err != nil {
return nil, err
}
err = ExportLayer(path, exportPath, parentLayerPaths)
if err != nil {
os.RemoveAll(exportPath)
return nil, err
}
return &legacyLayerReaderWrapper{newLegacyLayerReader(exportPath)}, nil
}
layers, err := layerPathsToDescriptors(parentLayerPaths)
if err != nil { if err != nil {
return nil, err return nil, err
} }
r := &FilterLayerReader{} err = ExportLayer(path, exportPath, parentLayerPaths)
err = exportLayerBegin(&stdDriverInfo, path, layers, &r.context)
if err != nil { if err != nil {
return nil, hcserror.New(err, "ExportLayerBegin", "") os.RemoveAll(exportPath)
return nil, err
} }
return r, err return &legacyLayerReaderWrapper{newLegacyLayerReader(exportPath)}, nil
} }
type legacyLayerReaderWrapper struct { type legacyLayerReaderWrapper struct {

View File

@ -11,20 +11,29 @@ import (
// the path at which that layer can be accessed. This path may be a volume path // the path at which that layer can be accessed. This path may be a volume path
// if the layer is a mounted read-write layer, otherwise it is expected to be the // if the layer is a mounted read-write layer, otherwise it is expected to be the
// folder path at which the layer is stored. // folder path at which the layer is stored.
func GetLayerMountPath(path string) (string, error) { func GetLayerMountPath(path string) (_ string, err error) {
title := "hcsshim::GetLayerMountPath " title := "hcsshim::GetLayerMountPath"
logrus.Debugf(title+"path %s", path) fields := logrus.Fields{
"path": path,
}
logrus.WithFields(fields).Debug(title)
defer func() {
if err != nil {
fields[logrus.ErrorKey] = err
logrus.WithFields(fields).Error(err)
} else {
logrus.WithFields(fields).Debug(title + " - succeeded")
}
}()
var mountPathLength uintptr var mountPathLength uintptr
mountPathLength = 0 mountPathLength = 0
// Call the procedure itself. // Call the procedure itself.
logrus.Debugf("Calling proc (1)") logrus.WithFields(fields).Debug("Calling proc (1)")
err := getLayerMountPath(&stdDriverInfo, path, &mountPathLength, nil) err = getLayerMountPath(&stdDriverInfo, path, &mountPathLength, nil)
if err != nil { if err != nil {
err = hcserror.Errorf(err, title, "(first call) path=%s", path) return "", hcserror.New(err, title+" - failed", "(first call)")
logrus.Error(err)
return "", err
} }
// Allocate a mount path of the returned length. // Allocate a mount path of the returned length.
@ -35,15 +44,13 @@ func GetLayerMountPath(path string) (string, error) {
mountPathp[0] = 0 mountPathp[0] = 0
// Call the procedure again // Call the procedure again
logrus.Debugf("Calling proc (2)") logrus.WithFields(fields).Debug("Calling proc (2)")
err = getLayerMountPath(&stdDriverInfo, path, &mountPathLength, &mountPathp[0]) err = getLayerMountPath(&stdDriverInfo, path, &mountPathLength, &mountPathp[0])
if err != nil { if err != nil {
err = hcserror.Errorf(err, title, "(second call) path=%s", path) return "", hcserror.New(err, title+" - failed", "(second call)")
logrus.Error(err)
return "", err
} }
mountPath := syscall.UTF16ToString(mountPathp[0:]) mountPath := syscall.UTF16ToString(mountPathp[0:])
logrus.Debugf(title+"succeeded path=%s mountPath=%s", path, mountPath) fields["mountPath"] = mountPath
return mountPath, nil return mountPath, nil
} }

View File

@ -10,17 +10,20 @@ import (
// image store and return descriptive info about those images for the purpose // image store and return descriptive info about those images for the purpose
// of registering them with the graphdriver, graph, and tagstore. // of registering them with the graphdriver, graph, and tagstore.
func GetSharedBaseImages() (imageData string, err error) { func GetSharedBaseImages() (imageData string, err error) {
title := "hcsshim::GetSharedBaseImages " title := "hcsshim::GetSharedBaseImages"
logrus.Debug(title)
defer func() {
if err != nil {
logrus.WithError(err).Error(err)
} else {
logrus.WithField("imageData", imageData).Debug(title + " - succeeded")
}
}()
logrus.Debugf("Calling proc")
var buffer *uint16 var buffer *uint16
err = getBaseImages(&buffer) err = getBaseImages(&buffer)
if err != nil { if err != nil {
err = hcserror.New(err, title, "") return "", hcserror.New(err, title+" - failed", "")
logrus.Error(err)
return
} }
imageData = interop.ConvertAndFreeCoTaskMemString(buffer) return interop.ConvertAndFreeCoTaskMemString(buffer), nil
logrus.Debugf(title+" - succeeded output=%s", imageData)
return
} }

View File

@ -1,24 +1,30 @@
package wclayer package wclayer
import ( import (
"fmt"
"github.com/Microsoft/hcsshim/internal/hcserror" "github.com/Microsoft/hcsshim/internal/hcserror"
"github.com/sirupsen/logrus" "github.com/sirupsen/logrus"
) )
// GrantVmAccess adds access to a file for a given VM // GrantVmAccess adds access to a file for a given VM
func GrantVmAccess(vmid string, filepath string) error { func GrantVmAccess(vmid string, filepath string) (err error) {
title := fmt.Sprintf("hcsshim::GrantVmAccess id:%s path:%s ", vmid, filepath) title := "hcsshim::GrantVmAccess"
logrus.Debugf(title) fields := logrus.Fields{
"vm-id": vmid,
err := grantVmAccess(vmid, filepath) "path": filepath,
if err != nil {
err = hcserror.Errorf(err, title, "path=%s", filepath)
logrus.Error(err)
return err
} }
logrus.WithFields(fields).Debug(title)
defer func() {
if err != nil {
fields[logrus.ErrorKey] = err
logrus.WithFields(fields).Error(err)
} else {
logrus.WithFields(fields).Debug(title + " - succeeded")
}
}()
logrus.Debugf(title + " - succeeded") err = grantVmAccess(vmid, filepath)
if err != nil {
return hcserror.New(err, title+" - failed", "")
}
return nil return nil
} }

View File

@ -1,7 +1,6 @@
package wclayer package wclayer
import ( import (
"errors"
"io/ioutil" "io/ioutil"
"os" "os"
"path/filepath" "path/filepath"
@ -16,9 +15,21 @@ import (
// that into a layer with the id layerId. Note that in order to correctly populate // that into a layer with the id layerId. Note that in order to correctly populate
// the layer and interperet the transport format, all parent layers must already // the layer and interperet the transport format, all parent layers must already
// be present on the system at the paths provided in parentLayerPaths. // be present on the system at the paths provided in parentLayerPaths.
func ImportLayer(path string, importFolderPath string, parentLayerPaths []string) error { func ImportLayer(path string, importFolderPath string, parentLayerPaths []string) (err error) {
title := "hcsshim::ImportLayer " title := "hcsshim::ImportLayer"
logrus.Debugf(title+"path %s folder %s", path, importFolderPath) fields := logrus.Fields{
"path": path,
"importFolderPath": importFolderPath,
}
logrus.WithFields(fields).Debug(title)
defer func() {
if err != nil {
fields[logrus.ErrorKey] = err
logrus.WithFields(fields).Error(err)
} else {
logrus.WithFields(fields).Debug(title + " - succeeded")
}
}()
// Generate layer descriptors // Generate layer descriptors
layers, err := layerPathsToDescriptors(parentLayerPaths) layers, err := layerPathsToDescriptors(parentLayerPaths)
@ -28,12 +39,8 @@ func ImportLayer(path string, importFolderPath string, parentLayerPaths []string
err = importLayer(&stdDriverInfo, path, importFolderPath, layers) err = importLayer(&stdDriverInfo, path, importFolderPath, layers)
if err != nil { if err != nil {
err = hcserror.Errorf(err, title, "path=%s folder=%s", path, importFolderPath) return hcserror.New(err, title+" - failed", "")
logrus.Error(err)
return err
} }
logrus.Debugf(title+"succeeded path=%s folder=%s", path, importFolderPath)
return nil return nil
} }
@ -52,69 +59,6 @@ type LayerWriter interface {
Close() error Close() error
} }
// FilterLayerWriter provides an interface to write the contents of a layer to the file system.
type FilterLayerWriter struct {
context uintptr
}
// Add adds a file or directory to the layer. The file's parent directory must have already been added.
//
// name contains the file's relative path. fileInfo contains file times and file attributes; the rest
// of the file metadata and the file data must be written as a Win32 backup stream to the Write() method.
// winio.BackupStreamWriter can be used to facilitate this.
func (w *FilterLayerWriter) Add(name string, fileInfo *winio.FileBasicInfo) error {
if name[0] != '\\' {
name = `\` + name
}
err := importLayerNext(w.context, name, fileInfo)
if err != nil {
return hcserror.New(err, "ImportLayerNext", "")
}
return nil
}
// AddLink adds a hard link to the layer. The target of the link must have already been added.
func (w *FilterLayerWriter) AddLink(name string, target string) error {
return errors.New("hard links not yet supported")
}
// Remove removes a file from the layer. The file must have been present in the parent layer.
//
// name contains the file's relative path.
func (w *FilterLayerWriter) Remove(name string) error {
if name[0] != '\\' {
name = `\` + name
}
err := importLayerNext(w.context, name, nil)
if err != nil {
return hcserror.New(err, "ImportLayerNext", "")
}
return nil
}
// Write writes more backup stream data to the current file.
func (w *FilterLayerWriter) Write(b []byte) (int, error) {
err := importLayerWrite(w.context, b)
if err != nil {
err = hcserror.New(err, "ImportLayerWrite", "")
return 0, err
}
return len(b), err
}
// Close completes the layer write operation. The error must be checked to ensure that the
// operation was successful.
func (w *FilterLayerWriter) Close() (err error) {
if w.context != 0 {
err = importLayerEnd(w.context)
if err != nil {
err = hcserror.New(err, "ImportLayerEnd", "")
}
w.context = 0
}
return
}
type legacyLayerWriterWrapper struct { type legacyLayerWriterWrapper struct {
*legacyLayerWriter *legacyLayerWriter
path string path string
@ -175,32 +119,17 @@ func NewLayerWriter(path string, parentLayerPaths []string) (LayerWriter, error)
}, nil }, nil
} }
if procImportLayerBegin.Find() != nil { importPath, err := ioutil.TempDir("", "hcs")
// The new layer reader is not available on this Windows build. Fall back to the
// legacy export code path.
importPath, err := ioutil.TempDir("", "hcs")
if err != nil {
return nil, err
}
w, err := newLegacyLayerWriter(importPath, parentLayerPaths, path)
if err != nil {
return nil, err
}
return &legacyLayerWriterWrapper{
legacyLayerWriter: w,
path: importPath,
parentLayerPaths: parentLayerPaths,
}, nil
}
layers, err := layerPathsToDescriptors(parentLayerPaths)
if err != nil { if err != nil {
return nil, err return nil, err
} }
w, err := newLegacyLayerWriter(importPath, parentLayerPaths, path)
w := &FilterLayerWriter{}
err = importLayerBegin(&stdDriverInfo, path, layers, &w.context)
if err != nil { if err != nil {
return nil, hcserror.New(err, "ImportLayerStart", "") return nil, err
} }
return w, nil return &legacyLayerWriterWrapper{
legacyLayerWriter: w,
path: importPath,
parentLayerPaths: parentLayerPaths,
}, nil
} }

View File

@ -7,19 +7,27 @@ import (
// LayerExists will return true if a layer with the given id exists and is known // LayerExists will return true if a layer with the given id exists and is known
// to the system. // to the system.
func LayerExists(path string) (bool, error) { func LayerExists(path string) (_ bool, err error) {
title := "hcsshim::LayerExists " title := "hcsshim::LayerExists"
logrus.Debugf(title+"path %s", path) fields := logrus.Fields{
"path": path,
}
logrus.WithFields(fields).Debug(title)
defer func() {
if err != nil {
fields[logrus.ErrorKey] = err
logrus.WithFields(fields).Error(err)
} else {
logrus.WithFields(fields).Debug(title + " - succeeded")
}
}()
// Call the procedure itself. // Call the procedure itself.
var exists uint32 var exists uint32
err := layerExists(&stdDriverInfo, path, &exists) err = layerExists(&stdDriverInfo, path, &exists)
if err != nil { if err != nil {
err = hcserror.Errorf(err, title, "path=%s", path) return false, hcserror.New(err, title+" - failed", "")
logrus.Error(err)
return false, err
} }
fields["layer-exists"] = exists != 0
logrus.Debugf(title+"succeeded path=%s exists=%d", path, exists)
return exists != 0, nil return exists != 0, nil
} }

View File

@ -75,13 +75,13 @@ func layerPathsToDescriptors(parentLayerPaths []string) ([]WC_LAYER_DESCRIPTOR,
for i := 0; i < len(parentLayerPaths); i++ { for i := 0; i < len(parentLayerPaths); i++ {
g, err := LayerID(parentLayerPaths[i]) g, err := LayerID(parentLayerPaths[i])
if err != nil { if err != nil {
logrus.Debugf("Failed to convert name to guid %s", err) logrus.WithError(err).Debug("Failed to convert name to guid")
return nil, err return nil, err
} }
p, err := syscall.UTF16PtrFromString(parentLayerPaths[i]) p, err := syscall.UTF16PtrFromString(parentLayerPaths[i])
if err != nil { if err != nil {
logrus.Debugf("Failed conversion of parentLayerPath to pointer %s", err) logrus.WithError(err).Debug("Failed conversion of parentLayerPath to pointer")
return nil, err return nil, err
} }

View File

@ -10,15 +10,25 @@ import (
// Host Compute Service, ensuring GUIDs generated with the same string are common // Host Compute Service, ensuring GUIDs generated with the same string are common
// across all clients. // across all clients.
func NameToGuid(name string) (id guid.GUID, err error) { func NameToGuid(name string) (id guid.GUID, err error) {
title := "hcsshim::NameToGuid " title := "hcsshim::NameToGuid"
fields := logrus.Fields{
"name": name,
}
logrus.WithFields(fields).Debug(title)
defer func() {
if err != nil {
fields[logrus.ErrorKey] = err
logrus.WithFields(fields).Error(err)
} else {
logrus.WithFields(fields).Debug(title + " - succeeded")
}
}()
err = nameToGuid(name, &id) err = nameToGuid(name, &id)
if err != nil { if err != nil {
err = hcserror.Errorf(err, title, "name=%s", name) err = hcserror.New(err, title+" - failed", "")
logrus.Error(err)
return return
} }
fields["guid"] = id.String()
logrus.Debugf(title+"name:%s guid:%s", name, id.String())
return return
} }

View File

@ -14,9 +14,20 @@ var prepareLayerLock sync.Mutex
// parent layers, and is necessary in order to view or interact with the layer // parent layers, and is necessary in order to view or interact with the layer
// as an actual filesystem (reading and writing files, creating directories, etc). // as an actual filesystem (reading and writing files, creating directories, etc).
// Disabling the filter must be done via UnprepareLayer. // Disabling the filter must be done via UnprepareLayer.
func PrepareLayer(path string, parentLayerPaths []string) error { func PrepareLayer(path string, parentLayerPaths []string) (err error) {
title := "hcsshim::PrepareLayer " title := "hcsshim::PrepareLayer"
logrus.Debugf(title+"path %s", path) fields := logrus.Fields{
"path": path,
}
logrus.WithFields(fields).Debug(title)
defer func() {
if err != nil {
fields[logrus.ErrorKey] = err
logrus.WithFields(fields).Error(err)
} else {
logrus.WithFields(fields).Debug(title + " - succeeded")
}
}()
// Generate layer descriptors // Generate layer descriptors
layers, err := layerPathsToDescriptors(parentLayerPaths) layers, err := layerPathsToDescriptors(parentLayerPaths)
@ -30,11 +41,7 @@ func PrepareLayer(path string, parentLayerPaths []string) error {
defer prepareLayerLock.Unlock() defer prepareLayerLock.Unlock()
err = prepareLayer(&stdDriverInfo, path, layers) err = prepareLayer(&stdDriverInfo, path, layers)
if err != nil { if err != nil {
err = hcserror.Errorf(err, title, "path=%s", path) return hcserror.New(err, title+" - failed", "")
logrus.Error(err)
return err
} }
logrus.Debugf(title+"succeeded path=%s", path)
return nil return nil
} }

View File

@ -7,17 +7,24 @@ import (
// UnprepareLayer disables the filesystem filter for the read-write layer with // UnprepareLayer disables the filesystem filter for the read-write layer with
// the given id. // the given id.
func UnprepareLayer(path string) error { func UnprepareLayer(path string) (err error) {
title := "hcsshim::UnprepareLayer " title := "hcsshim::UnprepareLayer"
logrus.Debugf(title+"path %s", path) fields := logrus.Fields{
"path": path,
err := unprepareLayer(&stdDriverInfo, path)
if err != nil {
err = hcserror.Errorf(err, title, "path=%s", path)
logrus.Error(err)
return err
} }
logrus.WithFields(fields).Debug(title)
defer func() {
if err != nil {
fields[logrus.ErrorKey] = err
logrus.WithFields(fields).Error(err)
} else {
logrus.WithFields(fields).Debug(title + " - succeeded")
}
}()
logrus.Debugf(title+"succeeded path=%s", path) err = unprepareLayer(&stdDriverInfo, path)
if err != nil {
return hcserror.New(err, title+" - failed", "")
}
return nil return nil
} }

View File

@ -2,7 +2,7 @@ package wclayer
import "github.com/Microsoft/hcsshim/internal/guid" import "github.com/Microsoft/hcsshim/internal/guid"
//go:generate go run ../../mksyscall_windows.go -output zsyscall_windows.go -winio wclayer.go //go:generate go run ../../mksyscall_windows.go -output zsyscall_windows.go wclayer.go
//sys activateLayer(info *driverInfo, id string) (hr error) = vmcompute.ActivateLayer? //sys activateLayer(info *driverInfo, id string) (hr error) = vmcompute.ActivateLayer?
//sys copyLayer(info *driverInfo, srcId string, dstId string, descriptors []WC_LAYER_DESCRIPTOR) (hr error) = vmcompute.CopyLayer? //sys copyLayer(info *driverInfo, srcId string, dstId string, descriptors []WC_LAYER_DESCRIPTOR) (hr error) = vmcompute.CopyLayer?
@ -22,16 +22,6 @@ import "github.com/Microsoft/hcsshim/internal/guid"
//sys processBaseImage(path string) (hr error) = vmcompute.ProcessBaseImage? //sys processBaseImage(path string) (hr error) = vmcompute.ProcessBaseImage?
//sys processUtilityImage(path string) (hr error) = vmcompute.ProcessUtilityImage? //sys processUtilityImage(path string) (hr error) = vmcompute.ProcessUtilityImage?
//sys importLayerBegin(info *driverInfo, id string, descriptors []WC_LAYER_DESCRIPTOR, context *uintptr) (hr error) = vmcompute.ImportLayerBegin?
//sys importLayerNext(context uintptr, fileName string, fileInfo *winio.FileBasicInfo) (hr error) = vmcompute.ImportLayerNext?
//sys importLayerWrite(context uintptr, buffer []byte) (hr error) = vmcompute.ImportLayerWrite?
//sys importLayerEnd(context uintptr) (hr error) = vmcompute.ImportLayerEnd?
//sys exportLayerBegin(info *driverInfo, id string, descriptors []WC_LAYER_DESCRIPTOR, context *uintptr) (hr error) = vmcompute.ExportLayerBegin?
//sys exportLayerNext(context uintptr, fileName **uint16, fileInfo *winio.FileBasicInfo, fileSize *int64, deleted *uint32) (hr error) = vmcompute.ExportLayerNext?
//sys exportLayerRead(context uintptr, buffer []byte, bytesRead *uint32) (hr error) = vmcompute.ExportLayerRead?
//sys exportLayerEnd(context uintptr) (hr error) = vmcompute.ExportLayerEnd?
//sys grantVmAccess(vmid string, filepath string) (hr error) = vmcompute.GrantVmAccess? //sys grantVmAccess(vmid string, filepath string) (hr error) = vmcompute.GrantVmAccess?
type _guid = guid.GUID type _guid = guid.GUID

View File

@ -1,4 +1,4 @@
// MACHINE GENERATED BY 'go generate' COMMAND; DO NOT EDIT // Code generated mksyscall_windows.exe DO NOT EDIT
package wclayer package wclayer
@ -6,8 +6,6 @@ import (
"syscall" "syscall"
"unsafe" "unsafe"
"github.com/Microsoft/go-winio"
"github.com/Microsoft/hcsshim/internal/interop"
"golang.org/x/sys/windows" "golang.org/x/sys/windows"
) )
@ -58,14 +56,6 @@ var (
procUnprepareLayer = modvmcompute.NewProc("UnprepareLayer") procUnprepareLayer = modvmcompute.NewProc("UnprepareLayer")
procProcessBaseImage = modvmcompute.NewProc("ProcessBaseImage") procProcessBaseImage = modvmcompute.NewProc("ProcessBaseImage")
procProcessUtilityImage = modvmcompute.NewProc("ProcessUtilityImage") procProcessUtilityImage = modvmcompute.NewProc("ProcessUtilityImage")
procImportLayerBegin = modvmcompute.NewProc("ImportLayerBegin")
procImportLayerNext = modvmcompute.NewProc("ImportLayerNext")
procImportLayerWrite = modvmcompute.NewProc("ImportLayerWrite")
procImportLayerEnd = modvmcompute.NewProc("ImportLayerEnd")
procExportLayerBegin = modvmcompute.NewProc("ExportLayerBegin")
procExportLayerNext = modvmcompute.NewProc("ExportLayerNext")
procExportLayerRead = modvmcompute.NewProc("ExportLayerRead")
procExportLayerEnd = modvmcompute.NewProc("ExportLayerEnd")
procGrantVmAccess = modvmcompute.NewProc("GrantVmAccess") procGrantVmAccess = modvmcompute.NewProc("GrantVmAccess")
) )
@ -84,7 +74,10 @@ func _activateLayer(info *driverInfo, id *uint16) (hr error) {
} }
r0, _, _ := syscall.Syscall(procActivateLayer.Addr(), 2, uintptr(unsafe.Pointer(info)), uintptr(unsafe.Pointer(id)), 0) r0, _, _ := syscall.Syscall(procActivateLayer.Addr(), 2, uintptr(unsafe.Pointer(info)), uintptr(unsafe.Pointer(id)), 0)
if int32(r0) < 0 { if int32(r0) < 0 {
hr = interop.Win32FromHresult(r0) if r0&0x1fff0000 == 0x00070000 {
r0 &= 0xffff
}
hr = syscall.Errno(r0)
} }
return return
} }
@ -113,7 +106,10 @@ func _copyLayer(info *driverInfo, srcId *uint16, dstId *uint16, descriptors []WC
} }
r0, _, _ := syscall.Syscall6(procCopyLayer.Addr(), 5, uintptr(unsafe.Pointer(info)), uintptr(unsafe.Pointer(srcId)), uintptr(unsafe.Pointer(dstId)), uintptr(unsafe.Pointer(_p2)), uintptr(len(descriptors)), 0) r0, _, _ := syscall.Syscall6(procCopyLayer.Addr(), 5, uintptr(unsafe.Pointer(info)), uintptr(unsafe.Pointer(srcId)), uintptr(unsafe.Pointer(dstId)), uintptr(unsafe.Pointer(_p2)), uintptr(len(descriptors)), 0)
if int32(r0) < 0 { if int32(r0) < 0 {
hr = interop.Win32FromHresult(r0) if r0&0x1fff0000 == 0x00070000 {
r0 &= 0xffff
}
hr = syscall.Errno(r0)
} }
return return
} }
@ -138,7 +134,10 @@ func _createLayer(info *driverInfo, id *uint16, parent *uint16) (hr error) {
} }
r0, _, _ := syscall.Syscall(procCreateLayer.Addr(), 3, uintptr(unsafe.Pointer(info)), uintptr(unsafe.Pointer(id)), uintptr(unsafe.Pointer(parent))) r0, _, _ := syscall.Syscall(procCreateLayer.Addr(), 3, uintptr(unsafe.Pointer(info)), uintptr(unsafe.Pointer(id)), uintptr(unsafe.Pointer(parent)))
if int32(r0) < 0 { if int32(r0) < 0 {
hr = interop.Win32FromHresult(r0) if r0&0x1fff0000 == 0x00070000 {
r0 &= 0xffff
}
hr = syscall.Errno(r0)
} }
return return
} }
@ -162,7 +161,10 @@ func _createSandboxLayer(info *driverInfo, id *uint16, parent uintptr, descripto
} }
r0, _, _ := syscall.Syscall6(procCreateSandboxLayer.Addr(), 5, uintptr(unsafe.Pointer(info)), uintptr(unsafe.Pointer(id)), uintptr(parent), uintptr(unsafe.Pointer(_p1)), uintptr(len(descriptors)), 0) r0, _, _ := syscall.Syscall6(procCreateSandboxLayer.Addr(), 5, uintptr(unsafe.Pointer(info)), uintptr(unsafe.Pointer(id)), uintptr(parent), uintptr(unsafe.Pointer(_p1)), uintptr(len(descriptors)), 0)
if int32(r0) < 0 { if int32(r0) < 0 {
hr = interop.Win32FromHresult(r0) if r0&0x1fff0000 == 0x00070000 {
r0 &= 0xffff
}
hr = syscall.Errno(r0)
} }
return return
} }
@ -182,7 +184,10 @@ func _expandSandboxSize(info *driverInfo, id *uint16, size uint64) (hr error) {
} }
r0, _, _ := syscall.Syscall(procExpandSandboxSize.Addr(), 3, uintptr(unsafe.Pointer(info)), uintptr(unsafe.Pointer(id)), uintptr(size)) r0, _, _ := syscall.Syscall(procExpandSandboxSize.Addr(), 3, uintptr(unsafe.Pointer(info)), uintptr(unsafe.Pointer(id)), uintptr(size))
if int32(r0) < 0 { if int32(r0) < 0 {
hr = interop.Win32FromHresult(r0) if r0&0x1fff0000 == 0x00070000 {
r0 &= 0xffff
}
hr = syscall.Errno(r0)
} }
return return
} }
@ -202,7 +207,10 @@ func _deactivateLayer(info *driverInfo, id *uint16) (hr error) {
} }
r0, _, _ := syscall.Syscall(procDeactivateLayer.Addr(), 2, uintptr(unsafe.Pointer(info)), uintptr(unsafe.Pointer(id)), 0) r0, _, _ := syscall.Syscall(procDeactivateLayer.Addr(), 2, uintptr(unsafe.Pointer(info)), uintptr(unsafe.Pointer(id)), 0)
if int32(r0) < 0 { if int32(r0) < 0 {
hr = interop.Win32FromHresult(r0) if r0&0x1fff0000 == 0x00070000 {
r0 &= 0xffff
}
hr = syscall.Errno(r0)
} }
return return
} }
@ -222,7 +230,10 @@ func _destroyLayer(info *driverInfo, id *uint16) (hr error) {
} }
r0, _, _ := syscall.Syscall(procDestroyLayer.Addr(), 2, uintptr(unsafe.Pointer(info)), uintptr(unsafe.Pointer(id)), 0) r0, _, _ := syscall.Syscall(procDestroyLayer.Addr(), 2, uintptr(unsafe.Pointer(info)), uintptr(unsafe.Pointer(id)), 0)
if int32(r0) < 0 { if int32(r0) < 0 {
hr = interop.Win32FromHresult(r0) if r0&0x1fff0000 == 0x00070000 {
r0 &= 0xffff
}
hr = syscall.Errno(r0)
} }
return return
} }
@ -251,7 +262,10 @@ func _exportLayer(info *driverInfo, id *uint16, path *uint16, descriptors []WC_L
} }
r0, _, _ := syscall.Syscall6(procExportLayer.Addr(), 5, uintptr(unsafe.Pointer(info)), uintptr(unsafe.Pointer(id)), uintptr(unsafe.Pointer(path)), uintptr(unsafe.Pointer(_p2)), uintptr(len(descriptors)), 0) r0, _, _ := syscall.Syscall6(procExportLayer.Addr(), 5, uintptr(unsafe.Pointer(info)), uintptr(unsafe.Pointer(id)), uintptr(unsafe.Pointer(path)), uintptr(unsafe.Pointer(_p2)), uintptr(len(descriptors)), 0)
if int32(r0) < 0 { if int32(r0) < 0 {
hr = interop.Win32FromHresult(r0) if r0&0x1fff0000 == 0x00070000 {
r0 &= 0xffff
}
hr = syscall.Errno(r0)
} }
return return
} }
@ -271,7 +285,10 @@ func _getLayerMountPath(info *driverInfo, id *uint16, length *uintptr, buffer *u
} }
r0, _, _ := syscall.Syscall6(procGetLayerMountPath.Addr(), 4, uintptr(unsafe.Pointer(info)), uintptr(unsafe.Pointer(id)), uintptr(unsafe.Pointer(length)), uintptr(unsafe.Pointer(buffer)), 0, 0) r0, _, _ := syscall.Syscall6(procGetLayerMountPath.Addr(), 4, uintptr(unsafe.Pointer(info)), uintptr(unsafe.Pointer(id)), uintptr(unsafe.Pointer(length)), uintptr(unsafe.Pointer(buffer)), 0, 0)
if int32(r0) < 0 { if int32(r0) < 0 {
hr = interop.Win32FromHresult(r0) if r0&0x1fff0000 == 0x00070000 {
r0 &= 0xffff
}
hr = syscall.Errno(r0)
} }
return return
} }
@ -282,7 +299,10 @@ func getBaseImages(buffer **uint16) (hr error) {
} }
r0, _, _ := syscall.Syscall(procGetBaseImages.Addr(), 1, uintptr(unsafe.Pointer(buffer)), 0, 0) r0, _, _ := syscall.Syscall(procGetBaseImages.Addr(), 1, uintptr(unsafe.Pointer(buffer)), 0, 0)
if int32(r0) < 0 { if int32(r0) < 0 {
hr = interop.Win32FromHresult(r0) if r0&0x1fff0000 == 0x00070000 {
r0 &= 0xffff
}
hr = syscall.Errno(r0)
} }
return return
} }
@ -311,7 +331,10 @@ func _importLayer(info *driverInfo, id *uint16, path *uint16, descriptors []WC_L
} }
r0, _, _ := syscall.Syscall6(procImportLayer.Addr(), 5, uintptr(unsafe.Pointer(info)), uintptr(unsafe.Pointer(id)), uintptr(unsafe.Pointer(path)), uintptr(unsafe.Pointer(_p2)), uintptr(len(descriptors)), 0) r0, _, _ := syscall.Syscall6(procImportLayer.Addr(), 5, uintptr(unsafe.Pointer(info)), uintptr(unsafe.Pointer(id)), uintptr(unsafe.Pointer(path)), uintptr(unsafe.Pointer(_p2)), uintptr(len(descriptors)), 0)
if int32(r0) < 0 { if int32(r0) < 0 {
hr = interop.Win32FromHresult(r0) if r0&0x1fff0000 == 0x00070000 {
r0 &= 0xffff
}
hr = syscall.Errno(r0)
} }
return return
} }
@ -331,7 +354,10 @@ func _layerExists(info *driverInfo, id *uint16, exists *uint32) (hr error) {
} }
r0, _, _ := syscall.Syscall(procLayerExists.Addr(), 3, uintptr(unsafe.Pointer(info)), uintptr(unsafe.Pointer(id)), uintptr(unsafe.Pointer(exists))) r0, _, _ := syscall.Syscall(procLayerExists.Addr(), 3, uintptr(unsafe.Pointer(info)), uintptr(unsafe.Pointer(id)), uintptr(unsafe.Pointer(exists)))
if int32(r0) < 0 { if int32(r0) < 0 {
hr = interop.Win32FromHresult(r0) if r0&0x1fff0000 == 0x00070000 {
r0 &= 0xffff
}
hr = syscall.Errno(r0)
} }
return return
} }
@ -351,7 +377,10 @@ func _nameToGuid(name *uint16, guid *_guid) (hr error) {
} }
r0, _, _ := syscall.Syscall(procNameToGuid.Addr(), 2, uintptr(unsafe.Pointer(name)), uintptr(unsafe.Pointer(guid)), 0) r0, _, _ := syscall.Syscall(procNameToGuid.Addr(), 2, uintptr(unsafe.Pointer(name)), uintptr(unsafe.Pointer(guid)), 0)
if int32(r0) < 0 { if int32(r0) < 0 {
hr = interop.Win32FromHresult(r0) if r0&0x1fff0000 == 0x00070000 {
r0 &= 0xffff
}
hr = syscall.Errno(r0)
} }
return return
} }
@ -375,7 +404,10 @@ func _prepareLayer(info *driverInfo, id *uint16, descriptors []WC_LAYER_DESCRIPT
} }
r0, _, _ := syscall.Syscall6(procPrepareLayer.Addr(), 4, uintptr(unsafe.Pointer(info)), uintptr(unsafe.Pointer(id)), uintptr(unsafe.Pointer(_p1)), uintptr(len(descriptors)), 0, 0) r0, _, _ := syscall.Syscall6(procPrepareLayer.Addr(), 4, uintptr(unsafe.Pointer(info)), uintptr(unsafe.Pointer(id)), uintptr(unsafe.Pointer(_p1)), uintptr(len(descriptors)), 0, 0)
if int32(r0) < 0 { if int32(r0) < 0 {
hr = interop.Win32FromHresult(r0) if r0&0x1fff0000 == 0x00070000 {
r0 &= 0xffff
}
hr = syscall.Errno(r0)
} }
return return
} }
@ -395,7 +427,10 @@ func _unprepareLayer(info *driverInfo, id *uint16) (hr error) {
} }
r0, _, _ := syscall.Syscall(procUnprepareLayer.Addr(), 2, uintptr(unsafe.Pointer(info)), uintptr(unsafe.Pointer(id)), 0) r0, _, _ := syscall.Syscall(procUnprepareLayer.Addr(), 2, uintptr(unsafe.Pointer(info)), uintptr(unsafe.Pointer(id)), 0)
if int32(r0) < 0 { if int32(r0) < 0 {
hr = interop.Win32FromHresult(r0) if r0&0x1fff0000 == 0x00070000 {
r0 &= 0xffff
}
hr = syscall.Errno(r0)
} }
return return
} }
@ -415,7 +450,10 @@ func _processBaseImage(path *uint16) (hr error) {
} }
r0, _, _ := syscall.Syscall(procProcessBaseImage.Addr(), 1, uintptr(unsafe.Pointer(path)), 0, 0) r0, _, _ := syscall.Syscall(procProcessBaseImage.Addr(), 1, uintptr(unsafe.Pointer(path)), 0, 0)
if int32(r0) < 0 { if int32(r0) < 0 {
hr = interop.Win32FromHresult(r0) if r0&0x1fff0000 == 0x00070000 {
r0 &= 0xffff
}
hr = syscall.Errno(r0)
} }
return return
} }
@ -435,138 +473,10 @@ func _processUtilityImage(path *uint16) (hr error) {
} }
r0, _, _ := syscall.Syscall(procProcessUtilityImage.Addr(), 1, uintptr(unsafe.Pointer(path)), 0, 0) r0, _, _ := syscall.Syscall(procProcessUtilityImage.Addr(), 1, uintptr(unsafe.Pointer(path)), 0, 0)
if int32(r0) < 0 { if int32(r0) < 0 {
hr = interop.Win32FromHresult(r0) if r0&0x1fff0000 == 0x00070000 {
} r0 &= 0xffff
return }
} hr = syscall.Errno(r0)
func importLayerBegin(info *driverInfo, id string, descriptors []WC_LAYER_DESCRIPTOR, context *uintptr) (hr error) {
var _p0 *uint16
_p0, hr = syscall.UTF16PtrFromString(id)
if hr != nil {
return
}
return _importLayerBegin(info, _p0, descriptors, context)
}
func _importLayerBegin(info *driverInfo, id *uint16, descriptors []WC_LAYER_DESCRIPTOR, context *uintptr) (hr error) {
var _p1 *WC_LAYER_DESCRIPTOR
if len(descriptors) > 0 {
_p1 = &descriptors[0]
}
if hr = procImportLayerBegin.Find(); hr != nil {
return
}
r0, _, _ := syscall.Syscall6(procImportLayerBegin.Addr(), 5, uintptr(unsafe.Pointer(info)), uintptr(unsafe.Pointer(id)), uintptr(unsafe.Pointer(_p1)), uintptr(len(descriptors)), uintptr(unsafe.Pointer(context)), 0)
if int32(r0) < 0 {
hr = interop.Win32FromHresult(r0)
}
return
}
func importLayerNext(context uintptr, fileName string, fileInfo *winio.FileBasicInfo) (hr error) {
var _p0 *uint16
_p0, hr = syscall.UTF16PtrFromString(fileName)
if hr != nil {
return
}
return _importLayerNext(context, _p0, fileInfo)
}
func _importLayerNext(context uintptr, fileName *uint16, fileInfo *winio.FileBasicInfo) (hr error) {
if hr = procImportLayerNext.Find(); hr != nil {
return
}
r0, _, _ := syscall.Syscall(procImportLayerNext.Addr(), 3, uintptr(context), uintptr(unsafe.Pointer(fileName)), uintptr(unsafe.Pointer(fileInfo)))
if int32(r0) < 0 {
hr = interop.Win32FromHresult(r0)
}
return
}
func importLayerWrite(context uintptr, buffer []byte) (hr error) {
var _p0 *byte
if len(buffer) > 0 {
_p0 = &buffer[0]
}
if hr = procImportLayerWrite.Find(); hr != nil {
return
}
r0, _, _ := syscall.Syscall(procImportLayerWrite.Addr(), 3, uintptr(context), uintptr(unsafe.Pointer(_p0)), uintptr(len(buffer)))
if int32(r0) < 0 {
hr = interop.Win32FromHresult(r0)
}
return
}
func importLayerEnd(context uintptr) (hr error) {
if hr = procImportLayerEnd.Find(); hr != nil {
return
}
r0, _, _ := syscall.Syscall(procImportLayerEnd.Addr(), 1, uintptr(context), 0, 0)
if int32(r0) < 0 {
hr = interop.Win32FromHresult(r0)
}
return
}
func exportLayerBegin(info *driverInfo, id string, descriptors []WC_LAYER_DESCRIPTOR, context *uintptr) (hr error) {
var _p0 *uint16
_p0, hr = syscall.UTF16PtrFromString(id)
if hr != nil {
return
}
return _exportLayerBegin(info, _p0, descriptors, context)
}
func _exportLayerBegin(info *driverInfo, id *uint16, descriptors []WC_LAYER_DESCRIPTOR, context *uintptr) (hr error) {
var _p1 *WC_LAYER_DESCRIPTOR
if len(descriptors) > 0 {
_p1 = &descriptors[0]
}
if hr = procExportLayerBegin.Find(); hr != nil {
return
}
r0, _, _ := syscall.Syscall6(procExportLayerBegin.Addr(), 5, uintptr(unsafe.Pointer(info)), uintptr(unsafe.Pointer(id)), uintptr(unsafe.Pointer(_p1)), uintptr(len(descriptors)), uintptr(unsafe.Pointer(context)), 0)
if int32(r0) < 0 {
hr = interop.Win32FromHresult(r0)
}
return
}
func exportLayerNext(context uintptr, fileName **uint16, fileInfo *winio.FileBasicInfo, fileSize *int64, deleted *uint32) (hr error) {
if hr = procExportLayerNext.Find(); hr != nil {
return
}
r0, _, _ := syscall.Syscall6(procExportLayerNext.Addr(), 5, uintptr(context), uintptr(unsafe.Pointer(fileName)), uintptr(unsafe.Pointer(fileInfo)), uintptr(unsafe.Pointer(fileSize)), uintptr(unsafe.Pointer(deleted)), 0)
if int32(r0) < 0 {
hr = interop.Win32FromHresult(r0)
}
return
}
func exportLayerRead(context uintptr, buffer []byte, bytesRead *uint32) (hr error) {
var _p0 *byte
if len(buffer) > 0 {
_p0 = &buffer[0]
}
if hr = procExportLayerRead.Find(); hr != nil {
return
}
r0, _, _ := syscall.Syscall6(procExportLayerRead.Addr(), 4, uintptr(context), uintptr(unsafe.Pointer(_p0)), uintptr(len(buffer)), uintptr(unsafe.Pointer(bytesRead)), 0, 0)
if int32(r0) < 0 {
hr = interop.Win32FromHresult(r0)
}
return
}
func exportLayerEnd(context uintptr) (hr error) {
if hr = procExportLayerEnd.Find(); hr != nil {
return
}
r0, _, _ := syscall.Syscall(procExportLayerEnd.Addr(), 1, uintptr(context), 0, 0)
if int32(r0) < 0 {
hr = interop.Win32FromHresult(r0)
} }
return return
} }
@ -591,7 +501,10 @@ func _grantVmAccess(vmid *uint16, filepath *uint16) (hr error) {
} }
r0, _, _ := syscall.Syscall(procGrantVmAccess.Addr(), 2, uintptr(unsafe.Pointer(vmid)), uintptr(unsafe.Pointer(filepath)), 0) r0, _, _ := syscall.Syscall(procGrantVmAccess.Addr(), 2, uintptr(unsafe.Pointer(vmid)), uintptr(unsafe.Pointer(filepath)), 0)
if int32(r0) < 0 { if int32(r0) < 0 {
hr = interop.Win32FromHresult(r0) if r0&0x1fff0000 == 0x00070000 {
r0 &= 0xffff
}
hr = syscall.Errno(r0)
} }
return return
} }

View File

@ -5,7 +5,6 @@ import (
"path/filepath" "path/filepath"
"github.com/Microsoft/hcsshim/internal/guid" "github.com/Microsoft/hcsshim/internal/guid"
"github.com/Microsoft/hcsshim/internal/wclayer" "github.com/Microsoft/hcsshim/internal/wclayer"
) )
@ -74,9 +73,6 @@ type DriverInfo struct {
HomeDir string HomeDir string
} }
type FilterLayerReader = wclayer.FilterLayerReader
type FilterLayerWriter = wclayer.FilterLayerWriter
type GUID [16]byte type GUID [16]byte
func NameToGuid(name string) (id GUID, err error) { func NameToGuid(name string) (id GUID, err error) {

21
vendor/github.com/Microsoft/hcsshim/vendor.conf generated vendored Normal file
View File

@ -0,0 +1,21 @@
github.com/blang/semver v3.1.0
github.com/containerd/console c12b1e7919c14469339a5d38f2f8ed9b64a9de23
github.com/containerd/go-runc 5a6d9f37cfa36b15efba46dc7ea349fa9b7143c3
github.com/hashicorp/errwrap 7554cd9344cec97297fa6649b055a8c98c2a1e55
github.com/hashicorp/go-multierror ed905158d87462226a13fe39ddf685ea65f1c11f
github.com/konsorten/go-windows-terminal-sequences v1.0.1
github.com/linuxkit/virtsock 8e79449dea0735c1c056d814934dd035734cc97c
github.com/Microsoft/go-winio 16cfc975803886a5e47c4257a24c8d8c52e178b2
github.com/Microsoft/opengcs v0.3.9
github.com/opencontainers/runtime-spec eba862dc2470385a233c7507392675cbeadf7353
github.com/opencontainers/runtime-tools 1d69bd0f9c39677d0630e50664fbc3154ae61b88
github.com/pkg/errors v0.8.1
github.com/sirupsen/logrus v1.3.0
github.com/syndtr/gocapability db04d3cc01c8b54962a58ec7e491717d06cfcc16
github.com/urfave/cli 7bc6a0acffa589f415f88aca16cc1de5ffd66f9c
github.com/xeipuuv/gojsonpointer 4e3ac2762d5f479393488629ee9370b50873b3a6
github.com/xeipuuv/gojsonreference bd5ef7bd5415a7ac448318e64f11a24cd21e594b
github.com/xeipuuv/gojsonschema 1d523034197ff1f222f6429836dd36a2457a1874
golang.org/x/crypto ff983b9c42bc9fbf91556e191cc8efb585c16908
golang.org/x/sync 37e7f081c4d4c64e13b10787722085407fe5d15f
golang.org/x/sys e5ecc2a6747ce8d4af18ed98b3de5ae30eb3a5bb

View File

@ -1,4 +1,4 @@
// MACHINE GENERATED BY 'go generate' COMMAND; DO NOT EDIT // Code generated mksyscall_windows.exe DO NOT EDIT
package hcsshim package hcsshim
@ -6,7 +6,6 @@ import (
"syscall" "syscall"
"unsafe" "unsafe"
"github.com/Microsoft/hcsshim/internal/interop"
"golang.org/x/sys/windows" "golang.org/x/sys/windows"
) )
@ -46,7 +45,10 @@ var (
func SetCurrentThreadCompartmentId(compartmentId uint32) (hr error) { func SetCurrentThreadCompartmentId(compartmentId uint32) (hr error) {
r0, _, _ := syscall.Syscall(procSetCurrentThreadCompartmentId.Addr(), 1, uintptr(compartmentId), 0, 0) r0, _, _ := syscall.Syscall(procSetCurrentThreadCompartmentId.Addr(), 1, uintptr(compartmentId), 0, 0)
if int32(r0) < 0 { if int32(r0) < 0 {
hr = interop.Win32FromHresult(r0) if r0&0x1fff0000 == 0x00070000 {
r0 &= 0xffff
}
hr = syscall.Errno(r0)
} }
return return
} }

View File

@ -1,8 +1,9 @@
# cgroups # cgroups
[![Build Status](https://travis-ci.org/containerd/cgroups.svg?branch=master)](https://travis-ci.org/containerd/cgroups) [![Build Status](https://travis-ci.org/containerd/cgroups.svg?branch=master)](https://travis-ci.org/containerd/cgroups)
[![codecov](https://codecov.io/gh/containerd/cgroups/branch/master/graph/badge.svg)](https://codecov.io/gh/containerd/cgroups) [![codecov](https://codecov.io/gh/containerd/cgroups/branch/master/graph/badge.svg)](https://codecov.io/gh/containerd/cgroups)
[![GoDoc](https://godoc.org/github.com/containerd/cgroups?status.svg)](https://godoc.org/github.com/containerd/cgroups)
[![Go Report Card](https://goreportcard.com/badge/github.com/containerd/cgroups)](https://goreportcard.com/report/github.com/containerd/cgroups)
Go package for creating, managing, inspecting, and destroying cgroups. Go package for creating, managing, inspecting, and destroying cgroups.
The resources format for settings on the cgroup uses the OCI runtime-spec found The resources format for settings on the cgroup uses the OCI runtime-spec found
@ -110,3 +111,14 @@ err := control.MoveTo(destination)
```go ```go
subCgroup, err := control.New("child", resources) subCgroup, err := control.New("child", resources)
``` ```
## Project details
Cgroups is a containerd sub-project, licensed under the [Apache 2.0 license](./LICENSE).
As a containerd sub-project, you will find the:
* [Project governance](https://github.com/containerd/project/blob/master/GOVERNANCE.md),
* [Maintainers](https://github.com/containerd/project/blob/master/MAINTAINERS),
* and [Contributing guidelines](https://github.com/containerd/project/blob/master/CONTRIBUTING.md)
information in our [`containerd/project`](https://github.com/containerd/project) repository.

View File

@ -191,31 +191,42 @@ func (b *blkioController) readEntry(devices map[deviceKey]string, path, name str
} }
func createBlkioSettings(blkio *specs.LinuxBlockIO) []blkioSettings { func createBlkioSettings(blkio *specs.LinuxBlockIO) []blkioSettings {
settings := []blkioSettings{ settings := []blkioSettings{}
{
name: "weight", if blkio.Weight != nil {
value: blkio.Weight,
format: uintf,
},
{
name: "leaf_weight",
value: blkio.LeafWeight,
format: uintf,
},
}
for _, wd := range blkio.WeightDevice {
settings = append(settings, settings = append(settings,
blkioSettings{ blkioSettings{
name: "weight_device", name: "weight",
value: wd, value: blkio.Weight,
format: weightdev, format: uintf,
},
blkioSettings{
name: "leaf_weight_device",
value: wd,
format: weightleafdev,
}) })
} }
if blkio.LeafWeight != nil {
settings = append(settings,
blkioSettings{
name: "leaf_weight",
value: blkio.LeafWeight,
format: uintf,
})
}
for _, wd := range blkio.WeightDevice {
if wd.Weight != nil {
settings = append(settings,
blkioSettings{
name: "weight_device",
value: wd,
format: weightdev,
})
}
if wd.LeafWeight != nil {
settings = append(settings,
blkioSettings{
name: "leaf_weight_device",
value: wd,
format: weightleafdev,
})
}
}
for _, t := range []struct { for _, t := range []struct {
name string name string
list []specs.LinuxThrottleDevice list []specs.LinuxThrottleDevice
@ -265,12 +276,12 @@ func uintf(v interface{}) []byte {
func weightdev(v interface{}) []byte { func weightdev(v interface{}) []byte {
wd := v.(specs.LinuxWeightDevice) wd := v.(specs.LinuxWeightDevice)
return []byte(fmt.Sprintf("%d:%d %d", wd.Major, wd.Minor, wd.Weight)) return []byte(fmt.Sprintf("%d:%d %d", wd.Major, wd.Minor, *wd.Weight))
} }
func weightleafdev(v interface{}) []byte { func weightleafdev(v interface{}) []byte {
wd := v.(specs.LinuxWeightDevice) wd := v.(specs.LinuxWeightDevice)
return []byte(fmt.Sprintf("%d:%d %d", wd.Major, wd.Minor, wd.LeafWeight)) return []byte(fmt.Sprintf("%d:%d %d", wd.Major, wd.Minor, *wd.LeafWeight))
} }
func throttleddev(v interface{}) []byte { func throttleddev(v interface{}) []byte {

View File

@ -48,11 +48,12 @@ func New(hierarchy Hierarchy, path Path, resources *specs.LinuxResources) (Cgrou
// Load will load an existing cgroup and allow it to be controlled // Load will load an existing cgroup and allow it to be controlled
func Load(hierarchy Hierarchy, path Path) (Cgroup, error) { func Load(hierarchy Hierarchy, path Path) (Cgroup, error) {
var activeSubsystems []Subsystem
subsystems, err := hierarchy() subsystems, err := hierarchy()
if err != nil { if err != nil {
return nil, err return nil, err
} }
// check the the subsystems still exist // check that the subsystems still exist, and keep only those that actually exist
for _, s := range pathers(subsystems) { for _, s := range pathers(subsystems) {
p, err := path(s.Name()) p, err := path(s.Name())
if err != nil { if err != nil {
@ -63,14 +64,15 @@ func Load(hierarchy Hierarchy, path Path) (Cgroup, error) {
} }
if _, err := os.Lstat(s.Path(p)); err != nil { if _, err := os.Lstat(s.Path(p)); err != nil {
if os.IsNotExist(err) { if os.IsNotExist(err) {
return nil, ErrCgroupDeleted continue
} }
return nil, err return nil, err
} }
activeSubsystems = append(activeSubsystems, s)
} }
return &cgroup{ return &cgroup{
path: path, path: path,
subsystems: subsystems, subsystems: activeSubsystems,
}, nil }, nil
} }
@ -319,6 +321,49 @@ func (c *cgroup) processes(subsystem Name, recursive bool) ([]Process, error) {
return processes, err return processes, err
} }
// Tasks returns the tasks running inside the cgroup along
// with the subsystem used, pid, and path
func (c *cgroup) Tasks(subsystem Name, recursive bool) ([]Task, error) {
c.mu.Lock()
defer c.mu.Unlock()
if c.err != nil {
return nil, c.err
}
return c.tasks(subsystem, recursive)
}
func (c *cgroup) tasks(subsystem Name, recursive bool) ([]Task, error) {
s := c.getSubsystem(subsystem)
sp, err := c.path(subsystem)
if err != nil {
return nil, err
}
path := s.(pather).Path(sp)
var tasks []Task
err = filepath.Walk(path, func(p string, info os.FileInfo, err error) error {
if err != nil {
return err
}
if !recursive && info.IsDir() {
if p == path {
return nil
}
return filepath.SkipDir
}
dir, name := filepath.Split(p)
if name != cgroupTasks {
return nil
}
procs, err := readTasksPids(dir, subsystem)
if err != nil {
return err
}
tasks = append(tasks, procs...)
return nil
})
return tasks, err
}
// Freeze freezes the entire cgroup and all the processes inside it // Freeze freezes the entire cgroup and all the processes inside it
func (c *cgroup) Freeze() error { func (c *cgroup) Freeze() error {
c.mu.Lock() c.mu.Lock()

View File

@ -44,6 +44,15 @@ type Process struct {
Path string Path string
} }
type Task struct {
// Subsystem is the name of the subsystem that the task is in
Subsystem Name
// Pid is the process id of the task
Pid int
// Path is the full path of the subsystem and location that the task is in
Path string
}
// Cgroup handles interactions with the individual groups to perform // Cgroup handles interactions with the individual groups to perform
// actions on them as them main interface to this cgroup package // actions on them as them main interface to this cgroup package
type Cgroup interface { type Cgroup interface {
@ -64,6 +73,8 @@ type Cgroup interface {
Update(resources *specs.LinuxResources) error Update(resources *specs.LinuxResources) error
// Processes returns all the processes in a select subsystem for the cgroup // Processes returns all the processes in a select subsystem for the cgroup
Processes(Name, bool) ([]Process, error) Processes(Name, bool) ([]Process, error)
// Tasks returns all the tasks in a select subsystem for the cgroup
Tasks(Name, bool) ([]Task, error)
// Freeze freezes or pauses all processes inside the cgroup // Freeze freezes or pauses all processes inside the cgroup
Freeze() error Freeze() error
// Thaw thaw or resumes all processes inside the cgroup // Thaw thaw or resumes all processes inside the cgroup

View File

@ -57,21 +57,21 @@ func (c *cpusetController) Create(path string, resources *specs.LinuxResources)
if resources.CPU != nil { if resources.CPU != nil {
for _, t := range []struct { for _, t := range []struct {
name string name string
value *string value string
}{ }{
{ {
name: "cpus", name: "cpus",
value: &resources.CPU.Cpus, value: resources.CPU.Cpus,
}, },
{ {
name: "mems", name: "mems",
value: &resources.CPU.Mems, value: resources.CPU.Mems,
}, },
} { } {
if t.value != nil { if t.value != "" {
if err := ioutil.WriteFile( if err := ioutil.WriteFile(
filepath.Join(c.Path(path), fmt.Sprintf("cpuset.%s", t.name)), filepath.Join(c.Path(path), fmt.Sprintf("cpuset.%s", t.name)),
[]byte(*t.value), []byte(t.value),
defaultFilePerm, defaultFilePerm,
); err != nil { ); err != nil {
return err return err

View File

@ -58,6 +58,9 @@ func (d *devicesController) Create(path string, resources *specs.LinuxResources)
if device.Allow { if device.Allow {
file = allowDeviceFile file = allowDeviceFile
} }
if device.Type == "" {
device.Type = "a"
}
if err := ioutil.WriteFile( if err := ioutil.WriteFile(
filepath.Join(d.Path(path), file), filepath.Join(d.Path(path), file),
[]byte(deviceString(device)), []byte(deviceString(device)),

View File

@ -50,7 +50,7 @@ func (n *netprioController) Create(path string, resources *specs.LinuxResources)
if resources.Network != nil { if resources.Network != nil {
for _, prio := range resources.Network.Priorities { for _, prio := range resources.Network.Priorities {
if err := ioutil.WriteFile( if err := ioutil.WriteFile(
filepath.Join(n.Path(path), "net_prio_ifpriomap"), filepath.Join(n.Path(path), "net_prio.ifpriomap"),
formatPrio(prio.Name, prio.Priority), formatPrio(prio.Name, prio.Priority),
defaultFilePerm, defaultFilePerm,
); err != nil { ); err != nil {

View File

@ -42,7 +42,7 @@ const (
) )
// Subsystems returns a complete list of the default cgroups // Subsystems returns a complete list of the default cgroups
// avaliable on most linux systems // available on most linux systems
func Subsystems() []Name { func Subsystems() []Name {
n := []Name{ n := []Name{
Hugetlb, Hugetlb,

View File

@ -32,6 +32,11 @@ const (
defaultSlice = "system.slice" defaultSlice = "system.slice"
) )
var (
canDelegate bool
once sync.Once
)
func Systemd() ([]Subsystem, error) { func Systemd() ([]Subsystem, error) {
root, err := v1MountPoint() root, err := v1MountPoint()
if err != nil { if err != nil {
@ -54,7 +59,7 @@ func Slice(slice, name string) Path {
slice = defaultSlice slice = defaultSlice
} }
return func(subsystem Name) (string, error) { return func(subsystem Name) (string, error) {
return filepath.Join(slice, unitName(name)), nil return filepath.Join(slice, name), nil
} }
} }
@ -80,15 +85,39 @@ func (s *SystemdController) Create(path string, resources *specs.LinuxResources)
} }
defer conn.Close() defer conn.Close()
slice, name := splitName(path) slice, name := splitName(path)
// We need to see if systemd can handle the delegate property
// Systemd will return an error if it cannot handle delegate regardless
// of its bool setting.
checkDelegate := func() {
canDelegate = true
dlSlice := newProperty("Delegate", true)
if _, err := conn.StartTransientUnit(slice, "testdelegate", []systemdDbus.Property{dlSlice}, nil); err != nil {
if dbusError, ok := err.(dbus.Error); ok {
// Starting with systemd v237, Delegate is not even a property of slices anymore,
// so the D-Bus call fails with "InvalidArgs" error.
if strings.Contains(dbusError.Name, "org.freedesktop.DBus.Error.PropertyReadOnly") || strings.Contains(dbusError.Name, "org.freedesktop.DBus.Error.InvalidArgs") {
canDelegate = false
}
}
}
conn.StopUnit(slice, "testDelegate", nil)
}
once.Do(checkDelegate)
properties := []systemdDbus.Property{ properties := []systemdDbus.Property{
systemdDbus.PropDescription(fmt.Sprintf("cgroup %s", name)), systemdDbus.PropDescription(fmt.Sprintf("cgroup %s", name)),
systemdDbus.PropWants(slice), systemdDbus.PropWants(slice),
newProperty("DefaultDependencies", false), newProperty("DefaultDependencies", false),
newProperty("Delegate", true),
newProperty("MemoryAccounting", true), newProperty("MemoryAccounting", true),
newProperty("CPUAccounting", true), newProperty("CPUAccounting", true),
newProperty("BlockIOAccounting", true), newProperty("BlockIOAccounting", true),
} }
// If we can delegate, we add the property back in
if canDelegate {
properties = append(properties, newProperty("Delegate", true))
}
ch := make(chan string) ch := make(chan string)
_, err = conn.StartTransientUnit(name, "replace", properties, ch) _, err = conn.StartTransientUnit(name, "replace", properties, ch)
if err != nil { if err != nil {

View File

@ -111,7 +111,7 @@ func remove(path string) error {
return fmt.Errorf("cgroups: unable to remove path %q", path) return fmt.Errorf("cgroups: unable to remove path %q", path)
} }
// readPids will read all the pids in a cgroup by the provided path // readPids will read all the pids of processes in a cgroup by the provided path
func readPids(path string, subsystem Name) ([]Process, error) { func readPids(path string, subsystem Name) ([]Process, error) {
f, err := os.Open(filepath.Join(path, cgroupProcs)) f, err := os.Open(filepath.Join(path, cgroupProcs))
if err != nil { if err != nil {
@ -138,6 +138,33 @@ func readPids(path string, subsystem Name) ([]Process, error) {
return out, nil return out, nil
} }
// readTasksPids will read all the pids of tasks in a cgroup by the provided path
func readTasksPids(path string, subsystem Name) ([]Task, error) {
f, err := os.Open(filepath.Join(path, cgroupTasks))
if err != nil {
return nil, err
}
defer f.Close()
var (
out []Task
s = bufio.NewScanner(f)
)
for s.Scan() {
if t := s.Text(); t != "" {
pid, err := strconv.Atoi(t)
if err != nil {
return nil, err
}
out = append(out, Task{
Pid: pid,
Subsystem: subsystem,
Path: path,
})
}
}
return out, nil
}
func hugePageSizes() ([]string, error) { func hugePageSizes() ([]string, error) {
var ( var (
pageSizes []string pageSizes []string

View File

@ -172,11 +172,9 @@ checkpoint, err := task.Checkpoint(context)
err := client.Push(context, "myregistry/checkpoints/redis:master", checkpoint) err := client.Push(context, "myregistry/checkpoints/redis:master", checkpoint)
// on a new machine pull the checkpoint and restore the redis container // on a new machine pull the checkpoint and restore the redis container
image, err := client.Pull(context, "myregistry/checkpoints/redis:master") checkpoint, err := client.Pull(context, "myregistry/checkpoints/redis:master")
checkpoint := image.Target() redis, err = client.NewContainer(context, "redis-master", containerd.WithNewSnapshot("redis-rootfs", checkpoint))
redis, err = client.NewContainer(context, "redis-master", containerd.WithCheckpoint(checkpoint, "redis-rootfs"))
defer container.Delete(context) defer container.Delete(context)
task, err = redis.NewTask(context, cio.Stdio, containerd.WithTaskCheckpoint(checkpoint)) task, err = redis.NewTask(context, cio.Stdio, containerd.WithTaskCheckpoint(checkpoint))
@ -212,11 +210,6 @@ See [PLUGINS.md](PLUGINS.md) for how to create plugins
Please see [RELEASES.md](RELEASES.md) for details on versioning and stability Please see [RELEASES.md](RELEASES.md) for details on versioning and stability
of containerd components. of containerd components.
### Development reports.
Weekly summary on the progress and what is being worked on.
https://github.com/containerd/containerd/tree/master/reports
### Communication ### Communication
For async communication and long running discussions please use issues and pull requests on the github repo. For async communication and long running discussions please use issues and pull requests on the github repo.
@ -227,6 +220,10 @@ For sync communication we have a community slack with a #containerd channel that
**Slack:** Catch us in the #containerd and #containerd-dev channels on dockercommunity.slack.com. **Slack:** Catch us in the #containerd and #containerd-dev channels on dockercommunity.slack.com.
[Click here for an invite to docker community slack.](https://join.slack.com/t/dockercommunity/shared_invite/enQtNDY4MDc1Mzc0MzIwLTgxZDBlMmM4ZGEyNDc1N2FkMzlhODJkYmE1YTVkYjM1MDE3ZjAwZjBkOGFlOTJkZjRmZGYzNjYyY2M3ZTUxYzQ) [Click here for an invite to docker community slack.](https://join.slack.com/t/dockercommunity/shared_invite/enQtNDY4MDc1Mzc0MzIwLTgxZDBlMmM4ZGEyNDc1N2FkMzlhODJkYmE1YTVkYjM1MDE3ZjAwZjBkOGFlOTJkZjRmZGYzNjYyY2M3ZTUxYzQ)
### Security audit
A third party security audit was performed by Cure53 in 4Q2018; the [full report](docs/SECURITY_AUDIT.pdf) is available in our docs/ directory.
### Reporting security issues ### Reporting security issues
__If you are reporting a security issue, please reach out discreetly at security@containerd.io__. __If you are reporting a security issue, please reach out discreetly at security@containerd.io__.

View File

@ -100,7 +100,7 @@ const (
// readdir calls to this directory do not follow to lower layers. // readdir calls to this directory do not follow to lower layers.
whiteoutOpaqueDir = whiteoutMetaPrefix + ".opq" whiteoutOpaqueDir = whiteoutMetaPrefix + ".opq"
paxSchilyXattr = "SCHILY.xattrs." paxSchilyXattr = "SCHILY.xattr."
) )
// Apply applies a tar stream of an OCI style diff tar. // Apply applies a tar stream of an OCI style diff tar.

View File

@ -74,7 +74,7 @@ func tarName(p string) (string, error) {
// in file names, it is mostly safe to replace however we must // in file names, it is mostly safe to replace however we must
// check just in case // check just in case
if strings.Contains(p, "/") { if strings.Contains(p, "/") {
return "", fmt.Errorf("Windows path contains forward slash: %s", p) return "", fmt.Errorf("windows path contains forward slash: %s", p)
} }
return strings.Replace(p, string(os.PathSeparator), "/", -1), nil return strings.Replace(p, string(os.PathSeparator), "/", -1), nil
@ -130,11 +130,7 @@ func skipFile(hdr *tar.Header) bool {
// specific or Linux-specific, this warning should be changed to an error // specific or Linux-specific, this warning should be changed to an error
// to cater for the situation where someone does manage to upload a Linux // to cater for the situation where someone does manage to upload a Linux
// image but have it tagged as Windows inadvertently. // image but have it tagged as Windows inadvertently.
if strings.Contains(hdr.Name, ":") { return strings.Contains(hdr.Name, ":")
return true
}
return false
} }
// handleTarTypeBlockCharFifo is an OS-specific helper function used by // handleTarTypeBlockCharFifo is an OS-specific helper function used by

View File

@ -1,4 +1,4 @@
// +build freebsd linux openbsd solaris // +build !windows
/* /*
Copyright The containerd Authors. Copyright The containerd Authors.

View File

@ -275,3 +275,7 @@ func Load(set *FIFOSet) (IO, error) {
closers: []io.Closer{set}, closers: []io.Closer{set},
}, nil }, nil
} }
func (p *pipes) closers() []io.Closer {
return []io.Closer{p.Stdin, p.Stdout, p.Stderr}
}

View File

@ -152,7 +152,3 @@ func NewDirectIO(ctx context.Context, fifos *FIFOSet) (*DirectIO, error) {
}, },
}, err }, err
} }
func (p *pipes) closers() []io.Closer {
return []io.Closer{p.Stdin, p.Stdout, p.Stderr}
}

View File

@ -17,6 +17,7 @@
package cio package cio
import ( import (
"context"
"fmt" "fmt"
"io" "io"
"net" "net"
@ -144,3 +145,22 @@ func NewDirectIO(stdin io.WriteCloser, stdout, stderr io.ReadCloser, terminal bo
}, },
} }
} }
// NewDirectIOFromFIFOSet returns an IO implementation that exposes the IO streams as io.ReadCloser
// and io.WriteCloser.
func NewDirectIOFromFIFOSet(ctx context.Context, stdin io.WriteCloser, stdout, stderr io.ReadCloser, fifos *FIFOSet) *DirectIO {
_, cancel := context.WithCancel(ctx)
pipes := pipes{
Stdin: stdin,
Stdout: stdout,
Stderr: stderr,
}
return &DirectIO{
pipes: pipes,
cio: cio{
config: fifos.Config,
closers: append(pipes.closers(), fifos),
cancel: cancel,
},
}
}

View File

@ -61,6 +61,7 @@ import (
ocispec "github.com/opencontainers/image-spec/specs-go/v1" ocispec "github.com/opencontainers/image-spec/specs-go/v1"
specs "github.com/opencontainers/runtime-spec/specs-go" specs "github.com/opencontainers/runtime-spec/specs-go"
"github.com/pkg/errors" "github.com/pkg/errors"
"golang.org/x/sync/semaphore"
"google.golang.org/grpc" "google.golang.org/grpc"
"google.golang.org/grpc/health/grpc_health_v1" "google.golang.org/grpc/health/grpc_health_v1"
) )
@ -292,6 +293,9 @@ type RemoteContext struct {
// platforms will be used to create a PlatformMatcher with no ordering // platforms will be used to create a PlatformMatcher with no ordering
// preference. // preference.
Platforms []string Platforms []string
// MaxConcurrentDownloads is the max concurrent content downloads for each pull.
MaxConcurrentDownloads int
} }
func defaultRemoteContext() *RemoteContext { func defaultRemoteContext() *RemoteContext {
@ -403,12 +407,23 @@ func (c *Client) fetch(ctx context.Context, rCtx *RemoteContext, ref string, lim
} }
var ( var (
schema1Converter *schema1.Converter handler images.Handler
handler images.Handler
isConvertible bool
converterFunc func(context.Context, ocispec.Descriptor) (ocispec.Descriptor, error)
limiter *semaphore.Weighted
) )
if desc.MediaType == images.MediaTypeDockerSchema1Manifest && rCtx.ConvertSchema1 { if desc.MediaType == images.MediaTypeDockerSchema1Manifest && rCtx.ConvertSchema1 {
schema1Converter = schema1.NewConverter(store, fetcher) schema1Converter := schema1.NewConverter(store, fetcher)
handler = images.Handlers(append(rCtx.BaseHandlers, schema1Converter)...) handler = images.Handlers(append(rCtx.BaseHandlers, schema1Converter)...)
isConvertible = true
converterFunc = func(ctx context.Context, _ ocispec.Descriptor) (ocispec.Descriptor, error) {
return schema1Converter.Convert(ctx)
}
} else { } else {
// Get all the children for a descriptor // Get all the children for a descriptor
childrenHandler := images.ChildrenHandler(store) childrenHandler := images.ChildrenHandler(store)
@ -421,18 +436,37 @@ func (c *Client) fetch(ctx context.Context, rCtx *RemoteContext, ref string, lim
childrenHandler = images.LimitManifests(childrenHandler, rCtx.PlatformMatcher, limit) childrenHandler = images.LimitManifests(childrenHandler, rCtx.PlatformMatcher, limit)
} }
// set isConvertible to true if there is application/octet-stream media type
convertibleHandler := images.HandlerFunc(
func(_ context.Context, desc ocispec.Descriptor) ([]ocispec.Descriptor, error) {
if desc.MediaType == docker.LegacyConfigMediaType {
isConvertible = true
}
return []ocispec.Descriptor{}, nil
},
)
handler = images.Handlers(append(rCtx.BaseHandlers, handler = images.Handlers(append(rCtx.BaseHandlers,
remotes.FetchHandler(store, fetcher), remotes.FetchHandler(store, fetcher),
convertibleHandler,
childrenHandler, childrenHandler,
)...) )...)
converterFunc = func(ctx context.Context, desc ocispec.Descriptor) (ocispec.Descriptor, error) {
return docker.ConvertManifest(ctx, store, desc)
}
} }
if err := images.Dispatch(ctx, handler, desc); err != nil { if rCtx.MaxConcurrentDownloads > 0 {
limiter = semaphore.NewWeighted(int64(rCtx.MaxConcurrentDownloads))
}
if err := images.Dispatch(ctx, handler, limiter, desc); err != nil {
return images.Image{}, err return images.Image{}, err
} }
if schema1Converter != nil {
desc, err = schema1Converter.Convert(ctx) if isConvertible {
if err != nil { if desc, err = converterFunc(ctx, desc); err != nil {
return images.Image{}, err return images.Image{}, err
} }
} }

View File

@ -178,3 +178,11 @@ func WithImageHandler(h images.Handler) RemoteOpt {
return nil return nil
} }
} }
// WithMaxConcurrentDownloads sets max concurrent download limit.
func WithMaxConcurrentDownloads(max int) RemoteOpt {
return func(client *Client, c *RemoteContext) error {
c.MaxConcurrentDownloads = max
return nil
}
}

View File

@ -387,18 +387,16 @@ func (h *handler) Execute(_ []string, r <-chan svc.ChangeRequest, s chan<- svc.S
h.fromsvc <- nil h.fromsvc <- nil
s <- svc.Status{State: svc.Running, Accepts: svc.AcceptStop | svc.AcceptShutdown | svc.Accepted(windows.SERVICE_ACCEPT_PARAMCHANGE)} s <- svc.Status{State: svc.Running, Accepts: svc.AcceptStop | svc.AcceptShutdown | svc.Accepted(windows.SERVICE_ACCEPT_PARAMCHANGE)}
Loop: Loop:
for { for c := range r {
select { switch c.Cmd {
case c := <-r: case svc.Interrogate:
switch c.Cmd { s <- c.CurrentStatus
case svc.Interrogate: case svc.Stop, svc.Shutdown:
s <- c.CurrentStatus s <- svc.Status{State: svc.StopPending, Accepts: 0}
case svc.Stop, svc.Shutdown: h.s.Stop()
s <- svc.Status{State: svc.StopPending, Accepts: 0} break Loop
h.s.Stop()
break Loop
}
} }
} }

View File

@ -124,6 +124,10 @@ var (
Name: "allow-new-privs", Name: "allow-new-privs",
Usage: "turn off OCI spec's NoNewPrivileges feature flag", Usage: "turn off OCI spec's NoNewPrivileges feature flag",
}, },
cli.Uint64Flag{
Name: "memory-limit",
Usage: "memory limit (in bytes) for the container",
},
} }
) )

View File

@ -1,3 +1,5 @@
// +build windows
/* /*
Copyright The containerd Authors. Copyright The containerd Authors.
@ -14,17 +16,15 @@
limitations under the License. limitations under the License.
*/ */
package archive package commands
import ( import (
"time" "github.com/urfave/cli"
"github.com/pkg/errors"
) )
// as at MacOS 10.12 there is apparently no way to set timestamps func init() {
// with nanosecond precision. We could fall back to utimes/lutimes ContainerFlags = append(ContainerFlags, cli.Uint64Flag{
// and lose the precision as a temporary workaround. Name: "cpu-count",
func chtimes(path string, atime, mtime time.Time) error { Usage: "number of CPUs available to the container",
return errors.New("OSX missing UtimesNanoAt") })
} }

View File

@ -290,6 +290,11 @@ var (
Name: "validate", Name: "validate",
Usage: "validate the result against a format (json, mediatype, etc.)", Usage: "validate the result against a format (json, mediatype, etc.)",
}, },
cli.StringFlag{
Name: "editor",
Usage: "select editor (vim, emacs, etc.)",
EnvVar: "EDITOR",
},
}, },
Action: func(context *cli.Context) error { Action: func(context *cli.Context) error {
var ( var (
@ -320,7 +325,7 @@ var (
} }
defer ra.Close() defer ra.Close()
nrc, err := edit(content.NewReader(ra)) nrc, err := edit(context, content.NewReader(ra))
if err != nil { if err != nil {
return err return err
} }
@ -505,7 +510,12 @@ var (
} }
) )
func edit(rd io.Reader) (io.ReadCloser, error) { func edit(context *cli.Context, rd io.Reader) (io.ReadCloser, error) {
editor := context.String("editor")
if editor == "" {
return nil, fmt.Errorf("editor is required")
}
tmp, err := ioutil.TempFile(os.Getenv("XDG_RUNTIME_DIR"), "edit-") tmp, err := ioutil.TempFile(os.Getenv("XDG_RUNTIME_DIR"), "edit-")
if err != nil { if err != nil {
return nil, err return nil, err
@ -516,7 +526,7 @@ func edit(rd io.Reader) (io.ReadCloser, error) {
return nil, err return nil, err
} }
cmd := exec.Command("sh", "-c", "$EDITOR "+tmp.Name()) cmd := exec.Command("sh", "-c", fmt.Sprintf("%s %s", editor, tmp.Name()))
cmd.Stdin = os.Stdin cmd.Stdin = os.Stdin
cmd.Stdout = os.Stdout cmd.Stdout = os.Stdout

View File

@ -21,7 +21,7 @@ import (
"os" "os"
"github.com/containerd/containerd/cmd/ctr/commands" "github.com/containerd/containerd/cmd/ctr/commands"
oci "github.com/containerd/containerd/images/oci" "github.com/containerd/containerd/images/oci"
"github.com/containerd/containerd/reference" "github.com/containerd/containerd/reference"
digest "github.com/opencontainers/go-digest" digest "github.com/opencontainers/go-digest"
ocispec "github.com/opencontainers/image-spec/specs-go/v1" ocispec "github.com/opencontainers/image-spec/specs-go/v1"
@ -52,6 +52,10 @@ Currently, only OCI format is supported.
Usage: "media type of manifest digest", Usage: "media type of manifest digest",
Value: ocispec.MediaTypeImageManifest, Value: ocispec.MediaTypeImageManifest,
}, },
cli.BoolFlag{
Name: "all-platforms",
Usage: "exports content from all platforms",
},
}, },
Action: func(context *cli.Context) error { Action: func(context *cli.Context) error {
var ( var (
@ -101,7 +105,14 @@ Currently, only OCI format is supported.
return nil return nil
} }
} }
r, err := client.Export(ctx, &oci.V1Exporter{}, desc)
var (
exportOpts []oci.V1ExporterOpt
)
exportOpts = append(exportOpts, oci.WithAllPlatforms(context.Bool("all-platforms")))
r, err := client.Export(ctx, desc, exportOpts...)
if err != nil { if err != nil {
return err return err
} }

View File

@ -86,9 +86,10 @@ func parseMountFlag(m string) (specs.Mount, error) {
// Command runs a container // Command runs a container
var Command = cli.Command{ var Command = cli.Command{
Name: "run", Name: "run",
Usage: "run a container", Usage: "run a container",
ArgsUsage: "[flags] Image|RootFS ID [COMMAND] [ARG...]", ArgsUsage: "[flags] Image|RootFS ID [COMMAND] [ARG...]",
SkipArgReorder: true,
Flags: append([]cli.Flag{ Flags: append([]cli.Flag{
cli.BoolFlag{ cli.BoolFlag{
Name: "rm", Name: "rm",

View File

@ -139,6 +139,10 @@ func NewContainer(ctx gocontext.Context, client *containerd.Client, context *cli
// NOTE: can be set to "" explicitly for disabling cgroup. // NOTE: can be set to "" explicitly for disabling cgroup.
opts = append(opts, oci.WithCgroup(context.String("cgroup"))) opts = append(opts, oci.WithCgroup(context.String("cgroup")))
} }
limit := context.Uint64("memory-limit")
if limit != 0 {
opts = append(opts, oci.WithMemoryLimit(limit))
}
} }
cOpts = append(cOpts, containerd.WithRuntime(context.String("runtime"), nil)) cOpts = append(cOpts, containerd.WithRuntime(context.String("runtime"), nil))

View File

@ -105,6 +105,14 @@ func NewContainer(ctx gocontext.Context, client *containerd.Client, context *cli
if context.Bool("isolated") { if context.Bool("isolated") {
opts = append(opts, oci.WithWindowsHyperV) opts = append(opts, oci.WithWindowsHyperV)
} }
limit := context.Uint64("memory-limit")
if limit != 0 {
opts = append(opts, oci.WithMemoryLimit(limit))
}
ccount := context.Uint64("cpu-count")
if ccount != 0 {
opts = append(opts, oci.WithWindowsCPUCount(ccount))
}
} }
cOpts = append(cOpts, containerd.WithContainerLabels(commands.LabelArgs(context.StringSlice("label")))) cOpts = append(cOpts, containerd.WithContainerLabels(commands.LabelArgs(context.StringSlice("label"))))

View File

@ -36,6 +36,14 @@ var checkpointCommand = cli.Command{
Name: "exit", Name: "exit",
Usage: "stop the container after the checkpoint", Usage: "stop the container after the checkpoint",
}, },
cli.StringFlag{
Name: "image-path",
Usage: "path to criu image files",
},
cli.StringFlag{
Name: "work-path",
Usage: "path to criu work files and logs",
},
}, },
Action: func(context *cli.Context) error { Action: func(context *cli.Context) error {
id := context.Args().First() id := context.Args().First()
@ -59,40 +67,55 @@ var checkpointCommand = cli.Command{
if err != nil { if err != nil {
return err return err
} }
var opts []containerd.CheckpointTaskOpts opts := []containerd.CheckpointTaskOpts{withCheckpointOpts(info.Runtime.Name, context)}
if context.Bool("exit") {
opts = append(opts, withExit(info.Runtime.Name))
}
checkpoint, err := task.Checkpoint(ctx, opts...) checkpoint, err := task.Checkpoint(ctx, opts...)
if err != nil { if err != nil {
return err return err
} }
fmt.Println(checkpoint.Name()) if context.String("image-path") == "" {
fmt.Println(checkpoint.Name())
}
return nil return nil
}, },
} }
func withExit(rt string) containerd.CheckpointTaskOpts { // withCheckpointOpts only suitable for runc runtime now
func withCheckpointOpts(rt string, context *cli.Context) containerd.CheckpointTaskOpts {
return func(r *containerd.CheckpointTaskInfo) error { return func(r *containerd.CheckpointTaskInfo) error {
imagePath := context.String("image-path")
workPath := context.String("work-path")
switch rt { switch rt {
case "io.containerd.runc.v1": case "io.containerd.runc.v1":
if r.Options == nil { if r.Options == nil {
r.Options = &options.CheckpointOptions{ r.Options = &options.CheckpointOptions{}
Exit: true, }
} opts, _ := r.Options.(*options.CheckpointOptions)
} else {
opts, _ := r.Options.(*options.CheckpointOptions) if context.Bool("exit") {
opts.Exit = true opts.Exit = true
} }
default: if imagePath != "" {
opts.ImagePath = imagePath
}
if workPath != "" {
opts.WorkPath = workPath
}
case "io.containerd.runtime.v1.linux":
if r.Options == nil { if r.Options == nil {
r.Options = &runctypes.CheckpointOptions{ r.Options = &runctypes.CheckpointOptions{}
Exit: true, }
} opts, _ := r.Options.(*runctypes.CheckpointOptions)
} else {
opts, _ := r.Options.(*runctypes.CheckpointOptions) if context.Bool("exit") {
opts.Exit = true opts.Exit = true
} }
if imagePath != "" {
opts.ImagePath = imagePath
}
if workPath != "" {
opts.WorkPath = workPath
}
} }
return nil return nil
} }

View File

@ -28,9 +28,10 @@ import (
//TODO:(jessvalarezo) exec-id is optional here, update to required arg //TODO:(jessvalarezo) exec-id is optional here, update to required arg
var execCommand = cli.Command{ var execCommand = cli.Command{
Name: "exec", Name: "exec",
Usage: "execute additional processes in an existing container", Usage: "execute additional processes in an existing container",
ArgsUsage: "[flags] CONTAINER CMD [ARG...]", ArgsUsage: "[flags] CONTAINER CMD [ARG...]",
SkipArgReorder: true,
Flags: []cli.Flag{ Flags: []cli.Flag{
cli.StringFlag{ cli.StringFlag{
Name: "cwd", Name: "cwd",

View File

@ -47,7 +47,5 @@ func unlock(ref string) {
locksMu.Lock() locksMu.Lock()
defer locksMu.Unlock() defer locksMu.Unlock()
if _, ok := locks[ref]; ok { delete(locks, ref)
delete(locks, ref)
}
} }

View File

@ -58,7 +58,7 @@ func (s *fsApplier) Apply(ctx context.Context, desc ocispec.Descriptor, mounts [
defer func() { defer func() {
if err == nil { if err == nil {
log.G(ctx).WithFields(logrus.Fields{ log.G(ctx).WithFields(logrus.Fields{
"d": time.Now().Sub(t1), "d": time.Since(t1),
"dgst": desc.Digest, "dgst": desc.Digest,
"size": desc.Size, "size": desc.Size,
"media": desc.MediaType, "media": desc.MediaType,

View File

@ -20,36 +20,23 @@ import (
"context" "context"
"io" "io"
"github.com/containerd/containerd/images" "github.com/containerd/containerd/images/oci"
ocispec "github.com/opencontainers/image-spec/specs-go/v1" ocispec "github.com/opencontainers/image-spec/specs-go/v1"
"github.com/pkg/errors" "github.com/pkg/errors"
) )
type exportOpts struct {
}
// ExportOpt allows the caller to specify export-specific options
type ExportOpt func(c *exportOpts) error
func resolveExportOpt(opts ...ExportOpt) (exportOpts, error) {
var eopts exportOpts
for _, o := range opts {
if err := o(&eopts); err != nil {
return eopts, err
}
}
return eopts, nil
}
// Export exports an image to a Tar stream. // Export exports an image to a Tar stream.
// OCI format is used by default. // OCI format is used by default.
// It is up to caller to put "org.opencontainers.image.ref.name" annotation to desc. // It is up to caller to put "org.opencontainers.image.ref.name" annotation to desc.
// TODO(AkihiroSuda): support exporting multiple descriptors at once to a single archive stream. // TODO(AkihiroSuda): support exporting multiple descriptors at once to a single archive stream.
func (c *Client) Export(ctx context.Context, exporter images.Exporter, desc ocispec.Descriptor, opts ...ExportOpt) (io.ReadCloser, error) { func (c *Client) Export(ctx context.Context, desc ocispec.Descriptor, opts ...oci.V1ExporterOpt) (io.ReadCloser, error) {
_, err := resolveExportOpt(opts...) // unused now
exporter, err := oci.ResolveV1ExportOpt(opts...)
if err != nil { if err != nil {
return nil, err return nil, err
} }
pr, pw := io.Pipe() pr, pw := io.Pipe()
go func() { go func() {
pw.CloseWithError(errors.Wrap(exporter.Export(ctx, c.ContentStore(), desc, pw), "export failed")) pw.CloseWithError(errors.Wrap(exporter.Export(ctx, c.ContentStore(), desc, pw), "export failed"))

View File

@ -185,7 +185,6 @@ func (s *scanner) scanQuoted(quote rune) {
ch = s.next() ch = s.next()
} }
} }
return
} }
func (s *scanner) scanEscape(quote rune) rune { func (s *scanner) scanEscape(quote rune) rune {

View File

@ -45,7 +45,7 @@ var (
// Validate return nil if the string s is a valid identifier. // Validate return nil if the string s is a valid identifier.
// //
// identifiers must be valid domain names according to RFC 1035, section 2.3.1. To // identifiers must be valid domain names according to RFC 1035, section 2.3.1. To
// enforce case insensitvity, all characters must be lower case. // enforce case insensitivity, all characters must be lower case.
// //
// In general, identifiers that pass this validation, should be safe for use as // In general, identifiers that pass this validation, should be safe for use as
// a domain names or filesystem path component. // a domain names or filesystem path component.

View File

@ -170,26 +170,22 @@ func (i *image) Unpack(ctx context.Context, snapshotterName string) error {
chain = append(chain, layer.Diff.Digest) chain = append(chain, layer.Diff.Digest)
} }
if unpacked { desc, err := i.i.Config(ctx, cs, i.platform)
desc, err := i.i.Config(ctx, cs, i.platform) if err != nil {
if err != nil { return err
return err
}
rootfs := identity.ChainID(chain).String()
cinfo := content.Info{
Digest: desc.Digest,
Labels: map[string]string{
fmt.Sprintf("containerd.io/gc.ref.snapshot.%s", snapshotterName): rootfs,
},
}
if _, err := cs.Update(ctx, cinfo, fmt.Sprintf("labels.containerd.io/gc.ref.snapshot.%s", snapshotterName)); err != nil {
return err
}
} }
return nil rootfs := identity.ChainID(chain).String()
cinfo := content.Info{
Digest: desc.Digest,
Labels: map[string]string{
fmt.Sprintf("containerd.io/gc.ref.snapshot.%s", snapshotterName): rootfs,
},
}
_, err = cs.Update(ctx, cinfo, fmt.Sprintf("labels.containerd.io/gc.ref.snapshot.%s", snapshotterName))
return err
} }
func (i *image) getLayers(ctx context.Context, platform platforms.MatchComparer) ([]rootfs.Layer, error) { func (i *image) getLayers(ctx context.Context, platform platforms.MatchComparer) ([]rootfs.Layer, error) {

View File

@ -26,6 +26,7 @@ import (
ocispec "github.com/opencontainers/image-spec/specs-go/v1" ocispec "github.com/opencontainers/image-spec/specs-go/v1"
"github.com/pkg/errors" "github.com/pkg/errors"
"golang.org/x/sync/errgroup" "golang.org/x/sync/errgroup"
"golang.org/x/sync/semaphore"
) )
var ( var (
@ -108,19 +109,30 @@ func Walk(ctx context.Context, handler Handler, descs ...ocispec.Descriptor) err
// handler may return `ErrSkipDesc` to signal to the dispatcher to not traverse // handler may return `ErrSkipDesc` to signal to the dispatcher to not traverse
// any children. // any children.
// //
// A concurrency limiter can be passed in to limit the number of concurrent
// handlers running. When limiter is nil, there is no limit.
//
// Typically, this function will be used with `FetchHandler`, often composed // Typically, this function will be used with `FetchHandler`, often composed
// with other handlers. // with other handlers.
// //
// If any handler returns an error, the dispatch session will be canceled. // If any handler returns an error, the dispatch session will be canceled.
func Dispatch(ctx context.Context, handler Handler, descs ...ocispec.Descriptor) error { func Dispatch(ctx context.Context, handler Handler, limiter *semaphore.Weighted, descs ...ocispec.Descriptor) error {
eg, ctx := errgroup.WithContext(ctx) eg, ctx := errgroup.WithContext(ctx)
for _, desc := range descs { for _, desc := range descs {
desc := desc desc := desc
if limiter != nil {
if err := limiter.Acquire(ctx, 1); err != nil {
return err
}
}
eg.Go(func() error { eg.Go(func() error {
desc := desc desc := desc
children, err := handler.Handle(ctx, desc) children, err := handler.Handle(ctx, desc)
if limiter != nil {
limiter.Release(1)
}
if err != nil { if err != nil {
if errors.Cause(err) == ErrSkipDesc { if errors.Cause(err) == ErrSkipDesc {
return nil // don't traverse the children. return nil // don't traverse the children.
@ -129,7 +141,7 @@ func Dispatch(ctx context.Context, handler Handler, descs ...ocispec.Descriptor)
} }
if len(children) > 0 { if len(children) > 0 {
return Dispatch(ctx, handler, children...) return Dispatch(ctx, handler, limiter, children...)
} }
return nil return nil

View File

@ -25,6 +25,7 @@ import (
"github.com/containerd/containerd/content" "github.com/containerd/containerd/content"
"github.com/containerd/containerd/images" "github.com/containerd/containerd/images"
"github.com/containerd/containerd/platforms"
ocispecs "github.com/opencontainers/image-spec/specs-go" ocispecs "github.com/opencontainers/image-spec/specs-go"
ocispec "github.com/opencontainers/image-spec/specs-go/v1" ocispec "github.com/opencontainers/image-spec/specs-go/v1"
"github.com/pkg/errors" "github.com/pkg/errors"
@ -37,6 +38,36 @@ import (
// e.g. application/vnd.docker.image.rootfs.diff.tar.gzip // e.g. application/vnd.docker.image.rootfs.diff.tar.gzip
// -> application/vnd.oci.image.layer.v1.tar+gzip // -> application/vnd.oci.image.layer.v1.tar+gzip
type V1Exporter struct { type V1Exporter struct {
AllPlatforms bool
}
// V1ExporterOpt allows the caller to set additional options to a new V1Exporter
type V1ExporterOpt func(c *V1Exporter) error
// DefaultV1Exporter return a default V1Exporter pointer
func DefaultV1Exporter() *V1Exporter {
return &V1Exporter{
AllPlatforms: false,
}
}
// ResolveV1ExportOpt return a new V1Exporter with V1ExporterOpt
func ResolveV1ExportOpt(opts ...V1ExporterOpt) (*V1Exporter, error) {
exporter := DefaultV1Exporter()
for _, o := range opts {
if err := o(exporter); err != nil {
return exporter, err
}
}
return exporter, nil
}
// WithAllPlatforms set V1Exporter`s AllPlatforms option
func WithAllPlatforms(allPlatforms bool) V1ExporterOpt {
return func(c *V1Exporter) error {
c.AllPlatforms = allPlatforms
return nil
}
} }
// Export implements Exporter. // Export implements Exporter.
@ -56,8 +87,15 @@ func (oe *V1Exporter) Export(ctx context.Context, store content.Provider, desc o
return nil, nil return nil, nil
} }
childrenHandler := images.ChildrenHandler(store)
if !oe.AllPlatforms {
// get local default platform to fetch image manifest
childrenHandler = images.FilterPlatforms(childrenHandler, platforms.Any(platforms.DefaultSpec()))
}
handlers := images.Handlers( handlers := images.Handlers(
images.ChildrenHandler(store), childrenHandler,
images.HandlerFunc(exportHandler), images.HandlerFunc(exportHandler),
) )

View File

@ -99,8 +99,7 @@ func (c *Client) Import(ctx context.Context, reader io.Reader, opts ...ImportOpt
}) })
} }
var handler images.HandlerFunc var handler images.HandlerFunc = func(ctx context.Context, desc ocispec.Descriptor) ([]ocispec.Descriptor, error) {
handler = func(ctx context.Context, desc ocispec.Descriptor) ([]ocispec.Descriptor, error) {
// Only save images at top level // Only save images at top level
if desc.Digest != index.Digest { if desc.Digest != index.Digest {
return images.Children(ctx, cs, desc) return images.Children(ctx, cs, desc)

View File

@ -59,7 +59,6 @@ func (c *Client) Install(ctx context.Context, image Image, opts ...InstallOpts)
if err != nil { if err != nil {
return err return err
} }
defer r.Close()
if _, err := archive.Apply(ctx, path, r, archive.WithFilter(func(hdr *tar.Header) (bool, error) { if _, err := archive.Apply(ctx, path, r, archive.WithFilter(func(hdr *tar.Header) (bool, error) {
d := filepath.Dir(hdr.Name) d := filepath.Dir(hdr.Name)
result := d == "bin" result := d == "bin"
@ -73,8 +72,10 @@ func (c *Client) Install(ctx context.Context, image Image, opts ...InstallOpts)
} }
return result, nil return result, nil
})); err != nil { })); err != nil {
r.Close()
return err return err
} }
r.Close()
} }
return nil return nil
} }

View File

@ -38,16 +38,31 @@ import (
type contentStore struct { type contentStore struct {
content.Store content.Store
db *DB db *DB
l sync.RWMutex shared bool
l sync.RWMutex
} }
// newContentStore returns a namespaced content store using an existing // newContentStore returns a namespaced content store using an existing
// content store interface. // content store interface.
func newContentStore(db *DB, cs content.Store) *contentStore { // policy defines the sharing behavior for content between namespaces. Both
// modes will result in shared storage in the backend for committed. Choose
// "shared" to prevent separate namespaces from having to pull the same content
// twice. Choose "isolated" if the content must not be shared between
// namespaces.
//
// If the policy is "shared", writes will try to resolve the "expected" digest
// against the backend, allowing imports of content from other namespaces. In
// "isolated" mode, the client must prove they have the content by providing
// the entire blob before the content can be added to another namespace.
//
// Since we have only two policies right now, it's simpler using bool to
// represent it internally.
func newContentStore(db *DB, shared bool, cs content.Store) *contentStore {
return &contentStore{ return &contentStore{
Store: cs, Store: cs,
db: db, db: db,
shared: shared,
} }
} }
@ -383,13 +398,15 @@ func (cs *contentStore) Writer(ctx context.Context, opts ...content.WriterOpt) (
return nil return nil
} }
if st, err := cs.Store.Info(ctx, wOpts.Desc.Digest); err == nil { if cs.shared {
// Ensure the expected size is the same, it is likely if st, err := cs.Store.Info(ctx, wOpts.Desc.Digest); err == nil {
// an error if the size is mismatched but the caller // Ensure the expected size is the same, it is likely
// must resolve this on commit // an error if the size is mismatched but the caller
if wOpts.Desc.Size == 0 || wOpts.Desc.Size == st.Size { // must resolve this on commit
shared = true if wOpts.Desc.Size == 0 || wOpts.Desc.Size == st.Size {
wOpts.Desc.Size = st.Size shared = true
wOpts.Desc.Size = st.Size
}
} }
} }
} }
@ -762,7 +779,7 @@ func (cs *contentStore) garbageCollect(ctx context.Context) (d time.Duration, er
t1 := time.Now() t1 := time.Now()
defer func() { defer func() {
if err == nil { if err == nil {
d = time.Now().Sub(t1) d = time.Since(t1)
} }
cs.l.Unlock() cs.l.Unlock()
}() }()

View File

@ -46,6 +46,19 @@ const (
dbVersion = 3 dbVersion = 3
) )
// DBOpt configures how we set up the DB
type DBOpt func(*dbOptions)
// WithPolicyIsolated isolates contents between namespaces
func WithPolicyIsolated(o *dbOptions) {
o.shared = false
}
// dbOptions configure db options.
type dbOptions struct {
shared bool
}
// DB represents a metadata database backed by a bolt // DB represents a metadata database backed by a bolt
// database. The database is fully namespaced and stores // database. The database is fully namespaced and stores
// image, container, namespace, snapshot, and content data // image, container, namespace, snapshot, and content data
@ -72,19 +85,28 @@ type DB struct {
// mutationCallbacks are called after each mutation with the flag // mutationCallbacks are called after each mutation with the flag
// set indicating whether any dirty flags are set // set indicating whether any dirty flags are set
mutationCallbacks []func(bool) mutationCallbacks []func(bool)
dbopts dbOptions
} }
// NewDB creates a new metadata database using the provided // NewDB creates a new metadata database using the provided
// bolt database, content store, and snapshotters. // bolt database, content store, and snapshotters.
func NewDB(db *bolt.DB, cs content.Store, ss map[string]snapshots.Snapshotter) *DB { func NewDB(db *bolt.DB, cs content.Store, ss map[string]snapshots.Snapshotter, opts ...DBOpt) *DB {
m := &DB{ m := &DB{
db: db, db: db,
ss: make(map[string]*snapshotter, len(ss)), ss: make(map[string]*snapshotter, len(ss)),
dirtySS: map[string]struct{}{}, dirtySS: map[string]struct{}{},
dbopts: dbOptions{
shared: true,
},
}
for _, opt := range opts {
opt(&m.dbopts)
} }
// Initialize data stores // Initialize data stores
m.cs = newContentStore(m, cs) m.cs = newContentStore(m, m.dbopts.shared, cs)
for name, sn := range ss { for name, sn := range ss {
m.ss[name] = newSnapshotter(m, name, sn) m.ss[name] = newSnapshotter(m, name, sn)
} }
@ -154,7 +176,7 @@ func (m *DB) Init(ctx context.Context) error {
if err := m.migrate(tx); err != nil { if err := m.migrate(tx); err != nil {
return errors.Wrapf(err, "failed to migrate to %s.%d", m.schema, m.version) return errors.Wrapf(err, "failed to migrate to %s.%d", m.schema, m.version)
} }
log.G(ctx).WithField("d", time.Now().Sub(t0)).Debugf("finished database migration to %s.%d", m.schema, m.version) log.G(ctx).WithField("d", time.Since(t0)).Debugf("finished database migration to %s.%d", m.schema, m.version)
} }
} }
@ -306,7 +328,7 @@ func (m *DB) GarbageCollect(ctx context.Context) (gc.Stats, error) {
m.cleanupSnapshotter(snapshotterName) m.cleanupSnapshotter(snapshotterName)
sl.Lock() sl.Lock()
stats.SnapshotD[snapshotterName] = time.Now().Sub(st1) stats.SnapshotD[snapshotterName] = time.Since(st1)
sl.Unlock() sl.Unlock()
wg.Done() wg.Done()
@ -321,7 +343,7 @@ func (m *DB) GarbageCollect(ctx context.Context) (gc.Stats, error) {
go func() { go func() {
ct1 := time.Now() ct1 := time.Now()
m.cleanupContent() m.cleanupContent()
stats.ContentD = time.Now().Sub(ct1) stats.ContentD = time.Since(ct1)
wg.Done() wg.Done()
}() }()
m.dirtyCS = false m.dirtyCS = false
@ -329,7 +351,7 @@ func (m *DB) GarbageCollect(ctx context.Context) (gc.Stats, error) {
m.dirtyL.Unlock() m.dirtyL.Unlock()
stats.MetaD = time.Now().Sub(t1) stats.MetaD = time.Since(t1)
m.wlock.Unlock() m.wlock.Unlock()
wg.Wait() wg.Wait()

View File

@ -296,10 +296,6 @@ func references(ctx context.Context, tx *bolt.Tx, node gc.Node, fn func(gc.Node)
bkt := getBucket(tx, bucketKeyVersion, []byte(node.Namespace), bucketKeyObjectSnapshots, []byte(ss), []byte(name)) bkt := getBucket(tx, bucketKeyVersion, []byte(node.Namespace), bucketKeyObjectSnapshots, []byte(ss), []byte(name))
if bkt == nil { if bkt == nil {
getBucket(tx, bucketKeyVersion, []byte(node.Namespace), bucketKeyObjectSnapshots).ForEach(func(k, v []byte) error {
return nil
})
// Node may be created from dead edge // Node may be created from dead edge
return nil return nil
} }

View File

@ -628,7 +628,7 @@ func (s *snapshotter) garbageCollect(ctx context.Context) (d time.Duration, err
} }
} }
if err == nil { if err == nil {
d = time.Now().Sub(t1) d = time.Since(t1)
} }
}() }()

View File

@ -141,8 +141,10 @@ func WithEnv(environmentVariables []string) SpecOpts {
// replaced by env key or appended to the list // replaced by env key or appended to the list
func replaceOrAppendEnvValues(defaults, overrides []string) []string { func replaceOrAppendEnvValues(defaults, overrides []string) []string {
cache := make(map[string]int, len(defaults)) cache := make(map[string]int, len(defaults))
results := make([]string, 0, len(defaults))
for i, e := range defaults { for i, e := range defaults {
parts := strings.SplitN(e, "=", 2) parts := strings.SplitN(e, "=", 2)
results = append(results, e)
cache[parts[0]] = i cache[parts[0]] = i
} }
@ -150,7 +152,7 @@ func replaceOrAppendEnvValues(defaults, overrides []string) []string {
// Values w/o = means they want this env to be removed/unset. // Values w/o = means they want this env to be removed/unset.
if !strings.Contains(value, "=") { if !strings.Contains(value, "=") {
if i, exists := cache[value]; exists { if i, exists := cache[value]; exists {
defaults[i] = "" // Used to indicate it should be removed results[i] = "" // Used to indicate it should be removed
} }
continue continue
} }
@ -158,21 +160,21 @@ func replaceOrAppendEnvValues(defaults, overrides []string) []string {
// Just do a normal set/update // Just do a normal set/update
parts := strings.SplitN(value, "=", 2) parts := strings.SplitN(value, "=", 2)
if i, exists := cache[parts[0]]; exists { if i, exists := cache[parts[0]]; exists {
defaults[i] = value results[i] = value
} else { } else {
defaults = append(defaults, value) results = append(results, value)
} }
} }
// Now remove all entries that we want to "unset" // Now remove all entries that we want to "unset"
for i := 0; i < len(defaults); i++ { for i := 0; i < len(results); i++ {
if defaults[i] == "" { if results[i] == "" {
defaults = append(defaults[:i], defaults[i+1:]...) results = append(results[:i], results[i+1:]...)
i-- i--
} }
} }
return defaults return results
} }
// WithProcessArgs replaces the args on the generated spec // WithProcessArgs replaces the args on the generated spec
@ -310,7 +312,7 @@ func WithImageConfigArgs(image Image, args []string) SpecOpts {
setProcess(s) setProcess(s)
if s.Linux != nil { if s.Linux != nil {
s.Process.Env = append(s.Process.Env, config.Env...) s.Process.Env = replaceOrAppendEnvValues(s.Process.Env, config.Env)
cmd := config.Cmd cmd := config.Cmd
if len(args) > 0 { if len(args) > 0 {
cmd = args cmd = args
@ -332,8 +334,14 @@ func WithImageConfigArgs(image Image, args []string) SpecOpts {
// even if there is no specified user in the image config // even if there is no specified user in the image config
return WithAdditionalGIDs("root")(ctx, client, c, s) return WithAdditionalGIDs("root")(ctx, client, c, s)
} else if s.Windows != nil { } else if s.Windows != nil {
s.Process.Env = config.Env s.Process.Env = replaceOrAppendEnvValues(s.Process.Env, config.Env)
s.Process.Args = append(config.Entrypoint, config.Cmd...) cmd := config.Cmd
if len(args) > 0 {
cmd = args
}
s.Process.Args = append(config.Entrypoint, cmd...)
s.Process.Cwd = config.WorkingDir
s.Process.User = specs.User{ s.Process.User = specs.User{
Username: config.User, Username: config.User,
} }
@ -1026,3 +1034,32 @@ func WithWindowsHyperV(_ context.Context, _ Client, _ *containers.Container, s *
} }
return nil return nil
} }
// WithMemoryLimit sets the `Linux.LinuxResources.Memory.Limit` section to the
// `limit` specified if the `Linux` section is not `nil`. Additionally sets the
// `Windows.WindowsResources.Memory.Limit` section if the `Windows` section is
// not `nil`.
func WithMemoryLimit(limit uint64) SpecOpts {
return func(_ context.Context, _ Client, _ *containers.Container, s *Spec) error {
if s.Linux != nil {
if s.Linux.Resources == nil {
s.Linux.Resources = &specs.LinuxResources{}
}
if s.Linux.Resources.Memory == nil {
s.Linux.Resources.Memory = &specs.LinuxMemory{}
}
l := int64(limit)
s.Linux.Resources.Memory.Limit = &l
}
if s.Windows != nil {
if s.Windows.Resources == nil {
s.Windows.Resources = &specs.WindowsResources{}
}
if s.Windows.Resources.Memory == nil {
s.Windows.Resources.Memory = &specs.WindowsMemoryResources{}
}
s.Windows.Resources.Memory.Limit = &limit
}
return nil
}
}

View File

@ -0,0 +1,41 @@
// +build windows
/*
Copyright The containerd Authors.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
package oci
import (
"context"
"github.com/containerd/containerd/containers"
specs "github.com/opencontainers/runtime-spec/specs-go"
)
// WithWindowsCPUCount sets the `Windows.Resources.CPU.Count` section to the
// `count` specified.
func WithWindowsCPUCount(count uint64) SpecOpts {
return func(_ context.Context, _ Client, _ *containers.Container, s *Spec) error {
if s.Windows.Resources == nil {
s.Windows.Resources = &specs.WindowsResources{}
}
if s.Windows.Resources.CPU == nil {
s.Windows.Resources.CPU = &specs.WindowsCPUResources{}
}
s.Windows.Resources.CPU.Count = &count
return nil
}
}

View File

@ -70,9 +70,9 @@ func (h Bar) Format(state fmt.State, r rune) {
negative := width - pad - positive negative := width - pad - positive
n := 1 n := 1
n += copy(p[n:], []byte(green)) n += copy(p[n:], green)
n += copy(p[n:], bytes.Repeat([]byte("+"), positive)) n += copy(p[n:], bytes.Repeat([]byte("+"), positive))
n += copy(p[n:], []byte(reset)) n += copy(p[n:], reset)
if negative > 0 { if negative > 0 {
copy(p[n:len(p)-1], bytes.Repeat([]byte("-"), negative)) copy(p[n:len(p)-1], bytes.Repeat([]byte("-"), negative))

View File

@ -19,6 +19,6 @@ package progress
const ( const (
escape = "\x1b" escape = "\x1b"
reset = escape + "[0m" reset = escape + "[0m"
red = escape + "[31m" // nolint: unused, varcheck red = escape + "[31m" // nolint: staticcheck, varcheck
green = escape + "[32m" green = escape + "[32m"
) )

View File

@ -42,10 +42,7 @@ var (
// IsSkipPlugin returns true if the error is skipping the plugin // IsSkipPlugin returns true if the error is skipping the plugin
func IsSkipPlugin(err error) bool { func IsSkipPlugin(err error) bool {
if errors.Cause(err) == ErrSkipPlugin { return errors.Cause(err) == ErrSkipPlugin
return true
}
return false
} }
// Type is the type of the plugin // Type is the type of the plugin

View File

@ -111,9 +111,11 @@ func (p *process) Start(ctx context.Context) error {
ExecID: p.id, ExecID: p.id,
}) })
if err != nil { if err != nil {
p.io.Cancel() if p.io != nil {
p.io.Wait() p.io.Cancel()
p.io.Close() p.io.Wait()
p.io.Close()
}
return errdefs.FromGRPC(err) return errdefs.FromGRPC(err)
} }
p.pid = r.Pid p.pid = r.Pid

View File

@ -79,8 +79,8 @@ func init() {
var t octetType var t octetType
isCtl := c <= 31 || c == 127 isCtl := c <= 31 || c == 127
isChar := 0 <= c && c <= 127 isChar := 0 <= c && c <= 127
isSeparator := strings.IndexRune(" \t\"(),/:;<=>?@[]\\{}", rune(c)) >= 0 isSeparator := strings.ContainsRune(" \t\"(),/:;<=>?@[]\\{}", rune(c))
if strings.IndexRune(" \t\r\n", rune(c)) >= 0 { if strings.ContainsRune(" \t\r\n", rune(c)) {
t |= isSpace t |= isSpace
} }
if isChar && !isCtl && !isSeparator { if isChar && !isCtl && !isSeparator {

View File

@ -194,7 +194,11 @@ func (a *dockerAuthorizer) fetchTokenWithOAuth(ctx context.Context, to tokenOpti
form.Set("password", to.secret) form.Set("password", to.secret)
} }
resp, err := ctxhttp.PostForm(ctx, a.client, to.realm, form) resp, err := ctxhttp.Post(
ctx, a.client, to.realm,
"application/x-www-form-urlencoded; charset=utf-8",
strings.NewReader(form.Encode()),
)
if err != nil { if err != nil {
return "", err return "", err
} }

View File

@ -0,0 +1,88 @@
/*
Copyright The containerd Authors.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
package docker
import (
"bytes"
"context"
"encoding/json"
"fmt"
"github.com/containerd/containerd/content"
"github.com/containerd/containerd/images"
"github.com/containerd/containerd/log"
"github.com/containerd/containerd/remotes"
digest "github.com/opencontainers/go-digest"
ocispec "github.com/opencontainers/image-spec/specs-go/v1"
"github.com/pkg/errors"
)
// LegacyConfigMediaType should be replaced by OCI image spec.
//
// More detail: docker/distribution#1622
const LegacyConfigMediaType = "application/octet-stream"
// ConvertManifest changes application/octet-stream to schema2 config media type if need.
//
// NOTE:
// 1. original manifest will be deleted by next gc round.
// 2. don't cover manifest list.
func ConvertManifest(ctx context.Context, store content.Store, desc ocispec.Descriptor) (ocispec.Descriptor, error) {
if !(desc.MediaType == images.MediaTypeDockerSchema2Manifest ||
desc.MediaType == ocispec.MediaTypeImageManifest) {
log.G(ctx).Warnf("do nothing for media type: %s", desc.MediaType)
return desc, nil
}
// read manifest data
mb, err := content.ReadBlob(ctx, store, desc)
if err != nil {
return ocispec.Descriptor{}, errors.Wrap(err, "failed to read index data")
}
var manifest ocispec.Manifest
if err := json.Unmarshal(mb, &manifest); err != nil {
return ocispec.Descriptor{}, errors.Wrap(err, "failed to unmarshal data into manifest")
}
// check config media type
if manifest.Config.MediaType != LegacyConfigMediaType {
return desc, nil
}
manifest.Config.MediaType = images.MediaTypeDockerSchema2Config
data, err := json.MarshalIndent(manifest, "", " ")
if err != nil {
return ocispec.Descriptor{}, errors.Wrap(err, "failed to marshal manifest")
}
// update manifest with gc labels
desc.Digest = digest.Canonical.FromBytes(data)
desc.Size = int64(len(data))
labels := map[string]string{}
for i, c := range append([]ocispec.Descriptor{manifest.Config}, manifest.Layers...) {
labels[fmt.Sprintf("containerd.io/gc.ref.content.%d", i)] = c.Digest.String()
}
ref := remotes.MakeRefKey(ctx, desc)
if err := content.WriteBlob(ctx, store, ref, bytes.NewReader(data), desc, content.WithLabels(labels)); err != nil {
return ocispec.Descriptor{}, errors.Wrap(err, "failed to update content")
}
return desc, nil
}

View File

@ -181,7 +181,7 @@ func PushContent(ctx context.Context, pusher Pusher, desc ocispec.Descriptor, pr
pushHandler, pushHandler,
) )
if err := images.Dispatch(ctx, images.Handlers(handlers...), desc); err != nil { if err := images.Dispatch(ctx, images.Handlers(handlers...), nil, desc); err != nil {
return err return err
} }

View File

@ -60,6 +60,8 @@ type CreateOptions struct {
ShimCgroup string `protobuf:"bytes,9,opt,name=shim_cgroup,json=shimCgroup,proto3" json:"shim_cgroup,omitempty"` ShimCgroup string `protobuf:"bytes,9,opt,name=shim_cgroup,json=shimCgroup,proto3" json:"shim_cgroup,omitempty"`
IoUid uint32 `protobuf:"varint,10,opt,name=io_uid,json=ioUid,proto3" json:"io_uid,omitempty"` IoUid uint32 `protobuf:"varint,10,opt,name=io_uid,json=ioUid,proto3" json:"io_uid,omitempty"`
IoGid uint32 `protobuf:"varint,11,opt,name=io_gid,json=ioGid,proto3" json:"io_gid,omitempty"` IoGid uint32 `protobuf:"varint,11,opt,name=io_gid,json=ioGid,proto3" json:"io_gid,omitempty"`
CriuWorkPath string `protobuf:"bytes,12,opt,name=criu_work_path,json=criuWorkPath,proto3" json:"criu_work_path,omitempty"`
CriuImagePath string `protobuf:"bytes,13,opt,name=criu_image_path,json=criuImagePath,proto3" json:"criu_image_path,omitempty"`
} }
func (m *CreateOptions) Reset() { *m = CreateOptions{} } func (m *CreateOptions) Reset() { *m = CreateOptions{} }
@ -74,6 +76,8 @@ type CheckpointOptions struct {
FileLocks bool `protobuf:"varint,5,opt,name=file_locks,json=fileLocks,proto3" json:"file_locks,omitempty"` FileLocks bool `protobuf:"varint,5,opt,name=file_locks,json=fileLocks,proto3" json:"file_locks,omitempty"`
EmptyNamespaces []string `protobuf:"bytes,6,rep,name=empty_namespaces,json=emptyNamespaces" json:"empty_namespaces,omitempty"` EmptyNamespaces []string `protobuf:"bytes,6,rep,name=empty_namespaces,json=emptyNamespaces" json:"empty_namespaces,omitempty"`
CgroupsMode string `protobuf:"bytes,7,opt,name=cgroups_mode,json=cgroupsMode,proto3" json:"cgroups_mode,omitempty"` CgroupsMode string `protobuf:"bytes,7,opt,name=cgroups_mode,json=cgroupsMode,proto3" json:"cgroups_mode,omitempty"`
WorkPath string `protobuf:"bytes,8,opt,name=work_path,json=workPath,proto3" json:"work_path,omitempty"`
ImagePath string `protobuf:"bytes,9,opt,name=image_path,json=imagePath,proto3" json:"image_path,omitempty"`
} }
func (m *CheckpointOptions) Reset() { *m = CheckpointOptions{} } func (m *CheckpointOptions) Reset() { *m = CheckpointOptions{} }
@ -252,6 +256,18 @@ func (m *CreateOptions) MarshalTo(dAtA []byte) (int, error) {
i++ i++
i = encodeVarintRunc(dAtA, i, uint64(m.IoGid)) i = encodeVarintRunc(dAtA, i, uint64(m.IoGid))
} }
if len(m.CriuWorkPath) > 0 {
dAtA[i] = 0x62
i++
i = encodeVarintRunc(dAtA, i, uint64(len(m.CriuWorkPath)))
i += copy(dAtA[i:], m.CriuWorkPath)
}
if len(m.CriuImagePath) > 0 {
dAtA[i] = 0x6a
i++
i = encodeVarintRunc(dAtA, i, uint64(len(m.CriuImagePath)))
i += copy(dAtA[i:], m.CriuImagePath)
}
return i, nil return i, nil
} }
@ -341,6 +357,18 @@ func (m *CheckpointOptions) MarshalTo(dAtA []byte) (int, error) {
i = encodeVarintRunc(dAtA, i, uint64(len(m.CgroupsMode))) i = encodeVarintRunc(dAtA, i, uint64(len(m.CgroupsMode)))
i += copy(dAtA[i:], m.CgroupsMode) i += copy(dAtA[i:], m.CgroupsMode)
} }
if len(m.WorkPath) > 0 {
dAtA[i] = 0x42
i++
i = encodeVarintRunc(dAtA, i, uint64(len(m.WorkPath)))
i += copy(dAtA[i:], m.WorkPath)
}
if len(m.ImagePath) > 0 {
dAtA[i] = 0x4a
i++
i = encodeVarintRunc(dAtA, i, uint64(len(m.ImagePath)))
i += copy(dAtA[i:], m.ImagePath)
}
return i, nil return i, nil
} }
@ -439,6 +467,14 @@ func (m *CreateOptions) Size() (n int) {
if m.IoGid != 0 { if m.IoGid != 0 {
n += 1 + sovRunc(uint64(m.IoGid)) n += 1 + sovRunc(uint64(m.IoGid))
} }
l = len(m.CriuWorkPath)
if l > 0 {
n += 1 + l + sovRunc(uint64(l))
}
l = len(m.CriuImagePath)
if l > 0 {
n += 1 + l + sovRunc(uint64(l))
}
return n return n
} }
@ -470,6 +506,14 @@ func (m *CheckpointOptions) Size() (n int) {
if l > 0 { if l > 0 {
n += 1 + l + sovRunc(uint64(l)) n += 1 + l + sovRunc(uint64(l))
} }
l = len(m.WorkPath)
if l > 0 {
n += 1 + l + sovRunc(uint64(l))
}
l = len(m.ImagePath)
if l > 0 {
n += 1 + l + sovRunc(uint64(l))
}
return n return n
} }
@ -525,6 +569,8 @@ func (this *CreateOptions) String() string {
`ShimCgroup:` + fmt.Sprintf("%v", this.ShimCgroup) + `,`, `ShimCgroup:` + fmt.Sprintf("%v", this.ShimCgroup) + `,`,
`IoUid:` + fmt.Sprintf("%v", this.IoUid) + `,`, `IoUid:` + fmt.Sprintf("%v", this.IoUid) + `,`,
`IoGid:` + fmt.Sprintf("%v", this.IoGid) + `,`, `IoGid:` + fmt.Sprintf("%v", this.IoGid) + `,`,
`CriuWorkPath:` + fmt.Sprintf("%v", this.CriuWorkPath) + `,`,
`CriuImagePath:` + fmt.Sprintf("%v", this.CriuImagePath) + `,`,
`}`, `}`,
}, "") }, "")
return s return s
@ -541,6 +587,8 @@ func (this *CheckpointOptions) String() string {
`FileLocks:` + fmt.Sprintf("%v", this.FileLocks) + `,`, `FileLocks:` + fmt.Sprintf("%v", this.FileLocks) + `,`,
`EmptyNamespaces:` + fmt.Sprintf("%v", this.EmptyNamespaces) + `,`, `EmptyNamespaces:` + fmt.Sprintf("%v", this.EmptyNamespaces) + `,`,
`CgroupsMode:` + fmt.Sprintf("%v", this.CgroupsMode) + `,`, `CgroupsMode:` + fmt.Sprintf("%v", this.CgroupsMode) + `,`,
`WorkPath:` + fmt.Sprintf("%v", this.WorkPath) + `,`,
`ImagePath:` + fmt.Sprintf("%v", this.ImagePath) + `,`,
`}`, `}`,
}, "") }, "")
return s return s
@ -994,6 +1042,64 @@ func (m *CreateOptions) Unmarshal(dAtA []byte) error {
break break
} }
} }
case 12:
if wireType != 2 {
return fmt.Errorf("proto: wrong wireType = %d for field CriuWorkPath", wireType)
}
var stringLen uint64
for shift := uint(0); ; shift += 7 {
if shift >= 64 {
return ErrIntOverflowRunc
}
if iNdEx >= l {
return io.ErrUnexpectedEOF
}
b := dAtA[iNdEx]
iNdEx++
stringLen |= (uint64(b) & 0x7F) << shift
if b < 0x80 {
break
}
}
intStringLen := int(stringLen)
if intStringLen < 0 {
return ErrInvalidLengthRunc
}
postIndex := iNdEx + intStringLen
if postIndex > l {
return io.ErrUnexpectedEOF
}
m.CriuWorkPath = string(dAtA[iNdEx:postIndex])
iNdEx = postIndex
case 13:
if wireType != 2 {
return fmt.Errorf("proto: wrong wireType = %d for field CriuImagePath", wireType)
}
var stringLen uint64
for shift := uint(0); ; shift += 7 {
if shift >= 64 {
return ErrIntOverflowRunc
}
if iNdEx >= l {
return io.ErrUnexpectedEOF
}
b := dAtA[iNdEx]
iNdEx++
stringLen |= (uint64(b) & 0x7F) << shift
if b < 0x80 {
break
}
}
intStringLen := int(stringLen)
if intStringLen < 0 {
return ErrInvalidLengthRunc
}
postIndex := iNdEx + intStringLen
if postIndex > l {
return io.ErrUnexpectedEOF
}
m.CriuImagePath = string(dAtA[iNdEx:postIndex])
iNdEx = postIndex
default: default:
iNdEx = preIndex iNdEx = preIndex
skippy, err := skipRunc(dAtA[iNdEx:]) skippy, err := skipRunc(dAtA[iNdEx:])
@ -1202,6 +1308,64 @@ func (m *CheckpointOptions) Unmarshal(dAtA []byte) error {
} }
m.CgroupsMode = string(dAtA[iNdEx:postIndex]) m.CgroupsMode = string(dAtA[iNdEx:postIndex])
iNdEx = postIndex iNdEx = postIndex
case 8:
if wireType != 2 {
return fmt.Errorf("proto: wrong wireType = %d for field WorkPath", wireType)
}
var stringLen uint64
for shift := uint(0); ; shift += 7 {
if shift >= 64 {
return ErrIntOverflowRunc
}
if iNdEx >= l {
return io.ErrUnexpectedEOF
}
b := dAtA[iNdEx]
iNdEx++
stringLen |= (uint64(b) & 0x7F) << shift
if b < 0x80 {
break
}
}
intStringLen := int(stringLen)
if intStringLen < 0 {
return ErrInvalidLengthRunc
}
postIndex := iNdEx + intStringLen
if postIndex > l {
return io.ErrUnexpectedEOF
}
m.WorkPath = string(dAtA[iNdEx:postIndex])
iNdEx = postIndex
case 9:
if wireType != 2 {
return fmt.Errorf("proto: wrong wireType = %d for field ImagePath", wireType)
}
var stringLen uint64
for shift := uint(0); ; shift += 7 {
if shift >= 64 {
return ErrIntOverflowRunc
}
if iNdEx >= l {
return io.ErrUnexpectedEOF
}
b := dAtA[iNdEx]
iNdEx++
stringLen |= (uint64(b) & 0x7F) << shift
if b < 0x80 {
break
}
}
intStringLen := int(stringLen)
if intStringLen < 0 {
return ErrInvalidLengthRunc
}
postIndex := iNdEx + intStringLen
if postIndex > l {
return io.ErrUnexpectedEOF
}
m.ImagePath = string(dAtA[iNdEx:postIndex])
iNdEx = postIndex
default: default:
iNdEx = preIndex iNdEx = preIndex
skippy, err := skipRunc(dAtA[iNdEx:]) skippy, err := skipRunc(dAtA[iNdEx:])
@ -1412,39 +1576,43 @@ func init() {
} }
var fileDescriptorRunc = []byte{ var fileDescriptorRunc = []byte{
// 541 bytes of a gzipped FileDescriptorProto // 604 bytes of a gzipped FileDescriptorProto
0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xdc, 0x93, 0xc1, 0x6e, 0xd3, 0x40, 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xdc, 0x94, 0xcf, 0x6e, 0xd3, 0x40,
0x10, 0x86, 0x6b, 0xda, 0x26, 0xce, 0xa4, 0x29, 0xb0, 0x50, 0xc9, 0x14, 0x91, 0x86, 0x00, 0x52, 0x10, 0xc6, 0xeb, 0xfe, 0x49, 0x9c, 0x49, 0xd2, 0xc2, 0x42, 0x25, 0xd3, 0xaa, 0x69, 0x08, 0x7f,
0xb8, 0xa4, 0x12, 0x88, 0x13, 0xb7, 0xa6, 0x08, 0x55, 0x40, 0xa9, 0x0c, 0x95, 0x10, 0x42, 0x5a, 0x14, 0x2e, 0xa9, 0x04, 0xe2, 0xc4, 0xad, 0x29, 0x42, 0x15, 0x50, 0x2a, 0x43, 0x05, 0x42, 0x48,
0xb9, 0xeb, 0x21, 0x59, 0xc5, 0xde, 0x59, 0x79, 0xd7, 0xd4, 0xb9, 0xf5, 0x09, 0x78, 0xae, 0x1e, 0x2b, 0x77, 0x3d, 0x24, 0xab, 0xc4, 0x3b, 0x96, 0x77, 0x4d, 0x92, 0x1b, 0x4f, 0xc0, 0x0b, 0xf1,
0x39, 0x72, 0x42, 0x34, 0x2f, 0x02, 0xf2, 0xda, 0x0e, 0x9c, 0x39, 0x72, 0xfb, 0xe7, 0xfb, 0xc7, 0x02, 0x3d, 0x21, 0x8e, 0x9c, 0x10, 0xcd, 0x93, 0xa0, 0x5d, 0xc7, 0x69, 0xcf, 0x1c, 0xb9, 0xcd,
0x9e, 0xd1, 0xbf, 0x1a, 0x98, 0x4c, 0xa5, 0x9d, 0xe5, 0x67, 0x63, 0x41, 0xe9, 0xbe, 0x20, 0x65, 0xfc, 0xe6, 0xb3, 0x67, 0xf4, 0x7d, 0xb2, 0xa1, 0x3f, 0x90, 0x66, 0x98, 0x9f, 0xf7, 0x04, 0x25,
0x23, 0xa9, 0x30, 0x8b, 0xff, 0x96, 0x59, 0xae, 0xac, 0x4c, 0x71, 0x3f, 0x91, 0x2a, 0x2f, 0xca, 0x07, 0x82, 0x94, 0x89, 0xa4, 0xc2, 0x2c, 0xbe, 0x5e, 0x66, 0xb9, 0x32, 0x32, 0xc1, 0x83, 0xb1,
0x4a, 0xd8, 0x85, 0x46, 0xe3, 0xd4, 0x58, 0x67, 0x64, 0x89, 0xed, 0xfc, 0x69, 0x1f, 0xbb, 0xb6, 0x54, 0xf9, 0xd4, 0x76, 0xc2, 0xcc, 0x52, 0xd4, 0xae, 0xea, 0xa5, 0x19, 0x19, 0x62, 0xdb, 0x57,
0x71, 0x69, 0xee, 0xde, 0x9e, 0xd2, 0x94, 0x5c, 0xc7, 0x7e, 0xa9, 0xaa, 0xe6, 0xe1, 0x57, 0x0f, 0xf2, 0x9e, 0x93, 0xf5, 0xec, 0x70, 0xe7, 0xf6, 0x80, 0x06, 0xe4, 0x14, 0x07, 0xb6, 0x2a, 0xc4,
0xba, 0x61, 0xae, 0xc4, 0x5b, 0x6d, 0x25, 0x29, 0xc3, 0x02, 0x68, 0xd7, 0x23, 0x02, 0x6f, 0xe0, 0x9d, 0x6f, 0x1e, 0xd4, 0xc3, 0x5c, 0x89, 0x37, 0xa9, 0x91, 0xa4, 0x34, 0x0b, 0xa0, 0xba, 0x58,
0x8d, 0x3a, 0x61, 0x53, 0xb2, 0xfb, 0xb0, 0x55, 0x4b, 0x9e, 0x11, 0xd9, 0xe0, 0x9a, 0xb3, 0xbb, 0x11, 0x78, 0x6d, 0xaf, 0x5b, 0x0b, 0xcb, 0x96, 0xdd, 0x85, 0xc6, 0xa2, 0xe4, 0x19, 0x91, 0x09,
0x35, 0x0b, 0x89, 0x2c, 0xbb, 0x0b, 0x1d, 0x91, 0xc9, 0x9c, 0xeb, 0xc8, 0xce, 0x82, 0x75, 0xe7, 0x56, 0xdd, 0xb8, 0xbe, 0x60, 0x21, 0x91, 0x61, 0xbb, 0x50, 0x13, 0x99, 0xcc, 0x79, 0x1a, 0x99,
0xfb, 0x25, 0x38, 0x89, 0xec, 0x8c, 0x3d, 0x82, 0x6d, 0xb3, 0x30, 0x16, 0xd3, 0x98, 0x8b, 0x69, 0x61, 0xb0, 0xe6, 0xe6, 0xbe, 0x05, 0xa7, 0x91, 0x19, 0xb2, 0x07, 0xb0, 0xa9, 0x67, 0xda, 0x60,
0x46, 0xb9, 0x0e, 0x36, 0x06, 0xde, 0xc8, 0x0f, 0x7b, 0x35, 0x9d, 0x38, 0x38, 0xbc, 0x58, 0x87, 0x12, 0x73, 0x31, 0xc8, 0x28, 0x4f, 0x83, 0xf5, 0xb6, 0xd7, 0xf5, 0xc3, 0xe6, 0x82, 0xf6, 0x1d,
0xde, 0x24, 0xc3, 0xc8, 0x62, 0xb3, 0xd2, 0x10, 0x7a, 0x8a, 0xb8, 0x96, 0x5f, 0xc8, 0x56, 0x93, 0xec, 0xfc, 0x58, 0x83, 0x66, 0x3f, 0xc3, 0xc8, 0x60, 0x79, 0x52, 0x07, 0x9a, 0x8a, 0x78, 0x2a,
0x3d, 0xf7, 0x5d, 0x57, 0xd1, 0x49, 0xc9, 0xdc, 0xe4, 0x3b, 0xe0, 0x93, 0x46, 0xc5, 0xad, 0xd0, 0xbf, 0x90, 0x29, 0x36, 0x7b, 0xee, 0xb9, 0xba, 0xa2, 0x53, 0xcb, 0xdc, 0xe6, 0x3b, 0xe0, 0x53,
0x6e, 0x31, 0x3f, 0x6c, 0x97, 0xf5, 0x7b, 0xa1, 0xd9, 0x13, 0xd8, 0xc1, 0xc2, 0x62, 0xa6, 0xa2, 0x8a, 0x8a, 0x1b, 0x91, 0xba, 0xc3, 0xfc, 0xb0, 0x6a, 0xfb, 0x77, 0x22, 0x65, 0x8f, 0x61, 0x1b,
0x84, 0xe7, 0x4a, 0x16, 0xdc, 0x90, 0x98, 0xa3, 0x35, 0x6e, 0x41, 0x3f, 0xbc, 0xd5, 0x98, 0xa7, 0xa7, 0x06, 0x33, 0x15, 0x8d, 0x79, 0xae, 0xe4, 0x94, 0x6b, 0x12, 0x23, 0x34, 0xda, 0x1d, 0xe8,
0x4a, 0x16, 0xef, 0x2a, 0x8b, 0xed, 0x82, 0x6f, 0x31, 0x4b, 0xa5, 0x8a, 0x92, 0x7a, 0xcb, 0x55, 0x87, 0xb7, 0xca, 0xe1, 0x99, 0x92, 0xd3, 0xb7, 0xc5, 0x88, 0xed, 0x80, 0x6f, 0x30, 0x4b, 0xa4,
0xcd, 0xee, 0x01, 0x7c, 0x96, 0x09, 0xf2, 0x84, 0xc4, 0xdc, 0x04, 0x9b, 0xce, 0xed, 0x94, 0xe4, 0x8a, 0xc6, 0x8b, 0x2b, 0x97, 0x3d, 0xdb, 0x03, 0xf8, 0x2c, 0xc7, 0xc8, 0xc7, 0x24, 0x46, 0x3a,
0x75, 0x09, 0xd8, 0x63, 0xb8, 0x81, 0xa9, 0xb6, 0x0b, 0xae, 0xa2, 0x14, 0x8d, 0x8e, 0x04, 0x9a, 0xd8, 0x70, 0xd3, 0x9a, 0x25, 0xaf, 0x2c, 0x60, 0x8f, 0xe0, 0x06, 0x26, 0xa9, 0x99, 0x71, 0x15,
0xa0, 0x35, 0x58, 0x1f, 0x75, 0xc2, 0xeb, 0x8e, 0x1f, 0xaf, 0x70, 0x99, 0x68, 0x95, 0x84, 0xe1, 0x25, 0xa8, 0xd3, 0x48, 0xa0, 0x0e, 0x2a, 0xed, 0xb5, 0x6e, 0x2d, 0xdc, 0x72, 0xfc, 0x64, 0x89,
0x29, 0xc5, 0x18, 0xb4, 0xab, 0x44, 0x6b, 0xf6, 0x86, 0x62, 0x64, 0x0f, 0x61, 0x5b, 0x11, 0x57, 0xad, 0xa3, 0x85, 0x13, 0x9a, 0x27, 0x14, 0x63, 0x50, 0x2d, 0x1c, 0x5d, 0xb0, 0xd7, 0x14, 0x23,
0x78, 0xce, 0xe7, 0xb8, 0xc8, 0xa4, 0x9a, 0x06, 0xbe, 0x1b, 0xb8, 0xa5, 0xe8, 0x18, 0xcf, 0x5f, 0xbb, 0x0f, 0x9b, 0x8a, 0xb8, 0xc2, 0x09, 0x1f, 0xe1, 0x2c, 0x93, 0x6a, 0x10, 0xf8, 0x6e, 0x61,
0x55, 0x8c, 0xed, 0x41, 0xd7, 0xcc, 0x64, 0xda, 0xe4, 0xda, 0x71, 0xff, 0x81, 0x12, 0x55, 0xa1, 0x43, 0xd1, 0x09, 0x4e, 0x5e, 0x16, 0x8c, 0xed, 0x43, 0x5d, 0x0f, 0x65, 0x52, 0xfa, 0x5a, 0x73,
0xb2, 0x1d, 0x68, 0x49, 0xe2, 0xb9, 0x8c, 0x03, 0x18, 0x78, 0xa3, 0x5e, 0xb8, 0x29, 0xe9, 0x54, 0xef, 0x01, 0x8b, 0x0a, 0x53, 0xd9, 0x36, 0x54, 0x24, 0xf1, 0x5c, 0xc6, 0x01, 0xb4, 0xbd, 0x6e,
0xc6, 0x35, 0x9e, 0xca, 0x38, 0xe8, 0x36, 0xf8, 0xa5, 0x8c, 0x87, 0xbf, 0x3c, 0xb8, 0x39, 0x99, 0x33, 0xdc, 0x90, 0x74, 0x26, 0xe3, 0x05, 0x1e, 0xc8, 0x38, 0xa8, 0x97, 0xf8, 0x85, 0x8c, 0xed,
0xa1, 0x98, 0x6b, 0x92, 0xca, 0x36, 0xcf, 0xc0, 0x60, 0x03, 0x0b, 0xd9, 0xa4, 0xef, 0xf4, 0xff, 0x52, 0x17, 0xe3, 0x84, 0xb2, 0x51, 0x91, 0x65, 0xc3, 0xbd, 0xb1, 0x61, 0xe9, 0x7b, 0xca, 0x46,
0x1a, 0xfb, 0xf0, 0x19, 0x6c, 0x9f, 0x64, 0x24, 0xd0, 0x98, 0x43, 0xb4, 0x91, 0x4c, 0x0c, 0x7b, 0x2e, 0xcf, 0x87, 0xb0, 0xe5, 0x54, 0x32, 0x89, 0x06, 0x58, 0xc8, 0x9a, 0x4e, 0xd6, 0xb4, 0xf8,
0x00, 0x6d, 0x2c, 0x50, 0x70, 0x19, 0x57, 0x77, 0x71, 0x00, 0xcb, 0x1f, 0x7b, 0xad, 0x17, 0x05, 0xd8, 0x52, 0xab, 0xeb, 0x7c, 0x5f, 0x85, 0x9b, 0xfd, 0x21, 0x8a, 0x51, 0x4a, 0x52, 0x99, 0x32,
0x8a, 0xa3, 0xc3, 0xb0, 0x55, 0x5a, 0x47, 0xf1, 0xc1, 0xa7, 0xcb, 0xab, 0xfe, 0xda, 0xf7, 0xab, 0x54, 0x06, 0xeb, 0x38, 0x95, 0x65, 0x96, 0xae, 0xfe, 0x6f, 0x43, 0xdc, 0x85, 0xda, 0x95, 0x95,
0xfe, 0xda, 0xc5, 0xb2, 0xef, 0x5d, 0x2e, 0xfb, 0xde, 0xb7, 0x65, 0xdf, 0xfb, 0xb9, 0xec, 0x7b, 0x7e, 0xf1, 0x59, 0x4c, 0x4a, 0x1b, 0xf7, 0x00, 0xae, 0x39, 0x58, 0x44, 0x57, 0x93, 0x4b, 0xf7,
0x1f, 0x0f, 0xfe, 0xf5, 0xb0, 0x9f, 0xaf, 0xd4, 0x87, 0xb5, 0xb3, 0x96, 0xbb, 0xd9, 0xa7, 0xbf, 0x9e, 0xc2, 0xe6, 0x69, 0x46, 0x02, 0xb5, 0x3e, 0x42, 0x13, 0xc9, 0xb1, 0x66, 0xf7, 0xa0, 0x8a,
0x03, 0x00, 0x00, 0xff, 0xff, 0x18, 0xa1, 0x4b, 0x5b, 0x27, 0x04, 0x00, 0x00, 0x53, 0x14, 0x5c, 0xc6, 0xc5, 0x17, 0x7a, 0x08, 0xf3, 0xdf, 0xfb, 0x95, 0xe7, 0x53, 0x14, 0xc7,
0x47, 0x61, 0xc5, 0x8e, 0x8e, 0xe3, 0xc3, 0x4f, 0x17, 0x97, 0xad, 0x95, 0x5f, 0x97, 0xad, 0x95,
0xaf, 0xf3, 0x96, 0x77, 0x31, 0x6f, 0x79, 0x3f, 0xe7, 0x2d, 0xef, 0xcf, 0xbc, 0xe5, 0x7d, 0x3c,
0xfc, 0xd7, 0x5f, 0xcc, 0xb3, 0x65, 0xf5, 0x61, 0xe5, 0xbc, 0xe2, 0xfe, 0x1e, 0x4f, 0xfe, 0x06,
0x00, 0x00, 0xff, 0xff, 0x7f, 0x24, 0x6f, 0x2e, 0xb1, 0x04, 0x00, 0x00,
} }

View File

@ -25,6 +25,8 @@ message CreateOptions {
string shim_cgroup = 9; string shim_cgroup = 9;
uint32 io_uid = 10; uint32 io_uid = 10;
uint32 io_gid = 11; uint32 io_gid = 11;
string criu_work_path = 12;
string criu_image_path = 13;
} }
message CheckpointOptions { message CheckpointOptions {
@ -35,6 +37,8 @@ message CheckpointOptions {
bool file_locks = 5; bool file_locks = 5;
repeated string empty_namespaces = 6; repeated string empty_namespaces = 6;
string cgroups_mode = 7; string cgroups_mode = 7;
string work_path = 8;
string image_path = 9;
} }
message ProcessDetails { message ProcessDetails {

View File

@ -69,4 +69,8 @@ type PlatformRuntime interface {
// Tasks returns all the current tasks for the runtime. // Tasks returns all the current tasks for the runtime.
// Any container runs at most one task at a time. // Any container runs at most one task at a time.
Tasks(context.Context, bool) ([]Task, error) Tasks(context.Context, bool) ([]Task, error)
// Add adds a task into runtime.
Add(context.Context, Task) error
// Delete remove a task.
Delete(context.Context, string)
} }

View File

@ -20,6 +20,7 @@ package linux
import ( import (
"context" "context"
"fmt"
"io/ioutil" "io/ioutil"
"os" "os"
"path/filepath" "path/filepath"
@ -114,12 +115,12 @@ func (b *bundle) NewShimClient(ctx context.Context, namespace string, getClientO
// Delete deletes the bundle from disk // Delete deletes the bundle from disk
func (b *bundle) Delete() error { func (b *bundle) Delete() error {
err := os.RemoveAll(b.path) err := atomicDelete(b.path)
if err == nil { if err == nil {
return os.RemoveAll(b.workDir) return atomicDelete(b.workDir)
} }
// error removing the bundle path; still attempt removing work dir // error removing the bundle path; still attempt removing work dir
err2 := os.RemoveAll(b.workDir) err2 := atomicDelete(b.workDir)
if err2 == nil { if err2 == nil {
return err return err
} }
@ -152,3 +153,13 @@ func (b *bundle) shimConfig(namespace string, c *Config, runcOptions *runctypes.
SystemdCgroup: systemdCgroup, SystemdCgroup: systemdCgroup,
} }
} }
// atomicDelete renames the path to a hidden file before removal
func atomicDelete(path string) error {
// create a hidden dir for an atomic removal
atomicPath := filepath.Join(filepath.Dir(path), fmt.Sprintf(".%s", filepath.Base(path)))
if err := os.Rename(path, atomicPath); err != nil {
return err
}
return os.RemoveAll(atomicPath)
}

View File

@ -69,7 +69,3 @@ func (s *deletedState) SetExited(status int) {
func (s *deletedState) Exec(ctx context.Context, path string, r *ExecConfig) (proc.Process, error) { func (s *deletedState) Exec(ctx context.Context, path string, r *ExecConfig) (proc.Process, error) {
return nil, errors.Errorf("cannot exec in a deleted state") return nil, errors.Errorf("cannot exec in a deleted state")
} }
func (s *deletedState) Pid() int {
return -1
}

Some files were not shown because too many files have changed in this diff Show More