From 80188e253a11afe464e7cddbc6e8d263394047ae Mon Sep 17 00:00:00 2001 From: Lantao Liu Date: Wed, 23 May 2018 10:16:33 -0700 Subject: [PATCH 1/3] Update containerd to d1435e6e4dcffd99e0da396ff771b5bbe0d93f5e. Signed-off-by: Lantao Liu --- vendor.conf | 10 +- .../github.com/Microsoft/hcsshim/baselayer.go | 54 +- .../github.com/Microsoft/hcsshim/hcsshim.go | 2 +- .../Microsoft/hcsshim/hnsendpoint.go | 646 +++++++++--------- .../Microsoft/hcsshim/hnsnetwork.go | 282 ++++---- .../github.com/Microsoft/hcsshim/hnspolicy.go | 188 ++--- .../Microsoft/hcsshim/hnspolicylist.go | 400 +++++------ .../Microsoft/hcsshim/importlayer.go | 40 +- vendor/github.com/Microsoft/hcsshim/legacy.go | 289 +++++--- .../github.com/Microsoft/hcsshim/legacy18.go | 14 +- .../github.com/Microsoft/hcsshim/legacy19.go | 14 +- .../github.com/Microsoft/hcsshim/safeopen.go | 427 ++++++++++++ .../github.com/Microsoft/hcsshim/zhcsshim.go | 38 ++ .../containerd/containerd/README.md | 2 +- .../containerd/containerd/archive/tar.go | 2 +- .../containerd/containerd/cio/io.go | 42 ++ .../containerd/containerd/cio/io_unix.go | 10 + .../containerd/containerd/client.go | 151 +--- .../containerd/cmd/containerd/command/main.go | 5 +- .../cmd/ctr/commands/content/content.go | 2 +- .../cmd/ctr/commands/content/fetch.go | 16 +- .../cmd/ctr/commands/events/events.go | 48 +- .../cmd/ctr/commands/images/pull.go | 14 +- .../containerd/cmd/ctr/commands/shim/shim.go | 3 +- .../cmd/ctr/commands/snapshots/snapshots.go | 11 +- .../containerd/cmd/ctr/commands/tasks/list.go | 2 +- .../cmd/ctr/commands/tasks/tasks_unix.go | 31 +- .../containerd/containerd/container.go | 8 +- .../containerd/containerd/container_opts.go | 3 +- .../containerd/contrib/apparmor/apparmor.go | 2 +- .../github.com/containerd/containerd/grpc.go | 3 +- .../containerd/containerd/import.go | 121 ++++ .../containerd/containerd/leases/grpc.go | 3 +- .../containerd/linux/proc/init_state.go | 28 +- .../containerd/containerd/linux/runtime.go | 3 +- .../{reaper => linux/shim}/reaper.go | 2 +- .../containerd/linux/shim/service.go | 3 +- .../containerd/containerd/metadata/buckets.go | 6 +- .../containerd/metrics/cgroups/cgroups.go | 3 +- .../containerd/mount/mountinfo_linux.go | 109 +-- .../containerd/containerd/mount/temp.go | 9 +- .../containerd/containerd/namespaces/grpc.go | 3 +- .../containerd/containerd/oci/spec.go | 6 +- .../containerd/containerd/oci/spec_opts.go | 16 +- .../containerd/oci/spec_opts_unix.go | 56 +- .../containerd/oci/spec_opts_windows.go | 6 +- .../containerd/containerd/oci/spec_unix.go | 4 +- .../containerd/containerd/oci/spec_windows.go | 4 +- .../containerd/containerd/plugin/plugin.go | 4 +- .../containerd/containerd/rootfs/apply.go | 119 ++-- .../containerd/containerd/rootfs/diff.go | 2 +- .../containerd/containerd/rootfs/init.go | 2 +- .../containerd/containerd/runtime/runtime.go | 6 +- .../containerd/containerd/server/server.go | 4 +- .../containerd/services/containers/local.go | 3 +- .../containerd/services/containers/service.go | 3 +- .../containerd/services/content/service.go | 2 +- .../containerd/services/diff/local.go | 3 +- .../containerd/services/diff/service.go | 3 +- .../containerd/services/events/service.go | 3 +- .../containerd/services/images/local.go | 5 +- .../containerd/services/images/service.go | 3 +- .../services/introspection/service.go | 3 +- .../containerd/services/leases/local.go | 2 +- .../containerd/services/leases/service.go | 3 +- .../containerd/services/namespaces/local.go | 2 +- .../containerd/services/namespaces/service.go | 3 +- .../containerd/services/snapshots/service.go | 5 +- .../containerd/services/tasks/local.go | 14 +- .../containerd/services/tasks/service.go | 3 +- .../containerd/services/version/service.go | 3 +- .../containerd/containerd/sys/env.go | 33 + .../containerd/containerd/sys/oom_unix.go | 2 +- .../containerd/containerd/vendor.conf | 10 +- .../containerd/containerd/version/version.go | 2 +- .../github.com/containerd/go-runc/console.go | 2 +- vendor/github.com/containerd/go-runc/runc.go | 12 +- .../go-digest/{LICENSE.code => LICENSE} | 0 .../opencontainers/go-digest/README.md | 18 +- .../opencontainers/go-digest/algorithm.go | 54 +- .../opencontainers/go-digest/digest.go | 56 +- .../opencontainers/go-digest/digester.go | 14 + .../opencontainers/go-digest/doc.go | 14 + .../opencontainers/go-digest/verifiers.go | 14 + vendor/golang.org/x/net/context/context.go | 102 --- vendor/golang.org/x/net/context/go19.go | 20 + vendor/golang.org/x/net/context/pre_go19.go | 109 +++ .../x/net/http2/configure_transport.go | 2 +- vendor/golang.org/x/net/http2/errors.go | 13 +- vendor/golang.org/x/net/http2/go18.go | 2 + vendor/golang.org/x/net/http2/http2.go | 8 +- vendor/golang.org/x/net/http2/not_go18.go | 2 + vendor/golang.org/x/net/http2/pipe.go | 2 +- vendor/golang.org/x/net/http2/server.go | 19 +- vendor/golang.org/x/net/http2/transport.go | 27 +- vendor/golang.org/x/net/idna/idna.go | 64 +- vendor/golang.org/x/net/trace/events.go | 6 +- vendor/golang.org/x/net/trace/trace.go | 58 +- 98 files changed, 2493 insertions(+), 1513 deletions(-) create mode 100644 vendor/github.com/Microsoft/hcsshim/safeopen.go create mode 100644 vendor/github.com/containerd/containerd/import.go rename vendor/github.com/containerd/containerd/{reaper => linux/shim}/reaper.go (99%) create mode 100644 vendor/github.com/containerd/containerd/sys/env.go rename vendor/github.com/opencontainers/go-digest/{LICENSE.code => LICENSE} (100%) create mode 100644 vendor/golang.org/x/net/context/go19.go create mode 100644 vendor/golang.org/x/net/context/pre_go19.go diff --git a/vendor.conf b/vendor.conf index 0e9fdc8d9..4a34e0a14 100644 --- a/vendor.conf +++ b/vendor.conf @@ -4,11 +4,11 @@ github.com/boltdb/bolt e9cf4fae01b5a8ff89d0ec6b32f0d9c9f79aefdd github.com/BurntSushi/toml a368813c5e648fee92e5f6c30e3944ff9d5e8895 github.com/containerd/cgroups fe281dd265766145e943a034aa41086474ea6130 github.com/containerd/console cb7008ab3d8359b78c5f464cb7cf160107ad5925 -github.com/containerd/containerd 1381f8fddc4f826e12b48d46c9def347d5aa338a +github.com/containerd/containerd d1435e6e4dcffd99e0da396ff771b5bbe0d93f5e github.com/containerd/continuity 3e8f2ea4b190484acb976a5b378d373429639a1a github.com/containerd/fifo 3d5202aec260678c48179c56f40e6f38a095738c github.com/containerd/go-cni f2d7272f12d045b16ed924f50e91f9f9cecc55a7 -github.com/containerd/go-runc bcb223a061a3dd7de1a89c0b402a60f4dd9bd307 +github.com/containerd/go-runc f271fa2021de855d4d918dbef83c5fe19db1bdd5 github.com/containerd/typeurl f6943554a7e7e88b3c14aad190bf05932da84788 github.com/containernetworking/cni v0.6.0 github.com/containernetworking/plugins v0.7.0 @@ -34,8 +34,8 @@ github.com/hashicorp/go-multierror ed905158d87462226a13fe39ddf685ea65f1c11f github.com/json-iterator/go 1.0.4 github.com/matttproud/golang_protobuf_extensions v1.0.0 github.com/Microsoft/go-winio v0.4.5 -github.com/Microsoft/hcsshim v0.6.7 -github.com/opencontainers/go-digest 21dfd564fd89c944783d00d069f33e3e7123c448 +github.com/Microsoft/hcsshim v0.6.10 +github.com/opencontainers/go-digest c9281466c8b2f606084ac71339773efd177436e7 github.com/opencontainers/image-spec v1.0.1 github.com/opencontainers/runc 69663f0bd4b60df09991c08812a60108003fa340 github.com/opencontainers/runtime-spec v1.0.1 @@ -56,7 +56,7 @@ github.com/syndtr/gocapability db04d3cc01c8b54962a58ec7e491717d06cfcc16 github.com/tchap/go-patricia 5ad6cdb7538b0097d5598c7e57f0a24072adf7dc github.com/urfave/cli 7bc6a0acffa589f415f88aca16cc1de5ffd66f9c golang.org/x/crypto 49796115aa4b964c318aad4f3084fdb41e9aa067 -golang.org/x/net 7dcfb8076726a3fdd9353b6b8a1f1b6be6811bd6 +golang.org/x/net b3756b4b77d7b13260a0a2ec658753cf48922eac golang.org/x/sync 450f422ab23cf9881c94e2db30cac0eb1b7cf80c golang.org/x/sys 314a259e304ff91bd6985da2a7149bbf91237993 https://github.com/golang/sys golang.org/x/text 19e51611da83d6be54ddafce4a4af510cb3e9ea4 diff --git a/vendor/github.com/Microsoft/hcsshim/baselayer.go b/vendor/github.com/Microsoft/hcsshim/baselayer.go index 9babd4e18..860185c35 100644 --- a/vendor/github.com/Microsoft/hcsshim/baselayer.go +++ b/vendor/github.com/Microsoft/hcsshim/baselayer.go @@ -10,7 +10,7 @@ import ( ) type baseLayerWriter struct { - root string + root *os.File f *os.File bw *winio.BackupFileWriter err error @@ -26,10 +26,10 @@ type dirInfo struct { // reapplyDirectoryTimes reapplies directory modification, creation, etc. times // after processing of the directory tree has completed. The times are expected // to be ordered such that parent directories come before child directories. -func reapplyDirectoryTimes(dis []dirInfo) error { +func reapplyDirectoryTimes(root *os.File, dis []dirInfo) error { for i := range dis { di := &dis[len(dis)-i-1] // reverse order: process child directories first - f, err := winio.OpenForBackup(di.path, syscall.GENERIC_READ|syscall.GENERIC_WRITE, syscall.FILE_SHARE_READ, syscall.OPEN_EXISTING) + f, err := openRelative(di.path, root, syscall.GENERIC_READ|syscall.GENERIC_WRITE, syscall.FILE_SHARE_READ, _FILE_OPEN, _FILE_DIRECTORY_FILE) if err != nil { return err } @@ -75,12 +75,6 @@ func (w *baseLayerWriter) Add(name string, fileInfo *winio.FileBasicInfo) (err e w.hasUtilityVM = true } - path := filepath.Join(w.root, name) - path, err = makeLongAbsPath(path) - if err != nil { - return err - } - var f *os.File defer func() { if f != nil { @@ -88,27 +82,23 @@ func (w *baseLayerWriter) Add(name string, fileInfo *winio.FileBasicInfo) (err e } }() - createmode := uint32(syscall.CREATE_NEW) + extraFlags := uint32(0) if fileInfo.FileAttributes&syscall.FILE_ATTRIBUTE_DIRECTORY != 0 { - err := os.Mkdir(path, 0) - if err != nil && !os.IsExist(err) { - return err - } - createmode = syscall.OPEN_EXISTING + extraFlags |= _FILE_DIRECTORY_FILE if fileInfo.FileAttributes&syscall.FILE_ATTRIBUTE_REPARSE_POINT == 0 { - w.dirInfo = append(w.dirInfo, dirInfo{path, *fileInfo}) + w.dirInfo = append(w.dirInfo, dirInfo{name, *fileInfo}) } } mode := uint32(syscall.GENERIC_READ | syscall.GENERIC_WRITE | winio.WRITE_DAC | winio.WRITE_OWNER | winio.ACCESS_SYSTEM_SECURITY) - f, err = winio.OpenForBackup(path, mode, syscall.FILE_SHARE_READ, createmode) + f, err = openRelative(name, w.root, mode, syscall.FILE_SHARE_READ, _FILE_CREATE, extraFlags) if err != nil { - return makeError(err, "Failed to OpenForBackup", path) + return makeError(err, "Failed to openRelative", name) } err = winio.SetFileBasicInfo(f, fileInfo) if err != nil { - return makeError(err, "Failed to SetFileBasicInfo", path) + return makeError(err, "Failed to SetFileBasicInfo", name) } w.f = f @@ -129,17 +119,7 @@ func (w *baseLayerWriter) AddLink(name string, target string) (err error) { return err } - linkpath, err := makeLongAbsPath(filepath.Join(w.root, name)) - if err != nil { - return err - } - - linktarget, err := makeLongAbsPath(filepath.Join(w.root, target)) - if err != nil { - return err - } - - return os.Link(linktarget, linkpath) + return linkRelative(target, w.root, name, w.root) } func (w *baseLayerWriter) Remove(name string) error { @@ -155,6 +135,10 @@ func (w *baseLayerWriter) Write(b []byte) (int, error) { } func (w *baseLayerWriter) Close() error { + defer func() { + w.root.Close() + w.root = nil + }() err := w.closeCurrentFile() if err != nil { return err @@ -162,18 +146,22 @@ func (w *baseLayerWriter) Close() error { if w.err == nil { // Restore the file times of all the directories, since they may have // been modified by creating child directories. - err = reapplyDirectoryTimes(w.dirInfo) + err = reapplyDirectoryTimes(w.root, w.dirInfo) if err != nil { return err } - err = ProcessBaseLayer(w.root) + err = ProcessBaseLayer(w.root.Name()) if err != nil { return err } if w.hasUtilityVM { - err = ProcessUtilityVMImage(filepath.Join(w.root, "UtilityVM")) + err := ensureNotReparsePointRelative("UtilityVM", w.root) + if err != nil { + return err + } + err = ProcessUtilityVMImage(filepath.Join(w.root.Name(), "UtilityVM")) if err != nil { return err } diff --git a/vendor/github.com/Microsoft/hcsshim/hcsshim.go b/vendor/github.com/Microsoft/hcsshim/hcsshim.go index 236ba1fa3..b65953191 100644 --- a/vendor/github.com/Microsoft/hcsshim/hcsshim.go +++ b/vendor/github.com/Microsoft/hcsshim/hcsshim.go @@ -11,7 +11,7 @@ import ( "github.com/sirupsen/logrus" ) -//go:generate go run mksyscall_windows.go -output zhcsshim.go hcsshim.go +//go:generate go run mksyscall_windows.go -output zhcsshim.go hcsshim.go safeopen.go //sys coTaskMemFree(buffer unsafe.Pointer) = ole32.CoTaskMemFree //sys SetCurrentThreadCompartmentId(compartmentId uint32) (hr error) = iphlpapi.SetCurrentThreadCompartmentId diff --git a/vendor/github.com/Microsoft/hcsshim/hnsendpoint.go b/vendor/github.com/Microsoft/hcsshim/hnsendpoint.go index 7e516f8a2..90689cb1e 100644 --- a/vendor/github.com/Microsoft/hcsshim/hnsendpoint.go +++ b/vendor/github.com/Microsoft/hcsshim/hnsendpoint.go @@ -1,323 +1,323 @@ -package hcsshim - -import ( - "encoding/json" - "net" - - "github.com/sirupsen/logrus" -) - -// HNSEndpoint represents a network endpoint in HNS -type HNSEndpoint struct { - Id string `json:"ID,omitempty"` - Name string `json:",omitempty"` - VirtualNetwork string `json:",omitempty"` - VirtualNetworkName string `json:",omitempty"` - Policies []json.RawMessage `json:",omitempty"` - MacAddress string `json:",omitempty"` - IPAddress net.IP `json:",omitempty"` - DNSSuffix string `json:",omitempty"` - DNSServerList string `json:",omitempty"` - GatewayAddress string `json:",omitempty"` - EnableInternalDNS bool `json:",omitempty"` - DisableICC bool `json:",omitempty"` - PrefixLength uint8 `json:",omitempty"` - IsRemoteEndpoint bool `json:",omitempty"` -} - -//SystemType represents the type of the system on which actions are done -type SystemType string - -// SystemType const -const ( - ContainerType SystemType = "Container" - VirtualMachineType SystemType = "VirtualMachine" - HostType SystemType = "Host" -) - -// EndpointAttachDetachRequest is the structure used to send request to the container to modify the system -// Supported resource types are Network and Request Types are Add/Remove -type EndpointAttachDetachRequest struct { - ContainerID string `json:"ContainerId,omitempty"` - SystemType SystemType `json:"SystemType"` - CompartmentID uint16 `json:"CompartmentId,omitempty"` - VirtualNICName string `json:"VirtualNicName,omitempty"` -} - -// EndpointResquestResponse is object to get the endpoint request response -type EndpointResquestResponse struct { - Success bool - Error string -} - -// HNSEndpointRequest makes a HNS call to modify/query a network endpoint -func HNSEndpointRequest(method, path, request string) (*HNSEndpoint, error) { - endpoint := &HNSEndpoint{} - err := hnsCall(method, "/endpoints/"+path, request, &endpoint) - if err != nil { - return nil, err - } - - return endpoint, nil -} - -// HNSListEndpointRequest makes a HNS call to query the list of available endpoints -func HNSListEndpointRequest() ([]HNSEndpoint, error) { - var endpoint []HNSEndpoint - err := hnsCall("GET", "/endpoints/", "", &endpoint) - if err != nil { - return nil, err - } - - return endpoint, nil -} - -// HotAttachEndpoint makes a HCS Call to attach the endpoint to the container -func HotAttachEndpoint(containerID string, endpointID string) error { - return modifyNetworkEndpoint(containerID, endpointID, Add) -} - -// HotDetachEndpoint makes a HCS Call to detach the endpoint from the container -func HotDetachEndpoint(containerID string, endpointID string) error { - return modifyNetworkEndpoint(containerID, endpointID, Remove) -} - -// ModifyContainer corresponding to the container id, by sending a request -func modifyContainer(id string, request *ResourceModificationRequestResponse) error { - container, err := OpenContainer(id) - if err != nil { - if IsNotExist(err) { - return ErrComputeSystemDoesNotExist - } - return getInnerError(err) - } - defer container.Close() - err = container.Modify(request) - if err != nil { - if IsNotSupported(err) { - return ErrPlatformNotSupported - } - return getInnerError(err) - } - - return nil -} - -func modifyNetworkEndpoint(containerID string, endpointID string, request RequestType) error { - requestMessage := &ResourceModificationRequestResponse{ - Resource: Network, - Request: request, - Data: endpointID, - } - err := modifyContainer(containerID, requestMessage) - - if err != nil { - return err - } - - return nil -} - -// GetHNSEndpointByID get the Endpoint by ID -func GetHNSEndpointByID(endpointID string) (*HNSEndpoint, error) { - return HNSEndpointRequest("GET", endpointID, "") -} - -// GetHNSEndpointByName gets the endpoint filtered by Name -func GetHNSEndpointByName(endpointName string) (*HNSEndpoint, error) { - hnsResponse, err := HNSListEndpointRequest() - if err != nil { - return nil, err - } - for _, hnsEndpoint := range hnsResponse { - if hnsEndpoint.Name == endpointName { - return &hnsEndpoint, nil - } - } - return nil, EndpointNotFoundError{EndpointName: endpointName} -} - -// Create Endpoint by sending EndpointRequest to HNS. TODO: Create a separate HNS interface to place all these methods -func (endpoint *HNSEndpoint) Create() (*HNSEndpoint, error) { - operation := "Create" - title := "HCSShim::HNSEndpoint::" + operation - logrus.Debugf(title+" id=%s", endpoint.Id) - - jsonString, err := json.Marshal(endpoint) - if err != nil { - return nil, err - } - return HNSEndpointRequest("POST", "", string(jsonString)) -} - -// Delete Endpoint by sending EndpointRequest to HNS -func (endpoint *HNSEndpoint) Delete() (*HNSEndpoint, error) { - operation := "Delete" - title := "HCSShim::HNSEndpoint::" + operation - logrus.Debugf(title+" id=%s", endpoint.Id) - - return HNSEndpointRequest("DELETE", endpoint.Id, "") -} - -// Update Endpoint -func (endpoint *HNSEndpoint) Update() (*HNSEndpoint, error) { - operation := "Update" - title := "HCSShim::HNSEndpoint::" + operation - logrus.Debugf(title+" id=%s", endpoint.Id) - jsonString, err := json.Marshal(endpoint) - if err != nil { - return nil, err - } - err = hnsCall("POST", "/endpoints/"+endpoint.Id, string(jsonString), &endpoint) - - return endpoint, err -} - -// ContainerHotAttach attaches an endpoint to a running container -func (endpoint *HNSEndpoint) ContainerHotAttach(containerID string) error { - operation := "ContainerHotAttach" - title := "HCSShim::HNSEndpoint::" + operation - logrus.Debugf(title+" id=%s, containerId=%s", endpoint.Id, containerID) - - return modifyNetworkEndpoint(containerID, endpoint.Id, Add) -} - -// ContainerHotDetach detaches an endpoint from a running container -func (endpoint *HNSEndpoint) ContainerHotDetach(containerID string) error { - operation := "ContainerHotDetach" - title := "HCSShim::HNSEndpoint::" + operation - logrus.Debugf(title+" id=%s, containerId=%s", endpoint.Id, containerID) - - return modifyNetworkEndpoint(containerID, endpoint.Id, Remove) -} - -// ApplyACLPolicy applies a set of ACL Policies on the Endpoint -func (endpoint *HNSEndpoint) ApplyACLPolicy(policies ...*ACLPolicy) error { - operation := "ApplyACLPolicy" - title := "HCSShim::HNSEndpoint::" + operation - logrus.Debugf(title+" id=%s", endpoint.Id) - - for _, policy := range policies { - if policy == nil { - continue - } - jsonString, err := json.Marshal(policy) - if err != nil { - return err - } - endpoint.Policies = append(endpoint.Policies, jsonString) - } - - _, err := endpoint.Update() - return err -} - -// ContainerAttach attaches an endpoint to container -func (endpoint *HNSEndpoint) ContainerAttach(containerID string, compartmentID uint16) error { - operation := "ContainerAttach" - title := "HCSShim::HNSEndpoint::" + operation - logrus.Debugf(title+" id=%s", endpoint.Id) - - requestMessage := &EndpointAttachDetachRequest{ - ContainerID: containerID, - CompartmentID: compartmentID, - SystemType: ContainerType, - } - response := &EndpointResquestResponse{} - jsonString, err := json.Marshal(requestMessage) - if err != nil { - return err - } - return hnsCall("POST", "/endpoints/"+endpoint.Id+"/attach", string(jsonString), &response) -} - -// ContainerDetach detaches an endpoint from container -func (endpoint *HNSEndpoint) ContainerDetach(containerID string) error { - operation := "ContainerDetach" - title := "HCSShim::HNSEndpoint::" + operation - logrus.Debugf(title+" id=%s", endpoint.Id) - - requestMessage := &EndpointAttachDetachRequest{ - ContainerID: containerID, - SystemType: ContainerType, - } - response := &EndpointResquestResponse{} - - jsonString, err := json.Marshal(requestMessage) - if err != nil { - return err - } - return hnsCall("POST", "/endpoints/"+endpoint.Id+"/detach", string(jsonString), &response) -} - -// HostAttach attaches a nic on the host -func (endpoint *HNSEndpoint) HostAttach(compartmentID uint16) error { - operation := "HostAttach" - title := "HCSShim::HNSEndpoint::" + operation - logrus.Debugf(title+" id=%s", endpoint.Id) - requestMessage := &EndpointAttachDetachRequest{ - CompartmentID: compartmentID, - SystemType: HostType, - } - response := &EndpointResquestResponse{} - - jsonString, err := json.Marshal(requestMessage) - if err != nil { - return err - } - return hnsCall("POST", "/endpoints/"+endpoint.Id+"/attach", string(jsonString), &response) - -} - -// HostDetach detaches a nic on the host -func (endpoint *HNSEndpoint) HostDetach() error { - operation := "HostDetach" - title := "HCSShim::HNSEndpoint::" + operation - logrus.Debugf(title+" id=%s", endpoint.Id) - requestMessage := &EndpointAttachDetachRequest{ - SystemType: HostType, - } - response := &EndpointResquestResponse{} - - jsonString, err := json.Marshal(requestMessage) - if err != nil { - return err - } - return hnsCall("POST", "/endpoints/"+endpoint.Id+"/detach", string(jsonString), &response) -} - -// VirtualMachineNICAttach attaches a endpoint to a virtual machine -func (endpoint *HNSEndpoint) VirtualMachineNICAttach(virtualMachineNICName string) error { - operation := "VirtualMachineNicAttach" - title := "HCSShim::HNSEndpoint::" + operation - logrus.Debugf(title+" id=%s", endpoint.Id) - requestMessage := &EndpointAttachDetachRequest{ - VirtualNICName: virtualMachineNICName, - SystemType: VirtualMachineType, - } - response := &EndpointResquestResponse{} - - jsonString, err := json.Marshal(requestMessage) - if err != nil { - return err - } - return hnsCall("POST", "/endpoints/"+endpoint.Id+"/attach", string(jsonString), &response) -} - -// VirtualMachineNICDetach detaches a endpoint from a virtual machine -func (endpoint *HNSEndpoint) VirtualMachineNICDetach() error { - operation := "VirtualMachineNicDetach" - title := "HCSShim::HNSEndpoint::" + operation - logrus.Debugf(title+" id=%s", endpoint.Id) - - requestMessage := &EndpointAttachDetachRequest{ - SystemType: VirtualMachineType, - } - response := &EndpointResquestResponse{} - - jsonString, err := json.Marshal(requestMessage) - if err != nil { - return err - } - return hnsCall("POST", "/endpoints/"+endpoint.Id+"/detach", string(jsonString), &response) -} +package hcsshim + +import ( + "encoding/json" + "net" + + "github.com/sirupsen/logrus" +) + +// HNSEndpoint represents a network endpoint in HNS +type HNSEndpoint struct { + Id string `json:"ID,omitempty"` + Name string `json:",omitempty"` + VirtualNetwork string `json:",omitempty"` + VirtualNetworkName string `json:",omitempty"` + Policies []json.RawMessage `json:",omitempty"` + MacAddress string `json:",omitempty"` + IPAddress net.IP `json:",omitempty"` + DNSSuffix string `json:",omitempty"` + DNSServerList string `json:",omitempty"` + GatewayAddress string `json:",omitempty"` + EnableInternalDNS bool `json:",omitempty"` + DisableICC bool `json:",omitempty"` + PrefixLength uint8 `json:",omitempty"` + IsRemoteEndpoint bool `json:",omitempty"` +} + +//SystemType represents the type of the system on which actions are done +type SystemType string + +// SystemType const +const ( + ContainerType SystemType = "Container" + VirtualMachineType SystemType = "VirtualMachine" + HostType SystemType = "Host" +) + +// EndpointAttachDetachRequest is the structure used to send request to the container to modify the system +// Supported resource types are Network and Request Types are Add/Remove +type EndpointAttachDetachRequest struct { + ContainerID string `json:"ContainerId,omitempty"` + SystemType SystemType `json:"SystemType"` + CompartmentID uint16 `json:"CompartmentId,omitempty"` + VirtualNICName string `json:"VirtualNicName,omitempty"` +} + +// EndpointResquestResponse is object to get the endpoint request response +type EndpointResquestResponse struct { + Success bool + Error string +} + +// HNSEndpointRequest makes a HNS call to modify/query a network endpoint +func HNSEndpointRequest(method, path, request string) (*HNSEndpoint, error) { + endpoint := &HNSEndpoint{} + err := hnsCall(method, "/endpoints/"+path, request, &endpoint) + if err != nil { + return nil, err + } + + return endpoint, nil +} + +// HNSListEndpointRequest makes a HNS call to query the list of available endpoints +func HNSListEndpointRequest() ([]HNSEndpoint, error) { + var endpoint []HNSEndpoint + err := hnsCall("GET", "/endpoints/", "", &endpoint) + if err != nil { + return nil, err + } + + return endpoint, nil +} + +// HotAttachEndpoint makes a HCS Call to attach the endpoint to the container +func HotAttachEndpoint(containerID string, endpointID string) error { + return modifyNetworkEndpoint(containerID, endpointID, Add) +} + +// HotDetachEndpoint makes a HCS Call to detach the endpoint from the container +func HotDetachEndpoint(containerID string, endpointID string) error { + return modifyNetworkEndpoint(containerID, endpointID, Remove) +} + +// ModifyContainer corresponding to the container id, by sending a request +func modifyContainer(id string, request *ResourceModificationRequestResponse) error { + container, err := OpenContainer(id) + if err != nil { + if IsNotExist(err) { + return ErrComputeSystemDoesNotExist + } + return getInnerError(err) + } + defer container.Close() + err = container.Modify(request) + if err != nil { + if IsNotSupported(err) { + return ErrPlatformNotSupported + } + return getInnerError(err) + } + + return nil +} + +func modifyNetworkEndpoint(containerID string, endpointID string, request RequestType) error { + requestMessage := &ResourceModificationRequestResponse{ + Resource: Network, + Request: request, + Data: endpointID, + } + err := modifyContainer(containerID, requestMessage) + + if err != nil { + return err + } + + return nil +} + +// GetHNSEndpointByID get the Endpoint by ID +func GetHNSEndpointByID(endpointID string) (*HNSEndpoint, error) { + return HNSEndpointRequest("GET", endpointID, "") +} + +// GetHNSEndpointByName gets the endpoint filtered by Name +func GetHNSEndpointByName(endpointName string) (*HNSEndpoint, error) { + hnsResponse, err := HNSListEndpointRequest() + if err != nil { + return nil, err + } + for _, hnsEndpoint := range hnsResponse { + if hnsEndpoint.Name == endpointName { + return &hnsEndpoint, nil + } + } + return nil, EndpointNotFoundError{EndpointName: endpointName} +} + +// Create Endpoint by sending EndpointRequest to HNS. TODO: Create a separate HNS interface to place all these methods +func (endpoint *HNSEndpoint) Create() (*HNSEndpoint, error) { + operation := "Create" + title := "HCSShim::HNSEndpoint::" + operation + logrus.Debugf(title+" id=%s", endpoint.Id) + + jsonString, err := json.Marshal(endpoint) + if err != nil { + return nil, err + } + return HNSEndpointRequest("POST", "", string(jsonString)) +} + +// Delete Endpoint by sending EndpointRequest to HNS +func (endpoint *HNSEndpoint) Delete() (*HNSEndpoint, error) { + operation := "Delete" + title := "HCSShim::HNSEndpoint::" + operation + logrus.Debugf(title+" id=%s", endpoint.Id) + + return HNSEndpointRequest("DELETE", endpoint.Id, "") +} + +// Update Endpoint +func (endpoint *HNSEndpoint) Update() (*HNSEndpoint, error) { + operation := "Update" + title := "HCSShim::HNSEndpoint::" + operation + logrus.Debugf(title+" id=%s", endpoint.Id) + jsonString, err := json.Marshal(endpoint) + if err != nil { + return nil, err + } + err = hnsCall("POST", "/endpoints/"+endpoint.Id, string(jsonString), &endpoint) + + return endpoint, err +} + +// ContainerHotAttach attaches an endpoint to a running container +func (endpoint *HNSEndpoint) ContainerHotAttach(containerID string) error { + operation := "ContainerHotAttach" + title := "HCSShim::HNSEndpoint::" + operation + logrus.Debugf(title+" id=%s, containerId=%s", endpoint.Id, containerID) + + return modifyNetworkEndpoint(containerID, endpoint.Id, Add) +} + +// ContainerHotDetach detaches an endpoint from a running container +func (endpoint *HNSEndpoint) ContainerHotDetach(containerID string) error { + operation := "ContainerHotDetach" + title := "HCSShim::HNSEndpoint::" + operation + logrus.Debugf(title+" id=%s, containerId=%s", endpoint.Id, containerID) + + return modifyNetworkEndpoint(containerID, endpoint.Id, Remove) +} + +// ApplyACLPolicy applies a set of ACL Policies on the Endpoint +func (endpoint *HNSEndpoint) ApplyACLPolicy(policies ...*ACLPolicy) error { + operation := "ApplyACLPolicy" + title := "HCSShim::HNSEndpoint::" + operation + logrus.Debugf(title+" id=%s", endpoint.Id) + + for _, policy := range policies { + if policy == nil { + continue + } + jsonString, err := json.Marshal(policy) + if err != nil { + return err + } + endpoint.Policies = append(endpoint.Policies, jsonString) + } + + _, err := endpoint.Update() + return err +} + +// ContainerAttach attaches an endpoint to container +func (endpoint *HNSEndpoint) ContainerAttach(containerID string, compartmentID uint16) error { + operation := "ContainerAttach" + title := "HCSShim::HNSEndpoint::" + operation + logrus.Debugf(title+" id=%s", endpoint.Id) + + requestMessage := &EndpointAttachDetachRequest{ + ContainerID: containerID, + CompartmentID: compartmentID, + SystemType: ContainerType, + } + response := &EndpointResquestResponse{} + jsonString, err := json.Marshal(requestMessage) + if err != nil { + return err + } + return hnsCall("POST", "/endpoints/"+endpoint.Id+"/attach", string(jsonString), &response) +} + +// ContainerDetach detaches an endpoint from container +func (endpoint *HNSEndpoint) ContainerDetach(containerID string) error { + operation := "ContainerDetach" + title := "HCSShim::HNSEndpoint::" + operation + logrus.Debugf(title+" id=%s", endpoint.Id) + + requestMessage := &EndpointAttachDetachRequest{ + ContainerID: containerID, + SystemType: ContainerType, + } + response := &EndpointResquestResponse{} + + jsonString, err := json.Marshal(requestMessage) + if err != nil { + return err + } + return hnsCall("POST", "/endpoints/"+endpoint.Id+"/detach", string(jsonString), &response) +} + +// HostAttach attaches a nic on the host +func (endpoint *HNSEndpoint) HostAttach(compartmentID uint16) error { + operation := "HostAttach" + title := "HCSShim::HNSEndpoint::" + operation + logrus.Debugf(title+" id=%s", endpoint.Id) + requestMessage := &EndpointAttachDetachRequest{ + CompartmentID: compartmentID, + SystemType: HostType, + } + response := &EndpointResquestResponse{} + + jsonString, err := json.Marshal(requestMessage) + if err != nil { + return err + } + return hnsCall("POST", "/endpoints/"+endpoint.Id+"/attach", string(jsonString), &response) + +} + +// HostDetach detaches a nic on the host +func (endpoint *HNSEndpoint) HostDetach() error { + operation := "HostDetach" + title := "HCSShim::HNSEndpoint::" + operation + logrus.Debugf(title+" id=%s", endpoint.Id) + requestMessage := &EndpointAttachDetachRequest{ + SystemType: HostType, + } + response := &EndpointResquestResponse{} + + jsonString, err := json.Marshal(requestMessage) + if err != nil { + return err + } + return hnsCall("POST", "/endpoints/"+endpoint.Id+"/detach", string(jsonString), &response) +} + +// VirtualMachineNICAttach attaches a endpoint to a virtual machine +func (endpoint *HNSEndpoint) VirtualMachineNICAttach(virtualMachineNICName string) error { + operation := "VirtualMachineNicAttach" + title := "HCSShim::HNSEndpoint::" + operation + logrus.Debugf(title+" id=%s", endpoint.Id) + requestMessage := &EndpointAttachDetachRequest{ + VirtualNICName: virtualMachineNICName, + SystemType: VirtualMachineType, + } + response := &EndpointResquestResponse{} + + jsonString, err := json.Marshal(requestMessage) + if err != nil { + return err + } + return hnsCall("POST", "/endpoints/"+endpoint.Id+"/attach", string(jsonString), &response) +} + +// VirtualMachineNICDetach detaches a endpoint from a virtual machine +func (endpoint *HNSEndpoint) VirtualMachineNICDetach() error { + operation := "VirtualMachineNicDetach" + title := "HCSShim::HNSEndpoint::" + operation + logrus.Debugf(title+" id=%s", endpoint.Id) + + requestMessage := &EndpointAttachDetachRequest{ + SystemType: VirtualMachineType, + } + response := &EndpointResquestResponse{} + + jsonString, err := json.Marshal(requestMessage) + if err != nil { + return err + } + return hnsCall("POST", "/endpoints/"+endpoint.Id+"/detach", string(jsonString), &response) +} diff --git a/vendor/github.com/Microsoft/hcsshim/hnsnetwork.go b/vendor/github.com/Microsoft/hcsshim/hnsnetwork.go index 04c1b5919..398583a4e 100644 --- a/vendor/github.com/Microsoft/hcsshim/hnsnetwork.go +++ b/vendor/github.com/Microsoft/hcsshim/hnsnetwork.go @@ -1,141 +1,141 @@ -package hcsshim - -import ( - "encoding/json" - "net" - - "github.com/sirupsen/logrus" -) - -// Subnet is assoicated with a network and represents a list -// of subnets available to the network -type Subnet struct { - AddressPrefix string `json:",omitempty"` - GatewayAddress string `json:",omitempty"` - Policies []json.RawMessage `json:",omitempty"` -} - -// MacPool is assoicated with a network and represents a list -// of macaddresses available to the network -type MacPool struct { - StartMacAddress string `json:",omitempty"` - EndMacAddress string `json:",omitempty"` -} - -// HNSNetwork represents a network in HNS -type HNSNetwork struct { - Id string `json:"ID,omitempty"` - Name string `json:",omitempty"` - Type string `json:",omitempty"` - NetworkAdapterName string `json:",omitempty"` - SourceMac string `json:",omitempty"` - Policies []json.RawMessage `json:",omitempty"` - MacPools []MacPool `json:",omitempty"` - Subnets []Subnet `json:",omitempty"` - DNSSuffix string `json:",omitempty"` - DNSServerList string `json:",omitempty"` - DNSServerCompartment uint32 `json:",omitempty"` - ManagementIP string `json:",omitempty"` - AutomaticDNS bool `json:",omitempty"` -} - -type hnsNetworkResponse struct { - Success bool - Error string - Output HNSNetwork -} - -type hnsResponse struct { - Success bool - Error string - Output json.RawMessage -} - -// HNSNetworkRequest makes a call into HNS to update/query a single network -func HNSNetworkRequest(method, path, request string) (*HNSNetwork, error) { - var network HNSNetwork - err := hnsCall(method, "/networks/"+path, request, &network) - if err != nil { - return nil, err - } - - return &network, nil -} - -// HNSListNetworkRequest makes a HNS call to query the list of available networks -func HNSListNetworkRequest(method, path, request string) ([]HNSNetwork, error) { - var network []HNSNetwork - err := hnsCall(method, "/networks/"+path, request, &network) - if err != nil { - return nil, err - } - - return network, nil -} - -// GetHNSNetworkByID -func GetHNSNetworkByID(networkID string) (*HNSNetwork, error) { - return HNSNetworkRequest("GET", networkID, "") -} - -// GetHNSNetworkName filtered by Name -func GetHNSNetworkByName(networkName string) (*HNSNetwork, error) { - hsnnetworks, err := HNSListNetworkRequest("GET", "", "") - if err != nil { - return nil, err - } - for _, hnsnetwork := range hsnnetworks { - if hnsnetwork.Name == networkName { - return &hnsnetwork, nil - } - } - return nil, NetworkNotFoundError{NetworkName: networkName} -} - -// Create Network by sending NetworkRequest to HNS. -func (network *HNSNetwork) Create() (*HNSNetwork, error) { - operation := "Create" - title := "HCSShim::HNSNetwork::" + operation - logrus.Debugf(title+" id=%s", network.Id) - - jsonString, err := json.Marshal(network) - if err != nil { - return nil, err - } - return HNSNetworkRequest("POST", "", string(jsonString)) -} - -// Delete Network by sending NetworkRequest to HNS -func (network *HNSNetwork) Delete() (*HNSNetwork, error) { - operation := "Delete" - title := "HCSShim::HNSNetwork::" + operation - logrus.Debugf(title+" id=%s", network.Id) - - return HNSNetworkRequest("DELETE", network.Id, "") -} - -// Creates an endpoint on the Network. -func (network *HNSNetwork) NewEndpoint(ipAddress net.IP, macAddress net.HardwareAddr) *HNSEndpoint { - return &HNSEndpoint{ - VirtualNetwork: network.Id, - IPAddress: ipAddress, - MacAddress: string(macAddress), - } -} - -func (network *HNSNetwork) CreateEndpoint(endpoint *HNSEndpoint) (*HNSEndpoint, error) { - operation := "CreateEndpoint" - title := "HCSShim::HNSNetwork::" + operation - logrus.Debugf(title+" id=%s, endpointId=%s", network.Id, endpoint.Id) - - endpoint.VirtualNetwork = network.Id - return endpoint.Create() -} - -func (network *HNSNetwork) CreateRemoteEndpoint(endpoint *HNSEndpoint) (*HNSEndpoint, error) { - operation := "CreateRemoteEndpoint" - title := "HCSShim::HNSNetwork::" + operation - logrus.Debugf(title+" id=%s", network.Id) - endpoint.IsRemoteEndpoint = true - return network.CreateEndpoint(endpoint) -} +package hcsshim + +import ( + "encoding/json" + "net" + + "github.com/sirupsen/logrus" +) + +// Subnet is assoicated with a network and represents a list +// of subnets available to the network +type Subnet struct { + AddressPrefix string `json:",omitempty"` + GatewayAddress string `json:",omitempty"` + Policies []json.RawMessage `json:",omitempty"` +} + +// MacPool is assoicated with a network and represents a list +// of macaddresses available to the network +type MacPool struct { + StartMacAddress string `json:",omitempty"` + EndMacAddress string `json:",omitempty"` +} + +// HNSNetwork represents a network in HNS +type HNSNetwork struct { + Id string `json:"ID,omitempty"` + Name string `json:",omitempty"` + Type string `json:",omitempty"` + NetworkAdapterName string `json:",omitempty"` + SourceMac string `json:",omitempty"` + Policies []json.RawMessage `json:",omitempty"` + MacPools []MacPool `json:",omitempty"` + Subnets []Subnet `json:",omitempty"` + DNSSuffix string `json:",omitempty"` + DNSServerList string `json:",omitempty"` + DNSServerCompartment uint32 `json:",omitempty"` + ManagementIP string `json:",omitempty"` + AutomaticDNS bool `json:",omitempty"` +} + +type hnsNetworkResponse struct { + Success bool + Error string + Output HNSNetwork +} + +type hnsResponse struct { + Success bool + Error string + Output json.RawMessage +} + +// HNSNetworkRequest makes a call into HNS to update/query a single network +func HNSNetworkRequest(method, path, request string) (*HNSNetwork, error) { + var network HNSNetwork + err := hnsCall(method, "/networks/"+path, request, &network) + if err != nil { + return nil, err + } + + return &network, nil +} + +// HNSListNetworkRequest makes a HNS call to query the list of available networks +func HNSListNetworkRequest(method, path, request string) ([]HNSNetwork, error) { + var network []HNSNetwork + err := hnsCall(method, "/networks/"+path, request, &network) + if err != nil { + return nil, err + } + + return network, nil +} + +// GetHNSNetworkByID +func GetHNSNetworkByID(networkID string) (*HNSNetwork, error) { + return HNSNetworkRequest("GET", networkID, "") +} + +// GetHNSNetworkName filtered by Name +func GetHNSNetworkByName(networkName string) (*HNSNetwork, error) { + hsnnetworks, err := HNSListNetworkRequest("GET", "", "") + if err != nil { + return nil, err + } + for _, hnsnetwork := range hsnnetworks { + if hnsnetwork.Name == networkName { + return &hnsnetwork, nil + } + } + return nil, NetworkNotFoundError{NetworkName: networkName} +} + +// Create Network by sending NetworkRequest to HNS. +func (network *HNSNetwork) Create() (*HNSNetwork, error) { + operation := "Create" + title := "HCSShim::HNSNetwork::" + operation + logrus.Debugf(title+" id=%s", network.Id) + + jsonString, err := json.Marshal(network) + if err != nil { + return nil, err + } + return HNSNetworkRequest("POST", "", string(jsonString)) +} + +// Delete Network by sending NetworkRequest to HNS +func (network *HNSNetwork) Delete() (*HNSNetwork, error) { + operation := "Delete" + title := "HCSShim::HNSNetwork::" + operation + logrus.Debugf(title+" id=%s", network.Id) + + return HNSNetworkRequest("DELETE", network.Id, "") +} + +// Creates an endpoint on the Network. +func (network *HNSNetwork) NewEndpoint(ipAddress net.IP, macAddress net.HardwareAddr) *HNSEndpoint { + return &HNSEndpoint{ + VirtualNetwork: network.Id, + IPAddress: ipAddress, + MacAddress: string(macAddress), + } +} + +func (network *HNSNetwork) CreateEndpoint(endpoint *HNSEndpoint) (*HNSEndpoint, error) { + operation := "CreateEndpoint" + title := "HCSShim::HNSNetwork::" + operation + logrus.Debugf(title+" id=%s, endpointId=%s", network.Id, endpoint.Id) + + endpoint.VirtualNetwork = network.Id + return endpoint.Create() +} + +func (network *HNSNetwork) CreateRemoteEndpoint(endpoint *HNSEndpoint) (*HNSEndpoint, error) { + operation := "CreateRemoteEndpoint" + title := "HCSShim::HNSNetwork::" + operation + logrus.Debugf(title+" id=%s", network.Id) + endpoint.IsRemoteEndpoint = true + return network.CreateEndpoint(endpoint) +} diff --git a/vendor/github.com/Microsoft/hcsshim/hnspolicy.go b/vendor/github.com/Microsoft/hcsshim/hnspolicy.go index 65b8e93d9..bf860e938 100644 --- a/vendor/github.com/Microsoft/hcsshim/hnspolicy.go +++ b/vendor/github.com/Microsoft/hcsshim/hnspolicy.go @@ -1,94 +1,94 @@ -package hcsshim - -// Type of Request Support in ModifySystem -type PolicyType string - -// RequestType const -const ( - Nat PolicyType = "NAT" - ACL PolicyType = "ACL" - PA PolicyType = "PA" - VLAN PolicyType = "VLAN" - VSID PolicyType = "VSID" - VNet PolicyType = "VNET" - L2Driver PolicyType = "L2Driver" - Isolation PolicyType = "Isolation" - QOS PolicyType = "QOS" - OutboundNat PolicyType = "OutBoundNAT" - ExternalLoadBalancer PolicyType = "ELB" - Route PolicyType = "ROUTE" -) - -type NatPolicy struct { - Type PolicyType `json:"Type"` - Protocol string - InternalPort uint16 - ExternalPort uint16 -} - -type QosPolicy struct { - Type PolicyType `json:"Type"` - MaximumOutgoingBandwidthInBytes uint64 -} - -type IsolationPolicy struct { - Type PolicyType `json:"Type"` - VLAN uint - VSID uint - InDefaultIsolation bool -} - -type VlanPolicy struct { - Type PolicyType `json:"Type"` - VLAN uint -} - -type VsidPolicy struct { - Type PolicyType `json:"Type"` - VSID uint -} - -type PaPolicy struct { - Type PolicyType `json:"Type"` - PA string `json:"PA"` -} - -type OutboundNatPolicy struct { - Policy - VIP string `json:"VIP,omitempty"` - Exceptions []string `json:"ExceptionList,omitempty"` -} - -type ActionType string -type DirectionType string -type RuleType string - -const ( - Allow ActionType = "Allow" - Block ActionType = "Block" - - In DirectionType = "In" - Out DirectionType = "Out" - - Host RuleType = "Host" - Switch RuleType = "Switch" -) - -type ACLPolicy struct { - Type PolicyType `json:"Type"` - Protocol uint16 - InternalPort uint16 - Action ActionType - Direction DirectionType - LocalAddresses string - RemoteAddresses string - LocalPort uint16 - RemotePort uint16 - RuleType RuleType `json:"RuleType,omitempty"` - Priority uint16 - ServiceName string -} - -type Policy struct { - Type PolicyType `json:"Type"` -} +package hcsshim + +// Type of Request Support in ModifySystem +type PolicyType string + +// RequestType const +const ( + Nat PolicyType = "NAT" + ACL PolicyType = "ACL" + PA PolicyType = "PA" + VLAN PolicyType = "VLAN" + VSID PolicyType = "VSID" + VNet PolicyType = "VNET" + L2Driver PolicyType = "L2Driver" + Isolation PolicyType = "Isolation" + QOS PolicyType = "QOS" + OutboundNat PolicyType = "OutBoundNAT" + ExternalLoadBalancer PolicyType = "ELB" + Route PolicyType = "ROUTE" +) + +type NatPolicy struct { + Type PolicyType `json:"Type"` + Protocol string + InternalPort uint16 + ExternalPort uint16 +} + +type QosPolicy struct { + Type PolicyType `json:"Type"` + MaximumOutgoingBandwidthInBytes uint64 +} + +type IsolationPolicy struct { + Type PolicyType `json:"Type"` + VLAN uint + VSID uint + InDefaultIsolation bool +} + +type VlanPolicy struct { + Type PolicyType `json:"Type"` + VLAN uint +} + +type VsidPolicy struct { + Type PolicyType `json:"Type"` + VSID uint +} + +type PaPolicy struct { + Type PolicyType `json:"Type"` + PA string `json:"PA"` +} + +type OutboundNatPolicy struct { + Policy + VIP string `json:"VIP,omitempty"` + Exceptions []string `json:"ExceptionList,omitempty"` +} + +type ActionType string +type DirectionType string +type RuleType string + +const ( + Allow ActionType = "Allow" + Block ActionType = "Block" + + In DirectionType = "In" + Out DirectionType = "Out" + + Host RuleType = "Host" + Switch RuleType = "Switch" +) + +type ACLPolicy struct { + Type PolicyType `json:"Type"` + Protocol uint16 + InternalPort uint16 + Action ActionType + Direction DirectionType + LocalAddresses string + RemoteAddresses string + LocalPort uint16 + RemotePort uint16 + RuleType RuleType `json:"RuleType,omitempty"` + Priority uint16 + ServiceName string +} + +type Policy struct { + Type PolicyType `json:"Type"` +} diff --git a/vendor/github.com/Microsoft/hcsshim/hnspolicylist.go b/vendor/github.com/Microsoft/hcsshim/hnspolicylist.go index bbd7e1edb..ef1ccab16 100644 --- a/vendor/github.com/Microsoft/hcsshim/hnspolicylist.go +++ b/vendor/github.com/Microsoft/hcsshim/hnspolicylist.go @@ -1,200 +1,200 @@ -package hcsshim - -import ( - "encoding/json" - - "github.com/sirupsen/logrus" -) - -// RoutePolicy is a structure defining schema for Route based Policy -type RoutePolicy struct { - Policy - DestinationPrefix string `json:"DestinationPrefix,omitempty"` - NextHop string `json:"NextHop,omitempty"` - EncapEnabled bool `json:"NeedEncap,omitempty"` -} - -// ELBPolicy is a structure defining schema for ELB LoadBalancing based Policy -type ELBPolicy struct { - LBPolicy - SourceVIP string `json:"SourceVIP,omitempty"` - VIPs []string `json:"VIPs,omitempty"` - ILB bool `json:"ILB,omitempty"` -} - -// LBPolicy is a structure defining schema for LoadBalancing based Policy -type LBPolicy struct { - Policy - Protocol uint16 `json:"Protocol,omitempty"` - InternalPort uint16 - ExternalPort uint16 -} - -// PolicyList is a structure defining schema for Policy list request -type PolicyList struct { - ID string `json:"ID,omitempty"` - EndpointReferences []string `json:"References,omitempty"` - Policies []json.RawMessage `json:"Policies,omitempty"` -} - -// HNSPolicyListRequest makes a call into HNS to update/query a single network -func HNSPolicyListRequest(method, path, request string) (*PolicyList, error) { - var policy PolicyList - err := hnsCall(method, "/policylists/"+path, request, &policy) - if err != nil { - return nil, err - } - - return &policy, nil -} - -// HNSListPolicyListRequest gets all the policy list -func HNSListPolicyListRequest() ([]PolicyList, error) { - var plist []PolicyList - err := hnsCall("GET", "/policylists/", "", &plist) - if err != nil { - return nil, err - } - - return plist, nil -} - -// PolicyListRequest makes a HNS call to modify/query a network policy list -func PolicyListRequest(method, path, request string) (*PolicyList, error) { - policylist := &PolicyList{} - err := hnsCall(method, "/policylists/"+path, request, &policylist) - if err != nil { - return nil, err - } - - return policylist, nil -} - -// GetPolicyListByID get the policy list by ID -func GetPolicyListByID(policyListID string) (*PolicyList, error) { - return PolicyListRequest("GET", policyListID, "") -} - -// Create PolicyList by sending PolicyListRequest to HNS. -func (policylist *PolicyList) Create() (*PolicyList, error) { - operation := "Create" - title := "HCSShim::PolicyList::" + operation - logrus.Debugf(title+" id=%s", policylist.ID) - jsonString, err := json.Marshal(policylist) - if err != nil { - return nil, err - } - return PolicyListRequest("POST", "", string(jsonString)) -} - -// Delete deletes PolicyList -func (policylist *PolicyList) Delete() (*PolicyList, error) { - operation := "Delete" - title := "HCSShim::PolicyList::" + operation - logrus.Debugf(title+" id=%s", policylist.ID) - - return PolicyListRequest("DELETE", policylist.ID, "") -} - -// AddEndpoint add an endpoint to a Policy List -func (policylist *PolicyList) AddEndpoint(endpoint *HNSEndpoint) (*PolicyList, error) { - operation := "AddEndpoint" - title := "HCSShim::PolicyList::" + operation - logrus.Debugf(title+" id=%s, endpointId:%s", policylist.ID, endpoint.Id) - - _, err := policylist.Delete() - if err != nil { - return nil, err - } - - // Add Endpoint to the Existing List - policylist.EndpointReferences = append(policylist.EndpointReferences, "/endpoints/"+endpoint.Id) - - return policylist.Create() -} - -// RemoveEndpoint removes an endpoint from the Policy List -func (policylist *PolicyList) RemoveEndpoint(endpoint *HNSEndpoint) (*PolicyList, error) { - operation := "RemoveEndpoint" - title := "HCSShim::PolicyList::" + operation - logrus.Debugf(title+" id=%s, endpointId:%s", policylist.ID, endpoint.Id) - - _, err := policylist.Delete() - if err != nil { - return nil, err - } - - elementToRemove := "/endpoints/" + endpoint.Id - - var references []string - - for _, endpointReference := range policylist.EndpointReferences { - if endpointReference == elementToRemove { - continue - } - references = append(references, endpointReference) - } - policylist.EndpointReferences = references - return policylist.Create() -} - -// AddLoadBalancer policy list for the specified endpoints -func AddLoadBalancer(endpoints []HNSEndpoint, isILB bool, sourceVIP, vip string, protocol uint16, internalPort uint16, externalPort uint16) (*PolicyList, error) { - operation := "AddLoadBalancer" - 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) - - policylist := &PolicyList{} - - elbPolicy := &ELBPolicy{ - SourceVIP: sourceVIP, - ILB: isILB, - } - - if len(vip) > 0 { - elbPolicy.VIPs = []string{vip} - } - elbPolicy.Type = ExternalLoadBalancer - elbPolicy.Protocol = protocol - elbPolicy.InternalPort = internalPort - elbPolicy.ExternalPort = externalPort - - for _, endpoint := range endpoints { - policylist.EndpointReferences = append(policylist.EndpointReferences, "/endpoints/"+endpoint.Id) - } - - jsonString, err := json.Marshal(elbPolicy) - if err != nil { - return nil, err - } - policylist.Policies = append(policylist.Policies, jsonString) - return policylist.Create() -} - -// AddRoute adds route policy list for the specified endpoints -func AddRoute(endpoints []HNSEndpoint, destinationPrefix string, nextHop string, encapEnabled bool) (*PolicyList, error) { - operation := "AddRoute" - title := "HCSShim::PolicyList::" + operation - logrus.Debugf(title+" destinationPrefix:%s", destinationPrefix) - - policylist := &PolicyList{} - - rPolicy := &RoutePolicy{ - DestinationPrefix: destinationPrefix, - NextHop: nextHop, - EncapEnabled: encapEnabled, - } - rPolicy.Type = Route - - for _, endpoint := range endpoints { - policylist.EndpointReferences = append(policylist.EndpointReferences, "/endpoints/"+endpoint.Id) - } - - jsonString, err := json.Marshal(rPolicy) - if err != nil { - return nil, err - } - - policylist.Policies = append(policylist.Policies, jsonString) - return policylist.Create() -} +package hcsshim + +import ( + "encoding/json" + + "github.com/sirupsen/logrus" +) + +// RoutePolicy is a structure defining schema for Route based Policy +type RoutePolicy struct { + Policy + DestinationPrefix string `json:"DestinationPrefix,omitempty"` + NextHop string `json:"NextHop,omitempty"` + EncapEnabled bool `json:"NeedEncap,omitempty"` +} + +// ELBPolicy is a structure defining schema for ELB LoadBalancing based Policy +type ELBPolicy struct { + LBPolicy + SourceVIP string `json:"SourceVIP,omitempty"` + VIPs []string `json:"VIPs,omitempty"` + ILB bool `json:"ILB,omitempty"` +} + +// LBPolicy is a structure defining schema for LoadBalancing based Policy +type LBPolicy struct { + Policy + Protocol uint16 `json:"Protocol,omitempty"` + InternalPort uint16 + ExternalPort uint16 +} + +// PolicyList is a structure defining schema for Policy list request +type PolicyList struct { + ID string `json:"ID,omitempty"` + EndpointReferences []string `json:"References,omitempty"` + Policies []json.RawMessage `json:"Policies,omitempty"` +} + +// HNSPolicyListRequest makes a call into HNS to update/query a single network +func HNSPolicyListRequest(method, path, request string) (*PolicyList, error) { + var policy PolicyList + err := hnsCall(method, "/policylists/"+path, request, &policy) + if err != nil { + return nil, err + } + + return &policy, nil +} + +// HNSListPolicyListRequest gets all the policy list +func HNSListPolicyListRequest() ([]PolicyList, error) { + var plist []PolicyList + err := hnsCall("GET", "/policylists/", "", &plist) + if err != nil { + return nil, err + } + + return plist, nil +} + +// PolicyListRequest makes a HNS call to modify/query a network policy list +func PolicyListRequest(method, path, request string) (*PolicyList, error) { + policylist := &PolicyList{} + err := hnsCall(method, "/policylists/"+path, request, &policylist) + if err != nil { + return nil, err + } + + return policylist, nil +} + +// GetPolicyListByID get the policy list by ID +func GetPolicyListByID(policyListID string) (*PolicyList, error) { + return PolicyListRequest("GET", policyListID, "") +} + +// Create PolicyList by sending PolicyListRequest to HNS. +func (policylist *PolicyList) Create() (*PolicyList, error) { + operation := "Create" + title := "HCSShim::PolicyList::" + operation + logrus.Debugf(title+" id=%s", policylist.ID) + jsonString, err := json.Marshal(policylist) + if err != nil { + return nil, err + } + return PolicyListRequest("POST", "", string(jsonString)) +} + +// Delete deletes PolicyList +func (policylist *PolicyList) Delete() (*PolicyList, error) { + operation := "Delete" + title := "HCSShim::PolicyList::" + operation + logrus.Debugf(title+" id=%s", policylist.ID) + + return PolicyListRequest("DELETE", policylist.ID, "") +} + +// AddEndpoint add an endpoint to a Policy List +func (policylist *PolicyList) AddEndpoint(endpoint *HNSEndpoint) (*PolicyList, error) { + operation := "AddEndpoint" + title := "HCSShim::PolicyList::" + operation + logrus.Debugf(title+" id=%s, endpointId:%s", policylist.ID, endpoint.Id) + + _, err := policylist.Delete() + if err != nil { + return nil, err + } + + // Add Endpoint to the Existing List + policylist.EndpointReferences = append(policylist.EndpointReferences, "/endpoints/"+endpoint.Id) + + return policylist.Create() +} + +// RemoveEndpoint removes an endpoint from the Policy List +func (policylist *PolicyList) RemoveEndpoint(endpoint *HNSEndpoint) (*PolicyList, error) { + operation := "RemoveEndpoint" + title := "HCSShim::PolicyList::" + operation + logrus.Debugf(title+" id=%s, endpointId:%s", policylist.ID, endpoint.Id) + + _, err := policylist.Delete() + if err != nil { + return nil, err + } + + elementToRemove := "/endpoints/" + endpoint.Id + + var references []string + + for _, endpointReference := range policylist.EndpointReferences { + if endpointReference == elementToRemove { + continue + } + references = append(references, endpointReference) + } + policylist.EndpointReferences = references + return policylist.Create() +} + +// AddLoadBalancer policy list for the specified endpoints +func AddLoadBalancer(endpoints []HNSEndpoint, isILB bool, sourceVIP, vip string, protocol uint16, internalPort uint16, externalPort uint16) (*PolicyList, error) { + operation := "AddLoadBalancer" + 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) + + policylist := &PolicyList{} + + elbPolicy := &ELBPolicy{ + SourceVIP: sourceVIP, + ILB: isILB, + } + + if len(vip) > 0 { + elbPolicy.VIPs = []string{vip} + } + elbPolicy.Type = ExternalLoadBalancer + elbPolicy.Protocol = protocol + elbPolicy.InternalPort = internalPort + elbPolicy.ExternalPort = externalPort + + for _, endpoint := range endpoints { + policylist.EndpointReferences = append(policylist.EndpointReferences, "/endpoints/"+endpoint.Id) + } + + jsonString, err := json.Marshal(elbPolicy) + if err != nil { + return nil, err + } + policylist.Policies = append(policylist.Policies, jsonString) + return policylist.Create() +} + +// AddRoute adds route policy list for the specified endpoints +func AddRoute(endpoints []HNSEndpoint, destinationPrefix string, nextHop string, encapEnabled bool) (*PolicyList, error) { + operation := "AddRoute" + title := "HCSShim::PolicyList::" + operation + logrus.Debugf(title+" destinationPrefix:%s", destinationPrefix) + + policylist := &PolicyList{} + + rPolicy := &RoutePolicy{ + DestinationPrefix: destinationPrefix, + NextHop: nextHop, + EncapEnabled: encapEnabled, + } + rPolicy.Type = Route + + for _, endpoint := range endpoints { + policylist.EndpointReferences = append(policylist.EndpointReferences, "/endpoints/"+endpoint.Id) + } + + jsonString, err := json.Marshal(rPolicy) + if err != nil { + return nil, err + } + + policylist.Policies = append(policylist.Policies, jsonString) + return policylist.Create() +} diff --git a/vendor/github.com/Microsoft/hcsshim/importlayer.go b/vendor/github.com/Microsoft/hcsshim/importlayer.go index 3aed14376..2742b9f75 100644 --- a/vendor/github.com/Microsoft/hcsshim/importlayer.go +++ b/vendor/github.com/Microsoft/hcsshim/importlayer.go @@ -129,37 +129,39 @@ type legacyLayerWriterWrapper struct { } func (r *legacyLayerWriterWrapper) Close() error { - defer os.RemoveAll(r.root) + defer os.RemoveAll(r.root.Name()) + defer r.legacyLayerWriter.CloseRoots() err := r.legacyLayerWriter.Close() if err != nil { return err } - // Use the original path here because ImportLayer does not support long paths for the source in TP5. - // But do use a long path for the destination to work around another bug with directories - // with MAX_PATH - 12 < length < MAX_PATH. info := r.info - fullPath, err := makeLongAbsPath(filepath.Join(info.HomeDir, r.layerID)) - if err != nil { + info.HomeDir = "" + if err = ImportLayer(info, r.destRoot.Name(), r.path, r.parentLayerPaths); err != nil { return err } - - info.HomeDir = "" - if err = ImportLayer(info, fullPath, r.path, r.parentLayerPaths); err != nil { - return err + for _, name := range r.Tombstones { + if err = removeRelative(name, r.destRoot); err != nil && !os.IsNotExist(err) { + return err + } } // Add any hard links that were collected. for _, lnk := range r.PendingLinks { - if err = os.Remove(lnk.Path); err != nil && !os.IsNotExist(err) { + if err = removeRelative(lnk.Path, r.destRoot); err != nil && !os.IsNotExist(err) { return err } - if err = os.Link(lnk.Target, lnk.Path); err != nil { + if err = linkRelative(lnk.Target, lnk.TargetRoot, lnk.Path, r.destRoot); err != nil { return err } } // Prepare the utility VM for use if one is present in the layer. if r.HasUtilityVM { - err = ProcessUtilityVMImage(filepath.Join(fullPath, "UtilityVM")) + err := ensureNotReparsePointRelative("UtilityVM", r.destRoot) + if err != nil { + return err + } + err = ProcessUtilityVMImage(filepath.Join(r.destRoot.Name(), "UtilityVM")) if err != nil { return err } @@ -173,8 +175,12 @@ func (r *legacyLayerWriterWrapper) Close() error { func NewLayerWriter(info DriverInfo, layerID string, parentLayerPaths []string) (LayerWriter, error) { if len(parentLayerPaths) == 0 { // This is a base layer. It gets imported differently. + f, err := openRoot(filepath.Join(info.HomeDir, layerID)) + if err != nil { + return nil, err + } return &baseLayerWriter{ - root: filepath.Join(info.HomeDir, layerID), + root: f, }, nil } @@ -185,8 +191,12 @@ func NewLayerWriter(info DriverInfo, layerID string, parentLayerPaths []string) if err != nil { return nil, err } + w, err := newLegacyLayerWriter(path, parentLayerPaths, filepath.Join(info.HomeDir, layerID)) + if err != nil { + return nil, err + } return &legacyLayerWriterWrapper{ - legacyLayerWriter: newLegacyLayerWriter(path, parentLayerPaths, filepath.Join(info.HomeDir, layerID)), + legacyLayerWriter: w, info: info, layerID: layerID, path: path, diff --git a/vendor/github.com/Microsoft/hcsshim/legacy.go b/vendor/github.com/Microsoft/hcsshim/legacy.go index a0a97d7c7..5f009e517 100644 --- a/vendor/github.com/Microsoft/hcsshim/legacy.go +++ b/vendor/github.com/Microsoft/hcsshim/legacy.go @@ -121,6 +121,16 @@ func (r *legacyLayerReader) walkUntilCancelled() error { if err != nil { return err } + + // Indirect fix for https://github.com/moby/moby/issues/32838#issuecomment-343610048. + // Handle failure from what may be a golang bug in the conversion of + // UTF16 to UTF8 in files which are left in the recycle bin. Os.Lstat + // which is called by filepath.Walk will fail when a filename contains + // unicode characters. Skip the recycle bin regardless which is goodness. + if path == filepath.Join(r.root, `Files\$Recycle.Bin`) && info.IsDir() { + return filepath.SkipDir + } + if path == r.root || path == filepath.Join(r.root, "tombstones.txt") || strings.HasSuffix(path, ".$wcidirs$") { return nil } @@ -326,59 +336,79 @@ func (r *legacyLayerReader) Close() error { type pendingLink struct { Path, Target string + TargetRoot *os.File +} + +type pendingDir struct { + Path string + Root *os.File } type legacyLayerWriter struct { - root string - parentRoots []string - destRoot string - currentFile *os.File - backupWriter *winio.BackupFileWriter - tombstones []string - pathFixed bool - HasUtilityVM bool - uvmDi []dirInfo - addedFiles map[string]bool - PendingLinks []pendingLink + root *os.File + destRoot *os.File + parentRoots []*os.File + currentFile *os.File + currentFileName string + currentFileRoot *os.File + backupWriter *winio.BackupFileWriter + Tombstones []string + HasUtilityVM bool + uvmDi []dirInfo + addedFiles map[string]bool + PendingLinks []pendingLink + pendingDirs []pendingDir + currentIsDir bool } // newLegacyLayerWriter returns a LayerWriter that can write the contaler layer // transport format to disk. -func newLegacyLayerWriter(root string, parentRoots []string, destRoot string) *legacyLayerWriter { - return &legacyLayerWriter{ - root: root, - parentRoots: parentRoots, - destRoot: destRoot, - addedFiles: make(map[string]bool), +func newLegacyLayerWriter(root string, parentRoots []string, destRoot string) (w *legacyLayerWriter, err error) { + w = &legacyLayerWriter{ + addedFiles: make(map[string]bool), } + defer func() { + if err != nil { + w.CloseRoots() + w = nil + } + }() + w.root, err = openRoot(root) + if err != nil { + return + } + w.destRoot, err = openRoot(destRoot) + if err != nil { + return + } + for _, r := range parentRoots { + f, err := openRoot(r) + if err != nil { + return w, err + } + w.parentRoots = append(w.parentRoots, f) + } + return } -func (w *legacyLayerWriter) init() error { - if !w.pathFixed { - path, err := makeLongAbsPath(w.root) - if err != nil { - return err - } - for i, p := range w.parentRoots { - w.parentRoots[i], err = makeLongAbsPath(p) - if err != nil { - return err - } - } - destPath, err := makeLongAbsPath(w.destRoot) - if err != nil { - return err - } - w.root = path - w.destRoot = destPath - w.pathFixed = true +func (w *legacyLayerWriter) CloseRoots() { + if w.root != nil { + w.root.Close() + w.root = nil } - return nil + if w.destRoot != nil { + w.destRoot.Close() + w.destRoot = nil + } + for i := range w.parentRoots { + w.parentRoots[i].Close() + } + w.parentRoots = nil } func (w *legacyLayerWriter) initUtilityVM() error { if !w.HasUtilityVM { - err := os.Mkdir(filepath.Join(w.destRoot, utilityVMPath), 0) + err := mkdirRelative(utilityVMPath, w.destRoot) if err != nil { return err } @@ -386,7 +416,7 @@ func (w *legacyLayerWriter) initUtilityVM() error { // clone the utility VM from the parent layer into this layer. Use hard // links to avoid unnecessary copying, since most of the files are // immutable. - err = cloneTree(filepath.Join(w.parentRoots[0], utilityVMFilesPath), filepath.Join(w.destRoot, utilityVMFilesPath), mutatedUtilityVMFiles) + err = cloneTree(w.parentRoots[0], w.destRoot, utilityVMFilesPath, mutatedUtilityVMFiles) if err != nil { return fmt.Errorf("cloning the parent utility VM image failed: %s", err) } @@ -395,7 +425,40 @@ func (w *legacyLayerWriter) initUtilityVM() error { return nil } -func (w *legacyLayerWriter) reset() { +func (w *legacyLayerWriter) reset() error { + if w.currentIsDir { + r := w.currentFile + br := winio.NewBackupStreamReader(r) + // Seek to the beginning of the backup stream, skipping the fileattrs + if _, err := r.Seek(4, io.SeekStart); err != nil { + return err + } + + for { + bhdr, err := br.Next() + if err == io.EOF { + // end of backupstream data + break + } + if err != nil { + return err + } + switch bhdr.Id { + case winio.BackupReparseData: + // The current file is a `.$wcidirs$` metadata file that + // describes a directory reparse point. Delete the placeholder + // directory to prevent future files being added into the + // destination of the reparse point during the ImportLayer call + if err := removeRelative(w.currentFileName, w.currentFileRoot); err != nil { + return err + } + w.pendingDirs = append(w.pendingDirs, pendingDir{Path: w.currentFileName, Root: w.currentFileRoot}) + default: + // ignore all other stream types, as we only care about directory reparse points + } + } + w.currentIsDir = false + } if w.backupWriter != nil { w.backupWriter.Close() w.backupWriter = nil @@ -403,21 +466,21 @@ func (w *legacyLayerWriter) reset() { if w.currentFile != nil { w.currentFile.Close() w.currentFile = nil + w.currentFileName = "" + w.currentFileRoot = nil } + return nil } // copyFileWithMetadata copies a file using the backup/restore APIs in order to preserve metadata -func copyFileWithMetadata(srcPath, destPath string, isDir bool) (fileInfo *winio.FileBasicInfo, err error) { - createDisposition := uint32(syscall.CREATE_NEW) - if isDir { - err = os.Mkdir(destPath, 0) - if err != nil { - return nil, err - } - createDisposition = syscall.OPEN_EXISTING - } - - src, err := openFileOrDir(srcPath, syscall.GENERIC_READ|winio.ACCESS_SYSTEM_SECURITY, syscall.OPEN_EXISTING) +func copyFileWithMetadata(srcRoot, destRoot *os.File, subPath string, isDir bool) (fileInfo *winio.FileBasicInfo, err error) { + src, err := openRelative( + subPath, + srcRoot, + syscall.GENERIC_READ|winio.ACCESS_SYSTEM_SECURITY, + syscall.FILE_SHARE_READ, + _FILE_OPEN, + _FILE_OPEN_REPARSE_POINT) if err != nil { return nil, err } @@ -430,7 +493,17 @@ func copyFileWithMetadata(srcPath, destPath string, isDir bool) (fileInfo *winio return nil, err } - dest, err := openFileOrDir(destPath, syscall.GENERIC_READ|syscall.GENERIC_WRITE|winio.WRITE_DAC|winio.WRITE_OWNER|winio.ACCESS_SYSTEM_SECURITY, createDisposition) + extraFlags := uint32(0) + if isDir { + extraFlags |= _FILE_DIRECTORY_FILE + } + dest, err := openRelative( + subPath, + destRoot, + syscall.GENERIC_READ|syscall.GENERIC_WRITE|winio.WRITE_DAC|winio.WRITE_OWNER|winio.ACCESS_SYSTEM_SECURITY, + syscall.FILE_SHARE_READ, + _FILE_CREATE, + extraFlags) if err != nil { return nil, err } @@ -459,18 +532,21 @@ func copyFileWithMetadata(srcPath, destPath string, isDir bool) (fileInfo *winio // cloneTree clones a directory tree using hard links. It skips hard links for // the file names in the provided map and just copies those files. -func cloneTree(srcPath, destPath string, mutatedFiles map[string]bool) error { +func cloneTree(srcRoot *os.File, destRoot *os.File, subPath string, mutatedFiles map[string]bool) error { var di []dirInfo - err := filepath.Walk(srcPath, func(srcFilePath string, info os.FileInfo, err error) error { + err := ensureNotReparsePointRelative(subPath, srcRoot) + if err != nil { + return err + } + err = filepath.Walk(filepath.Join(srcRoot.Name(), subPath), func(srcFilePath string, info os.FileInfo, err error) error { if err != nil { return err } - relPath, err := filepath.Rel(srcPath, srcFilePath) + relPath, err := filepath.Rel(srcRoot.Name(), srcFilePath) if err != nil { return err } - destFilePath := filepath.Join(destPath, relPath) fileAttributes := info.Sys().(*syscall.Win32FileAttributeData).FileAttributes // Directories, reparse points, and files that will be mutated during @@ -482,15 +558,15 @@ func cloneTree(srcPath, destPath string, mutatedFiles map[string]bool) error { isDir := fileAttributes&syscall.FILE_ATTRIBUTE_DIRECTORY != 0 if isDir || isReparsePoint || mutatedFiles[relPath] { - fi, err := copyFileWithMetadata(srcFilePath, destFilePath, isDir) + fi, err := copyFileWithMetadata(srcRoot, destRoot, relPath, isDir) if err != nil { return err } if isDir && !isReparsePoint { - di = append(di, dirInfo{path: destFilePath, fileInfo: *fi}) + di = append(di, dirInfo{path: relPath, fileInfo: *fi}) } } else { - err = os.Link(srcFilePath, destFilePath) + err = linkRelative(relPath, srcRoot, relPath, destRoot) if err != nil { return err } @@ -508,13 +584,11 @@ func cloneTree(srcPath, destPath string, mutatedFiles map[string]bool) error { return err } - return reapplyDirectoryTimes(di) + return reapplyDirectoryTimes(destRoot, di) } func (w *legacyLayerWriter) Add(name string, fileInfo *winio.FileBasicInfo) error { - w.reset() - err := w.init() - if err != nil { + if err := w.reset(); err != nil { return err } @@ -522,6 +596,7 @@ func (w *legacyLayerWriter) Add(name string, fileInfo *winio.FileBasicInfo) erro return w.initUtilityVM() } + name = filepath.Clean(name) if hasPathPrefix(name, utilityVMPath) { if !w.HasUtilityVM { return errors.New("missing UtilityVM directory") @@ -529,10 +604,9 @@ func (w *legacyLayerWriter) Add(name string, fileInfo *winio.FileBasicInfo) erro if !hasPathPrefix(name, utilityVMFilesPath) && name != utilityVMFilesPath { return errors.New("invalid UtilityVM layer") } - path := filepath.Join(w.destRoot, name) - createDisposition := uint32(syscall.OPEN_EXISTING) + createDisposition := uint32(_FILE_OPEN) if (fileInfo.FileAttributes & syscall.FILE_ATTRIBUTE_DIRECTORY) != 0 { - st, err := os.Lstat(path) + st, err := lstatRelative(name, w.destRoot) if err != nil && !os.IsNotExist(err) { return err } @@ -540,37 +614,44 @@ func (w *legacyLayerWriter) Add(name string, fileInfo *winio.FileBasicInfo) erro // Delete the existing file/directory if it is not the same type as this directory. existingAttr := st.Sys().(*syscall.Win32FileAttributeData).FileAttributes if (uint32(fileInfo.FileAttributes)^existingAttr)&(syscall.FILE_ATTRIBUTE_DIRECTORY|syscall.FILE_ATTRIBUTE_REPARSE_POINT) != 0 { - if err = os.RemoveAll(path); err != nil { + if err = removeAllRelative(name, w.destRoot); err != nil { return err } st = nil } } if st == nil { - if err = os.Mkdir(path, 0); err != nil { + if err = mkdirRelative(name, w.destRoot); err != nil { return err } } if fileInfo.FileAttributes&syscall.FILE_ATTRIBUTE_REPARSE_POINT == 0 { - w.uvmDi = append(w.uvmDi, dirInfo{path: path, fileInfo: *fileInfo}) + w.uvmDi = append(w.uvmDi, dirInfo{path: name, fileInfo: *fileInfo}) } } else { // Overwrite any existing hard link. - err = os.Remove(path) + err := removeRelative(name, w.destRoot) if err != nil && !os.IsNotExist(err) { return err } - createDisposition = syscall.CREATE_NEW + createDisposition = _FILE_CREATE } - f, err := openFileOrDir(path, syscall.GENERIC_READ|syscall.GENERIC_WRITE|winio.WRITE_DAC|winio.WRITE_OWNER|winio.ACCESS_SYSTEM_SECURITY, createDisposition) + f, err := openRelative( + name, + w.destRoot, + syscall.GENERIC_READ|syscall.GENERIC_WRITE|winio.WRITE_DAC|winio.WRITE_OWNER|winio.ACCESS_SYSTEM_SECURITY, + syscall.FILE_SHARE_READ, + createDisposition, + _FILE_OPEN_REPARSE_POINT, + ) if err != nil { return err } defer func() { if f != nil { f.Close() - os.Remove(path) + removeRelative(name, w.destRoot) } }() @@ -581,28 +662,31 @@ func (w *legacyLayerWriter) Add(name string, fileInfo *winio.FileBasicInfo) erro w.backupWriter = winio.NewBackupFileWriter(f, true) w.currentFile = f + w.currentFileName = name + w.currentFileRoot = w.destRoot w.addedFiles[name] = true f = nil return nil } - path := filepath.Join(w.root, name) + fname := name if (fileInfo.FileAttributes & syscall.FILE_ATTRIBUTE_DIRECTORY) != 0 { - err := os.Mkdir(path, 0) + err := mkdirRelative(name, w.root) if err != nil { return err } - path += ".$wcidirs$" + fname += ".$wcidirs$" + w.currentIsDir = true } - f, err := openFileOrDir(path, syscall.GENERIC_READ|syscall.GENERIC_WRITE, syscall.CREATE_NEW) + f, err := openRelative(fname, w.root, syscall.GENERIC_READ|syscall.GENERIC_WRITE, syscall.FILE_SHARE_READ, _FILE_CREATE, 0) if err != nil { return err } defer func() { if f != nil { f.Close() - os.Remove(path) + removeRelative(fname, w.root) } }() @@ -624,19 +708,20 @@ func (w *legacyLayerWriter) Add(name string, fileInfo *winio.FileBasicInfo) erro } w.currentFile = f + w.currentFileName = name + w.currentFileRoot = w.root w.addedFiles[name] = true f = nil return nil } func (w *legacyLayerWriter) AddLink(name string, target string) error { - w.reset() - err := w.init() - if err != nil { + if err := w.reset(); err != nil { return err } - var roots []string + target = filepath.Clean(target) + var roots []*os.File if hasPathPrefix(target, filesPath) { // Look for cross-layer hard link targets in the parent layers, since // nothing is in the destination path yet. @@ -645,7 +730,7 @@ func (w *legacyLayerWriter) AddLink(name string, target string) error { // Since the utility VM is fully cloned into the destination path // already, look for cross-layer hard link targets directly in the // destination path. - roots = []string{w.destRoot} + roots = []*os.File{w.destRoot} } if roots == nil || (!hasPathPrefix(name, filesPath) && !hasPathPrefix(name, utilityVMFilesPath)) { @@ -654,12 +739,12 @@ func (w *legacyLayerWriter) AddLink(name string, target string) error { // Find to try the target of the link in a previously added file. If that // fails, search in parent layers. - var selectedRoot string + var selectedRoot *os.File if _, ok := w.addedFiles[target]; ok { selectedRoot = w.destRoot } else { for _, r := range roots { - if _, err = os.Lstat(filepath.Join(r, target)); err != nil { + if _, err := lstatRelative(target, r); err != nil { if !os.IsNotExist(err) { return err } @@ -668,22 +753,25 @@ func (w *legacyLayerWriter) AddLink(name string, target string) error { break } } - if selectedRoot == "" { + if selectedRoot == nil { return fmt.Errorf("failed to find link target for '%s' -> '%s'", name, target) } } + // The link can't be written until after the ImportLayer call. w.PendingLinks = append(w.PendingLinks, pendingLink{ - Path: filepath.Join(w.destRoot, name), - Target: filepath.Join(selectedRoot, target), + Path: name, + Target: target, + TargetRoot: selectedRoot, }) w.addedFiles[name] = true return nil } func (w *legacyLayerWriter) Remove(name string) error { + name = filepath.Clean(name) if hasPathPrefix(name, filesPath) { - w.tombstones = append(w.tombstones, name[len(filesPath)+1:]) + w.Tombstones = append(w.Tombstones, name) } else if hasPathPrefix(name, utilityVMFilesPath) { err := w.initUtilityVM() if err != nil { @@ -692,11 +780,10 @@ func (w *legacyLayerWriter) Remove(name string) error { // Make sure the path exists; os.RemoveAll will not fail if the file is // already gone, and this needs to be a fatal error for diagnostics // purposes. - path := filepath.Join(w.destRoot, name) - if _, err := os.Lstat(path); err != nil { + if _, err := lstatRelative(name, w.destRoot); err != nil { return err } - err = os.RemoveAll(path) + err = removeAllRelative(name, w.destRoot) if err != nil { return err } @@ -718,28 +805,20 @@ func (w *legacyLayerWriter) Write(b []byte) (int, error) { } func (w *legacyLayerWriter) Close() error { - w.reset() - err := w.init() - if err != nil { + if err := w.reset(); err != nil { return err } - tf, err := os.Create(filepath.Join(w.root, "tombstones.txt")) - if err != nil { + if err := removeRelative("tombstones.txt", w.root); err != nil && !os.IsNotExist(err) { return err } - defer tf.Close() - _, err = tf.Write([]byte("\xef\xbb\xbfVersion 1.0\n")) - if err != nil { - return err - } - for _, t := range w.tombstones { - _, err = tf.Write([]byte(filepath.Join(`\`, t) + "\n")) + for _, pd := range w.pendingDirs { + err := mkdirRelative(pd.Path, pd.Root) if err != nil { return err } } if w.HasUtilityVM { - err = reapplyDirectoryTimes(w.uvmDi) + err := reapplyDirectoryTimes(w.destRoot, w.uvmDi) if err != nil { return err } diff --git a/vendor/github.com/Microsoft/hcsshim/legacy18.go b/vendor/github.com/Microsoft/hcsshim/legacy18.go index 578552f91..0f593e8ab 100644 --- a/vendor/github.com/Microsoft/hcsshim/legacy18.go +++ b/vendor/github.com/Microsoft/hcsshim/legacy18.go @@ -1,7 +1,7 @@ -// +build !go1.9 - -package hcsshim - -// Due to a bug in go1.8 and before, directory reparse points need to be skipped -// during filepath.Walk. This is fixed in go1.9 -var shouldSkipDirectoryReparse = true +// +build !go1.9 + +package hcsshim + +// Due to a bug in go1.8 and before, directory reparse points need to be skipped +// during filepath.Walk. This is fixed in go1.9 +var shouldSkipDirectoryReparse = true diff --git a/vendor/github.com/Microsoft/hcsshim/legacy19.go b/vendor/github.com/Microsoft/hcsshim/legacy19.go index 6aa1dc058..fb0b7644f 100644 --- a/vendor/github.com/Microsoft/hcsshim/legacy19.go +++ b/vendor/github.com/Microsoft/hcsshim/legacy19.go @@ -1,7 +1,7 @@ -// +build go1.9 - -package hcsshim - -// Due to a bug in go1.8 and before, directory reparse points need to be skipped -// during filepath.Walk. This is fixed in go1.9 -var shouldSkipDirectoryReparse = false +// +build go1.9 + +package hcsshim + +// Due to a bug in go1.8 and before, directory reparse points need to be skipped +// during filepath.Walk. This is fixed in go1.9 +var shouldSkipDirectoryReparse = false diff --git a/vendor/github.com/Microsoft/hcsshim/safeopen.go b/vendor/github.com/Microsoft/hcsshim/safeopen.go new file mode 100644 index 000000000..5356456b9 --- /dev/null +++ b/vendor/github.com/Microsoft/hcsshim/safeopen.go @@ -0,0 +1,427 @@ +package hcsshim + +import ( + "errors" + "io" + "os" + "path/filepath" + "strings" + "syscall" + "unicode/utf16" + "unsafe" + + winio "github.com/Microsoft/go-winio" +) + +//sys ntCreateFile(handle *uintptr, accessMask uint32, oa *objectAttributes, iosb *ioStatusBlock, allocationSize *uint64, fileAttributes uint32, shareAccess uint32, createDisposition uint32, createOptions uint32, eaBuffer *byte, eaLength uint32) (status uint32) = ntdll.NtCreateFile +//sys ntSetInformationFile(handle uintptr, iosb *ioStatusBlock, information uintptr, length uint32, class uint32) (status uint32) = ntdll.NtSetInformationFile +//sys rtlNtStatusToDosError(status uint32) (winerr error) = ntdll.RtlNtStatusToDosErrorNoTeb +//sys localAlloc(flags uint32, size int) (ptr uintptr) = kernel32.LocalAlloc +//sys localFree(ptr uintptr) = kernel32.LocalFree + +type ioStatusBlock struct { + Status, Information uintptr +} + +type objectAttributes struct { + Length uintptr + RootDirectory uintptr + ObjectName uintptr + Attributes uintptr + SecurityDescriptor uintptr + SecurityQoS uintptr +} + +type unicodeString struct { + Length uint16 + MaximumLength uint16 + Buffer uintptr +} + +type fileLinkInformation struct { + ReplaceIfExists bool + RootDirectory uintptr + FileNameLength uint32 + FileName [1]uint16 +} + +type fileDispositionInformationEx struct { + Flags uintptr +} + +const ( + _FileLinkInformation = 11 + _FileDispositionInformationEx = 64 + + _FILE_READ_ATTRIBUTES = 0x0080 + _FILE_WRITE_ATTRIBUTES = 0x0100 + _DELETE = 0x10000 + + _FILE_OPEN = 1 + _FILE_CREATE = 2 + + _FILE_DIRECTORY_FILE = 0x00000001 + _FILE_SYNCHRONOUS_IO_NONALERT = 0x00000020 + _FILE_DELETE_ON_CLOSE = 0x00001000 + _FILE_OPEN_FOR_BACKUP_INTENT = 0x00004000 + _FILE_OPEN_REPARSE_POINT = 0x00200000 + + _FILE_DISPOSITION_DELETE = 0x00000001 + + _OBJ_DONT_REPARSE = 0x1000 + + _STATUS_REPARSE_POINT_ENCOUNTERED = 0xC000050B +) + +func openRoot(path string) (*os.File, error) { + longpath, err := makeLongAbsPath(path) + if err != nil { + return nil, err + } + return winio.OpenForBackup(longpath, syscall.GENERIC_READ, syscall.FILE_SHARE_READ|syscall.FILE_SHARE_WRITE|syscall.FILE_SHARE_DELETE, syscall.OPEN_EXISTING) +} + +func ntRelativePath(path string) ([]uint16, error) { + path = filepath.Clean(path) + if strings.Contains(":", path) { + // Since alternate data streams must follow the file they + // are attached to, finding one here (out of order) is invalid. + return nil, errors.New("path contains invalid character `:`") + } + fspath := filepath.FromSlash(path) + if len(fspath) > 0 && fspath[0] == '\\' { + return nil, errors.New("expected relative path") + } + + path16 := utf16.Encode(([]rune)(fspath)) + if len(path16) > 32767 { + return nil, syscall.ENAMETOOLONG + } + + return path16, nil +} + +// openRelativeInternal opens a relative path from the given root, failing if +// any of the intermediate path components are reparse points. +func openRelativeInternal(path string, root *os.File, accessMask uint32, shareFlags uint32, createDisposition uint32, flags uint32) (*os.File, error) { + var ( + h uintptr + iosb ioStatusBlock + oa objectAttributes + ) + + path16, err := ntRelativePath(path) + if err != nil { + return nil, err + } + + if root == nil || root.Fd() == 0 { + return nil, errors.New("missing root directory") + } + + upathBuffer := localAlloc(0, int(unsafe.Sizeof(unicodeString{}))+len(path16)*2) + defer localFree(upathBuffer) + + upath := (*unicodeString)(unsafe.Pointer(upathBuffer)) + upath.Length = uint16(len(path16) * 2) + upath.MaximumLength = upath.Length + upath.Buffer = upathBuffer + unsafe.Sizeof(*upath) + copy((*[32768]uint16)(unsafe.Pointer(upath.Buffer))[:], path16) + + oa.Length = unsafe.Sizeof(oa) + oa.ObjectName = upathBuffer + oa.RootDirectory = uintptr(root.Fd()) + oa.Attributes = _OBJ_DONT_REPARSE + status := ntCreateFile( + &h, + accessMask|syscall.SYNCHRONIZE, + &oa, + &iosb, + nil, + 0, + shareFlags, + createDisposition, + _FILE_OPEN_FOR_BACKUP_INTENT|_FILE_SYNCHRONOUS_IO_NONALERT|flags, + nil, + 0, + ) + if status != 0 { + return nil, rtlNtStatusToDosError(status) + } + + fullPath, err := makeLongAbsPath(filepath.Join(root.Name(), path)) + if err != nil { + syscall.Close(syscall.Handle(h)) + return nil, err + } + + return os.NewFile(h, fullPath), nil +} + +// openRelative opens a relative path from the given root, failing if +// any of the intermediate path components are reparse points. +func openRelative(path string, root *os.File, accessMask uint32, shareFlags uint32, createDisposition uint32, flags uint32) (*os.File, error) { + f, err := openRelativeInternal(path, root, accessMask, shareFlags, createDisposition, flags) + if err != nil { + err = &os.PathError{Op: "open", Path: filepath.Join(root.Name(), path), Err: err} + } + return f, err +} + +// linkRelative creates a hard link from oldname to newname (relative to oldroot +// and newroot), failing if any of the intermediate path components are reparse +// points. +func linkRelative(oldname string, oldroot *os.File, newname string, newroot *os.File) error { + // Open the old file. + oldf, err := openRelativeInternal( + oldname, + oldroot, + syscall.FILE_WRITE_ATTRIBUTES, + syscall.FILE_SHARE_READ|syscall.FILE_SHARE_WRITE|syscall.FILE_SHARE_DELETE, + _FILE_OPEN, + 0, + ) + if err != nil { + return &os.LinkError{Op: "link", Old: filepath.Join(oldroot.Name(), oldname), New: filepath.Join(newroot.Name(), newname), Err: err} + } + defer oldf.Close() + + // Open the parent of the new file. + var parent *os.File + parentPath := filepath.Dir(newname) + if parentPath != "." { + parent, err = openRelativeInternal( + parentPath, + newroot, + syscall.GENERIC_READ, + syscall.FILE_SHARE_READ|syscall.FILE_SHARE_WRITE|syscall.FILE_SHARE_DELETE, + _FILE_OPEN, + _FILE_DIRECTORY_FILE) + if err != nil { + return &os.LinkError{Op: "link", Old: oldf.Name(), New: filepath.Join(newroot.Name(), newname), Err: err} + } + defer parent.Close() + + fi, err := winio.GetFileBasicInfo(parent) + if err != nil { + return err + } + if (fi.FileAttributes & syscall.FILE_ATTRIBUTE_REPARSE_POINT) != 0 { + return &os.LinkError{Op: "link", Old: oldf.Name(), New: filepath.Join(newroot.Name(), newname), Err: rtlNtStatusToDosError(_STATUS_REPARSE_POINT_ENCOUNTERED)} + } + + } else { + parent = newroot + } + + // Issue an NT call to create the link. This will be safe because NT will + // not open any more directories to create the link, so it cannot walk any + // more reparse points. + newbase := filepath.Base(newname) + newbase16, err := ntRelativePath(newbase) + if err != nil { + return err + } + + size := int(unsafe.Offsetof(fileLinkInformation{}.FileName)) + len(newbase16)*2 + linkinfoBuffer := localAlloc(0, size) + defer localFree(linkinfoBuffer) + linkinfo := (*fileLinkInformation)(unsafe.Pointer(linkinfoBuffer)) + linkinfo.RootDirectory = parent.Fd() + linkinfo.FileNameLength = uint32(len(newbase16) * 2) + copy((*[32768]uint16)(unsafe.Pointer(&linkinfo.FileName[0]))[:], newbase16) + + var iosb ioStatusBlock + status := ntSetInformationFile( + oldf.Fd(), + &iosb, + linkinfoBuffer, + uint32(size), + _FileLinkInformation, + ) + if status != 0 { + return &os.LinkError{Op: "link", Old: oldf.Name(), New: filepath.Join(parent.Name(), newbase), Err: rtlNtStatusToDosError(status)} + } + + return nil +} + +// deleteOnClose marks a file to be deleted when the handle is closed. +func deleteOnClose(f *os.File) error { + disposition := fileDispositionInformationEx{Flags: _FILE_DISPOSITION_DELETE} + var iosb ioStatusBlock + status := ntSetInformationFile( + f.Fd(), + &iosb, + uintptr(unsafe.Pointer(&disposition)), + uint32(unsafe.Sizeof(disposition)), + _FileDispositionInformationEx, + ) + if status != 0 { + return rtlNtStatusToDosError(status) + } + return nil +} + +// clearReadOnly clears the readonly attribute on a file. +func clearReadOnly(f *os.File) error { + bi, err := winio.GetFileBasicInfo(f) + if err != nil { + return err + } + if bi.FileAttributes&syscall.FILE_ATTRIBUTE_READONLY == 0 { + return nil + } + sbi := winio.FileBasicInfo{ + FileAttributes: bi.FileAttributes &^ syscall.FILE_ATTRIBUTE_READONLY, + } + if sbi.FileAttributes == 0 { + sbi.FileAttributes = syscall.FILE_ATTRIBUTE_NORMAL + } + return winio.SetFileBasicInfo(f, &sbi) +} + +// removeRelative removes a file or directory relative to a root, failing if any +// intermediate path components are reparse points. +func removeRelative(path string, root *os.File) error { + f, err := openRelativeInternal( + path, + root, + _FILE_READ_ATTRIBUTES|_FILE_WRITE_ATTRIBUTES|_DELETE, + syscall.FILE_SHARE_READ|syscall.FILE_SHARE_WRITE|syscall.FILE_SHARE_DELETE, + _FILE_OPEN, + _FILE_OPEN_REPARSE_POINT) + if err == nil { + defer f.Close() + err = deleteOnClose(f) + if err == syscall.ERROR_ACCESS_DENIED { + // Maybe the file is marked readonly. Clear the bit and retry. + clearReadOnly(f) + err = deleteOnClose(f) + } + } + if err != nil { + return &os.PathError{Op: "remove", Path: filepath.Join(root.Name(), path), Err: err} + } + return nil +} + +// removeAllRelative removes a directory tree relative to a root, failing if any +// intermediate path components are reparse points. +func removeAllRelative(path string, root *os.File) error { + fi, err := lstatRelative(path, root) + if err != nil { + if os.IsNotExist(err) { + return nil + } + return err + } + fileAttributes := fi.Sys().(*syscall.Win32FileAttributeData).FileAttributes + if fileAttributes&syscall.FILE_ATTRIBUTE_DIRECTORY == 0 || fileAttributes&syscall.FILE_ATTRIBUTE_REPARSE_POINT != 0 { + // If this is a reparse point, it can't have children. Simple remove will do. + err := removeRelative(path, root) + if err == nil || os.IsNotExist(err) { + return nil + } + return err + } + + // It is necessary to use os.Open as Readdirnames does not work with + // openRelative. This is safe because the above lstatrelative fails + // if the target is outside the root, and we know this is not a + // symlink from the above FILE_ATTRIBUTE_REPARSE_POINT check. + fd, err := os.Open(filepath.Join(root.Name(), path)) + if err != nil { + if os.IsNotExist(err) { + // Race. It was deleted between the Lstat and Open. + // Return nil per RemoveAll's docs. + return nil + } + return err + } + + // Remove contents & return first error. + for { + names, err1 := fd.Readdirnames(100) + for _, name := range names { + err1 := removeAllRelative(path+string(os.PathSeparator)+name, root) + if err == nil { + err = err1 + } + } + if err1 == io.EOF { + break + } + // If Readdirnames returned an error, use it. + if err == nil { + err = err1 + } + if len(names) == 0 { + break + } + } + fd.Close() + + // Remove directory. + err1 := removeRelative(path, root) + if err1 == nil || os.IsNotExist(err1) { + return nil + } + if err == nil { + err = err1 + } + return err +} + +// mkdirRelative creates a directory relative to a root, failing if any +// intermediate path components are reparse points. +func mkdirRelative(path string, root *os.File) error { + f, err := openRelativeInternal( + path, + root, + 0, + syscall.FILE_SHARE_READ|syscall.FILE_SHARE_WRITE|syscall.FILE_SHARE_DELETE, + _FILE_CREATE, + _FILE_DIRECTORY_FILE) + if err == nil { + f.Close() + } else { + err = &os.PathError{Op: "mkdir", Path: filepath.Join(root.Name(), path), Err: err} + } + return err +} + +// lstatRelative performs a stat operation on a file relative to a root, failing +// if any intermediate path components are reparse points. +func lstatRelative(path string, root *os.File) (os.FileInfo, error) { + f, err := openRelativeInternal( + path, + root, + _FILE_READ_ATTRIBUTES, + syscall.FILE_SHARE_READ|syscall.FILE_SHARE_WRITE|syscall.FILE_SHARE_DELETE, + _FILE_OPEN, + _FILE_OPEN_REPARSE_POINT) + if err != nil { + return nil, &os.PathError{Op: "stat", Path: filepath.Join(root.Name(), path), Err: err} + } + defer f.Close() + return f.Stat() +} + +// ensureNotReparsePointRelative validates that a given file (relative to a +// root) and all intermediate path components are not a reparse points. +func ensureNotReparsePointRelative(path string, root *os.File) error { + // Perform an open with OBJ_DONT_REPARSE but without specifying FILE_OPEN_REPARSE_POINT. + f, err := openRelative( + path, + root, + 0, + syscall.FILE_SHARE_READ|syscall.FILE_SHARE_WRITE|syscall.FILE_SHARE_DELETE, + _FILE_OPEN, + 0) + if err != nil { + return err + } + f.Close() + return nil +} diff --git a/vendor/github.com/Microsoft/hcsshim/zhcsshim.go b/vendor/github.com/Microsoft/hcsshim/zhcsshim.go index 5d1a851ae..5123e8d8e 100644 --- a/vendor/github.com/Microsoft/hcsshim/zhcsshim.go +++ b/vendor/github.com/Microsoft/hcsshim/zhcsshim.go @@ -41,6 +41,8 @@ var ( modole32 = windows.NewLazySystemDLL("ole32.dll") modiphlpapi = windows.NewLazySystemDLL("iphlpapi.dll") modvmcompute = windows.NewLazySystemDLL("vmcompute.dll") + modntdll = windows.NewLazySystemDLL("ntdll.dll") + modkernel32 = windows.NewLazySystemDLL("kernel32.dll") procCoTaskMemFree = modole32.NewProc("CoTaskMemFree") procSetCurrentThreadCompartmentId = modiphlpapi.NewProc("SetCurrentThreadCompartmentId") @@ -94,6 +96,11 @@ var ( procHcsUnregisterProcessCallback = modvmcompute.NewProc("HcsUnregisterProcessCallback") procHcsModifyServiceSettings = modvmcompute.NewProc("HcsModifyServiceSettings") procHNSCall = modvmcompute.NewProc("HNSCall") + procNtCreateFile = modntdll.NewProc("NtCreateFile") + procNtSetInformationFile = modntdll.NewProc("NtSetInformationFile") + procRtlNtStatusToDosErrorNoTeb = modntdll.NewProc("RtlNtStatusToDosErrorNoTeb") + procLocalAlloc = modkernel32.NewProc("LocalAlloc") + procLocalFree = modkernel32.NewProc("LocalFree") ) func coTaskMemFree(buffer unsafe.Pointer) { @@ -1040,3 +1047,34 @@ func __hnsCall(method *uint16, path *uint16, object *uint16, response **uint16) } return } + +func ntCreateFile(handle *uintptr, accessMask uint32, oa *objectAttributes, iosb *ioStatusBlock, allocationSize *uint64, fileAttributes uint32, shareAccess uint32, createDisposition uint32, createOptions uint32, eaBuffer *byte, eaLength uint32) (status uint32) { + r0, _, _ := syscall.Syscall12(procNtCreateFile.Addr(), 11, uintptr(unsafe.Pointer(handle)), uintptr(accessMask), uintptr(unsafe.Pointer(oa)), uintptr(unsafe.Pointer(iosb)), uintptr(unsafe.Pointer(allocationSize)), uintptr(fileAttributes), uintptr(shareAccess), uintptr(createDisposition), uintptr(createOptions), uintptr(unsafe.Pointer(eaBuffer)), uintptr(eaLength), 0) + status = uint32(r0) + return +} + +func ntSetInformationFile(handle uintptr, iosb *ioStatusBlock, information uintptr, length uint32, class uint32) (status uint32) { + r0, _, _ := syscall.Syscall6(procNtSetInformationFile.Addr(), 5, uintptr(handle), uintptr(unsafe.Pointer(iosb)), uintptr(information), uintptr(length), uintptr(class), 0) + status = uint32(r0) + return +} + +func rtlNtStatusToDosError(status uint32) (winerr error) { + r0, _, _ := syscall.Syscall(procRtlNtStatusToDosErrorNoTeb.Addr(), 1, uintptr(status), 0, 0) + if r0 != 0 { + winerr = syscall.Errno(r0) + } + return +} + +func localAlloc(flags uint32, size int) (ptr uintptr) { + r0, _, _ := syscall.Syscall(procLocalAlloc.Addr(), 2, uintptr(flags), uintptr(size), 0) + ptr = uintptr(r0) + return +} + +func localFree(ptr uintptr) { + syscall.Syscall(procLocalFree.Addr(), 1, uintptr(ptr), 0, 0) + return +} diff --git a/vendor/github.com/containerd/containerd/README.md b/vendor/github.com/containerd/containerd/README.md index 7a2357fa9..2130d68cf 100644 --- a/vendor/github.com/containerd/containerd/README.md +++ b/vendor/github.com/containerd/containerd/README.md @@ -1,4 +1,4 @@ -![banner](/docs/images/containerd-dark.png?raw=true) +![banner](/docs/static/img/containerd-dark.png?raw=true) [![GoDoc](https://godoc.org/github.com/containerd/containerd?status.svg)](https://godoc.org/github.com/containerd/containerd) [![Build Status](https://travis-ci.org/containerd/containerd.svg?branch=master)](https://travis-ci.org/containerd/containerd) diff --git a/vendor/github.com/containerd/containerd/archive/tar.go b/vendor/github.com/containerd/containerd/archive/tar.go index f626bb453..7d7702bee 100644 --- a/vendor/github.com/containerd/containerd/archive/tar.go +++ b/vendor/github.com/containerd/containerd/archive/tar.go @@ -199,7 +199,7 @@ func applyNaive(ctx context.Context, root string, tr *tar.Reader, options ApplyO basename := filepath.Base(hdr.Name) aufsHardlinks[basename] = hdr if aufsTempdir == "" { - if aufsTempdir, err = ioutil.TempDir("", "dockerplnk"); err != nil { + if aufsTempdir, err = ioutil.TempDir(os.Getenv("XDG_RUNTIME_DIR"), "dockerplnk"); err != nil { return 0, err } defer os.RemoveAll(aufsTempdir) diff --git a/vendor/github.com/containerd/containerd/cio/io.go b/vendor/github.com/containerd/containerd/cio/io.go index a49c11735..2f9b5f103 100644 --- a/vendor/github.com/containerd/containerd/cio/io.go +++ b/vendor/github.com/containerd/containerd/cio/io.go @@ -21,6 +21,7 @@ import ( "fmt" "io" "os" + "path/filepath" "sync" "github.com/containerd/containerd/defaults" @@ -213,3 +214,44 @@ type DirectIO struct { } var _ IO = &DirectIO{} + +// LogFile creates a file on disk that logs the task's STDOUT,STDERR. +// If the log file already exists, the logs will be appended to the file. +func LogFile(path string) Creator { + return func(_ string) (IO, error) { + if err := os.MkdirAll(filepath.Dir(path), 0755); err != nil { + return nil, err + } + f, err := os.OpenFile(path, os.O_APPEND|os.O_CREATE|os.O_WRONLY, 0644) + if err != nil { + return nil, err + } + f.Close() + return &logIO{ + config: Config{ + Stdout: path, + Stderr: path, + }, + }, nil + } +} + +type logIO struct { + config Config +} + +func (l *logIO) Config() Config { + return l.config +} + +func (l *logIO) Cancel() { + +} + +func (l *logIO) Wait() { + +} + +func (l *logIO) Close() error { + return nil +} diff --git a/vendor/github.com/containerd/containerd/cio/io_unix.go b/vendor/github.com/containerd/containerd/cio/io_unix.go index 3ab2a30b0..8715c65c8 100644 --- a/vendor/github.com/containerd/containerd/cio/io_unix.go +++ b/vendor/github.com/containerd/containerd/cio/io_unix.go @@ -141,8 +141,18 @@ func openFifos(ctx context.Context, fifos *FIFOSet) (pipes, error) { // NewDirectIO returns an IO implementation that exposes the IO streams as io.ReadCloser // and io.WriteCloser. func NewDirectIO(ctx context.Context, fifos *FIFOSet) (*DirectIO, error) { + return newDirectIO(ctx, fifos, false) +} + +// NewDirectIOWithTerminal returns an IO implementation that exposes the streams with terminal enabled +func NewDirectIOWithTerminal(ctx context.Context, fifos *FIFOSet) (*DirectIO, error) { + return newDirectIO(ctx, fifos, true) +} + +func newDirectIO(ctx context.Context, fifos *FIFOSet, terminal bool) (*DirectIO, error) { ctx, cancel := context.WithCancel(ctx) pipes, err := openFifos(ctx, fifos) + fifos.Config.Terminal = terminal return &DirectIO{ pipes: pipes, cio: cio{ diff --git a/vendor/github.com/containerd/containerd/client.go b/vendor/github.com/containerd/containerd/client.go index c8e0b4a6b..3cf7ff3ee 100644 --- a/vendor/github.com/containerd/containerd/client.go +++ b/vendor/github.com/containerd/containerd/client.go @@ -19,7 +19,6 @@ package containerd import ( "context" "fmt" - "io" "net/http" "runtime" "strconv" @@ -339,38 +338,43 @@ func (c *Client) Pull(ctx context.Context, ref string, opts ...RemoteOpt) (Image } } - imgrec := images.Image{ - Name: name, - Target: desc, - Labels: pullCtx.Labels, + img := &image{ + client: c, + i: images.Image{ + Name: name, + Target: desc, + Labels: pullCtx.Labels, + }, + } + + if pullCtx.Unpack { + if err := img.Unpack(ctx, pullCtx.Snapshotter); err != nil { + return nil, errors.Wrapf(err, "failed to unpack image on snapshotter %s", pullCtx.Snapshotter) + } } is := c.ImageService() - if created, err := is.Create(ctx, imgrec); err != nil { - if !errdefs.IsAlreadyExists(err) { - return nil, err - } + for { + if created, err := is.Create(ctx, img.i); err != nil { + if !errdefs.IsAlreadyExists(err) { + return nil, err + } - updated, err := is.Update(ctx, imgrec) - if err != nil { - return nil, err - } + updated, err := is.Update(ctx, img.i) + if err != nil { + // if image was removed, try create again + if errdefs.IsNotFound(err) { + continue + } + return nil, err + } - imgrec = updated - } else { - imgrec = created - } - - img := &image{ - client: c, - i: imgrec, - } - if pullCtx.Unpack { - if err := img.Unpack(ctx, pullCtx.Snapshotter); err != nil { - errors.Wrapf(err, "failed to unpack image on snapshotter %s", pullCtx.Snapshotter) + img.i = updated + } else { + img.i = created } + return img, nil } - return img, nil } // Push uploads the provided content to a remote resource @@ -551,98 +555,3 @@ func (c *Client) Version(ctx context.Context) (Version, error) { Revision: response.Revision, }, nil } - -type importOpts struct { -} - -// ImportOpt allows the caller to specify import specific options -type ImportOpt func(c *importOpts) error - -func resolveImportOpt(opts ...ImportOpt) (importOpts, error) { - var iopts importOpts - for _, o := range opts { - if err := o(&iopts); err != nil { - return iopts, err - } - } - return iopts, nil -} - -// Import imports an image from a Tar stream using reader. -// Caller needs to specify importer. Future version may use oci.v1 as the default. -// Note that unreferrenced blobs may be imported to the content store as well. -func (c *Client) Import(ctx context.Context, importer images.Importer, reader io.Reader, opts ...ImportOpt) ([]Image, error) { - _, err := resolveImportOpt(opts...) // unused now - if err != nil { - return nil, err - } - - ctx, done, err := c.WithLease(ctx) - if err != nil { - return nil, err - } - defer done(ctx) - - imgrecs, err := importer.Import(ctx, c.ContentStore(), reader) - if err != nil { - // is.Update() is not called on error - return nil, err - } - - is := c.ImageService() - var images []Image - for _, imgrec := range imgrecs { - if updated, err := is.Update(ctx, imgrec, "target"); err != nil { - if !errdefs.IsNotFound(err) { - return nil, err - } - - created, err := is.Create(ctx, imgrec) - if err != nil { - return nil, err - } - - imgrec = created - } else { - imgrec = updated - } - - images = append(images, &image{ - client: c, - i: imgrec, - }) - } - return images, nil -} - -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. -// OCI format is used by default. -// 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. -func (c *Client) Export(ctx context.Context, exporter images.Exporter, desc ocispec.Descriptor, opts ...ExportOpt) (io.ReadCloser, error) { - _, err := resolveExportOpt(opts...) // unused now - if err != nil { - return nil, err - } - pr, pw := io.Pipe() - go func() { - pw.CloseWithError(exporter.Export(ctx, c.ContentStore(), desc, pw)) - }() - return pr, nil -} diff --git a/vendor/github.com/containerd/containerd/cmd/containerd/command/main.go b/vendor/github.com/containerd/containerd/cmd/containerd/command/main.go index 274135757..8fba0fa38 100644 --- a/vendor/github.com/containerd/containerd/cmd/containerd/command/main.go +++ b/vendor/github.com/containerd/containerd/cmd/containerd/command/main.go @@ -17,7 +17,7 @@ package command import ( - "context" + gocontext "context" "fmt" "io/ioutil" golog "log" @@ -35,7 +35,6 @@ import ( "github.com/pkg/errors" "github.com/sirupsen/logrus" "github.com/urfave/cli" - gocontext "golang.org/x/net/context" "google.golang.org/grpc/grpclog" ) @@ -168,7 +167,7 @@ func App() *cli.App { return app } -func serve(ctx context.Context, l net.Listener, serveFunc func(net.Listener) error) { +func serve(ctx gocontext.Context, l net.Listener, serveFunc func(net.Listener) error) { path := l.Addr().String() log.G(ctx).WithField("address", path).Info("serving...") go func() { diff --git a/vendor/github.com/containerd/containerd/cmd/ctr/commands/content/content.go b/vendor/github.com/containerd/containerd/cmd/ctr/commands/content/content.go index 6e4b26a14..a5cc90f3b 100644 --- a/vendor/github.com/containerd/containerd/cmd/ctr/commands/content/content.go +++ b/vendor/github.com/containerd/containerd/cmd/ctr/commands/content/content.go @@ -506,7 +506,7 @@ var ( ) func edit(rd io.Reader) (io.ReadCloser, error) { - tmp, err := ioutil.TempFile("", "edit-") + tmp, err := ioutil.TempFile(os.Getenv("XDG_RUNTIME_DIR"), "edit-") if err != nil { return nil, err } diff --git a/vendor/github.com/containerd/containerd/cmd/ctr/commands/content/fetch.go b/vendor/github.com/containerd/containerd/cmd/ctr/commands/content/fetch.go index 96933eb9a..01abb4cad 100644 --- a/vendor/github.com/containerd/containerd/cmd/ctr/commands/content/fetch.go +++ b/vendor/github.com/containerd/containerd/cmd/ctr/commands/content/fetch.go @@ -61,19 +61,19 @@ Most of this is experimental and there are few leaps to make this work.`, var ( ref = clicontext.Args().First() ) - _, err := Fetch(ref, clicontext) + client, ctx, cancel, err := commands.NewClient(clicontext) + if err != nil { + return err + } + defer cancel() + + _, err = Fetch(ctx, client, ref, clicontext) return err }, } // Fetch loads all resources into the content store and returns the image -func Fetch(ref string, cliContext *cli.Context) (containerd.Image, error) { - client, ctx, cancel, err := commands.NewClient(cliContext) - if err != nil { - return nil, err - } - defer cancel() - +func Fetch(ctx context.Context, client *containerd.Client, ref string, cliContext *cli.Context) (containerd.Image, error) { resolver, err := commands.GetResolver(ctx, cliContext) if err != nil { return nil, err diff --git a/vendor/github.com/containerd/containerd/cmd/ctr/commands/events/events.go b/vendor/github.com/containerd/containerd/cmd/ctr/commands/events/events.go index 083ee041f..507de4459 100644 --- a/vendor/github.com/containerd/containerd/cmd/ctr/commands/events/events.go +++ b/vendor/github.com/containerd/containerd/cmd/ctr/commands/events/events.go @@ -42,38 +42,36 @@ var Command = cli.Command{ defer cancel() eventsClient := client.EventService() eventsCh, errCh := eventsClient.Subscribe(ctx, context.Args()...) - for { + open := true + for open { var e *events.Envelope select { - case evt, closed := <-eventsCh: - if closed { - return nil - } - e = evt - case err := <-errCh: + case e = <-eventsCh: + case err, open = <-errCh: return err } - - var out []byte - if e.Event != nil { - v, err := typeurl.UnmarshalAny(e.Event) - if err != nil { + if e != nil { + var out []byte + if e.Event != nil { + v, err := typeurl.UnmarshalAny(e.Event) + if err != nil { + return err + } + out, err = json.Marshal(v) + if err != nil { + return err + } + } + if _, err := fmt.Println( + e.Timestamp, + e.Namespace, + e.Topic, + string(out), + ); err != nil { return err } - out, err = json.Marshal(v) - if err != nil { - return err - } - } - - if _, err := fmt.Println( - e.Timestamp, - e.Namespace, - e.Topic, - string(out), - ); err != nil { - return err } } + return nil }, } diff --git a/vendor/github.com/containerd/containerd/cmd/ctr/commands/images/pull.go b/vendor/github.com/containerd/containerd/cmd/ctr/commands/images/pull.go index 4ea72b6bf..10e4f1d52 100644 --- a/vendor/github.com/containerd/containerd/cmd/ctr/commands/images/pull.go +++ b/vendor/github.com/containerd/containerd/cmd/ctr/commands/images/pull.go @@ -57,10 +57,20 @@ command. As part of this process, we do the following: if ref == "" { return fmt.Errorf("please provide an image reference to pull") } - ctx, cancel := commands.AppContext(context) + + client, ctx, cancel, err := commands.NewClient(context) + if err != nil { + return err + } defer cancel() - img, err := content.Fetch(ref, context) + ctx, done, err := client.WithLease(ctx) + if err != nil { + return err + } + defer done(ctx) + + img, err := content.Fetch(ctx, client, ref, context) if err != nil { return err } diff --git a/vendor/github.com/containerd/containerd/cmd/ctr/commands/shim/shim.go b/vendor/github.com/containerd/containerd/cmd/ctr/commands/shim/shim.go index b40dd1db9..988299e03 100644 --- a/vendor/github.com/containerd/containerd/cmd/ctr/commands/shim/shim.go +++ b/vendor/github.com/containerd/containerd/cmd/ctr/commands/shim/shim.go @@ -19,12 +19,11 @@ package shim import ( + gocontext "context" "fmt" "io/ioutil" "net" - gocontext "context" - "github.com/containerd/console" "github.com/containerd/containerd/cmd/ctr/commands" shim "github.com/containerd/containerd/linux/shim/v1" diff --git a/vendor/github.com/containerd/containerd/cmd/ctr/commands/snapshots/snapshots.go b/vendor/github.com/containerd/containerd/cmd/ctr/commands/snapshots/snapshots.go index 9fd79f264..da4ab95d8 100644 --- a/vendor/github.com/containerd/containerd/cmd/ctr/commands/snapshots/snapshots.go +++ b/vendor/github.com/containerd/containerd/cmd/ctr/commands/snapshots/snapshots.go @@ -304,7 +304,11 @@ var prepareCommand = cli.Command{ defer cancel() snapshotter := client.SnapshotService(context.GlobalString("snapshotter")) - mounts, err := snapshotter.Prepare(ctx, key, parent) + labels := map[string]string{ + "containerd.io/gc.root": time.Now().UTC().Format(time.RFC3339), + } + + mounts, err := snapshotter.Prepare(ctx, key, parent, snapshots.WithLabels(labels)) if err != nil { return err } @@ -404,7 +408,10 @@ var commitCommand = cli.Command{ } defer cancel() snapshotter := client.SnapshotService(context.GlobalString("snapshotter")) - return snapshotter.Commit(ctx, key, active) + labels := map[string]string{ + "containerd.io/gc.root": time.Now().UTC().Format(time.RFC3339), + } + return snapshotter.Commit(ctx, key, active, snapshots.WithLabels(labels)) }, } diff --git a/vendor/github.com/containerd/containerd/cmd/ctr/commands/tasks/list.go b/vendor/github.com/containerd/containerd/cmd/ctr/commands/tasks/list.go index 80732b216..edffbb13d 100644 --- a/vendor/github.com/containerd/containerd/cmd/ctr/commands/tasks/list.go +++ b/vendor/github.com/containerd/containerd/cmd/ctr/commands/tasks/list.go @@ -34,7 +34,7 @@ var listCommand = cli.Command{ Flags: []cli.Flag{ cli.BoolFlag{ Name: "quiet, q", - Usage: "print only the task id & pid", + Usage: "print only the task id", }, }, Action: func(context *cli.Context) error { diff --git a/vendor/github.com/containerd/containerd/cmd/ctr/commands/tasks/tasks_unix.go b/vendor/github.com/containerd/containerd/cmd/ctr/commands/tasks/tasks_unix.go index ef563eec8..f7b111410 100644 --- a/vendor/github.com/containerd/containerd/cmd/ctr/commands/tasks/tasks_unix.go +++ b/vendor/github.com/containerd/containerd/cmd/ctr/commands/tasks/tasks_unix.go @@ -69,25 +69,24 @@ func HandleConsoleResize(ctx gocontext.Context, task resizer, con console.Consol // NewTask creates a new task func NewTask(ctx gocontext.Context, client *containerd.Client, container containerd.Container, checkpoint string, tty, nullIO bool, ioOpts []cio.Opt, opts ...containerd.NewTaskOpts) (containerd.Task, error) { stdio := cio.NewCreator(append([]cio.Opt{cio.WithStdio}, ioOpts...)...) - if checkpoint == "" { - ioCreator := stdio + if checkpoint != "" { + im, err := client.GetImage(ctx, checkpoint) + if err != nil { + return nil, err + } + opts = append(opts, containerd.WithTaskCheckpoint(im)) + } + ioCreator := stdio + if tty { + ioCreator = cio.NewCreator(append([]cio.Opt{cio.WithStdio, cio.WithTerminal}, ioOpts...)...) + } + if nullIO { if tty { - ioCreator = cio.NewCreator(append([]cio.Opt{cio.WithStdio, cio.WithTerminal}, ioOpts...)...) + return nil, errors.New("tty and null-io cannot be used together") } - if nullIO { - if tty { - return nil, errors.New("tty and null-io cannot be used together") - } - ioCreator = cio.NullIO - } - return container.NewTask(ctx, ioCreator, opts...) + ioCreator = cio.NullIO } - im, err := client.GetImage(ctx, checkpoint) - if err != nil { - return nil, err - } - opts = append(opts, containerd.WithTaskCheckpoint(im)) - return container.NewTask(ctx, stdio, opts...) + return container.NewTask(ctx, ioCreator, opts...) } func getNewTaskOpts(context *cli.Context) []containerd.NewTaskOpts { diff --git a/vendor/github.com/containerd/containerd/container.go b/vendor/github.com/containerd/containerd/container.go index 895e793ae..001b16c74 100644 --- a/vendor/github.com/containerd/containerd/container.go +++ b/vendor/github.com/containerd/containerd/container.go @@ -28,9 +28,9 @@ import ( "github.com/containerd/containerd/cio" "github.com/containerd/containerd/containers" "github.com/containerd/containerd/errdefs" + "github.com/containerd/containerd/oci" "github.com/containerd/typeurl" prototypes "github.com/gogo/protobuf/types" - specs "github.com/opencontainers/runtime-spec/specs-go" "github.com/pkg/errors" ) @@ -45,7 +45,7 @@ type Container interface { // NewTask creates a new task based on the container metadata NewTask(context.Context, cio.Creator, ...NewTaskOpts) (Task, error) // Spec returns the OCI runtime specification - Spec(context.Context) (*specs.Spec, error) + Spec(context.Context) (*oci.Spec, error) // Task returns the current task for the container // // If cio.Attach options are passed the client will reattach to the IO for the running @@ -126,12 +126,12 @@ func (c *container) SetLabels(ctx context.Context, labels map[string]string) (ma } // Spec returns the current OCI specification for the container -func (c *container) Spec(ctx context.Context) (*specs.Spec, error) { +func (c *container) Spec(ctx context.Context) (*oci.Spec, error) { r, err := c.get(ctx) if err != nil { return nil, err } - var s specs.Spec + var s oci.Spec if err := json.Unmarshal(r.Spec.Value, &s); err != nil { return nil, err } diff --git a/vendor/github.com/containerd/containerd/container_opts.go b/vendor/github.com/containerd/containerd/container_opts.go index 4f586a4ec..df12cafd5 100644 --- a/vendor/github.com/containerd/containerd/container_opts.go +++ b/vendor/github.com/containerd/containerd/container_opts.go @@ -26,7 +26,6 @@ import ( "github.com/containerd/typeurl" "github.com/gogo/protobuf/types" "github.com/opencontainers/image-spec/identity" - specs "github.com/opencontainers/runtime-spec/specs-go" "github.com/pkg/errors" ) @@ -196,7 +195,7 @@ func WithNewSpec(opts ...oci.SpecOpts) NewContainerOpts { } // WithSpec sets the provided spec on the container -func WithSpec(s *specs.Spec, opts ...oci.SpecOpts) NewContainerOpts { +func WithSpec(s *oci.Spec, opts ...oci.SpecOpts) NewContainerOpts { return func(ctx context.Context, client *Client, c *containers.Container) error { for _, o := range opts { if err := o(ctx, client, c, s); err != nil { diff --git a/vendor/github.com/containerd/containerd/contrib/apparmor/apparmor.go b/vendor/github.com/containerd/containerd/contrib/apparmor/apparmor.go index 5bb108640..5ebfee2af 100644 --- a/vendor/github.com/containerd/containerd/contrib/apparmor/apparmor.go +++ b/vendor/github.com/containerd/containerd/contrib/apparmor/apparmor.go @@ -53,7 +53,7 @@ func WithDefaultProfile(name string) oci.SpecOpts { if err != nil { return err } - f, err := ioutil.TempFile("", p.Name) + f, err := ioutil.TempFile(os.Getenv("XDG_RUNTIME_DIR"), p.Name) if err != nil { return err } diff --git a/vendor/github.com/containerd/containerd/grpc.go b/vendor/github.com/containerd/containerd/grpc.go index 05fd5cca2..c3506d735 100644 --- a/vendor/github.com/containerd/containerd/grpc.go +++ b/vendor/github.com/containerd/containerd/grpc.go @@ -17,8 +17,9 @@ package containerd import ( + "context" + "github.com/containerd/containerd/namespaces" - "golang.org/x/net/context" "google.golang.org/grpc" ) diff --git a/vendor/github.com/containerd/containerd/import.go b/vendor/github.com/containerd/containerd/import.go new file mode 100644 index 000000000..3148d240b --- /dev/null +++ b/vendor/github.com/containerd/containerd/import.go @@ -0,0 +1,121 @@ +/* + 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 containerd + +import ( + "context" + "io" + + "github.com/containerd/containerd/errdefs" + "github.com/containerd/containerd/images" + ocispec "github.com/opencontainers/image-spec/specs-go/v1" +) + +type importOpts struct { +} + +// ImportOpt allows the caller to specify import specific options +type ImportOpt func(c *importOpts) error + +func resolveImportOpt(opts ...ImportOpt) (importOpts, error) { + var iopts importOpts + for _, o := range opts { + if err := o(&iopts); err != nil { + return iopts, err + } + } + return iopts, nil +} + +// Import imports an image from a Tar stream using reader. +// Caller needs to specify importer. Future version may use oci.v1 as the default. +// Note that unreferrenced blobs may be imported to the content store as well. +func (c *Client) Import(ctx context.Context, importer images.Importer, reader io.Reader, opts ...ImportOpt) ([]Image, error) { + _, err := resolveImportOpt(opts...) // unused now + if err != nil { + return nil, err + } + + ctx, done, err := c.WithLease(ctx) + if err != nil { + return nil, err + } + defer done(ctx) + + imgrecs, err := importer.Import(ctx, c.ContentStore(), reader) + if err != nil { + // is.Update() is not called on error + return nil, err + } + + is := c.ImageService() + var images []Image + for _, imgrec := range imgrecs { + if updated, err := is.Update(ctx, imgrec, "target"); err != nil { + if !errdefs.IsNotFound(err) { + return nil, err + } + + created, err := is.Create(ctx, imgrec) + if err != nil { + return nil, err + } + + imgrec = created + } else { + imgrec = updated + } + + images = append(images, &image{ + client: c, + i: imgrec, + }) + } + return images, nil +} + +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. +// OCI format is used by default. +// 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. +func (c *Client) Export(ctx context.Context, exporter images.Exporter, desc ocispec.Descriptor, opts ...ExportOpt) (io.ReadCloser, error) { + _, err := resolveExportOpt(opts...) // unused now + if err != nil { + return nil, err + } + pr, pw := io.Pipe() + go func() { + pw.CloseWithError(exporter.Export(ctx, c.ContentStore(), desc, pw)) + }() + return pr, nil +} diff --git a/vendor/github.com/containerd/containerd/leases/grpc.go b/vendor/github.com/containerd/containerd/leases/grpc.go index 284924e7d..22f287a8b 100644 --- a/vendor/github.com/containerd/containerd/leases/grpc.go +++ b/vendor/github.com/containerd/containerd/leases/grpc.go @@ -17,7 +17,8 @@ package leases import ( - "golang.org/x/net/context" + "context" + "google.golang.org/grpc/metadata" ) diff --git a/vendor/github.com/containerd/containerd/linux/proc/init_state.go b/vendor/github.com/containerd/containerd/linux/proc/init_state.go index 8944d6192..0cbdc7ac1 100644 --- a/vendor/github.com/containerd/containerd/linux/proc/init_state.go +++ b/vendor/github.com/containerd/containerd/linux/proc/init_state.go @@ -194,10 +194,23 @@ func (s *createdCheckpointState) Start(ctx context.Context) error { s.p.mu.Lock() defer s.p.mu.Unlock() p := s.p + sio := p.stdio + + var ( + err error + socket *runc.Socket + ) + if sio.Terminal { + if socket, err = runc.NewTempConsoleSocket(); err != nil { + return errors.Wrap(err, "failed to create OCI runtime console socket") + } + defer socket.Close() + s.opts.ConsoleSocket = socket + } + if _, err := s.p.runtime.Restore(ctx, p.id, p.bundle, s.opts); err != nil { return p.runtimeError(err, "OCI runtime restore failed") } - sio := p.stdio if sio.Stdin != "" { sc, err := fifo.OpenFifo(ctx, sio.Stdin, syscall.O_WRONLY|syscall.O_NONBLOCK, 0) if err != nil { @@ -207,7 +220,17 @@ func (s *createdCheckpointState) Start(ctx context.Context) error { p.closers = append(p.closers, sc) } var copyWaitGroup sync.WaitGroup - if !sio.IsNull() { + if socket != nil { + console, err := socket.ReceiveMaster() + if err != nil { + return errors.Wrap(err, "failed to retrieve console master") + } + console, err = p.platform.CopyConsole(ctx, console, sio.Stdin, sio.Stdout, sio.Stderr, &p.wg, ©WaitGroup) + if err != nil { + return errors.Wrap(err, "failed to start console copy") + } + p.console = console + } else if !sio.IsNull() { if err := copyPipes(ctx, p.io, sio.Stdin, sio.Stdout, sio.Stderr, &p.wg, ©WaitGroup); err != nil { return errors.Wrap(err, "failed to start io pipe copy") } @@ -219,7 +242,6 @@ func (s *createdCheckpointState) Start(ctx context.Context) error { return errors.Wrap(err, "failed to retrieve OCI runtime container pid") } p.pid = pid - return s.transition("running") } diff --git a/vendor/github.com/containerd/containerd/linux/runtime.go b/vendor/github.com/containerd/containerd/linux/runtime.go index 6cc673173..26dedbfa9 100644 --- a/vendor/github.com/containerd/containerd/linux/runtime.go +++ b/vendor/github.com/containerd/containerd/linux/runtime.go @@ -79,7 +79,7 @@ func init() { }) } -var _ = (runtime.Runtime)(&Runtime{}) +var _ = (runtime.PlatformRuntime)(&Runtime{}) // Config options for the runtime type Config struct { @@ -510,6 +510,7 @@ func (r *Runtime) getRuntime(ctx context.Context, ns, id string) (*runc.Runc, er LogFormat: runc.JSON, PdeathSignal: unix.SIGKILL, Root: filepath.Join(root, ns), + Debug: r.config.ShimDebug, }, nil } diff --git a/vendor/github.com/containerd/containerd/reaper/reaper.go b/vendor/github.com/containerd/containerd/linux/shim/reaper.go similarity index 99% rename from vendor/github.com/containerd/containerd/reaper/reaper.go rename to vendor/github.com/containerd/containerd/linux/shim/reaper.go index bdcb14c26..2937f1a9e 100644 --- a/vendor/github.com/containerd/containerd/reaper/reaper.go +++ b/vendor/github.com/containerd/containerd/linux/shim/reaper.go @@ -16,7 +16,7 @@ limitations under the License. */ -package reaper +package shim import ( "os/exec" diff --git a/vendor/github.com/containerd/containerd/linux/shim/service.go b/vendor/github.com/containerd/containerd/linux/shim/service.go index 49d847e87..02ac59ef5 100644 --- a/vendor/github.com/containerd/containerd/linux/shim/service.go +++ b/vendor/github.com/containerd/containerd/linux/shim/service.go @@ -34,7 +34,6 @@ import ( shimapi "github.com/containerd/containerd/linux/shim/v1" "github.com/containerd/containerd/log" "github.com/containerd/containerd/namespaces" - "github.com/containerd/containerd/reaper" "github.com/containerd/containerd/runtime" runc "github.com/containerd/go-runc" "github.com/containerd/typeurl" @@ -81,7 +80,7 @@ func NewService(config Config, publisher events.Publisher) (*Service, error) { context: ctx, processes: make(map[string]proc.Process), events: make(chan interface{}, 128), - ec: reaper.Default.Subscribe(), + ec: Default.Subscribe(), } go s.processExits() if err := s.initPlatform(); err != nil { diff --git a/vendor/github.com/containerd/containerd/metadata/buckets.go b/vendor/github.com/containerd/containerd/metadata/buckets.go index 873626f2b..a82c32fd0 100644 --- a/vendor/github.com/containerd/containerd/metadata/buckets.go +++ b/vendor/github.com/containerd/containerd/metadata/buckets.go @@ -135,11 +135,7 @@ func getImagesBucket(tx *bolt.Tx, namespace string) *bolt.Bucket { } func createContainersBucket(tx *bolt.Tx, namespace string) (*bolt.Bucket, error) { - bkt, err := createBucketIfNotExists(tx, bucketKeyVersion, []byte(namespace), bucketKeyObjectContainers) - if err != nil { - return nil, err - } - return bkt, nil + return createBucketIfNotExists(tx, bucketKeyVersion, []byte(namespace), bucketKeyObjectContainers) } func getContainersBucket(tx *bolt.Tx, namespace string) *bolt.Bucket { diff --git a/vendor/github.com/containerd/containerd/metrics/cgroups/cgroups.go b/vendor/github.com/containerd/containerd/metrics/cgroups/cgroups.go index 9fbfa756c..86a2b8e8d 100644 --- a/vendor/github.com/containerd/containerd/metrics/cgroups/cgroups.go +++ b/vendor/github.com/containerd/containerd/metrics/cgroups/cgroups.go @@ -19,6 +19,8 @@ package cgroups import ( + "context" + "github.com/containerd/cgroups" eventstypes "github.com/containerd/containerd/api/events" "github.com/containerd/containerd/events" @@ -30,7 +32,6 @@ import ( "github.com/containerd/containerd/runtime" metrics "github.com/docker/go-metrics" "github.com/sirupsen/logrus" - "golang.org/x/net/context" ) // Config for the cgroups monitor diff --git a/vendor/github.com/containerd/containerd/mount/mountinfo_linux.go b/vendor/github.com/containerd/containerd/mount/mountinfo_linux.go index 9c442c8ed..a986f8f4e 100644 --- a/vendor/github.com/containerd/containerd/mount/mountinfo_linux.go +++ b/vendor/github.com/containerd/containerd/mount/mountinfo_linux.go @@ -23,27 +23,10 @@ import ( "fmt" "io" "os" + "strconv" "strings" ) -const ( - /* 36 35 98:0 /mnt1 /mnt2 rw,noatime master:1 - ext3 /dev/root rw,errors=continue - (1)(2)(3) (4) (5) (6) (7) (8) (9) (10) (11) - - (1) mount ID: unique identifier of the mount (may be reused after umount) - (2) parent ID: ID of parent (or of self for the top of the mount tree) - (3) major:minor: value of st_dev for files on filesystem - (4) root: root of the mount within the filesystem - (5) mount point: mount point relative to the process's root - (6) mount options: per mount options - (7) optional fields: zero or more fields of the form "tag[:value]" - (8) separator: marks the end of the optional fields - (9) filesystem type: name of filesystem of the form "type[.subtype]" - (10) mount source: filesystem specific information or "none" - (11) super options: per super block options*/ - mountinfoFormat = "%d %d %d:%d %s %s %s %s" -) - // Self retrieves a list of mounts for the current running process. func Self() ([]Info, error) { f, err := os.Open("/proc/self/mountinfo") @@ -56,41 +39,83 @@ func Self() ([]Info, error) { } func parseInfoFile(r io.Reader) ([]Info, error) { - var ( - s = bufio.NewScanner(r) - out = []Info{} - ) + s := bufio.NewScanner(r) + out := []Info{} for s.Scan() { if err := s.Err(); err != nil { return nil, err } - var ( - p = Info{} - text = s.Text() - optionalFields string - ) + /* + 36 35 98:0 /mnt1 /mnt2 rw,noatime master:1 - ext3 /dev/root rw,errors=continue + (1)(2)(3) (4) (5) (6) (7) (8) (9) (10) (11) + (1) mount ID: unique identifier of the mount (may be reused after umount) + (2) parent ID: ID of parent (or of self for the top of the mount tree) + (3) major:minor: value of st_dev for files on filesystem + (4) root: root of the mount within the filesystem + (5) mount point: mount point relative to the process's root + (6) mount options: per mount options + (7) optional fields: zero or more fields of the form "tag[:value]" + (8) separator: marks the end of the optional fields + (9) filesystem type: name of filesystem of the form "type[.subtype]" + (10) mount source: filesystem specific information or "none" + (11) super options: per super block options + */ - if _, err := fmt.Sscanf(text, mountinfoFormat, - &p.ID, &p.Parent, &p.Major, &p.Minor, - &p.Root, &p.Mountpoint, &p.Options, &optionalFields); err != nil { - return nil, fmt.Errorf("Scanning '%s' failed: %s", text, err) + text := s.Text() + fields := strings.Split(text, " ") + numFields := len(fields) + if numFields < 10 { + // should be at least 10 fields + return nil, fmt.Errorf("Parsing '%s' failed: not enough fields (%d)", text, numFields) } - // Safe as mountinfo encodes mountpoints with spaces as \040. - index := strings.Index(text, " - ") - postSeparatorFields := strings.Fields(text[index+3:]) - if len(postSeparatorFields) < 3 { - return nil, fmt.Errorf("Error found less than 3 fields post '-' in %q", text) + p := Info{} + // ignore any numbers parsing errors, as there should not be any + p.ID, _ = strconv.Atoi(fields[0]) + p.Parent, _ = strconv.Atoi(fields[1]) + mm := strings.Split(fields[2], ":") + if len(mm) != 2 { + return nil, fmt.Errorf("Parsing '%s' failed: unexpected minor:major pair %s", text, mm) } + p.Major, _ = strconv.Atoi(mm[0]) + p.Minor, _ = strconv.Atoi(mm[1]) - if optionalFields != "-" { - p.Optional = optionalFields - } + p.Root = fields[3] + p.Mountpoint = fields[4] + p.Options = fields[5] + + // one or more optional fields, when a separator (-) + i := 6 + for ; i < numFields && fields[i] != "-"; i++ { + switch i { + case 6: + p.Optional = fields[6] + default: + /* NOTE there might be more optional fields before the separator + such as fields[7]...fields[N] (where N < separatorIndex), + although as of Linux kernel 4.15 the only known ones are + mount propagation flags in fields[6]. The correct + behavior is to ignore any unknown optional fields. + */ + } + } + if i == numFields { + return nil, fmt.Errorf("Parsing '%s' failed: missing separator ('-')", text) + } + // There should be 3 fields after the separator... + if i+4 > numFields { + return nil, fmt.Errorf("Parsing '%s' failed: not enough fields after a separator", text) + } + // ... but in Linux <= 3.9 mounting a cifs with spaces in a share name + // (like "//serv/My Documents") _may_ end up having a space in the last field + // of mountinfo (like "unc=//serv/My Documents"). Since kernel 3.10-rc1, cifs + // option unc= is ignored, so a space should not appear. In here we ignore + // those "extra" fields caused by extra spaces. + p.FSType = fields[i+1] + p.Source = fields[i+2] + p.VFSOptions = fields[i+3] - p.FSType = postSeparatorFields[0] - p.Source = postSeparatorFields[1] - p.VFSOptions = strings.Join(postSeparatorFields[2:], " ") out = append(out, p) } return out, nil diff --git a/vendor/github.com/containerd/containerd/mount/temp.go b/vendor/github.com/containerd/containerd/mount/temp.go index 5994759f3..9dc4010fe 100644 --- a/vendor/github.com/containerd/containerd/mount/temp.go +++ b/vendor/github.com/containerd/containerd/mount/temp.go @@ -25,7 +25,7 @@ import ( "github.com/pkg/errors" ) -var tempMountLocation = os.TempDir() +var tempMountLocation = getTempDir() // WithTempMount mounts the provided mounts to a temp dir, and pass the temp dir to f. // The mounts are valid during the call to the f. @@ -64,3 +64,10 @@ func WithTempMount(ctx context.Context, mounts []Mount, f func(root string) erro } return errors.Wrapf(f(root), "mount callback failed on %s", root) } + +func getTempDir() string { + if xdg := os.Getenv("XDG_RUNTIME_DIR"); xdg != "" { + return xdg + } + return os.TempDir() +} diff --git a/vendor/github.com/containerd/containerd/namespaces/grpc.go b/vendor/github.com/containerd/containerd/namespaces/grpc.go index fe1ca1d7c..6991460da 100644 --- a/vendor/github.com/containerd/containerd/namespaces/grpc.go +++ b/vendor/github.com/containerd/containerd/namespaces/grpc.go @@ -17,7 +17,8 @@ package namespaces import ( - "golang.org/x/net/context" + "context" + "google.golang.org/grpc/metadata" ) diff --git a/vendor/github.com/containerd/containerd/oci/spec.go b/vendor/github.com/containerd/containerd/oci/spec.go index 78284187a..23f9315a4 100644 --- a/vendor/github.com/containerd/containerd/oci/spec.go +++ b/vendor/github.com/containerd/containerd/oci/spec.go @@ -23,9 +23,13 @@ import ( specs "github.com/opencontainers/runtime-spec/specs-go" ) +// Spec is a type alias to the OCI runtime spec to allow third part SpecOpts +// to be created without the "issues" with go vendoring and package imports +type Spec = specs.Spec + // GenerateSpec will generate a default spec from the provided image // for use as a containerd container -func GenerateSpec(ctx context.Context, client Client, c *containers.Container, opts ...SpecOpts) (*specs.Spec, error) { +func GenerateSpec(ctx context.Context, client Client, c *containers.Container, opts ...SpecOpts) (*Spec, error) { s, err := createDefaultSpec(ctx, c.ID) if err != nil { return nil, err diff --git a/vendor/github.com/containerd/containerd/oci/spec_opts.go b/vendor/github.com/containerd/containerd/oci/spec_opts.go index 96f6b3496..57d95306c 100644 --- a/vendor/github.com/containerd/containerd/oci/spec_opts.go +++ b/vendor/github.com/containerd/containerd/oci/spec_opts.go @@ -25,11 +25,11 @@ import ( ) // SpecOpts sets spec specific information to a newly generated OCI spec -type SpecOpts func(context.Context, Client, *containers.Container, *specs.Spec) error +type SpecOpts func(context.Context, Client, *containers.Container, *Spec) error // Compose converts a sequence of spec operations into a single operation func Compose(opts ...SpecOpts) SpecOpts { - return func(ctx context.Context, client Client, c *containers.Container, s *specs.Spec) error { + return func(ctx context.Context, client Client, c *containers.Container, s *Spec) error { for _, o := range opts { if err := o(ctx, client, c, s); err != nil { return err @@ -40,7 +40,7 @@ func Compose(opts ...SpecOpts) SpecOpts { } // setProcess sets Process to empty if unset -func setProcess(s *specs.Spec) { +func setProcess(s *Spec) { if s.Process == nil { s.Process = &specs.Process{} } @@ -48,7 +48,7 @@ func setProcess(s *specs.Spec) { // WithProcessArgs replaces the args on the generated spec func WithProcessArgs(args ...string) SpecOpts { - return func(_ context.Context, _ Client, _ *containers.Container, s *specs.Spec) error { + return func(_ context.Context, _ Client, _ *containers.Container, s *Spec) error { setProcess(s) s.Process.Args = args return nil @@ -57,7 +57,7 @@ func WithProcessArgs(args ...string) SpecOpts { // WithProcessCwd replaces the current working directory on the generated spec func WithProcessCwd(cwd string) SpecOpts { - return func(_ context.Context, _ Client, _ *containers.Container, s *specs.Spec) error { + return func(_ context.Context, _ Client, _ *containers.Container, s *Spec) error { setProcess(s) s.Process.Cwd = cwd return nil @@ -66,7 +66,7 @@ func WithProcessCwd(cwd string) SpecOpts { // WithHostname sets the container's hostname func WithHostname(name string) SpecOpts { - return func(_ context.Context, _ Client, _ *containers.Container, s *specs.Spec) error { + return func(_ context.Context, _ Client, _ *containers.Container, s *Spec) error { s.Hostname = name return nil } @@ -74,7 +74,7 @@ func WithHostname(name string) SpecOpts { // WithEnv appends environment variables func WithEnv(environmentVariables []string) SpecOpts { - return func(_ context.Context, _ Client, _ *containers.Container, s *specs.Spec) error { + return func(_ context.Context, _ Client, _ *containers.Container, s *Spec) error { if len(environmentVariables) > 0 { setProcess(s) s.Process.Env = replaceOrAppendEnvValues(s.Process.Env, environmentVariables) @@ -85,7 +85,7 @@ func WithEnv(environmentVariables []string) SpecOpts { // WithMounts appends mounts func WithMounts(mounts []specs.Mount) SpecOpts { - return func(_ context.Context, _ Client, _ *containers.Container, s *specs.Spec) error { + return func(_ context.Context, _ Client, _ *containers.Container, s *Spec) error { s.Mounts = append(s.Mounts, mounts...) return nil } diff --git a/vendor/github.com/containerd/containerd/oci/spec_opts_unix.go b/vendor/github.com/containerd/containerd/oci/spec_opts_unix.go index 46053aa55..04b18e2f4 100644 --- a/vendor/github.com/containerd/containerd/oci/spec_opts_unix.go +++ b/vendor/github.com/containerd/containerd/oci/spec_opts_unix.go @@ -42,7 +42,7 @@ import ( // WithTTY sets the information on the spec as well as the environment variables for // using a TTY -func WithTTY(_ context.Context, _ Client, _ *containers.Container, s *specs.Spec) error { +func WithTTY(_ context.Context, _ Client, _ *containers.Container, s *Spec) error { setProcess(s) s.Process.Terminal = true s.Process.Env = append(s.Process.Env, "TERM=xterm") @@ -50,21 +50,21 @@ func WithTTY(_ context.Context, _ Client, _ *containers.Container, s *specs.Spec } // setRoot sets Root to empty if unset -func setRoot(s *specs.Spec) { +func setRoot(s *Spec) { if s.Root == nil { s.Root = &specs.Root{} } } // setLinux sets Linux to empty if unset -func setLinux(s *specs.Spec) { +func setLinux(s *Spec) { if s.Linux == nil { s.Linux = &specs.Linux{} } } // setCapabilities sets Linux Capabilities to empty if unset -func setCapabilities(s *specs.Spec) { +func setCapabilities(s *Spec) { setProcess(s) if s.Process.Capabilities == nil { s.Process.Capabilities = &specs.LinuxCapabilities{} @@ -73,7 +73,7 @@ func setCapabilities(s *specs.Spec) { // WithHostNamespace allows a task to run inside the host's linux namespace func WithHostNamespace(ns specs.LinuxNamespaceType) SpecOpts { - return func(_ context.Context, _ Client, _ *containers.Container, s *specs.Spec) error { + return func(_ context.Context, _ Client, _ *containers.Container, s *Spec) error { setLinux(s) for i, n := range s.Linux.Namespaces { if n.Type == ns { @@ -88,7 +88,7 @@ func WithHostNamespace(ns specs.LinuxNamespaceType) SpecOpts { // WithLinuxNamespace uses the passed in namespace for the spec. If a namespace of the same type already exists in the // spec, the existing namespace is replaced by the one provided. func WithLinuxNamespace(ns specs.LinuxNamespace) SpecOpts { - return func(_ context.Context, _ Client, _ *containers.Container, s *specs.Spec) error { + return func(_ context.Context, _ Client, _ *containers.Container, s *Spec) error { setLinux(s) for i, n := range s.Linux.Namespaces { if n.Type == ns.Type { @@ -106,7 +106,7 @@ func WithLinuxNamespace(ns specs.LinuxNamespace) SpecOpts { // WithImageConfig configures the spec to from the configuration of an Image func WithImageConfig(image Image) SpecOpts { - return func(ctx context.Context, client Client, c *containers.Container, s *specs.Spec) error { + return func(ctx context.Context, client Client, c *containers.Container, s *Spec) error { ic, err := image.Config(ctx) if err != nil { return err @@ -148,7 +148,7 @@ func WithImageConfig(image Image) SpecOpts { // WithRootFSPath specifies unmanaged rootfs path. func WithRootFSPath(path string) SpecOpts { - return func(_ context.Context, _ Client, _ *containers.Container, s *specs.Spec) error { + return func(_ context.Context, _ Client, _ *containers.Container, s *Spec) error { setRoot(s) s.Root.Path = path // Entrypoint is not set here (it's up to caller) @@ -158,7 +158,7 @@ func WithRootFSPath(path string) SpecOpts { // WithRootFSReadonly sets specs.Root.Readonly to true func WithRootFSReadonly() SpecOpts { - return func(_ context.Context, _ Client, _ *containers.Container, s *specs.Spec) error { + return func(_ context.Context, _ Client, _ *containers.Container, s *Spec) error { setRoot(s) s.Root.Readonly = true return nil @@ -166,14 +166,14 @@ func WithRootFSReadonly() SpecOpts { } // WithNoNewPrivileges sets no_new_privileges on the process for the container -func WithNoNewPrivileges(_ context.Context, _ Client, _ *containers.Container, s *specs.Spec) error { +func WithNoNewPrivileges(_ context.Context, _ Client, _ *containers.Container, s *Spec) error { setProcess(s) s.Process.NoNewPrivileges = true return nil } // WithHostHostsFile bind-mounts the host's /etc/hosts into the container as readonly -func WithHostHostsFile(_ context.Context, _ Client, _ *containers.Container, s *specs.Spec) error { +func WithHostHostsFile(_ context.Context, _ Client, _ *containers.Container, s *Spec) error { s.Mounts = append(s.Mounts, specs.Mount{ Destination: "/etc/hosts", Type: "bind", @@ -184,7 +184,7 @@ func WithHostHostsFile(_ context.Context, _ Client, _ *containers.Container, s * } // WithHostResolvconf bind-mounts the host's /etc/resolv.conf into the container as readonly -func WithHostResolvconf(_ context.Context, _ Client, _ *containers.Container, s *specs.Spec) error { +func WithHostResolvconf(_ context.Context, _ Client, _ *containers.Container, s *Spec) error { s.Mounts = append(s.Mounts, specs.Mount{ Destination: "/etc/resolv.conf", Type: "bind", @@ -195,7 +195,7 @@ func WithHostResolvconf(_ context.Context, _ Client, _ *containers.Container, s } // WithHostLocaltime bind-mounts the host's /etc/localtime into the container as readonly -func WithHostLocaltime(_ context.Context, _ Client, _ *containers.Container, s *specs.Spec) error { +func WithHostLocaltime(_ context.Context, _ Client, _ *containers.Container, s *Spec) error { s.Mounts = append(s.Mounts, specs.Mount{ Destination: "/etc/localtime", Type: "bind", @@ -208,7 +208,7 @@ func WithHostLocaltime(_ context.Context, _ Client, _ *containers.Container, s * // WithUserNamespace sets the uid and gid mappings for the task // this can be called multiple times to add more mappings to the generated spec func WithUserNamespace(container, host, size uint32) SpecOpts { - return func(_ context.Context, _ Client, _ *containers.Container, s *specs.Spec) error { + return func(_ context.Context, _ Client, _ *containers.Container, s *Spec) error { var hasUserns bool setLinux(s) for _, ns := range s.Linux.Namespaces { @@ -235,7 +235,7 @@ func WithUserNamespace(container, host, size uint32) SpecOpts { // WithCgroup sets the container's cgroup path func WithCgroup(path string) SpecOpts { - return func(_ context.Context, _ Client, _ *containers.Container, s *specs.Spec) error { + return func(_ context.Context, _ Client, _ *containers.Container, s *Spec) error { setLinux(s) s.Linux.CgroupsPath = path return nil @@ -245,7 +245,7 @@ func WithCgroup(path string) SpecOpts { // WithNamespacedCgroup uses the namespace set on the context to create a // root directory for containers in the cgroup with the id as the subcgroup func WithNamespacedCgroup() SpecOpts { - return func(ctx context.Context, _ Client, c *containers.Container, s *specs.Spec) error { + return func(ctx context.Context, _ Client, c *containers.Container, s *Spec) error { namespace, err := namespaces.NamespaceRequired(ctx) if err != nil { return err @@ -260,7 +260,7 @@ func WithNamespacedCgroup() SpecOpts { // It accepts a valid user string in OCI Image Spec v1.0.0: // user, uid, user:group, uid:gid, uid:group, user:gid func WithUser(userstr string) SpecOpts { - return func(ctx context.Context, client Client, c *containers.Container, s *specs.Spec) error { + return func(ctx context.Context, client Client, c *containers.Container, s *Spec) error { setProcess(s) parts := strings.Split(userstr, ":") switch len(parts) { @@ -338,7 +338,7 @@ func WithUser(userstr string) SpecOpts { // WithUIDGID allows the UID and GID for the Process to be set func WithUIDGID(uid, gid uint32) SpecOpts { - return func(_ context.Context, _ Client, _ *containers.Container, s *specs.Spec) error { + return func(_ context.Context, _ Client, _ *containers.Container, s *Spec) error { setProcess(s) s.Process.User.UID = uid s.Process.User.GID = gid @@ -351,7 +351,7 @@ func WithUIDGID(uid, gid uint32) SpecOpts { // or uid is not found in /etc/passwd, it sets gid to be the same with // uid, and not returns error. func WithUserID(uid uint32) SpecOpts { - return func(ctx context.Context, client Client, c *containers.Container, s *specs.Spec) (err error) { + return func(ctx context.Context, client Client, c *containers.Container, s *Spec) (err error) { setProcess(s) if c.Snapshotter == "" && c.SnapshotKey == "" { if !isRootfsAbs(s.Root.Path) { @@ -404,7 +404,7 @@ func WithUserID(uid uint32) SpecOpts { // does not exist, or the username is not found in /etc/passwd, // it returns error. func WithUsername(username string) SpecOpts { - return func(ctx context.Context, client Client, c *containers.Container, s *specs.Spec) (err error) { + return func(ctx context.Context, client Client, c *containers.Container, s *Spec) (err error) { setProcess(s) if c.Snapshotter == "" && c.SnapshotKey == "" { if !isRootfsAbs(s.Root.Path) { @@ -445,7 +445,7 @@ func WithUsername(username string) SpecOpts { // WithCapabilities sets Linux capabilities on the process func WithCapabilities(caps []string) SpecOpts { - return func(_ context.Context, _ Client, _ *containers.Container, s *specs.Spec) error { + return func(_ context.Context, _ Client, _ *containers.Container, s *Spec) error { setCapabilities(s) s.Process.Capabilities.Bounding = caps @@ -518,7 +518,7 @@ func isRootfsAbs(root string) bool { // WithMaskedPaths sets the masked paths option func WithMaskedPaths(paths []string) SpecOpts { - return func(_ context.Context, _ Client, _ *containers.Container, s *specs.Spec) error { + return func(_ context.Context, _ Client, _ *containers.Container, s *Spec) error { setLinux(s) s.Linux.MaskedPaths = paths return nil @@ -527,7 +527,7 @@ func WithMaskedPaths(paths []string) SpecOpts { // WithReadonlyPaths sets the read only paths option func WithReadonlyPaths(paths []string) SpecOpts { - return func(_ context.Context, _ Client, _ *containers.Container, s *specs.Spec) error { + return func(_ context.Context, _ Client, _ *containers.Container, s *Spec) error { setLinux(s) s.Linux.ReadonlyPaths = paths return nil @@ -535,7 +535,7 @@ func WithReadonlyPaths(paths []string) SpecOpts { } // WithWriteableSysfs makes any sysfs mounts writeable -func WithWriteableSysfs(_ context.Context, _ Client, _ *containers.Container, s *specs.Spec) error { +func WithWriteableSysfs(_ context.Context, _ Client, _ *containers.Container, s *Spec) error { for i, m := range s.Mounts { if m.Type == "sysfs" { var options []string @@ -552,7 +552,7 @@ func WithWriteableSysfs(_ context.Context, _ Client, _ *containers.Container, s } // WithWriteableCgroupfs makes any cgroup mounts writeable -func WithWriteableCgroupfs(_ context.Context, _ Client, _ *containers.Container, s *specs.Spec) error { +func WithWriteableCgroupfs(_ context.Context, _ Client, _ *containers.Container, s *Spec) error { for i, m := range s.Mounts { if m.Type == "cgroup" { var options []string @@ -570,7 +570,7 @@ func WithWriteableCgroupfs(_ context.Context, _ Client, _ *containers.Container, // WithSelinuxLabel sets the process SELinux label func WithSelinuxLabel(label string) SpecOpts { - return func(_ context.Context, _ Client, _ *containers.Container, s *specs.Spec) error { + return func(_ context.Context, _ Client, _ *containers.Container, s *Spec) error { setProcess(s) s.Process.SelinuxLabel = label return nil @@ -579,7 +579,7 @@ func WithSelinuxLabel(label string) SpecOpts { // WithApparmorProfile sets the Apparmor profile for the process func WithApparmorProfile(profile string) SpecOpts { - return func(_ context.Context, _ Client, _ *containers.Container, s *specs.Spec) error { + return func(_ context.Context, _ Client, _ *containers.Container, s *Spec) error { setProcess(s) s.Process.ApparmorProfile = profile return nil @@ -587,7 +587,7 @@ func WithApparmorProfile(profile string) SpecOpts { } // WithSeccompUnconfined clears the seccomp profile -func WithSeccompUnconfined(_ context.Context, _ Client, _ *containers.Container, s *specs.Spec) error { +func WithSeccompUnconfined(_ context.Context, _ Client, _ *containers.Container, s *Spec) error { setLinux(s) s.Linux.Seccomp = nil return nil diff --git a/vendor/github.com/containerd/containerd/oci/spec_opts_windows.go b/vendor/github.com/containerd/containerd/oci/spec_opts_windows.go index 4da0802dd..7fe76ea5b 100644 --- a/vendor/github.com/containerd/containerd/oci/spec_opts_windows.go +++ b/vendor/github.com/containerd/containerd/oci/spec_opts_windows.go @@ -32,7 +32,7 @@ import ( // WithImageConfig configures the spec to from the configuration of an Image func WithImageConfig(image Image) SpecOpts { - return func(ctx context.Context, client Client, _ *containers.Container, s *specs.Spec) error { + return func(ctx context.Context, client Client, _ *containers.Container, s *Spec) error { setProcess(s) ic, err := image.Config(ctx) if err != nil { @@ -67,7 +67,7 @@ func WithImageConfig(image Image) SpecOpts { // WithTTY sets the information on the spec as well as the environment variables for // using a TTY func WithTTY(width, height int) SpecOpts { - return func(_ context.Context, _ Client, _ *containers.Container, s *specs.Spec) error { + return func(_ context.Context, _ Client, _ *containers.Container, s *Spec) error { setProcess(s) s.Process.Terminal = true if s.Process.ConsoleSize == nil { @@ -81,7 +81,7 @@ func WithTTY(width, height int) SpecOpts { // WithUsername sets the username on the process func WithUsername(username string) SpecOpts { - return func(ctx context.Context, client Client, c *containers.Container, s *specs.Spec) error { + return func(ctx context.Context, client Client, c *containers.Container, s *Spec) error { setProcess(s) s.Process.User.Username = username return nil diff --git a/vendor/github.com/containerd/containerd/oci/spec_unix.go b/vendor/github.com/containerd/containerd/oci/spec_unix.go index e52e42228..f791c357f 100644 --- a/vendor/github.com/containerd/containerd/oci/spec_unix.go +++ b/vendor/github.com/containerd/containerd/oci/spec_unix.go @@ -76,12 +76,12 @@ func defaultNamespaces() []specs.LinuxNamespace { } } -func createDefaultSpec(ctx context.Context, id string) (*specs.Spec, error) { +func createDefaultSpec(ctx context.Context, id string) (*Spec, error) { ns, err := namespaces.NamespaceRequired(ctx) if err != nil { return nil, err } - s := &specs.Spec{ + s := &Spec{ Version: specs.Version, Root: &specs.Root{ Path: defaultRootfsPath, diff --git a/vendor/github.com/containerd/containerd/oci/spec_windows.go b/vendor/github.com/containerd/containerd/oci/spec_windows.go index f8cdb8a9b..82d7ef158 100644 --- a/vendor/github.com/containerd/containerd/oci/spec_windows.go +++ b/vendor/github.com/containerd/containerd/oci/spec_windows.go @@ -22,8 +22,8 @@ import ( specs "github.com/opencontainers/runtime-spec/specs-go" ) -func createDefaultSpec(ctx context.Context, id string) (*specs.Spec, error) { - return &specs.Spec{ +func createDefaultSpec(ctx context.Context, id string) (*Spec, error) { + return &Spec{ Version: specs.Version, Root: &specs.Root{}, Process: &specs.Process{ diff --git a/vendor/github.com/containerd/containerd/plugin/plugin.go b/vendor/github.com/containerd/containerd/plugin/plugin.go index ed53daeba..81318ed6a 100644 --- a/vendor/github.com/containerd/containerd/plugin/plugin.go +++ b/vendor/github.com/containerd/containerd/plugin/plugin.go @@ -54,8 +54,8 @@ type Type string func (t Type) String() string { return string(t) } const ( - // AllPlugins declares that the plugin should be initialized after all others. - AllPlugins Type = "*" + // InternalPlugin implements an internal plugin to containerd + InternalPlugin Type = "io.containerd.internal.v1" // RuntimePlugin implements a runtime RuntimePlugin Type = "io.containerd.runtime.v1" // ServicePlugin implements a internal service diff --git a/vendor/github.com/containerd/containerd/rootfs/apply.go b/vendor/github.com/containerd/containerd/rootfs/apply.go index 73613337d..a1a2db938 100644 --- a/vendor/github.com/containerd/containerd/rootfs/apply.go +++ b/vendor/github.com/containerd/containerd/rootfs/apply.go @@ -17,6 +17,7 @@ package rootfs import ( + "context" "crypto/rand" "encoding/base64" "fmt" @@ -25,12 +26,12 @@ import ( "github.com/containerd/containerd/diff" "github.com/containerd/containerd/errdefs" "github.com/containerd/containerd/log" + "github.com/containerd/containerd/mount" "github.com/containerd/containerd/snapshots" "github.com/opencontainers/go-digest" "github.com/opencontainers/image-spec/identity" ocispec "github.com/opencontainers/image-spec/specs-go/v1" "github.com/pkg/errors" - "golang.org/x/net/context" ) // Layer represents the descriptors for a layer diff. These descriptions @@ -47,16 +48,27 @@ type Layer struct { // Layers are applied in order they are given, making the first layer the // bottom-most layer in the layer chain. func ApplyLayers(ctx context.Context, layers []Layer, sn snapshots.Snapshotter, a diff.Applier) (digest.Digest, error) { - var chain []digest.Digest - for _, layer := range layers { - if _, err := ApplyLayer(ctx, layer, chain, sn, a); err != nil { - // TODO: possibly wait and retry if extraction of same chain id was in progress - return "", err + chain := make([]digest.Digest, len(layers)) + for i, layer := range layers { + chain[i] = layer.Diff.Digest + } + chainID := identity.ChainID(chain) + + // Just stat top layer, remaining layers will have their existence checked + // on prepare. Calling prepare on upper layers first guarantees that upper + // layers are not removed while calling stat on lower layers + _, err := sn.Stat(ctx, chainID.String()) + if err != nil { + if !errdefs.IsNotFound(err) { + return "", errors.Wrapf(err, "failed to stat snapshot %s", chainID) } - chain = append(chain, layer.Diff.Digest) + if err := applyLayers(ctx, layers, chain, sn, a); err != nil && !errdefs.IsAlreadyExists(err) { + return "", err + } } - return identity.ChainID(chain), nil + + return chainID, nil } // ApplyLayer applies a single layer on top of the given provided layer chain, @@ -64,59 +76,90 @@ func ApplyLayers(ctx context.Context, layers []Layer, sn snapshots.Snapshotter, // is returned, if the layer already exists false is returned. func ApplyLayer(ctx context.Context, layer Layer, chain []digest.Digest, sn snapshots.Snapshotter, a diff.Applier, opts ...snapshots.Opt) (bool, error) { var ( - parent = identity.ChainID(chain) - chainID = identity.ChainID(append(chain, layer.Diff.Digest)) + chainID = identity.ChainID(append(chain, layer.Diff.Digest)).String() + applied bool + ) + if _, err := sn.Stat(ctx, chainID); err != nil { + if !errdefs.IsNotFound(err) { + return false, errors.Wrapf(err, "failed to stat snapshot %s", chainID) + } + + if err := applyLayers(ctx, []Layer{layer}, append(chain, layer.Diff.Digest), sn, a, opts...); err != nil { + if !errdefs.IsAlreadyExists(err) { + return false, err + } + } else { + applied = true + } + } + return applied, nil +} + +func applyLayers(ctx context.Context, layers []Layer, chain []digest.Digest, sn snapshots.Snapshotter, a diff.Applier, opts ...snapshots.Opt) error { + var ( + parent = identity.ChainID(chain[:len(chain)-1]) + chainID = identity.ChainID(chain) + layer = layers[len(layers)-1] diff ocispec.Descriptor + key string + mounts []mount.Mount + err error ) - _, err := sn.Stat(ctx, chainID.String()) - if err == nil { - log.G(ctx).Debugf("Extraction not needed, layer snapshot %s exists", chainID) - return false, nil - } else if !errdefs.IsNotFound(err) { - return false, errors.Wrapf(err, "failed to stat snapshot %s", chainID) - } + for { + key = fmt.Sprintf("extract-%s %s", uniquePart(), chainID) - key := fmt.Sprintf("extract-%s %s", uniquePart(), chainID) + // Prepare snapshot with from parent, label as root + mounts, err = sn.Prepare(ctx, key, parent.String(), opts...) + if err != nil { + if errdefs.IsNotFound(err) && len(layers) > 1 { + if err := applyLayers(ctx, layers[:len(layers)-1], chain[:len(chain)-1], sn, a); err != nil { + if !errdefs.IsAlreadyExists(err) { + return err + } + } + // Do no try applying layers again + layers = nil + continue + } else if errdefs.IsAlreadyExists(err) { + // Try a different key + continue + } - // Prepare snapshot with from parent, label as root - mounts, err := sn.Prepare(ctx, key, parent.String(), opts...) - if err != nil { - //TODO: If is snapshot exists error, retry - return false, errors.Wrapf(err, "failed to prepare extraction snapshot %q", key) + // Already exists should have the caller retry + return errors.Wrapf(err, "failed to prepare extraction snapshot %q", key) + + } + break } defer func() { if err != nil { - log.G(ctx).WithError(err).WithField("key", key).Infof("Apply failure, attempting cleanup") + if !errdefs.IsAlreadyExists(err) { + log.G(ctx).WithError(err).WithField("key", key).Infof("apply failure, attempting cleanup") + } + if rerr := sn.Remove(ctx, key); rerr != nil { - log.G(ctx).WithError(rerr).Warnf("Extraction snapshot %q removal failed", key) + log.G(ctx).WithError(rerr).WithField("key", key).Warnf("extraction snapshot removal failed") } } }() diff, err = a.Apply(ctx, layer.Blob, mounts) if err != nil { - return false, errors.Wrapf(err, "failed to extract layer %s", layer.Diff.Digest) + err = errors.Wrapf(err, "failed to extract layer %s", layer.Diff.Digest) + return err } if diff.Digest != layer.Diff.Digest { err = errors.Errorf("wrong diff id calculated on extraction %q", diff.Digest) - return false, err + return err } if err = sn.Commit(ctx, chainID.String(), key, opts...); err != nil { - if !errdefs.IsAlreadyExists(err) { - return false, errors.Wrapf(err, "failed to commit snapshot %s", key) - } - - // Destination already exists, cleanup key and return without error - err = nil - if err := sn.Remove(ctx, key); err != nil { - return false, errors.Wrapf(err, "failed to cleanup aborted apply %s", key) - } - return false, nil + err = errors.Wrapf(err, "failed to commit snapshot %s", key) + return err } - return true, nil + return nil } func uniquePart() string { diff --git a/vendor/github.com/containerd/containerd/rootfs/diff.go b/vendor/github.com/containerd/containerd/rootfs/diff.go index c7f954e9f..b3e6ba8a3 100644 --- a/vendor/github.com/containerd/containerd/rootfs/diff.go +++ b/vendor/github.com/containerd/containerd/rootfs/diff.go @@ -17,13 +17,13 @@ package rootfs import ( + "context" "fmt" "github.com/containerd/containerd/diff" "github.com/containerd/containerd/mount" "github.com/containerd/containerd/snapshots" ocispec "github.com/opencontainers/image-spec/specs-go/v1" - "golang.org/x/net/context" ) // CreateDiff creates a layer diff for the given snapshot identifier from the diff --git a/vendor/github.com/containerd/containerd/rootfs/init.go b/vendor/github.com/containerd/containerd/rootfs/init.go index 326f30f70..325e5531d 100644 --- a/vendor/github.com/containerd/containerd/rootfs/init.go +++ b/vendor/github.com/containerd/containerd/rootfs/init.go @@ -75,7 +75,7 @@ func createInitLayer(ctx context.Context, parent, initName string, initFn func(s // TODO: ensure not exist error once added to snapshot package // Create tempdir - td, err := ioutil.TempDir("", "create-init-") + td, err := ioutil.TempDir(os.Getenv("XDG_RUNTIME_DIR"), "create-init-") if err != nil { return "", err } diff --git a/vendor/github.com/containerd/containerd/runtime/runtime.go b/vendor/github.com/containerd/containerd/runtime/runtime.go index 000af4ad3..0057c1a4e 100644 --- a/vendor/github.com/containerd/containerd/runtime/runtime.go +++ b/vendor/github.com/containerd/containerd/runtime/runtime.go @@ -53,9 +53,9 @@ type Exit struct { Timestamp time.Time } -// Runtime is responsible for the creation of containers for a certain platform, -// arch, or custom usage. -type Runtime interface { +// PlatformRuntime is responsible for the creation and management of +// tasks and processes for a platform. +type PlatformRuntime interface { // ID of the runtime ID() string // Create creates a task with the provided id and options. diff --git a/vendor/github.com/containerd/containerd/server/server.go b/vendor/github.com/containerd/containerd/server/server.go index 59c74d08b..d6e22cb71 100644 --- a/vendor/github.com/containerd/containerd/server/server.go +++ b/vendor/github.com/containerd/containerd/server/server.go @@ -17,6 +17,7 @@ package server import ( + "context" "expvar" "io" "net" @@ -37,7 +38,6 @@ import ( metrics "github.com/docker/go-metrics" grpc_prometheus "github.com/grpc-ecosystem/go-grpc-prometheus" "github.com/pkg/errors" - "golang.org/x/net/context" "google.golang.org/grpc" ) @@ -146,7 +146,7 @@ func (s *Server) ServeGRPC(l net.Listener) error { // enable grpc time histograms to measure rpc latencies grpc_prometheus.EnableHandlingTimeHistogram() } - // before we start serving the grpc API regster the grpc_prometheus metrics + // before we start serving the grpc API register the grpc_prometheus metrics // handler. This needs to be the last service registered so that it can collect // metrics for every other service grpc_prometheus.Register(s.rpc) diff --git a/vendor/github.com/containerd/containerd/services/containers/local.go b/vendor/github.com/containerd/containerd/services/containers/local.go index 1e59da6c3..424bc21e6 100644 --- a/vendor/github.com/containerd/containerd/services/containers/local.go +++ b/vendor/github.com/containerd/containerd/services/containers/local.go @@ -17,6 +17,8 @@ package containers import ( + "context" + "github.com/boltdb/bolt" eventstypes "github.com/containerd/containerd/api/events" api "github.com/containerd/containerd/api/services/containers/v1" @@ -27,7 +29,6 @@ import ( "github.com/containerd/containerd/plugin" "github.com/containerd/containerd/services" ptypes "github.com/gogo/protobuf/types" - "golang.org/x/net/context" "google.golang.org/grpc" "google.golang.org/grpc/codes" "google.golang.org/grpc/status" diff --git a/vendor/github.com/containerd/containerd/services/containers/service.go b/vendor/github.com/containerd/containerd/services/containers/service.go index f25c0b0ff..89c072cbb 100644 --- a/vendor/github.com/containerd/containerd/services/containers/service.go +++ b/vendor/github.com/containerd/containerd/services/containers/service.go @@ -17,12 +17,13 @@ package containers import ( + "context" + api "github.com/containerd/containerd/api/services/containers/v1" "github.com/containerd/containerd/plugin" "github.com/containerd/containerd/services" ptypes "github.com/gogo/protobuf/types" "github.com/pkg/errors" - "golang.org/x/net/context" "google.golang.org/grpc" ) diff --git a/vendor/github.com/containerd/containerd/services/content/service.go b/vendor/github.com/containerd/containerd/services/content/service.go index 9038e168a..b615e3aa0 100644 --- a/vendor/github.com/containerd/containerd/services/content/service.go +++ b/vendor/github.com/containerd/containerd/services/content/service.go @@ -17,6 +17,7 @@ package content import ( + "context" "io" "sync" @@ -30,7 +31,6 @@ import ( digest "github.com/opencontainers/go-digest" "github.com/pkg/errors" "github.com/sirupsen/logrus" - "golang.org/x/net/context" "google.golang.org/grpc" "google.golang.org/grpc/codes" "google.golang.org/grpc/status" diff --git a/vendor/github.com/containerd/containerd/services/diff/local.go b/vendor/github.com/containerd/containerd/services/diff/local.go index 0b90dc271..0cb6222c5 100644 --- a/vendor/github.com/containerd/containerd/services/diff/local.go +++ b/vendor/github.com/containerd/containerd/services/diff/local.go @@ -17,6 +17,8 @@ package diff import ( + "context" + diffapi "github.com/containerd/containerd/api/services/diff/v1" "github.com/containerd/containerd/api/types" "github.com/containerd/containerd/diff" @@ -26,7 +28,6 @@ import ( "github.com/containerd/containerd/services" ocispec "github.com/opencontainers/image-spec/specs-go/v1" "github.com/pkg/errors" - "golang.org/x/net/context" "google.golang.org/grpc" ) diff --git a/vendor/github.com/containerd/containerd/services/diff/service.go b/vendor/github.com/containerd/containerd/services/diff/service.go index e12c4a062..369e8f84d 100644 --- a/vendor/github.com/containerd/containerd/services/diff/service.go +++ b/vendor/github.com/containerd/containerd/services/diff/service.go @@ -17,11 +17,12 @@ package diff import ( + "context" + diffapi "github.com/containerd/containerd/api/services/diff/v1" "github.com/containerd/containerd/plugin" "github.com/containerd/containerd/services" "github.com/pkg/errors" - "golang.org/x/net/context" "google.golang.org/grpc" ) diff --git a/vendor/github.com/containerd/containerd/services/events/service.go b/vendor/github.com/containerd/containerd/services/events/service.go index 58a0d02f5..d620cbf02 100644 --- a/vendor/github.com/containerd/containerd/services/events/service.go +++ b/vendor/github.com/containerd/containerd/services/events/service.go @@ -17,6 +17,8 @@ package events import ( + "context" + api "github.com/containerd/containerd/api/services/events/v1" "github.com/containerd/containerd/errdefs" "github.com/containerd/containerd/events" @@ -24,7 +26,6 @@ import ( "github.com/containerd/containerd/plugin" ptypes "github.com/gogo/protobuf/types" "github.com/pkg/errors" - "golang.org/x/net/context" "google.golang.org/grpc" ) diff --git a/vendor/github.com/containerd/containerd/services/images/local.go b/vendor/github.com/containerd/containerd/services/images/local.go index 1cca1a42a..116c4e432 100644 --- a/vendor/github.com/containerd/containerd/services/images/local.go +++ b/vendor/github.com/containerd/containerd/services/images/local.go @@ -17,7 +17,7 @@ package images import ( - gocontext "context" + "context" eventstypes "github.com/containerd/containerd/api/events" imagesapi "github.com/containerd/containerd/api/services/images/v1" @@ -30,7 +30,6 @@ import ( "github.com/containerd/containerd/plugin" "github.com/containerd/containerd/services" ptypes "github.com/gogo/protobuf/types" - "golang.org/x/net/context" "google.golang.org/grpc" "google.golang.org/grpc/codes" "google.golang.org/grpc/status" @@ -64,7 +63,7 @@ func init() { } type gcScheduler interface { - ScheduleAndWait(gocontext.Context) (gc.Stats, error) + ScheduleAndWait(context.Context) (gc.Stats, error) } type local struct { diff --git a/vendor/github.com/containerd/containerd/services/images/service.go b/vendor/github.com/containerd/containerd/services/images/service.go index a025c66c9..83d802140 100644 --- a/vendor/github.com/containerd/containerd/services/images/service.go +++ b/vendor/github.com/containerd/containerd/services/images/service.go @@ -17,12 +17,13 @@ package images import ( + "context" + imagesapi "github.com/containerd/containerd/api/services/images/v1" "github.com/containerd/containerd/plugin" "github.com/containerd/containerd/services" ptypes "github.com/gogo/protobuf/types" "github.com/pkg/errors" - "golang.org/x/net/context" "google.golang.org/grpc" ) diff --git a/vendor/github.com/containerd/containerd/services/introspection/service.go b/vendor/github.com/containerd/containerd/services/introspection/service.go index 014ac0ed0..bc5913bd7 100644 --- a/vendor/github.com/containerd/containerd/services/introspection/service.go +++ b/vendor/github.com/containerd/containerd/services/introspection/service.go @@ -17,6 +17,8 @@ package introspection import ( + context "context" + api "github.com/containerd/containerd/api/services/introspection/v1" "github.com/containerd/containerd/api/types" "github.com/containerd/containerd/errdefs" @@ -24,7 +26,6 @@ import ( "github.com/containerd/containerd/plugin" "github.com/gogo/googleapis/google/rpc" ptypes "github.com/gogo/protobuf/types" - context "golang.org/x/net/context" "google.golang.org/grpc" "google.golang.org/grpc/status" ) diff --git a/vendor/github.com/containerd/containerd/services/leases/local.go b/vendor/github.com/containerd/containerd/services/leases/local.go index d3e0c2f2c..1b3a62112 100644 --- a/vendor/github.com/containerd/containerd/services/leases/local.go +++ b/vendor/github.com/containerd/containerd/services/leases/local.go @@ -17,6 +17,7 @@ package leases import ( + "context" "crypto/rand" "encoding/base64" "fmt" @@ -30,7 +31,6 @@ import ( "github.com/containerd/containerd/plugin" "github.com/containerd/containerd/services" ptypes "github.com/gogo/protobuf/types" - "golang.org/x/net/context" ) func init() { diff --git a/vendor/github.com/containerd/containerd/services/leases/service.go b/vendor/github.com/containerd/containerd/services/leases/service.go index e9cccf921..a0a433430 100644 --- a/vendor/github.com/containerd/containerd/services/leases/service.go +++ b/vendor/github.com/containerd/containerd/services/leases/service.go @@ -17,6 +17,8 @@ package leases import ( + "context" + "google.golang.org/grpc" api "github.com/containerd/containerd/api/services/leases/v1" @@ -24,7 +26,6 @@ import ( "github.com/containerd/containerd/services" ptypes "github.com/gogo/protobuf/types" "github.com/pkg/errors" - "golang.org/x/net/context" ) func init() { diff --git a/vendor/github.com/containerd/containerd/services/namespaces/local.go b/vendor/github.com/containerd/containerd/services/namespaces/local.go index dfa86740b..08d21be2b 100644 --- a/vendor/github.com/containerd/containerd/services/namespaces/local.go +++ b/vendor/github.com/containerd/containerd/services/namespaces/local.go @@ -17,6 +17,7 @@ package namespaces import ( + "context" "strings" "github.com/boltdb/bolt" @@ -29,7 +30,6 @@ import ( "github.com/containerd/containerd/plugin" "github.com/containerd/containerd/services" ptypes "github.com/gogo/protobuf/types" - "golang.org/x/net/context" "google.golang.org/grpc" "google.golang.org/grpc/codes" "google.golang.org/grpc/status" diff --git a/vendor/github.com/containerd/containerd/services/namespaces/service.go b/vendor/github.com/containerd/containerd/services/namespaces/service.go index 965590688..d3c74a2cb 100644 --- a/vendor/github.com/containerd/containerd/services/namespaces/service.go +++ b/vendor/github.com/containerd/containerd/services/namespaces/service.go @@ -17,12 +17,13 @@ package namespaces import ( + "context" + api "github.com/containerd/containerd/api/services/namespaces/v1" "github.com/containerd/containerd/plugin" "github.com/containerd/containerd/services" ptypes "github.com/gogo/protobuf/types" "github.com/pkg/errors" - "golang.org/x/net/context" "google.golang.org/grpc" ) diff --git a/vendor/github.com/containerd/containerd/services/snapshots/service.go b/vendor/github.com/containerd/containerd/services/snapshots/service.go index 1d10fae1e..8ef7a47f5 100644 --- a/vendor/github.com/containerd/containerd/services/snapshots/service.go +++ b/vendor/github.com/containerd/containerd/services/snapshots/service.go @@ -17,7 +17,7 @@ package snapshots import ( - gocontext "context" + "context" snapshotsapi "github.com/containerd/containerd/api/services/snapshots/v1" "github.com/containerd/containerd/api/types" @@ -29,7 +29,6 @@ import ( "github.com/containerd/containerd/snapshots" ptypes "github.com/gogo/protobuf/types" "github.com/pkg/errors" - "golang.org/x/net/context" "google.golang.org/grpc" ) @@ -216,7 +215,7 @@ func (s *service) List(sr *snapshotsapi.ListSnapshotsRequest, ss snapshotsapi.Sn }) } ) - err = sn.Walk(ss.Context(), func(ctx gocontext.Context, info snapshots.Info) error { + err = sn.Walk(ss.Context(), func(ctx context.Context, info snapshots.Info) error { buffer = append(buffer, fromInfo(info)) if len(buffer) >= 100 { diff --git a/vendor/github.com/containerd/containerd/services/tasks/local.go b/vendor/github.com/containerd/containerd/services/tasks/local.go index 5bdadab62..1de7a4aa2 100644 --- a/vendor/github.com/containerd/containerd/services/tasks/local.go +++ b/vendor/github.com/containerd/containerd/services/tasks/local.go @@ -18,6 +18,7 @@ package tasks import ( "bytes" + "context" "fmt" "io" "io/ioutil" @@ -45,7 +46,6 @@ import ( "github.com/containerd/typeurl" ptypes "github.com/gogo/protobuf/types" "github.com/pkg/errors" - "golang.org/x/net/context" "google.golang.org/grpc" "google.golang.org/grpc/codes" "google.golang.org/grpc/status" @@ -79,14 +79,14 @@ func initFunc(ic *plugin.InitContext) (interface{}, error) { return nil, err } cs := m.(*metadata.DB).ContentStore() - runtimes := make(map[string]runtime.Runtime) + runtimes := make(map[string]runtime.PlatformRuntime) for _, rr := range rt { ri, err := rr.Instance() if err != nil { log.G(ic.Context).WithError(err).Warn("could not load runtime instance due to initialization error") continue } - r := ri.(runtime.Runtime) + r := ri.(runtime.PlatformRuntime) runtimes[r.ID()] = r } @@ -102,7 +102,7 @@ func initFunc(ic *plugin.InitContext) (interface{}, error) { } type local struct { - runtimes map[string]runtime.Runtime + runtimes map[string]runtime.PlatformRuntime db *metadata.DB store content.Store publisher events.Publisher @@ -114,7 +114,7 @@ func (l *local) Create(ctx context.Context, r *api.CreateTaskRequest, _ ...grpc. err error ) if r.Checkpoint != nil { - checkpointPath, err = ioutil.TempDir("", "ctrd-checkpoint") + checkpointPath, err = ioutil.TempDir(os.Getenv("XDG_RUNTIME_DIR"), "ctrd-checkpoint") if err != nil { return nil, err } @@ -450,7 +450,7 @@ func (l *local) Checkpoint(ctx context.Context, r *api.CheckpointTaskRequest, _ if err != nil { return nil, err } - image, err := ioutil.TempDir("", "ctd-checkpoint") + image, err := ioutil.TempDir(os.Getenv("XDG_RUNTIME_DIR"), "ctd-checkpoint") if err != nil { return nil, errdefs.ToGRPC(err) } @@ -625,7 +625,7 @@ func (l *local) getTaskFromContainer(ctx context.Context, container *containers. return t, nil } -func (l *local) getRuntime(name string) (runtime.Runtime, error) { +func (l *local) getRuntime(name string) (runtime.PlatformRuntime, error) { runtime, ok := l.runtimes[name] if !ok { return nil, status.Errorf(codes.NotFound, "unknown runtime %q", name) diff --git a/vendor/github.com/containerd/containerd/services/tasks/service.go b/vendor/github.com/containerd/containerd/services/tasks/service.go index becf1508b..a92a9a07e 100644 --- a/vendor/github.com/containerd/containerd/services/tasks/service.go +++ b/vendor/github.com/containerd/containerd/services/tasks/service.go @@ -17,12 +17,13 @@ package tasks import ( + "context" + api "github.com/containerd/containerd/api/services/tasks/v1" "github.com/containerd/containerd/plugin" "github.com/containerd/containerd/services" ptypes "github.com/gogo/protobuf/types" "github.com/pkg/errors" - "golang.org/x/net/context" "google.golang.org/grpc" ) diff --git a/vendor/github.com/containerd/containerd/services/version/service.go b/vendor/github.com/containerd/containerd/services/version/service.go index e2da522f5..aaa5d25a7 100644 --- a/vendor/github.com/containerd/containerd/services/version/service.go +++ b/vendor/github.com/containerd/containerd/services/version/service.go @@ -17,11 +17,12 @@ package version import ( + "context" + api "github.com/containerd/containerd/api/services/version/v1" "github.com/containerd/containerd/plugin" ctrdversion "github.com/containerd/containerd/version" ptypes "github.com/gogo/protobuf/types" - "golang.org/x/net/context" "google.golang.org/grpc" ) diff --git a/vendor/github.com/containerd/containerd/sys/env.go b/vendor/github.com/containerd/containerd/sys/env.go new file mode 100644 index 000000000..8450d6275 --- /dev/null +++ b/vendor/github.com/containerd/containerd/sys/env.go @@ -0,0 +1,33 @@ +// +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 sys + +import "golang.org/x/sys/unix" + +// RunningPrivileged returns true if the effective user ID of the +// calling process is 0 +func RunningPrivileged() bool { + return unix.Geteuid() == 0 +} + +// RunningUnprivileged returns true if the effective user ID of the +// calling process is not 0 +func RunningUnprivileged() bool { + return !RunningPrivileged() +} diff --git a/vendor/github.com/containerd/containerd/sys/oom_unix.go b/vendor/github.com/containerd/containerd/sys/oom_unix.go index 1abe7485b..7192efec1 100644 --- a/vendor/github.com/containerd/containerd/sys/oom_unix.go +++ b/vendor/github.com/containerd/containerd/sys/oom_unix.go @@ -38,7 +38,7 @@ func SetOOMScore(pid, score int) error { } defer f.Close() if _, err = f.WriteString(strconv.Itoa(score)); err != nil { - if os.IsPermission(err) && system.RunningInUserNS() { + if os.IsPermission(err) && (system.RunningInUserNS() || RunningUnprivileged()) { return nil } return err diff --git a/vendor/github.com/containerd/containerd/vendor.conf b/vendor/github.com/containerd/containerd/vendor.conf index c4eb0cfb7..2bb147bfc 100644 --- a/vendor/github.com/containerd/containerd/vendor.conf +++ b/vendor/github.com/containerd/containerd/vendor.conf @@ -1,4 +1,4 @@ -github.com/containerd/go-runc bcb223a061a3dd7de1a89c0b402a60f4dd9bd307 +github.com/containerd/go-runc f271fa2021de855d4d918dbef83c5fe19db1bdd5 github.com/containerd/console cb7008ab3d8359b78c5f464cb7cf160107ad5925 github.com/containerd/cgroups fe281dd265766145e943a034aa41086474ea6130 github.com/containerd/typeurl f6943554a7e7e88b3c14aad190bf05932da84788 @@ -24,17 +24,17 @@ github.com/opencontainers/runc 69663f0bd4b60df09991c08812a60108003fa340 github.com/sirupsen/logrus v1.0.0 github.com/pmezard/go-difflib v1.0.0 github.com/urfave/cli 7bc6a0acffa589f415f88aca16cc1de5ffd66f9c -golang.org/x/net 7dcfb8076726a3fdd9353b6b8a1f1b6be6811bd6 +golang.org/x/net b3756b4b77d7b13260a0a2ec658753cf48922eac google.golang.org/grpc v1.10.1 github.com/pkg/errors v0.8.0 -github.com/opencontainers/go-digest 21dfd564fd89c944783d00d069f33e3e7123c448 +github.com/opencontainers/go-digest c9281466c8b2f606084ac71339773efd177436e7 golang.org/x/sys 314a259e304ff91bd6985da2a7149bbf91237993 https://github.com/golang/sys github.com/opencontainers/image-spec v1.0.1 golang.org/x/sync 450f422ab23cf9881c94e2db30cac0eb1b7cf80c github.com/BurntSushi/toml a368813c5e648fee92e5f6c30e3944ff9d5e8895 github.com/grpc-ecosystem/go-grpc-prometheus 6b7015e65d366bf3f19b2b2a000a831940f0f7e0 github.com/Microsoft/go-winio v0.4.5 -github.com/Microsoft/hcsshim v0.6.7 +github.com/Microsoft/hcsshim v0.6.10 github.com/boltdb/bolt e9cf4fae01b5a8ff89d0ec6b32f0d9c9f79aefdd google.golang.org/genproto d80a6e20e776b0b17a324d0ba1ab50a39c8e8944 golang.org/x/text 19e51611da83d6be54ddafce4a4af510cb3e9ea4 @@ -44,7 +44,7 @@ github.com/gotestyourself/gotestyourself 44dbf532bbf5767611f6f2a61bded572e337010 github.com/google/go-cmp v0.1.0 # cri dependencies -github.com/containerd/cri v1.0.0-rc.2 +github.com/containerd/cri v1.0.0 github.com/containerd/go-cni f2d7272f12d045b16ed924f50e91f9f9cecc55a7 github.com/blang/semver v3.1.0 github.com/containernetworking/cni v0.6.0 diff --git a/vendor/github.com/containerd/containerd/version/version.go b/vendor/github.com/containerd/containerd/version/version.go index e1b5f54e0..051919a68 100644 --- a/vendor/github.com/containerd/containerd/version/version.go +++ b/vendor/github.com/containerd/containerd/version/version.go @@ -21,7 +21,7 @@ var ( Package = "github.com/containerd/containerd" // Version holds the complete version number. Filled in at linking time. - Version = "1.1.0-rc.2+unknown" + Version = "1.1.0+unknown" // Revision is filled with the VCS (e.g. git) revision being used to build // the program at linking time. diff --git a/vendor/github.com/containerd/go-runc/console.go b/vendor/github.com/containerd/go-runc/console.go index e81730075..dc7b82ea0 100644 --- a/vendor/github.com/containerd/go-runc/console.go +++ b/vendor/github.com/containerd/go-runc/console.go @@ -43,7 +43,7 @@ func NewConsoleSocket(path string) (*Socket, error) { return nil, err } return &Socket{ - l: l, + l: l, }, nil } diff --git a/vendor/github.com/containerd/go-runc/runc.go b/vendor/github.com/containerd/go-runc/runc.go index 74d77c192..e4cf98e8e 100644 --- a/vendor/github.com/containerd/go-runc/runc.go +++ b/vendor/github.com/containerd/go-runc/runc.go @@ -512,10 +512,11 @@ type RestoreOpts struct { CheckpointOpts IO - Detach bool - PidFile string - NoSubreaper bool - NoPivot bool + Detach bool + PidFile string + NoSubreaper bool + NoPivot bool + ConsoleSocket ConsoleSocket } func (o *RestoreOpts) args() ([]string, error) { @@ -530,6 +531,9 @@ func (o *RestoreOpts) args() ([]string, error) { } out = append(out, "--pid-file", abs) } + if o.ConsoleSocket != nil { + out = append(out, "--console-socket", o.ConsoleSocket.Path()) + } if o.NoPivot { out = append(out, "--no-pivot") } diff --git a/vendor/github.com/opencontainers/go-digest/LICENSE.code b/vendor/github.com/opencontainers/go-digest/LICENSE similarity index 100% rename from vendor/github.com/opencontainers/go-digest/LICENSE.code rename to vendor/github.com/opencontainers/go-digest/LICENSE diff --git a/vendor/github.com/opencontainers/go-digest/README.md b/vendor/github.com/opencontainers/go-digest/README.md index d65261e20..25aac3470 100644 --- a/vendor/github.com/opencontainers/go-digest/README.md +++ b/vendor/github.com/opencontainers/go-digest/README.md @@ -88,17 +88,17 @@ the alternatives you tried before submitting a PR. # Reporting security issues -The maintainers take security seriously. If you discover a security -issue, please bring it to their attention right away! +Please DO NOT file a public issue, instead send your report privately to +security@opencontainers.org. -Please DO NOT file a public issue, instead send your report privately -to security@docker.com. +The maintainers take security seriously. If you discover a security issue, +please bring it to their attention right away! -Security reports are greatly appreciated and we will publicly thank you -for it. We also like to send gifts—if you're into Docker schwag, make -sure to let us know. We currently do not offer a paid security bounty -program, but are not ruling it out in the future. +If you are reporting a security issue, do not create an issue or file a pull +request on GitHub. Instead, disclose the issue responsibly by sending an email +to security@opencontainers.org (which is inhabited only by the maintainers of +the various OCI projects). # Copyright and license -Copyright © 2016 Docker, Inc. All rights reserved, except as follows. Code is released under the [Apache 2.0 license](LICENSE.code). This `README.md` file and the [`CONTRIBUTING.md`](CONTRIBUTING.md) file are licensed under the Creative Commons Attribution 4.0 International License under the terms and conditions set forth in the file [`LICENSE.docs`](LICENSE.docs). You may obtain a duplicate copy of the same license, titled CC BY-SA 4.0, at http://creativecommons.org/licenses/by-sa/4.0/. +Copyright © 2016 Docker, Inc. All rights reserved, except as follows. Code is released under the [Apache 2.0 license](LICENSE). This `README.md` file and the [`CONTRIBUTING.md`](CONTRIBUTING.md) file are licensed under the Creative Commons Attribution 4.0 International License under the terms and conditions set forth in the file [`LICENSE.docs`](LICENSE.docs). You may obtain a duplicate copy of the same license, titled CC BY-SA 4.0, at http://creativecommons.org/licenses/by-sa/4.0/. diff --git a/vendor/github.com/opencontainers/go-digest/algorithm.go b/vendor/github.com/opencontainers/go-digest/algorithm.go index a3c44801d..8813bd26f 100644 --- a/vendor/github.com/opencontainers/go-digest/algorithm.go +++ b/vendor/github.com/opencontainers/go-digest/algorithm.go @@ -1,3 +1,17 @@ +// Copyright 2017 Docker, Inc. +// +// 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 +// +// https://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 digest import ( @@ -5,6 +19,7 @@ import ( "fmt" "hash" "io" + "regexp" ) // Algorithm identifies and implementation of a digester by an identifier. @@ -14,9 +29,9 @@ type Algorithm string // supported digest types const ( - SHA256 Algorithm = "sha256" // sha256 with hex encoding - SHA384 Algorithm = "sha384" // sha384 with hex encoding - SHA512 Algorithm = "sha512" // sha512 with hex encoding + SHA256 Algorithm = "sha256" // sha256 with hex encoding (lower case only) + SHA384 Algorithm = "sha384" // sha384 with hex encoding (lower case only) + SHA512 Algorithm = "sha512" // sha512 with hex encoding (lower case only) // Canonical is the primary digest algorithm used with the distribution // project. Other digests may be used but this one is the primary storage @@ -36,6 +51,14 @@ var ( SHA384: crypto.SHA384, SHA512: crypto.SHA512, } + + // anchoredEncodedRegexps contains anchored regular expressions for hex-encoded digests. + // Note that /A-F/ disallowed. + anchoredEncodedRegexps = map[Algorithm]*regexp.Regexp{ + SHA256: regexp.MustCompile(`^[a-f0-9]{64}$`), + SHA384: regexp.MustCompile(`^[a-f0-9]{96}$`), + SHA512: regexp.MustCompile(`^[a-f0-9]{128}$`), + } ) // Available returns true if the digest type is available for use. If this @@ -111,6 +134,14 @@ func (a Algorithm) Hash() hash.Hash { return algorithms[a].New() } +// Encode encodes the raw bytes of a digest, typically from a hash.Hash, into +// the encoded portion of the digest. +func (a Algorithm) Encode(d []byte) string { + // TODO(stevvooe): Currently, all algorithms use a hex encoding. When we + // add support for back registration, we can modify this accordingly. + return fmt.Sprintf("%x", d) +} + // FromReader returns the digest of the reader using the algorithm. func (a Algorithm) FromReader(rd io.Reader) (Digest, error) { digester := a.Digester() @@ -142,3 +173,20 @@ func (a Algorithm) FromBytes(p []byte) Digest { func (a Algorithm) FromString(s string) Digest { return a.FromBytes([]byte(s)) } + +// Validate validates the encoded portion string +func (a Algorithm) Validate(encoded string) error { + r, ok := anchoredEncodedRegexps[a] + if !ok { + return ErrDigestUnsupported + } + // Digests much always be hex-encoded, ensuring that their hex portion will + // always be size*2 + if a.Size()*2 != len(encoded) { + return ErrDigestInvalidLength + } + if r.MatchString(encoded) { + return nil + } + return ErrDigestInvalidFormat +} diff --git a/vendor/github.com/opencontainers/go-digest/digest.go b/vendor/github.com/opencontainers/go-digest/digest.go index 7c66c30c0..ad398cba2 100644 --- a/vendor/github.com/opencontainers/go-digest/digest.go +++ b/vendor/github.com/opencontainers/go-digest/digest.go @@ -1,3 +1,17 @@ +// Copyright 2017 Docker, Inc. +// +// 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 +// +// https://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 digest import ( @@ -31,16 +45,21 @@ func NewDigest(alg Algorithm, h hash.Hash) Digest { // functions. This is also useful for rebuilding digests from binary // serializations. func NewDigestFromBytes(alg Algorithm, p []byte) Digest { - return Digest(fmt.Sprintf("%s:%x", alg, p)) + return NewDigestFromEncoded(alg, alg.Encode(p)) } -// NewDigestFromHex returns a Digest from alg and a the hex encoded digest. +// NewDigestFromHex is deprecated. Please use NewDigestFromEncoded. func NewDigestFromHex(alg, hex string) Digest { - return Digest(fmt.Sprintf("%s:%s", alg, hex)) + return NewDigestFromEncoded(Algorithm(alg), hex) +} + +// NewDigestFromEncoded returns a Digest from alg and the encoded digest. +func NewDigestFromEncoded(alg Algorithm, encoded string) Digest { + return Digest(fmt.Sprintf("%s:%s", alg, encoded)) } // DigestRegexp matches valid digest types. -var DigestRegexp = regexp.MustCompile(`[a-zA-Z0-9-_+.]+:[a-fA-F0-9]+`) +var DigestRegexp = regexp.MustCompile(`[a-z0-9]+(?:[.+_-][a-z0-9]+)*:[a-zA-Z0-9=_-]+`) // DigestRegexpAnchored matches valid digest types, anchored to the start and end of the match. var DigestRegexpAnchored = regexp.MustCompile(`^` + DigestRegexp.String() + `$`) @@ -82,26 +101,18 @@ func FromString(s string) Digest { // error if not. func (d Digest) Validate() error { s := string(d) - i := strings.Index(s, ":") - - // validate i then run through regexp - if i < 0 || i+1 == len(s) || !DigestRegexpAnchored.MatchString(s) { + if i <= 0 || i+1 == len(s) { return ErrDigestInvalidFormat } - - algorithm := Algorithm(s[:i]) + algorithm, encoded := Algorithm(s[:i]), s[i+1:] if !algorithm.Available() { + if !DigestRegexpAnchored.MatchString(s) { + return ErrDigestInvalidFormat + } return ErrDigestUnsupported } - - // Digests much always be hex-encoded, ensuring that their hex portion will - // always be size*2 - if algorithm.Size()*2 != len(s[i+1:]) { - return ErrDigestInvalidLength - } - - return nil + return algorithm.Validate(encoded) } // Algorithm returns the algorithm portion of the digest. This will panic if @@ -119,12 +130,17 @@ func (d Digest) Verifier() Verifier { } } -// Hex returns the hex digest portion of the digest. This will panic if the +// Encoded returns the encoded portion of the digest. This will panic if the // underlying digest is not in a valid format. -func (d Digest) Hex() string { +func (d Digest) Encoded() string { return string(d[d.sepIndex()+1:]) } +// Hex is deprecated. Please use Digest.Encoded. +func (d Digest) Hex() string { + return d.Encoded() +} + func (d Digest) String() string { return string(d) } diff --git a/vendor/github.com/opencontainers/go-digest/digester.go b/vendor/github.com/opencontainers/go-digest/digester.go index 918a3f919..36fa2728e 100644 --- a/vendor/github.com/opencontainers/go-digest/digester.go +++ b/vendor/github.com/opencontainers/go-digest/digester.go @@ -1,3 +1,17 @@ +// Copyright 2017 Docker, Inc. +// +// 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 +// +// https://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 digest import "hash" diff --git a/vendor/github.com/opencontainers/go-digest/doc.go b/vendor/github.com/opencontainers/go-digest/doc.go index f64b0db32..491ea1ef1 100644 --- a/vendor/github.com/opencontainers/go-digest/doc.go +++ b/vendor/github.com/opencontainers/go-digest/doc.go @@ -1,3 +1,17 @@ +// Copyright 2017 Docker, Inc. +// +// 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 +// +// https://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 digest provides a generalized type to opaquely represent message // digests and their operations within the registry. The Digest type is // designed to serve as a flexible identifier in a content-addressable system. diff --git a/vendor/github.com/opencontainers/go-digest/verifiers.go b/vendor/github.com/opencontainers/go-digest/verifiers.go index f1db6cda8..32125e918 100644 --- a/vendor/github.com/opencontainers/go-digest/verifiers.go +++ b/vendor/github.com/opencontainers/go-digest/verifiers.go @@ -1,3 +1,17 @@ +// Copyright 2017 Docker, Inc. +// +// 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 +// +// https://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 digest import ( diff --git a/vendor/golang.org/x/net/context/context.go b/vendor/golang.org/x/net/context/context.go index f143ed6a1..d3681ab42 100644 --- a/vendor/golang.org/x/net/context/context.go +++ b/vendor/golang.org/x/net/context/context.go @@ -36,103 +36,6 @@ // Contexts. package context // import "golang.org/x/net/context" -import "time" - -// A Context carries a deadline, a cancelation signal, and other values across -// API boundaries. -// -// Context's methods may be called by multiple goroutines simultaneously. -type Context interface { - // Deadline returns the time when work done on behalf of this context - // should be canceled. Deadline returns ok==false when no deadline is - // set. Successive calls to Deadline return the same results. - Deadline() (deadline time.Time, ok bool) - - // Done returns a channel that's closed when work done on behalf of this - // context should be canceled. Done may return nil if this context can - // never be canceled. Successive calls to Done return the same value. - // - // WithCancel arranges for Done to be closed when cancel is called; - // WithDeadline arranges for Done to be closed when the deadline - // expires; WithTimeout arranges for Done to be closed when the timeout - // elapses. - // - // Done is provided for use in select statements: - // - // // Stream generates values with DoSomething and sends them to out - // // until DoSomething returns an error or ctx.Done is closed. - // func Stream(ctx context.Context, out chan<- Value) error { - // for { - // v, err := DoSomething(ctx) - // if err != nil { - // return err - // } - // select { - // case <-ctx.Done(): - // return ctx.Err() - // case out <- v: - // } - // } - // } - // - // See http://blog.golang.org/pipelines for more examples of how to use - // a Done channel for cancelation. - Done() <-chan struct{} - - // Err returns a non-nil error value after Done is closed. Err returns - // Canceled if the context was canceled or DeadlineExceeded if the - // context's deadline passed. No other values for Err are defined. - // After Done is closed, successive calls to Err return the same value. - Err() error - - // Value returns the value associated with this context for key, or nil - // if no value is associated with key. Successive calls to Value with - // the same key returns the same result. - // - // Use context values only for request-scoped data that transits - // processes and API boundaries, not for passing optional parameters to - // functions. - // - // A key identifies a specific value in a Context. Functions that wish - // to store values in Context typically allocate a key in a global - // variable then use that key as the argument to context.WithValue and - // Context.Value. A key can be any type that supports equality; - // packages should define keys as an unexported type to avoid - // collisions. - // - // Packages that define a Context key should provide type-safe accessors - // for the values stores using that key: - // - // // Package user defines a User type that's stored in Contexts. - // package user - // - // import "golang.org/x/net/context" - // - // // User is the type of value stored in the Contexts. - // type User struct {...} - // - // // key is an unexported type for keys defined in this package. - // // This prevents collisions with keys defined in other packages. - // type key int - // - // // userKey is the key for user.User values in Contexts. It is - // // unexported; clients use user.NewContext and user.FromContext - // // instead of using this key directly. - // var userKey key = 0 - // - // // NewContext returns a new Context that carries value u. - // func NewContext(ctx context.Context, u *User) context.Context { - // return context.WithValue(ctx, userKey, u) - // } - // - // // FromContext returns the User value stored in ctx, if any. - // func FromContext(ctx context.Context) (*User, bool) { - // u, ok := ctx.Value(userKey).(*User) - // return u, ok - // } - Value(key interface{}) interface{} -} - // Background returns a non-nil, empty Context. It is never canceled, has no // values, and has no deadline. It is typically used by the main function, // initialization, and tests, and as the top-level Context for incoming @@ -149,8 +52,3 @@ func Background() Context { func TODO() Context { return todo } - -// A CancelFunc tells an operation to abandon its work. -// A CancelFunc does not wait for the work to stop. -// After the first call, subsequent calls to a CancelFunc do nothing. -type CancelFunc func() diff --git a/vendor/golang.org/x/net/context/go19.go b/vendor/golang.org/x/net/context/go19.go new file mode 100644 index 000000000..d88bd1db1 --- /dev/null +++ b/vendor/golang.org/x/net/context/go19.go @@ -0,0 +1,20 @@ +// Copyright 2017 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +// +build go1.9 + +package context + +import "context" // standard library's context, as of Go 1.7 + +// A Context carries a deadline, a cancelation signal, and other values across +// API boundaries. +// +// Context's methods may be called by multiple goroutines simultaneously. +type Context = context.Context + +// A CancelFunc tells an operation to abandon its work. +// A CancelFunc does not wait for the work to stop. +// After the first call, subsequent calls to a CancelFunc do nothing. +type CancelFunc = context.CancelFunc diff --git a/vendor/golang.org/x/net/context/pre_go19.go b/vendor/golang.org/x/net/context/pre_go19.go new file mode 100644 index 000000000..b105f80be --- /dev/null +++ b/vendor/golang.org/x/net/context/pre_go19.go @@ -0,0 +1,109 @@ +// Copyright 2014 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +// +build !go1.9 + +package context + +import "time" + +// A Context carries a deadline, a cancelation signal, and other values across +// API boundaries. +// +// Context's methods may be called by multiple goroutines simultaneously. +type Context interface { + // Deadline returns the time when work done on behalf of this context + // should be canceled. Deadline returns ok==false when no deadline is + // set. Successive calls to Deadline return the same results. + Deadline() (deadline time.Time, ok bool) + + // Done returns a channel that's closed when work done on behalf of this + // context should be canceled. Done may return nil if this context can + // never be canceled. Successive calls to Done return the same value. + // + // WithCancel arranges for Done to be closed when cancel is called; + // WithDeadline arranges for Done to be closed when the deadline + // expires; WithTimeout arranges for Done to be closed when the timeout + // elapses. + // + // Done is provided for use in select statements: + // + // // Stream generates values with DoSomething and sends them to out + // // until DoSomething returns an error or ctx.Done is closed. + // func Stream(ctx context.Context, out chan<- Value) error { + // for { + // v, err := DoSomething(ctx) + // if err != nil { + // return err + // } + // select { + // case <-ctx.Done(): + // return ctx.Err() + // case out <- v: + // } + // } + // } + // + // See http://blog.golang.org/pipelines for more examples of how to use + // a Done channel for cancelation. + Done() <-chan struct{} + + // Err returns a non-nil error value after Done is closed. Err returns + // Canceled if the context was canceled or DeadlineExceeded if the + // context's deadline passed. No other values for Err are defined. + // After Done is closed, successive calls to Err return the same value. + Err() error + + // Value returns the value associated with this context for key, or nil + // if no value is associated with key. Successive calls to Value with + // the same key returns the same result. + // + // Use context values only for request-scoped data that transits + // processes and API boundaries, not for passing optional parameters to + // functions. + // + // A key identifies a specific value in a Context. Functions that wish + // to store values in Context typically allocate a key in a global + // variable then use that key as the argument to context.WithValue and + // Context.Value. A key can be any type that supports equality; + // packages should define keys as an unexported type to avoid + // collisions. + // + // Packages that define a Context key should provide type-safe accessors + // for the values stores using that key: + // + // // Package user defines a User type that's stored in Contexts. + // package user + // + // import "golang.org/x/net/context" + // + // // User is the type of value stored in the Contexts. + // type User struct {...} + // + // // key is an unexported type for keys defined in this package. + // // This prevents collisions with keys defined in other packages. + // type key int + // + // // userKey is the key for user.User values in Contexts. It is + // // unexported; clients use user.NewContext and user.FromContext + // // instead of using this key directly. + // var userKey key = 0 + // + // // NewContext returns a new Context that carries value u. + // func NewContext(ctx context.Context, u *User) context.Context { + // return context.WithValue(ctx, userKey, u) + // } + // + // // FromContext returns the User value stored in ctx, if any. + // func FromContext(ctx context.Context) (*User, bool) { + // u, ok := ctx.Value(userKey).(*User) + // return u, ok + // } + Value(key interface{}) interface{} +} + +// A CancelFunc tells an operation to abandon its work. +// A CancelFunc does not wait for the work to stop. +// After the first call, subsequent calls to a CancelFunc do nothing. +type CancelFunc func() diff --git a/vendor/golang.org/x/net/http2/configure_transport.go b/vendor/golang.org/x/net/http2/configure_transport.go index 4f720f530..b65fc6d42 100644 --- a/vendor/golang.org/x/net/http2/configure_transport.go +++ b/vendor/golang.org/x/net/http2/configure_transport.go @@ -56,7 +56,7 @@ func configureTransport(t1 *http.Transport) (*Transport, error) { } // registerHTTPSProtocol calls Transport.RegisterProtocol but -// convering panics into errors. +// converting panics into errors. func registerHTTPSProtocol(t *http.Transport, rt http.RoundTripper) (err error) { defer func() { if e := recover(); e != nil { diff --git a/vendor/golang.org/x/net/http2/errors.go b/vendor/golang.org/x/net/http2/errors.go index 20fd7626a..71f2c4631 100644 --- a/vendor/golang.org/x/net/http2/errors.go +++ b/vendor/golang.org/x/net/http2/errors.go @@ -87,13 +87,16 @@ type goAwayFlowError struct{} func (goAwayFlowError) Error() string { return "connection exceeded flow control window size" } -// connErrorReason wraps a ConnectionError with an informative error about why it occurs. - +// connError represents an HTTP/2 ConnectionError error code, along +// with a string (for debugging) explaining why. +// // Errors of this type are only returned by the frame parser functions -// and converted into ConnectionError(ErrCodeProtocol). +// and converted into ConnectionError(Code), after stashing away +// the Reason into the Framer's errDetail field, accessible via +// the (*Framer).ErrorDetail method. type connError struct { - Code ErrCode - Reason string + Code ErrCode // the ConnectionError error code + Reason string // additional reason } func (e connError) Error() string { diff --git a/vendor/golang.org/x/net/http2/go18.go b/vendor/golang.org/x/net/http2/go18.go index 73cc2381f..4f30d228a 100644 --- a/vendor/golang.org/x/net/http2/go18.go +++ b/vendor/golang.org/x/net/http2/go18.go @@ -52,3 +52,5 @@ func reqGetBody(req *http.Request) func() (io.ReadCloser, error) { func reqBodyIsNoBody(body io.ReadCloser) bool { return body == http.NoBody } + +func go18httpNoBody() io.ReadCloser { return http.NoBody } // for tests only diff --git a/vendor/golang.org/x/net/http2/http2.go b/vendor/golang.org/x/net/http2/http2.go index b6b0f9ad1..d565f40e0 100644 --- a/vendor/golang.org/x/net/http2/http2.go +++ b/vendor/golang.org/x/net/http2/http2.go @@ -376,12 +376,16 @@ func (s *sorter) SortStrings(ss []string) { // validPseudoPath reports whether v is a valid :path pseudo-header // value. It must be either: // -// *) a non-empty string starting with '/', but not with with "//", +// *) a non-empty string starting with '/' // *) the string '*', for OPTIONS requests. // // For now this is only used a quick check for deciding when to clean // up Opaque URLs before sending requests from the Transport. // See golang.org/issue/16847 +// +// We used to enforce that the path also didn't start with "//", but +// Google's GFE accepts such paths and Chrome sends them, so ignore +// that part of the spec. See golang.org/issue/19103. func validPseudoPath(v string) bool { - return (len(v) > 0 && v[0] == '/' && (len(v) == 1 || v[1] != '/')) || v == "*" + return (len(v) > 0 && v[0] == '/') || v == "*" } diff --git a/vendor/golang.org/x/net/http2/not_go18.go b/vendor/golang.org/x/net/http2/not_go18.go index efbf83c32..6f8d3f86f 100644 --- a/vendor/golang.org/x/net/http2/not_go18.go +++ b/vendor/golang.org/x/net/http2/not_go18.go @@ -25,3 +25,5 @@ func reqGetBody(req *http.Request) func() (io.ReadCloser, error) { } func reqBodyIsNoBody(io.ReadCloser) bool { return false } + +func go18httpNoBody() io.ReadCloser { return nil } // for tests only diff --git a/vendor/golang.org/x/net/http2/pipe.go b/vendor/golang.org/x/net/http2/pipe.go index 0b9848be8..a6140099c 100644 --- a/vendor/golang.org/x/net/http2/pipe.go +++ b/vendor/golang.org/x/net/http2/pipe.go @@ -50,7 +50,7 @@ func (p *pipe) Read(d []byte) (n int, err error) { if p.breakErr != nil { return 0, p.breakErr } - if p.b.Len() > 0 { + if p.b != nil && p.b.Len() > 0 { return p.b.Read(d) } if p.err != nil { diff --git a/vendor/golang.org/x/net/http2/server.go b/vendor/golang.org/x/net/http2/server.go index 7367b31c5..eae143ddf 100644 --- a/vendor/golang.org/x/net/http2/server.go +++ b/vendor/golang.org/x/net/http2/server.go @@ -2252,6 +2252,7 @@ type responseWriterState struct { wroteHeader bool // WriteHeader called (explicitly or implicitly). Not necessarily sent to user yet. sentHeader bool // have we sent the header frame? handlerDone bool // handler has finished + dirty bool // a Write failed; don't reuse this responseWriterState sentContentLen int64 // non-zero if handler set a Content-Length header wroteBytes int64 @@ -2333,6 +2334,7 @@ func (rws *responseWriterState) writeChunk(p []byte) (n int, err error) { date: date, }) if err != nil { + rws.dirty = true return 0, err } if endStream { @@ -2354,6 +2356,7 @@ func (rws *responseWriterState) writeChunk(p []byte) (n int, err error) { if len(p) > 0 || endStream { // only send a 0 byte DATA frame if we're ending the stream. if err := rws.conn.writeDataFromHandler(rws.stream, p, endStream); err != nil { + rws.dirty = true return 0, err } } @@ -2365,6 +2368,9 @@ func (rws *responseWriterState) writeChunk(p []byte) (n int, err error) { trailers: rws.trailers, endStream: true, }) + if err != nil { + rws.dirty = true + } return len(p), err } return len(p), nil @@ -2504,7 +2510,7 @@ func cloneHeader(h http.Header) http.Header { // // * Handler calls w.Write or w.WriteString -> // * -> rws.bw (*bufio.Writer) -> -// * (Handler migth call Flush) +// * (Handler might call Flush) // * -> chunkWriter{rws} // * -> responseWriterState.writeChunk(p []byte) // * -> responseWriterState.writeChunk (most of the magic; see comment there) @@ -2543,10 +2549,19 @@ func (w *responseWriter) write(lenData int, dataB []byte, dataS string) (n int, func (w *responseWriter) handlerDone() { rws := w.rws + dirty := rws.dirty rws.handlerDone = true w.Flush() w.rws = nil - responseWriterStatePool.Put(rws) + if !dirty { + // Only recycle the pool if all prior Write calls to + // the serverConn goroutine completed successfully. If + // they returned earlier due to resets from the peer + // there might still be write goroutines outstanding + // from the serverConn referencing the rws memory. See + // issue 20704. + responseWriterStatePool.Put(rws) + } } // Push errors. diff --git a/vendor/golang.org/x/net/http2/transport.go b/vendor/golang.org/x/net/http2/transport.go index 3a85f25a2..850d7ae09 100644 --- a/vendor/golang.org/x/net/http2/transport.go +++ b/vendor/golang.org/x/net/http2/transport.go @@ -694,7 +694,7 @@ func checkConnHeaders(req *http.Request) error { // req.ContentLength, where 0 actually means zero (not unknown) and -1 // means unknown. func actualContentLength(req *http.Request) int64 { - if req.Body == nil { + if req.Body == nil || reqBodyIsNoBody(req.Body) { return 0 } if req.ContentLength != 0 { @@ -725,8 +725,8 @@ func (cc *ClientConn) RoundTrip(req *http.Request) (*http.Response, error) { } body := req.Body - hasBody := body != nil contentLen := actualContentLength(req) + hasBody := contentLen != 0 // TODO(bradfitz): this is a copy of the logic in net/http. Unify somewhere? var requestedGzip bool @@ -1713,16 +1713,27 @@ func (rl *clientConnReadLoop) processData(f *DataFrame) error { } // Return any padded flow control now, since we won't // refund it later on body reads. - if pad := int32(f.Length) - int32(len(data)); pad > 0 { - cs.inflow.add(pad) - cc.inflow.add(pad) + var refund int + if pad := int(f.Length) - len(data); pad > 0 { + refund += pad + } + // Return len(data) now if the stream is already closed, + // since data will never be read. + didReset := cs.didReset + if didReset { + refund += len(data) + } + if refund > 0 { + cc.inflow.add(int32(refund)) cc.wmu.Lock() - cc.fr.WriteWindowUpdate(0, uint32(pad)) - cc.fr.WriteWindowUpdate(cs.ID, uint32(pad)) + cc.fr.WriteWindowUpdate(0, uint32(refund)) + if !didReset { + cs.inflow.add(int32(refund)) + cc.fr.WriteWindowUpdate(cs.ID, uint32(refund)) + } cc.bw.Flush() cc.wmu.Unlock() } - didReset := cs.didReset cc.mu.Unlock() if len(data) > 0 && !didReset { diff --git a/vendor/golang.org/x/net/idna/idna.go b/vendor/golang.org/x/net/idna/idna.go index ee2dbda6d..eb2473507 100644 --- a/vendor/golang.org/x/net/idna/idna.go +++ b/vendor/golang.org/x/net/idna/idna.go @@ -67,6 +67,15 @@ func VerifyDNSLength(verify bool) Option { return func(o *options) { o.verifyDNSLength = verify } } +// RemoveLeadingDots removes leading label separators. Leading runes that map to +// dots, such as U+3002, are removed as well. +// +// This is the behavior suggested by the UTS #46 and is adopted by some +// browsers. +func RemoveLeadingDots(remove bool) Option { + return func(o *options) { o.removeLeadingDots = remove } +} + // ValidateLabels sets whether to check the mandatory label validation criteria // as defined in Section 5.4 of RFC 5891. This includes testing for correct use // of hyphens ('-'), normalization, validity of runes, and the context rules. @@ -133,14 +142,16 @@ func MapForLookup() Option { o.mapping = validateAndMap StrictDomainName(true)(o) ValidateLabels(true)(o) + RemoveLeadingDots(true)(o) } } type options struct { - transitional bool - useSTD3Rules bool - validateLabels bool - verifyDNSLength bool + transitional bool + useSTD3Rules bool + validateLabels bool + verifyDNSLength bool + removeLeadingDots bool trie *idnaTrie @@ -240,21 +251,23 @@ var ( punycode = &Profile{} lookup = &Profile{options{ - transitional: true, - useSTD3Rules: true, - validateLabels: true, - trie: trie, - fromPuny: validateFromPunycode, - mapping: validateAndMap, - bidirule: bidirule.ValidString, + transitional: true, + useSTD3Rules: true, + validateLabels: true, + removeLeadingDots: true, + trie: trie, + fromPuny: validateFromPunycode, + mapping: validateAndMap, + bidirule: bidirule.ValidString, }} display = &Profile{options{ - useSTD3Rules: true, - validateLabels: true, - trie: trie, - fromPuny: validateFromPunycode, - mapping: validateAndMap, - bidirule: bidirule.ValidString, + useSTD3Rules: true, + validateLabels: true, + removeLeadingDots: true, + trie: trie, + fromPuny: validateFromPunycode, + mapping: validateAndMap, + bidirule: bidirule.ValidString, }} registration = &Profile{options{ useSTD3Rules: true, @@ -293,7 +306,9 @@ func (p *Profile) process(s string, toASCII bool) (string, error) { s, err = p.mapping(p, s) } // Remove leading empty labels. - for ; len(s) > 0 && s[0] == '.'; s = s[1:] { + if p.removeLeadingDots { + for ; len(s) > 0 && s[0] == '.'; s = s[1:] { + } } // It seems like we should only create this error on ToASCII, but the // UTS 46 conformance tests suggests we should always check this. @@ -373,23 +388,20 @@ func validateRegistration(p *Profile, s string) (string, error) { if !norm.NFC.IsNormalString(s) { return s, &labelError{s, "V1"} } - var err error for i := 0; i < len(s); { v, sz := trie.lookupString(s[i:]) - i += sz // Copy bytes not copied so far. switch p.simplify(info(v).category()) { // TODO: handle the NV8 defined in the Unicode idna data set to allow // for strict conformance to IDNA2008. case valid, deviation: case disallowed, mapped, unknown, ignored: - if err == nil { - r, _ := utf8.DecodeRuneInString(s[i:]) - err = runeError(r) - } + r, _ := utf8.DecodeRuneInString(s[i:]) + return s, runeError(r) } + i += sz } - return s, err + return s, nil } func validateAndMap(p *Profile, s string) (string, error) { @@ -408,7 +420,7 @@ func validateAndMap(p *Profile, s string) (string, error) { continue case disallowed: if err == nil { - r, _ := utf8.DecodeRuneInString(s[i:]) + r, _ := utf8.DecodeRuneInString(s[start:]) err = runeError(r) } continue diff --git a/vendor/golang.org/x/net/trace/events.go b/vendor/golang.org/x/net/trace/events.go index d8daec1a7..c646a6952 100644 --- a/vendor/golang.org/x/net/trace/events.go +++ b/vendor/golang.org/x/net/trace/events.go @@ -39,9 +39,9 @@ var buckets = []bucket{ } // RenderEvents renders the HTML page typically served at /debug/events. -// It does not do any auth checking; see AuthRequest for the default auth check -// used by the handler registered on http.DefaultServeMux. -// req may be nil. +// It does not do any auth checking. The request may be nil. +// +// Most users will use the Events handler. func RenderEvents(w http.ResponseWriter, req *http.Request, sensitive bool) { now := time.Now() data := &struct { diff --git a/vendor/golang.org/x/net/trace/trace.go b/vendor/golang.org/x/net/trace/trace.go index 3d9b64611..bb72a527e 100644 --- a/vendor/golang.org/x/net/trace/trace.go +++ b/vendor/golang.org/x/net/trace/trace.go @@ -110,30 +110,46 @@ var AuthRequest = func(req *http.Request) (any, sensitive bool) { } func init() { - http.HandleFunc("/debug/requests", func(w http.ResponseWriter, req *http.Request) { - any, sensitive := AuthRequest(req) - if !any { - http.Error(w, "not allowed", http.StatusUnauthorized) - return - } - w.Header().Set("Content-Type", "text/html; charset=utf-8") - Render(w, req, sensitive) - }) - http.HandleFunc("/debug/events", func(w http.ResponseWriter, req *http.Request) { - any, sensitive := AuthRequest(req) - if !any { - http.Error(w, "not allowed", http.StatusUnauthorized) - return - } - w.Header().Set("Content-Type", "text/html; charset=utf-8") - RenderEvents(w, req, sensitive) - }) + // TODO(jbd): Serve Traces from /debug/traces in the future? + // There is no requirement for a request to be present to have traces. + http.HandleFunc("/debug/requests", Traces) + http.HandleFunc("/debug/events", Events) +} + +// Traces responds with traces from the program. +// The package initialization registers it in http.DefaultServeMux +// at /debug/requests. +// +// It performs authorization by running AuthRequest. +func Traces(w http.ResponseWriter, req *http.Request) { + any, sensitive := AuthRequest(req) + if !any { + http.Error(w, "not allowed", http.StatusUnauthorized) + return + } + w.Header().Set("Content-Type", "text/html; charset=utf-8") + Render(w, req, sensitive) +} + +// Events responds with a page of events collected by EventLogs. +// The package initialization registers it in http.DefaultServeMux +// at /debug/events. +// +// It performs authorization by running AuthRequest. +func Events(w http.ResponseWriter, req *http.Request) { + any, sensitive := AuthRequest(req) + if !any { + http.Error(w, "not allowed", http.StatusUnauthorized) + return + } + w.Header().Set("Content-Type", "text/html; charset=utf-8") + RenderEvents(w, req, sensitive) } // Render renders the HTML page typically served at /debug/requests. -// It does not do any auth checking; see AuthRequest for the default auth check -// used by the handler registered on http.DefaultServeMux. -// req may be nil. +// It does not do any auth checking. The request may be nil. +// +// Most users will use the Traces handler. func Render(w io.Writer, req *http.Request, sensitive bool) { data := &struct { Families []string From 4f00103c99f396b9655221f8a4dcdfe284a8eccd Mon Sep 17 00:00:00 2001 From: Lantao Liu Date: Wed, 23 May 2018 10:39:38 -0700 Subject: [PATCH 2/3] Disable restart plugin on GCE. Signed-off-by: Lantao Liu --- cluster/gce/configure.sh | 3 +++ 1 file changed, 3 insertions(+) diff --git a/cluster/gce/configure.sh b/cluster/gce/configure.sh index 636d41078..728e4a4ec 100755 --- a/cluster/gce/configure.sh +++ b/cluster/gce/configure.sh @@ -155,6 +155,9 @@ if [ -n "${network_policy_provider}" ] && [ "${network_policy_provider}" != "non fi log_level="${CONTAINERD_LOG_LEVEL:-"info"}" cat > ${config_path} < Date: Wed, 23 May 2018 11:13:00 -0700 Subject: [PATCH 3/3] Use containerd.WithPullUnpack. Signed-off-by: Lantao Liu --- pkg/server/image_pull.go | 12 +++--------- 1 file changed, 3 insertions(+), 9 deletions(-) diff --git a/pkg/server/image_pull.go b/pkg/server/image_pull.go index aea3db8c9..4db105e06 100644 --- a/pkg/server/image_pull.go +++ b/pkg/server/image_pull.go @@ -100,20 +100,14 @@ func (c *criService) PullImage(ctx context.Context, r *runtime.PullImageRequest) // image has already been converted. isSchema1 := desc.MediaType == containerdimages.MediaTypeDockerSchema1Manifest - // TODO(mikebrow): add truncIndex for image id image, err := c.client.Pull(ctx, ref, containerd.WithSchema1Conversion, containerd.WithResolver(resolver), + containerd.WithPullSnapshotter(c.config.ContainerdConfig.Snapshotter), + containerd.WithPullUnpack, ) if err != nil { - return nil, errors.Wrapf(err, "failed to pull image %q", ref) - } - - // Do best effort unpack. - logrus.Debugf("Unpack image %q", imageRef) - if err := image.Unpack(ctx, c.config.ContainerdConfig.Snapshotter); err != nil { - logrus.WithError(err).Warnf("Failed to unpack image %q", imageRef) - // Do not fail image pulling. Unpack will be retried before container creation. + return nil, errors.Wrapf(err, "failed to pull and unpack image %q", ref) } // Get image information.