From 07d871600437e04553ea197753fa7c21898ce149 Mon Sep 17 00:00:00 2001 From: Darren Stahl Date: Wed, 2 May 2018 16:19:15 -0700 Subject: [PATCH] Update hcsshim to v0.6.10 Signed-off-by: Darren Stahl --- vendor.conf | 2 +- .../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 ++ 13 files changed, 1469 insertions(+), 927 deletions(-) create mode 100644 vendor/github.com/Microsoft/hcsshim/safeopen.go diff --git a/vendor.conf b/vendor.conf index 4c42a6722..2bb147bfc 100644 --- a/vendor.conf +++ b/vendor.conf @@ -34,7 +34,7 @@ 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 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 +}