mirror of https://github.com/docker/cli.git
vndr docker/docker to 53e55db
And update the associated packages that have also updated from docker/docker vendor.conf. Signed-off-by: Andrew Hsu <andrewhsu@docker.com>
This commit is contained in:
parent
0198955105
commit
f6af8b3dfb
14
vendor.conf
14
vendor.conf
|
@ -2,8 +2,8 @@ github.com/agl/ed25519 5312a61534124124185d41f09206b9fef1d88403
|
||||||
github.com/asaskevich/govalidator f9ffefc3facfbe0caee3fea233cbb6e8208f4541
|
github.com/asaskevich/govalidator f9ffefc3facfbe0caee3fea233cbb6e8208f4541
|
||||||
github.com/Azure/go-ansiterm d6e3b3328b783f23731bc4d058875b0371ff8109
|
github.com/Azure/go-ansiterm d6e3b3328b783f23731bc4d058875b0371ff8109
|
||||||
github.com/beorn7/perks 3a771d992973f24aa725d07868b467d1ddfceafb
|
github.com/beorn7/perks 3a771d992973f24aa725d07868b467d1ddfceafb
|
||||||
github.com/containerd/console 4d8a41f4ce5b9bae77c41786ea2458330f43f081
|
github.com/containerd/console c12b1e7919c14469339a5d38f2f8ed9b64a9de23
|
||||||
github.com/containerd/containerd v1.2.0-beta.0
|
github.com/containerd/containerd v1.2.0-beta.2
|
||||||
github.com/containerd/continuity d8fb8589b0e8e85b8c8bbaa8840226d0dfeb7371
|
github.com/containerd/continuity d8fb8589b0e8e85b8c8bbaa8840226d0dfeb7371
|
||||||
github.com/containerd/fifo 3d5202a
|
github.com/containerd/fifo 3d5202a
|
||||||
github.com/containerd/typeurl f694355
|
github.com/containerd/typeurl f694355
|
||||||
|
@ -12,7 +12,7 @@ github.com/cpuguy83/go-md2man v1.0.8
|
||||||
github.com/davecgh/go-spew 346938d642f2ec3594ed81d874461961cd0faa76 # v1.1.0
|
github.com/davecgh/go-spew 346938d642f2ec3594ed81d874461961cd0faa76 # v1.1.0
|
||||||
github.com/dgrijalva/jwt-go a2c85815a77d0f951e33ba4db5ae93629a1530af
|
github.com/dgrijalva/jwt-go a2c85815a77d0f951e33ba4db5ae93629a1530af
|
||||||
github.com/docker/distribution 83389a148052d74ac602f5f1d62f86ff2f3c4aa5
|
github.com/docker/distribution 83389a148052d74ac602f5f1d62f86ff2f3c4aa5
|
||||||
github.com/docker/docker 6ba1e91877691c4043b57c97090668bc4fd874b6
|
github.com/docker/docker 53e55db9d3f0f0910ea95515222c8a35e106f10e
|
||||||
github.com/docker/docker-credential-helpers 5241b46610f2491efdf9d1c85f1ddf5b02f6d962
|
github.com/docker/docker-credential-helpers 5241b46610f2491efdf9d1c85f1ddf5b02f6d962
|
||||||
# the docker/go package contains a customized version of canonical/json
|
# the docker/go package contains a customized version of canonical/json
|
||||||
# and is used by Notary. The package is periodically rebased on current Go versions.
|
# and is used by Notary. The package is periodically rebased on current Go versions.
|
||||||
|
@ -47,18 +47,18 @@ github.com/inconshreveable/mousetrap 76626ae9c91c4f2a10f34cad8ce83ea42c93bb75 #
|
||||||
github.com/json-iterator/go ab8a2e0c74be9d3be70b3184d9acc634935ded82 # 1.1.4
|
github.com/json-iterator/go ab8a2e0c74be9d3be70b3184d9acc634935ded82 # 1.1.4
|
||||||
github.com/mattn/go-shellwords v1.0.3
|
github.com/mattn/go-shellwords v1.0.3
|
||||||
github.com/matttproud/golang_protobuf_extensions v1.0.1
|
github.com/matttproud/golang_protobuf_extensions v1.0.1
|
||||||
github.com/Microsoft/hcsshim v0.6.11
|
github.com/Microsoft/hcsshim 44c060121b68e8bdc40b411beba551f3b4ee9e55
|
||||||
github.com/Microsoft/go-winio v0.4.9
|
github.com/Microsoft/go-winio v0.4.10
|
||||||
github.com/miekg/pkcs11 287d9350987cc9334667882061e202e96cdfb4d0
|
github.com/miekg/pkcs11 287d9350987cc9334667882061e202e96cdfb4d0
|
||||||
github.com/mitchellh/mapstructure f15292f7a699fcc1a38a80977f80a046874ba8ac
|
github.com/mitchellh/mapstructure f15292f7a699fcc1a38a80977f80a046874ba8ac
|
||||||
github.com/moby/buildkit e8c7acc99c33f5e73b8c38f618406392dee59675
|
github.com/moby/buildkit 6812dac65e0440bb75affce1fb2175e640edc15d
|
||||||
github.com/modern-go/concurrent bacd9c7ef1dd9b15be4a9909b8ac7a4e313eec94 # 1.0.3
|
github.com/modern-go/concurrent bacd9c7ef1dd9b15be4a9909b8ac7a4e313eec94 # 1.0.3
|
||||||
github.com/modern-go/reflect2 4b7aa43c6742a2c18fdef89dd197aaae7dac7ccd # 1.0.1
|
github.com/modern-go/reflect2 4b7aa43c6742a2c18fdef89dd197aaae7dac7ccd # 1.0.1
|
||||||
github.com/morikuni/aec 39771216ff4c63d11f5e604076f9c45e8be1067b
|
github.com/morikuni/aec 39771216ff4c63d11f5e604076f9c45e8be1067b
|
||||||
github.com/Nvveen/Gotty a8b993ba6abdb0e0c12b0125c603323a71c7790c https://github.com/ijc25/Gotty
|
github.com/Nvveen/Gotty a8b993ba6abdb0e0c12b0125c603323a71c7790c https://github.com/ijc25/Gotty
|
||||||
github.com/opencontainers/go-digest v1.0.0-rc1
|
github.com/opencontainers/go-digest v1.0.0-rc1
|
||||||
github.com/opencontainers/image-spec v1.0.1
|
github.com/opencontainers/image-spec v1.0.1
|
||||||
github.com/opencontainers/runc ad0f5255060d36872be04de22f8731f38ef2d7b1
|
github.com/opencontainers/runc 20aff4f0488c6d4b8df4d85b4f63f1f704c11abd
|
||||||
github.com/opencontainers/runtime-spec v1.0.1
|
github.com/opencontainers/runtime-spec v1.0.1
|
||||||
github.com/opentracing/opentracing-go 1361b9cd60be79c4c3a7fa9841b3c132e40066a7
|
github.com/opentracing/opentracing-go 1361b9cd60be79c4c3a7fa9841b3c132e40066a7
|
||||||
github.com/peterbourgon/diskv 5f041e8faa004a95c88a202771f4cc3e991971e6 # v2.0.1
|
github.com/peterbourgon/diskv 5f041e8faa004a95c88a202771f4cc3e991971e6 # v2.0.1
|
||||||
|
|
|
@ -20,7 +20,8 @@ const (
|
||||||
// FileBasicInfo contains file access time and file attributes information.
|
// FileBasicInfo contains file access time and file attributes information.
|
||||||
type FileBasicInfo struct {
|
type FileBasicInfo struct {
|
||||||
CreationTime, LastAccessTime, LastWriteTime, ChangeTime syscall.Filetime
|
CreationTime, LastAccessTime, LastWriteTime, ChangeTime syscall.Filetime
|
||||||
FileAttributes uintptr // includes padding
|
FileAttributes uint32
|
||||||
|
pad uint32 // padding
|
||||||
}
|
}
|
||||||
|
|
||||||
// GetFileBasicInfo retrieves times and attributes for a file.
|
// GetFileBasicInfo retrieves times and attributes for a file.
|
||||||
|
|
|
@ -1,12 +1,13 @@
|
||||||
# hcsshim
|
# hcsshim
|
||||||
|
|
||||||
This package supports launching Windows Server containers from Go. It is
|
[![Build status](https://ci.appveyor.com/api/projects/status/nbcw28mnkqml0loa/branch/master?svg=true)](https://ci.appveyor.com/project/WindowsVirtualization/hcsshim/branch/master)
|
||||||
primarily used in the [Docker Engine](https://github.com/docker/docker) project,
|
|
||||||
but it can be freely used by other projects as well.
|
|
||||||
|
|
||||||
|
This package contains the Golang interface for using the Windows [Host Compute Service](https://blogs.technet.microsoft.com/virtualization/2017/01/27/introducing-the-host-compute-service-hcs/) (HCS) to launch and manage [Windows Containers](https://docs.microsoft.com/en-us/virtualization/windowscontainers/about/). It also contains other helpers and functions for managing Windows Containers such as the Golang interface for the Host Network Service (HNS).
|
||||||
|
|
||||||
|
It is primarily used in the [Moby Project](https://github.com/moby/moby), but it can be freely used by other projects as well.
|
||||||
|
|
||||||
## Contributing
|
## Contributing
|
||||||
---------------
|
|
||||||
This project welcomes contributions and suggestions. Most contributions require you to agree to a
|
This project welcomes contributions and suggestions. Most contributions require you to agree to a
|
||||||
Contributor License Agreement (CLA) declaring that you have the right to, and actually do, grant us
|
Contributor License Agreement (CLA) declaring that you have the right to, and actually do, grant us
|
||||||
the rights to use your contribution. For details, visit https://cla.microsoft.com.
|
the rights to use your contribution. For details, visit https://cla.microsoft.com.
|
||||||
|
@ -19,6 +20,11 @@ This project has adopted the [Microsoft Open Source Code of Conduct](https://ope
|
||||||
For more information see the [Code of Conduct FAQ](https://opensource.microsoft.com/codeofconduct/faq/) or
|
For more information see the [Code of Conduct FAQ](https://opensource.microsoft.com/codeofconduct/faq/) or
|
||||||
contact [opencode@microsoft.com](mailto:opencode@microsoft.com) with any additional questions or comments.
|
contact [opencode@microsoft.com](mailto:opencode@microsoft.com) with any additional questions or comments.
|
||||||
|
|
||||||
|
## Dependencies
|
||||||
|
|
||||||
|
This project requires Golang 1.9 or newer to build.
|
||||||
|
|
||||||
|
For system requirements to run this project, see the Microsoft docs on [Windows Container requirements](https://docs.microsoft.com/en-us/virtualization/windowscontainers/deploy-containers/system-requirements).
|
||||||
|
|
||||||
## Reporting Security Issues
|
## Reporting Security Issues
|
||||||
|
|
||||||
|
@ -29,5 +35,7 @@ email to ensure we received your original message. Further information, includin
|
||||||
[MSRC PGP](https://technet.microsoft.com/en-us/security/dn606155) key, can be found in
|
[MSRC PGP](https://technet.microsoft.com/en-us/security/dn606155) key, can be found in
|
||||||
the [Security TechCenter](https://technet.microsoft.com/en-us/security/default).
|
the [Security TechCenter](https://technet.microsoft.com/en-us/security/default).
|
||||||
|
|
||||||
-------------------------------------------
|
For additional details, see [Report a Computer Security Vulnerability](https://technet.microsoft.com/en-us/security/ff852094.aspx) on Technet
|
||||||
|
|
||||||
|
---------------
|
||||||
Copyright (c) 2018 Microsoft Corp. All rights reserved.
|
Copyright (c) 2018 Microsoft Corp. All rights reserved.
|
||||||
|
|
|
@ -1,28 +0,0 @@
|
||||||
package hcsshim
|
|
||||||
|
|
||||||
import "github.com/sirupsen/logrus"
|
|
||||||
|
|
||||||
// ActivateLayer will find the layer with the given id and mount it's filesystem.
|
|
||||||
// For a read/write layer, the mounted filesystem will appear as a volume on the
|
|
||||||
// host, while a read-only layer is generally expected to be a no-op.
|
|
||||||
// An activated layer must later be deactivated via DeactivateLayer.
|
|
||||||
func ActivateLayer(info DriverInfo, id string) error {
|
|
||||||
title := "hcsshim::ActivateLayer "
|
|
||||||
logrus.Debugf(title+"Flavour %d ID %s", info.Flavour, id)
|
|
||||||
|
|
||||||
infop, err := convertDriverInfo(info)
|
|
||||||
if err != nil {
|
|
||||||
logrus.Error(err)
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
err = activateLayer(&infop, id)
|
|
||||||
if err != nil {
|
|
||||||
err = makeErrorf(err, title, "id=%s flavour=%d", id, info.Flavour)
|
|
||||||
logrus.Error(err)
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
logrus.Debugf(title+" - succeeded id=%s flavour=%d", id, info.Flavour)
|
|
||||||
return nil
|
|
||||||
}
|
|
|
@ -1,800 +1,192 @@
|
||||||
package hcsshim
|
package hcsshim
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"encoding/json"
|
|
||||||
"fmt"
|
"fmt"
|
||||||
"os"
|
"os"
|
||||||
"sync"
|
|
||||||
"syscall"
|
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"github.com/sirupsen/logrus"
|
"github.com/Microsoft/hcsshim/internal/hcs"
|
||||||
|
"github.com/Microsoft/hcsshim/internal/mergemaps"
|
||||||
|
"github.com/Microsoft/hcsshim/internal/schema1"
|
||||||
)
|
)
|
||||||
|
|
||||||
var (
|
|
||||||
defaultTimeout = time.Minute * 4
|
|
||||||
)
|
|
||||||
|
|
||||||
const (
|
|
||||||
pendingUpdatesQuery = `{ "PropertyTypes" : ["PendingUpdates"]}`
|
|
||||||
statisticsQuery = `{ "PropertyTypes" : ["Statistics"]}`
|
|
||||||
processListQuery = `{ "PropertyTypes" : ["ProcessList"]}`
|
|
||||||
mappedVirtualDiskQuery = `{ "PropertyTypes" : ["MappedVirtualDisk"]}`
|
|
||||||
)
|
|
||||||
|
|
||||||
type container struct {
|
|
||||||
handleLock sync.RWMutex
|
|
||||||
handle hcsSystem
|
|
||||||
id string
|
|
||||||
callbackNumber uintptr
|
|
||||||
}
|
|
||||||
|
|
||||||
// ContainerProperties holds the properties for a container and the processes running in that container
|
// ContainerProperties holds the properties for a container and the processes running in that container
|
||||||
type ContainerProperties struct {
|
type ContainerProperties = schema1.ContainerProperties
|
||||||
ID string `json:"Id"`
|
|
||||||
Name string
|
|
||||||
SystemType string
|
|
||||||
Owner string
|
|
||||||
SiloGUID string `json:"SiloGuid,omitempty"`
|
|
||||||
RuntimeID string `json:"RuntimeId,omitempty"`
|
|
||||||
IsRuntimeTemplate bool `json:",omitempty"`
|
|
||||||
RuntimeImagePath string `json:",omitempty"`
|
|
||||||
Stopped bool `json:",omitempty"`
|
|
||||||
ExitType string `json:",omitempty"`
|
|
||||||
AreUpdatesPending bool `json:",omitempty"`
|
|
||||||
ObRoot string `json:",omitempty"`
|
|
||||||
Statistics Statistics `json:",omitempty"`
|
|
||||||
ProcessList []ProcessListItem `json:",omitempty"`
|
|
||||||
MappedVirtualDiskControllers map[int]MappedVirtualDiskController `json:",omitempty"`
|
|
||||||
}
|
|
||||||
|
|
||||||
// MemoryStats holds the memory statistics for a container
|
// MemoryStats holds the memory statistics for a container
|
||||||
type MemoryStats struct {
|
type MemoryStats = schema1.MemoryStats
|
||||||
UsageCommitBytes uint64 `json:"MemoryUsageCommitBytes,omitempty"`
|
|
||||||
UsageCommitPeakBytes uint64 `json:"MemoryUsageCommitPeakBytes,omitempty"`
|
|
||||||
UsagePrivateWorkingSetBytes uint64 `json:"MemoryUsagePrivateWorkingSetBytes,omitempty"`
|
|
||||||
}
|
|
||||||
|
|
||||||
// ProcessorStats holds the processor statistics for a container
|
// ProcessorStats holds the processor statistics for a container
|
||||||
type ProcessorStats struct {
|
type ProcessorStats = schema1.ProcessorStats
|
||||||
TotalRuntime100ns uint64 `json:",omitempty"`
|
|
||||||
RuntimeUser100ns uint64 `json:",omitempty"`
|
|
||||||
RuntimeKernel100ns uint64 `json:",omitempty"`
|
|
||||||
}
|
|
||||||
|
|
||||||
// StorageStats holds the storage statistics for a container
|
// StorageStats holds the storage statistics for a container
|
||||||
type StorageStats struct {
|
type StorageStats = schema1.StorageStats
|
||||||
ReadCountNormalized uint64 `json:",omitempty"`
|
|
||||||
ReadSizeBytes uint64 `json:",omitempty"`
|
|
||||||
WriteCountNormalized uint64 `json:",omitempty"`
|
|
||||||
WriteSizeBytes uint64 `json:",omitempty"`
|
|
||||||
}
|
|
||||||
|
|
||||||
// NetworkStats holds the network statistics for a container
|
// NetworkStats holds the network statistics for a container
|
||||||
type NetworkStats struct {
|
type NetworkStats = schema1.NetworkStats
|
||||||
BytesReceived uint64 `json:",omitempty"`
|
|
||||||
BytesSent uint64 `json:",omitempty"`
|
|
||||||
PacketsReceived uint64 `json:",omitempty"`
|
|
||||||
PacketsSent uint64 `json:",omitempty"`
|
|
||||||
DroppedPacketsIncoming uint64 `json:",omitempty"`
|
|
||||||
DroppedPacketsOutgoing uint64 `json:",omitempty"`
|
|
||||||
EndpointId string `json:",omitempty"`
|
|
||||||
InstanceId string `json:",omitempty"`
|
|
||||||
}
|
|
||||||
|
|
||||||
// Statistics is the structure returned by a statistics call on a container
|
// Statistics is the structure returned by a statistics call on a container
|
||||||
type Statistics struct {
|
type Statistics = schema1.Statistics
|
||||||
Timestamp time.Time `json:",omitempty"`
|
|
||||||
ContainerStartTime time.Time `json:",omitempty"`
|
|
||||||
Uptime100ns uint64 `json:",omitempty"`
|
|
||||||
Memory MemoryStats `json:",omitempty"`
|
|
||||||
Processor ProcessorStats `json:",omitempty"`
|
|
||||||
Storage StorageStats `json:",omitempty"`
|
|
||||||
Network []NetworkStats `json:",omitempty"`
|
|
||||||
}
|
|
||||||
|
|
||||||
// ProcessList is the structure of an item returned by a ProcessList call on a container
|
// ProcessList is the structure of an item returned by a ProcessList call on a container
|
||||||
type ProcessListItem struct {
|
type ProcessListItem = schema1.ProcessListItem
|
||||||
CreateTimestamp time.Time `json:",omitempty"`
|
|
||||||
ImageName string `json:",omitempty"`
|
|
||||||
KernelTime100ns uint64 `json:",omitempty"`
|
|
||||||
MemoryCommitBytes uint64 `json:",omitempty"`
|
|
||||||
MemoryWorkingSetPrivateBytes uint64 `json:",omitempty"`
|
|
||||||
MemoryWorkingSetSharedBytes uint64 `json:",omitempty"`
|
|
||||||
ProcessId uint32 `json:",omitempty"`
|
|
||||||
UserTime100ns uint64 `json:",omitempty"`
|
|
||||||
}
|
|
||||||
|
|
||||||
// MappedVirtualDiskController is the structure of an item returned by a MappedVirtualDiskList call on a container
|
// MappedVirtualDiskController is the structure of an item returned by a MappedVirtualDiskList call on a container
|
||||||
type MappedVirtualDiskController struct {
|
type MappedVirtualDiskController = schema1.MappedVirtualDiskController
|
||||||
MappedVirtualDisks map[int]MappedVirtualDisk `json:",omitempty"`
|
|
||||||
}
|
|
||||||
|
|
||||||
// Type of Request Support in ModifySystem
|
// Type of Request Support in ModifySystem
|
||||||
type RequestType string
|
type RequestType = schema1.RequestType
|
||||||
|
|
||||||
// Type of Resource Support in ModifySystem
|
// Type of Resource Support in ModifySystem
|
||||||
type ResourceType string
|
type ResourceType = schema1.ResourceType
|
||||||
|
|
||||||
// RequestType const
|
// RequestType const
|
||||||
const (
|
const (
|
||||||
Add RequestType = "Add"
|
Add = schema1.Add
|
||||||
Remove RequestType = "Remove"
|
Remove = schema1.Remove
|
||||||
Network ResourceType = "Network"
|
Network = schema1.Network
|
||||||
)
|
)
|
||||||
|
|
||||||
// ResourceModificationRequestResponse is the structure used to send request to the container to modify the system
|
// ResourceModificationRequestResponse 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
|
// Supported resource types are Network and Request Types are Add/Remove
|
||||||
type ResourceModificationRequestResponse struct {
|
type ResourceModificationRequestResponse = schema1.ResourceModificationRequestResponse
|
||||||
Resource ResourceType `json:"ResourceType"`
|
|
||||||
Data interface{} `json:"Settings"`
|
type container struct {
|
||||||
Request RequestType `json:"RequestType,omitempty"`
|
system *hcs.System
|
||||||
}
|
}
|
||||||
|
|
||||||
// createContainerAdditionalJSON is read from the environment at initialisation
|
// createComputeSystemAdditionalJSON is read from the environment at initialisation
|
||||||
// time. It allows an environment variable to define additional JSON which
|
// time. It allows an environment variable to define additional JSON which
|
||||||
// is merged in the CreateContainer call to HCS.
|
// is merged in the CreateComputeSystem call to HCS.
|
||||||
var createContainerAdditionalJSON string
|
var createContainerAdditionalJSON []byte
|
||||||
|
|
||||||
func init() {
|
func init() {
|
||||||
createContainerAdditionalJSON = os.Getenv("HCSSHIM_CREATECONTAINER_ADDITIONALJSON")
|
createContainerAdditionalJSON = ([]byte)(os.Getenv("HCSSHIM_CREATECONTAINER_ADDITIONALJSON"))
|
||||||
}
|
}
|
||||||
|
|
||||||
// CreateContainer creates a new container with the given configuration but does not start it.
|
// CreateContainer creates a new container with the given configuration but does not start it.
|
||||||
func CreateContainer(id string, c *ContainerConfig) (Container, error) {
|
func CreateContainer(id string, c *ContainerConfig) (Container, error) {
|
||||||
return createContainerWithJSON(id, c, "")
|
fullConfig, err := mergemaps.MergeJSON(c, createContainerAdditionalJSON)
|
||||||
}
|
if err != nil {
|
||||||
|
return nil, fmt.Errorf("failed to merge additional JSON '%s': %s", createContainerAdditionalJSON, err)
|
||||||
// CreateContainerWithJSON creates a new container with the given configuration but does not start it.
|
|
||||||
// It is identical to CreateContainer except that optional additional JSON can be merged before passing to HCS.
|
|
||||||
func CreateContainerWithJSON(id string, c *ContainerConfig, additionalJSON string) (Container, error) {
|
|
||||||
return createContainerWithJSON(id, c, additionalJSON)
|
|
||||||
}
|
|
||||||
|
|
||||||
func createContainerWithJSON(id string, c *ContainerConfig, additionalJSON string) (Container, error) {
|
|
||||||
operation := "CreateContainer"
|
|
||||||
title := "HCSShim::" + operation
|
|
||||||
|
|
||||||
container := &container{
|
|
||||||
id: id,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
configurationb, err := json.Marshal(c)
|
system, err := hcs.CreateComputeSystem(id, fullConfig)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
return &container{system}, err
|
||||||
configuration := string(configurationb)
|
|
||||||
logrus.Debugf(title+" id=%s config=%s", id, configuration)
|
|
||||||
|
|
||||||
// Merge any additional JSON. Priority is given to what is passed in explicitly,
|
|
||||||
// falling back to what's set in the environment.
|
|
||||||
if additionalJSON == "" && createContainerAdditionalJSON != "" {
|
|
||||||
additionalJSON = createContainerAdditionalJSON
|
|
||||||
}
|
|
||||||
if additionalJSON != "" {
|
|
||||||
configurationMap := map[string]interface{}{}
|
|
||||||
if err := json.Unmarshal([]byte(configuration), &configurationMap); err != nil {
|
|
||||||
return nil, fmt.Errorf("failed to unmarshal %s: %s", configuration, err)
|
|
||||||
}
|
|
||||||
|
|
||||||
additionalMap := map[string]interface{}{}
|
|
||||||
if err := json.Unmarshal([]byte(additionalJSON), &additionalMap); err != nil {
|
|
||||||
return nil, fmt.Errorf("failed to unmarshal %s: %s", additionalJSON, err)
|
|
||||||
}
|
|
||||||
|
|
||||||
mergedMap := mergeMaps(additionalMap, configurationMap)
|
|
||||||
mergedJSON, err := json.Marshal(mergedMap)
|
|
||||||
if err != nil {
|
|
||||||
return nil, fmt.Errorf("failed to marshal merged configuration map %+v: %s", mergedMap, err)
|
|
||||||
}
|
|
||||||
|
|
||||||
configuration = string(mergedJSON)
|
|
||||||
logrus.Debugf(title+" id=%s merged config=%s", id, configuration)
|
|
||||||
}
|
|
||||||
|
|
||||||
var (
|
|
||||||
resultp *uint16
|
|
||||||
identity syscall.Handle
|
|
||||||
)
|
|
||||||
createError := hcsCreateComputeSystem(id, configuration, identity, &container.handle, &resultp)
|
|
||||||
|
|
||||||
if createError == nil || IsPending(createError) {
|
|
||||||
if err := container.registerCallback(); err != nil {
|
|
||||||
// Terminate the container if it still exists. We're okay to ignore a failure here.
|
|
||||||
container.Terminate()
|
|
||||||
return nil, makeContainerError(container, operation, "", err)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
err = processAsyncHcsResult(createError, resultp, container.callbackNumber, hcsNotificationSystemCreateCompleted, &defaultTimeout)
|
|
||||||
if err != nil {
|
|
||||||
if err == ErrTimeout {
|
|
||||||
// Terminate the container if it still exists. We're okay to ignore a failure here.
|
|
||||||
container.Terminate()
|
|
||||||
}
|
|
||||||
return nil, makeContainerError(container, operation, configuration, err)
|
|
||||||
}
|
|
||||||
|
|
||||||
logrus.Debugf(title+" succeeded id=%s handle=%d", id, container.handle)
|
|
||||||
return container, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// mergeMaps recursively merges map `fromMap` into map `ToMap`. Any pre-existing values
|
|
||||||
// in ToMap are overwritten. Values in fromMap are added to ToMap.
|
|
||||||
// From http://stackoverflow.com/questions/40491438/merging-two-json-strings-in-golang
|
|
||||||
func mergeMaps(fromMap, ToMap interface{}) interface{} {
|
|
||||||
switch fromMap := fromMap.(type) {
|
|
||||||
case map[string]interface{}:
|
|
||||||
ToMap, ok := ToMap.(map[string]interface{})
|
|
||||||
if !ok {
|
|
||||||
return fromMap
|
|
||||||
}
|
|
||||||
for keyToMap, valueToMap := range ToMap {
|
|
||||||
if valueFromMap, ok := fromMap[keyToMap]; ok {
|
|
||||||
fromMap[keyToMap] = mergeMaps(valueFromMap, valueToMap)
|
|
||||||
} else {
|
|
||||||
fromMap[keyToMap] = valueToMap
|
|
||||||
}
|
|
||||||
}
|
|
||||||
case nil:
|
|
||||||
// merge(nil, map[string]interface{...}) -> map[string]interface{...}
|
|
||||||
ToMap, ok := ToMap.(map[string]interface{})
|
|
||||||
if ok {
|
|
||||||
return ToMap
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return fromMap
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// OpenContainer opens an existing container by ID.
|
// OpenContainer opens an existing container by ID.
|
||||||
func OpenContainer(id string) (Container, error) {
|
func OpenContainer(id string) (Container, error) {
|
||||||
operation := "OpenContainer"
|
system, err := hcs.OpenComputeSystem(id)
|
||||||
title := "HCSShim::" + operation
|
|
||||||
logrus.Debugf(title+" id=%s", id)
|
|
||||||
|
|
||||||
container := &container{
|
|
||||||
id: id,
|
|
||||||
}
|
|
||||||
|
|
||||||
var (
|
|
||||||
handle hcsSystem
|
|
||||||
resultp *uint16
|
|
||||||
)
|
|
||||||
err := hcsOpenComputeSystem(id, &handle, &resultp)
|
|
||||||
err = processHcsResult(err, resultp)
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, makeContainerError(container, operation, "", err)
|
return nil, err
|
||||||
}
|
}
|
||||||
|
return &container{system}, err
|
||||||
container.handle = handle
|
|
||||||
|
|
||||||
if err := container.registerCallback(); err != nil {
|
|
||||||
return nil, makeContainerError(container, operation, "", err)
|
|
||||||
}
|
|
||||||
|
|
||||||
logrus.Debugf(title+" succeeded id=%s handle=%d", id, handle)
|
|
||||||
return container, nil
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// GetContainers gets a list of the containers on the system that match the query
|
// GetContainers gets a list of the containers on the system that match the query
|
||||||
func GetContainers(q ComputeSystemQuery) ([]ContainerProperties, error) {
|
func GetContainers(q ComputeSystemQuery) ([]ContainerProperties, error) {
|
||||||
operation := "GetContainers"
|
return hcs.GetComputeSystems(q)
|
||||||
title := "HCSShim::" + operation
|
|
||||||
|
|
||||||
queryb, err := json.Marshal(q)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
query := string(queryb)
|
|
||||||
logrus.Debugf(title+" query=%s", query)
|
|
||||||
|
|
||||||
var (
|
|
||||||
resultp *uint16
|
|
||||||
computeSystemsp *uint16
|
|
||||||
)
|
|
||||||
err = hcsEnumerateComputeSystems(query, &computeSystemsp, &resultp)
|
|
||||||
err = processHcsResult(err, resultp)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
if computeSystemsp == nil {
|
|
||||||
return nil, ErrUnexpectedValue
|
|
||||||
}
|
|
||||||
computeSystemsRaw := convertAndFreeCoTaskMemBytes(computeSystemsp)
|
|
||||||
computeSystems := []ContainerProperties{}
|
|
||||||
if err := json.Unmarshal(computeSystemsRaw, &computeSystems); err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
logrus.Debugf(title + " succeeded")
|
|
||||||
return computeSystems, nil
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Start synchronously starts the container.
|
// Start synchronously starts the container.
|
||||||
func (container *container) Start() error {
|
func (container *container) Start() error {
|
||||||
container.handleLock.RLock()
|
return convertSystemError(container.system.Start(), container)
|
||||||
defer container.handleLock.RUnlock()
|
|
||||||
operation := "Start"
|
|
||||||
title := "HCSShim::Container::" + operation
|
|
||||||
logrus.Debugf(title+" id=%s", container.id)
|
|
||||||
|
|
||||||
if container.handle == 0 {
|
|
||||||
return makeContainerError(container, operation, "", ErrAlreadyClosed)
|
|
||||||
}
|
|
||||||
|
|
||||||
var resultp *uint16
|
|
||||||
err := hcsStartComputeSystem(container.handle, "", &resultp)
|
|
||||||
err = processAsyncHcsResult(err, resultp, container.callbackNumber, hcsNotificationSystemStartCompleted, &defaultTimeout)
|
|
||||||
if err != nil {
|
|
||||||
return makeContainerError(container, operation, "", err)
|
|
||||||
}
|
|
||||||
|
|
||||||
logrus.Debugf(title+" succeeded id=%s", container.id)
|
|
||||||
return nil
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Shutdown requests a container shutdown, if IsPending() on the error returned is true,
|
// Shutdown requests a container shutdown, but it may not actually be shutdown until Wait() succeeds.
|
||||||
// it may not actually be shut down until Wait() succeeds.
|
|
||||||
func (container *container) Shutdown() error {
|
func (container *container) Shutdown() error {
|
||||||
container.handleLock.RLock()
|
return convertSystemError(container.system.Shutdown(), container)
|
||||||
defer container.handleLock.RUnlock()
|
|
||||||
operation := "Shutdown"
|
|
||||||
title := "HCSShim::Container::" + operation
|
|
||||||
logrus.Debugf(title+" id=%s", container.id)
|
|
||||||
|
|
||||||
if container.handle == 0 {
|
|
||||||
return makeContainerError(container, operation, "", ErrAlreadyClosed)
|
|
||||||
}
|
|
||||||
|
|
||||||
var resultp *uint16
|
|
||||||
err := hcsShutdownComputeSystem(container.handle, "", &resultp)
|
|
||||||
err = processHcsResult(err, resultp)
|
|
||||||
if err != nil {
|
|
||||||
return makeContainerError(container, operation, "", err)
|
|
||||||
}
|
|
||||||
|
|
||||||
logrus.Debugf(title+" succeeded id=%s", container.id)
|
|
||||||
return nil
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Terminate requests a container terminate, if IsPending() on the error returned is true,
|
// Terminate requests a container terminate, but it may not actually be terminated until Wait() succeeds.
|
||||||
// it may not actually be shut down until Wait() succeeds.
|
|
||||||
func (container *container) Terminate() error {
|
func (container *container) Terminate() error {
|
||||||
container.handleLock.RLock()
|
return convertSystemError(container.system.Terminate(), container)
|
||||||
defer container.handleLock.RUnlock()
|
|
||||||
operation := "Terminate"
|
|
||||||
title := "HCSShim::Container::" + operation
|
|
||||||
logrus.Debugf(title+" id=%s", container.id)
|
|
||||||
|
|
||||||
if container.handle == 0 {
|
|
||||||
return makeContainerError(container, operation, "", ErrAlreadyClosed)
|
|
||||||
}
|
|
||||||
|
|
||||||
var resultp *uint16
|
|
||||||
err := hcsTerminateComputeSystem(container.handle, "", &resultp)
|
|
||||||
err = processHcsResult(err, resultp)
|
|
||||||
if err != nil {
|
|
||||||
return makeContainerError(container, operation, "", err)
|
|
||||||
}
|
|
||||||
|
|
||||||
logrus.Debugf(title+" succeeded id=%s", container.id)
|
|
||||||
return nil
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Wait synchronously waits for the container to shutdown or terminate.
|
// Waits synchronously waits for the container to shutdown or terminate.
|
||||||
func (container *container) Wait() error {
|
func (container *container) Wait() error {
|
||||||
operation := "Wait"
|
return convertSystemError(container.system.Wait(), container)
|
||||||
title := "HCSShim::Container::" + operation
|
|
||||||
logrus.Debugf(title+" id=%s", container.id)
|
|
||||||
|
|
||||||
err := waitForNotification(container.callbackNumber, hcsNotificationSystemExited, nil)
|
|
||||||
if err != nil {
|
|
||||||
return makeContainerError(container, operation, "", err)
|
|
||||||
}
|
|
||||||
|
|
||||||
logrus.Debugf(title+" succeeded id=%s", container.id)
|
|
||||||
return nil
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// WaitTimeout synchronously waits for the container to terminate or the duration to elapse.
|
// WaitTimeout synchronously waits for the container to terminate or the duration to elapse. It
|
||||||
// If the timeout expires, IsTimeout(err) == true
|
// returns false if timeout occurs.
|
||||||
func (container *container) WaitTimeout(timeout time.Duration) error {
|
func (container *container) WaitTimeout(t time.Duration) error {
|
||||||
operation := "WaitTimeout"
|
return convertSystemError(container.system.WaitTimeout(t), container)
|
||||||
title := "HCSShim::Container::" + operation
|
|
||||||
logrus.Debugf(title+" id=%s", container.id)
|
|
||||||
|
|
||||||
err := waitForNotification(container.callbackNumber, hcsNotificationSystemExited, &timeout)
|
|
||||||
if err != nil {
|
|
||||||
return makeContainerError(container, operation, "", err)
|
|
||||||
}
|
|
||||||
|
|
||||||
logrus.Debugf(title+" succeeded id=%s", container.id)
|
|
||||||
return nil
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func (container *container) properties(query string) (*ContainerProperties, error) {
|
// Pause pauses the execution of a container.
|
||||||
var (
|
func (container *container) Pause() error {
|
||||||
resultp *uint16
|
return convertSystemError(container.system.Pause(), container)
|
||||||
propertiesp *uint16
|
}
|
||||||
)
|
|
||||||
err := hcsGetComputeSystemProperties(container.handle, query, &propertiesp, &resultp)
|
|
||||||
err = processHcsResult(err, resultp)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
if propertiesp == nil {
|
// Resume resumes the execution of a container.
|
||||||
return nil, ErrUnexpectedValue
|
func (container *container) Resume() error {
|
||||||
}
|
return convertSystemError(container.system.Resume(), container)
|
||||||
propertiesRaw := convertAndFreeCoTaskMemBytes(propertiesp)
|
|
||||||
properties := &ContainerProperties{}
|
|
||||||
if err := json.Unmarshal(propertiesRaw, properties); err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
return properties, nil
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// HasPendingUpdates returns true if the container has updates pending to install
|
// HasPendingUpdates returns true if the container has updates pending to install
|
||||||
func (container *container) HasPendingUpdates() (bool, error) {
|
func (container *container) HasPendingUpdates() (bool, error) {
|
||||||
container.handleLock.RLock()
|
return false, nil
|
||||||
defer container.handleLock.RUnlock()
|
|
||||||
operation := "HasPendingUpdates"
|
|
||||||
title := "HCSShim::Container::" + operation
|
|
||||||
logrus.Debugf(title+" id=%s", container.id)
|
|
||||||
|
|
||||||
if container.handle == 0 {
|
|
||||||
return false, makeContainerError(container, operation, "", ErrAlreadyClosed)
|
|
||||||
}
|
|
||||||
|
|
||||||
properties, err := container.properties(pendingUpdatesQuery)
|
|
||||||
if err != nil {
|
|
||||||
return false, makeContainerError(container, operation, "", err)
|
|
||||||
}
|
|
||||||
|
|
||||||
logrus.Debugf(title+" succeeded id=%s", container.id)
|
|
||||||
return properties.AreUpdatesPending, nil
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Statistics returns statistics for the container
|
// Statistics returns statistics for the container. This is a legacy v1 call
|
||||||
func (container *container) Statistics() (Statistics, error) {
|
func (container *container) Statistics() (Statistics, error) {
|
||||||
container.handleLock.RLock()
|
properties, err := container.system.Properties(schema1.PropertyTypeStatistics)
|
||||||
defer container.handleLock.RUnlock()
|
|
||||||
operation := "Statistics"
|
|
||||||
title := "HCSShim::Container::" + operation
|
|
||||||
logrus.Debugf(title+" id=%s", container.id)
|
|
||||||
|
|
||||||
if container.handle == 0 {
|
|
||||||
return Statistics{}, makeContainerError(container, operation, "", ErrAlreadyClosed)
|
|
||||||
}
|
|
||||||
|
|
||||||
properties, err := container.properties(statisticsQuery)
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return Statistics{}, makeContainerError(container, operation, "", err)
|
return Statistics{}, convertSystemError(err, container)
|
||||||
}
|
}
|
||||||
|
|
||||||
logrus.Debugf(title+" succeeded id=%s", container.id)
|
|
||||||
return properties.Statistics, nil
|
return properties.Statistics, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// ProcessList returns an array of ProcessListItems for the container
|
// ProcessList returns an array of ProcessListItems for the container. This is a legacy v1 call
|
||||||
func (container *container) ProcessList() ([]ProcessListItem, error) {
|
func (container *container) ProcessList() ([]ProcessListItem, error) {
|
||||||
container.handleLock.RLock()
|
properties, err := container.system.Properties(schema1.PropertyTypeProcessList)
|
||||||
defer container.handleLock.RUnlock()
|
|
||||||
operation := "ProcessList"
|
|
||||||
title := "HCSShim::Container::" + operation
|
|
||||||
logrus.Debugf(title+" id=%s", container.id)
|
|
||||||
|
|
||||||
if container.handle == 0 {
|
|
||||||
return nil, makeContainerError(container, operation, "", ErrAlreadyClosed)
|
|
||||||
}
|
|
||||||
|
|
||||||
properties, err := container.properties(processListQuery)
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, makeContainerError(container, operation, "", err)
|
return nil, convertSystemError(err, container)
|
||||||
}
|
}
|
||||||
|
|
||||||
logrus.Debugf(title+" succeeded id=%s", container.id)
|
|
||||||
return properties.ProcessList, nil
|
return properties.ProcessList, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// MappedVirtualDisks returns a map of the controllers and the disks mapped
|
// This is a legacy v1 call
|
||||||
// to a container.
|
|
||||||
//
|
|
||||||
// Example of JSON returned by the query.
|
|
||||||
//{
|
|
||||||
// "Id":"1126e8d7d279c707a666972a15976371d365eaf622c02cea2c442b84f6f550a3_svm",
|
|
||||||
// "SystemType":"Container",
|
|
||||||
// "RuntimeOsType":"Linux",
|
|
||||||
// "RuntimeId":"00000000-0000-0000-0000-000000000000",
|
|
||||||
// "State":"Running",
|
|
||||||
// "MappedVirtualDiskControllers":{
|
|
||||||
// "0":{
|
|
||||||
// "MappedVirtualDisks":{
|
|
||||||
// "2":{
|
|
||||||
// "HostPath":"C:\\lcow\\lcow\\scratch\\1126e8d7d279c707a666972a15976371d365eaf622c02cea2c442b84f6f550a3.vhdx",
|
|
||||||
// "ContainerPath":"/mnt/gcs/LinuxServiceVM/scratch",
|
|
||||||
// "Lun":2,
|
|
||||||
// "CreateInUtilityVM":true
|
|
||||||
// },
|
|
||||||
// "3":{
|
|
||||||
// "HostPath":"C:\\lcow\\lcow\\1126e8d7d279c707a666972a15976371d365eaf622c02cea2c442b84f6f550a3\\sandbox.vhdx",
|
|
||||||
// "Lun":3,
|
|
||||||
// "CreateInUtilityVM":true,
|
|
||||||
// "AttachOnly":true
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
//}
|
|
||||||
func (container *container) MappedVirtualDisks() (map[int]MappedVirtualDiskController, error) {
|
func (container *container) MappedVirtualDisks() (map[int]MappedVirtualDiskController, error) {
|
||||||
container.handleLock.RLock()
|
properties, err := container.system.Properties(schema1.PropertyTypeMappedVirtualDisk)
|
||||||
defer container.handleLock.RUnlock()
|
|
||||||
operation := "MappedVirtualDiskList"
|
|
||||||
title := "HCSShim::Container::" + operation
|
|
||||||
logrus.Debugf(title+" id=%s", container.id)
|
|
||||||
|
|
||||||
if container.handle == 0 {
|
|
||||||
return nil, makeContainerError(container, operation, "", ErrAlreadyClosed)
|
|
||||||
}
|
|
||||||
|
|
||||||
properties, err := container.properties(mappedVirtualDiskQuery)
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, makeContainerError(container, operation, "", err)
|
return nil, convertSystemError(err, container)
|
||||||
}
|
}
|
||||||
|
|
||||||
logrus.Debugf(title+" succeeded id=%s", container.id)
|
|
||||||
return properties.MappedVirtualDiskControllers, nil
|
return properties.MappedVirtualDiskControllers, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// Pause pauses the execution of the container. This feature is not enabled in TP5.
|
|
||||||
func (container *container) Pause() error {
|
|
||||||
container.handleLock.RLock()
|
|
||||||
defer container.handleLock.RUnlock()
|
|
||||||
operation := "Pause"
|
|
||||||
title := "HCSShim::Container::" + operation
|
|
||||||
logrus.Debugf(title+" id=%s", container.id)
|
|
||||||
|
|
||||||
if container.handle == 0 {
|
|
||||||
return makeContainerError(container, operation, "", ErrAlreadyClosed)
|
|
||||||
}
|
|
||||||
|
|
||||||
var resultp *uint16
|
|
||||||
err := hcsPauseComputeSystem(container.handle, "", &resultp)
|
|
||||||
err = processAsyncHcsResult(err, resultp, container.callbackNumber, hcsNotificationSystemPauseCompleted, &defaultTimeout)
|
|
||||||
if err != nil {
|
|
||||||
return makeContainerError(container, operation, "", err)
|
|
||||||
}
|
|
||||||
|
|
||||||
logrus.Debugf(title+" succeeded id=%s", container.id)
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// Resume resumes the execution of the container. This feature is not enabled in TP5.
|
|
||||||
func (container *container) Resume() error {
|
|
||||||
container.handleLock.RLock()
|
|
||||||
defer container.handleLock.RUnlock()
|
|
||||||
operation := "Resume"
|
|
||||||
title := "HCSShim::Container::" + operation
|
|
||||||
logrus.Debugf(title+" id=%s", container.id)
|
|
||||||
|
|
||||||
if container.handle == 0 {
|
|
||||||
return makeContainerError(container, operation, "", ErrAlreadyClosed)
|
|
||||||
}
|
|
||||||
|
|
||||||
var resultp *uint16
|
|
||||||
err := hcsResumeComputeSystem(container.handle, "", &resultp)
|
|
||||||
err = processAsyncHcsResult(err, resultp, container.callbackNumber, hcsNotificationSystemResumeCompleted, &defaultTimeout)
|
|
||||||
if err != nil {
|
|
||||||
return makeContainerError(container, operation, "", err)
|
|
||||||
}
|
|
||||||
|
|
||||||
logrus.Debugf(title+" succeeded id=%s", container.id)
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// CreateProcess launches a new process within the container.
|
// CreateProcess launches a new process within the container.
|
||||||
func (container *container) CreateProcess(c *ProcessConfig) (Process, error) {
|
func (container *container) CreateProcess(c *ProcessConfig) (Process, error) {
|
||||||
container.handleLock.RLock()
|
p, err := container.system.CreateProcess(c)
|
||||||
defer container.handleLock.RUnlock()
|
|
||||||
operation := "CreateProcess"
|
|
||||||
title := "HCSShim::Container::" + operation
|
|
||||||
var (
|
|
||||||
processInfo hcsProcessInformation
|
|
||||||
processHandle hcsProcess
|
|
||||||
resultp *uint16
|
|
||||||
)
|
|
||||||
|
|
||||||
if container.handle == 0 {
|
|
||||||
return nil, makeContainerError(container, operation, "", ErrAlreadyClosed)
|
|
||||||
}
|
|
||||||
|
|
||||||
// If we are not emulating a console, ignore any console size passed to us
|
|
||||||
if !c.EmulateConsole {
|
|
||||||
c.ConsoleSize[0] = 0
|
|
||||||
c.ConsoleSize[1] = 0
|
|
||||||
}
|
|
||||||
|
|
||||||
configurationb, err := json.Marshal(c)
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, makeContainerError(container, operation, "", err)
|
return nil, convertSystemError(err, container)
|
||||||
}
|
}
|
||||||
|
return &process{p}, nil
|
||||||
configuration := string(configurationb)
|
|
||||||
logrus.Debugf(title+" id=%s config=%s", container.id, configuration)
|
|
||||||
|
|
||||||
err = hcsCreateProcess(container.handle, configuration, &processInfo, &processHandle, &resultp)
|
|
||||||
err = processHcsResult(err, resultp)
|
|
||||||
if err != nil {
|
|
||||||
return nil, makeContainerError(container, operation, configuration, err)
|
|
||||||
}
|
|
||||||
|
|
||||||
process := &process{
|
|
||||||
handle: processHandle,
|
|
||||||
processID: int(processInfo.ProcessId),
|
|
||||||
container: container,
|
|
||||||
cachedPipes: &cachedPipes{
|
|
||||||
stdIn: processInfo.StdInput,
|
|
||||||
stdOut: processInfo.StdOutput,
|
|
||||||
stdErr: processInfo.StdError,
|
|
||||||
},
|
|
||||||
}
|
|
||||||
|
|
||||||
if err := process.registerCallback(); err != nil {
|
|
||||||
return nil, makeContainerError(container, operation, "", err)
|
|
||||||
}
|
|
||||||
|
|
||||||
logrus.Debugf(title+" succeeded id=%s processid=%d", container.id, process.processID)
|
|
||||||
return process, nil
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// OpenProcess gets an interface to an existing process within the container.
|
// OpenProcess gets an interface to an existing process within the container.
|
||||||
func (container *container) OpenProcess(pid int) (Process, error) {
|
func (container *container) OpenProcess(pid int) (Process, error) {
|
||||||
container.handleLock.RLock()
|
p, err := container.system.OpenProcess(pid)
|
||||||
defer container.handleLock.RUnlock()
|
|
||||||
operation := "OpenProcess"
|
|
||||||
title := "HCSShim::Container::" + operation
|
|
||||||
logrus.Debugf(title+" id=%s, processid=%d", container.id, pid)
|
|
||||||
var (
|
|
||||||
processHandle hcsProcess
|
|
||||||
resultp *uint16
|
|
||||||
)
|
|
||||||
|
|
||||||
if container.handle == 0 {
|
|
||||||
return nil, makeContainerError(container, operation, "", ErrAlreadyClosed)
|
|
||||||
}
|
|
||||||
|
|
||||||
err := hcsOpenProcess(container.handle, uint32(pid), &processHandle, &resultp)
|
|
||||||
err = processHcsResult(err, resultp)
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, makeContainerError(container, operation, "", err)
|
return nil, convertSystemError(err, container)
|
||||||
}
|
}
|
||||||
|
return &process{p}, nil
|
||||||
process := &process{
|
|
||||||
handle: processHandle,
|
|
||||||
processID: pid,
|
|
||||||
container: container,
|
|
||||||
}
|
|
||||||
|
|
||||||
if err := process.registerCallback(); err != nil {
|
|
||||||
return nil, makeContainerError(container, operation, "", err)
|
|
||||||
}
|
|
||||||
|
|
||||||
logrus.Debugf(title+" succeeded id=%s processid=%s", container.id, process.processID)
|
|
||||||
return process, nil
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Close cleans up any state associated with the container but does not terminate or wait for it.
|
// Close cleans up any state associated with the container but does not terminate or wait for it.
|
||||||
func (container *container) Close() error {
|
func (container *container) Close() error {
|
||||||
container.handleLock.Lock()
|
return convertSystemError(container.system.Close(), container)
|
||||||
defer container.handleLock.Unlock()
|
|
||||||
operation := "Close"
|
|
||||||
title := "HCSShim::Container::" + operation
|
|
||||||
logrus.Debugf(title+" id=%s", container.id)
|
|
||||||
|
|
||||||
// Don't double free this
|
|
||||||
if container.handle == 0 {
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
if err := container.unregisterCallback(); err != nil {
|
|
||||||
return makeContainerError(container, operation, "", err)
|
|
||||||
}
|
|
||||||
|
|
||||||
if err := hcsCloseComputeSystem(container.handle); err != nil {
|
|
||||||
return makeContainerError(container, operation, "", err)
|
|
||||||
}
|
|
||||||
|
|
||||||
container.handle = 0
|
|
||||||
|
|
||||||
logrus.Debugf(title+" succeeded id=%s", container.id)
|
|
||||||
return nil
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func (container *container) registerCallback() error {
|
// Modify the System
|
||||||
context := ¬ifcationWatcherContext{
|
|
||||||
channels: newChannels(),
|
|
||||||
}
|
|
||||||
|
|
||||||
callbackMapLock.Lock()
|
|
||||||
callbackNumber := nextCallback
|
|
||||||
nextCallback++
|
|
||||||
callbackMap[callbackNumber] = context
|
|
||||||
callbackMapLock.Unlock()
|
|
||||||
|
|
||||||
var callbackHandle hcsCallback
|
|
||||||
err := hcsRegisterComputeSystemCallback(container.handle, notificationWatcherCallback, callbackNumber, &callbackHandle)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
context.handle = callbackHandle
|
|
||||||
container.callbackNumber = callbackNumber
|
|
||||||
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func (container *container) unregisterCallback() error {
|
|
||||||
callbackNumber := container.callbackNumber
|
|
||||||
|
|
||||||
callbackMapLock.RLock()
|
|
||||||
context := callbackMap[callbackNumber]
|
|
||||||
callbackMapLock.RUnlock()
|
|
||||||
|
|
||||||
if context == nil {
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
handle := context.handle
|
|
||||||
|
|
||||||
if handle == 0 {
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// hcsUnregisterComputeSystemCallback has its own syncronization
|
|
||||||
// to wait for all callbacks to complete. We must NOT hold the callbackMapLock.
|
|
||||||
err := hcsUnregisterComputeSystemCallback(handle)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
closeChannels(context.channels)
|
|
||||||
|
|
||||||
callbackMapLock.Lock()
|
|
||||||
callbackMap[callbackNumber] = nil
|
|
||||||
callbackMapLock.Unlock()
|
|
||||||
|
|
||||||
handle = 0
|
|
||||||
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// Modifies the System by sending a request to HCS
|
|
||||||
func (container *container) Modify(config *ResourceModificationRequestResponse) error {
|
func (container *container) Modify(config *ResourceModificationRequestResponse) error {
|
||||||
container.handleLock.RLock()
|
return convertSystemError(container.system.Modify(config), container)
|
||||||
defer container.handleLock.RUnlock()
|
|
||||||
operation := "Modify"
|
|
||||||
title := "HCSShim::Container::" + operation
|
|
||||||
|
|
||||||
if container.handle == 0 {
|
|
||||||
return makeContainerError(container, operation, "", ErrAlreadyClosed)
|
|
||||||
}
|
|
||||||
|
|
||||||
requestJSON, err := json.Marshal(config)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
requestString := string(requestJSON)
|
|
||||||
logrus.Debugf(title+" id=%s request=%s", container.id, requestString)
|
|
||||||
|
|
||||||
var resultp *uint16
|
|
||||||
err = hcsModifyComputeSystem(container.handle, requestString, &resultp)
|
|
||||||
err = processHcsResult(err, resultp)
|
|
||||||
if err != nil {
|
|
||||||
return makeContainerError(container, operation, "", err)
|
|
||||||
}
|
|
||||||
logrus.Debugf(title+" succeeded id=%s", container.id)
|
|
||||||
return nil
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,27 +0,0 @@
|
||||||
package hcsshim
|
|
||||||
|
|
||||||
import "github.com/sirupsen/logrus"
|
|
||||||
|
|
||||||
// CreateLayer creates a new, empty, read-only layer on the filesystem based on
|
|
||||||
// the parent layer provided.
|
|
||||||
func CreateLayer(info DriverInfo, id, parent string) error {
|
|
||||||
title := "hcsshim::CreateLayer "
|
|
||||||
logrus.Debugf(title+"Flavour %d ID %s parent %s", info.Flavour, id, parent)
|
|
||||||
|
|
||||||
// Convert info to API calling convention
|
|
||||||
infop, err := convertDriverInfo(info)
|
|
||||||
if err != nil {
|
|
||||||
logrus.Error(err)
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
err = createLayer(&infop, id, parent)
|
|
||||||
if err != nil {
|
|
||||||
err = makeErrorf(err, title, "id=%s parent=%s flavour=%d", id, parent, info.Flavour)
|
|
||||||
logrus.Error(err)
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
logrus.Debugf(title+" - succeeded id=%s parent=%s flavour=%d", id, parent, info.Flavour)
|
|
||||||
return nil
|
|
||||||
}
|
|
|
@ -1,35 +0,0 @@
|
||||||
package hcsshim
|
|
||||||
|
|
||||||
import "github.com/sirupsen/logrus"
|
|
||||||
|
|
||||||
// CreateSandboxLayer creates and populates new read-write layer for use by a container.
|
|
||||||
// This requires both the id of the direct parent layer, as well as the full list
|
|
||||||
// of paths to all parent layers up to the base (and including the direct parent
|
|
||||||
// whose id was provided).
|
|
||||||
func CreateSandboxLayer(info DriverInfo, layerId, parentId string, parentLayerPaths []string) error {
|
|
||||||
title := "hcsshim::CreateSandboxLayer "
|
|
||||||
logrus.Debugf(title+"layerId %s parentId %s", layerId, parentId)
|
|
||||||
|
|
||||||
// Generate layer descriptors
|
|
||||||
layers, err := layerPathsToDescriptors(parentLayerPaths)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
// Convert info to API calling convention
|
|
||||||
infop, err := convertDriverInfo(info)
|
|
||||||
if err != nil {
|
|
||||||
logrus.Error(err)
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
err = createSandboxLayer(&infop, layerId, parentId, layers)
|
|
||||||
if err != nil {
|
|
||||||
err = makeErrorf(err, title, "layerId=%s parentId=%s", layerId, parentId)
|
|
||||||
logrus.Error(err)
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
logrus.Debugf(title+"- succeeded layerId=%s parentId=%s", layerId, parentId)
|
|
||||||
return nil
|
|
||||||
}
|
|
|
@ -1,26 +0,0 @@
|
||||||
package hcsshim
|
|
||||||
|
|
||||||
import "github.com/sirupsen/logrus"
|
|
||||||
|
|
||||||
// DeactivateLayer will dismount a layer that was mounted via ActivateLayer.
|
|
||||||
func DeactivateLayer(info DriverInfo, id string) error {
|
|
||||||
title := "hcsshim::DeactivateLayer "
|
|
||||||
logrus.Debugf(title+"Flavour %d ID %s", info.Flavour, id)
|
|
||||||
|
|
||||||
// Convert info to API calling convention
|
|
||||||
infop, err := convertDriverInfo(info)
|
|
||||||
if err != nil {
|
|
||||||
logrus.Error(err)
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
err = deactivateLayer(&infop, id)
|
|
||||||
if err != nil {
|
|
||||||
err = makeErrorf(err, title, "id=%s flavour=%d", id, info.Flavour)
|
|
||||||
logrus.Error(err)
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
logrus.Debugf(title+"succeeded flavour=%d id=%s", info.Flavour, id)
|
|
||||||
return nil
|
|
||||||
}
|
|
|
@ -1,27 +0,0 @@
|
||||||
package hcsshim
|
|
||||||
|
|
||||||
import "github.com/sirupsen/logrus"
|
|
||||||
|
|
||||||
// DestroyLayer will remove the on-disk files representing the layer with the given
|
|
||||||
// id, including that layer's containing folder, if any.
|
|
||||||
func DestroyLayer(info DriverInfo, id string) error {
|
|
||||||
title := "hcsshim::DestroyLayer "
|
|
||||||
logrus.Debugf(title+"Flavour %d ID %s", info.Flavour, id)
|
|
||||||
|
|
||||||
// Convert info to API calling convention
|
|
||||||
infop, err := convertDriverInfo(info)
|
|
||||||
if err != nil {
|
|
||||||
logrus.Error(err)
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
err = destroyLayer(&infop, id)
|
|
||||||
if err != nil {
|
|
||||||
err = makeErrorf(err, title, "id=%s flavour=%d", id, info.Flavour)
|
|
||||||
logrus.Error(err)
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
logrus.Debugf(title+"succeeded flavour=%d id=%s", info.Flavour, id)
|
|
||||||
return nil
|
|
||||||
}
|
|
|
@ -1,92 +1,83 @@
|
||||||
package hcsshim
|
package hcsshim
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"errors"
|
|
||||||
"fmt"
|
"fmt"
|
||||||
"syscall"
|
"syscall"
|
||||||
|
|
||||||
|
"github.com/Microsoft/hcsshim/internal/hns"
|
||||||
|
|
||||||
|
"github.com/Microsoft/hcsshim/internal/hcs"
|
||||||
|
"github.com/Microsoft/hcsshim/internal/hcserror"
|
||||||
)
|
)
|
||||||
|
|
||||||
var (
|
var (
|
||||||
// ErrComputeSystemDoesNotExist is an error encountered when the container being operated on no longer exists
|
// ErrComputeSystemDoesNotExist is an error encountered when the container being operated on no longer exists = hcs.exist
|
||||||
ErrComputeSystemDoesNotExist = syscall.Errno(0xc037010e)
|
ErrComputeSystemDoesNotExist = hcs.ErrComputeSystemDoesNotExist
|
||||||
|
|
||||||
// ErrElementNotFound is an error encountered when the object being referenced does not exist
|
// ErrElementNotFound is an error encountered when the object being referenced does not exist
|
||||||
ErrElementNotFound = syscall.Errno(0x490)
|
ErrElementNotFound = hcs.ErrElementNotFound
|
||||||
|
|
||||||
// ErrElementNotFound is an error encountered when the object being referenced does not exist
|
// ErrElementNotFound is an error encountered when the object being referenced does not exist
|
||||||
ErrNotSupported = syscall.Errno(0x32)
|
ErrNotSupported = hcs.ErrNotSupported
|
||||||
|
|
||||||
// ErrInvalidData is an error encountered when the request being sent to hcs is invalid/unsupported
|
// ErrInvalidData is an error encountered when the request being sent to hcs is invalid/unsupported
|
||||||
// decimal -2147024883 / hex 0x8007000d
|
// decimal -2147024883 / hex 0x8007000d
|
||||||
ErrInvalidData = syscall.Errno(0xd)
|
ErrInvalidData = hcs.ErrInvalidData
|
||||||
|
|
||||||
// ErrHandleClose is an error encountered when the handle generating the notification being waited on has been closed
|
// ErrHandleClose is an error encountered when the handle generating the notification being waited on has been closed
|
||||||
ErrHandleClose = errors.New("hcsshim: the handle generating this notification has been closed")
|
ErrHandleClose = hcs.ErrHandleClose
|
||||||
|
|
||||||
// ErrAlreadyClosed is an error encountered when using a handle that has been closed by the Close method
|
// ErrAlreadyClosed is an error encountered when using a handle that has been closed by the Close method
|
||||||
ErrAlreadyClosed = errors.New("hcsshim: the handle has already been closed")
|
ErrAlreadyClosed = hcs.ErrAlreadyClosed
|
||||||
|
|
||||||
// ErrInvalidNotificationType is an error encountered when an invalid notification type is used
|
// ErrInvalidNotificationType is an error encountered when an invalid notification type is used
|
||||||
ErrInvalidNotificationType = errors.New("hcsshim: invalid notification type")
|
ErrInvalidNotificationType = hcs.ErrInvalidNotificationType
|
||||||
|
|
||||||
// ErrInvalidProcessState is an error encountered when the process is not in a valid state for the requested operation
|
// ErrInvalidProcessState is an error encountered when the process is not in a valid state for the requested operation
|
||||||
ErrInvalidProcessState = errors.New("the process is in an invalid state for the attempted operation")
|
ErrInvalidProcessState = hcs.ErrInvalidProcessState
|
||||||
|
|
||||||
// ErrTimeout is an error encountered when waiting on a notification times out
|
// ErrTimeout is an error encountered when waiting on a notification times out
|
||||||
ErrTimeout = errors.New("hcsshim: timeout waiting for notification")
|
ErrTimeout = hcs.ErrTimeout
|
||||||
|
|
||||||
// ErrUnexpectedContainerExit is the error encountered when a container exits while waiting for
|
// ErrUnexpectedContainerExit is the error encountered when a container exits while waiting for
|
||||||
// a different expected notification
|
// a different expected notification
|
||||||
ErrUnexpectedContainerExit = errors.New("unexpected container exit")
|
ErrUnexpectedContainerExit = hcs.ErrUnexpectedContainerExit
|
||||||
|
|
||||||
// ErrUnexpectedProcessAbort is the error encountered when communication with the compute service
|
// ErrUnexpectedProcessAbort is the error encountered when communication with the compute service
|
||||||
// is lost while waiting for a notification
|
// is lost while waiting for a notification
|
||||||
ErrUnexpectedProcessAbort = errors.New("lost communication with compute service")
|
ErrUnexpectedProcessAbort = hcs.ErrUnexpectedProcessAbort
|
||||||
|
|
||||||
// ErrUnexpectedValue is an error encountered when hcs returns an invalid value
|
// ErrUnexpectedValue is an error encountered when hcs returns an invalid value
|
||||||
ErrUnexpectedValue = errors.New("unexpected value returned from hcs")
|
ErrUnexpectedValue = hcs.ErrUnexpectedValue
|
||||||
|
|
||||||
// ErrVmcomputeAlreadyStopped is an error encountered when a shutdown or terminate request is made on a stopped container
|
// ErrVmcomputeAlreadyStopped is an error encountered when a shutdown or terminate request is made on a stopped container
|
||||||
ErrVmcomputeAlreadyStopped = syscall.Errno(0xc0370110)
|
ErrVmcomputeAlreadyStopped = hcs.ErrVmcomputeAlreadyStopped
|
||||||
|
|
||||||
// ErrVmcomputeOperationPending is an error encountered when the operation is being completed asynchronously
|
// ErrVmcomputeOperationPending is an error encountered when the operation is being completed asynchronously
|
||||||
ErrVmcomputeOperationPending = syscall.Errno(0xC0370103)
|
ErrVmcomputeOperationPending = hcs.ErrVmcomputeOperationPending
|
||||||
|
|
||||||
// ErrVmcomputeOperationInvalidState is an error encountered when the compute system is not in a valid state for the requested operation
|
// ErrVmcomputeOperationInvalidState is an error encountered when the compute system is not in a valid state for the requested operation
|
||||||
ErrVmcomputeOperationInvalidState = syscall.Errno(0xc0370105)
|
ErrVmcomputeOperationInvalidState = hcs.ErrVmcomputeOperationInvalidState
|
||||||
|
|
||||||
// ErrProcNotFound is an error encountered when the the process cannot be found
|
// ErrProcNotFound is an error encountered when the the process cannot be found
|
||||||
ErrProcNotFound = syscall.Errno(0x7f)
|
ErrProcNotFound = hcs.ErrProcNotFound
|
||||||
|
|
||||||
// ErrVmcomputeOperationAccessIsDenied is an error which can be encountered when enumerating compute systems in RS1/RS2
|
// ErrVmcomputeOperationAccessIsDenied is an error which can be encountered when enumerating compute systems in RS1/RS2
|
||||||
// builds when the underlying silo might be in the process of terminating. HCS was fixed in RS3.
|
// builds when the underlying silo might be in the process of terminating. HCS was fixed in RS3.
|
||||||
ErrVmcomputeOperationAccessIsDenied = syscall.Errno(0x5)
|
ErrVmcomputeOperationAccessIsDenied = hcs.ErrVmcomputeOperationAccessIsDenied
|
||||||
|
|
||||||
// ErrVmcomputeInvalidJSON is an error encountered when the compute system does not support/understand the messages sent by management
|
// ErrVmcomputeInvalidJSON is an error encountered when the compute system does not support/understand the messages sent by management
|
||||||
ErrVmcomputeInvalidJSON = syscall.Errno(0xc037010d)
|
ErrVmcomputeInvalidJSON = hcs.ErrVmcomputeInvalidJSON
|
||||||
|
|
||||||
// ErrVmcomputeUnknownMessage is an error encountered guest compute system doesn't support the message
|
// ErrVmcomputeUnknownMessage is an error encountered guest compute system doesn't support the message
|
||||||
ErrVmcomputeUnknownMessage = syscall.Errno(0xc037010b)
|
ErrVmcomputeUnknownMessage = hcs.ErrVmcomputeUnknownMessage
|
||||||
|
|
||||||
// ErrNotSupported is an error encountered when hcs doesn't support the request
|
// ErrNotSupported is an error encountered when hcs doesn't support the request
|
||||||
ErrPlatformNotSupported = errors.New("unsupported platform request")
|
ErrPlatformNotSupported = hcs.ErrPlatformNotSupported
|
||||||
)
|
)
|
||||||
|
|
||||||
type EndpointNotFoundError struct {
|
type EndpointNotFoundError = hns.EndpointNotFoundError
|
||||||
EndpointName string
|
type NetworkNotFoundError = hns.NetworkNotFoundError
|
||||||
}
|
|
||||||
|
|
||||||
func (e EndpointNotFoundError) Error() string {
|
|
||||||
return fmt.Sprintf("Endpoint %s not found", e.EndpointName)
|
|
||||||
}
|
|
||||||
|
|
||||||
type NetworkNotFoundError struct {
|
|
||||||
NetworkName string
|
|
||||||
}
|
|
||||||
|
|
||||||
func (e NetworkNotFoundError) Error() string {
|
|
||||||
return fmt.Sprintf("Network %s not found", e.NetworkName)
|
|
||||||
}
|
|
||||||
|
|
||||||
// ProcessError is an error encountered in HCS during an operation on a Process object
|
// ProcessError is an error encountered in HCS during an operation on a Process object
|
||||||
type ProcessError struct {
|
type ProcessError struct {
|
||||||
|
@ -94,6 +85,7 @@ type ProcessError struct {
|
||||||
Operation string
|
Operation string
|
||||||
ExtraInfo string
|
ExtraInfo string
|
||||||
Err error
|
Err error
|
||||||
|
Events []hcs.ErrorEvent
|
||||||
}
|
}
|
||||||
|
|
||||||
// ContainerError is an error encountered in HCS during an operation on a Container object
|
// ContainerError is an error encountered in HCS during an operation on a Container object
|
||||||
|
@ -102,6 +94,7 @@ type ContainerError struct {
|
||||||
Operation string
|
Operation string
|
||||||
ExtraInfo string
|
ExtraInfo string
|
||||||
Err error
|
Err error
|
||||||
|
Events []hcs.ErrorEvent
|
||||||
}
|
}
|
||||||
|
|
||||||
func (e *ContainerError) Error() string {
|
func (e *ContainerError) Error() string {
|
||||||
|
@ -113,7 +106,7 @@ func (e *ContainerError) Error() string {
|
||||||
return "unexpected nil container for error: " + e.Err.Error()
|
return "unexpected nil container for error: " + e.Err.Error()
|
||||||
}
|
}
|
||||||
|
|
||||||
s := "container " + e.Container.id
|
s := "container " + e.Container.system.ID()
|
||||||
|
|
||||||
if e.Operation != "" {
|
if e.Operation != "" {
|
||||||
s += " encountered an error during " + e.Operation
|
s += " encountered an error during " + e.Operation
|
||||||
|
@ -123,11 +116,15 @@ func (e *ContainerError) Error() string {
|
||||||
case nil:
|
case nil:
|
||||||
break
|
break
|
||||||
case syscall.Errno:
|
case syscall.Errno:
|
||||||
s += fmt.Sprintf(": failure in a Windows system call: %s (0x%x)", e.Err, win32FromError(e.Err))
|
s += fmt.Sprintf(": failure in a Windows system call: %s (0x%x)", e.Err, hcserror.Win32FromError(e.Err))
|
||||||
default:
|
default:
|
||||||
s += fmt.Sprintf(": %s", e.Err.Error())
|
s += fmt.Sprintf(": %s", e.Err.Error())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
for _, ev := range e.Events {
|
||||||
|
s += "\n" + ev.String()
|
||||||
|
}
|
||||||
|
|
||||||
if e.ExtraInfo != "" {
|
if e.ExtraInfo != "" {
|
||||||
s += " extra info: " + e.ExtraInfo
|
s += " extra info: " + e.ExtraInfo
|
||||||
}
|
}
|
||||||
|
@ -153,12 +150,7 @@ func (e *ProcessError) Error() string {
|
||||||
return "Unexpected nil process for error: " + e.Err.Error()
|
return "Unexpected nil process for error: " + e.Err.Error()
|
||||||
}
|
}
|
||||||
|
|
||||||
s := fmt.Sprintf("process %d", e.Process.processID)
|
s := fmt.Sprintf("process %d in container %s", e.Process.p.Pid(), e.Process.p.SystemID())
|
||||||
|
|
||||||
if e.Process.container != nil {
|
|
||||||
s += " in container " + e.Process.container.id
|
|
||||||
}
|
|
||||||
|
|
||||||
if e.Operation != "" {
|
if e.Operation != "" {
|
||||||
s += " encountered an error during " + e.Operation
|
s += " encountered an error during " + e.Operation
|
||||||
}
|
}
|
||||||
|
@ -167,11 +159,15 @@ func (e *ProcessError) Error() string {
|
||||||
case nil:
|
case nil:
|
||||||
break
|
break
|
||||||
case syscall.Errno:
|
case syscall.Errno:
|
||||||
s += fmt.Sprintf(": failure in a Windows system call: %s (0x%x)", e.Err, win32FromError(e.Err))
|
s += fmt.Sprintf(": failure in a Windows system call: %s (0x%x)", e.Err, hcserror.Win32FromError(e.Err))
|
||||||
default:
|
default:
|
||||||
s += fmt.Sprintf(": %s", e.Err.Error())
|
s += fmt.Sprintf(": %s", e.Err.Error())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
for _, ev := range e.Events {
|
||||||
|
s += "\n" + ev.String()
|
||||||
|
}
|
||||||
|
|
||||||
return s
|
return s
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -189,37 +185,31 @@ func makeProcessError(process *process, operation string, extraInfo string, err
|
||||||
// already exited, or does not exist. Both IsAlreadyStopped and IsNotExist
|
// already exited, or does not exist. Both IsAlreadyStopped and IsNotExist
|
||||||
// will currently return true when the error is ErrElementNotFound or ErrProcNotFound.
|
// will currently return true when the error is ErrElementNotFound or ErrProcNotFound.
|
||||||
func IsNotExist(err error) bool {
|
func IsNotExist(err error) bool {
|
||||||
err = getInnerError(err)
|
|
||||||
if _, ok := err.(EndpointNotFoundError); ok {
|
if _, ok := err.(EndpointNotFoundError); ok {
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
if _, ok := err.(NetworkNotFoundError); ok {
|
if _, ok := err.(NetworkNotFoundError); ok {
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
return err == ErrComputeSystemDoesNotExist ||
|
return hcs.IsNotExist(getInnerError(err))
|
||||||
err == ErrElementNotFound ||
|
|
||||||
err == ErrProcNotFound
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// IsAlreadyClosed checks if an error is caused by the Container or Process having been
|
// IsAlreadyClosed checks if an error is caused by the Container or Process having been
|
||||||
// already closed by a call to the Close() method.
|
// already closed by a call to the Close() method.
|
||||||
func IsAlreadyClosed(err error) bool {
|
func IsAlreadyClosed(err error) bool {
|
||||||
err = getInnerError(err)
|
return hcs.IsAlreadyClosed(getInnerError(err))
|
||||||
return err == ErrAlreadyClosed
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// IsPending returns a boolean indicating whether the error is that
|
// IsPending returns a boolean indicating whether the error is that
|
||||||
// the requested operation is being completed in the background.
|
// the requested operation is being completed in the background.
|
||||||
func IsPending(err error) bool {
|
func IsPending(err error) bool {
|
||||||
err = getInnerError(err)
|
return hcs.IsPending(getInnerError(err))
|
||||||
return err == ErrVmcomputeOperationPending
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// IsTimeout returns a boolean indicating whether the error is caused by
|
// IsTimeout returns a boolean indicating whether the error is caused by
|
||||||
// a timeout waiting for the operation to complete.
|
// a timeout waiting for the operation to complete.
|
||||||
func IsTimeout(err error) bool {
|
func IsTimeout(err error) bool {
|
||||||
err = getInnerError(err)
|
return hcs.IsTimeout(getInnerError(err))
|
||||||
return err == ErrTimeout
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// IsAlreadyStopped returns a boolean indicating whether the error is caused by
|
// IsAlreadyStopped returns a boolean indicating whether the error is caused by
|
||||||
|
@ -228,10 +218,7 @@ func IsTimeout(err error) bool {
|
||||||
// already exited, or does not exist. Both IsAlreadyStopped and IsNotExist
|
// already exited, or does not exist. Both IsAlreadyStopped and IsNotExist
|
||||||
// will currently return true when the error is ErrElementNotFound or ErrProcNotFound.
|
// will currently return true when the error is ErrElementNotFound or ErrProcNotFound.
|
||||||
func IsAlreadyStopped(err error) bool {
|
func IsAlreadyStopped(err error) bool {
|
||||||
err = getInnerError(err)
|
return hcs.IsAlreadyStopped(getInnerError(err))
|
||||||
return err == ErrVmcomputeAlreadyStopped ||
|
|
||||||
err == ErrElementNotFound ||
|
|
||||||
err == ErrProcNotFound
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// IsNotSupported returns a boolean indicating whether the error is caused by
|
// IsNotSupported returns a boolean indicating whether the error is caused by
|
||||||
|
@ -240,12 +227,7 @@ func IsAlreadyStopped(err error) bool {
|
||||||
// ErrVmcomputeInvalidJSON, ErrInvalidData, ErrNotSupported or ErrVmcomputeUnknownMessage
|
// ErrVmcomputeInvalidJSON, ErrInvalidData, ErrNotSupported or ErrVmcomputeUnknownMessage
|
||||||
// is thrown from the Platform
|
// is thrown from the Platform
|
||||||
func IsNotSupported(err error) bool {
|
func IsNotSupported(err error) bool {
|
||||||
err = getInnerError(err)
|
return hcs.IsNotSupported(getInnerError(err))
|
||||||
// If Platform doesn't recognize or support the request sent, below errors are seen
|
|
||||||
return err == ErrVmcomputeInvalidJSON ||
|
|
||||||
err == ErrInvalidData ||
|
|
||||||
err == ErrNotSupported ||
|
|
||||||
err == ErrVmcomputeUnknownMessage
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func getInnerError(err error) error {
|
func getInnerError(err error) error {
|
||||||
|
@ -259,3 +241,17 @@ func getInnerError(err error) error {
|
||||||
}
|
}
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func convertSystemError(err error, c *container) error {
|
||||||
|
if serr, ok := err.(*hcs.SystemError); ok {
|
||||||
|
return &ContainerError{Container: c, Operation: serr.Op, ExtraInfo: serr.Extra, Err: serr.Err, Events: serr.Events}
|
||||||
|
}
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
func convertProcessError(err error, p *process) error {
|
||||||
|
if perr, ok := err.(*hcs.ProcessError); ok {
|
||||||
|
return &ProcessError{Process: p, Operation: perr.Op, Err: perr.Err, Events: perr.Events}
|
||||||
|
}
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
|
@ -1,26 +0,0 @@
|
||||||
package hcsshim
|
|
||||||
|
|
||||||
import "github.com/sirupsen/logrus"
|
|
||||||
|
|
||||||
// ExpandSandboxSize expands the size of a layer to at least size bytes.
|
|
||||||
func ExpandSandboxSize(info DriverInfo, layerId string, size uint64) error {
|
|
||||||
title := "hcsshim::ExpandSandboxSize "
|
|
||||||
logrus.Debugf(title+"layerId=%s size=%d", layerId, size)
|
|
||||||
|
|
||||||
// Convert info to API calling convention
|
|
||||||
infop, err := convertDriverInfo(info)
|
|
||||||
if err != nil {
|
|
||||||
logrus.Error(err)
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
err = expandSandboxSize(&infop, layerId, size)
|
|
||||||
if err != nil {
|
|
||||||
err = makeErrorf(err, title, "layerId=%s size=%d", layerId, size)
|
|
||||||
logrus.Error(err)
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
logrus.Debugf(title+"- succeeded layerId=%s size=%d", layerId, size)
|
|
||||||
return nil
|
|
||||||
}
|
|
|
@ -1,19 +0,0 @@
|
||||||
package hcsshim
|
|
||||||
|
|
||||||
import (
|
|
||||||
"crypto/sha1"
|
|
||||||
"fmt"
|
|
||||||
)
|
|
||||||
|
|
||||||
type GUID [16]byte
|
|
||||||
|
|
||||||
func NewGUID(source string) *GUID {
|
|
||||||
h := sha1.Sum([]byte(source))
|
|
||||||
var g GUID
|
|
||||||
copy(g[0:], h[0:16])
|
|
||||||
return &g
|
|
||||||
}
|
|
||||||
|
|
||||||
func (g *GUID) ToString() string {
|
|
||||||
return fmt.Sprintf("%02x%02x%02x%02x-%02x%02x-%02x%02x-%02x-%02x", g[3], g[2], g[1], g[0], g[5], g[4], g[7], g[6], g[8:10], g[10:])
|
|
||||||
}
|
|
|
@ -4,80 +4,20 @@
|
||||||
package hcsshim
|
package hcsshim
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"fmt"
|
|
||||||
"syscall"
|
"syscall"
|
||||||
"unsafe"
|
|
||||||
|
|
||||||
"github.com/sirupsen/logrus"
|
"github.com/Microsoft/hcsshim/internal/hcserror"
|
||||||
)
|
)
|
||||||
|
|
||||||
//go:generate go run mksyscall_windows.go -output zhcsshim.go hcsshim.go safeopen.go
|
//go:generate go run mksyscall_windows.go -output zsyscall_windows.go hcsshim.go
|
||||||
|
|
||||||
//sys coTaskMemFree(buffer unsafe.Pointer) = ole32.CoTaskMemFree
|
|
||||||
//sys SetCurrentThreadCompartmentId(compartmentId uint32) (hr error) = iphlpapi.SetCurrentThreadCompartmentId
|
//sys SetCurrentThreadCompartmentId(compartmentId uint32) (hr error) = iphlpapi.SetCurrentThreadCompartmentId
|
||||||
|
|
||||||
//sys activateLayer(info *driverInfo, id string) (hr error) = vmcompute.ActivateLayer?
|
|
||||||
//sys copyLayer(info *driverInfo, srcId string, dstId string, descriptors []WC_LAYER_DESCRIPTOR) (hr error) = vmcompute.CopyLayer?
|
|
||||||
//sys createLayer(info *driverInfo, id string, parent string) (hr error) = vmcompute.CreateLayer?
|
|
||||||
//sys createSandboxLayer(info *driverInfo, id string, parent string, descriptors []WC_LAYER_DESCRIPTOR) (hr error) = vmcompute.CreateSandboxLayer?
|
|
||||||
//sys expandSandboxSize(info *driverInfo, id string, size uint64) (hr error) = vmcompute.ExpandSandboxSize?
|
|
||||||
//sys deactivateLayer(info *driverInfo, id string) (hr error) = vmcompute.DeactivateLayer?
|
|
||||||
//sys destroyLayer(info *driverInfo, id string) (hr error) = vmcompute.DestroyLayer?
|
|
||||||
//sys exportLayer(info *driverInfo, id string, path string, descriptors []WC_LAYER_DESCRIPTOR) (hr error) = vmcompute.ExportLayer?
|
|
||||||
//sys getLayerMountPath(info *driverInfo, id string, length *uintptr, buffer *uint16) (hr error) = vmcompute.GetLayerMountPath?
|
|
||||||
//sys getBaseImages(buffer **uint16) (hr error) = vmcompute.GetBaseImages?
|
|
||||||
//sys importLayer(info *driverInfo, id string, path string, descriptors []WC_LAYER_DESCRIPTOR) (hr error) = vmcompute.ImportLayer?
|
|
||||||
//sys layerExists(info *driverInfo, id string, exists *uint32) (hr error) = vmcompute.LayerExists?
|
|
||||||
//sys nameToGuid(name string, guid *GUID) (hr error) = vmcompute.NameToGuid?
|
|
||||||
//sys prepareLayer(info *driverInfo, id string, descriptors []WC_LAYER_DESCRIPTOR) (hr error) = vmcompute.PrepareLayer?
|
|
||||||
//sys unprepareLayer(info *driverInfo, id string) (hr error) = vmcompute.UnprepareLayer?
|
|
||||||
//sys processBaseImage(path string) (hr error) = vmcompute.ProcessBaseImage?
|
|
||||||
//sys processUtilityImage(path string) (hr error) = vmcompute.ProcessUtilityImage?
|
|
||||||
|
|
||||||
//sys importLayerBegin(info *driverInfo, id string, descriptors []WC_LAYER_DESCRIPTOR, context *uintptr) (hr error) = vmcompute.ImportLayerBegin?
|
|
||||||
//sys importLayerNext(context uintptr, fileName string, fileInfo *winio.FileBasicInfo) (hr error) = vmcompute.ImportLayerNext?
|
|
||||||
//sys importLayerWrite(context uintptr, buffer []byte) (hr error) = vmcompute.ImportLayerWrite?
|
|
||||||
//sys importLayerEnd(context uintptr) (hr error) = vmcompute.ImportLayerEnd?
|
|
||||||
|
|
||||||
//sys exportLayerBegin(info *driverInfo, id string, descriptors []WC_LAYER_DESCRIPTOR, context *uintptr) (hr error) = vmcompute.ExportLayerBegin?
|
|
||||||
//sys exportLayerNext(context uintptr, fileName **uint16, fileInfo *winio.FileBasicInfo, fileSize *int64, deleted *uint32) (hr error) = vmcompute.ExportLayerNext?
|
|
||||||
//sys exportLayerRead(context uintptr, buffer []byte, bytesRead *uint32) (hr error) = vmcompute.ExportLayerRead?
|
|
||||||
//sys exportLayerEnd(context uintptr) (hr error) = vmcompute.ExportLayerEnd?
|
|
||||||
|
|
||||||
//sys hcsEnumerateComputeSystems(query string, computeSystems **uint16, result **uint16) (hr error) = vmcompute.HcsEnumerateComputeSystems?
|
|
||||||
//sys hcsCreateComputeSystem(id string, configuration string, identity syscall.Handle, computeSystem *hcsSystem, result **uint16) (hr error) = vmcompute.HcsCreateComputeSystem?
|
|
||||||
//sys hcsOpenComputeSystem(id string, computeSystem *hcsSystem, result **uint16) (hr error) = vmcompute.HcsOpenComputeSystem?
|
|
||||||
//sys hcsCloseComputeSystem(computeSystem hcsSystem) (hr error) = vmcompute.HcsCloseComputeSystem?
|
|
||||||
//sys hcsStartComputeSystem(computeSystem hcsSystem, options string, result **uint16) (hr error) = vmcompute.HcsStartComputeSystem?
|
|
||||||
//sys hcsShutdownComputeSystem(computeSystem hcsSystem, options string, result **uint16) (hr error) = vmcompute.HcsShutdownComputeSystem?
|
|
||||||
//sys hcsTerminateComputeSystem(computeSystem hcsSystem, options string, result **uint16) (hr error) = vmcompute.HcsTerminateComputeSystem?
|
|
||||||
//sys hcsPauseComputeSystem(computeSystem hcsSystem, options string, result **uint16) (hr error) = vmcompute.HcsPauseComputeSystem?
|
|
||||||
//sys hcsResumeComputeSystem(computeSystem hcsSystem, options string, result **uint16) (hr error) = vmcompute.HcsResumeComputeSystem?
|
|
||||||
//sys hcsGetComputeSystemProperties(computeSystem hcsSystem, propertyQuery string, properties **uint16, result **uint16) (hr error) = vmcompute.HcsGetComputeSystemProperties?
|
|
||||||
//sys hcsModifyComputeSystem(computeSystem hcsSystem, configuration string, result **uint16) (hr error) = vmcompute.HcsModifyComputeSystem?
|
|
||||||
//sys hcsRegisterComputeSystemCallback(computeSystem hcsSystem, callback uintptr, context uintptr, callbackHandle *hcsCallback) (hr error) = vmcompute.HcsRegisterComputeSystemCallback?
|
|
||||||
//sys hcsUnregisterComputeSystemCallback(callbackHandle hcsCallback) (hr error) = vmcompute.HcsUnregisterComputeSystemCallback?
|
|
||||||
|
|
||||||
//sys hcsCreateProcess(computeSystem hcsSystem, processParameters string, processInformation *hcsProcessInformation, process *hcsProcess, result **uint16) (hr error) = vmcompute.HcsCreateProcess?
|
|
||||||
//sys hcsOpenProcess(computeSystem hcsSystem, pid uint32, process *hcsProcess, result **uint16) (hr error) = vmcompute.HcsOpenProcess?
|
|
||||||
//sys hcsCloseProcess(process hcsProcess) (hr error) = vmcompute.HcsCloseProcess?
|
|
||||||
//sys hcsTerminateProcess(process hcsProcess, result **uint16) (hr error) = vmcompute.HcsTerminateProcess?
|
|
||||||
//sys hcsGetProcessInfo(process hcsProcess, processInformation *hcsProcessInformation, result **uint16) (hr error) = vmcompute.HcsGetProcessInfo?
|
|
||||||
//sys hcsGetProcessProperties(process hcsProcess, processProperties **uint16, result **uint16) (hr error) = vmcompute.HcsGetProcessProperties?
|
|
||||||
//sys hcsModifyProcess(process hcsProcess, settings string, result **uint16) (hr error) = vmcompute.HcsModifyProcess?
|
|
||||||
//sys hcsGetServiceProperties(propertyQuery string, properties **uint16, result **uint16) (hr error) = vmcompute.HcsGetServiceProperties?
|
|
||||||
//sys hcsRegisterProcessCallback(process hcsProcess, callback uintptr, context uintptr, callbackHandle *hcsCallback) (hr error) = vmcompute.HcsRegisterProcessCallback?
|
|
||||||
//sys hcsUnregisterProcessCallback(callbackHandle hcsCallback) (hr error) = vmcompute.HcsUnregisterProcessCallback?
|
|
||||||
|
|
||||||
//sys hcsModifyServiceSettings(settings string, result **uint16) (hr error) = vmcompute.HcsModifyServiceSettings?
|
|
||||||
|
|
||||||
//sys _hnsCall(method string, path string, object string, response **uint16) (hr error) = vmcompute.HNSCall?
|
|
||||||
|
|
||||||
const (
|
const (
|
||||||
// Specific user-visible exit codes
|
// Specific user-visible exit codes
|
||||||
WaitErrExecFailed = 32767
|
WaitErrExecFailed = 32767
|
||||||
|
|
||||||
ERROR_GEN_FAILURE = syscall.Errno(31)
|
ERROR_GEN_FAILURE = hcserror.ERROR_GEN_FAILURE
|
||||||
ERROR_SHUTDOWN_IN_PROGRESS = syscall.Errno(1115)
|
ERROR_SHUTDOWN_IN_PROGRESS = syscall.Errno(1115)
|
||||||
WSAEINVAL = syscall.Errno(10022)
|
WSAEINVAL = syscall.Errno(10022)
|
||||||
|
|
||||||
|
@ -85,82 +25,4 @@ const (
|
||||||
TimeoutInfinite = 0xFFFFFFFF
|
TimeoutInfinite = 0xFFFFFFFF
|
||||||
)
|
)
|
||||||
|
|
||||||
type HcsError struct {
|
type HcsError = hcserror.HcsError
|
||||||
title string
|
|
||||||
rest string
|
|
||||||
Err error
|
|
||||||
}
|
|
||||||
|
|
||||||
type hcsSystem syscall.Handle
|
|
||||||
type hcsProcess syscall.Handle
|
|
||||||
type hcsCallback syscall.Handle
|
|
||||||
|
|
||||||
type hcsProcessInformation struct {
|
|
||||||
ProcessId uint32
|
|
||||||
Reserved uint32
|
|
||||||
StdInput syscall.Handle
|
|
||||||
StdOutput syscall.Handle
|
|
||||||
StdError syscall.Handle
|
|
||||||
}
|
|
||||||
|
|
||||||
func makeError(err error, title, rest string) error {
|
|
||||||
// Pass through DLL errors directly since they do not originate from HCS.
|
|
||||||
if _, ok := err.(*syscall.DLLError); ok {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
return &HcsError{title, rest, err}
|
|
||||||
}
|
|
||||||
|
|
||||||
func makeErrorf(err error, title, format string, a ...interface{}) error {
|
|
||||||
return makeError(err, title, fmt.Sprintf(format, a...))
|
|
||||||
}
|
|
||||||
|
|
||||||
func win32FromError(err error) uint32 {
|
|
||||||
if herr, ok := err.(*HcsError); ok {
|
|
||||||
return win32FromError(herr.Err)
|
|
||||||
}
|
|
||||||
if code, ok := err.(syscall.Errno); ok {
|
|
||||||
return uint32(code)
|
|
||||||
}
|
|
||||||
return uint32(ERROR_GEN_FAILURE)
|
|
||||||
}
|
|
||||||
|
|
||||||
func win32FromHresult(hr uintptr) uintptr {
|
|
||||||
if hr&0x1fff0000 == 0x00070000 {
|
|
||||||
return hr & 0xffff
|
|
||||||
}
|
|
||||||
return hr
|
|
||||||
}
|
|
||||||
|
|
||||||
func (e *HcsError) Error() string {
|
|
||||||
s := e.title
|
|
||||||
if len(s) > 0 && s[len(s)-1] != ' ' {
|
|
||||||
s += " "
|
|
||||||
}
|
|
||||||
s += fmt.Sprintf("failed in Win32: %s (0x%x)", e.Err, win32FromError(e.Err))
|
|
||||||
if e.rest != "" {
|
|
||||||
if e.rest[0] != ' ' {
|
|
||||||
s += " "
|
|
||||||
}
|
|
||||||
s += e.rest
|
|
||||||
}
|
|
||||||
return s
|
|
||||||
}
|
|
||||||
|
|
||||||
func convertAndFreeCoTaskMemString(buffer *uint16) string {
|
|
||||||
str := syscall.UTF16ToString((*[1 << 30]uint16)(unsafe.Pointer(buffer))[:])
|
|
||||||
coTaskMemFree(unsafe.Pointer(buffer))
|
|
||||||
return str
|
|
||||||
}
|
|
||||||
|
|
||||||
func convertAndFreeCoTaskMemBytes(buffer *uint16) []byte {
|
|
||||||
return []byte(convertAndFreeCoTaskMemString(buffer))
|
|
||||||
}
|
|
||||||
|
|
||||||
func processHcsResult(err error, resultp *uint16) error {
|
|
||||||
if resultp != nil {
|
|
||||||
result := convertAndFreeCoTaskMemString(resultp)
|
|
||||||
logrus.Debugf("Result: %s", result)
|
|
||||||
}
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
|
@ -1,29 +1,11 @@
|
||||||
package hcsshim
|
package hcsshim
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"encoding/json"
|
"github.com/Microsoft/hcsshim/internal/hns"
|
||||||
"net"
|
|
||||||
|
|
||||||
"github.com/sirupsen/logrus"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
// HNSEndpoint represents a network endpoint in HNS
|
// HNSEndpoint represents a network endpoint in HNS
|
||||||
type HNSEndpoint struct {
|
type HNSEndpoint = hns.HNSEndpoint
|
||||||
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
|
//SystemType represents the type of the system on which actions are done
|
||||||
type SystemType string
|
type SystemType string
|
||||||
|
@ -37,39 +19,19 @@ const (
|
||||||
|
|
||||||
// EndpointAttachDetachRequest is the structure used to send request to the container to modify the system
|
// 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
|
// Supported resource types are Network and Request Types are Add/Remove
|
||||||
type EndpointAttachDetachRequest struct {
|
type EndpointAttachDetachRequest = hns.EndpointAttachDetachRequest
|
||||||
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
|
// EndpointResquestResponse is object to get the endpoint request response
|
||||||
type EndpointResquestResponse struct {
|
type EndpointResquestResponse = hns.EndpointResquestResponse
|
||||||
Success bool
|
|
||||||
Error string
|
|
||||||
}
|
|
||||||
|
|
||||||
// HNSEndpointRequest makes a HNS call to modify/query a network endpoint
|
// HNSEndpointRequest makes a HNS call to modify/query a network endpoint
|
||||||
func HNSEndpointRequest(method, path, request string) (*HNSEndpoint, error) {
|
func HNSEndpointRequest(method, path, request string) (*HNSEndpoint, error) {
|
||||||
endpoint := &HNSEndpoint{}
|
return hns.HNSEndpointRequest(method, path, request)
|
||||||
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
|
// HNSListEndpointRequest makes a HNS call to query the list of available endpoints
|
||||||
func HNSListEndpointRequest() ([]HNSEndpoint, error) {
|
func HNSListEndpointRequest() ([]HNSEndpoint, error) {
|
||||||
var endpoint []HNSEndpoint
|
return hns.HNSListEndpointRequest()
|
||||||
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
|
// HotAttachEndpoint makes a HCS Call to attach the endpoint to the container
|
||||||
|
@ -120,204 +82,10 @@ func modifyNetworkEndpoint(containerID string, endpointID string, request Reques
|
||||||
|
|
||||||
// GetHNSEndpointByID get the Endpoint by ID
|
// GetHNSEndpointByID get the Endpoint by ID
|
||||||
func GetHNSEndpointByID(endpointID string) (*HNSEndpoint, error) {
|
func GetHNSEndpointByID(endpointID string) (*HNSEndpoint, error) {
|
||||||
return HNSEndpointRequest("GET", endpointID, "")
|
return hns.GetHNSEndpointByID(endpointID)
|
||||||
}
|
}
|
||||||
|
|
||||||
// GetHNSEndpointByName gets the endpoint filtered by Name
|
// GetHNSEndpointByName gets the endpoint filtered by Name
|
||||||
func GetHNSEndpointByName(endpointName string) (*HNSEndpoint, error) {
|
func GetHNSEndpointByName(endpointName string) (*HNSEndpoint, error) {
|
||||||
hnsResponse, err := HNSListEndpointRequest()
|
return hns.GetHNSEndpointByName(endpointName)
|
||||||
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)
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,16 @@
|
||||||
|
package hcsshim
|
||||||
|
|
||||||
|
import (
|
||||||
|
"github.com/Microsoft/hcsshim/internal/hns"
|
||||||
|
)
|
||||||
|
|
||||||
|
type HNSGlobals = hns.HNSGlobals
|
||||||
|
type HNSVersion = hns.HNSVersion
|
||||||
|
|
||||||
|
var (
|
||||||
|
HNSVersion1803 = hns.HNSVersion1803
|
||||||
|
)
|
||||||
|
|
||||||
|
func GetHNSGlobals() (*HNSGlobals, error) {
|
||||||
|
return hns.GetHNSGlobals()
|
||||||
|
}
|
|
@ -1,141 +1,36 @@
|
||||||
package hcsshim
|
package hcsshim
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"encoding/json"
|
"github.com/Microsoft/hcsshim/internal/hns"
|
||||||
"net"
|
|
||||||
|
|
||||||
"github.com/sirupsen/logrus"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
// Subnet is assoicated with a network and represents a list
|
// Subnet is assoicated with a network and represents a list
|
||||||
// of subnets available to the network
|
// of subnets available to the network
|
||||||
type Subnet struct {
|
type Subnet = hns.Subnet
|
||||||
AddressPrefix string `json:",omitempty"`
|
|
||||||
GatewayAddress string `json:",omitempty"`
|
|
||||||
Policies []json.RawMessage `json:",omitempty"`
|
|
||||||
}
|
|
||||||
|
|
||||||
// MacPool is assoicated with a network and represents a list
|
// MacPool is assoicated with a network and represents a list
|
||||||
// of macaddresses available to the network
|
// of macaddresses available to the network
|
||||||
type MacPool struct {
|
type MacPool = hns.MacPool
|
||||||
StartMacAddress string `json:",omitempty"`
|
|
||||||
EndMacAddress string `json:",omitempty"`
|
|
||||||
}
|
|
||||||
|
|
||||||
// HNSNetwork represents a network in HNS
|
// HNSNetwork represents a network in HNS
|
||||||
type HNSNetwork struct {
|
type HNSNetwork = hns.HNSNetwork
|
||||||
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
|
// HNSNetworkRequest makes a call into HNS to update/query a single network
|
||||||
func HNSNetworkRequest(method, path, request string) (*HNSNetwork, error) {
|
func HNSNetworkRequest(method, path, request string) (*HNSNetwork, error) {
|
||||||
var network HNSNetwork
|
return hns.HNSNetworkRequest(method, path, request)
|
||||||
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
|
// HNSListNetworkRequest makes a HNS call to query the list of available networks
|
||||||
func HNSListNetworkRequest(method, path, request string) ([]HNSNetwork, error) {
|
func HNSListNetworkRequest(method, path, request string) ([]HNSNetwork, error) {
|
||||||
var network []HNSNetwork
|
return hns.HNSListNetworkRequest(method, path, request)
|
||||||
err := hnsCall(method, "/networks/"+path, request, &network)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
return network, nil
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// GetHNSNetworkByID
|
// GetHNSNetworkByID
|
||||||
func GetHNSNetworkByID(networkID string) (*HNSNetwork, error) {
|
func GetHNSNetworkByID(networkID string) (*HNSNetwork, error) {
|
||||||
return HNSNetworkRequest("GET", networkID, "")
|
return hns.GetHNSNetworkByID(networkID)
|
||||||
}
|
}
|
||||||
|
|
||||||
// GetHNSNetworkName filtered by Name
|
// GetHNSNetworkName filtered by Name
|
||||||
func GetHNSNetworkByName(networkName string) (*HNSNetwork, error) {
|
func GetHNSNetworkByName(networkName string) (*HNSNetwork, error) {
|
||||||
hsnnetworks, err := HNSListNetworkRequest("GET", "", "")
|
return hns.GetHNSNetworkByName(networkName)
|
||||||
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)
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,94 +1,57 @@
|
||||||
package hcsshim
|
package hcsshim
|
||||||
|
|
||||||
|
import (
|
||||||
|
"github.com/Microsoft/hcsshim/internal/hns"
|
||||||
|
)
|
||||||
|
|
||||||
// Type of Request Support in ModifySystem
|
// Type of Request Support in ModifySystem
|
||||||
type PolicyType string
|
type PolicyType = hns.PolicyType
|
||||||
|
|
||||||
// RequestType const
|
// RequestType const
|
||||||
const (
|
const (
|
||||||
Nat PolicyType = "NAT"
|
Nat = hns.Nat
|
||||||
ACL PolicyType = "ACL"
|
ACL = hns.ACL
|
||||||
PA PolicyType = "PA"
|
PA = hns.PA
|
||||||
VLAN PolicyType = "VLAN"
|
VLAN = hns.VLAN
|
||||||
VSID PolicyType = "VSID"
|
VSID = hns.VSID
|
||||||
VNet PolicyType = "VNET"
|
VNet = hns.VNet
|
||||||
L2Driver PolicyType = "L2Driver"
|
L2Driver = hns.L2Driver
|
||||||
Isolation PolicyType = "Isolation"
|
Isolation = hns.Isolation
|
||||||
QOS PolicyType = "QOS"
|
QOS = hns.QOS
|
||||||
OutboundNat PolicyType = "OutBoundNAT"
|
OutboundNat = hns.OutboundNat
|
||||||
ExternalLoadBalancer PolicyType = "ELB"
|
ExternalLoadBalancer = hns.ExternalLoadBalancer
|
||||||
Route PolicyType = "ROUTE"
|
Route = hns.Route
|
||||||
)
|
)
|
||||||
|
|
||||||
type NatPolicy struct {
|
type NatPolicy = hns.NatPolicy
|
||||||
Type PolicyType `json:"Type"`
|
|
||||||
Protocol string
|
|
||||||
InternalPort uint16
|
|
||||||
ExternalPort uint16
|
|
||||||
}
|
|
||||||
|
|
||||||
type QosPolicy struct {
|
type QosPolicy = hns.QosPolicy
|
||||||
Type PolicyType `json:"Type"`
|
|
||||||
MaximumOutgoingBandwidthInBytes uint64
|
|
||||||
}
|
|
||||||
|
|
||||||
type IsolationPolicy struct {
|
type IsolationPolicy = hns.IsolationPolicy
|
||||||
Type PolicyType `json:"Type"`
|
|
||||||
VLAN uint
|
|
||||||
VSID uint
|
|
||||||
InDefaultIsolation bool
|
|
||||||
}
|
|
||||||
|
|
||||||
type VlanPolicy struct {
|
type VlanPolicy = hns.VlanPolicy
|
||||||
Type PolicyType `json:"Type"`
|
|
||||||
VLAN uint
|
|
||||||
}
|
|
||||||
|
|
||||||
type VsidPolicy struct {
|
type VsidPolicy = hns.VsidPolicy
|
||||||
Type PolicyType `json:"Type"`
|
|
||||||
VSID uint
|
|
||||||
}
|
|
||||||
|
|
||||||
type PaPolicy struct {
|
type PaPolicy = hns.PaPolicy
|
||||||
Type PolicyType `json:"Type"`
|
|
||||||
PA string `json:"PA"`
|
|
||||||
}
|
|
||||||
|
|
||||||
type OutboundNatPolicy struct {
|
type OutboundNatPolicy = hns.OutboundNatPolicy
|
||||||
Policy
|
|
||||||
VIP string `json:"VIP,omitempty"`
|
|
||||||
Exceptions []string `json:"ExceptionList,omitempty"`
|
|
||||||
}
|
|
||||||
|
|
||||||
type ActionType string
|
type ActionType = hns.ActionType
|
||||||
type DirectionType string
|
type DirectionType = hns.DirectionType
|
||||||
type RuleType string
|
type RuleType = hns.RuleType
|
||||||
|
|
||||||
const (
|
const (
|
||||||
Allow ActionType = "Allow"
|
Allow = hns.Allow
|
||||||
Block ActionType = "Block"
|
Block = hns.Block
|
||||||
|
|
||||||
In DirectionType = "In"
|
In = hns.In
|
||||||
Out DirectionType = "Out"
|
Out = hns.Out
|
||||||
|
|
||||||
Host RuleType = "Host"
|
Host = hns.Host
|
||||||
Switch RuleType = "Switch"
|
Switch = hns.Switch
|
||||||
)
|
)
|
||||||
|
|
||||||
type ACLPolicy struct {
|
type ACLPolicy = hns.ACLPolicy
|
||||||
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 Policy = hns.Policy
|
||||||
Type PolicyType `json:"Type"`
|
|
||||||
}
|
|
||||||
|
|
|
@ -1,200 +1,47 @@
|
||||||
package hcsshim
|
package hcsshim
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"encoding/json"
|
"github.com/Microsoft/hcsshim/internal/hns"
|
||||||
|
|
||||||
"github.com/sirupsen/logrus"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
// RoutePolicy is a structure defining schema for Route based Policy
|
// RoutePolicy is a structure defining schema for Route based Policy
|
||||||
type RoutePolicy struct {
|
type RoutePolicy = hns.RoutePolicy
|
||||||
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
|
// ELBPolicy is a structure defining schema for ELB LoadBalancing based Policy
|
||||||
type ELBPolicy struct {
|
type ELBPolicy = hns.ELBPolicy
|
||||||
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
|
// LBPolicy is a structure defining schema for LoadBalancing based Policy
|
||||||
type LBPolicy struct {
|
type LBPolicy = hns.LBPolicy
|
||||||
Policy
|
|
||||||
Protocol uint16 `json:"Protocol,omitempty"`
|
|
||||||
InternalPort uint16
|
|
||||||
ExternalPort uint16
|
|
||||||
}
|
|
||||||
|
|
||||||
// PolicyList is a structure defining schema for Policy list request
|
// PolicyList is a structure defining schema for Policy list request
|
||||||
type PolicyList struct {
|
type PolicyList = hns.PolicyList
|
||||||
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
|
// HNSPolicyListRequest makes a call into HNS to update/query a single network
|
||||||
func HNSPolicyListRequest(method, path, request string) (*PolicyList, error) {
|
func HNSPolicyListRequest(method, path, request string) (*PolicyList, error) {
|
||||||
var policy PolicyList
|
return hns.HNSPolicyListRequest(method, path, request)
|
||||||
err := hnsCall(method, "/policylists/"+path, request, &policy)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
return &policy, nil
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// HNSListPolicyListRequest gets all the policy list
|
// HNSListPolicyListRequest gets all the policy list
|
||||||
func HNSListPolicyListRequest() ([]PolicyList, error) {
|
func HNSListPolicyListRequest() ([]PolicyList, error) {
|
||||||
var plist []PolicyList
|
return hns.HNSListPolicyListRequest()
|
||||||
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
|
// PolicyListRequest makes a HNS call to modify/query a network policy list
|
||||||
func PolicyListRequest(method, path, request string) (*PolicyList, error) {
|
func PolicyListRequest(method, path, request string) (*PolicyList, error) {
|
||||||
policylist := &PolicyList{}
|
return hns.PolicyListRequest(method, path, request)
|
||||||
err := hnsCall(method, "/policylists/"+path, request, &policylist)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
return policylist, nil
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// GetPolicyListByID get the policy list by ID
|
// GetPolicyListByID get the policy list by ID
|
||||||
func GetPolicyListByID(policyListID string) (*PolicyList, error) {
|
func GetPolicyListByID(policyListID string) (*PolicyList, error) {
|
||||||
return PolicyListRequest("GET", policyListID, "")
|
return hns.GetPolicyListByID(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
|
// AddLoadBalancer policy list for the specified endpoints
|
||||||
func AddLoadBalancer(endpoints []HNSEndpoint, isILB bool, sourceVIP, vip string, protocol uint16, internalPort uint16, externalPort uint16) (*PolicyList, error) {
|
func AddLoadBalancer(endpoints []HNSEndpoint, isILB bool, sourceVIP, vip string, protocol uint16, internalPort uint16, externalPort uint16) (*PolicyList, error) {
|
||||||
operation := "AddLoadBalancer"
|
return hns.AddLoadBalancer(endpoints, isILB, sourceVIP, vip, protocol, internalPort, externalPort)
|
||||||
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
|
// AddRoute adds route policy list for the specified endpoints
|
||||||
func AddRoute(endpoints []HNSEndpoint, destinationPrefix string, nextHop string, encapEnabled bool) (*PolicyList, error) {
|
func AddRoute(endpoints []HNSEndpoint, destinationPrefix string, nextHop string, encapEnabled bool) (*PolicyList, error) {
|
||||||
operation := "AddRoute"
|
return hns.AddRoute(endpoints, destinationPrefix, nextHop, encapEnabled)
|
||||||
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()
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,13 @@
|
||||||
|
package hcsshim
|
||||||
|
|
||||||
|
import (
|
||||||
|
"github.com/Microsoft/hcsshim/internal/hns"
|
||||||
|
)
|
||||||
|
|
||||||
|
type HNSSupportedFeatures = hns.HNSSupportedFeatures
|
||||||
|
|
||||||
|
type HNSAclFeatures = hns.HNSAclFeatures
|
||||||
|
|
||||||
|
func GetHNSSupportedFeatures() HNSSupportedFeatures {
|
||||||
|
return hns.GetHNSSupportedFeatures()
|
||||||
|
}
|
|
@ -1,106 +1,27 @@
|
||||||
package hcsshim
|
package hcsshim
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"encoding/json"
|
|
||||||
"io"
|
"io"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
|
"github.com/Microsoft/hcsshim/internal/schema1"
|
||||||
)
|
)
|
||||||
|
|
||||||
// ProcessConfig is used as both the input of Container.CreateProcess
|
// ProcessConfig is used as both the input of Container.CreateProcess
|
||||||
// and to convert the parameters to JSON for passing onto the HCS
|
// and to convert the parameters to JSON for passing onto the HCS
|
||||||
type ProcessConfig struct {
|
type ProcessConfig = schema1.ProcessConfig
|
||||||
ApplicationName string `json:",omitempty"`
|
|
||||||
CommandLine string `json:",omitempty"`
|
|
||||||
CommandArgs []string `json:",omitempty"` // Used by Linux Containers on Windows
|
|
||||||
User string `json:",omitempty"`
|
|
||||||
WorkingDirectory string `json:",omitempty"`
|
|
||||||
Environment map[string]string `json:",omitempty"`
|
|
||||||
EmulateConsole bool `json:",omitempty"`
|
|
||||||
CreateStdInPipe bool `json:",omitempty"`
|
|
||||||
CreateStdOutPipe bool `json:",omitempty"`
|
|
||||||
CreateStdErrPipe bool `json:",omitempty"`
|
|
||||||
ConsoleSize [2]uint `json:",omitempty"`
|
|
||||||
CreateInUtilityVm bool `json:",omitempty"` // Used by Linux Containers on Windows
|
|
||||||
OCISpecification *json.RawMessage `json:",omitempty"` // Used by Linux Containers on Windows
|
|
||||||
}
|
|
||||||
|
|
||||||
type Layer struct {
|
type Layer = schema1.Layer
|
||||||
ID string
|
type MappedDir = schema1.MappedDir
|
||||||
Path string
|
type MappedPipe = schema1.MappedPipe
|
||||||
}
|
type HvRuntime = schema1.HvRuntime
|
||||||
|
type MappedVirtualDisk = schema1.MappedVirtualDisk
|
||||||
type MappedDir struct {
|
|
||||||
HostPath string
|
|
||||||
ContainerPath string
|
|
||||||
ReadOnly bool
|
|
||||||
BandwidthMaximum uint64
|
|
||||||
IOPSMaximum uint64
|
|
||||||
CreateInUtilityVM bool
|
|
||||||
}
|
|
||||||
|
|
||||||
type MappedPipe struct {
|
|
||||||
HostPath string
|
|
||||||
ContainerPipeName string
|
|
||||||
}
|
|
||||||
|
|
||||||
type HvRuntime struct {
|
|
||||||
ImagePath string `json:",omitempty"`
|
|
||||||
SkipTemplate bool `json:",omitempty"`
|
|
||||||
LinuxInitrdFile string `json:",omitempty"` // File under ImagePath on host containing an initrd image for starting a Linux utility VM
|
|
||||||
LinuxKernelFile string `json:",omitempty"` // File under ImagePath on host containing a kernel for starting a Linux utility VM
|
|
||||||
LinuxBootParameters string `json:",omitempty"` // Additional boot parameters for starting a Linux Utility VM in initrd mode
|
|
||||||
BootSource string `json:",omitempty"` // "Vhd" for Linux Utility VM booting from VHD
|
|
||||||
WritableBootSource bool `json:",omitempty"` // Linux Utility VM booting from VHD
|
|
||||||
}
|
|
||||||
|
|
||||||
type MappedVirtualDisk struct {
|
|
||||||
HostPath string `json:",omitempty"` // Path to VHD on the host
|
|
||||||
ContainerPath string // Platform-specific mount point path in the container
|
|
||||||
CreateInUtilityVM bool `json:",omitempty"`
|
|
||||||
ReadOnly bool `json:",omitempty"`
|
|
||||||
Cache string `json:",omitempty"` // "" (Unspecified); "Disabled"; "Enabled"; "Private"; "PrivateAllowSharing"
|
|
||||||
AttachOnly bool `json:",omitempty:`
|
|
||||||
}
|
|
||||||
|
|
||||||
// ContainerConfig is used as both the input of CreateContainer
|
// ContainerConfig is used as both the input of CreateContainer
|
||||||
// and to convert the parameters to JSON for passing onto the HCS
|
// and to convert the parameters to JSON for passing onto the HCS
|
||||||
type ContainerConfig struct {
|
type ContainerConfig = schema1.ContainerConfig
|
||||||
SystemType string // HCS requires this to be hard-coded to "Container"
|
|
||||||
Name string // Name of the container. We use the docker ID.
|
|
||||||
Owner string `json:",omitempty"` // The management platform that created this container
|
|
||||||
VolumePath string `json:",omitempty"` // Windows volume path for scratch space. Used by Windows Server Containers only. Format \\?\\Volume{GUID}
|
|
||||||
IgnoreFlushesDuringBoot bool `json:",omitempty"` // Optimization hint for container startup in Windows
|
|
||||||
LayerFolderPath string `json:",omitempty"` // Where the layer folders are located. Used by Windows Server Containers only. Format %root%\windowsfilter\containerID
|
|
||||||
Layers []Layer // List of storage layers. Required for Windows Server and Hyper-V Containers. Format ID=GUID;Path=%root%\windowsfilter\layerID
|
|
||||||
Credentials string `json:",omitempty"` // Credentials information
|
|
||||||
ProcessorCount uint32 `json:",omitempty"` // Number of processors to assign to the container.
|
|
||||||
ProcessorWeight uint64 `json:",omitempty"` // CPU shares (relative weight to other containers with cpu shares). Range is from 1 to 10000. A value of 0 results in default shares.
|
|
||||||
ProcessorMaximum int64 `json:",omitempty"` // Specifies the portion of processor cycles that this container can use as a percentage times 100. Range is from 1 to 10000. A value of 0 results in no limit.
|
|
||||||
StorageIOPSMaximum uint64 `json:",omitempty"` // Maximum Storage IOPS
|
|
||||||
StorageBandwidthMaximum uint64 `json:",omitempty"` // Maximum Storage Bandwidth in bytes per second
|
|
||||||
StorageSandboxSize uint64 `json:",omitempty"` // Size in bytes that the container system drive should be expanded to if smaller
|
|
||||||
MemoryMaximumInMB int64 `json:",omitempty"` // Maximum memory available to the container in Megabytes
|
|
||||||
HostName string `json:",omitempty"` // Hostname
|
|
||||||
MappedDirectories []MappedDir `json:",omitempty"` // List of mapped directories (volumes/mounts)
|
|
||||||
MappedPipes []MappedPipe `json:",omitempty"` // List of mapped Windows named pipes
|
|
||||||
HvPartition bool // True if it a Hyper-V Container
|
|
||||||
NetworkSharedContainerName string `json:",omitempty"` // Name (ID) of the container that we will share the network stack with.
|
|
||||||
EndpointList []string `json:",omitempty"` // List of networking endpoints to be attached to container
|
|
||||||
HvRuntime *HvRuntime `json:",omitempty"` // Hyper-V container settings. Used by Hyper-V containers only. Format ImagePath=%root%\BaseLayerID\UtilityVM
|
|
||||||
Servicing bool `json:",omitempty"` // True if this container is for servicing
|
|
||||||
AllowUnqualifiedDNSQuery bool `json:",omitempty"` // True to allow unqualified DNS name resolution
|
|
||||||
DNSSearchList string `json:",omitempty"` // Comma seperated list of DNS suffixes to use for name resolution
|
|
||||||
ContainerType string `json:",omitempty"` // "Linux" for Linux containers on Windows. Omitted otherwise.
|
|
||||||
TerminateOnLastHandleClosed bool `json:",omitempty"` // Should HCS terminate the container once all handles have been closed
|
|
||||||
MappedVirtualDisks []MappedVirtualDisk `json:",omitempty"` // Array of virtual disks to mount at start
|
|
||||||
}
|
|
||||||
|
|
||||||
type ComputeSystemQuery struct {
|
type ComputeSystemQuery = schema1.ComputeSystemQuery
|
||||||
IDs []string `json:"Ids,omitempty"`
|
|
||||||
Types []string `json:",omitempty"`
|
|
||||||
Names []string `json:",omitempty"`
|
|
||||||
Owners []string `json:",omitempty"`
|
|
||||||
}
|
|
||||||
|
|
||||||
// Container represents a created (but not necessarily running) container.
|
// Container represents a created (but not necessarily running) container.
|
||||||
type Container interface {
|
type Container interface {
|
||||||
|
|
|
@ -0,0 +1,22 @@
|
||||||
|
package guid
|
||||||
|
|
||||||
|
import (
|
||||||
|
"crypto/rand"
|
||||||
|
"fmt"
|
||||||
|
"io"
|
||||||
|
)
|
||||||
|
|
||||||
|
type GUID [16]byte
|
||||||
|
|
||||||
|
func New() GUID {
|
||||||
|
g := GUID{}
|
||||||
|
_, err := io.ReadFull(rand.Reader, g[:])
|
||||||
|
if err != nil {
|
||||||
|
panic(err)
|
||||||
|
}
|
||||||
|
return g
|
||||||
|
}
|
||||||
|
|
||||||
|
func (g GUID) String() string {
|
||||||
|
return fmt.Sprintf("%02x%02x%02x%02x-%02x%02x-%02x%02x-%02x-%02x", g[3], g[2], g[1], g[0], g[5], g[4], g[7], g[6], g[8:10], g[10:])
|
||||||
|
}
|
|
@ -1,8 +1,10 @@
|
||||||
package hcsshim
|
package hcs
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"sync"
|
"sync"
|
||||||
"syscall"
|
"syscall"
|
||||||
|
|
||||||
|
"github.com/Microsoft/hcsshim/internal/interop"
|
||||||
)
|
)
|
||||||
|
|
||||||
var (
|
var (
|
||||||
|
@ -62,7 +64,7 @@ func closeChannels(channels notificationChannels) {
|
||||||
func notificationWatcher(notificationType hcsNotification, callbackNumber uintptr, notificationStatus uintptr, notificationData *uint16) uintptr {
|
func notificationWatcher(notificationType hcsNotification, callbackNumber uintptr, notificationStatus uintptr, notificationData *uint16) uintptr {
|
||||||
var result error
|
var result error
|
||||||
if int32(notificationStatus) < 0 {
|
if int32(notificationStatus) < 0 {
|
||||||
result = syscall.Errno(win32FromHresult(notificationStatus))
|
result = interop.Win32FromHresult(notificationStatus)
|
||||||
}
|
}
|
||||||
|
|
||||||
callbackMapLock.RLock()
|
callbackMapLock.RLock()
|
|
@ -1,4 +1,4 @@
|
||||||
package hcsshim
|
package hcs
|
||||||
|
|
||||||
import "C"
|
import "C"
|
||||||
|
|
|
@ -0,0 +1,279 @@
|
||||||
|
package hcs
|
||||||
|
|
||||||
|
import (
|
||||||
|
"encoding/json"
|
||||||
|
"errors"
|
||||||
|
"fmt"
|
||||||
|
"syscall"
|
||||||
|
|
||||||
|
"github.com/Microsoft/hcsshim/internal/interop"
|
||||||
|
"github.com/sirupsen/logrus"
|
||||||
|
)
|
||||||
|
|
||||||
|
var (
|
||||||
|
// ErrComputeSystemDoesNotExist is an error encountered when the container being operated on no longer exists
|
||||||
|
ErrComputeSystemDoesNotExist = syscall.Errno(0xc037010e)
|
||||||
|
|
||||||
|
// ErrElementNotFound is an error encountered when the object being referenced does not exist
|
||||||
|
ErrElementNotFound = syscall.Errno(0x490)
|
||||||
|
|
||||||
|
// ErrElementNotFound is an error encountered when the object being referenced does not exist
|
||||||
|
ErrNotSupported = syscall.Errno(0x32)
|
||||||
|
|
||||||
|
// ErrInvalidData is an error encountered when the request being sent to hcs is invalid/unsupported
|
||||||
|
// decimal -2147024883 / hex 0x8007000d
|
||||||
|
ErrInvalidData = syscall.Errno(0xd)
|
||||||
|
|
||||||
|
// ErrHandleClose is an error encountered when the handle generating the notification being waited on has been closed
|
||||||
|
ErrHandleClose = errors.New("hcsshim: the handle generating this notification has been closed")
|
||||||
|
|
||||||
|
// ErrAlreadyClosed is an error encountered when using a handle that has been closed by the Close method
|
||||||
|
ErrAlreadyClosed = errors.New("hcsshim: the handle has already been closed")
|
||||||
|
|
||||||
|
// ErrInvalidNotificationType is an error encountered when an invalid notification type is used
|
||||||
|
ErrInvalidNotificationType = errors.New("hcsshim: invalid notification type")
|
||||||
|
|
||||||
|
// ErrInvalidProcessState is an error encountered when the process is not in a valid state for the requested operation
|
||||||
|
ErrInvalidProcessState = errors.New("the process is in an invalid state for the attempted operation")
|
||||||
|
|
||||||
|
// ErrTimeout is an error encountered when waiting on a notification times out
|
||||||
|
ErrTimeout = errors.New("hcsshim: timeout waiting for notification")
|
||||||
|
|
||||||
|
// ErrUnexpectedContainerExit is the error encountered when a container exits while waiting for
|
||||||
|
// a different expected notification
|
||||||
|
ErrUnexpectedContainerExit = errors.New("unexpected container exit")
|
||||||
|
|
||||||
|
// ErrUnexpectedProcessAbort is the error encountered when communication with the compute service
|
||||||
|
// is lost while waiting for a notification
|
||||||
|
ErrUnexpectedProcessAbort = errors.New("lost communication with compute service")
|
||||||
|
|
||||||
|
// ErrUnexpectedValue is an error encountered when hcs returns an invalid value
|
||||||
|
ErrUnexpectedValue = errors.New("unexpected value returned from hcs")
|
||||||
|
|
||||||
|
// ErrVmcomputeAlreadyStopped is an error encountered when a shutdown or terminate request is made on a stopped container
|
||||||
|
ErrVmcomputeAlreadyStopped = syscall.Errno(0xc0370110)
|
||||||
|
|
||||||
|
// ErrVmcomputeOperationPending is an error encountered when the operation is being completed asynchronously
|
||||||
|
ErrVmcomputeOperationPending = syscall.Errno(0xC0370103)
|
||||||
|
|
||||||
|
// ErrVmcomputeOperationInvalidState is an error encountered when the compute system is not in a valid state for the requested operation
|
||||||
|
ErrVmcomputeOperationInvalidState = syscall.Errno(0xc0370105)
|
||||||
|
|
||||||
|
// ErrProcNotFound is an error encountered when the the process cannot be found
|
||||||
|
ErrProcNotFound = syscall.Errno(0x7f)
|
||||||
|
|
||||||
|
// ErrVmcomputeOperationAccessIsDenied is an error which can be encountered when enumerating compute systems in RS1/RS2
|
||||||
|
// builds when the underlying silo might be in the process of terminating. HCS was fixed in RS3.
|
||||||
|
ErrVmcomputeOperationAccessIsDenied = syscall.Errno(0x5)
|
||||||
|
|
||||||
|
// ErrVmcomputeInvalidJSON is an error encountered when the compute system does not support/understand the messages sent by management
|
||||||
|
ErrVmcomputeInvalidJSON = syscall.Errno(0xc037010d)
|
||||||
|
|
||||||
|
// ErrVmcomputeUnknownMessage is an error encountered guest compute system doesn't support the message
|
||||||
|
ErrVmcomputeUnknownMessage = syscall.Errno(0xc037010b)
|
||||||
|
|
||||||
|
// ErrNotSupported is an error encountered when hcs doesn't support the request
|
||||||
|
ErrPlatformNotSupported = errors.New("unsupported platform request")
|
||||||
|
)
|
||||||
|
|
||||||
|
type ErrorEvent struct {
|
||||||
|
Message string `json:"Message,omitempty"` // Fully formated error message
|
||||||
|
StackTrace string `json:"StackTrace,omitempty"` // Stack trace in string form
|
||||||
|
Provider string `json:"Provider,omitempty"`
|
||||||
|
EventID uint16 `json:"EventId,omitempty"`
|
||||||
|
Flags uint32 `json:"Flags,omitempty"`
|
||||||
|
Source string `json:"Source,omitempty"`
|
||||||
|
//Data []EventData `json:"Data,omitempty"` // Omit this as HCS doesn't encode this well. It's more confusing to include. It is however logged in debug mode (see processHcsResult function)
|
||||||
|
}
|
||||||
|
|
||||||
|
type hcsResult struct {
|
||||||
|
Error int32
|
||||||
|
ErrorMessage string
|
||||||
|
ErrorEvents []ErrorEvent `json:"ErrorEvents,omitempty"`
|
||||||
|
}
|
||||||
|
|
||||||
|
func (ev *ErrorEvent) String() string {
|
||||||
|
evs := "[Event Detail: " + ev.Message
|
||||||
|
if ev.StackTrace != "" {
|
||||||
|
evs += " Stack Trace: " + ev.StackTrace
|
||||||
|
}
|
||||||
|
if ev.Provider != "" {
|
||||||
|
evs += " Provider: " + ev.Provider
|
||||||
|
}
|
||||||
|
if ev.EventID != 0 {
|
||||||
|
evs = fmt.Sprintf("%s EventID: %d", evs, ev.EventID)
|
||||||
|
}
|
||||||
|
if ev.Flags != 0 {
|
||||||
|
evs = fmt.Sprintf("%s flags: %d", evs, ev.Flags)
|
||||||
|
}
|
||||||
|
if ev.Source != "" {
|
||||||
|
evs += " Source: " + ev.Source
|
||||||
|
}
|
||||||
|
evs += "]"
|
||||||
|
return evs
|
||||||
|
}
|
||||||
|
|
||||||
|
func processHcsResult(resultp *uint16) []ErrorEvent {
|
||||||
|
if resultp != nil {
|
||||||
|
resultj := interop.ConvertAndFreeCoTaskMemString(resultp)
|
||||||
|
logrus.Debugf("Result: %s", resultj)
|
||||||
|
result := &hcsResult{}
|
||||||
|
if err := json.Unmarshal([]byte(resultj), result); err != nil {
|
||||||
|
logrus.Warnf("Could not unmarshal HCS result %s: %s", resultj, err)
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
return result.ErrorEvents
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
type HcsError struct {
|
||||||
|
Op string
|
||||||
|
Err error
|
||||||
|
Events []ErrorEvent
|
||||||
|
}
|
||||||
|
|
||||||
|
func (e *HcsError) Error() string {
|
||||||
|
s := e.Op + ": " + e.Err.Error()
|
||||||
|
for _, ev := range e.Events {
|
||||||
|
s += "\n" + ev.String()
|
||||||
|
}
|
||||||
|
return s
|
||||||
|
}
|
||||||
|
|
||||||
|
// ProcessError is an error encountered in HCS during an operation on a Process object
|
||||||
|
type ProcessError struct {
|
||||||
|
SystemID string
|
||||||
|
Pid int
|
||||||
|
Op string
|
||||||
|
Err error
|
||||||
|
Events []ErrorEvent
|
||||||
|
}
|
||||||
|
|
||||||
|
// SystemError is an error encountered in HCS during an operation on a Container object
|
||||||
|
type SystemError struct {
|
||||||
|
ID string
|
||||||
|
Op string
|
||||||
|
Err error
|
||||||
|
Extra string
|
||||||
|
Events []ErrorEvent
|
||||||
|
}
|
||||||
|
|
||||||
|
func (e *SystemError) Error() string {
|
||||||
|
s := e.Op + " " + e.ID + ": " + e.Err.Error()
|
||||||
|
for _, ev := range e.Events {
|
||||||
|
s += "\n" + ev.String()
|
||||||
|
}
|
||||||
|
if e.Extra != "" {
|
||||||
|
s += "\n(extra info: " + e.Extra + ")"
|
||||||
|
}
|
||||||
|
return s
|
||||||
|
}
|
||||||
|
|
||||||
|
func makeSystemError(system *System, op string, extra string, err error, events []ErrorEvent) error {
|
||||||
|
// Don't double wrap errors
|
||||||
|
if _, ok := err.(*SystemError); ok {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
return &SystemError{
|
||||||
|
ID: system.ID(),
|
||||||
|
Op: op,
|
||||||
|
Extra: extra,
|
||||||
|
Err: err,
|
||||||
|
Events: events,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (e *ProcessError) Error() string {
|
||||||
|
s := fmt.Sprintf("%s %s:%d: %s", e.Op, e.SystemID, e.Pid, e.Err.Error())
|
||||||
|
for _, ev := range e.Events {
|
||||||
|
s += "\n" + ev.String()
|
||||||
|
}
|
||||||
|
return s
|
||||||
|
}
|
||||||
|
|
||||||
|
func makeProcessError(process *Process, op string, err error, events []ErrorEvent) error {
|
||||||
|
// Don't double wrap errors
|
||||||
|
if _, ok := err.(*ProcessError); ok {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
return &ProcessError{
|
||||||
|
Pid: process.Pid(),
|
||||||
|
SystemID: process.SystemID(),
|
||||||
|
Op: op,
|
||||||
|
Err: err,
|
||||||
|
Events: events,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// IsNotExist checks if an error is caused by the Container or Process not existing.
|
||||||
|
// Note: Currently, ErrElementNotFound can mean that a Process has either
|
||||||
|
// already exited, or does not exist. Both IsAlreadyStopped and IsNotExist
|
||||||
|
// will currently return true when the error is ErrElementNotFound or ErrProcNotFound.
|
||||||
|
func IsNotExist(err error) bool {
|
||||||
|
err = getInnerError(err)
|
||||||
|
return err == ErrComputeSystemDoesNotExist ||
|
||||||
|
err == ErrElementNotFound ||
|
||||||
|
err == ErrProcNotFound
|
||||||
|
}
|
||||||
|
|
||||||
|
// IsAlreadyClosed checks if an error is caused by the Container or Process having been
|
||||||
|
// already closed by a call to the Close() method.
|
||||||
|
func IsAlreadyClosed(err error) bool {
|
||||||
|
err = getInnerError(err)
|
||||||
|
return err == ErrAlreadyClosed
|
||||||
|
}
|
||||||
|
|
||||||
|
// IsPending returns a boolean indicating whether the error is that
|
||||||
|
// the requested operation is being completed in the background.
|
||||||
|
func IsPending(err error) bool {
|
||||||
|
err = getInnerError(err)
|
||||||
|
return err == ErrVmcomputeOperationPending
|
||||||
|
}
|
||||||
|
|
||||||
|
// IsTimeout returns a boolean indicating whether the error is caused by
|
||||||
|
// a timeout waiting for the operation to complete.
|
||||||
|
func IsTimeout(err error) bool {
|
||||||
|
err = getInnerError(err)
|
||||||
|
return err == ErrTimeout
|
||||||
|
}
|
||||||
|
|
||||||
|
// IsAlreadyStopped returns a boolean indicating whether the error is caused by
|
||||||
|
// a Container or Process being already stopped.
|
||||||
|
// Note: Currently, ErrElementNotFound can mean that a Process has either
|
||||||
|
// already exited, or does not exist. Both IsAlreadyStopped and IsNotExist
|
||||||
|
// will currently return true when the error is ErrElementNotFound or ErrProcNotFound.
|
||||||
|
func IsAlreadyStopped(err error) bool {
|
||||||
|
err = getInnerError(err)
|
||||||
|
return err == ErrVmcomputeAlreadyStopped ||
|
||||||
|
err == ErrElementNotFound ||
|
||||||
|
err == ErrProcNotFound
|
||||||
|
}
|
||||||
|
|
||||||
|
// IsNotSupported returns a boolean indicating whether the error is caused by
|
||||||
|
// unsupported platform requests
|
||||||
|
// Note: Currently Unsupported platform requests can be mean either
|
||||||
|
// ErrVmcomputeInvalidJSON, ErrInvalidData, ErrNotSupported or ErrVmcomputeUnknownMessage
|
||||||
|
// is thrown from the Platform
|
||||||
|
func IsNotSupported(err error) bool {
|
||||||
|
err = getInnerError(err)
|
||||||
|
// If Platform doesn't recognize or support the request sent, below errors are seen
|
||||||
|
return err == ErrVmcomputeInvalidJSON ||
|
||||||
|
err == ErrInvalidData ||
|
||||||
|
err == ErrNotSupported ||
|
||||||
|
err == ErrVmcomputeUnknownMessage
|
||||||
|
}
|
||||||
|
|
||||||
|
func getInnerError(err error) error {
|
||||||
|
switch pe := err.(type) {
|
||||||
|
case nil:
|
||||||
|
return nil
|
||||||
|
case *HcsError:
|
||||||
|
err = pe.Err
|
||||||
|
case *SystemError:
|
||||||
|
err = pe.Err
|
||||||
|
case *ProcessError:
|
||||||
|
err = pe.Err
|
||||||
|
}
|
||||||
|
return err
|
||||||
|
}
|
|
@ -0,0 +1,47 @@
|
||||||
|
// Shim for the Host Compute Service (HCS) to manage Windows Server
|
||||||
|
// containers and Hyper-V containers.
|
||||||
|
|
||||||
|
package hcs
|
||||||
|
|
||||||
|
import (
|
||||||
|
"syscall"
|
||||||
|
)
|
||||||
|
|
||||||
|
//go:generate go run ../../mksyscall_windows.go -output zsyscall_windows.go hcs.go
|
||||||
|
|
||||||
|
//sys hcsEnumerateComputeSystems(query string, computeSystems **uint16, result **uint16) (hr error) = vmcompute.HcsEnumerateComputeSystems?
|
||||||
|
//sys hcsCreateComputeSystem(id string, configuration string, identity syscall.Handle, computeSystem *hcsSystem, result **uint16) (hr error) = vmcompute.HcsCreateComputeSystem?
|
||||||
|
//sys hcsOpenComputeSystem(id string, computeSystem *hcsSystem, result **uint16) (hr error) = vmcompute.HcsOpenComputeSystem?
|
||||||
|
//sys hcsCloseComputeSystem(computeSystem hcsSystem) (hr error) = vmcompute.HcsCloseComputeSystem?
|
||||||
|
//sys hcsStartComputeSystem(computeSystem hcsSystem, options string, result **uint16) (hr error) = vmcompute.HcsStartComputeSystem?
|
||||||
|
//sys hcsShutdownComputeSystem(computeSystem hcsSystem, options string, result **uint16) (hr error) = vmcompute.HcsShutdownComputeSystem?
|
||||||
|
//sys hcsTerminateComputeSystem(computeSystem hcsSystem, options string, result **uint16) (hr error) = vmcompute.HcsTerminateComputeSystem?
|
||||||
|
//sys hcsPauseComputeSystem(computeSystem hcsSystem, options string, result **uint16) (hr error) = vmcompute.HcsPauseComputeSystem?
|
||||||
|
//sys hcsResumeComputeSystem(computeSystem hcsSystem, options string, result **uint16) (hr error) = vmcompute.HcsResumeComputeSystem?
|
||||||
|
//sys hcsGetComputeSystemProperties(computeSystem hcsSystem, propertyQuery string, properties **uint16, result **uint16) (hr error) = vmcompute.HcsGetComputeSystemProperties?
|
||||||
|
//sys hcsModifyComputeSystem(computeSystem hcsSystem, configuration string, result **uint16) (hr error) = vmcompute.HcsModifyComputeSystem?
|
||||||
|
//sys hcsRegisterComputeSystemCallback(computeSystem hcsSystem, callback uintptr, context uintptr, callbackHandle *hcsCallback) (hr error) = vmcompute.HcsRegisterComputeSystemCallback?
|
||||||
|
//sys hcsUnregisterComputeSystemCallback(callbackHandle hcsCallback) (hr error) = vmcompute.HcsUnregisterComputeSystemCallback?
|
||||||
|
|
||||||
|
//sys hcsCreateProcess(computeSystem hcsSystem, processParameters string, processInformation *hcsProcessInformation, process *hcsProcess, result **uint16) (hr error) = vmcompute.HcsCreateProcess?
|
||||||
|
//sys hcsOpenProcess(computeSystem hcsSystem, pid uint32, process *hcsProcess, result **uint16) (hr error) = vmcompute.HcsOpenProcess?
|
||||||
|
//sys hcsCloseProcess(process hcsProcess) (hr error) = vmcompute.HcsCloseProcess?
|
||||||
|
//sys hcsTerminateProcess(process hcsProcess, result **uint16) (hr error) = vmcompute.HcsTerminateProcess?
|
||||||
|
//sys hcsGetProcessInfo(process hcsProcess, processInformation *hcsProcessInformation, result **uint16) (hr error) = vmcompute.HcsGetProcessInfo?
|
||||||
|
//sys hcsGetProcessProperties(process hcsProcess, processProperties **uint16, result **uint16) (hr error) = vmcompute.HcsGetProcessProperties?
|
||||||
|
//sys hcsModifyProcess(process hcsProcess, settings string, result **uint16) (hr error) = vmcompute.HcsModifyProcess?
|
||||||
|
//sys hcsGetServiceProperties(propertyQuery string, properties **uint16, result **uint16) (hr error) = vmcompute.HcsGetServiceProperties?
|
||||||
|
//sys hcsRegisterProcessCallback(process hcsProcess, callback uintptr, context uintptr, callbackHandle *hcsCallback) (hr error) = vmcompute.HcsRegisterProcessCallback?
|
||||||
|
//sys hcsUnregisterProcessCallback(callbackHandle hcsCallback) (hr error) = vmcompute.HcsUnregisterProcessCallback?
|
||||||
|
|
||||||
|
type hcsSystem syscall.Handle
|
||||||
|
type hcsProcess syscall.Handle
|
||||||
|
type hcsCallback syscall.Handle
|
||||||
|
|
||||||
|
type hcsProcessInformation struct {
|
||||||
|
ProcessId uint32
|
||||||
|
Reserved uint32
|
||||||
|
StdInput syscall.Handle
|
||||||
|
StdOutput syscall.Handle
|
||||||
|
StdError syscall.Handle
|
||||||
|
}
|
|
@ -0,0 +1,386 @@
|
||||||
|
package hcs
|
||||||
|
|
||||||
|
import (
|
||||||
|
"encoding/json"
|
||||||
|
"io"
|
||||||
|
"sync"
|
||||||
|
"syscall"
|
||||||
|
"time"
|
||||||
|
|
||||||
|
"github.com/Microsoft/hcsshim/internal/interop"
|
||||||
|
"github.com/sirupsen/logrus"
|
||||||
|
)
|
||||||
|
|
||||||
|
// ContainerError is an error encountered in HCS
|
||||||
|
type Process struct {
|
||||||
|
handleLock sync.RWMutex
|
||||||
|
handle hcsProcess
|
||||||
|
processID int
|
||||||
|
system *System
|
||||||
|
cachedPipes *cachedPipes
|
||||||
|
callbackNumber uintptr
|
||||||
|
}
|
||||||
|
|
||||||
|
type cachedPipes struct {
|
||||||
|
stdIn syscall.Handle
|
||||||
|
stdOut syscall.Handle
|
||||||
|
stdErr syscall.Handle
|
||||||
|
}
|
||||||
|
|
||||||
|
type processModifyRequest struct {
|
||||||
|
Operation string
|
||||||
|
ConsoleSize *consoleSize `json:",omitempty"`
|
||||||
|
CloseHandle *closeHandle `json:",omitempty"`
|
||||||
|
}
|
||||||
|
|
||||||
|
type consoleSize struct {
|
||||||
|
Height uint16
|
||||||
|
Width uint16
|
||||||
|
}
|
||||||
|
|
||||||
|
type closeHandle struct {
|
||||||
|
Handle string
|
||||||
|
}
|
||||||
|
|
||||||
|
type ProcessStatus struct {
|
||||||
|
ProcessID uint32
|
||||||
|
Exited bool
|
||||||
|
ExitCode uint32
|
||||||
|
LastWaitResult int32
|
||||||
|
}
|
||||||
|
|
||||||
|
const (
|
||||||
|
stdIn string = "StdIn"
|
||||||
|
stdOut string = "StdOut"
|
||||||
|
stdErr string = "StdErr"
|
||||||
|
)
|
||||||
|
|
||||||
|
const (
|
||||||
|
modifyConsoleSize string = "ConsoleSize"
|
||||||
|
modifyCloseHandle string = "CloseHandle"
|
||||||
|
)
|
||||||
|
|
||||||
|
// Pid returns the process ID of the process within the container.
|
||||||
|
func (process *Process) Pid() int {
|
||||||
|
return process.processID
|
||||||
|
}
|
||||||
|
|
||||||
|
// SystemID returns the ID of the process's compute system.
|
||||||
|
func (process *Process) SystemID() string {
|
||||||
|
return process.system.ID()
|
||||||
|
}
|
||||||
|
|
||||||
|
// Kill signals the process to terminate but does not wait for it to finish terminating.
|
||||||
|
func (process *Process) Kill() error {
|
||||||
|
process.handleLock.RLock()
|
||||||
|
defer process.handleLock.RUnlock()
|
||||||
|
operation := "Kill"
|
||||||
|
title := "hcsshim::Process::" + operation
|
||||||
|
logrus.Debugf(title+" processid=%d", process.processID)
|
||||||
|
|
||||||
|
if process.handle == 0 {
|
||||||
|
return makeProcessError(process, operation, ErrAlreadyClosed, nil)
|
||||||
|
}
|
||||||
|
|
||||||
|
var resultp *uint16
|
||||||
|
err := hcsTerminateProcess(process.handle, &resultp)
|
||||||
|
events := processHcsResult(resultp)
|
||||||
|
if err != nil {
|
||||||
|
return makeProcessError(process, operation, err, events)
|
||||||
|
}
|
||||||
|
|
||||||
|
logrus.Debugf(title+" succeeded processid=%d", process.processID)
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// Wait waits for the process to exit.
|
||||||
|
func (process *Process) Wait() error {
|
||||||
|
operation := "Wait"
|
||||||
|
title := "hcsshim::Process::" + operation
|
||||||
|
logrus.Debugf(title+" processid=%d", process.processID)
|
||||||
|
|
||||||
|
err := waitForNotification(process.callbackNumber, hcsNotificationProcessExited, nil)
|
||||||
|
if err != nil {
|
||||||
|
return makeProcessError(process, operation, err, nil)
|
||||||
|
}
|
||||||
|
|
||||||
|
logrus.Debugf(title+" succeeded processid=%d", process.processID)
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// WaitTimeout waits for the process to exit or the duration to elapse. It returns
|
||||||
|
// false if timeout occurs.
|
||||||
|
func (process *Process) WaitTimeout(timeout time.Duration) error {
|
||||||
|
operation := "WaitTimeout"
|
||||||
|
title := "hcsshim::Process::" + operation
|
||||||
|
logrus.Debugf(title+" processid=%d", process.processID)
|
||||||
|
|
||||||
|
err := waitForNotification(process.callbackNumber, hcsNotificationProcessExited, &timeout)
|
||||||
|
if err != nil {
|
||||||
|
return makeProcessError(process, operation, err, nil)
|
||||||
|
}
|
||||||
|
|
||||||
|
logrus.Debugf(title+" succeeded processid=%d", process.processID)
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// ResizeConsole resizes the console of the process.
|
||||||
|
func (process *Process) ResizeConsole(width, height uint16) error {
|
||||||
|
process.handleLock.RLock()
|
||||||
|
defer process.handleLock.RUnlock()
|
||||||
|
operation := "ResizeConsole"
|
||||||
|
title := "hcsshim::Process::" + operation
|
||||||
|
logrus.Debugf(title+" processid=%d", process.processID)
|
||||||
|
|
||||||
|
if process.handle == 0 {
|
||||||
|
return makeProcessError(process, operation, ErrAlreadyClosed, nil)
|
||||||
|
}
|
||||||
|
|
||||||
|
modifyRequest := processModifyRequest{
|
||||||
|
Operation: modifyConsoleSize,
|
||||||
|
ConsoleSize: &consoleSize{
|
||||||
|
Height: height,
|
||||||
|
Width: width,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
modifyRequestb, err := json.Marshal(modifyRequest)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
modifyRequestStr := string(modifyRequestb)
|
||||||
|
|
||||||
|
var resultp *uint16
|
||||||
|
err = hcsModifyProcess(process.handle, modifyRequestStr, &resultp)
|
||||||
|
events := processHcsResult(resultp)
|
||||||
|
if err != nil {
|
||||||
|
return makeProcessError(process, operation, err, events)
|
||||||
|
}
|
||||||
|
|
||||||
|
logrus.Debugf(title+" succeeded processid=%d", process.processID)
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (process *Process) Properties() (*ProcessStatus, error) {
|
||||||
|
process.handleLock.RLock()
|
||||||
|
defer process.handleLock.RUnlock()
|
||||||
|
operation := "Properties"
|
||||||
|
title := "hcsshim::Process::" + operation
|
||||||
|
logrus.Debugf(title+" processid=%d", process.processID)
|
||||||
|
|
||||||
|
if process.handle == 0 {
|
||||||
|
return nil, makeProcessError(process, operation, ErrAlreadyClosed, nil)
|
||||||
|
}
|
||||||
|
|
||||||
|
var (
|
||||||
|
resultp *uint16
|
||||||
|
propertiesp *uint16
|
||||||
|
)
|
||||||
|
err := hcsGetProcessProperties(process.handle, &propertiesp, &resultp)
|
||||||
|
events := processHcsResult(resultp)
|
||||||
|
if err != nil {
|
||||||
|
return nil, makeProcessError(process, operation, err, events)
|
||||||
|
}
|
||||||
|
|
||||||
|
if propertiesp == nil {
|
||||||
|
return nil, ErrUnexpectedValue
|
||||||
|
}
|
||||||
|
propertiesRaw := interop.ConvertAndFreeCoTaskMemBytes(propertiesp)
|
||||||
|
|
||||||
|
properties := &ProcessStatus{}
|
||||||
|
if err := json.Unmarshal(propertiesRaw, properties); err != nil {
|
||||||
|
return nil, makeProcessError(process, operation, err, nil)
|
||||||
|
}
|
||||||
|
|
||||||
|
logrus.Debugf(title+" succeeded processid=%d, properties=%s", process.processID, propertiesRaw)
|
||||||
|
return properties, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// ExitCode returns the exit code of the process. The process must have
|
||||||
|
// already terminated.
|
||||||
|
func (process *Process) ExitCode() (int, error) {
|
||||||
|
operation := "ExitCode"
|
||||||
|
properties, err := process.Properties()
|
||||||
|
if err != nil {
|
||||||
|
return 0, makeProcessError(process, operation, err, nil)
|
||||||
|
}
|
||||||
|
|
||||||
|
if properties.Exited == false {
|
||||||
|
return 0, makeProcessError(process, operation, ErrInvalidProcessState, nil)
|
||||||
|
}
|
||||||
|
|
||||||
|
if properties.LastWaitResult != 0 {
|
||||||
|
return 0, makeProcessError(process, operation, syscall.Errno(properties.LastWaitResult), nil)
|
||||||
|
}
|
||||||
|
|
||||||
|
return int(properties.ExitCode), nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// Stdio returns the stdin, stdout, and stderr pipes, respectively. Closing
|
||||||
|
// these pipes does not close the underlying pipes; it should be possible to
|
||||||
|
// call this multiple times to get multiple interfaces.
|
||||||
|
func (process *Process) Stdio() (io.WriteCloser, io.ReadCloser, io.ReadCloser, error) {
|
||||||
|
process.handleLock.RLock()
|
||||||
|
defer process.handleLock.RUnlock()
|
||||||
|
operation := "Stdio"
|
||||||
|
title := "hcsshim::Process::" + operation
|
||||||
|
logrus.Debugf(title+" processid=%d", process.processID)
|
||||||
|
|
||||||
|
if process.handle == 0 {
|
||||||
|
return nil, nil, nil, makeProcessError(process, operation, ErrAlreadyClosed, nil)
|
||||||
|
}
|
||||||
|
|
||||||
|
var stdIn, stdOut, stdErr syscall.Handle
|
||||||
|
|
||||||
|
if process.cachedPipes == nil {
|
||||||
|
var (
|
||||||
|
processInfo hcsProcessInformation
|
||||||
|
resultp *uint16
|
||||||
|
)
|
||||||
|
err := hcsGetProcessInfo(process.handle, &processInfo, &resultp)
|
||||||
|
events := processHcsResult(resultp)
|
||||||
|
if err != nil {
|
||||||
|
return nil, nil, nil, makeProcessError(process, operation, err, events)
|
||||||
|
}
|
||||||
|
|
||||||
|
stdIn, stdOut, stdErr = processInfo.StdInput, processInfo.StdOutput, processInfo.StdError
|
||||||
|
} else {
|
||||||
|
// Use cached pipes
|
||||||
|
stdIn, stdOut, stdErr = process.cachedPipes.stdIn, process.cachedPipes.stdOut, process.cachedPipes.stdErr
|
||||||
|
|
||||||
|
// Invalidate the cache
|
||||||
|
process.cachedPipes = nil
|
||||||
|
}
|
||||||
|
|
||||||
|
pipes, err := makeOpenFiles([]syscall.Handle{stdIn, stdOut, stdErr})
|
||||||
|
if err != nil {
|
||||||
|
return nil, nil, nil, makeProcessError(process, operation, err, nil)
|
||||||
|
}
|
||||||
|
|
||||||
|
logrus.Debugf(title+" succeeded processid=%d", process.processID)
|
||||||
|
return pipes[0], pipes[1], pipes[2], nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// CloseStdin closes the write side of the stdin pipe so that the process is
|
||||||
|
// notified on the read side that there is no more data in stdin.
|
||||||
|
func (process *Process) CloseStdin() error {
|
||||||
|
process.handleLock.RLock()
|
||||||
|
defer process.handleLock.RUnlock()
|
||||||
|
operation := "CloseStdin"
|
||||||
|
title := "hcsshim::Process::" + operation
|
||||||
|
logrus.Debugf(title+" processid=%d", process.processID)
|
||||||
|
|
||||||
|
if process.handle == 0 {
|
||||||
|
return makeProcessError(process, operation, ErrAlreadyClosed, nil)
|
||||||
|
}
|
||||||
|
|
||||||
|
modifyRequest := processModifyRequest{
|
||||||
|
Operation: modifyCloseHandle,
|
||||||
|
CloseHandle: &closeHandle{
|
||||||
|
Handle: stdIn,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
modifyRequestb, err := json.Marshal(modifyRequest)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
modifyRequestStr := string(modifyRequestb)
|
||||||
|
|
||||||
|
var resultp *uint16
|
||||||
|
err = hcsModifyProcess(process.handle, modifyRequestStr, &resultp)
|
||||||
|
events := processHcsResult(resultp)
|
||||||
|
if err != nil {
|
||||||
|
return makeProcessError(process, operation, err, events)
|
||||||
|
}
|
||||||
|
|
||||||
|
logrus.Debugf(title+" succeeded processid=%d", process.processID)
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// Close cleans up any state associated with the process but does not kill
|
||||||
|
// or wait on it.
|
||||||
|
func (process *Process) Close() error {
|
||||||
|
process.handleLock.Lock()
|
||||||
|
defer process.handleLock.Unlock()
|
||||||
|
operation := "Close"
|
||||||
|
title := "hcsshim::Process::" + operation
|
||||||
|
logrus.Debugf(title+" processid=%d", process.processID)
|
||||||
|
|
||||||
|
// Don't double free this
|
||||||
|
if process.handle == 0 {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
if err := process.unregisterCallback(); err != nil {
|
||||||
|
return makeProcessError(process, operation, err, nil)
|
||||||
|
}
|
||||||
|
|
||||||
|
if err := hcsCloseProcess(process.handle); err != nil {
|
||||||
|
return makeProcessError(process, operation, err, nil)
|
||||||
|
}
|
||||||
|
|
||||||
|
process.handle = 0
|
||||||
|
|
||||||
|
logrus.Debugf(title+" succeeded processid=%d", process.processID)
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (process *Process) registerCallback() error {
|
||||||
|
context := ¬ifcationWatcherContext{
|
||||||
|
channels: newChannels(),
|
||||||
|
}
|
||||||
|
|
||||||
|
callbackMapLock.Lock()
|
||||||
|
callbackNumber := nextCallback
|
||||||
|
nextCallback++
|
||||||
|
callbackMap[callbackNumber] = context
|
||||||
|
callbackMapLock.Unlock()
|
||||||
|
|
||||||
|
var callbackHandle hcsCallback
|
||||||
|
err := hcsRegisterProcessCallback(process.handle, notificationWatcherCallback, callbackNumber, &callbackHandle)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
context.handle = callbackHandle
|
||||||
|
process.callbackNumber = callbackNumber
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (process *Process) unregisterCallback() error {
|
||||||
|
callbackNumber := process.callbackNumber
|
||||||
|
|
||||||
|
callbackMapLock.RLock()
|
||||||
|
context := callbackMap[callbackNumber]
|
||||||
|
callbackMapLock.RUnlock()
|
||||||
|
|
||||||
|
if context == nil {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
handle := context.handle
|
||||||
|
|
||||||
|
if handle == 0 {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// hcsUnregisterProcessCallback has its own syncronization
|
||||||
|
// to wait for all callbacks to complete. We must NOT hold the callbackMapLock.
|
||||||
|
err := hcsUnregisterProcessCallback(handle)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
closeChannels(context.channels)
|
||||||
|
|
||||||
|
callbackMapLock.Lock()
|
||||||
|
callbackMap[callbackNumber] = nil
|
||||||
|
callbackMapLock.Unlock()
|
||||||
|
|
||||||
|
handle = 0
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
|
@ -0,0 +1,547 @@
|
||||||
|
package hcs
|
||||||
|
|
||||||
|
import (
|
||||||
|
"encoding/json"
|
||||||
|
"os"
|
||||||
|
"strconv"
|
||||||
|
"sync"
|
||||||
|
"syscall"
|
||||||
|
"time"
|
||||||
|
|
||||||
|
"github.com/Microsoft/hcsshim/internal/interop"
|
||||||
|
"github.com/Microsoft/hcsshim/internal/schema1"
|
||||||
|
"github.com/Microsoft/hcsshim/internal/timeout"
|
||||||
|
"github.com/sirupsen/logrus"
|
||||||
|
)
|
||||||
|
|
||||||
|
// currentContainerStarts is used to limit the number of concurrent container
|
||||||
|
// starts.
|
||||||
|
var currentContainerStarts containerStarts
|
||||||
|
|
||||||
|
type containerStarts struct {
|
||||||
|
maxParallel int
|
||||||
|
inProgress int
|
||||||
|
sync.Mutex
|
||||||
|
}
|
||||||
|
|
||||||
|
func init() {
|
||||||
|
mpsS := os.Getenv("HCSSHIM_MAX_PARALLEL_START")
|
||||||
|
if len(mpsS) > 0 {
|
||||||
|
mpsI, err := strconv.Atoi(mpsS)
|
||||||
|
if err != nil || mpsI < 0 {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
currentContainerStarts.maxParallel = mpsI
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
type System struct {
|
||||||
|
handleLock sync.RWMutex
|
||||||
|
handle hcsSystem
|
||||||
|
id string
|
||||||
|
callbackNumber uintptr
|
||||||
|
}
|
||||||
|
|
||||||
|
// CreateComputeSystem creates a new compute system with the given configuration but does not start it.
|
||||||
|
func CreateComputeSystem(id string, hcsDocumentInterface interface{}) (*System, error) {
|
||||||
|
operation := "CreateComputeSystem"
|
||||||
|
title := "hcsshim::" + operation
|
||||||
|
|
||||||
|
computeSystem := &System{
|
||||||
|
id: id,
|
||||||
|
}
|
||||||
|
|
||||||
|
hcsDocumentB, err := json.Marshal(hcsDocumentInterface)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
hcsDocument := string(hcsDocumentB)
|
||||||
|
logrus.Debugf(title+" ID=%s config=%s", id, hcsDocument)
|
||||||
|
|
||||||
|
var (
|
||||||
|
resultp *uint16
|
||||||
|
identity syscall.Handle
|
||||||
|
)
|
||||||
|
createError := hcsCreateComputeSystem(id, hcsDocument, identity, &computeSystem.handle, &resultp)
|
||||||
|
|
||||||
|
if createError == nil || IsPending(createError) {
|
||||||
|
if err := computeSystem.registerCallback(); err != nil {
|
||||||
|
// Terminate the compute system if it still exists. We're okay to
|
||||||
|
// ignore a failure here.
|
||||||
|
computeSystem.Terminate()
|
||||||
|
return nil, makeSystemError(computeSystem, operation, "", err, nil)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
events, err := processAsyncHcsResult(createError, resultp, computeSystem.callbackNumber, hcsNotificationSystemCreateCompleted, &timeout.Duration)
|
||||||
|
if err != nil {
|
||||||
|
if err == ErrTimeout {
|
||||||
|
// Terminate the compute system if it still exists. We're okay to
|
||||||
|
// ignore a failure here.
|
||||||
|
computeSystem.Terminate()
|
||||||
|
}
|
||||||
|
return nil, makeSystemError(computeSystem, operation, hcsDocument, err, events)
|
||||||
|
}
|
||||||
|
|
||||||
|
logrus.Debugf(title+" succeeded id=%s handle=%d", id, computeSystem.handle)
|
||||||
|
return computeSystem, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// OpenComputeSystem opens an existing compute system by ID.
|
||||||
|
func OpenComputeSystem(id string) (*System, error) {
|
||||||
|
operation := "OpenComputeSystem"
|
||||||
|
title := "hcsshim::" + operation
|
||||||
|
logrus.Debugf(title+" ID=%s", id)
|
||||||
|
|
||||||
|
computeSystem := &System{
|
||||||
|
id: id,
|
||||||
|
}
|
||||||
|
|
||||||
|
var (
|
||||||
|
handle hcsSystem
|
||||||
|
resultp *uint16
|
||||||
|
)
|
||||||
|
err := hcsOpenComputeSystem(id, &handle, &resultp)
|
||||||
|
events := processHcsResult(resultp)
|
||||||
|
if err != nil {
|
||||||
|
return nil, makeSystemError(computeSystem, operation, "", err, events)
|
||||||
|
}
|
||||||
|
|
||||||
|
computeSystem.handle = handle
|
||||||
|
|
||||||
|
if err := computeSystem.registerCallback(); err != nil {
|
||||||
|
return nil, makeSystemError(computeSystem, operation, "", err, nil)
|
||||||
|
}
|
||||||
|
|
||||||
|
logrus.Debugf(title+" succeeded id=%s handle=%d", id, handle)
|
||||||
|
return computeSystem, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// GetComputeSystems gets a list of the compute systems on the system that match the query
|
||||||
|
func GetComputeSystems(q schema1.ComputeSystemQuery) ([]schema1.ContainerProperties, error) {
|
||||||
|
operation := "GetComputeSystems"
|
||||||
|
title := "hcsshim::" + operation
|
||||||
|
|
||||||
|
queryb, err := json.Marshal(q)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
query := string(queryb)
|
||||||
|
logrus.Debugf(title+" query=%s", query)
|
||||||
|
|
||||||
|
var (
|
||||||
|
resultp *uint16
|
||||||
|
computeSystemsp *uint16
|
||||||
|
)
|
||||||
|
err = hcsEnumerateComputeSystems(query, &computeSystemsp, &resultp)
|
||||||
|
events := processHcsResult(resultp)
|
||||||
|
if err != nil {
|
||||||
|
return nil, &HcsError{Op: operation, Err: err, Events: events}
|
||||||
|
}
|
||||||
|
|
||||||
|
if computeSystemsp == nil {
|
||||||
|
return nil, ErrUnexpectedValue
|
||||||
|
}
|
||||||
|
computeSystemsRaw := interop.ConvertAndFreeCoTaskMemBytes(computeSystemsp)
|
||||||
|
computeSystems := []schema1.ContainerProperties{}
|
||||||
|
if err := json.Unmarshal(computeSystemsRaw, &computeSystems); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
logrus.Debugf(title + " succeeded")
|
||||||
|
return computeSystems, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// Start synchronously starts the computeSystem.
|
||||||
|
func (computeSystem *System) Start() error {
|
||||||
|
computeSystem.handleLock.RLock()
|
||||||
|
defer computeSystem.handleLock.RUnlock()
|
||||||
|
title := "hcsshim::ComputeSystem::Start ID=" + computeSystem.ID()
|
||||||
|
logrus.Debugf(title)
|
||||||
|
|
||||||
|
if computeSystem.handle == 0 {
|
||||||
|
return makeSystemError(computeSystem, "Start", "", ErrAlreadyClosed, nil)
|
||||||
|
}
|
||||||
|
|
||||||
|
// This is a very simple backoff-retry loop to limit the number
|
||||||
|
// of parallel container starts if environment variable
|
||||||
|
// HCSSHIM_MAX_PARALLEL_START is set to a positive integer.
|
||||||
|
// It should generally only be used as a workaround to various
|
||||||
|
// platform issues that exist between RS1 and RS4 as of Aug 2018
|
||||||
|
if currentContainerStarts.maxParallel > 0 {
|
||||||
|
for {
|
||||||
|
currentContainerStarts.Lock()
|
||||||
|
if currentContainerStarts.inProgress < currentContainerStarts.maxParallel {
|
||||||
|
currentContainerStarts.inProgress++
|
||||||
|
currentContainerStarts.Unlock()
|
||||||
|
break
|
||||||
|
}
|
||||||
|
if currentContainerStarts.inProgress == currentContainerStarts.maxParallel {
|
||||||
|
currentContainerStarts.Unlock()
|
||||||
|
time.Sleep(100 * time.Millisecond)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// Make sure we decrement the count when we are done.
|
||||||
|
defer func() {
|
||||||
|
currentContainerStarts.Lock()
|
||||||
|
currentContainerStarts.inProgress--
|
||||||
|
currentContainerStarts.Unlock()
|
||||||
|
}()
|
||||||
|
}
|
||||||
|
|
||||||
|
var resultp *uint16
|
||||||
|
err := hcsStartComputeSystem(computeSystem.handle, "", &resultp)
|
||||||
|
events, err := processAsyncHcsResult(err, resultp, computeSystem.callbackNumber, hcsNotificationSystemStartCompleted, &timeout.Duration)
|
||||||
|
if err != nil {
|
||||||
|
return makeSystemError(computeSystem, "Start", "", err, events)
|
||||||
|
}
|
||||||
|
|
||||||
|
logrus.Debugf(title + " succeeded")
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// ID returns the compute system's identifier.
|
||||||
|
func (computeSystem *System) ID() string {
|
||||||
|
return computeSystem.id
|
||||||
|
}
|
||||||
|
|
||||||
|
// Shutdown requests a compute system shutdown, if IsPending() on the error returned is true,
|
||||||
|
// it may not actually be shut down until Wait() succeeds.
|
||||||
|
func (computeSystem *System) Shutdown() error {
|
||||||
|
computeSystem.handleLock.RLock()
|
||||||
|
defer computeSystem.handleLock.RUnlock()
|
||||||
|
title := "hcsshim::ComputeSystem::Shutdown"
|
||||||
|
logrus.Debugf(title)
|
||||||
|
if computeSystem.handle == 0 {
|
||||||
|
return makeSystemError(computeSystem, "Shutdown", "", ErrAlreadyClosed, nil)
|
||||||
|
}
|
||||||
|
|
||||||
|
var resultp *uint16
|
||||||
|
err := hcsShutdownComputeSystem(computeSystem.handle, "", &resultp)
|
||||||
|
events := processHcsResult(resultp)
|
||||||
|
if err != nil {
|
||||||
|
return makeSystemError(computeSystem, "Shutdown", "", err, events)
|
||||||
|
}
|
||||||
|
|
||||||
|
logrus.Debugf(title + " succeeded")
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// Terminate requests a compute system terminate, if IsPending() on the error returned is true,
|
||||||
|
// it may not actually be shut down until Wait() succeeds.
|
||||||
|
func (computeSystem *System) Terminate() error {
|
||||||
|
computeSystem.handleLock.RLock()
|
||||||
|
defer computeSystem.handleLock.RUnlock()
|
||||||
|
title := "hcsshim::ComputeSystem::Terminate ID=" + computeSystem.ID()
|
||||||
|
logrus.Debugf(title)
|
||||||
|
|
||||||
|
if computeSystem.handle == 0 {
|
||||||
|
return makeSystemError(computeSystem, "Terminate", "", ErrAlreadyClosed, nil)
|
||||||
|
}
|
||||||
|
|
||||||
|
var resultp *uint16
|
||||||
|
err := hcsTerminateComputeSystem(computeSystem.handle, "", &resultp)
|
||||||
|
events := processHcsResult(resultp)
|
||||||
|
if err != nil {
|
||||||
|
return makeSystemError(computeSystem, "Terminate", "", err, events)
|
||||||
|
}
|
||||||
|
|
||||||
|
logrus.Debugf(title + " succeeded")
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// Wait synchronously waits for the compute system to shutdown or terminate.
|
||||||
|
func (computeSystem *System) Wait() error {
|
||||||
|
title := "hcsshim::ComputeSystem::Wait ID=" + computeSystem.ID()
|
||||||
|
logrus.Debugf(title)
|
||||||
|
|
||||||
|
err := waitForNotification(computeSystem.callbackNumber, hcsNotificationSystemExited, nil)
|
||||||
|
if err != nil {
|
||||||
|
return makeSystemError(computeSystem, "Wait", "", err, nil)
|
||||||
|
}
|
||||||
|
|
||||||
|
logrus.Debugf(title + " succeeded")
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// WaitTimeout synchronously waits for the compute system to terminate or the duration to elapse.
|
||||||
|
// If the timeout expires, IsTimeout(err) == true
|
||||||
|
func (computeSystem *System) WaitTimeout(timeout time.Duration) error {
|
||||||
|
title := "hcsshim::ComputeSystem::WaitTimeout ID=" + computeSystem.ID()
|
||||||
|
logrus.Debugf(title)
|
||||||
|
|
||||||
|
err := waitForNotification(computeSystem.callbackNumber, hcsNotificationSystemExited, &timeout)
|
||||||
|
if err != nil {
|
||||||
|
return makeSystemError(computeSystem, "WaitTimeout", "", err, nil)
|
||||||
|
}
|
||||||
|
|
||||||
|
logrus.Debugf(title + " succeeded")
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (computeSystem *System) Properties(types ...schema1.PropertyType) (*schema1.ContainerProperties, error) {
|
||||||
|
computeSystem.handleLock.RLock()
|
||||||
|
defer computeSystem.handleLock.RUnlock()
|
||||||
|
|
||||||
|
queryj, err := json.Marshal(schema1.PropertyQuery{types})
|
||||||
|
if err != nil {
|
||||||
|
return nil, makeSystemError(computeSystem, "Properties", "", err, nil)
|
||||||
|
}
|
||||||
|
|
||||||
|
var resultp, propertiesp *uint16
|
||||||
|
err = hcsGetComputeSystemProperties(computeSystem.handle, string(queryj), &propertiesp, &resultp)
|
||||||
|
events := processHcsResult(resultp)
|
||||||
|
if err != nil {
|
||||||
|
return nil, makeSystemError(computeSystem, "Properties", "", err, events)
|
||||||
|
}
|
||||||
|
|
||||||
|
if propertiesp == nil {
|
||||||
|
return nil, ErrUnexpectedValue
|
||||||
|
}
|
||||||
|
propertiesRaw := interop.ConvertAndFreeCoTaskMemBytes(propertiesp)
|
||||||
|
properties := &schema1.ContainerProperties{}
|
||||||
|
if err := json.Unmarshal(propertiesRaw, properties); err != nil {
|
||||||
|
return nil, makeSystemError(computeSystem, "Properties", "", err, nil)
|
||||||
|
}
|
||||||
|
return properties, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// Pause pauses the execution of the computeSystem. This feature is not enabled in TP5.
|
||||||
|
func (computeSystem *System) Pause() error {
|
||||||
|
computeSystem.handleLock.RLock()
|
||||||
|
defer computeSystem.handleLock.RUnlock()
|
||||||
|
title := "hcsshim::ComputeSystem::Pause ID=" + computeSystem.ID()
|
||||||
|
logrus.Debugf(title)
|
||||||
|
|
||||||
|
if computeSystem.handle == 0 {
|
||||||
|
return makeSystemError(computeSystem, "Pause", "", ErrAlreadyClosed, nil)
|
||||||
|
}
|
||||||
|
|
||||||
|
var resultp *uint16
|
||||||
|
err := hcsPauseComputeSystem(computeSystem.handle, "", &resultp)
|
||||||
|
events, err := processAsyncHcsResult(err, resultp, computeSystem.callbackNumber, hcsNotificationSystemPauseCompleted, &timeout.Duration)
|
||||||
|
if err != nil {
|
||||||
|
return makeSystemError(computeSystem, "Pause", "", err, events)
|
||||||
|
}
|
||||||
|
|
||||||
|
logrus.Debugf(title + " succeeded")
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// Resume resumes the execution of the computeSystem. This feature is not enabled in TP5.
|
||||||
|
func (computeSystem *System) Resume() error {
|
||||||
|
computeSystem.handleLock.RLock()
|
||||||
|
defer computeSystem.handleLock.RUnlock()
|
||||||
|
title := "hcsshim::ComputeSystem::Resume ID=" + computeSystem.ID()
|
||||||
|
logrus.Debugf(title)
|
||||||
|
|
||||||
|
if computeSystem.handle == 0 {
|
||||||
|
return makeSystemError(computeSystem, "Resume", "", ErrAlreadyClosed, nil)
|
||||||
|
}
|
||||||
|
|
||||||
|
var resultp *uint16
|
||||||
|
err := hcsResumeComputeSystem(computeSystem.handle, "", &resultp)
|
||||||
|
events, err := processAsyncHcsResult(err, resultp, computeSystem.callbackNumber, hcsNotificationSystemResumeCompleted, &timeout.Duration)
|
||||||
|
if err != nil {
|
||||||
|
return makeSystemError(computeSystem, "Resume", "", err, events)
|
||||||
|
}
|
||||||
|
|
||||||
|
logrus.Debugf(title + " succeeded")
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// CreateProcess launches a new process within the computeSystem.
|
||||||
|
func (computeSystem *System) CreateProcess(c interface{}) (*Process, error) {
|
||||||
|
computeSystem.handleLock.RLock()
|
||||||
|
defer computeSystem.handleLock.RUnlock()
|
||||||
|
title := "hcsshim::ComputeSystem::CreateProcess ID=" + computeSystem.ID()
|
||||||
|
var (
|
||||||
|
processInfo hcsProcessInformation
|
||||||
|
processHandle hcsProcess
|
||||||
|
resultp *uint16
|
||||||
|
)
|
||||||
|
|
||||||
|
if computeSystem.handle == 0 {
|
||||||
|
return nil, makeSystemError(computeSystem, "CreateProcess", "", ErrAlreadyClosed, nil)
|
||||||
|
}
|
||||||
|
|
||||||
|
configurationb, err := json.Marshal(c)
|
||||||
|
if err != nil {
|
||||||
|
return nil, makeSystemError(computeSystem, "CreateProcess", "", err, nil)
|
||||||
|
}
|
||||||
|
|
||||||
|
configuration := string(configurationb)
|
||||||
|
logrus.Debugf(title+" config=%s", configuration)
|
||||||
|
|
||||||
|
err = hcsCreateProcess(computeSystem.handle, configuration, &processInfo, &processHandle, &resultp)
|
||||||
|
events := processHcsResult(resultp)
|
||||||
|
if err != nil {
|
||||||
|
return nil, makeSystemError(computeSystem, "CreateProcess", configuration, err, events)
|
||||||
|
}
|
||||||
|
|
||||||
|
process := &Process{
|
||||||
|
handle: processHandle,
|
||||||
|
processID: int(processInfo.ProcessId),
|
||||||
|
system: computeSystem,
|
||||||
|
cachedPipes: &cachedPipes{
|
||||||
|
stdIn: processInfo.StdInput,
|
||||||
|
stdOut: processInfo.StdOutput,
|
||||||
|
stdErr: processInfo.StdError,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
if err := process.registerCallback(); err != nil {
|
||||||
|
return nil, makeSystemError(computeSystem, "CreateProcess", "", err, nil)
|
||||||
|
}
|
||||||
|
|
||||||
|
logrus.Debugf(title+" succeeded processid=%d", process.processID)
|
||||||
|
return process, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// OpenProcess gets an interface to an existing process within the computeSystem.
|
||||||
|
func (computeSystem *System) OpenProcess(pid int) (*Process, error) {
|
||||||
|
computeSystem.handleLock.RLock()
|
||||||
|
defer computeSystem.handleLock.RUnlock()
|
||||||
|
title := "hcsshim::ComputeSystem::OpenProcess ID=" + computeSystem.ID()
|
||||||
|
logrus.Debugf(title+" processid=%d", pid)
|
||||||
|
var (
|
||||||
|
processHandle hcsProcess
|
||||||
|
resultp *uint16
|
||||||
|
)
|
||||||
|
|
||||||
|
if computeSystem.handle == 0 {
|
||||||
|
return nil, makeSystemError(computeSystem, "OpenProcess", "", ErrAlreadyClosed, nil)
|
||||||
|
}
|
||||||
|
|
||||||
|
err := hcsOpenProcess(computeSystem.handle, uint32(pid), &processHandle, &resultp)
|
||||||
|
events := processHcsResult(resultp)
|
||||||
|
if err != nil {
|
||||||
|
return nil, makeSystemError(computeSystem, "OpenProcess", "", err, events)
|
||||||
|
}
|
||||||
|
|
||||||
|
process := &Process{
|
||||||
|
handle: processHandle,
|
||||||
|
processID: pid,
|
||||||
|
system: computeSystem,
|
||||||
|
}
|
||||||
|
|
||||||
|
if err := process.registerCallback(); err != nil {
|
||||||
|
return nil, makeSystemError(computeSystem, "OpenProcess", "", err, nil)
|
||||||
|
}
|
||||||
|
|
||||||
|
logrus.Debugf(title+" succeeded processid=%s", process.processID)
|
||||||
|
return process, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// Close cleans up any state associated with the compute system but does not terminate or wait for it.
|
||||||
|
func (computeSystem *System) Close() error {
|
||||||
|
computeSystem.handleLock.Lock()
|
||||||
|
defer computeSystem.handleLock.Unlock()
|
||||||
|
title := "hcsshim::ComputeSystem::Close ID=" + computeSystem.ID()
|
||||||
|
logrus.Debugf(title)
|
||||||
|
|
||||||
|
// Don't double free this
|
||||||
|
if computeSystem.handle == 0 {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
if err := computeSystem.unregisterCallback(); err != nil {
|
||||||
|
return makeSystemError(computeSystem, "Close", "", err, nil)
|
||||||
|
}
|
||||||
|
|
||||||
|
if err := hcsCloseComputeSystem(computeSystem.handle); err != nil {
|
||||||
|
return makeSystemError(computeSystem, "Close", "", err, nil)
|
||||||
|
}
|
||||||
|
|
||||||
|
computeSystem.handle = 0
|
||||||
|
|
||||||
|
logrus.Debugf(title + " succeeded")
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (computeSystem *System) registerCallback() error {
|
||||||
|
context := ¬ifcationWatcherContext{
|
||||||
|
channels: newChannels(),
|
||||||
|
}
|
||||||
|
|
||||||
|
callbackMapLock.Lock()
|
||||||
|
callbackNumber := nextCallback
|
||||||
|
nextCallback++
|
||||||
|
callbackMap[callbackNumber] = context
|
||||||
|
callbackMapLock.Unlock()
|
||||||
|
|
||||||
|
var callbackHandle hcsCallback
|
||||||
|
err := hcsRegisterComputeSystemCallback(computeSystem.handle, notificationWatcherCallback, callbackNumber, &callbackHandle)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
context.handle = callbackHandle
|
||||||
|
computeSystem.callbackNumber = callbackNumber
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (computeSystem *System) unregisterCallback() error {
|
||||||
|
callbackNumber := computeSystem.callbackNumber
|
||||||
|
|
||||||
|
callbackMapLock.RLock()
|
||||||
|
context := callbackMap[callbackNumber]
|
||||||
|
callbackMapLock.RUnlock()
|
||||||
|
|
||||||
|
if context == nil {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
handle := context.handle
|
||||||
|
|
||||||
|
if handle == 0 {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// hcsUnregisterComputeSystemCallback has its own syncronization
|
||||||
|
// to wait for all callbacks to complete. We must NOT hold the callbackMapLock.
|
||||||
|
err := hcsUnregisterComputeSystemCallback(handle)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
closeChannels(context.channels)
|
||||||
|
|
||||||
|
callbackMapLock.Lock()
|
||||||
|
callbackMap[callbackNumber] = nil
|
||||||
|
callbackMapLock.Unlock()
|
||||||
|
|
||||||
|
handle = 0
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// Modifies the System by sending a request to HCS
|
||||||
|
func (computeSystem *System) Modify(config interface{}) error {
|
||||||
|
computeSystem.handleLock.RLock()
|
||||||
|
defer computeSystem.handleLock.RUnlock()
|
||||||
|
title := "hcsshim::Modify ID=" + computeSystem.id
|
||||||
|
|
||||||
|
if computeSystem.handle == 0 {
|
||||||
|
return makeSystemError(computeSystem, "Modify", "", ErrAlreadyClosed, nil)
|
||||||
|
}
|
||||||
|
|
||||||
|
requestJSON, err := json.Marshal(config)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
requestString := string(requestJSON)
|
||||||
|
logrus.Debugf(title + " " + requestString)
|
||||||
|
|
||||||
|
var resultp *uint16
|
||||||
|
err = hcsModifyComputeSystem(computeSystem.handle, requestString, &resultp)
|
||||||
|
events := processHcsResult(resultp)
|
||||||
|
if err != nil {
|
||||||
|
return makeSystemError(computeSystem, "Modify", requestString, err, events)
|
||||||
|
}
|
||||||
|
logrus.Debugf(title + " succeeded ")
|
||||||
|
return nil
|
||||||
|
}
|
|
@ -1,4 +1,4 @@
|
||||||
package hcsshim
|
package hcs
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"io"
|
"io"
|
|
@ -1,4 +1,4 @@
|
||||||
package hcsshim
|
package hcs
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"time"
|
"time"
|
||||||
|
@ -6,13 +6,13 @@ import (
|
||||||
"github.com/sirupsen/logrus"
|
"github.com/sirupsen/logrus"
|
||||||
)
|
)
|
||||||
|
|
||||||
func processAsyncHcsResult(err error, resultp *uint16, callbackNumber uintptr, expectedNotification hcsNotification, timeout *time.Duration) error {
|
func processAsyncHcsResult(err error, resultp *uint16, callbackNumber uintptr, expectedNotification hcsNotification, timeout *time.Duration) ([]ErrorEvent, error) {
|
||||||
err = processHcsResult(err, resultp)
|
events := processHcsResult(resultp)
|
||||||
if IsPending(err) {
|
if IsPending(err) {
|
||||||
return waitForNotification(callbackNumber, expectedNotification, timeout)
|
return nil, waitForNotification(callbackNumber, expectedNotification, timeout)
|
||||||
}
|
}
|
||||||
|
|
||||||
return err
|
return events, err
|
||||||
}
|
}
|
||||||
|
|
||||||
func waitForNotification(callbackNumber uintptr, expectedNotification hcsNotification, timeout *time.Duration) error {
|
func waitForNotification(callbackNumber uintptr, expectedNotification hcsNotification, timeout *time.Duration) error {
|
441
vendor/github.com/Microsoft/hcsshim/internal/hcs/zsyscall_windows.go
generated
vendored
Normal file
441
vendor/github.com/Microsoft/hcsshim/internal/hcs/zsyscall_windows.go
generated
vendored
Normal file
|
@ -0,0 +1,441 @@
|
||||||
|
// MACHINE GENERATED BY 'go generate' COMMAND; DO NOT EDIT
|
||||||
|
|
||||||
|
package hcs
|
||||||
|
|
||||||
|
import (
|
||||||
|
"syscall"
|
||||||
|
"unsafe"
|
||||||
|
|
||||||
|
"github.com/Microsoft/hcsshim/internal/interop"
|
||||||
|
"golang.org/x/sys/windows"
|
||||||
|
)
|
||||||
|
|
||||||
|
var _ unsafe.Pointer
|
||||||
|
|
||||||
|
// Do the interface allocations only once for common
|
||||||
|
// Errno values.
|
||||||
|
const (
|
||||||
|
errnoERROR_IO_PENDING = 997
|
||||||
|
)
|
||||||
|
|
||||||
|
var (
|
||||||
|
errERROR_IO_PENDING error = syscall.Errno(errnoERROR_IO_PENDING)
|
||||||
|
)
|
||||||
|
|
||||||
|
// errnoErr returns common boxed Errno values, to prevent
|
||||||
|
// allocations at runtime.
|
||||||
|
func errnoErr(e syscall.Errno) error {
|
||||||
|
switch e {
|
||||||
|
case 0:
|
||||||
|
return nil
|
||||||
|
case errnoERROR_IO_PENDING:
|
||||||
|
return errERROR_IO_PENDING
|
||||||
|
}
|
||||||
|
// TODO: add more here, after collecting data on the common
|
||||||
|
// error values see on Windows. (perhaps when running
|
||||||
|
// all.bat?)
|
||||||
|
return e
|
||||||
|
}
|
||||||
|
|
||||||
|
var (
|
||||||
|
modvmcompute = windows.NewLazySystemDLL("vmcompute.dll")
|
||||||
|
|
||||||
|
procHcsEnumerateComputeSystems = modvmcompute.NewProc("HcsEnumerateComputeSystems")
|
||||||
|
procHcsCreateComputeSystem = modvmcompute.NewProc("HcsCreateComputeSystem")
|
||||||
|
procHcsOpenComputeSystem = modvmcompute.NewProc("HcsOpenComputeSystem")
|
||||||
|
procHcsCloseComputeSystem = modvmcompute.NewProc("HcsCloseComputeSystem")
|
||||||
|
procHcsStartComputeSystem = modvmcompute.NewProc("HcsStartComputeSystem")
|
||||||
|
procHcsShutdownComputeSystem = modvmcompute.NewProc("HcsShutdownComputeSystem")
|
||||||
|
procHcsTerminateComputeSystem = modvmcompute.NewProc("HcsTerminateComputeSystem")
|
||||||
|
procHcsPauseComputeSystem = modvmcompute.NewProc("HcsPauseComputeSystem")
|
||||||
|
procHcsResumeComputeSystem = modvmcompute.NewProc("HcsResumeComputeSystem")
|
||||||
|
procHcsGetComputeSystemProperties = modvmcompute.NewProc("HcsGetComputeSystemProperties")
|
||||||
|
procHcsModifyComputeSystem = modvmcompute.NewProc("HcsModifyComputeSystem")
|
||||||
|
procHcsRegisterComputeSystemCallback = modvmcompute.NewProc("HcsRegisterComputeSystemCallback")
|
||||||
|
procHcsUnregisterComputeSystemCallback = modvmcompute.NewProc("HcsUnregisterComputeSystemCallback")
|
||||||
|
procHcsCreateProcess = modvmcompute.NewProc("HcsCreateProcess")
|
||||||
|
procHcsOpenProcess = modvmcompute.NewProc("HcsOpenProcess")
|
||||||
|
procHcsCloseProcess = modvmcompute.NewProc("HcsCloseProcess")
|
||||||
|
procHcsTerminateProcess = modvmcompute.NewProc("HcsTerminateProcess")
|
||||||
|
procHcsGetProcessInfo = modvmcompute.NewProc("HcsGetProcessInfo")
|
||||||
|
procHcsGetProcessProperties = modvmcompute.NewProc("HcsGetProcessProperties")
|
||||||
|
procHcsModifyProcess = modvmcompute.NewProc("HcsModifyProcess")
|
||||||
|
procHcsGetServiceProperties = modvmcompute.NewProc("HcsGetServiceProperties")
|
||||||
|
procHcsRegisterProcessCallback = modvmcompute.NewProc("HcsRegisterProcessCallback")
|
||||||
|
procHcsUnregisterProcessCallback = modvmcompute.NewProc("HcsUnregisterProcessCallback")
|
||||||
|
)
|
||||||
|
|
||||||
|
func hcsEnumerateComputeSystems(query string, computeSystems **uint16, result **uint16) (hr error) {
|
||||||
|
var _p0 *uint16
|
||||||
|
_p0, hr = syscall.UTF16PtrFromString(query)
|
||||||
|
if hr != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
return _hcsEnumerateComputeSystems(_p0, computeSystems, result)
|
||||||
|
}
|
||||||
|
|
||||||
|
func _hcsEnumerateComputeSystems(query *uint16, computeSystems **uint16, result **uint16) (hr error) {
|
||||||
|
if hr = procHcsEnumerateComputeSystems.Find(); hr != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
r0, _, _ := syscall.Syscall(procHcsEnumerateComputeSystems.Addr(), 3, uintptr(unsafe.Pointer(query)), uintptr(unsafe.Pointer(computeSystems)), uintptr(unsafe.Pointer(result)))
|
||||||
|
if int32(r0) < 0 {
|
||||||
|
hr = interop.Win32FromHresult(r0)
|
||||||
|
}
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
func hcsCreateComputeSystem(id string, configuration string, identity syscall.Handle, computeSystem *hcsSystem, result **uint16) (hr error) {
|
||||||
|
var _p0 *uint16
|
||||||
|
_p0, hr = syscall.UTF16PtrFromString(id)
|
||||||
|
if hr != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
var _p1 *uint16
|
||||||
|
_p1, hr = syscall.UTF16PtrFromString(configuration)
|
||||||
|
if hr != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
return _hcsCreateComputeSystem(_p0, _p1, identity, computeSystem, result)
|
||||||
|
}
|
||||||
|
|
||||||
|
func _hcsCreateComputeSystem(id *uint16, configuration *uint16, identity syscall.Handle, computeSystem *hcsSystem, result **uint16) (hr error) {
|
||||||
|
if hr = procHcsCreateComputeSystem.Find(); hr != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
r0, _, _ := syscall.Syscall6(procHcsCreateComputeSystem.Addr(), 5, uintptr(unsafe.Pointer(id)), uintptr(unsafe.Pointer(configuration)), uintptr(identity), uintptr(unsafe.Pointer(computeSystem)), uintptr(unsafe.Pointer(result)), 0)
|
||||||
|
if int32(r0) < 0 {
|
||||||
|
hr = interop.Win32FromHresult(r0)
|
||||||
|
}
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
func hcsOpenComputeSystem(id string, computeSystem *hcsSystem, result **uint16) (hr error) {
|
||||||
|
var _p0 *uint16
|
||||||
|
_p0, hr = syscall.UTF16PtrFromString(id)
|
||||||
|
if hr != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
return _hcsOpenComputeSystem(_p0, computeSystem, result)
|
||||||
|
}
|
||||||
|
|
||||||
|
func _hcsOpenComputeSystem(id *uint16, computeSystem *hcsSystem, result **uint16) (hr error) {
|
||||||
|
if hr = procHcsOpenComputeSystem.Find(); hr != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
r0, _, _ := syscall.Syscall(procHcsOpenComputeSystem.Addr(), 3, uintptr(unsafe.Pointer(id)), uintptr(unsafe.Pointer(computeSystem)), uintptr(unsafe.Pointer(result)))
|
||||||
|
if int32(r0) < 0 {
|
||||||
|
hr = interop.Win32FromHresult(r0)
|
||||||
|
}
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
func hcsCloseComputeSystem(computeSystem hcsSystem) (hr error) {
|
||||||
|
if hr = procHcsCloseComputeSystem.Find(); hr != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
r0, _, _ := syscall.Syscall(procHcsCloseComputeSystem.Addr(), 1, uintptr(computeSystem), 0, 0)
|
||||||
|
if int32(r0) < 0 {
|
||||||
|
hr = interop.Win32FromHresult(r0)
|
||||||
|
}
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
func hcsStartComputeSystem(computeSystem hcsSystem, options string, result **uint16) (hr error) {
|
||||||
|
var _p0 *uint16
|
||||||
|
_p0, hr = syscall.UTF16PtrFromString(options)
|
||||||
|
if hr != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
return _hcsStartComputeSystem(computeSystem, _p0, result)
|
||||||
|
}
|
||||||
|
|
||||||
|
func _hcsStartComputeSystem(computeSystem hcsSystem, options *uint16, result **uint16) (hr error) {
|
||||||
|
if hr = procHcsStartComputeSystem.Find(); hr != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
r0, _, _ := syscall.Syscall(procHcsStartComputeSystem.Addr(), 3, uintptr(computeSystem), uintptr(unsafe.Pointer(options)), uintptr(unsafe.Pointer(result)))
|
||||||
|
if int32(r0) < 0 {
|
||||||
|
hr = interop.Win32FromHresult(r0)
|
||||||
|
}
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
func hcsShutdownComputeSystem(computeSystem hcsSystem, options string, result **uint16) (hr error) {
|
||||||
|
var _p0 *uint16
|
||||||
|
_p0, hr = syscall.UTF16PtrFromString(options)
|
||||||
|
if hr != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
return _hcsShutdownComputeSystem(computeSystem, _p0, result)
|
||||||
|
}
|
||||||
|
|
||||||
|
func _hcsShutdownComputeSystem(computeSystem hcsSystem, options *uint16, result **uint16) (hr error) {
|
||||||
|
if hr = procHcsShutdownComputeSystem.Find(); hr != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
r0, _, _ := syscall.Syscall(procHcsShutdownComputeSystem.Addr(), 3, uintptr(computeSystem), uintptr(unsafe.Pointer(options)), uintptr(unsafe.Pointer(result)))
|
||||||
|
if int32(r0) < 0 {
|
||||||
|
hr = interop.Win32FromHresult(r0)
|
||||||
|
}
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
func hcsTerminateComputeSystem(computeSystem hcsSystem, options string, result **uint16) (hr error) {
|
||||||
|
var _p0 *uint16
|
||||||
|
_p0, hr = syscall.UTF16PtrFromString(options)
|
||||||
|
if hr != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
return _hcsTerminateComputeSystem(computeSystem, _p0, result)
|
||||||
|
}
|
||||||
|
|
||||||
|
func _hcsTerminateComputeSystem(computeSystem hcsSystem, options *uint16, result **uint16) (hr error) {
|
||||||
|
if hr = procHcsTerminateComputeSystem.Find(); hr != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
r0, _, _ := syscall.Syscall(procHcsTerminateComputeSystem.Addr(), 3, uintptr(computeSystem), uintptr(unsafe.Pointer(options)), uintptr(unsafe.Pointer(result)))
|
||||||
|
if int32(r0) < 0 {
|
||||||
|
hr = interop.Win32FromHresult(r0)
|
||||||
|
}
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
func hcsPauseComputeSystem(computeSystem hcsSystem, options string, result **uint16) (hr error) {
|
||||||
|
var _p0 *uint16
|
||||||
|
_p0, hr = syscall.UTF16PtrFromString(options)
|
||||||
|
if hr != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
return _hcsPauseComputeSystem(computeSystem, _p0, result)
|
||||||
|
}
|
||||||
|
|
||||||
|
func _hcsPauseComputeSystem(computeSystem hcsSystem, options *uint16, result **uint16) (hr error) {
|
||||||
|
if hr = procHcsPauseComputeSystem.Find(); hr != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
r0, _, _ := syscall.Syscall(procHcsPauseComputeSystem.Addr(), 3, uintptr(computeSystem), uintptr(unsafe.Pointer(options)), uintptr(unsafe.Pointer(result)))
|
||||||
|
if int32(r0) < 0 {
|
||||||
|
hr = interop.Win32FromHresult(r0)
|
||||||
|
}
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
func hcsResumeComputeSystem(computeSystem hcsSystem, options string, result **uint16) (hr error) {
|
||||||
|
var _p0 *uint16
|
||||||
|
_p0, hr = syscall.UTF16PtrFromString(options)
|
||||||
|
if hr != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
return _hcsResumeComputeSystem(computeSystem, _p0, result)
|
||||||
|
}
|
||||||
|
|
||||||
|
func _hcsResumeComputeSystem(computeSystem hcsSystem, options *uint16, result **uint16) (hr error) {
|
||||||
|
if hr = procHcsResumeComputeSystem.Find(); hr != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
r0, _, _ := syscall.Syscall(procHcsResumeComputeSystem.Addr(), 3, uintptr(computeSystem), uintptr(unsafe.Pointer(options)), uintptr(unsafe.Pointer(result)))
|
||||||
|
if int32(r0) < 0 {
|
||||||
|
hr = interop.Win32FromHresult(r0)
|
||||||
|
}
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
func hcsGetComputeSystemProperties(computeSystem hcsSystem, propertyQuery string, properties **uint16, result **uint16) (hr error) {
|
||||||
|
var _p0 *uint16
|
||||||
|
_p0, hr = syscall.UTF16PtrFromString(propertyQuery)
|
||||||
|
if hr != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
return _hcsGetComputeSystemProperties(computeSystem, _p0, properties, result)
|
||||||
|
}
|
||||||
|
|
||||||
|
func _hcsGetComputeSystemProperties(computeSystem hcsSystem, propertyQuery *uint16, properties **uint16, result **uint16) (hr error) {
|
||||||
|
if hr = procHcsGetComputeSystemProperties.Find(); hr != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
r0, _, _ := syscall.Syscall6(procHcsGetComputeSystemProperties.Addr(), 4, uintptr(computeSystem), uintptr(unsafe.Pointer(propertyQuery)), uintptr(unsafe.Pointer(properties)), uintptr(unsafe.Pointer(result)), 0, 0)
|
||||||
|
if int32(r0) < 0 {
|
||||||
|
hr = interop.Win32FromHresult(r0)
|
||||||
|
}
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
func hcsModifyComputeSystem(computeSystem hcsSystem, configuration string, result **uint16) (hr error) {
|
||||||
|
var _p0 *uint16
|
||||||
|
_p0, hr = syscall.UTF16PtrFromString(configuration)
|
||||||
|
if hr != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
return _hcsModifyComputeSystem(computeSystem, _p0, result)
|
||||||
|
}
|
||||||
|
|
||||||
|
func _hcsModifyComputeSystem(computeSystem hcsSystem, configuration *uint16, result **uint16) (hr error) {
|
||||||
|
if hr = procHcsModifyComputeSystem.Find(); hr != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
r0, _, _ := syscall.Syscall(procHcsModifyComputeSystem.Addr(), 3, uintptr(computeSystem), uintptr(unsafe.Pointer(configuration)), uintptr(unsafe.Pointer(result)))
|
||||||
|
if int32(r0) < 0 {
|
||||||
|
hr = interop.Win32FromHresult(r0)
|
||||||
|
}
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
func hcsRegisterComputeSystemCallback(computeSystem hcsSystem, callback uintptr, context uintptr, callbackHandle *hcsCallback) (hr error) {
|
||||||
|
if hr = procHcsRegisterComputeSystemCallback.Find(); hr != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
r0, _, _ := syscall.Syscall6(procHcsRegisterComputeSystemCallback.Addr(), 4, uintptr(computeSystem), uintptr(callback), uintptr(context), uintptr(unsafe.Pointer(callbackHandle)), 0, 0)
|
||||||
|
if int32(r0) < 0 {
|
||||||
|
hr = interop.Win32FromHresult(r0)
|
||||||
|
}
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
func hcsUnregisterComputeSystemCallback(callbackHandle hcsCallback) (hr error) {
|
||||||
|
if hr = procHcsUnregisterComputeSystemCallback.Find(); hr != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
r0, _, _ := syscall.Syscall(procHcsUnregisterComputeSystemCallback.Addr(), 1, uintptr(callbackHandle), 0, 0)
|
||||||
|
if int32(r0) < 0 {
|
||||||
|
hr = interop.Win32FromHresult(r0)
|
||||||
|
}
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
func hcsCreateProcess(computeSystem hcsSystem, processParameters string, processInformation *hcsProcessInformation, process *hcsProcess, result **uint16) (hr error) {
|
||||||
|
var _p0 *uint16
|
||||||
|
_p0, hr = syscall.UTF16PtrFromString(processParameters)
|
||||||
|
if hr != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
return _hcsCreateProcess(computeSystem, _p0, processInformation, process, result)
|
||||||
|
}
|
||||||
|
|
||||||
|
func _hcsCreateProcess(computeSystem hcsSystem, processParameters *uint16, processInformation *hcsProcessInformation, process *hcsProcess, result **uint16) (hr error) {
|
||||||
|
if hr = procHcsCreateProcess.Find(); hr != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
r0, _, _ := syscall.Syscall6(procHcsCreateProcess.Addr(), 5, uintptr(computeSystem), uintptr(unsafe.Pointer(processParameters)), uintptr(unsafe.Pointer(processInformation)), uintptr(unsafe.Pointer(process)), uintptr(unsafe.Pointer(result)), 0)
|
||||||
|
if int32(r0) < 0 {
|
||||||
|
hr = interop.Win32FromHresult(r0)
|
||||||
|
}
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
func hcsOpenProcess(computeSystem hcsSystem, pid uint32, process *hcsProcess, result **uint16) (hr error) {
|
||||||
|
if hr = procHcsOpenProcess.Find(); hr != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
r0, _, _ := syscall.Syscall6(procHcsOpenProcess.Addr(), 4, uintptr(computeSystem), uintptr(pid), uintptr(unsafe.Pointer(process)), uintptr(unsafe.Pointer(result)), 0, 0)
|
||||||
|
if int32(r0) < 0 {
|
||||||
|
hr = interop.Win32FromHresult(r0)
|
||||||
|
}
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
func hcsCloseProcess(process hcsProcess) (hr error) {
|
||||||
|
if hr = procHcsCloseProcess.Find(); hr != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
r0, _, _ := syscall.Syscall(procHcsCloseProcess.Addr(), 1, uintptr(process), 0, 0)
|
||||||
|
if int32(r0) < 0 {
|
||||||
|
hr = interop.Win32FromHresult(r0)
|
||||||
|
}
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
func hcsTerminateProcess(process hcsProcess, result **uint16) (hr error) {
|
||||||
|
if hr = procHcsTerminateProcess.Find(); hr != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
r0, _, _ := syscall.Syscall(procHcsTerminateProcess.Addr(), 2, uintptr(process), uintptr(unsafe.Pointer(result)), 0)
|
||||||
|
if int32(r0) < 0 {
|
||||||
|
hr = interop.Win32FromHresult(r0)
|
||||||
|
}
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
func hcsGetProcessInfo(process hcsProcess, processInformation *hcsProcessInformation, result **uint16) (hr error) {
|
||||||
|
if hr = procHcsGetProcessInfo.Find(); hr != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
r0, _, _ := syscall.Syscall(procHcsGetProcessInfo.Addr(), 3, uintptr(process), uintptr(unsafe.Pointer(processInformation)), uintptr(unsafe.Pointer(result)))
|
||||||
|
if int32(r0) < 0 {
|
||||||
|
hr = interop.Win32FromHresult(r0)
|
||||||
|
}
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
func hcsGetProcessProperties(process hcsProcess, processProperties **uint16, result **uint16) (hr error) {
|
||||||
|
if hr = procHcsGetProcessProperties.Find(); hr != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
r0, _, _ := syscall.Syscall(procHcsGetProcessProperties.Addr(), 3, uintptr(process), uintptr(unsafe.Pointer(processProperties)), uintptr(unsafe.Pointer(result)))
|
||||||
|
if int32(r0) < 0 {
|
||||||
|
hr = interop.Win32FromHresult(r0)
|
||||||
|
}
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
func hcsModifyProcess(process hcsProcess, settings string, result **uint16) (hr error) {
|
||||||
|
var _p0 *uint16
|
||||||
|
_p0, hr = syscall.UTF16PtrFromString(settings)
|
||||||
|
if hr != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
return _hcsModifyProcess(process, _p0, result)
|
||||||
|
}
|
||||||
|
|
||||||
|
func _hcsModifyProcess(process hcsProcess, settings *uint16, result **uint16) (hr error) {
|
||||||
|
if hr = procHcsModifyProcess.Find(); hr != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
r0, _, _ := syscall.Syscall(procHcsModifyProcess.Addr(), 3, uintptr(process), uintptr(unsafe.Pointer(settings)), uintptr(unsafe.Pointer(result)))
|
||||||
|
if int32(r0) < 0 {
|
||||||
|
hr = interop.Win32FromHresult(r0)
|
||||||
|
}
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
func hcsGetServiceProperties(propertyQuery string, properties **uint16, result **uint16) (hr error) {
|
||||||
|
var _p0 *uint16
|
||||||
|
_p0, hr = syscall.UTF16PtrFromString(propertyQuery)
|
||||||
|
if hr != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
return _hcsGetServiceProperties(_p0, properties, result)
|
||||||
|
}
|
||||||
|
|
||||||
|
func _hcsGetServiceProperties(propertyQuery *uint16, properties **uint16, result **uint16) (hr error) {
|
||||||
|
if hr = procHcsGetServiceProperties.Find(); hr != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
r0, _, _ := syscall.Syscall(procHcsGetServiceProperties.Addr(), 3, uintptr(unsafe.Pointer(propertyQuery)), uintptr(unsafe.Pointer(properties)), uintptr(unsafe.Pointer(result)))
|
||||||
|
if int32(r0) < 0 {
|
||||||
|
hr = interop.Win32FromHresult(r0)
|
||||||
|
}
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
func hcsRegisterProcessCallback(process hcsProcess, callback uintptr, context uintptr, callbackHandle *hcsCallback) (hr error) {
|
||||||
|
if hr = procHcsRegisterProcessCallback.Find(); hr != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
r0, _, _ := syscall.Syscall6(procHcsRegisterProcessCallback.Addr(), 4, uintptr(process), uintptr(callback), uintptr(context), uintptr(unsafe.Pointer(callbackHandle)), 0, 0)
|
||||||
|
if int32(r0) < 0 {
|
||||||
|
hr = interop.Win32FromHresult(r0)
|
||||||
|
}
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
func hcsUnregisterProcessCallback(callbackHandle hcsCallback) (hr error) {
|
||||||
|
if hr = procHcsUnregisterProcessCallback.Find(); hr != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
r0, _, _ := syscall.Syscall(procHcsUnregisterProcessCallback.Addr(), 1, uintptr(callbackHandle), 0, 0)
|
||||||
|
if int32(r0) < 0 {
|
||||||
|
hr = interop.Win32FromHresult(r0)
|
||||||
|
}
|
||||||
|
return
|
||||||
|
}
|
|
@ -0,0 +1,51 @@
|
||||||
|
package hcserror
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"syscall"
|
||||||
|
)
|
||||||
|
|
||||||
|
const ERROR_GEN_FAILURE = syscall.Errno(31)
|
||||||
|
|
||||||
|
type HcsError struct {
|
||||||
|
title string
|
||||||
|
rest string
|
||||||
|
Err error
|
||||||
|
}
|
||||||
|
|
||||||
|
func (e *HcsError) Error() string {
|
||||||
|
s := e.title
|
||||||
|
if len(s) > 0 && s[len(s)-1] != ' ' {
|
||||||
|
s += " "
|
||||||
|
}
|
||||||
|
s += fmt.Sprintf("failed in Win32: %s (0x%x)", e.Err, Win32FromError(e.Err))
|
||||||
|
if e.rest != "" {
|
||||||
|
if e.rest[0] != ' ' {
|
||||||
|
s += " "
|
||||||
|
}
|
||||||
|
s += e.rest
|
||||||
|
}
|
||||||
|
return s
|
||||||
|
}
|
||||||
|
|
||||||
|
func New(err error, title, rest string) error {
|
||||||
|
// Pass through DLL errors directly since they do not originate from HCS.
|
||||||
|
if _, ok := err.(*syscall.DLLError); ok {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
return &HcsError{title, rest, err}
|
||||||
|
}
|
||||||
|
|
||||||
|
func Errorf(err error, title, format string, a ...interface{}) error {
|
||||||
|
return New(err, title, fmt.Sprintf(format, a...))
|
||||||
|
}
|
||||||
|
|
||||||
|
func Win32FromError(err error) uint32 {
|
||||||
|
if herr, ok := err.(*HcsError); ok {
|
||||||
|
return Win32FromError(herr.Err)
|
||||||
|
}
|
||||||
|
if code, ok := err.(syscall.Errno); ok {
|
||||||
|
return uint32(code)
|
||||||
|
}
|
||||||
|
return uint32(ERROR_GEN_FAILURE)
|
||||||
|
}
|
|
@ -0,0 +1,23 @@
|
||||||
|
package hns
|
||||||
|
|
||||||
|
import "fmt"
|
||||||
|
|
||||||
|
//go:generate go run ../../mksyscall_windows.go -output zsyscall_windows.go hns.go
|
||||||
|
|
||||||
|
//sys _hnsCall(method string, path string, object string, response **uint16) (hr error) = vmcompute.HNSCall?
|
||||||
|
|
||||||
|
type EndpointNotFoundError struct {
|
||||||
|
EndpointName string
|
||||||
|
}
|
||||||
|
|
||||||
|
func (e EndpointNotFoundError) Error() string {
|
||||||
|
return fmt.Sprintf("Endpoint %s not found", e.EndpointName)
|
||||||
|
}
|
||||||
|
|
||||||
|
type NetworkNotFoundError struct {
|
||||||
|
NetworkName string
|
||||||
|
}
|
||||||
|
|
||||||
|
func (e NetworkNotFoundError) Error() string {
|
||||||
|
return fmt.Sprintf("Network %s not found", e.NetworkName)
|
||||||
|
}
|
|
@ -0,0 +1,260 @@
|
||||||
|
package hns
|
||||||
|
|
||||||
|
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"`
|
||||||
|
Namespace *Namespace `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
|
||||||
|
}
|
||||||
|
|
||||||
|
// 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
|
||||||
|
}
|
||||||
|
|
||||||
|
// 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)
|
||||||
|
}
|
|
@ -1,9 +1,11 @@
|
||||||
package hcsshim
|
package hns
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"encoding/json"
|
"encoding/json"
|
||||||
"fmt"
|
"fmt"
|
||||||
|
|
||||||
|
"github.com/Microsoft/hcsshim/internal/hcserror"
|
||||||
|
"github.com/Microsoft/hcsshim/internal/interop"
|
||||||
"github.com/sirupsen/logrus"
|
"github.com/sirupsen/logrus"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@ -13,9 +15,9 @@ func hnsCall(method, path, request string, returnResponse interface{}) error {
|
||||||
|
|
||||||
err := _hnsCall(method, path, request, &responseBuffer)
|
err := _hnsCall(method, path, request, &responseBuffer)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return makeError(err, "hnsCall ", "")
|
return hcserror.New(err, "hnsCall ", "")
|
||||||
}
|
}
|
||||||
response := convertAndFreeCoTaskMemString(responseBuffer)
|
response := interop.ConvertAndFreeCoTaskMemString(responseBuffer)
|
||||||
|
|
||||||
hnsresponse := &hnsResponse{}
|
hnsresponse := &hnsResponse{}
|
||||||
if err = json.Unmarshal([]byte(response), &hnsresponse); err != nil {
|
if err = json.Unmarshal([]byte(response), &hnsresponse); err != nil {
|
|
@ -0,0 +1,28 @@
|
||||||
|
package hns
|
||||||
|
|
||||||
|
type HNSGlobals struct {
|
||||||
|
Version HNSVersion `json:"Version"`
|
||||||
|
}
|
||||||
|
|
||||||
|
type HNSVersion struct {
|
||||||
|
Major int `json:"Major"`
|
||||||
|
Minor int `json:"Minor"`
|
||||||
|
}
|
||||||
|
|
||||||
|
var (
|
||||||
|
HNSVersion1803 = HNSVersion{Major: 7, Minor: 2}
|
||||||
|
)
|
||||||
|
|
||||||
|
func GetHNSGlobals() (*HNSGlobals, error) {
|
||||||
|
var version HNSVersion
|
||||||
|
err := hnsCall("GET", "/globals/version", "", &version)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
globals := &HNSGlobals{
|
||||||
|
Version: version,
|
||||||
|
}
|
||||||
|
|
||||||
|
return globals, nil
|
||||||
|
}
|
|
@ -0,0 +1,141 @@
|
||||||
|
package hns
|
||||||
|
|
||||||
|
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)
|
||||||
|
}
|
|
@ -0,0 +1,98 @@
|
||||||
|
package hns
|
||||||
|
|
||||||
|
// 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"`
|
||||||
|
Id string `json:"Id,omitempty"`
|
||||||
|
Protocol uint16
|
||||||
|
Protocols string `json:"Protocols,omitempty"`
|
||||||
|
InternalPort uint16
|
||||||
|
Action ActionType
|
||||||
|
Direction DirectionType
|
||||||
|
LocalAddresses string
|
||||||
|
RemoteAddresses string
|
||||||
|
LocalPorts string `json:"LocalPorts,omitempty"`
|
||||||
|
LocalPort uint16
|
||||||
|
RemotePorts string `json:"RemotePorts,omitempty"`
|
||||||
|
RemotePort uint16
|
||||||
|
RuleType RuleType `json:"RuleType,omitempty"`
|
||||||
|
Priority uint16
|
||||||
|
ServiceName string
|
||||||
|
}
|
||||||
|
|
||||||
|
type Policy struct {
|
||||||
|
Type PolicyType `json:"Type"`
|
||||||
|
}
|
200
vendor/github.com/Microsoft/hcsshim/internal/hns/hnspolicylist.go
generated
vendored
Normal file
200
vendor/github.com/Microsoft/hcsshim/internal/hns/hnspolicylist.go
generated
vendored
Normal file
|
@ -0,0 +1,200 @@
|
||||||
|
package hns
|
||||||
|
|
||||||
|
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()
|
||||||
|
}
|
|
@ -0,0 +1,49 @@
|
||||||
|
package hns
|
||||||
|
|
||||||
|
import (
|
||||||
|
"github.com/sirupsen/logrus"
|
||||||
|
)
|
||||||
|
|
||||||
|
type HNSSupportedFeatures struct {
|
||||||
|
Acl HNSAclFeatures `json:"ACL"`
|
||||||
|
}
|
||||||
|
|
||||||
|
type HNSAclFeatures struct {
|
||||||
|
AclAddressLists bool `json:"AclAddressLists"`
|
||||||
|
AclNoHostRulePriority bool `json:"AclHostRulePriority"`
|
||||||
|
AclPortRanges bool `json:"AclPortRanges"`
|
||||||
|
AclRuleId bool `json:"AclRuleId"`
|
||||||
|
}
|
||||||
|
|
||||||
|
func GetHNSSupportedFeatures() HNSSupportedFeatures {
|
||||||
|
var hnsFeatures HNSSupportedFeatures
|
||||||
|
|
||||||
|
globals, err := GetHNSGlobals()
|
||||||
|
if err != nil {
|
||||||
|
// Expected on pre-1803 builds, all features will be false/unsupported
|
||||||
|
logrus.Debugf("Unable to obtain HNS globals: %s", err)
|
||||||
|
return hnsFeatures
|
||||||
|
}
|
||||||
|
|
||||||
|
hnsFeatures.Acl = HNSAclFeatures{
|
||||||
|
AclAddressLists: isHNSFeatureSupported(globals.Version, HNSVersion1803),
|
||||||
|
AclNoHostRulePriority: isHNSFeatureSupported(globals.Version, HNSVersion1803),
|
||||||
|
AclPortRanges: isHNSFeatureSupported(globals.Version, HNSVersion1803),
|
||||||
|
AclRuleId: isHNSFeatureSupported(globals.Version, HNSVersion1803),
|
||||||
|
}
|
||||||
|
|
||||||
|
return hnsFeatures
|
||||||
|
}
|
||||||
|
|
||||||
|
func isHNSFeatureSupported(currentVersion HNSVersion, minVersionSupported HNSVersion) bool {
|
||||||
|
if currentVersion.Major < minVersionSupported.Major {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
if currentVersion.Major > minVersionSupported.Major {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
if currentVersion.Minor < minVersionSupported.Minor {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
return true
|
||||||
|
}
|
|
@ -0,0 +1,110 @@
|
||||||
|
package hns
|
||||||
|
|
||||||
|
import (
|
||||||
|
"encoding/json"
|
||||||
|
"fmt"
|
||||||
|
"os"
|
||||||
|
"path"
|
||||||
|
"strings"
|
||||||
|
)
|
||||||
|
|
||||||
|
type namespaceRequest struct {
|
||||||
|
IsDefault bool `json:",omitempty"`
|
||||||
|
}
|
||||||
|
|
||||||
|
type namespaceEndpointRequest struct {
|
||||||
|
ID string `json:"Id"`
|
||||||
|
}
|
||||||
|
|
||||||
|
type NamespaceResource struct {
|
||||||
|
Type string
|
||||||
|
Data json.RawMessage
|
||||||
|
}
|
||||||
|
|
||||||
|
type namespaceResourceRequest struct {
|
||||||
|
Type string
|
||||||
|
Data interface{}
|
||||||
|
}
|
||||||
|
|
||||||
|
type Namespace struct {
|
||||||
|
ID string
|
||||||
|
IsDefault bool `json:",omitempty"`
|
||||||
|
ResourceList []NamespaceResource `json:",omitempty"`
|
||||||
|
}
|
||||||
|
|
||||||
|
func issueNamespaceRequest(id *string, method, subpath string, request interface{}) (*Namespace, error) {
|
||||||
|
var err error
|
||||||
|
hnspath := "/namespaces/"
|
||||||
|
if id != nil {
|
||||||
|
hnspath = path.Join(hnspath, *id)
|
||||||
|
}
|
||||||
|
if subpath != "" {
|
||||||
|
hnspath = path.Join(hnspath, subpath)
|
||||||
|
}
|
||||||
|
var reqJSON []byte
|
||||||
|
if request != nil {
|
||||||
|
if reqJSON, err = json.Marshal(request); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
var ns Namespace
|
||||||
|
err = hnsCall(method, hnspath, string(reqJSON), &ns)
|
||||||
|
if err != nil {
|
||||||
|
if strings.Contains(err.Error(), "Element not found.") {
|
||||||
|
return nil, os.ErrNotExist
|
||||||
|
}
|
||||||
|
return nil, fmt.Errorf("%s %s: %s", method, hnspath, err)
|
||||||
|
}
|
||||||
|
return &ns, err
|
||||||
|
}
|
||||||
|
|
||||||
|
func CreateNamespace() (string, error) {
|
||||||
|
req := namespaceRequest{}
|
||||||
|
ns, err := issueNamespaceRequest(nil, "POST", "", &req)
|
||||||
|
if err != nil {
|
||||||
|
return "", err
|
||||||
|
}
|
||||||
|
return ns.ID, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func RemoveNamespace(id string) error {
|
||||||
|
_, err := issueNamespaceRequest(&id, "DELETE", "", nil)
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
func GetNamespaceEndpoints(id string) ([]string, error) {
|
||||||
|
ns, err := issueNamespaceRequest(&id, "GET", "", nil)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
var endpoints []string
|
||||||
|
for _, rsrc := range ns.ResourceList {
|
||||||
|
if rsrc.Type == "Endpoint" {
|
||||||
|
var endpoint namespaceEndpointRequest
|
||||||
|
err = json.Unmarshal(rsrc.Data, &endpoint)
|
||||||
|
if err != nil {
|
||||||
|
return nil, fmt.Errorf("unmarshal endpoint: %s", err)
|
||||||
|
}
|
||||||
|
endpoints = append(endpoints, endpoint.ID)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return endpoints, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func AddNamespaceEndpoint(id string, endpointID string) error {
|
||||||
|
resource := namespaceResourceRequest{
|
||||||
|
Type: "Endpoint",
|
||||||
|
Data: namespaceEndpointRequest{endpointID},
|
||||||
|
}
|
||||||
|
_, err := issueNamespaceRequest(&id, "POST", "addresource", &resource)
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
func RemoveNamespaceEndpoint(id string, endpointID string) error {
|
||||||
|
resource := namespaceResourceRequest{
|
||||||
|
Type: "Endpoint",
|
||||||
|
Data: namespaceEndpointRequest{endpointID},
|
||||||
|
}
|
||||||
|
_, err := issueNamespaceRequest(&id, "POST", "removeresource", &resource)
|
||||||
|
return err
|
||||||
|
}
|
74
vendor/github.com/Microsoft/hcsshim/internal/hns/zsyscall_windows.go
generated
vendored
Normal file
74
vendor/github.com/Microsoft/hcsshim/internal/hns/zsyscall_windows.go
generated
vendored
Normal file
|
@ -0,0 +1,74 @@
|
||||||
|
// MACHINE GENERATED BY 'go generate' COMMAND; DO NOT EDIT
|
||||||
|
|
||||||
|
package hns
|
||||||
|
|
||||||
|
import (
|
||||||
|
"syscall"
|
||||||
|
"unsafe"
|
||||||
|
|
||||||
|
"github.com/Microsoft/hcsshim/internal/interop"
|
||||||
|
"golang.org/x/sys/windows"
|
||||||
|
)
|
||||||
|
|
||||||
|
var _ unsafe.Pointer
|
||||||
|
|
||||||
|
// Do the interface allocations only once for common
|
||||||
|
// Errno values.
|
||||||
|
const (
|
||||||
|
errnoERROR_IO_PENDING = 997
|
||||||
|
)
|
||||||
|
|
||||||
|
var (
|
||||||
|
errERROR_IO_PENDING error = syscall.Errno(errnoERROR_IO_PENDING)
|
||||||
|
)
|
||||||
|
|
||||||
|
// errnoErr returns common boxed Errno values, to prevent
|
||||||
|
// allocations at runtime.
|
||||||
|
func errnoErr(e syscall.Errno) error {
|
||||||
|
switch e {
|
||||||
|
case 0:
|
||||||
|
return nil
|
||||||
|
case errnoERROR_IO_PENDING:
|
||||||
|
return errERROR_IO_PENDING
|
||||||
|
}
|
||||||
|
// TODO: add more here, after collecting data on the common
|
||||||
|
// error values see on Windows. (perhaps when running
|
||||||
|
// all.bat?)
|
||||||
|
return e
|
||||||
|
}
|
||||||
|
|
||||||
|
var (
|
||||||
|
modvmcompute = windows.NewLazySystemDLL("vmcompute.dll")
|
||||||
|
|
||||||
|
procHNSCall = modvmcompute.NewProc("HNSCall")
|
||||||
|
)
|
||||||
|
|
||||||
|
func _hnsCall(method string, path string, object string, response **uint16) (hr error) {
|
||||||
|
var _p0 *uint16
|
||||||
|
_p0, hr = syscall.UTF16PtrFromString(method)
|
||||||
|
if hr != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
var _p1 *uint16
|
||||||
|
_p1, hr = syscall.UTF16PtrFromString(path)
|
||||||
|
if hr != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
var _p2 *uint16
|
||||||
|
_p2, hr = syscall.UTF16PtrFromString(object)
|
||||||
|
if hr != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
return __hnsCall(_p0, _p1, _p2, response)
|
||||||
|
}
|
||||||
|
|
||||||
|
func __hnsCall(method *uint16, path *uint16, object *uint16, response **uint16) (hr error) {
|
||||||
|
if hr = procHNSCall.Find(); hr != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
r0, _, _ := syscall.Syscall6(procHNSCall.Addr(), 4, uintptr(unsafe.Pointer(method)), uintptr(unsafe.Pointer(path)), uintptr(unsafe.Pointer(object)), uintptr(unsafe.Pointer(response)), 0, 0)
|
||||||
|
if int32(r0) < 0 {
|
||||||
|
hr = interop.Win32FromHresult(r0)
|
||||||
|
}
|
||||||
|
return
|
||||||
|
}
|
|
@ -0,0 +1,27 @@
|
||||||
|
package interop
|
||||||
|
|
||||||
|
import (
|
||||||
|
"syscall"
|
||||||
|
"unsafe"
|
||||||
|
)
|
||||||
|
|
||||||
|
//go:generate go run $GOROOT/src/syscall/mksyscall_windows.go -output zsyscall_windows.go interop.go
|
||||||
|
|
||||||
|
//sys coTaskMemFree(buffer unsafe.Pointer) = ole32.CoTaskMemFree
|
||||||
|
|
||||||
|
func ConvertAndFreeCoTaskMemString(buffer *uint16) string {
|
||||||
|
str := syscall.UTF16ToString((*[1 << 29]uint16)(unsafe.Pointer(buffer))[:])
|
||||||
|
coTaskMemFree(unsafe.Pointer(buffer))
|
||||||
|
return str
|
||||||
|
}
|
||||||
|
|
||||||
|
func ConvertAndFreeCoTaskMemBytes(buffer *uint16) []byte {
|
||||||
|
return []byte(ConvertAndFreeCoTaskMemString(buffer))
|
||||||
|
}
|
||||||
|
|
||||||
|
func Win32FromHresult(hr uintptr) syscall.Errno {
|
||||||
|
if hr&0x1fff0000 == 0x00070000 {
|
||||||
|
return syscall.Errno(hr & 0xffff)
|
||||||
|
}
|
||||||
|
return syscall.Errno(hr)
|
||||||
|
}
|
48
vendor/github.com/Microsoft/hcsshim/internal/interop/zsyscall_windows.go
generated
vendored
Normal file
48
vendor/github.com/Microsoft/hcsshim/internal/interop/zsyscall_windows.go
generated
vendored
Normal file
|
@ -0,0 +1,48 @@
|
||||||
|
// MACHINE GENERATED BY 'go generate' COMMAND; DO NOT EDIT
|
||||||
|
|
||||||
|
package interop
|
||||||
|
|
||||||
|
import (
|
||||||
|
"syscall"
|
||||||
|
"unsafe"
|
||||||
|
|
||||||
|
"golang.org/x/sys/windows"
|
||||||
|
)
|
||||||
|
|
||||||
|
var _ unsafe.Pointer
|
||||||
|
|
||||||
|
// Do the interface allocations only once for common
|
||||||
|
// Errno values.
|
||||||
|
const (
|
||||||
|
errnoERROR_IO_PENDING = 997
|
||||||
|
)
|
||||||
|
|
||||||
|
var (
|
||||||
|
errERROR_IO_PENDING error = syscall.Errno(errnoERROR_IO_PENDING)
|
||||||
|
)
|
||||||
|
|
||||||
|
// errnoErr returns common boxed Errno values, to prevent
|
||||||
|
// allocations at runtime.
|
||||||
|
func errnoErr(e syscall.Errno) error {
|
||||||
|
switch e {
|
||||||
|
case 0:
|
||||||
|
return nil
|
||||||
|
case errnoERROR_IO_PENDING:
|
||||||
|
return errERROR_IO_PENDING
|
||||||
|
}
|
||||||
|
// TODO: add more here, after collecting data on the common
|
||||||
|
// error values see on Windows. (perhaps when running
|
||||||
|
// all.bat?)
|
||||||
|
return e
|
||||||
|
}
|
||||||
|
|
||||||
|
var (
|
||||||
|
modole32 = windows.NewLazySystemDLL("ole32.dll")
|
||||||
|
|
||||||
|
procCoTaskMemFree = modole32.NewProc("CoTaskMemFree")
|
||||||
|
)
|
||||||
|
|
||||||
|
func coTaskMemFree(buffer unsafe.Pointer) {
|
||||||
|
syscall.Syscall(procCoTaskMemFree.Addr(), 1, uintptr(buffer), 0, 0)
|
||||||
|
return
|
||||||
|
}
|
|
@ -0,0 +1,24 @@
|
||||||
|
package longpath
|
||||||
|
|
||||||
|
import (
|
||||||
|
"path/filepath"
|
||||||
|
"strings"
|
||||||
|
)
|
||||||
|
|
||||||
|
// LongAbs makes a path absolute and returns it in NT long path form.
|
||||||
|
func LongAbs(path string) (string, error) {
|
||||||
|
if strings.HasPrefix(path, `\\?\`) || strings.HasPrefix(path, `\\.\`) {
|
||||||
|
return path, nil
|
||||||
|
}
|
||||||
|
if !filepath.IsAbs(path) {
|
||||||
|
absPath, err := filepath.Abs(path)
|
||||||
|
if err != nil {
|
||||||
|
return "", err
|
||||||
|
}
|
||||||
|
path = absPath
|
||||||
|
}
|
||||||
|
if strings.HasPrefix(path, `\\`) {
|
||||||
|
return `\\?\UNC\` + path[2:], nil
|
||||||
|
}
|
||||||
|
return `\\?\` + path, nil
|
||||||
|
}
|
|
@ -0,0 +1,52 @@
|
||||||
|
package mergemaps
|
||||||
|
|
||||||
|
import "encoding/json"
|
||||||
|
|
||||||
|
// Merge recursively merges map `fromMap` into map `ToMap`. Any pre-existing values
|
||||||
|
// in ToMap are overwritten. Values in fromMap are added to ToMap.
|
||||||
|
// From http://stackoverflow.com/questions/40491438/merging-two-json-strings-in-golang
|
||||||
|
func Merge(fromMap, ToMap interface{}) interface{} {
|
||||||
|
switch fromMap := fromMap.(type) {
|
||||||
|
case map[string]interface{}:
|
||||||
|
ToMap, ok := ToMap.(map[string]interface{})
|
||||||
|
if !ok {
|
||||||
|
return fromMap
|
||||||
|
}
|
||||||
|
for keyToMap, valueToMap := range ToMap {
|
||||||
|
if valueFromMap, ok := fromMap[keyToMap]; ok {
|
||||||
|
fromMap[keyToMap] = Merge(valueFromMap, valueToMap)
|
||||||
|
} else {
|
||||||
|
fromMap[keyToMap] = valueToMap
|
||||||
|
}
|
||||||
|
}
|
||||||
|
case nil:
|
||||||
|
// merge(nil, map[string]interface{...}) -> map[string]interface{...}
|
||||||
|
ToMap, ok := ToMap.(map[string]interface{})
|
||||||
|
if ok {
|
||||||
|
return ToMap
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return fromMap
|
||||||
|
}
|
||||||
|
|
||||||
|
// MergeJSON merges the contents of a JSON string into an object representation,
|
||||||
|
// returning a new object suitable for translating to JSON.
|
||||||
|
func MergeJSON(object interface{}, additionalJSON []byte) (interface{}, error) {
|
||||||
|
if len(additionalJSON) == 0 {
|
||||||
|
return object, nil
|
||||||
|
}
|
||||||
|
objectJSON, err := json.Marshal(object)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
var objectMap, newMap map[string]interface{}
|
||||||
|
err = json.Unmarshal(objectJSON, &objectMap)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
err = json.Unmarshal(additionalJSON, &newMap)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
return Merge(newMap, objectMap), nil
|
||||||
|
}
|
|
@ -1,4 +1,4 @@
|
||||||
package hcsshim
|
package safefile
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"errors"
|
"errors"
|
||||||
|
@ -10,9 +10,13 @@ import (
|
||||||
"unicode/utf16"
|
"unicode/utf16"
|
||||||
"unsafe"
|
"unsafe"
|
||||||
|
|
||||||
|
"github.com/Microsoft/hcsshim/internal/longpath"
|
||||||
|
|
||||||
winio "github.com/Microsoft/go-winio"
|
winio "github.com/Microsoft/go-winio"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
//go:generate go run $GOROOT\src\syscall\mksyscall_windows.go -output zsyscall_windows.go safeopen.go
|
||||||
|
|
||||||
//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 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 ntSetInformationFile(handle uintptr, iosb *ioStatusBlock, information uintptr, length uint32, class uint32) (status uint32) = ntdll.NtSetInformationFile
|
||||||
//sys rtlNtStatusToDosError(status uint32) (winerr error) = ntdll.RtlNtStatusToDosErrorNoTeb
|
//sys rtlNtStatusToDosError(status uint32) (winerr error) = ntdll.RtlNtStatusToDosErrorNoTeb
|
||||||
|
@ -53,28 +57,28 @@ const (
|
||||||
_FileLinkInformation = 11
|
_FileLinkInformation = 11
|
||||||
_FileDispositionInformationEx = 64
|
_FileDispositionInformationEx = 64
|
||||||
|
|
||||||
_FILE_READ_ATTRIBUTES = 0x0080
|
FILE_READ_ATTRIBUTES = 0x0080
|
||||||
_FILE_WRITE_ATTRIBUTES = 0x0100
|
FILE_WRITE_ATTRIBUTES = 0x0100
|
||||||
_DELETE = 0x10000
|
DELETE = 0x10000
|
||||||
|
|
||||||
_FILE_OPEN = 1
|
FILE_OPEN = 1
|
||||||
_FILE_CREATE = 2
|
FILE_CREATE = 2
|
||||||
|
|
||||||
_FILE_DIRECTORY_FILE = 0x00000001
|
FILE_DIRECTORY_FILE = 0x00000001
|
||||||
_FILE_SYNCHRONOUS_IO_NONALERT = 0x00000020
|
FILE_SYNCHRONOUS_IO_NONALERT = 0x00000020
|
||||||
_FILE_DELETE_ON_CLOSE = 0x00001000
|
FILE_DELETE_ON_CLOSE = 0x00001000
|
||||||
_FILE_OPEN_FOR_BACKUP_INTENT = 0x00004000
|
FILE_OPEN_FOR_BACKUP_INTENT = 0x00004000
|
||||||
_FILE_OPEN_REPARSE_POINT = 0x00200000
|
FILE_OPEN_REPARSE_POINT = 0x00200000
|
||||||
|
|
||||||
_FILE_DISPOSITION_DELETE = 0x00000001
|
FILE_DISPOSITION_DELETE = 0x00000001
|
||||||
|
|
||||||
_OBJ_DONT_REPARSE = 0x1000
|
_OBJ_DONT_REPARSE = 0x1000
|
||||||
|
|
||||||
_STATUS_REPARSE_POINT_ENCOUNTERED = 0xC000050B
|
_STATUS_REPARSE_POINT_ENCOUNTERED = 0xC000050B
|
||||||
)
|
)
|
||||||
|
|
||||||
func openRoot(path string) (*os.File, error) {
|
func OpenRoot(path string) (*os.File, error) {
|
||||||
longpath, err := makeLongAbsPath(path)
|
longpath, err := longpath.LongAbs(path)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
@ -141,7 +145,7 @@ func openRelativeInternal(path string, root *os.File, accessMask uint32, shareFl
|
||||||
0,
|
0,
|
||||||
shareFlags,
|
shareFlags,
|
||||||
createDisposition,
|
createDisposition,
|
||||||
_FILE_OPEN_FOR_BACKUP_INTENT|_FILE_SYNCHRONOUS_IO_NONALERT|flags,
|
FILE_OPEN_FOR_BACKUP_INTENT|FILE_SYNCHRONOUS_IO_NONALERT|flags,
|
||||||
nil,
|
nil,
|
||||||
0,
|
0,
|
||||||
)
|
)
|
||||||
|
@ -149,7 +153,7 @@ func openRelativeInternal(path string, root *os.File, accessMask uint32, shareFl
|
||||||
return nil, rtlNtStatusToDosError(status)
|
return nil, rtlNtStatusToDosError(status)
|
||||||
}
|
}
|
||||||
|
|
||||||
fullPath, err := makeLongAbsPath(filepath.Join(root.Name(), path))
|
fullPath, err := longpath.LongAbs(filepath.Join(root.Name(), path))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
syscall.Close(syscall.Handle(h))
|
syscall.Close(syscall.Handle(h))
|
||||||
return nil, err
|
return nil, err
|
||||||
|
@ -158,9 +162,9 @@ func openRelativeInternal(path string, root *os.File, accessMask uint32, shareFl
|
||||||
return os.NewFile(h, fullPath), nil
|
return os.NewFile(h, fullPath), nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// openRelative opens a relative path from the given root, failing if
|
// OpenRelative opens a relative path from the given root, failing if
|
||||||
// any of the intermediate path components are reparse points.
|
// 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) {
|
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)
|
f, err := openRelativeInternal(path, root, accessMask, shareFlags, createDisposition, flags)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
err = &os.PathError{Op: "open", Path: filepath.Join(root.Name(), path), Err: err}
|
err = &os.PathError{Op: "open", Path: filepath.Join(root.Name(), path), Err: err}
|
||||||
|
@ -168,17 +172,17 @@ func openRelative(path string, root *os.File, accessMask uint32, shareFlags uint
|
||||||
return f, err
|
return f, err
|
||||||
}
|
}
|
||||||
|
|
||||||
// linkRelative creates a hard link from oldname to newname (relative to oldroot
|
// LinkRelative creates a hard link from oldname to newname (relative to oldroot
|
||||||
// and newroot), failing if any of the intermediate path components are reparse
|
// and newroot), failing if any of the intermediate path components are reparse
|
||||||
// points.
|
// points.
|
||||||
func linkRelative(oldname string, oldroot *os.File, newname string, newroot *os.File) error {
|
func LinkRelative(oldname string, oldroot *os.File, newname string, newroot *os.File) error {
|
||||||
// Open the old file.
|
// Open the old file.
|
||||||
oldf, err := openRelativeInternal(
|
oldf, err := openRelativeInternal(
|
||||||
oldname,
|
oldname,
|
||||||
oldroot,
|
oldroot,
|
||||||
syscall.FILE_WRITE_ATTRIBUTES,
|
syscall.FILE_WRITE_ATTRIBUTES,
|
||||||
syscall.FILE_SHARE_READ|syscall.FILE_SHARE_WRITE|syscall.FILE_SHARE_DELETE,
|
syscall.FILE_SHARE_READ|syscall.FILE_SHARE_WRITE|syscall.FILE_SHARE_DELETE,
|
||||||
_FILE_OPEN,
|
FILE_OPEN,
|
||||||
0,
|
0,
|
||||||
)
|
)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
@ -195,8 +199,8 @@ func linkRelative(oldname string, oldroot *os.File, newname string, newroot *os.
|
||||||
newroot,
|
newroot,
|
||||||
syscall.GENERIC_READ,
|
syscall.GENERIC_READ,
|
||||||
syscall.FILE_SHARE_READ|syscall.FILE_SHARE_WRITE|syscall.FILE_SHARE_DELETE,
|
syscall.FILE_SHARE_READ|syscall.FILE_SHARE_WRITE|syscall.FILE_SHARE_DELETE,
|
||||||
_FILE_OPEN,
|
FILE_OPEN,
|
||||||
_FILE_DIRECTORY_FILE)
|
FILE_DIRECTORY_FILE)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return &os.LinkError{Op: "link", Old: oldf.Name(), New: filepath.Join(newroot.Name(), newname), Err: err}
|
return &os.LinkError{Op: "link", Old: oldf.Name(), New: filepath.Join(newroot.Name(), newname), Err: err}
|
||||||
}
|
}
|
||||||
|
@ -248,7 +252,7 @@ func linkRelative(oldname string, oldroot *os.File, newname string, newroot *os.
|
||||||
|
|
||||||
// deleteOnClose marks a file to be deleted when the handle is closed.
|
// deleteOnClose marks a file to be deleted when the handle is closed.
|
||||||
func deleteOnClose(f *os.File) error {
|
func deleteOnClose(f *os.File) error {
|
||||||
disposition := fileDispositionInformationEx{Flags: _FILE_DISPOSITION_DELETE}
|
disposition := fileDispositionInformationEx{Flags: FILE_DISPOSITION_DELETE}
|
||||||
var iosb ioStatusBlock
|
var iosb ioStatusBlock
|
||||||
status := ntSetInformationFile(
|
status := ntSetInformationFile(
|
||||||
f.Fd(),
|
f.Fd(),
|
||||||
|
@ -281,16 +285,16 @@ func clearReadOnly(f *os.File) error {
|
||||||
return winio.SetFileBasicInfo(f, &sbi)
|
return winio.SetFileBasicInfo(f, &sbi)
|
||||||
}
|
}
|
||||||
|
|
||||||
// removeRelative removes a file or directory relative to a root, failing if any
|
// RemoveRelative removes a file or directory relative to a root, failing if any
|
||||||
// intermediate path components are reparse points.
|
// intermediate path components are reparse points.
|
||||||
func removeRelative(path string, root *os.File) error {
|
func RemoveRelative(path string, root *os.File) error {
|
||||||
f, err := openRelativeInternal(
|
f, err := openRelativeInternal(
|
||||||
path,
|
path,
|
||||||
root,
|
root,
|
||||||
_FILE_READ_ATTRIBUTES|_FILE_WRITE_ATTRIBUTES|_DELETE,
|
FILE_READ_ATTRIBUTES|FILE_WRITE_ATTRIBUTES|DELETE,
|
||||||
syscall.FILE_SHARE_READ|syscall.FILE_SHARE_WRITE|syscall.FILE_SHARE_DELETE,
|
syscall.FILE_SHARE_READ|syscall.FILE_SHARE_WRITE|syscall.FILE_SHARE_DELETE,
|
||||||
_FILE_OPEN,
|
FILE_OPEN,
|
||||||
_FILE_OPEN_REPARSE_POINT)
|
FILE_OPEN_REPARSE_POINT)
|
||||||
if err == nil {
|
if err == nil {
|
||||||
defer f.Close()
|
defer f.Close()
|
||||||
err = deleteOnClose(f)
|
err = deleteOnClose(f)
|
||||||
|
@ -306,10 +310,10 @@ func removeRelative(path string, root *os.File) error {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// removeAllRelative removes a directory tree relative to a root, failing if any
|
// RemoveAllRelative removes a directory tree relative to a root, failing if any
|
||||||
// intermediate path components are reparse points.
|
// intermediate path components are reparse points.
|
||||||
func removeAllRelative(path string, root *os.File) error {
|
func RemoveAllRelative(path string, root *os.File) error {
|
||||||
fi, err := lstatRelative(path, root)
|
fi, err := LstatRelative(path, root)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
if os.IsNotExist(err) {
|
if os.IsNotExist(err) {
|
||||||
return nil
|
return nil
|
||||||
|
@ -319,7 +323,7 @@ func removeAllRelative(path string, root *os.File) error {
|
||||||
fileAttributes := fi.Sys().(*syscall.Win32FileAttributeData).FileAttributes
|
fileAttributes := fi.Sys().(*syscall.Win32FileAttributeData).FileAttributes
|
||||||
if fileAttributes&syscall.FILE_ATTRIBUTE_DIRECTORY == 0 || fileAttributes&syscall.FILE_ATTRIBUTE_REPARSE_POINT != 0 {
|
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.
|
// If this is a reparse point, it can't have children. Simple remove will do.
|
||||||
err := removeRelative(path, root)
|
err := RemoveRelative(path, root)
|
||||||
if err == nil || os.IsNotExist(err) {
|
if err == nil || os.IsNotExist(err) {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
@ -327,7 +331,7 @@ func removeAllRelative(path string, root *os.File) error {
|
||||||
}
|
}
|
||||||
|
|
||||||
// It is necessary to use os.Open as Readdirnames does not work with
|
// It is necessary to use os.Open as Readdirnames does not work with
|
||||||
// openRelative. This is safe because the above lstatrelative fails
|
// OpenRelative. This is safe because the above lstatrelative fails
|
||||||
// if the target is outside the root, and we know this is not a
|
// if the target is outside the root, and we know this is not a
|
||||||
// symlink from the above FILE_ATTRIBUTE_REPARSE_POINT check.
|
// symlink from the above FILE_ATTRIBUTE_REPARSE_POINT check.
|
||||||
fd, err := os.Open(filepath.Join(root.Name(), path))
|
fd, err := os.Open(filepath.Join(root.Name(), path))
|
||||||
|
@ -344,7 +348,7 @@ func removeAllRelative(path string, root *os.File) error {
|
||||||
for {
|
for {
|
||||||
names, err1 := fd.Readdirnames(100)
|
names, err1 := fd.Readdirnames(100)
|
||||||
for _, name := range names {
|
for _, name := range names {
|
||||||
err1 := removeAllRelative(path+string(os.PathSeparator)+name, root)
|
err1 := RemoveAllRelative(path+string(os.PathSeparator)+name, root)
|
||||||
if err == nil {
|
if err == nil {
|
||||||
err = err1
|
err = err1
|
||||||
}
|
}
|
||||||
|
@ -363,7 +367,7 @@ func removeAllRelative(path string, root *os.File) error {
|
||||||
fd.Close()
|
fd.Close()
|
||||||
|
|
||||||
// Remove directory.
|
// Remove directory.
|
||||||
err1 := removeRelative(path, root)
|
err1 := RemoveRelative(path, root)
|
||||||
if err1 == nil || os.IsNotExist(err1) {
|
if err1 == nil || os.IsNotExist(err1) {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
@ -373,16 +377,16 @@ func removeAllRelative(path string, root *os.File) error {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
// mkdirRelative creates a directory relative to a root, failing if any
|
// MkdirRelative creates a directory relative to a root, failing if any
|
||||||
// intermediate path components are reparse points.
|
// intermediate path components are reparse points.
|
||||||
func mkdirRelative(path string, root *os.File) error {
|
func MkdirRelative(path string, root *os.File) error {
|
||||||
f, err := openRelativeInternal(
|
f, err := openRelativeInternal(
|
||||||
path,
|
path,
|
||||||
root,
|
root,
|
||||||
0,
|
0,
|
||||||
syscall.FILE_SHARE_READ|syscall.FILE_SHARE_WRITE|syscall.FILE_SHARE_DELETE,
|
syscall.FILE_SHARE_READ|syscall.FILE_SHARE_WRITE|syscall.FILE_SHARE_DELETE,
|
||||||
_FILE_CREATE,
|
FILE_CREATE,
|
||||||
_FILE_DIRECTORY_FILE)
|
FILE_DIRECTORY_FILE)
|
||||||
if err == nil {
|
if err == nil {
|
||||||
f.Close()
|
f.Close()
|
||||||
} else {
|
} else {
|
||||||
|
@ -391,16 +395,16 @@ func mkdirRelative(path string, root *os.File) error {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
// lstatRelative performs a stat operation on a file relative to a root, failing
|
// LstatRelative performs a stat operation on a file relative to a root, failing
|
||||||
// if any intermediate path components are reparse points.
|
// if any intermediate path components are reparse points.
|
||||||
func lstatRelative(path string, root *os.File) (os.FileInfo, error) {
|
func LstatRelative(path string, root *os.File) (os.FileInfo, error) {
|
||||||
f, err := openRelativeInternal(
|
f, err := openRelativeInternal(
|
||||||
path,
|
path,
|
||||||
root,
|
root,
|
||||||
_FILE_READ_ATTRIBUTES,
|
FILE_READ_ATTRIBUTES,
|
||||||
syscall.FILE_SHARE_READ|syscall.FILE_SHARE_WRITE|syscall.FILE_SHARE_DELETE,
|
syscall.FILE_SHARE_READ|syscall.FILE_SHARE_WRITE|syscall.FILE_SHARE_DELETE,
|
||||||
_FILE_OPEN,
|
FILE_OPEN,
|
||||||
_FILE_OPEN_REPARSE_POINT)
|
FILE_OPEN_REPARSE_POINT)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, &os.PathError{Op: "stat", Path: filepath.Join(root.Name(), path), Err: err}
|
return nil, &os.PathError{Op: "stat", Path: filepath.Join(root.Name(), path), Err: err}
|
||||||
}
|
}
|
||||||
|
@ -408,16 +412,16 @@ func lstatRelative(path string, root *os.File) (os.FileInfo, error) {
|
||||||
return f.Stat()
|
return f.Stat()
|
||||||
}
|
}
|
||||||
|
|
||||||
// ensureNotReparsePointRelative validates that a given file (relative to a
|
// EnsureNotReparsePointRelative validates that a given file (relative to a
|
||||||
// root) and all intermediate path components are not a reparse points.
|
// root) and all intermediate path components are not a reparse points.
|
||||||
func ensureNotReparsePointRelative(path string, root *os.File) error {
|
func EnsureNotReparsePointRelative(path string, root *os.File) error {
|
||||||
// Perform an open with OBJ_DONT_REPARSE but without specifying FILE_OPEN_REPARSE_POINT.
|
// Perform an open with OBJ_DONT_REPARSE but without specifying FILE_OPEN_REPARSE_POINT.
|
||||||
f, err := openRelative(
|
f, err := OpenRelative(
|
||||||
path,
|
path,
|
||||||
root,
|
root,
|
||||||
0,
|
0,
|
||||||
syscall.FILE_SHARE_READ|syscall.FILE_SHARE_WRITE|syscall.FILE_SHARE_DELETE,
|
syscall.FILE_SHARE_READ|syscall.FILE_SHARE_WRITE|syscall.FILE_SHARE_DELETE,
|
||||||
_FILE_OPEN,
|
FILE_OPEN,
|
||||||
0)
|
0)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
79
vendor/github.com/Microsoft/hcsshim/internal/safefile/zsyscall_windows.go
generated
vendored
Normal file
79
vendor/github.com/Microsoft/hcsshim/internal/safefile/zsyscall_windows.go
generated
vendored
Normal file
|
@ -0,0 +1,79 @@
|
||||||
|
// MACHINE GENERATED BY 'go generate' COMMAND; DO NOT EDIT
|
||||||
|
|
||||||
|
package safefile
|
||||||
|
|
||||||
|
import (
|
||||||
|
"syscall"
|
||||||
|
"unsafe"
|
||||||
|
|
||||||
|
"golang.org/x/sys/windows"
|
||||||
|
)
|
||||||
|
|
||||||
|
var _ unsafe.Pointer
|
||||||
|
|
||||||
|
// Do the interface allocations only once for common
|
||||||
|
// Errno values.
|
||||||
|
const (
|
||||||
|
errnoERROR_IO_PENDING = 997
|
||||||
|
)
|
||||||
|
|
||||||
|
var (
|
||||||
|
errERROR_IO_PENDING error = syscall.Errno(errnoERROR_IO_PENDING)
|
||||||
|
)
|
||||||
|
|
||||||
|
// errnoErr returns common boxed Errno values, to prevent
|
||||||
|
// allocations at runtime.
|
||||||
|
func errnoErr(e syscall.Errno) error {
|
||||||
|
switch e {
|
||||||
|
case 0:
|
||||||
|
return nil
|
||||||
|
case errnoERROR_IO_PENDING:
|
||||||
|
return errERROR_IO_PENDING
|
||||||
|
}
|
||||||
|
// TODO: add more here, after collecting data on the common
|
||||||
|
// error values see on Windows. (perhaps when running
|
||||||
|
// all.bat?)
|
||||||
|
return e
|
||||||
|
}
|
||||||
|
|
||||||
|
var (
|
||||||
|
modntdll = windows.NewLazySystemDLL("ntdll.dll")
|
||||||
|
modkernel32 = windows.NewLazySystemDLL("kernel32.dll")
|
||||||
|
|
||||||
|
procNtCreateFile = modntdll.NewProc("NtCreateFile")
|
||||||
|
procNtSetInformationFile = modntdll.NewProc("NtSetInformationFile")
|
||||||
|
procRtlNtStatusToDosErrorNoTeb = modntdll.NewProc("RtlNtStatusToDosErrorNoTeb")
|
||||||
|
procLocalAlloc = modkernel32.NewProc("LocalAlloc")
|
||||||
|
procLocalFree = modkernel32.NewProc("LocalFree")
|
||||||
|
)
|
||||||
|
|
||||||
|
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
|
||||||
|
}
|
|
@ -0,0 +1,228 @@
|
||||||
|
package schema1
|
||||||
|
|
||||||
|
import (
|
||||||
|
"encoding/json"
|
||||||
|
"time"
|
||||||
|
)
|
||||||
|
|
||||||
|
// ProcessConfig is used as both the input of Container.CreateProcess
|
||||||
|
// and to convert the parameters to JSON for passing onto the HCS
|
||||||
|
type ProcessConfig struct {
|
||||||
|
ApplicationName string `json:",omitempty"`
|
||||||
|
CommandLine string `json:",omitempty"`
|
||||||
|
CommandArgs []string `json:",omitempty"` // Used by Linux Containers on Windows
|
||||||
|
User string `json:",omitempty"`
|
||||||
|
WorkingDirectory string `json:",omitempty"`
|
||||||
|
Environment map[string]string `json:",omitempty"`
|
||||||
|
EmulateConsole bool `json:",omitempty"`
|
||||||
|
CreateStdInPipe bool `json:",omitempty"`
|
||||||
|
CreateStdOutPipe bool `json:",omitempty"`
|
||||||
|
CreateStdErrPipe bool `json:",omitempty"`
|
||||||
|
ConsoleSize [2]uint `json:",omitempty"`
|
||||||
|
CreateInUtilityVm bool `json:",omitempty"` // Used by Linux Containers on Windows
|
||||||
|
OCISpecification *json.RawMessage `json:",omitempty"` // Used by Linux Containers on Windows
|
||||||
|
}
|
||||||
|
|
||||||
|
type Layer struct {
|
||||||
|
ID string
|
||||||
|
Path string
|
||||||
|
}
|
||||||
|
|
||||||
|
type MappedDir struct {
|
||||||
|
HostPath string
|
||||||
|
ContainerPath string
|
||||||
|
ReadOnly bool
|
||||||
|
BandwidthMaximum uint64
|
||||||
|
IOPSMaximum uint64
|
||||||
|
CreateInUtilityVM bool
|
||||||
|
// LinuxMetadata - Support added in 1803/RS4+.
|
||||||
|
LinuxMetadata bool `json:",omitempty"`
|
||||||
|
}
|
||||||
|
|
||||||
|
type MappedPipe struct {
|
||||||
|
HostPath string
|
||||||
|
ContainerPipeName string
|
||||||
|
}
|
||||||
|
|
||||||
|
type HvRuntime struct {
|
||||||
|
ImagePath string `json:",omitempty"`
|
||||||
|
SkipTemplate bool `json:",omitempty"`
|
||||||
|
LinuxInitrdFile string `json:",omitempty"` // File under ImagePath on host containing an initrd image for starting a Linux utility VM
|
||||||
|
LinuxKernelFile string `json:",omitempty"` // File under ImagePath on host containing a kernel for starting a Linux utility VM
|
||||||
|
LinuxBootParameters string `json:",omitempty"` // Additional boot parameters for starting a Linux Utility VM in initrd mode
|
||||||
|
BootSource string `json:",omitempty"` // "Vhd" for Linux Utility VM booting from VHD
|
||||||
|
WritableBootSource bool `json:",omitempty"` // Linux Utility VM booting from VHD
|
||||||
|
}
|
||||||
|
|
||||||
|
type MappedVirtualDisk struct {
|
||||||
|
HostPath string `json:",omitempty"` // Path to VHD on the host
|
||||||
|
ContainerPath string // Platform-specific mount point path in the container
|
||||||
|
CreateInUtilityVM bool `json:",omitempty"`
|
||||||
|
ReadOnly bool `json:",omitempty"`
|
||||||
|
Cache string `json:",omitempty"` // "" (Unspecified); "Disabled"; "Enabled"; "Private"; "PrivateAllowSharing"
|
||||||
|
AttachOnly bool `json:",omitempty:`
|
||||||
|
}
|
||||||
|
|
||||||
|
// AssignedDevice represents a device that has been directly assigned to a container
|
||||||
|
//
|
||||||
|
// NOTE: Support added in RS5
|
||||||
|
type AssignedDevice struct {
|
||||||
|
// InterfaceClassGUID of the device to assign to container.
|
||||||
|
InterfaceClassGUID string `json:"InterfaceClassGuid,omitempty"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// ContainerConfig is used as both the input of CreateContainer
|
||||||
|
// and to convert the parameters to JSON for passing onto the HCS
|
||||||
|
type ContainerConfig struct {
|
||||||
|
SystemType string // HCS requires this to be hard-coded to "Container"
|
||||||
|
Name string // Name of the container. We use the docker ID.
|
||||||
|
Owner string `json:",omitempty"` // The management platform that created this container
|
||||||
|
VolumePath string `json:",omitempty"` // Windows volume path for scratch space. Used by Windows Server Containers only. Format \\?\\Volume{GUID}
|
||||||
|
IgnoreFlushesDuringBoot bool `json:",omitempty"` // Optimization hint for container startup in Windows
|
||||||
|
LayerFolderPath string `json:",omitempty"` // Where the layer folders are located. Used by Windows Server Containers only. Format %root%\windowsfilter\containerID
|
||||||
|
Layers []Layer // List of storage layers. Required for Windows Server and Hyper-V Containers. Format ID=GUID;Path=%root%\windowsfilter\layerID
|
||||||
|
Credentials string `json:",omitempty"` // Credentials information
|
||||||
|
ProcessorCount uint32 `json:",omitempty"` // Number of processors to assign to the container.
|
||||||
|
ProcessorWeight uint64 `json:",omitempty"` // CPU shares (relative weight to other containers with cpu shares). Range is from 1 to 10000. A value of 0 results in default shares.
|
||||||
|
ProcessorMaximum int64 `json:",omitempty"` // Specifies the portion of processor cycles that this container can use as a percentage times 100. Range is from 1 to 10000. A value of 0 results in no limit.
|
||||||
|
StorageIOPSMaximum uint64 `json:",omitempty"` // Maximum Storage IOPS
|
||||||
|
StorageBandwidthMaximum uint64 `json:",omitempty"` // Maximum Storage Bandwidth in bytes per second
|
||||||
|
StorageSandboxSize uint64 `json:",omitempty"` // Size in bytes that the container system drive should be expanded to if smaller
|
||||||
|
MemoryMaximumInMB int64 `json:",omitempty"` // Maximum memory available to the container in Megabytes
|
||||||
|
HostName string `json:",omitempty"` // Hostname
|
||||||
|
MappedDirectories []MappedDir `json:",omitempty"` // List of mapped directories (volumes/mounts)
|
||||||
|
MappedPipes []MappedPipe `json:",omitempty"` // List of mapped Windows named pipes
|
||||||
|
HvPartition bool // True if it a Hyper-V Container
|
||||||
|
NetworkSharedContainerName string `json:",omitempty"` // Name (ID) of the container that we will share the network stack with.
|
||||||
|
EndpointList []string `json:",omitempty"` // List of networking endpoints to be attached to container
|
||||||
|
HvRuntime *HvRuntime `json:",omitempty"` // Hyper-V container settings. Used by Hyper-V containers only. Format ImagePath=%root%\BaseLayerID\UtilityVM
|
||||||
|
Servicing bool `json:",omitempty"` // True if this container is for servicing
|
||||||
|
AllowUnqualifiedDNSQuery bool `json:",omitempty"` // True to allow unqualified DNS name resolution
|
||||||
|
DNSSearchList string `json:",omitempty"` // Comma seperated list of DNS suffixes to use for name resolution
|
||||||
|
ContainerType string `json:",omitempty"` // "Linux" for Linux containers on Windows. Omitted otherwise.
|
||||||
|
TerminateOnLastHandleClosed bool `json:",omitempty"` // Should HCS terminate the container once all handles have been closed
|
||||||
|
MappedVirtualDisks []MappedVirtualDisk `json:",omitempty"` // Array of virtual disks to mount at start
|
||||||
|
AssignedDevices []AssignedDevice `json:",omitempty"` // Array of devices to assign. NOTE: Support added in RS5
|
||||||
|
}
|
||||||
|
|
||||||
|
type ComputeSystemQuery struct {
|
||||||
|
IDs []string `json:"Ids,omitempty"`
|
||||||
|
Types []string `json:",omitempty"`
|
||||||
|
Names []string `json:",omitempty"`
|
||||||
|
Owners []string `json:",omitempty"`
|
||||||
|
}
|
||||||
|
|
||||||
|
type PropertyType string
|
||||||
|
|
||||||
|
const (
|
||||||
|
PropertyTypeStatistics PropertyType = "Statistics"
|
||||||
|
PropertyTypeProcessList = "ProcessList"
|
||||||
|
PropertyTypeMappedVirtualDisk = "MappedVirtualDisk"
|
||||||
|
)
|
||||||
|
|
||||||
|
type PropertyQuery struct {
|
||||||
|
PropertyTypes []PropertyType `json:",omitempty"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// ContainerProperties holds the properties for a container and the processes running in that container
|
||||||
|
type ContainerProperties struct {
|
||||||
|
ID string `json:"Id"`
|
||||||
|
State string
|
||||||
|
Name string
|
||||||
|
SystemType string
|
||||||
|
Owner string
|
||||||
|
SiloGUID string `json:"SiloGuid,omitempty"`
|
||||||
|
RuntimeID string `json:"RuntimeId,omitempty"`
|
||||||
|
IsRuntimeTemplate bool `json:",omitempty"`
|
||||||
|
RuntimeImagePath string `json:",omitempty"`
|
||||||
|
Stopped bool `json:",omitempty"`
|
||||||
|
ExitType string `json:",omitempty"`
|
||||||
|
AreUpdatesPending bool `json:",omitempty"`
|
||||||
|
ObRoot string `json:",omitempty"`
|
||||||
|
Statistics Statistics `json:",omitempty"`
|
||||||
|
ProcessList []ProcessListItem `json:",omitempty"`
|
||||||
|
MappedVirtualDiskControllers map[int]MappedVirtualDiskController `json:",omitempty"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// MemoryStats holds the memory statistics for a container
|
||||||
|
type MemoryStats struct {
|
||||||
|
UsageCommitBytes uint64 `json:"MemoryUsageCommitBytes,omitempty"`
|
||||||
|
UsageCommitPeakBytes uint64 `json:"MemoryUsageCommitPeakBytes,omitempty"`
|
||||||
|
UsagePrivateWorkingSetBytes uint64 `json:"MemoryUsagePrivateWorkingSetBytes,omitempty"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// ProcessorStats holds the processor statistics for a container
|
||||||
|
type ProcessorStats struct {
|
||||||
|
TotalRuntime100ns uint64 `json:",omitempty"`
|
||||||
|
RuntimeUser100ns uint64 `json:",omitempty"`
|
||||||
|
RuntimeKernel100ns uint64 `json:",omitempty"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// StorageStats holds the storage statistics for a container
|
||||||
|
type StorageStats struct {
|
||||||
|
ReadCountNormalized uint64 `json:",omitempty"`
|
||||||
|
ReadSizeBytes uint64 `json:",omitempty"`
|
||||||
|
WriteCountNormalized uint64 `json:",omitempty"`
|
||||||
|
WriteSizeBytes uint64 `json:",omitempty"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// NetworkStats holds the network statistics for a container
|
||||||
|
type NetworkStats struct {
|
||||||
|
BytesReceived uint64 `json:",omitempty"`
|
||||||
|
BytesSent uint64 `json:",omitempty"`
|
||||||
|
PacketsReceived uint64 `json:",omitempty"`
|
||||||
|
PacketsSent uint64 `json:",omitempty"`
|
||||||
|
DroppedPacketsIncoming uint64 `json:",omitempty"`
|
||||||
|
DroppedPacketsOutgoing uint64 `json:",omitempty"`
|
||||||
|
EndpointId string `json:",omitempty"`
|
||||||
|
InstanceId string `json:",omitempty"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// Statistics is the structure returned by a statistics call on a container
|
||||||
|
type Statistics struct {
|
||||||
|
Timestamp time.Time `json:",omitempty"`
|
||||||
|
ContainerStartTime time.Time `json:",omitempty"`
|
||||||
|
Uptime100ns uint64 `json:",omitempty"`
|
||||||
|
Memory MemoryStats `json:",omitempty"`
|
||||||
|
Processor ProcessorStats `json:",omitempty"`
|
||||||
|
Storage StorageStats `json:",omitempty"`
|
||||||
|
Network []NetworkStats `json:",omitempty"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// ProcessList is the structure of an item returned by a ProcessList call on a container
|
||||||
|
type ProcessListItem struct {
|
||||||
|
CreateTimestamp time.Time `json:",omitempty"`
|
||||||
|
ImageName string `json:",omitempty"`
|
||||||
|
KernelTime100ns uint64 `json:",omitempty"`
|
||||||
|
MemoryCommitBytes uint64 `json:",omitempty"`
|
||||||
|
MemoryWorkingSetPrivateBytes uint64 `json:",omitempty"`
|
||||||
|
MemoryWorkingSetSharedBytes uint64 `json:",omitempty"`
|
||||||
|
ProcessId uint32 `json:",omitempty"`
|
||||||
|
UserTime100ns uint64 `json:",omitempty"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// MappedVirtualDiskController is the structure of an item returned by a MappedVirtualDiskList call on a container
|
||||||
|
type MappedVirtualDiskController struct {
|
||||||
|
MappedVirtualDisks map[int]MappedVirtualDisk `json:",omitempty"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// Type of Request Support in ModifySystem
|
||||||
|
type RequestType string
|
||||||
|
|
||||||
|
// Type of Resource Support in ModifySystem
|
||||||
|
type ResourceType string
|
||||||
|
|
||||||
|
// RequestType const
|
||||||
|
const (
|
||||||
|
Add RequestType = "Add"
|
||||||
|
Remove RequestType = "Remove"
|
||||||
|
Network ResourceType = "Network"
|
||||||
|
)
|
||||||
|
|
||||||
|
// ResourceModificationRequestResponse 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 ResourceModificationRequestResponse struct {
|
||||||
|
Resource ResourceType `json:"ResourceType"`
|
||||||
|
Data interface{} `json:"Settings"`
|
||||||
|
Request RequestType `json:"RequestType,omitempty"`
|
||||||
|
}
|
|
@ -0,0 +1,26 @@
|
||||||
|
package timeout
|
||||||
|
|
||||||
|
import (
|
||||||
|
"os"
|
||||||
|
"strconv"
|
||||||
|
"time"
|
||||||
|
)
|
||||||
|
|
||||||
|
// Duration is the default time to wait for various operations.
|
||||||
|
// - Waiting for async notifications from HCS
|
||||||
|
// - Waiting for processes to launch through
|
||||||
|
// - Waiting to copy data to/from a launched processes stdio pipes.
|
||||||
|
//
|
||||||
|
// This can be overridden through environment variable `HCS_TIMEOUT_SECONDS`
|
||||||
|
|
||||||
|
var Duration = 4 * time.Minute
|
||||||
|
|
||||||
|
func init() {
|
||||||
|
envTimeout := os.Getenv("HCSSHIM_TIMEOUT_SECONDS")
|
||||||
|
if len(envTimeout) > 0 {
|
||||||
|
e, err := strconv.Atoi(envTimeout)
|
||||||
|
if err == nil && e > 0 {
|
||||||
|
Duration = time.Second * time.Duration(e)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
25
vendor/github.com/Microsoft/hcsshim/internal/wclayer/activatelayer.go
generated
vendored
Normal file
25
vendor/github.com/Microsoft/hcsshim/internal/wclayer/activatelayer.go
generated
vendored
Normal file
|
@ -0,0 +1,25 @@
|
||||||
|
package wclayer
|
||||||
|
|
||||||
|
import (
|
||||||
|
"github.com/Microsoft/hcsshim/internal/hcserror"
|
||||||
|
"github.com/sirupsen/logrus"
|
||||||
|
)
|
||||||
|
|
||||||
|
// ActivateLayer will find the layer with the given id and mount it's filesystem.
|
||||||
|
// For a read/write layer, the mounted filesystem will appear as a volume on the
|
||||||
|
// host, while a read-only layer is generally expected to be a no-op.
|
||||||
|
// An activated layer must later be deactivated via DeactivateLayer.
|
||||||
|
func ActivateLayer(path string) error {
|
||||||
|
title := "hcsshim::ActivateLayer "
|
||||||
|
logrus.Debugf(title+"path %s", path)
|
||||||
|
|
||||||
|
err := activateLayer(&stdDriverInfo, path)
|
||||||
|
if err != nil {
|
||||||
|
err = hcserror.Errorf(err, title, "path=%s", path)
|
||||||
|
logrus.Error(err)
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
logrus.Debugf(title+" - succeeded path=%s", path)
|
||||||
|
return nil
|
||||||
|
}
|
|
@ -1,4 +1,4 @@
|
||||||
package hcsshim
|
package wclayer
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"errors"
|
"errors"
|
||||||
|
@ -7,6 +7,8 @@ import (
|
||||||
"syscall"
|
"syscall"
|
||||||
|
|
||||||
"github.com/Microsoft/go-winio"
|
"github.com/Microsoft/go-winio"
|
||||||
|
"github.com/Microsoft/hcsshim/internal/hcserror"
|
||||||
|
"github.com/Microsoft/hcsshim/internal/safefile"
|
||||||
)
|
)
|
||||||
|
|
||||||
type baseLayerWriter struct {
|
type baseLayerWriter struct {
|
||||||
|
@ -29,7 +31,7 @@ type dirInfo struct {
|
||||||
func reapplyDirectoryTimes(root *os.File, dis []dirInfo) error {
|
func reapplyDirectoryTimes(root *os.File, dis []dirInfo) error {
|
||||||
for i := range dis {
|
for i := range dis {
|
||||||
di := &dis[len(dis)-i-1] // reverse order: process child directories first
|
di := &dis[len(dis)-i-1] // reverse order: process child directories first
|
||||||
f, err := openRelative(di.path, root, syscall.GENERIC_READ|syscall.GENERIC_WRITE, syscall.FILE_SHARE_READ, _FILE_OPEN, _FILE_DIRECTORY_FILE)
|
f, err := safefile.OpenRelative(di.path, root, syscall.GENERIC_READ|syscall.GENERIC_WRITE, syscall.FILE_SHARE_READ, safefile.FILE_OPEN, safefile.FILE_DIRECTORY_FILE)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
@ -84,21 +86,21 @@ func (w *baseLayerWriter) Add(name string, fileInfo *winio.FileBasicInfo) (err e
|
||||||
|
|
||||||
extraFlags := uint32(0)
|
extraFlags := uint32(0)
|
||||||
if fileInfo.FileAttributes&syscall.FILE_ATTRIBUTE_DIRECTORY != 0 {
|
if fileInfo.FileAttributes&syscall.FILE_ATTRIBUTE_DIRECTORY != 0 {
|
||||||
extraFlags |= _FILE_DIRECTORY_FILE
|
extraFlags |= safefile.FILE_DIRECTORY_FILE
|
||||||
if fileInfo.FileAttributes&syscall.FILE_ATTRIBUTE_REPARSE_POINT == 0 {
|
if fileInfo.FileAttributes&syscall.FILE_ATTRIBUTE_REPARSE_POINT == 0 {
|
||||||
w.dirInfo = append(w.dirInfo, dirInfo{name, *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)
|
mode := uint32(syscall.GENERIC_READ | syscall.GENERIC_WRITE | winio.WRITE_DAC | winio.WRITE_OWNER | winio.ACCESS_SYSTEM_SECURITY)
|
||||||
f, err = openRelative(name, w.root, mode, syscall.FILE_SHARE_READ, _FILE_CREATE, extraFlags)
|
f, err = safefile.OpenRelative(name, w.root, mode, syscall.FILE_SHARE_READ, safefile.FILE_CREATE, extraFlags)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return makeError(err, "Failed to openRelative", name)
|
return hcserror.New(err, "Failed to safefile.OpenRelative", name)
|
||||||
}
|
}
|
||||||
|
|
||||||
err = winio.SetFileBasicInfo(f, fileInfo)
|
err = winio.SetFileBasicInfo(f, fileInfo)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return makeError(err, "Failed to SetFileBasicInfo", name)
|
return hcserror.New(err, "Failed to SetFileBasicInfo", name)
|
||||||
}
|
}
|
||||||
|
|
||||||
w.f = f
|
w.f = f
|
||||||
|
@ -119,7 +121,7 @@ func (w *baseLayerWriter) AddLink(name string, target string) (err error) {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
return linkRelative(target, w.root, name, w.root)
|
return safefile.LinkRelative(target, w.root, name, w.root)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (w *baseLayerWriter) Remove(name string) error {
|
func (w *baseLayerWriter) Remove(name string) error {
|
||||||
|
@ -157,7 +159,7 @@ func (w *baseLayerWriter) Close() error {
|
||||||
}
|
}
|
||||||
|
|
||||||
if w.hasUtilityVM {
|
if w.hasUtilityVM {
|
||||||
err := ensureNotReparsePointRelative("UtilityVM", w.root)
|
err := safefile.EnsureNotReparsePointRelative("UtilityVM", w.root)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
23
vendor/github.com/Microsoft/hcsshim/internal/wclayer/createlayer.go
generated
vendored
Normal file
23
vendor/github.com/Microsoft/hcsshim/internal/wclayer/createlayer.go
generated
vendored
Normal file
|
@ -0,0 +1,23 @@
|
||||||
|
package wclayer
|
||||||
|
|
||||||
|
import (
|
||||||
|
"github.com/Microsoft/hcsshim/internal/hcserror"
|
||||||
|
"github.com/sirupsen/logrus"
|
||||||
|
)
|
||||||
|
|
||||||
|
// CreateLayer creates a new, empty, read-only layer on the filesystem based on
|
||||||
|
// the parent layer provided.
|
||||||
|
func CreateLayer(path, parent string) error {
|
||||||
|
title := "hcsshim::CreateLayer "
|
||||||
|
logrus.Debugf(title+"Flavour %d ID %s parent %s", path, parent)
|
||||||
|
|
||||||
|
err := createLayer(&stdDriverInfo, path, parent)
|
||||||
|
if err != nil {
|
||||||
|
err = hcserror.Errorf(err, title, "path=%s parent=%s flavour=%d", path, parent)
|
||||||
|
logrus.Error(err)
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
logrus.Debugf(title+" - succeeded path=%s parent=%s flavour=%d", path, parent)
|
||||||
|
return nil
|
||||||
|
}
|
31
vendor/github.com/Microsoft/hcsshim/internal/wclayer/createscratchlayer.go
generated
vendored
Normal file
31
vendor/github.com/Microsoft/hcsshim/internal/wclayer/createscratchlayer.go
generated
vendored
Normal file
|
@ -0,0 +1,31 @@
|
||||||
|
package wclayer
|
||||||
|
|
||||||
|
import (
|
||||||
|
"github.com/Microsoft/hcsshim/internal/hcserror"
|
||||||
|
"github.com/sirupsen/logrus"
|
||||||
|
)
|
||||||
|
|
||||||
|
// CreateScratchLayer creates and populates new read-write layer for use by a container.
|
||||||
|
// This requires both the id of the direct parent layer, as well as the full list
|
||||||
|
// of paths to all parent layers up to the base (and including the direct parent
|
||||||
|
// whose id was provided).
|
||||||
|
func CreateScratchLayer(path string, parentLayerPaths []string) error {
|
||||||
|
title := "hcsshim::CreateScratchLayer "
|
||||||
|
logrus.Debugf(title+"path %s", path)
|
||||||
|
|
||||||
|
// Generate layer descriptors
|
||||||
|
layers, err := layerPathsToDescriptors(parentLayerPaths)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
err = createSandboxLayer(&stdDriverInfo, path, 0, layers)
|
||||||
|
if err != nil {
|
||||||
|
err = hcserror.Errorf(err, title, "path=%s", path)
|
||||||
|
logrus.Error(err)
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
logrus.Debugf(title+"- succeeded path=%s", path)
|
||||||
|
return nil
|
||||||
|
}
|
22
vendor/github.com/Microsoft/hcsshim/internal/wclayer/deactivatelayer.go
generated
vendored
Normal file
22
vendor/github.com/Microsoft/hcsshim/internal/wclayer/deactivatelayer.go
generated
vendored
Normal file
|
@ -0,0 +1,22 @@
|
||||||
|
package wclayer
|
||||||
|
|
||||||
|
import (
|
||||||
|
"github.com/Microsoft/hcsshim/internal/hcserror"
|
||||||
|
"github.com/sirupsen/logrus"
|
||||||
|
)
|
||||||
|
|
||||||
|
// DeactivateLayer will dismount a layer that was mounted via ActivateLayer.
|
||||||
|
func DeactivateLayer(path string) error {
|
||||||
|
title := "hcsshim::DeactivateLayer "
|
||||||
|
logrus.Debugf(title+"path %s", path)
|
||||||
|
|
||||||
|
err := deactivateLayer(&stdDriverInfo, path)
|
||||||
|
if err != nil {
|
||||||
|
err = hcserror.Errorf(err, title, "path=%s", path)
|
||||||
|
logrus.Error(err)
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
logrus.Debugf(title+"succeeded path=%s", path)
|
||||||
|
return nil
|
||||||
|
}
|
23
vendor/github.com/Microsoft/hcsshim/internal/wclayer/destroylayer.go
generated
vendored
Normal file
23
vendor/github.com/Microsoft/hcsshim/internal/wclayer/destroylayer.go
generated
vendored
Normal file
|
@ -0,0 +1,23 @@
|
||||||
|
package wclayer
|
||||||
|
|
||||||
|
import (
|
||||||
|
"github.com/Microsoft/hcsshim/internal/hcserror"
|
||||||
|
"github.com/sirupsen/logrus"
|
||||||
|
)
|
||||||
|
|
||||||
|
// DestroyLayer will remove the on-disk files representing the layer with the given
|
||||||
|
// path, including that layer's containing folder, if any.
|
||||||
|
func DestroyLayer(path string) error {
|
||||||
|
title := "hcsshim::DestroyLayer "
|
||||||
|
logrus.Debugf(title+"path %s", path)
|
||||||
|
|
||||||
|
err := destroyLayer(&stdDriverInfo, path)
|
||||||
|
if err != nil {
|
||||||
|
err = hcserror.Errorf(err, title, "path=%s", path)
|
||||||
|
logrus.Error(err)
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
logrus.Debugf(title+"succeeded path=%s", path)
|
||||||
|
return nil
|
||||||
|
}
|
22
vendor/github.com/Microsoft/hcsshim/internal/wclayer/expandscratchsize.go
generated
vendored
Normal file
22
vendor/github.com/Microsoft/hcsshim/internal/wclayer/expandscratchsize.go
generated
vendored
Normal file
|
@ -0,0 +1,22 @@
|
||||||
|
package wclayer
|
||||||
|
|
||||||
|
import (
|
||||||
|
"github.com/Microsoft/hcsshim/internal/hcserror"
|
||||||
|
"github.com/sirupsen/logrus"
|
||||||
|
)
|
||||||
|
|
||||||
|
// ExpandScratchSize expands the size of a layer to at least size bytes.
|
||||||
|
func ExpandScratchSize(path string, size uint64) error {
|
||||||
|
title := "hcsshim::ExpandScratchSize "
|
||||||
|
logrus.Debugf(title+"path=%s size=%d", path, size)
|
||||||
|
|
||||||
|
err := expandSandboxSize(&stdDriverInfo, path, size)
|
||||||
|
if err != nil {
|
||||||
|
err = hcserror.Errorf(err, title, "path=%s size=%d", path, size)
|
||||||
|
logrus.Error(err)
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
logrus.Debugf(title+"- succeeded path=%s size=%d", path, size)
|
||||||
|
return nil
|
||||||
|
}
|
|
@ -1,4 +1,4 @@
|
||||||
package hcsshim
|
package wclayer
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"io"
|
"io"
|
||||||
|
@ -7,6 +7,8 @@ import (
|
||||||
"syscall"
|
"syscall"
|
||||||
|
|
||||||
"github.com/Microsoft/go-winio"
|
"github.com/Microsoft/go-winio"
|
||||||
|
"github.com/Microsoft/hcsshim/internal/hcserror"
|
||||||
|
"github.com/Microsoft/hcsshim/internal/interop"
|
||||||
"github.com/sirupsen/logrus"
|
"github.com/sirupsen/logrus"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@ -15,9 +17,9 @@ import (
|
||||||
// format includes any metadata required for later importing the layer (using
|
// format includes any metadata required for later importing the layer (using
|
||||||
// ImportLayer), and requires the full list of parent layer paths in order to
|
// ImportLayer), and requires the full list of parent layer paths in order to
|
||||||
// perform the export.
|
// perform the export.
|
||||||
func ExportLayer(info DriverInfo, layerId string, exportFolderPath string, parentLayerPaths []string) error {
|
func ExportLayer(path string, exportFolderPath string, parentLayerPaths []string) error {
|
||||||
title := "hcsshim::ExportLayer "
|
title := "hcsshim::ExportLayer "
|
||||||
logrus.Debugf(title+"flavour %d layerId %s folder %s", info.Flavour, layerId, exportFolderPath)
|
logrus.Debugf(title+"path %s folder %s", path, exportFolderPath)
|
||||||
|
|
||||||
// Generate layer descriptors
|
// Generate layer descriptors
|
||||||
layers, err := layerPathsToDescriptors(parentLayerPaths)
|
layers, err := layerPathsToDescriptors(parentLayerPaths)
|
||||||
|
@ -25,21 +27,14 @@ func ExportLayer(info DriverInfo, layerId string, exportFolderPath string, paren
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
// Convert info to API calling convention
|
err = exportLayer(&stdDriverInfo, path, exportFolderPath, layers)
|
||||||
infop, err := convertDriverInfo(info)
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
err = hcserror.Errorf(err, title, "path=%s folder=%s", path, exportFolderPath)
|
||||||
logrus.Error(err)
|
logrus.Error(err)
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
err = exportLayer(&infop, layerId, exportFolderPath, layers)
|
logrus.Debugf(title+"succeeded path=%s folder=%s", path, exportFolderPath)
|
||||||
if err != nil {
|
|
||||||
err = makeErrorf(err, title, "layerId=%s flavour=%d folder=%s", layerId, info.Flavour, exportFolderPath)
|
|
||||||
logrus.Error(err)
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
logrus.Debugf(title+"succeeded flavour=%d layerId=%s folder=%s", info.Flavour, layerId, exportFolderPath)
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -69,11 +64,11 @@ func (r *FilterLayerReader) Next() (string, int64, *winio.FileBasicInfo, error)
|
||||||
if err == syscall.ERROR_NO_MORE_FILES {
|
if err == syscall.ERROR_NO_MORE_FILES {
|
||||||
err = io.EOF
|
err = io.EOF
|
||||||
} else {
|
} else {
|
||||||
err = makeError(err, "ExportLayerNext", "")
|
err = hcserror.New(err, "ExportLayerNext", "")
|
||||||
}
|
}
|
||||||
return "", 0, nil, err
|
return "", 0, nil, err
|
||||||
}
|
}
|
||||||
fileName := convertAndFreeCoTaskMemString(fileNamep)
|
fileName := interop.ConvertAndFreeCoTaskMemString(fileNamep)
|
||||||
if deleted != 0 {
|
if deleted != 0 {
|
||||||
fileInfo = nil
|
fileInfo = nil
|
||||||
}
|
}
|
||||||
|
@ -88,7 +83,7 @@ func (r *FilterLayerReader) Read(b []byte) (int, error) {
|
||||||
var bytesRead uint32
|
var bytesRead uint32
|
||||||
err := exportLayerRead(r.context, b, &bytesRead)
|
err := exportLayerRead(r.context, b, &bytesRead)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return 0, makeError(err, "ExportLayerRead", "")
|
return 0, hcserror.New(err, "ExportLayerRead", "")
|
||||||
}
|
}
|
||||||
if bytesRead == 0 {
|
if bytesRead == 0 {
|
||||||
return 0, io.EOF
|
return 0, io.EOF
|
||||||
|
@ -103,7 +98,7 @@ func (r *FilterLayerReader) Close() (err error) {
|
||||||
if r.context != 0 {
|
if r.context != 0 {
|
||||||
err = exportLayerEnd(r.context)
|
err = exportLayerEnd(r.context)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
err = makeError(err, "ExportLayerEnd", "")
|
err = hcserror.New(err, "ExportLayerEnd", "")
|
||||||
}
|
}
|
||||||
r.context = 0
|
r.context = 0
|
||||||
}
|
}
|
||||||
|
@ -113,34 +108,30 @@ func (r *FilterLayerReader) Close() (err error) {
|
||||||
// NewLayerReader returns a new layer reader for reading the contents of an on-disk layer.
|
// NewLayerReader returns a new layer reader for reading the contents of an on-disk layer.
|
||||||
// The caller must have taken the SeBackupPrivilege privilege
|
// The caller must have taken the SeBackupPrivilege privilege
|
||||||
// to call this and any methods on the resulting LayerReader.
|
// to call this and any methods on the resulting LayerReader.
|
||||||
func NewLayerReader(info DriverInfo, layerID string, parentLayerPaths []string) (LayerReader, error) {
|
func NewLayerReader(path string, parentLayerPaths []string) (LayerReader, error) {
|
||||||
if procExportLayerBegin.Find() != nil {
|
if procExportLayerBegin.Find() != nil {
|
||||||
// The new layer reader is not available on this Windows build. Fall back to the
|
// The new layer reader is not available on this Windows build. Fall back to the
|
||||||
// legacy export code path.
|
// legacy export code path.
|
||||||
path, err := ioutil.TempDir("", "hcs")
|
exportPath, err := ioutil.TempDir("", "hcs")
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
err = ExportLayer(info, layerID, path, parentLayerPaths)
|
err = ExportLayer(path, exportPath, parentLayerPaths)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
os.RemoveAll(path)
|
os.RemoveAll(exportPath)
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
return &legacyLayerReaderWrapper{newLegacyLayerReader(path)}, nil
|
return &legacyLayerReaderWrapper{newLegacyLayerReader(exportPath)}, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
layers, err := layerPathsToDescriptors(parentLayerPaths)
|
layers, err := layerPathsToDescriptors(parentLayerPaths)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
infop, err := convertDriverInfo(info)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
r := &FilterLayerReader{}
|
r := &FilterLayerReader{}
|
||||||
err = exportLayerBegin(&infop, layerID, layers, &r.context)
|
err = exportLayerBegin(&stdDriverInfo, path, layers, &r.context)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, makeError(err, "ExportLayerBegin", "")
|
return nil, hcserror.New(err, "ExportLayerBegin", "")
|
||||||
}
|
}
|
||||||
return r, err
|
return r, err
|
||||||
}
|
}
|
|
@ -1,34 +1,28 @@
|
||||||
package hcsshim
|
package wclayer
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"syscall"
|
"syscall"
|
||||||
|
|
||||||
|
"github.com/Microsoft/hcsshim/internal/hcserror"
|
||||||
"github.com/sirupsen/logrus"
|
"github.com/sirupsen/logrus"
|
||||||
)
|
)
|
||||||
|
|
||||||
// GetLayerMountPath will look for a mounted layer with the given id and return
|
// GetLayerMountPath will look for a mounted layer with the given path and return
|
||||||
// the path at which that layer can be accessed. This path may be a volume path
|
// the path at which that layer can be accessed. This path may be a volume path
|
||||||
// if the layer is a mounted read-write layer, otherwise it is expected to be the
|
// if the layer is a mounted read-write layer, otherwise it is expected to be the
|
||||||
// folder path at which the layer is stored.
|
// folder path at which the layer is stored.
|
||||||
func GetLayerMountPath(info DriverInfo, id string) (string, error) {
|
func GetLayerMountPath(path string) (string, error) {
|
||||||
title := "hcsshim::GetLayerMountPath "
|
title := "hcsshim::GetLayerMountPath "
|
||||||
logrus.Debugf(title+"Flavour %d ID %s", info.Flavour, id)
|
logrus.Debugf(title+"path %s", path)
|
||||||
|
|
||||||
// Convert info to API calling convention
|
|
||||||
infop, err := convertDriverInfo(info)
|
|
||||||
if err != nil {
|
|
||||||
logrus.Error(err)
|
|
||||||
return "", err
|
|
||||||
}
|
|
||||||
|
|
||||||
var mountPathLength uintptr
|
var mountPathLength uintptr
|
||||||
mountPathLength = 0
|
mountPathLength = 0
|
||||||
|
|
||||||
// Call the procedure itself.
|
// Call the procedure itself.
|
||||||
logrus.Debugf("Calling proc (1)")
|
logrus.Debugf("Calling proc (1)")
|
||||||
err = getLayerMountPath(&infop, id, &mountPathLength, nil)
|
err := getLayerMountPath(&stdDriverInfo, path, &mountPathLength, nil)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
err = makeErrorf(err, title, "(first call) id=%s flavour=%d", id, info.Flavour)
|
err = hcserror.Errorf(err, title, "(first call) path=%s", path)
|
||||||
logrus.Error(err)
|
logrus.Error(err)
|
||||||
return "", err
|
return "", err
|
||||||
}
|
}
|
||||||
|
@ -42,14 +36,14 @@ func GetLayerMountPath(info DriverInfo, id string) (string, error) {
|
||||||
|
|
||||||
// Call the procedure again
|
// Call the procedure again
|
||||||
logrus.Debugf("Calling proc (2)")
|
logrus.Debugf("Calling proc (2)")
|
||||||
err = getLayerMountPath(&infop, id, &mountPathLength, &mountPathp[0])
|
err = getLayerMountPath(&stdDriverInfo, path, &mountPathLength, &mountPathp[0])
|
||||||
if err != nil {
|
if err != nil {
|
||||||
err = makeErrorf(err, title, "(second call) id=%s flavour=%d", id, info.Flavour)
|
err = hcserror.Errorf(err, title, "(second call) path=%s", path)
|
||||||
logrus.Error(err)
|
logrus.Error(err)
|
||||||
return "", err
|
return "", err
|
||||||
}
|
}
|
||||||
|
|
||||||
path := syscall.UTF16ToString(mountPathp[0:])
|
mountPath := syscall.UTF16ToString(mountPathp[0:])
|
||||||
logrus.Debugf(title+"succeeded flavour=%d id=%s path=%s", info.Flavour, id, path)
|
logrus.Debugf(title+"succeeded path=%s mountPath=%s", path, mountPath)
|
||||||
return path, nil
|
return mountPath, nil
|
||||||
}
|
}
|
|
@ -1,6 +1,10 @@
|
||||||
package hcsshim
|
package wclayer
|
||||||
|
|
||||||
import "github.com/sirupsen/logrus"
|
import (
|
||||||
|
"github.com/Microsoft/hcsshim/internal/hcserror"
|
||||||
|
"github.com/Microsoft/hcsshim/internal/interop"
|
||||||
|
"github.com/sirupsen/logrus"
|
||||||
|
)
|
||||||
|
|
||||||
// GetSharedBaseImages will enumerate the images stored in the common central
|
// GetSharedBaseImages will enumerate the images stored in the common central
|
||||||
// image store and return descriptive info about those images for the purpose
|
// image store and return descriptive info about those images for the purpose
|
||||||
|
@ -12,11 +16,11 @@ func GetSharedBaseImages() (imageData string, err error) {
|
||||||
var buffer *uint16
|
var buffer *uint16
|
||||||
err = getBaseImages(&buffer)
|
err = getBaseImages(&buffer)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
err = makeError(err, title, "")
|
err = hcserror.New(err, title, "")
|
||||||
logrus.Error(err)
|
logrus.Error(err)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
imageData = convertAndFreeCoTaskMemString(buffer)
|
imageData = interop.ConvertAndFreeCoTaskMemString(buffer)
|
||||||
logrus.Debugf(title+" - succeeded output=%s", imageData)
|
logrus.Debugf(title+" - succeeded output=%s", imageData)
|
||||||
return
|
return
|
||||||
}
|
}
|
24
vendor/github.com/Microsoft/hcsshim/internal/wclayer/grantvmaccess.go
generated
vendored
Normal file
24
vendor/github.com/Microsoft/hcsshim/internal/wclayer/grantvmaccess.go
generated
vendored
Normal file
|
@ -0,0 +1,24 @@
|
||||||
|
package wclayer
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
|
||||||
|
"github.com/Microsoft/hcsshim/internal/hcserror"
|
||||||
|
"github.com/sirupsen/logrus"
|
||||||
|
)
|
||||||
|
|
||||||
|
// GrantVmAccess adds access to a file for a given VM
|
||||||
|
func GrantVmAccess(vmid string, filepath string) error {
|
||||||
|
title := fmt.Sprintf("hcsshim::GrantVmAccess id:%s path:%s ", vmid, filepath)
|
||||||
|
logrus.Debugf(title)
|
||||||
|
|
||||||
|
err := grantVmAccess(vmid, filepath)
|
||||||
|
if err != nil {
|
||||||
|
err = hcserror.Errorf(err, title, "path=%s", filepath)
|
||||||
|
logrus.Error(err)
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
logrus.Debugf(title + " - succeeded")
|
||||||
|
return nil
|
||||||
|
}
|
|
@ -1,4 +1,4 @@
|
||||||
package hcsshim
|
package wclayer
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"errors"
|
"errors"
|
||||||
|
@ -7,6 +7,8 @@ import (
|
||||||
"path/filepath"
|
"path/filepath"
|
||||||
|
|
||||||
"github.com/Microsoft/go-winio"
|
"github.com/Microsoft/go-winio"
|
||||||
|
"github.com/Microsoft/hcsshim/internal/hcserror"
|
||||||
|
"github.com/Microsoft/hcsshim/internal/safefile"
|
||||||
"github.com/sirupsen/logrus"
|
"github.com/sirupsen/logrus"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@ -14,9 +16,9 @@ import (
|
||||||
// that into a layer with the id layerId. Note that in order to correctly populate
|
// that into a layer with the id layerId. Note that in order to correctly populate
|
||||||
// the layer and interperet the transport format, all parent layers must already
|
// the layer and interperet the transport format, all parent layers must already
|
||||||
// be present on the system at the paths provided in parentLayerPaths.
|
// be present on the system at the paths provided in parentLayerPaths.
|
||||||
func ImportLayer(info DriverInfo, layerID string, importFolderPath string, parentLayerPaths []string) error {
|
func ImportLayer(path string, importFolderPath string, parentLayerPaths []string) error {
|
||||||
title := "hcsshim::ImportLayer "
|
title := "hcsshim::ImportLayer "
|
||||||
logrus.Debugf(title+"flavour %d layerId %s folder %s", info.Flavour, layerID, importFolderPath)
|
logrus.Debugf(title+"path %s folder %s", path, importFolderPath)
|
||||||
|
|
||||||
// Generate layer descriptors
|
// Generate layer descriptors
|
||||||
layers, err := layerPathsToDescriptors(parentLayerPaths)
|
layers, err := layerPathsToDescriptors(parentLayerPaths)
|
||||||
|
@ -24,21 +26,14 @@ func ImportLayer(info DriverInfo, layerID string, importFolderPath string, paren
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
// Convert info to API calling convention
|
err = importLayer(&stdDriverInfo, path, importFolderPath, layers)
|
||||||
infop, err := convertDriverInfo(info)
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
err = hcserror.Errorf(err, title, "path=%s folder=%s", path, importFolderPath)
|
||||||
logrus.Error(err)
|
logrus.Error(err)
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
err = importLayer(&infop, layerID, importFolderPath, layers)
|
logrus.Debugf(title+"succeeded path=%s folder=%s", path, importFolderPath)
|
||||||
if err != nil {
|
|
||||||
err = makeErrorf(err, title, "layerId=%s flavour=%d folder=%s", layerID, info.Flavour, importFolderPath)
|
|
||||||
logrus.Error(err)
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
logrus.Debugf(title+"succeeded flavour=%d layerId=%s folder=%s", info.Flavour, layerID, importFolderPath)
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -73,7 +68,7 @@ func (w *FilterLayerWriter) Add(name string, fileInfo *winio.FileBasicInfo) erro
|
||||||
}
|
}
|
||||||
err := importLayerNext(w.context, name, fileInfo)
|
err := importLayerNext(w.context, name, fileInfo)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return makeError(err, "ImportLayerNext", "")
|
return hcserror.New(err, "ImportLayerNext", "")
|
||||||
}
|
}
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
@ -92,7 +87,7 @@ func (w *FilterLayerWriter) Remove(name string) error {
|
||||||
}
|
}
|
||||||
err := importLayerNext(w.context, name, nil)
|
err := importLayerNext(w.context, name, nil)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return makeError(err, "ImportLayerNext", "")
|
return hcserror.New(err, "ImportLayerNext", "")
|
||||||
}
|
}
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
@ -101,7 +96,7 @@ func (w *FilterLayerWriter) Remove(name string) error {
|
||||||
func (w *FilterLayerWriter) Write(b []byte) (int, error) {
|
func (w *FilterLayerWriter) Write(b []byte) (int, error) {
|
||||||
err := importLayerWrite(w.context, b)
|
err := importLayerWrite(w.context, b)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
err = makeError(err, "ImportLayerWrite", "")
|
err = hcserror.New(err, "ImportLayerWrite", "")
|
||||||
return 0, err
|
return 0, err
|
||||||
}
|
}
|
||||||
return len(b), err
|
return len(b), err
|
||||||
|
@ -113,7 +108,7 @@ func (w *FilterLayerWriter) Close() (err error) {
|
||||||
if w.context != 0 {
|
if w.context != 0 {
|
||||||
err = importLayerEnd(w.context)
|
err = importLayerEnd(w.context)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
err = makeError(err, "ImportLayerEnd", "")
|
err = hcserror.New(err, "ImportLayerEnd", "")
|
||||||
}
|
}
|
||||||
w.context = 0
|
w.context = 0
|
||||||
}
|
}
|
||||||
|
@ -122,8 +117,6 @@ func (w *FilterLayerWriter) Close() (err error) {
|
||||||
|
|
||||||
type legacyLayerWriterWrapper struct {
|
type legacyLayerWriterWrapper struct {
|
||||||
*legacyLayerWriter
|
*legacyLayerWriter
|
||||||
info DriverInfo
|
|
||||||
layerID string
|
|
||||||
path string
|
path string
|
||||||
parentLayerPaths []string
|
parentLayerPaths []string
|
||||||
}
|
}
|
||||||
|
@ -136,28 +129,26 @@ func (r *legacyLayerWriterWrapper) Close() error {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
info := r.info
|
if err = ImportLayer(r.destRoot.Name(), r.path, r.parentLayerPaths); err != nil {
|
||||||
info.HomeDir = ""
|
|
||||||
if err = ImportLayer(info, r.destRoot.Name(), r.path, r.parentLayerPaths); err != nil {
|
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
for _, name := range r.Tombstones {
|
for _, name := range r.Tombstones {
|
||||||
if err = removeRelative(name, r.destRoot); err != nil && !os.IsNotExist(err) {
|
if err = safefile.RemoveRelative(name, r.destRoot); err != nil && !os.IsNotExist(err) {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// Add any hard links that were collected.
|
// Add any hard links that were collected.
|
||||||
for _, lnk := range r.PendingLinks {
|
for _, lnk := range r.PendingLinks {
|
||||||
if err = removeRelative(lnk.Path, r.destRoot); err != nil && !os.IsNotExist(err) {
|
if err = safefile.RemoveRelative(lnk.Path, r.destRoot); err != nil && !os.IsNotExist(err) {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
if err = linkRelative(lnk.Target, lnk.TargetRoot, lnk.Path, r.destRoot); err != nil {
|
if err = safefile.LinkRelative(lnk.Target, lnk.TargetRoot, lnk.Path, r.destRoot); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// Prepare the utility VM for use if one is present in the layer.
|
// Prepare the utility VM for use if one is present in the layer.
|
||||||
if r.HasUtilityVM {
|
if r.HasUtilityVM {
|
||||||
err := ensureNotReparsePointRelative("UtilityVM", r.destRoot)
|
err := safefile.EnsureNotReparsePointRelative("UtilityVM", r.destRoot)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
@ -172,10 +163,10 @@ func (r *legacyLayerWriterWrapper) Close() error {
|
||||||
// NewLayerWriter returns a new layer writer for creating a layer on disk.
|
// NewLayerWriter returns a new layer writer for creating a layer on disk.
|
||||||
// The caller must have taken the SeBackupPrivilege and SeRestorePrivilege privileges
|
// The caller must have taken the SeBackupPrivilege and SeRestorePrivilege privileges
|
||||||
// to call this and any methods on the resulting LayerWriter.
|
// to call this and any methods on the resulting LayerWriter.
|
||||||
func NewLayerWriter(info DriverInfo, layerID string, parentLayerPaths []string) (LayerWriter, error) {
|
func NewLayerWriter(path string, parentLayerPaths []string) (LayerWriter, error) {
|
||||||
if len(parentLayerPaths) == 0 {
|
if len(parentLayerPaths) == 0 {
|
||||||
// This is a base layer. It gets imported differently.
|
// This is a base layer. It gets imported differently.
|
||||||
f, err := openRoot(filepath.Join(info.HomeDir, layerID))
|
f, err := safefile.OpenRoot(path)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
@ -187,19 +178,17 @@ func NewLayerWriter(info DriverInfo, layerID string, parentLayerPaths []string)
|
||||||
if procImportLayerBegin.Find() != nil {
|
if procImportLayerBegin.Find() != nil {
|
||||||
// The new layer reader is not available on this Windows build. Fall back to the
|
// The new layer reader is not available on this Windows build. Fall back to the
|
||||||
// legacy export code path.
|
// legacy export code path.
|
||||||
path, err := ioutil.TempDir("", "hcs")
|
importPath, err := ioutil.TempDir("", "hcs")
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
w, err := newLegacyLayerWriter(path, parentLayerPaths, filepath.Join(info.HomeDir, layerID))
|
w, err := newLegacyLayerWriter(importPath, parentLayerPaths, path)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
return &legacyLayerWriterWrapper{
|
return &legacyLayerWriterWrapper{
|
||||||
legacyLayerWriter: w,
|
legacyLayerWriter: w,
|
||||||
info: info,
|
path: importPath,
|
||||||
layerID: layerID,
|
|
||||||
path: path,
|
|
||||||
parentLayerPaths: parentLayerPaths,
|
parentLayerPaths: parentLayerPaths,
|
||||||
}, nil
|
}, nil
|
||||||
}
|
}
|
||||||
|
@ -208,15 +197,10 @@ func NewLayerWriter(info DriverInfo, layerID string, parentLayerPaths []string)
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
infop, err := convertDriverInfo(info)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
w := &FilterLayerWriter{}
|
w := &FilterLayerWriter{}
|
||||||
err = importLayerBegin(&infop, layerID, layers, &w.context)
|
err = importLayerBegin(&stdDriverInfo, path, layers, &w.context)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, makeError(err, "ImportLayerStart", "")
|
return nil, hcserror.New(err, "ImportLayerStart", "")
|
||||||
}
|
}
|
||||||
return w, nil
|
return w, nil
|
||||||
}
|
}
|
25
vendor/github.com/Microsoft/hcsshim/internal/wclayer/layerexists.go
generated
vendored
Normal file
25
vendor/github.com/Microsoft/hcsshim/internal/wclayer/layerexists.go
generated
vendored
Normal file
|
@ -0,0 +1,25 @@
|
||||||
|
package wclayer
|
||||||
|
|
||||||
|
import (
|
||||||
|
"github.com/Microsoft/hcsshim/internal/hcserror"
|
||||||
|
"github.com/sirupsen/logrus"
|
||||||
|
)
|
||||||
|
|
||||||
|
// LayerExists will return true if a layer with the given id exists and is known
|
||||||
|
// to the system.
|
||||||
|
func LayerExists(path string) (bool, error) {
|
||||||
|
title := "hcsshim::LayerExists "
|
||||||
|
logrus.Debugf(title+"path %s", path)
|
||||||
|
|
||||||
|
// Call the procedure itself.
|
||||||
|
var exists uint32
|
||||||
|
err := layerExists(&stdDriverInfo, path, &exists)
|
||||||
|
if err != nil {
|
||||||
|
err = hcserror.Errorf(err, title, "path=%s", path)
|
||||||
|
logrus.Error(err)
|
||||||
|
return false, err
|
||||||
|
}
|
||||||
|
|
||||||
|
logrus.Debugf(title+"succeeded path=%s exists=%d", path, exists)
|
||||||
|
return exists != 0, nil
|
||||||
|
}
|
|
@ -0,0 +1,13 @@
|
||||||
|
package wclayer
|
||||||
|
|
||||||
|
import (
|
||||||
|
"path/filepath"
|
||||||
|
|
||||||
|
"github.com/Microsoft/hcsshim/internal/guid"
|
||||||
|
)
|
||||||
|
|
||||||
|
// LayerID returns the layer ID of a layer on disk.
|
||||||
|
func LayerID(path string) (guid.GUID, error) {
|
||||||
|
_, file := filepath.Split(path)
|
||||||
|
return NameToGuid(file)
|
||||||
|
}
|
|
@ -1,12 +1,12 @@
|
||||||
package hcsshim
|
package wclayer
|
||||||
|
|
||||||
// This file contains utility functions to support storage (graph) related
|
// This file contains utility functions to support storage (graph) related
|
||||||
// functionality.
|
// functionality.
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"path/filepath"
|
|
||||||
"syscall"
|
"syscall"
|
||||||
|
|
||||||
|
"github.com/Microsoft/hcsshim/internal/guid"
|
||||||
"github.com/sirupsen/logrus"
|
"github.com/sirupsen/logrus"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@ -22,28 +22,16 @@ struct DriverInfo {
|
||||||
LPCWSTR HomeDir;
|
LPCWSTR HomeDir;
|
||||||
};
|
};
|
||||||
*/
|
*/
|
||||||
type DriverInfo struct {
|
|
||||||
Flavour int
|
|
||||||
HomeDir string
|
|
||||||
}
|
|
||||||
|
|
||||||
type driverInfo struct {
|
type driverInfo struct {
|
||||||
Flavour int
|
Flavour int
|
||||||
HomeDirp *uint16
|
HomeDirp *uint16
|
||||||
}
|
}
|
||||||
|
|
||||||
func convertDriverInfo(info DriverInfo) (driverInfo, error) {
|
var (
|
||||||
homedirp, err := syscall.UTF16PtrFromString(info.HomeDir)
|
utf16EmptyString uint16
|
||||||
if err != nil {
|
stdDriverInfo = driverInfo{1, &utf16EmptyString}
|
||||||
logrus.Debugf("Failed conversion of home to pointer for driver info: %s", err.Error())
|
)
|
||||||
return driverInfo{}, err
|
|
||||||
}
|
|
||||||
|
|
||||||
return driverInfo{
|
|
||||||
Flavour: info.Flavour,
|
|
||||||
HomeDirp: homedirp,
|
|
||||||
}, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
/* To pass into syscall, we need a struct matching the following:
|
/* To pass into syscall, we need a struct matching the following:
|
||||||
typedef struct _WC_LAYER_DESCRIPTOR {
|
typedef struct _WC_LAYER_DESCRIPTOR {
|
||||||
|
@ -75,7 +63,7 @@ typedef struct _WC_LAYER_DESCRIPTOR {
|
||||||
} WC_LAYER_DESCRIPTOR, *PWC_LAYER_DESCRIPTOR;
|
} WC_LAYER_DESCRIPTOR, *PWC_LAYER_DESCRIPTOR;
|
||||||
*/
|
*/
|
||||||
type WC_LAYER_DESCRIPTOR struct {
|
type WC_LAYER_DESCRIPTOR struct {
|
||||||
LayerId GUID
|
LayerId guid.GUID
|
||||||
Flags uint32
|
Flags uint32
|
||||||
Pathp *uint16
|
Pathp *uint16
|
||||||
}
|
}
|
||||||
|
@ -85,10 +73,7 @@ func layerPathsToDescriptors(parentLayerPaths []string) ([]WC_LAYER_DESCRIPTOR,
|
||||||
var layers []WC_LAYER_DESCRIPTOR
|
var layers []WC_LAYER_DESCRIPTOR
|
||||||
|
|
||||||
for i := 0; i < len(parentLayerPaths); i++ {
|
for i := 0; i < len(parentLayerPaths); i++ {
|
||||||
// Create a layer descriptor, using the folder name
|
g, err := LayerID(parentLayerPaths[i])
|
||||||
// as the source for a GUID LayerId
|
|
||||||
_, folderName := filepath.Split(parentLayerPaths[i])
|
|
||||||
g, err := NameToGuid(folderName)
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
logrus.Debugf("Failed to convert name to guid %s", err)
|
logrus.Debugf("Failed to convert name to guid %s", err)
|
||||||
return nil, err
|
return nil, err
|
|
@ -1,4 +1,4 @@
|
||||||
package hcsshim
|
package wclayer
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"bufio"
|
"bufio"
|
||||||
|
@ -6,12 +6,15 @@ import (
|
||||||
"errors"
|
"errors"
|
||||||
"fmt"
|
"fmt"
|
||||||
"io"
|
"io"
|
||||||
|
"io/ioutil"
|
||||||
"os"
|
"os"
|
||||||
"path/filepath"
|
"path/filepath"
|
||||||
"strings"
|
"strings"
|
||||||
"syscall"
|
"syscall"
|
||||||
|
|
||||||
"github.com/Microsoft/go-winio"
|
"github.com/Microsoft/go-winio"
|
||||||
|
"github.com/Microsoft/hcsshim/internal/longpath"
|
||||||
|
"github.com/Microsoft/hcsshim/internal/safefile"
|
||||||
)
|
)
|
||||||
|
|
||||||
var errorIterationCanceled = errors.New("")
|
var errorIterationCanceled = errors.New("")
|
||||||
|
@ -34,23 +37,6 @@ func openFileOrDir(path string, mode uint32, createDisposition uint32) (file *os
|
||||||
return winio.OpenForBackup(path, mode, syscall.FILE_SHARE_READ, createDisposition)
|
return winio.OpenForBackup(path, mode, syscall.FILE_SHARE_READ, createDisposition)
|
||||||
}
|
}
|
||||||
|
|
||||||
func makeLongAbsPath(path string) (string, error) {
|
|
||||||
if strings.HasPrefix(path, `\\?\`) || strings.HasPrefix(path, `\\.\`) {
|
|
||||||
return path, nil
|
|
||||||
}
|
|
||||||
if !filepath.IsAbs(path) {
|
|
||||||
absPath, err := filepath.Abs(path)
|
|
||||||
if err != nil {
|
|
||||||
return "", err
|
|
||||||
}
|
|
||||||
path = absPath
|
|
||||||
}
|
|
||||||
if strings.HasPrefix(path, `\\`) {
|
|
||||||
return `\\?\UNC\` + path[2:], nil
|
|
||||||
}
|
|
||||||
return `\\?\` + path, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func hasPathPrefix(p, prefix string) bool {
|
func hasPathPrefix(p, prefix string) bool {
|
||||||
return strings.HasPrefix(p, prefix) && len(p) > len(prefix) && p[len(prefix)] == '\\'
|
return strings.HasPrefix(p, prefix) && len(p) > len(prefix) && p[len(prefix)] == '\\'
|
||||||
}
|
}
|
||||||
|
@ -106,7 +92,7 @@ func readTombstones(path string) (map[string]([]string), error) {
|
||||||
}
|
}
|
||||||
|
|
||||||
func (r *legacyLayerReader) walkUntilCancelled() error {
|
func (r *legacyLayerReader) walkUntilCancelled() error {
|
||||||
root, err := makeLongAbsPath(r.root)
|
root, err := longpath.LongAbs(r.root)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
@ -283,7 +269,7 @@ func (r *legacyLayerReader) Next() (path string, size int64, fileInfo *winio.Fil
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
fileInfo.FileAttributes = uintptr(attr)
|
fileInfo.FileAttributes = attr
|
||||||
beginning := int64(4)
|
beginning := int64(4)
|
||||||
|
|
||||||
// Find the accurate file size.
|
// Find the accurate file size.
|
||||||
|
@ -349,6 +335,7 @@ type legacyLayerWriter struct {
|
||||||
destRoot *os.File
|
destRoot *os.File
|
||||||
parentRoots []*os.File
|
parentRoots []*os.File
|
||||||
currentFile *os.File
|
currentFile *os.File
|
||||||
|
bufWriter *bufio.Writer
|
||||||
currentFileName string
|
currentFileName string
|
||||||
currentFileRoot *os.File
|
currentFileRoot *os.File
|
||||||
backupWriter *winio.BackupFileWriter
|
backupWriter *winio.BackupFileWriter
|
||||||
|
@ -373,21 +360,22 @@ func newLegacyLayerWriter(root string, parentRoots []string, destRoot string) (w
|
||||||
w = nil
|
w = nil
|
||||||
}
|
}
|
||||||
}()
|
}()
|
||||||
w.root, err = openRoot(root)
|
w.root, err = safefile.OpenRoot(root)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
w.destRoot, err = openRoot(destRoot)
|
w.destRoot, err = safefile.OpenRoot(destRoot)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
for _, r := range parentRoots {
|
for _, r := range parentRoots {
|
||||||
f, err := openRoot(r)
|
f, err := safefile.OpenRoot(r)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return w, err
|
return w, err
|
||||||
}
|
}
|
||||||
w.parentRoots = append(w.parentRoots, f)
|
w.parentRoots = append(w.parentRoots, f)
|
||||||
}
|
}
|
||||||
|
w.bufWriter = bufio.NewWriterSize(ioutil.Discard, 65536)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -408,7 +396,7 @@ func (w *legacyLayerWriter) CloseRoots() {
|
||||||
|
|
||||||
func (w *legacyLayerWriter) initUtilityVM() error {
|
func (w *legacyLayerWriter) initUtilityVM() error {
|
||||||
if !w.HasUtilityVM {
|
if !w.HasUtilityVM {
|
||||||
err := mkdirRelative(utilityVMPath, w.destRoot)
|
err := safefile.MkdirRelative(utilityVMPath, w.destRoot)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
@ -426,6 +414,11 @@ func (w *legacyLayerWriter) initUtilityVM() error {
|
||||||
}
|
}
|
||||||
|
|
||||||
func (w *legacyLayerWriter) reset() error {
|
func (w *legacyLayerWriter) reset() error {
|
||||||
|
err := w.bufWriter.Flush()
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
w.bufWriter.Reset(ioutil.Discard)
|
||||||
if w.currentIsDir {
|
if w.currentIsDir {
|
||||||
r := w.currentFile
|
r := w.currentFile
|
||||||
br := winio.NewBackupStreamReader(r)
|
br := winio.NewBackupStreamReader(r)
|
||||||
|
@ -449,7 +442,7 @@ func (w *legacyLayerWriter) reset() error {
|
||||||
// describes a directory reparse point. Delete the placeholder
|
// describes a directory reparse point. Delete the placeholder
|
||||||
// directory to prevent future files being added into the
|
// directory to prevent future files being added into the
|
||||||
// destination of the reparse point during the ImportLayer call
|
// destination of the reparse point during the ImportLayer call
|
||||||
if err := removeRelative(w.currentFileName, w.currentFileRoot); err != nil {
|
if err := safefile.RemoveRelative(w.currentFileName, w.currentFileRoot); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
w.pendingDirs = append(w.pendingDirs, pendingDir{Path: w.currentFileName, Root: w.currentFileRoot})
|
w.pendingDirs = append(w.pendingDirs, pendingDir{Path: w.currentFileName, Root: w.currentFileRoot})
|
||||||
|
@ -474,13 +467,13 @@ func (w *legacyLayerWriter) reset() error {
|
||||||
|
|
||||||
// copyFileWithMetadata copies a file using the backup/restore APIs in order to preserve metadata
|
// copyFileWithMetadata copies a file using the backup/restore APIs in order to preserve metadata
|
||||||
func copyFileWithMetadata(srcRoot, destRoot *os.File, subPath string, isDir bool) (fileInfo *winio.FileBasicInfo, err error) {
|
func copyFileWithMetadata(srcRoot, destRoot *os.File, subPath string, isDir bool) (fileInfo *winio.FileBasicInfo, err error) {
|
||||||
src, err := openRelative(
|
src, err := safefile.OpenRelative(
|
||||||
subPath,
|
subPath,
|
||||||
srcRoot,
|
srcRoot,
|
||||||
syscall.GENERIC_READ|winio.ACCESS_SYSTEM_SECURITY,
|
syscall.GENERIC_READ|winio.ACCESS_SYSTEM_SECURITY,
|
||||||
syscall.FILE_SHARE_READ,
|
syscall.FILE_SHARE_READ,
|
||||||
_FILE_OPEN,
|
safefile.FILE_OPEN,
|
||||||
_FILE_OPEN_REPARSE_POINT)
|
safefile.FILE_OPEN_REPARSE_POINT)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
@ -495,14 +488,14 @@ func copyFileWithMetadata(srcRoot, destRoot *os.File, subPath string, isDir bool
|
||||||
|
|
||||||
extraFlags := uint32(0)
|
extraFlags := uint32(0)
|
||||||
if isDir {
|
if isDir {
|
||||||
extraFlags |= _FILE_DIRECTORY_FILE
|
extraFlags |= safefile.FILE_DIRECTORY_FILE
|
||||||
}
|
}
|
||||||
dest, err := openRelative(
|
dest, err := safefile.OpenRelative(
|
||||||
subPath,
|
subPath,
|
||||||
destRoot,
|
destRoot,
|
||||||
syscall.GENERIC_READ|syscall.GENERIC_WRITE|winio.WRITE_DAC|winio.WRITE_OWNER|winio.ACCESS_SYSTEM_SECURITY,
|
syscall.GENERIC_READ|syscall.GENERIC_WRITE|winio.WRITE_DAC|winio.WRITE_OWNER|winio.ACCESS_SYSTEM_SECURITY,
|
||||||
syscall.FILE_SHARE_READ,
|
syscall.FILE_SHARE_READ,
|
||||||
_FILE_CREATE,
|
safefile.FILE_CREATE,
|
||||||
extraFlags)
|
extraFlags)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
|
@ -534,7 +527,7 @@ func copyFileWithMetadata(srcRoot, destRoot *os.File, subPath string, isDir bool
|
||||||
// the file names in the provided map and just copies those files.
|
// the file names in the provided map and just copies those files.
|
||||||
func cloneTree(srcRoot *os.File, destRoot *os.File, subPath string, mutatedFiles map[string]bool) error {
|
func cloneTree(srcRoot *os.File, destRoot *os.File, subPath string, mutatedFiles map[string]bool) error {
|
||||||
var di []dirInfo
|
var di []dirInfo
|
||||||
err := ensureNotReparsePointRelative(subPath, srcRoot)
|
err := safefile.EnsureNotReparsePointRelative(subPath, srcRoot)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
@ -566,18 +559,12 @@ func cloneTree(srcRoot *os.File, destRoot *os.File, subPath string, mutatedFiles
|
||||||
di = append(di, dirInfo{path: relPath, fileInfo: *fi})
|
di = append(di, dirInfo{path: relPath, fileInfo: *fi})
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
err = linkRelative(relPath, srcRoot, relPath, destRoot)
|
err = safefile.LinkRelative(relPath, srcRoot, relPath, destRoot)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Don't recurse on reparse points in go1.8 and older. Filepath.Walk
|
|
||||||
// handles this in go1.9 and newer.
|
|
||||||
if isDir && isReparsePoint && shouldSkipDirectoryReparse {
|
|
||||||
return filepath.SkipDir
|
|
||||||
}
|
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
})
|
})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
@ -604,9 +591,9 @@ func (w *legacyLayerWriter) Add(name string, fileInfo *winio.FileBasicInfo) erro
|
||||||
if !hasPathPrefix(name, utilityVMFilesPath) && name != utilityVMFilesPath {
|
if !hasPathPrefix(name, utilityVMFilesPath) && name != utilityVMFilesPath {
|
||||||
return errors.New("invalid UtilityVM layer")
|
return errors.New("invalid UtilityVM layer")
|
||||||
}
|
}
|
||||||
createDisposition := uint32(_FILE_OPEN)
|
createDisposition := uint32(safefile.FILE_OPEN)
|
||||||
if (fileInfo.FileAttributes & syscall.FILE_ATTRIBUTE_DIRECTORY) != 0 {
|
if (fileInfo.FileAttributes & syscall.FILE_ATTRIBUTE_DIRECTORY) != 0 {
|
||||||
st, err := lstatRelative(name, w.destRoot)
|
st, err := safefile.LstatRelative(name, w.destRoot)
|
||||||
if err != nil && !os.IsNotExist(err) {
|
if err != nil && !os.IsNotExist(err) {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
@ -614,14 +601,14 @@ 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.
|
// Delete the existing file/directory if it is not the same type as this directory.
|
||||||
existingAttr := st.Sys().(*syscall.Win32FileAttributeData).FileAttributes
|
existingAttr := st.Sys().(*syscall.Win32FileAttributeData).FileAttributes
|
||||||
if (uint32(fileInfo.FileAttributes)^existingAttr)&(syscall.FILE_ATTRIBUTE_DIRECTORY|syscall.FILE_ATTRIBUTE_REPARSE_POINT) != 0 {
|
if (uint32(fileInfo.FileAttributes)^existingAttr)&(syscall.FILE_ATTRIBUTE_DIRECTORY|syscall.FILE_ATTRIBUTE_REPARSE_POINT) != 0 {
|
||||||
if err = removeAllRelative(name, w.destRoot); err != nil {
|
if err = safefile.RemoveAllRelative(name, w.destRoot); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
st = nil
|
st = nil
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if st == nil {
|
if st == nil {
|
||||||
if err = mkdirRelative(name, w.destRoot); err != nil {
|
if err = safefile.MkdirRelative(name, w.destRoot); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -630,20 +617,20 @@ func (w *legacyLayerWriter) Add(name string, fileInfo *winio.FileBasicInfo) erro
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
// Overwrite any existing hard link.
|
// Overwrite any existing hard link.
|
||||||
err := removeRelative(name, w.destRoot)
|
err := safefile.RemoveRelative(name, w.destRoot)
|
||||||
if err != nil && !os.IsNotExist(err) {
|
if err != nil && !os.IsNotExist(err) {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
createDisposition = _FILE_CREATE
|
createDisposition = safefile.FILE_CREATE
|
||||||
}
|
}
|
||||||
|
|
||||||
f, err := openRelative(
|
f, err := safefile.OpenRelative(
|
||||||
name,
|
name,
|
||||||
w.destRoot,
|
w.destRoot,
|
||||||
syscall.GENERIC_READ|syscall.GENERIC_WRITE|winio.WRITE_DAC|winio.WRITE_OWNER|winio.ACCESS_SYSTEM_SECURITY,
|
syscall.GENERIC_READ|syscall.GENERIC_WRITE|winio.WRITE_DAC|winio.WRITE_OWNER|winio.ACCESS_SYSTEM_SECURITY,
|
||||||
syscall.FILE_SHARE_READ,
|
syscall.FILE_SHARE_READ,
|
||||||
createDisposition,
|
createDisposition,
|
||||||
_FILE_OPEN_REPARSE_POINT,
|
safefile.FILE_OPEN_REPARSE_POINT,
|
||||||
)
|
)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
|
@ -651,7 +638,7 @@ func (w *legacyLayerWriter) Add(name string, fileInfo *winio.FileBasicInfo) erro
|
||||||
defer func() {
|
defer func() {
|
||||||
if f != nil {
|
if f != nil {
|
||||||
f.Close()
|
f.Close()
|
||||||
removeRelative(name, w.destRoot)
|
safefile.RemoveRelative(name, w.destRoot)
|
||||||
}
|
}
|
||||||
}()
|
}()
|
||||||
|
|
||||||
|
@ -661,6 +648,7 @@ func (w *legacyLayerWriter) Add(name string, fileInfo *winio.FileBasicInfo) erro
|
||||||
}
|
}
|
||||||
|
|
||||||
w.backupWriter = winio.NewBackupFileWriter(f, true)
|
w.backupWriter = winio.NewBackupFileWriter(f, true)
|
||||||
|
w.bufWriter.Reset(w.backupWriter)
|
||||||
w.currentFile = f
|
w.currentFile = f
|
||||||
w.currentFileName = name
|
w.currentFileName = name
|
||||||
w.currentFileRoot = w.destRoot
|
w.currentFileRoot = w.destRoot
|
||||||
|
@ -671,7 +659,7 @@ func (w *legacyLayerWriter) Add(name string, fileInfo *winio.FileBasicInfo) erro
|
||||||
|
|
||||||
fname := name
|
fname := name
|
||||||
if (fileInfo.FileAttributes & syscall.FILE_ATTRIBUTE_DIRECTORY) != 0 {
|
if (fileInfo.FileAttributes & syscall.FILE_ATTRIBUTE_DIRECTORY) != 0 {
|
||||||
err := mkdirRelative(name, w.root)
|
err := safefile.MkdirRelative(name, w.root)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
@ -679,14 +667,14 @@ func (w *legacyLayerWriter) Add(name string, fileInfo *winio.FileBasicInfo) erro
|
||||||
w.currentIsDir = true
|
w.currentIsDir = true
|
||||||
}
|
}
|
||||||
|
|
||||||
f, err := openRelative(fname, w.root, syscall.GENERIC_READ|syscall.GENERIC_WRITE, syscall.FILE_SHARE_READ, _FILE_CREATE, 0)
|
f, err := safefile.OpenRelative(fname, w.root, syscall.GENERIC_READ|syscall.GENERIC_WRITE, syscall.FILE_SHARE_READ, safefile.FILE_CREATE, 0)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
defer func() {
|
defer func() {
|
||||||
if f != nil {
|
if f != nil {
|
||||||
f.Close()
|
f.Close()
|
||||||
removeRelative(fname, w.root)
|
safefile.RemoveRelative(fname, w.root)
|
||||||
}
|
}
|
||||||
}()
|
}()
|
||||||
|
|
||||||
|
@ -699,10 +687,13 @@ func (w *legacyLayerWriter) Add(name string, fileInfo *winio.FileBasicInfo) erro
|
||||||
|
|
||||||
if hasPathPrefix(name, hivesPath) {
|
if hasPathPrefix(name, hivesPath) {
|
||||||
w.backupWriter = winio.NewBackupFileWriter(f, false)
|
w.backupWriter = winio.NewBackupFileWriter(f, false)
|
||||||
|
w.bufWriter.Reset(w.backupWriter)
|
||||||
} else {
|
} else {
|
||||||
|
w.bufWriter.Reset(f)
|
||||||
// The file attributes are written before the stream.
|
// The file attributes are written before the stream.
|
||||||
err = binary.Write(f, binary.LittleEndian, uint32(fileInfo.FileAttributes))
|
err = binary.Write(w.bufWriter, binary.LittleEndian, uint32(fileInfo.FileAttributes))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
w.bufWriter.Reset(ioutil.Discard)
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -744,7 +735,7 @@ func (w *legacyLayerWriter) AddLink(name string, target string) error {
|
||||||
selectedRoot = w.destRoot
|
selectedRoot = w.destRoot
|
||||||
} else {
|
} else {
|
||||||
for _, r := range roots {
|
for _, r := range roots {
|
||||||
if _, err := lstatRelative(target, r); err != nil {
|
if _, err := safefile.LstatRelative(target, r); err != nil {
|
||||||
if !os.IsNotExist(err) {
|
if !os.IsNotExist(err) {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
@ -780,10 +771,10 @@ func (w *legacyLayerWriter) Remove(name string) error {
|
||||||
// Make sure the path exists; os.RemoveAll will not fail if the file is
|
// 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
|
// already gone, and this needs to be a fatal error for diagnostics
|
||||||
// purposes.
|
// purposes.
|
||||||
if _, err := lstatRelative(name, w.destRoot); err != nil {
|
if _, err := safefile.LstatRelative(name, w.destRoot); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
err = removeAllRelative(name, w.destRoot)
|
err = safefile.RemoveAllRelative(name, w.destRoot)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
@ -795,24 +786,21 @@ func (w *legacyLayerWriter) Remove(name string) error {
|
||||||
}
|
}
|
||||||
|
|
||||||
func (w *legacyLayerWriter) Write(b []byte) (int, error) {
|
func (w *legacyLayerWriter) Write(b []byte) (int, error) {
|
||||||
if w.backupWriter == nil {
|
if w.backupWriter == nil && w.currentFile == nil {
|
||||||
if w.currentFile == nil {
|
return 0, errors.New("closed")
|
||||||
return 0, errors.New("closed")
|
|
||||||
}
|
|
||||||
return w.currentFile.Write(b)
|
|
||||||
}
|
}
|
||||||
return w.backupWriter.Write(b)
|
return w.bufWriter.Write(b)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (w *legacyLayerWriter) Close() error {
|
func (w *legacyLayerWriter) Close() error {
|
||||||
if err := w.reset(); err != nil {
|
if err := w.reset(); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
if err := removeRelative("tombstones.txt", w.root); err != nil && !os.IsNotExist(err) {
|
if err := safefile.RemoveRelative("tombstones.txt", w.root); err != nil && !os.IsNotExist(err) {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
for _, pd := range w.pendingDirs {
|
for _, pd := range w.pendingDirs {
|
||||||
err := mkdirRelative(pd.Path, pd.Root)
|
err := safefile.MkdirRelative(pd.Path, pd.Root)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
24
vendor/github.com/Microsoft/hcsshim/internal/wclayer/nametoguid.go
generated
vendored
Normal file
24
vendor/github.com/Microsoft/hcsshim/internal/wclayer/nametoguid.go
generated
vendored
Normal file
|
@ -0,0 +1,24 @@
|
||||||
|
package wclayer
|
||||||
|
|
||||||
|
import (
|
||||||
|
"github.com/Microsoft/hcsshim/internal/guid"
|
||||||
|
"github.com/Microsoft/hcsshim/internal/hcserror"
|
||||||
|
"github.com/sirupsen/logrus"
|
||||||
|
)
|
||||||
|
|
||||||
|
// NameToGuid converts the given string into a GUID using the algorithm in the
|
||||||
|
// Host Compute Service, ensuring GUIDs generated with the same string are common
|
||||||
|
// across all clients.
|
||||||
|
func NameToGuid(name string) (id guid.GUID, err error) {
|
||||||
|
title := "hcsshim::NameToGuid "
|
||||||
|
|
||||||
|
err = nameToGuid(name, &id)
|
||||||
|
if err != nil {
|
||||||
|
err = hcserror.Errorf(err, title, "name=%s", name)
|
||||||
|
logrus.Error(err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
logrus.Debugf(title+"name:%s guid:%s", name, id.String())
|
||||||
|
return
|
||||||
|
}
|
|
@ -1,21 +1,22 @@
|
||||||
package hcsshim
|
package wclayer
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"sync"
|
"sync"
|
||||||
|
|
||||||
|
"github.com/Microsoft/hcsshim/internal/hcserror"
|
||||||
"github.com/sirupsen/logrus"
|
"github.com/sirupsen/logrus"
|
||||||
)
|
)
|
||||||
|
|
||||||
var prepareLayerLock sync.Mutex
|
var prepareLayerLock sync.Mutex
|
||||||
|
|
||||||
// PrepareLayer finds a mounted read-write layer matching layerId and enables the
|
// PrepareLayer finds a mounted read-write layer matching path and enables the
|
||||||
// the filesystem filter for use on that layer. This requires the paths to all
|
// the filesystem filter for use on that layer. This requires the paths to all
|
||||||
// parent layers, and is necessary in order to view or interact with the layer
|
// parent layers, and is necessary in order to view or interact with the layer
|
||||||
// as an actual filesystem (reading and writing files, creating directories, etc).
|
// as an actual filesystem (reading and writing files, creating directories, etc).
|
||||||
// Disabling the filter must be done via UnprepareLayer.
|
// Disabling the filter must be done via UnprepareLayer.
|
||||||
func PrepareLayer(info DriverInfo, layerId string, parentLayerPaths []string) error {
|
func PrepareLayer(path string, parentLayerPaths []string) error {
|
||||||
title := "hcsshim::PrepareLayer "
|
title := "hcsshim::PrepareLayer "
|
||||||
logrus.Debugf(title+"flavour %d layerId %s", info.Flavour, layerId)
|
logrus.Debugf(title+"path %s", path)
|
||||||
|
|
||||||
// Generate layer descriptors
|
// Generate layer descriptors
|
||||||
layers, err := layerPathsToDescriptors(parentLayerPaths)
|
layers, err := layerPathsToDescriptors(parentLayerPaths)
|
||||||
|
@ -23,24 +24,17 @@ func PrepareLayer(info DriverInfo, layerId string, parentLayerPaths []string) er
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
// Convert info to API calling convention
|
|
||||||
infop, err := convertDriverInfo(info)
|
|
||||||
if err != nil {
|
|
||||||
logrus.Error(err)
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
// This lock is a temporary workaround for a Windows bug. Only allowing one
|
// This lock is a temporary workaround for a Windows bug. Only allowing one
|
||||||
// call to prepareLayer at a time vastly reduces the chance of a timeout.
|
// call to prepareLayer at a time vastly reduces the chance of a timeout.
|
||||||
prepareLayerLock.Lock()
|
prepareLayerLock.Lock()
|
||||||
defer prepareLayerLock.Unlock()
|
defer prepareLayerLock.Unlock()
|
||||||
err = prepareLayer(&infop, layerId, layers)
|
err = prepareLayer(&stdDriverInfo, path, layers)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
err = makeErrorf(err, title, "layerId=%s flavour=%d", layerId, info.Flavour)
|
err = hcserror.Errorf(err, title, "path=%s", path)
|
||||||
logrus.Error(err)
|
logrus.Error(err)
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
logrus.Debugf(title+"succeeded flavour=%d layerId=%s", info.Flavour, layerId)
|
logrus.Debugf(title+"succeeded path=%s", path)
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
|
@ -1,4 +1,4 @@
|
||||||
package hcsshim
|
package wclayer
|
||||||
|
|
||||||
import "os"
|
import "os"
|
||||||
|
|
23
vendor/github.com/Microsoft/hcsshim/internal/wclayer/unpreparelayer.go
generated
vendored
Normal file
23
vendor/github.com/Microsoft/hcsshim/internal/wclayer/unpreparelayer.go
generated
vendored
Normal file
|
@ -0,0 +1,23 @@
|
||||||
|
package wclayer
|
||||||
|
|
||||||
|
import (
|
||||||
|
"github.com/Microsoft/hcsshim/internal/hcserror"
|
||||||
|
"github.com/sirupsen/logrus"
|
||||||
|
)
|
||||||
|
|
||||||
|
// UnprepareLayer disables the filesystem filter for the read-write layer with
|
||||||
|
// the given id.
|
||||||
|
func UnprepareLayer(path string) error {
|
||||||
|
title := "hcsshim::UnprepareLayer "
|
||||||
|
logrus.Debugf(title+"path %s", path)
|
||||||
|
|
||||||
|
err := unprepareLayer(&stdDriverInfo, path)
|
||||||
|
if err != nil {
|
||||||
|
err = hcserror.Errorf(err, title, "path=%s", path)
|
||||||
|
logrus.Error(err)
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
logrus.Debugf(title+"succeeded path=%s", path)
|
||||||
|
return nil
|
||||||
|
}
|
|
@ -0,0 +1,37 @@
|
||||||
|
package wclayer
|
||||||
|
|
||||||
|
import "github.com/Microsoft/hcsshim/internal/guid"
|
||||||
|
|
||||||
|
//go:generate go run ../../mksyscall_windows.go -output zsyscall_windows.go -winio wclayer.go
|
||||||
|
|
||||||
|
//sys activateLayer(info *driverInfo, id string) (hr error) = vmcompute.ActivateLayer?
|
||||||
|
//sys copyLayer(info *driverInfo, srcId string, dstId string, descriptors []WC_LAYER_DESCRIPTOR) (hr error) = vmcompute.CopyLayer?
|
||||||
|
//sys createLayer(info *driverInfo, id string, parent string) (hr error) = vmcompute.CreateLayer?
|
||||||
|
//sys createSandboxLayer(info *driverInfo, id string, parent uintptr, descriptors []WC_LAYER_DESCRIPTOR) (hr error) = vmcompute.CreateSandboxLayer?
|
||||||
|
//sys expandSandboxSize(info *driverInfo, id string, size uint64) (hr error) = vmcompute.ExpandSandboxSize?
|
||||||
|
//sys deactivateLayer(info *driverInfo, id string) (hr error) = vmcompute.DeactivateLayer?
|
||||||
|
//sys destroyLayer(info *driverInfo, id string) (hr error) = vmcompute.DestroyLayer?
|
||||||
|
//sys exportLayer(info *driverInfo, id string, path string, descriptors []WC_LAYER_DESCRIPTOR) (hr error) = vmcompute.ExportLayer?
|
||||||
|
//sys getLayerMountPath(info *driverInfo, id string, length *uintptr, buffer *uint16) (hr error) = vmcompute.GetLayerMountPath?
|
||||||
|
//sys getBaseImages(buffer **uint16) (hr error) = vmcompute.GetBaseImages?
|
||||||
|
//sys importLayer(info *driverInfo, id string, path string, descriptors []WC_LAYER_DESCRIPTOR) (hr error) = vmcompute.ImportLayer?
|
||||||
|
//sys layerExists(info *driverInfo, id string, exists *uint32) (hr error) = vmcompute.LayerExists?
|
||||||
|
//sys nameToGuid(name string, guid *_guid) (hr error) = vmcompute.NameToGuid?
|
||||||
|
//sys prepareLayer(info *driverInfo, id string, descriptors []WC_LAYER_DESCRIPTOR) (hr error) = vmcompute.PrepareLayer?
|
||||||
|
//sys unprepareLayer(info *driverInfo, id string) (hr error) = vmcompute.UnprepareLayer?
|
||||||
|
//sys processBaseImage(path string) (hr error) = vmcompute.ProcessBaseImage?
|
||||||
|
//sys processUtilityImage(path string) (hr error) = vmcompute.ProcessUtilityImage?
|
||||||
|
|
||||||
|
//sys importLayerBegin(info *driverInfo, id string, descriptors []WC_LAYER_DESCRIPTOR, context *uintptr) (hr error) = vmcompute.ImportLayerBegin?
|
||||||
|
//sys importLayerNext(context uintptr, fileName string, fileInfo *winio.FileBasicInfo) (hr error) = vmcompute.ImportLayerNext?
|
||||||
|
//sys importLayerWrite(context uintptr, buffer []byte) (hr error) = vmcompute.ImportLayerWrite?
|
||||||
|
//sys importLayerEnd(context uintptr) (hr error) = vmcompute.ImportLayerEnd?
|
||||||
|
|
||||||
|
//sys exportLayerBegin(info *driverInfo, id string, descriptors []WC_LAYER_DESCRIPTOR, context *uintptr) (hr error) = vmcompute.ExportLayerBegin?
|
||||||
|
//sys exportLayerNext(context uintptr, fileName **uint16, fileInfo *winio.FileBasicInfo, fileSize *int64, deleted *uint32) (hr error) = vmcompute.ExportLayerNext?
|
||||||
|
//sys exportLayerRead(context uintptr, buffer []byte, bytesRead *uint32) (hr error) = vmcompute.ExportLayerRead?
|
||||||
|
//sys exportLayerEnd(context uintptr) (hr error) = vmcompute.ExportLayerEnd?
|
||||||
|
|
||||||
|
//sys grantVmAccess(vmid string, filepath string) (hr error) = vmcompute.GrantVmAccess?
|
||||||
|
|
||||||
|
type _guid = guid.GUID
|
597
vendor/github.com/Microsoft/hcsshim/internal/wclayer/zsyscall_windows.go
generated
vendored
Normal file
597
vendor/github.com/Microsoft/hcsshim/internal/wclayer/zsyscall_windows.go
generated
vendored
Normal file
|
@ -0,0 +1,597 @@
|
||||||
|
// MACHINE GENERATED BY 'go generate' COMMAND; DO NOT EDIT
|
||||||
|
|
||||||
|
package wclayer
|
||||||
|
|
||||||
|
import (
|
||||||
|
"syscall"
|
||||||
|
"unsafe"
|
||||||
|
|
||||||
|
"github.com/Microsoft/go-winio"
|
||||||
|
"github.com/Microsoft/hcsshim/internal/interop"
|
||||||
|
"golang.org/x/sys/windows"
|
||||||
|
)
|
||||||
|
|
||||||
|
var _ unsafe.Pointer
|
||||||
|
|
||||||
|
// Do the interface allocations only once for common
|
||||||
|
// Errno values.
|
||||||
|
const (
|
||||||
|
errnoERROR_IO_PENDING = 997
|
||||||
|
)
|
||||||
|
|
||||||
|
var (
|
||||||
|
errERROR_IO_PENDING error = syscall.Errno(errnoERROR_IO_PENDING)
|
||||||
|
)
|
||||||
|
|
||||||
|
// errnoErr returns common boxed Errno values, to prevent
|
||||||
|
// allocations at runtime.
|
||||||
|
func errnoErr(e syscall.Errno) error {
|
||||||
|
switch e {
|
||||||
|
case 0:
|
||||||
|
return nil
|
||||||
|
case errnoERROR_IO_PENDING:
|
||||||
|
return errERROR_IO_PENDING
|
||||||
|
}
|
||||||
|
// TODO: add more here, after collecting data on the common
|
||||||
|
// error values see on Windows. (perhaps when running
|
||||||
|
// all.bat?)
|
||||||
|
return e
|
||||||
|
}
|
||||||
|
|
||||||
|
var (
|
||||||
|
modvmcompute = windows.NewLazySystemDLL("vmcompute.dll")
|
||||||
|
|
||||||
|
procActivateLayer = modvmcompute.NewProc("ActivateLayer")
|
||||||
|
procCopyLayer = modvmcompute.NewProc("CopyLayer")
|
||||||
|
procCreateLayer = modvmcompute.NewProc("CreateLayer")
|
||||||
|
procCreateSandboxLayer = modvmcompute.NewProc("CreateSandboxLayer")
|
||||||
|
procExpandSandboxSize = modvmcompute.NewProc("ExpandSandboxSize")
|
||||||
|
procDeactivateLayer = modvmcompute.NewProc("DeactivateLayer")
|
||||||
|
procDestroyLayer = modvmcompute.NewProc("DestroyLayer")
|
||||||
|
procExportLayer = modvmcompute.NewProc("ExportLayer")
|
||||||
|
procGetLayerMountPath = modvmcompute.NewProc("GetLayerMountPath")
|
||||||
|
procGetBaseImages = modvmcompute.NewProc("GetBaseImages")
|
||||||
|
procImportLayer = modvmcompute.NewProc("ImportLayer")
|
||||||
|
procLayerExists = modvmcompute.NewProc("LayerExists")
|
||||||
|
procNameToGuid = modvmcompute.NewProc("NameToGuid")
|
||||||
|
procPrepareLayer = modvmcompute.NewProc("PrepareLayer")
|
||||||
|
procUnprepareLayer = modvmcompute.NewProc("UnprepareLayer")
|
||||||
|
procProcessBaseImage = modvmcompute.NewProc("ProcessBaseImage")
|
||||||
|
procProcessUtilityImage = modvmcompute.NewProc("ProcessUtilityImage")
|
||||||
|
procImportLayerBegin = modvmcompute.NewProc("ImportLayerBegin")
|
||||||
|
procImportLayerNext = modvmcompute.NewProc("ImportLayerNext")
|
||||||
|
procImportLayerWrite = modvmcompute.NewProc("ImportLayerWrite")
|
||||||
|
procImportLayerEnd = modvmcompute.NewProc("ImportLayerEnd")
|
||||||
|
procExportLayerBegin = modvmcompute.NewProc("ExportLayerBegin")
|
||||||
|
procExportLayerNext = modvmcompute.NewProc("ExportLayerNext")
|
||||||
|
procExportLayerRead = modvmcompute.NewProc("ExportLayerRead")
|
||||||
|
procExportLayerEnd = modvmcompute.NewProc("ExportLayerEnd")
|
||||||
|
procGrantVmAccess = modvmcompute.NewProc("GrantVmAccess")
|
||||||
|
)
|
||||||
|
|
||||||
|
func activateLayer(info *driverInfo, id string) (hr error) {
|
||||||
|
var _p0 *uint16
|
||||||
|
_p0, hr = syscall.UTF16PtrFromString(id)
|
||||||
|
if hr != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
return _activateLayer(info, _p0)
|
||||||
|
}
|
||||||
|
|
||||||
|
func _activateLayer(info *driverInfo, id *uint16) (hr error) {
|
||||||
|
if hr = procActivateLayer.Find(); hr != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
r0, _, _ := syscall.Syscall(procActivateLayer.Addr(), 2, uintptr(unsafe.Pointer(info)), uintptr(unsafe.Pointer(id)), 0)
|
||||||
|
if int32(r0) < 0 {
|
||||||
|
hr = interop.Win32FromHresult(r0)
|
||||||
|
}
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
func copyLayer(info *driverInfo, srcId string, dstId string, descriptors []WC_LAYER_DESCRIPTOR) (hr error) {
|
||||||
|
var _p0 *uint16
|
||||||
|
_p0, hr = syscall.UTF16PtrFromString(srcId)
|
||||||
|
if hr != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
var _p1 *uint16
|
||||||
|
_p1, hr = syscall.UTF16PtrFromString(dstId)
|
||||||
|
if hr != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
return _copyLayer(info, _p0, _p1, descriptors)
|
||||||
|
}
|
||||||
|
|
||||||
|
func _copyLayer(info *driverInfo, srcId *uint16, dstId *uint16, descriptors []WC_LAYER_DESCRIPTOR) (hr error) {
|
||||||
|
var _p2 *WC_LAYER_DESCRIPTOR
|
||||||
|
if len(descriptors) > 0 {
|
||||||
|
_p2 = &descriptors[0]
|
||||||
|
}
|
||||||
|
if hr = procCopyLayer.Find(); hr != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
r0, _, _ := syscall.Syscall6(procCopyLayer.Addr(), 5, uintptr(unsafe.Pointer(info)), uintptr(unsafe.Pointer(srcId)), uintptr(unsafe.Pointer(dstId)), uintptr(unsafe.Pointer(_p2)), uintptr(len(descriptors)), 0)
|
||||||
|
if int32(r0) < 0 {
|
||||||
|
hr = interop.Win32FromHresult(r0)
|
||||||
|
}
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
func createLayer(info *driverInfo, id string, parent string) (hr error) {
|
||||||
|
var _p0 *uint16
|
||||||
|
_p0, hr = syscall.UTF16PtrFromString(id)
|
||||||
|
if hr != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
var _p1 *uint16
|
||||||
|
_p1, hr = syscall.UTF16PtrFromString(parent)
|
||||||
|
if hr != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
return _createLayer(info, _p0, _p1)
|
||||||
|
}
|
||||||
|
|
||||||
|
func _createLayer(info *driverInfo, id *uint16, parent *uint16) (hr error) {
|
||||||
|
if hr = procCreateLayer.Find(); hr != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
r0, _, _ := syscall.Syscall(procCreateLayer.Addr(), 3, uintptr(unsafe.Pointer(info)), uintptr(unsafe.Pointer(id)), uintptr(unsafe.Pointer(parent)))
|
||||||
|
if int32(r0) < 0 {
|
||||||
|
hr = interop.Win32FromHresult(r0)
|
||||||
|
}
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
func createSandboxLayer(info *driverInfo, id string, parent uintptr, descriptors []WC_LAYER_DESCRIPTOR) (hr error) {
|
||||||
|
var _p0 *uint16
|
||||||
|
_p0, hr = syscall.UTF16PtrFromString(id)
|
||||||
|
if hr != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
return _createSandboxLayer(info, _p0, parent, descriptors)
|
||||||
|
}
|
||||||
|
|
||||||
|
func _createSandboxLayer(info *driverInfo, id *uint16, parent uintptr, descriptors []WC_LAYER_DESCRIPTOR) (hr error) {
|
||||||
|
var _p1 *WC_LAYER_DESCRIPTOR
|
||||||
|
if len(descriptors) > 0 {
|
||||||
|
_p1 = &descriptors[0]
|
||||||
|
}
|
||||||
|
if hr = procCreateSandboxLayer.Find(); hr != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
r0, _, _ := syscall.Syscall6(procCreateSandboxLayer.Addr(), 5, uintptr(unsafe.Pointer(info)), uintptr(unsafe.Pointer(id)), uintptr(parent), uintptr(unsafe.Pointer(_p1)), uintptr(len(descriptors)), 0)
|
||||||
|
if int32(r0) < 0 {
|
||||||
|
hr = interop.Win32FromHresult(r0)
|
||||||
|
}
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
func expandSandboxSize(info *driverInfo, id string, size uint64) (hr error) {
|
||||||
|
var _p0 *uint16
|
||||||
|
_p0, hr = syscall.UTF16PtrFromString(id)
|
||||||
|
if hr != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
return _expandSandboxSize(info, _p0, size)
|
||||||
|
}
|
||||||
|
|
||||||
|
func _expandSandboxSize(info *driverInfo, id *uint16, size uint64) (hr error) {
|
||||||
|
if hr = procExpandSandboxSize.Find(); hr != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
r0, _, _ := syscall.Syscall(procExpandSandboxSize.Addr(), 3, uintptr(unsafe.Pointer(info)), uintptr(unsafe.Pointer(id)), uintptr(size))
|
||||||
|
if int32(r0) < 0 {
|
||||||
|
hr = interop.Win32FromHresult(r0)
|
||||||
|
}
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
func deactivateLayer(info *driverInfo, id string) (hr error) {
|
||||||
|
var _p0 *uint16
|
||||||
|
_p0, hr = syscall.UTF16PtrFromString(id)
|
||||||
|
if hr != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
return _deactivateLayer(info, _p0)
|
||||||
|
}
|
||||||
|
|
||||||
|
func _deactivateLayer(info *driverInfo, id *uint16) (hr error) {
|
||||||
|
if hr = procDeactivateLayer.Find(); hr != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
r0, _, _ := syscall.Syscall(procDeactivateLayer.Addr(), 2, uintptr(unsafe.Pointer(info)), uintptr(unsafe.Pointer(id)), 0)
|
||||||
|
if int32(r0) < 0 {
|
||||||
|
hr = interop.Win32FromHresult(r0)
|
||||||
|
}
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
func destroyLayer(info *driverInfo, id string) (hr error) {
|
||||||
|
var _p0 *uint16
|
||||||
|
_p0, hr = syscall.UTF16PtrFromString(id)
|
||||||
|
if hr != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
return _destroyLayer(info, _p0)
|
||||||
|
}
|
||||||
|
|
||||||
|
func _destroyLayer(info *driverInfo, id *uint16) (hr error) {
|
||||||
|
if hr = procDestroyLayer.Find(); hr != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
r0, _, _ := syscall.Syscall(procDestroyLayer.Addr(), 2, uintptr(unsafe.Pointer(info)), uintptr(unsafe.Pointer(id)), 0)
|
||||||
|
if int32(r0) < 0 {
|
||||||
|
hr = interop.Win32FromHresult(r0)
|
||||||
|
}
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
func exportLayer(info *driverInfo, id string, path string, descriptors []WC_LAYER_DESCRIPTOR) (hr error) {
|
||||||
|
var _p0 *uint16
|
||||||
|
_p0, hr = syscall.UTF16PtrFromString(id)
|
||||||
|
if hr != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
var _p1 *uint16
|
||||||
|
_p1, hr = syscall.UTF16PtrFromString(path)
|
||||||
|
if hr != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
return _exportLayer(info, _p0, _p1, descriptors)
|
||||||
|
}
|
||||||
|
|
||||||
|
func _exportLayer(info *driverInfo, id *uint16, path *uint16, descriptors []WC_LAYER_DESCRIPTOR) (hr error) {
|
||||||
|
var _p2 *WC_LAYER_DESCRIPTOR
|
||||||
|
if len(descriptors) > 0 {
|
||||||
|
_p2 = &descriptors[0]
|
||||||
|
}
|
||||||
|
if hr = procExportLayer.Find(); hr != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
r0, _, _ := syscall.Syscall6(procExportLayer.Addr(), 5, uintptr(unsafe.Pointer(info)), uintptr(unsafe.Pointer(id)), uintptr(unsafe.Pointer(path)), uintptr(unsafe.Pointer(_p2)), uintptr(len(descriptors)), 0)
|
||||||
|
if int32(r0) < 0 {
|
||||||
|
hr = interop.Win32FromHresult(r0)
|
||||||
|
}
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
func getLayerMountPath(info *driverInfo, id string, length *uintptr, buffer *uint16) (hr error) {
|
||||||
|
var _p0 *uint16
|
||||||
|
_p0, hr = syscall.UTF16PtrFromString(id)
|
||||||
|
if hr != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
return _getLayerMountPath(info, _p0, length, buffer)
|
||||||
|
}
|
||||||
|
|
||||||
|
func _getLayerMountPath(info *driverInfo, id *uint16, length *uintptr, buffer *uint16) (hr error) {
|
||||||
|
if hr = procGetLayerMountPath.Find(); hr != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
r0, _, _ := syscall.Syscall6(procGetLayerMountPath.Addr(), 4, uintptr(unsafe.Pointer(info)), uintptr(unsafe.Pointer(id)), uintptr(unsafe.Pointer(length)), uintptr(unsafe.Pointer(buffer)), 0, 0)
|
||||||
|
if int32(r0) < 0 {
|
||||||
|
hr = interop.Win32FromHresult(r0)
|
||||||
|
}
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
func getBaseImages(buffer **uint16) (hr error) {
|
||||||
|
if hr = procGetBaseImages.Find(); hr != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
r0, _, _ := syscall.Syscall(procGetBaseImages.Addr(), 1, uintptr(unsafe.Pointer(buffer)), 0, 0)
|
||||||
|
if int32(r0) < 0 {
|
||||||
|
hr = interop.Win32FromHresult(r0)
|
||||||
|
}
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
func importLayer(info *driverInfo, id string, path string, descriptors []WC_LAYER_DESCRIPTOR) (hr error) {
|
||||||
|
var _p0 *uint16
|
||||||
|
_p0, hr = syscall.UTF16PtrFromString(id)
|
||||||
|
if hr != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
var _p1 *uint16
|
||||||
|
_p1, hr = syscall.UTF16PtrFromString(path)
|
||||||
|
if hr != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
return _importLayer(info, _p0, _p1, descriptors)
|
||||||
|
}
|
||||||
|
|
||||||
|
func _importLayer(info *driverInfo, id *uint16, path *uint16, descriptors []WC_LAYER_DESCRIPTOR) (hr error) {
|
||||||
|
var _p2 *WC_LAYER_DESCRIPTOR
|
||||||
|
if len(descriptors) > 0 {
|
||||||
|
_p2 = &descriptors[0]
|
||||||
|
}
|
||||||
|
if hr = procImportLayer.Find(); hr != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
r0, _, _ := syscall.Syscall6(procImportLayer.Addr(), 5, uintptr(unsafe.Pointer(info)), uintptr(unsafe.Pointer(id)), uintptr(unsafe.Pointer(path)), uintptr(unsafe.Pointer(_p2)), uintptr(len(descriptors)), 0)
|
||||||
|
if int32(r0) < 0 {
|
||||||
|
hr = interop.Win32FromHresult(r0)
|
||||||
|
}
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
func layerExists(info *driverInfo, id string, exists *uint32) (hr error) {
|
||||||
|
var _p0 *uint16
|
||||||
|
_p0, hr = syscall.UTF16PtrFromString(id)
|
||||||
|
if hr != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
return _layerExists(info, _p0, exists)
|
||||||
|
}
|
||||||
|
|
||||||
|
func _layerExists(info *driverInfo, id *uint16, exists *uint32) (hr error) {
|
||||||
|
if hr = procLayerExists.Find(); hr != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
r0, _, _ := syscall.Syscall(procLayerExists.Addr(), 3, uintptr(unsafe.Pointer(info)), uintptr(unsafe.Pointer(id)), uintptr(unsafe.Pointer(exists)))
|
||||||
|
if int32(r0) < 0 {
|
||||||
|
hr = interop.Win32FromHresult(r0)
|
||||||
|
}
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
func nameToGuid(name string, guid *_guid) (hr error) {
|
||||||
|
var _p0 *uint16
|
||||||
|
_p0, hr = syscall.UTF16PtrFromString(name)
|
||||||
|
if hr != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
return _nameToGuid(_p0, guid)
|
||||||
|
}
|
||||||
|
|
||||||
|
func _nameToGuid(name *uint16, guid *_guid) (hr error) {
|
||||||
|
if hr = procNameToGuid.Find(); hr != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
r0, _, _ := syscall.Syscall(procNameToGuid.Addr(), 2, uintptr(unsafe.Pointer(name)), uintptr(unsafe.Pointer(guid)), 0)
|
||||||
|
if int32(r0) < 0 {
|
||||||
|
hr = interop.Win32FromHresult(r0)
|
||||||
|
}
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
func prepareLayer(info *driverInfo, id string, descriptors []WC_LAYER_DESCRIPTOR) (hr error) {
|
||||||
|
var _p0 *uint16
|
||||||
|
_p0, hr = syscall.UTF16PtrFromString(id)
|
||||||
|
if hr != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
return _prepareLayer(info, _p0, descriptors)
|
||||||
|
}
|
||||||
|
|
||||||
|
func _prepareLayer(info *driverInfo, id *uint16, descriptors []WC_LAYER_DESCRIPTOR) (hr error) {
|
||||||
|
var _p1 *WC_LAYER_DESCRIPTOR
|
||||||
|
if len(descriptors) > 0 {
|
||||||
|
_p1 = &descriptors[0]
|
||||||
|
}
|
||||||
|
if hr = procPrepareLayer.Find(); hr != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
r0, _, _ := syscall.Syscall6(procPrepareLayer.Addr(), 4, uintptr(unsafe.Pointer(info)), uintptr(unsafe.Pointer(id)), uintptr(unsafe.Pointer(_p1)), uintptr(len(descriptors)), 0, 0)
|
||||||
|
if int32(r0) < 0 {
|
||||||
|
hr = interop.Win32FromHresult(r0)
|
||||||
|
}
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
func unprepareLayer(info *driverInfo, id string) (hr error) {
|
||||||
|
var _p0 *uint16
|
||||||
|
_p0, hr = syscall.UTF16PtrFromString(id)
|
||||||
|
if hr != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
return _unprepareLayer(info, _p0)
|
||||||
|
}
|
||||||
|
|
||||||
|
func _unprepareLayer(info *driverInfo, id *uint16) (hr error) {
|
||||||
|
if hr = procUnprepareLayer.Find(); hr != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
r0, _, _ := syscall.Syscall(procUnprepareLayer.Addr(), 2, uintptr(unsafe.Pointer(info)), uintptr(unsafe.Pointer(id)), 0)
|
||||||
|
if int32(r0) < 0 {
|
||||||
|
hr = interop.Win32FromHresult(r0)
|
||||||
|
}
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
func processBaseImage(path string) (hr error) {
|
||||||
|
var _p0 *uint16
|
||||||
|
_p0, hr = syscall.UTF16PtrFromString(path)
|
||||||
|
if hr != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
return _processBaseImage(_p0)
|
||||||
|
}
|
||||||
|
|
||||||
|
func _processBaseImage(path *uint16) (hr error) {
|
||||||
|
if hr = procProcessBaseImage.Find(); hr != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
r0, _, _ := syscall.Syscall(procProcessBaseImage.Addr(), 1, uintptr(unsafe.Pointer(path)), 0, 0)
|
||||||
|
if int32(r0) < 0 {
|
||||||
|
hr = interop.Win32FromHresult(r0)
|
||||||
|
}
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
func processUtilityImage(path string) (hr error) {
|
||||||
|
var _p0 *uint16
|
||||||
|
_p0, hr = syscall.UTF16PtrFromString(path)
|
||||||
|
if hr != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
return _processUtilityImage(_p0)
|
||||||
|
}
|
||||||
|
|
||||||
|
func _processUtilityImage(path *uint16) (hr error) {
|
||||||
|
if hr = procProcessUtilityImage.Find(); hr != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
r0, _, _ := syscall.Syscall(procProcessUtilityImage.Addr(), 1, uintptr(unsafe.Pointer(path)), 0, 0)
|
||||||
|
if int32(r0) < 0 {
|
||||||
|
hr = interop.Win32FromHresult(r0)
|
||||||
|
}
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
func importLayerBegin(info *driverInfo, id string, descriptors []WC_LAYER_DESCRIPTOR, context *uintptr) (hr error) {
|
||||||
|
var _p0 *uint16
|
||||||
|
_p0, hr = syscall.UTF16PtrFromString(id)
|
||||||
|
if hr != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
return _importLayerBegin(info, _p0, descriptors, context)
|
||||||
|
}
|
||||||
|
|
||||||
|
func _importLayerBegin(info *driverInfo, id *uint16, descriptors []WC_LAYER_DESCRIPTOR, context *uintptr) (hr error) {
|
||||||
|
var _p1 *WC_LAYER_DESCRIPTOR
|
||||||
|
if len(descriptors) > 0 {
|
||||||
|
_p1 = &descriptors[0]
|
||||||
|
}
|
||||||
|
if hr = procImportLayerBegin.Find(); hr != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
r0, _, _ := syscall.Syscall6(procImportLayerBegin.Addr(), 5, uintptr(unsafe.Pointer(info)), uintptr(unsafe.Pointer(id)), uintptr(unsafe.Pointer(_p1)), uintptr(len(descriptors)), uintptr(unsafe.Pointer(context)), 0)
|
||||||
|
if int32(r0) < 0 {
|
||||||
|
hr = interop.Win32FromHresult(r0)
|
||||||
|
}
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
func importLayerNext(context uintptr, fileName string, fileInfo *winio.FileBasicInfo) (hr error) {
|
||||||
|
var _p0 *uint16
|
||||||
|
_p0, hr = syscall.UTF16PtrFromString(fileName)
|
||||||
|
if hr != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
return _importLayerNext(context, _p0, fileInfo)
|
||||||
|
}
|
||||||
|
|
||||||
|
func _importLayerNext(context uintptr, fileName *uint16, fileInfo *winio.FileBasicInfo) (hr error) {
|
||||||
|
if hr = procImportLayerNext.Find(); hr != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
r0, _, _ := syscall.Syscall(procImportLayerNext.Addr(), 3, uintptr(context), uintptr(unsafe.Pointer(fileName)), uintptr(unsafe.Pointer(fileInfo)))
|
||||||
|
if int32(r0) < 0 {
|
||||||
|
hr = interop.Win32FromHresult(r0)
|
||||||
|
}
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
func importLayerWrite(context uintptr, buffer []byte) (hr error) {
|
||||||
|
var _p0 *byte
|
||||||
|
if len(buffer) > 0 {
|
||||||
|
_p0 = &buffer[0]
|
||||||
|
}
|
||||||
|
if hr = procImportLayerWrite.Find(); hr != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
r0, _, _ := syscall.Syscall(procImportLayerWrite.Addr(), 3, uintptr(context), uintptr(unsafe.Pointer(_p0)), uintptr(len(buffer)))
|
||||||
|
if int32(r0) < 0 {
|
||||||
|
hr = interop.Win32FromHresult(r0)
|
||||||
|
}
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
func importLayerEnd(context uintptr) (hr error) {
|
||||||
|
if hr = procImportLayerEnd.Find(); hr != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
r0, _, _ := syscall.Syscall(procImportLayerEnd.Addr(), 1, uintptr(context), 0, 0)
|
||||||
|
if int32(r0) < 0 {
|
||||||
|
hr = interop.Win32FromHresult(r0)
|
||||||
|
}
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
func exportLayerBegin(info *driverInfo, id string, descriptors []WC_LAYER_DESCRIPTOR, context *uintptr) (hr error) {
|
||||||
|
var _p0 *uint16
|
||||||
|
_p0, hr = syscall.UTF16PtrFromString(id)
|
||||||
|
if hr != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
return _exportLayerBegin(info, _p0, descriptors, context)
|
||||||
|
}
|
||||||
|
|
||||||
|
func _exportLayerBegin(info *driverInfo, id *uint16, descriptors []WC_LAYER_DESCRIPTOR, context *uintptr) (hr error) {
|
||||||
|
var _p1 *WC_LAYER_DESCRIPTOR
|
||||||
|
if len(descriptors) > 0 {
|
||||||
|
_p1 = &descriptors[0]
|
||||||
|
}
|
||||||
|
if hr = procExportLayerBegin.Find(); hr != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
r0, _, _ := syscall.Syscall6(procExportLayerBegin.Addr(), 5, uintptr(unsafe.Pointer(info)), uintptr(unsafe.Pointer(id)), uintptr(unsafe.Pointer(_p1)), uintptr(len(descriptors)), uintptr(unsafe.Pointer(context)), 0)
|
||||||
|
if int32(r0) < 0 {
|
||||||
|
hr = interop.Win32FromHresult(r0)
|
||||||
|
}
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
func exportLayerNext(context uintptr, fileName **uint16, fileInfo *winio.FileBasicInfo, fileSize *int64, deleted *uint32) (hr error) {
|
||||||
|
if hr = procExportLayerNext.Find(); hr != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
r0, _, _ := syscall.Syscall6(procExportLayerNext.Addr(), 5, uintptr(context), uintptr(unsafe.Pointer(fileName)), uintptr(unsafe.Pointer(fileInfo)), uintptr(unsafe.Pointer(fileSize)), uintptr(unsafe.Pointer(deleted)), 0)
|
||||||
|
if int32(r0) < 0 {
|
||||||
|
hr = interop.Win32FromHresult(r0)
|
||||||
|
}
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
func exportLayerRead(context uintptr, buffer []byte, bytesRead *uint32) (hr error) {
|
||||||
|
var _p0 *byte
|
||||||
|
if len(buffer) > 0 {
|
||||||
|
_p0 = &buffer[0]
|
||||||
|
}
|
||||||
|
if hr = procExportLayerRead.Find(); hr != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
r0, _, _ := syscall.Syscall6(procExportLayerRead.Addr(), 4, uintptr(context), uintptr(unsafe.Pointer(_p0)), uintptr(len(buffer)), uintptr(unsafe.Pointer(bytesRead)), 0, 0)
|
||||||
|
if int32(r0) < 0 {
|
||||||
|
hr = interop.Win32FromHresult(r0)
|
||||||
|
}
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
func exportLayerEnd(context uintptr) (hr error) {
|
||||||
|
if hr = procExportLayerEnd.Find(); hr != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
r0, _, _ := syscall.Syscall(procExportLayerEnd.Addr(), 1, uintptr(context), 0, 0)
|
||||||
|
if int32(r0) < 0 {
|
||||||
|
hr = interop.Win32FromHresult(r0)
|
||||||
|
}
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
func grantVmAccess(vmid string, filepath string) (hr error) {
|
||||||
|
var _p0 *uint16
|
||||||
|
_p0, hr = syscall.UTF16PtrFromString(vmid)
|
||||||
|
if hr != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
var _p1 *uint16
|
||||||
|
_p1, hr = syscall.UTF16PtrFromString(filepath)
|
||||||
|
if hr != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
return _grantVmAccess(_p0, _p1)
|
||||||
|
}
|
||||||
|
|
||||||
|
func _grantVmAccess(vmid *uint16, filepath *uint16) (hr error) {
|
||||||
|
if hr = procGrantVmAccess.Find(); hr != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
r0, _, _ := syscall.Syscall(procGrantVmAccess.Addr(), 2, uintptr(unsafe.Pointer(vmid)), uintptr(unsafe.Pointer(filepath)), 0)
|
||||||
|
if int32(r0) < 0 {
|
||||||
|
hr = interop.Win32FromHresult(r0)
|
||||||
|
}
|
||||||
|
return
|
||||||
|
}
|
|
@ -0,0 +1,108 @@
|
||||||
|
package hcsshim
|
||||||
|
|
||||||
|
import (
|
||||||
|
"crypto/sha1"
|
||||||
|
"path/filepath"
|
||||||
|
|
||||||
|
"github.com/Microsoft/hcsshim/internal/guid"
|
||||||
|
|
||||||
|
"github.com/Microsoft/hcsshim/internal/wclayer"
|
||||||
|
)
|
||||||
|
|
||||||
|
func layerPath(info *DriverInfo, id string) string {
|
||||||
|
return filepath.Join(info.HomeDir, id)
|
||||||
|
}
|
||||||
|
|
||||||
|
func ActivateLayer(info DriverInfo, id string) error {
|
||||||
|
return wclayer.ActivateLayer(layerPath(&info, id))
|
||||||
|
}
|
||||||
|
func CreateLayer(info DriverInfo, id, parent string) error {
|
||||||
|
return wclayer.CreateLayer(layerPath(&info, id), parent)
|
||||||
|
}
|
||||||
|
// New clients should use CreateScratchLayer instead. Kept in to preserve API compatibility.
|
||||||
|
func CreateSandboxLayer(info DriverInfo, layerId, parentId string, parentLayerPaths []string) error {
|
||||||
|
return wclayer.CreateScratchLayer(layerPath(&info, layerId), parentLayerPaths)
|
||||||
|
}
|
||||||
|
func CreateScratchLayer(info DriverInfo, layerId, parentId string, parentLayerPaths []string) error {
|
||||||
|
return wclayer.CreateScratchLayer(layerPath(&info, layerId), parentLayerPaths)
|
||||||
|
}
|
||||||
|
func DeactivateLayer(info DriverInfo, id string) error {
|
||||||
|
return wclayer.DeactivateLayer(layerPath(&info, id))
|
||||||
|
}
|
||||||
|
func DestroyLayer(info DriverInfo, id string) error {
|
||||||
|
return wclayer.DestroyLayer(layerPath(&info, id))
|
||||||
|
}
|
||||||
|
// New clients should use ExpandScratchSize instead. Kept in to preserve API compatibility.
|
||||||
|
func ExpandSandboxSize(info DriverInfo, layerId string, size uint64) error {
|
||||||
|
return wclayer.ExpandScratchSize(layerPath(&info, layerId), size)
|
||||||
|
}
|
||||||
|
func ExpandScratchSize(info DriverInfo, layerId string, size uint64) error {
|
||||||
|
return wclayer.ExpandScratchSize(layerPath(&info, layerId), size)
|
||||||
|
}
|
||||||
|
func ExportLayer(info DriverInfo, layerId string, exportFolderPath string, parentLayerPaths []string) error {
|
||||||
|
return wclayer.ExportLayer(layerPath(&info, layerId), exportFolderPath, parentLayerPaths)
|
||||||
|
}
|
||||||
|
func GetLayerMountPath(info DriverInfo, id string) (string, error) {
|
||||||
|
return wclayer.GetLayerMountPath(layerPath(&info, id))
|
||||||
|
}
|
||||||
|
func GetSharedBaseImages() (imageData string, err error) {
|
||||||
|
return wclayer.GetSharedBaseImages()
|
||||||
|
}
|
||||||
|
func ImportLayer(info DriverInfo, layerID string, importFolderPath string, parentLayerPaths []string) error {
|
||||||
|
return wclayer.ImportLayer(layerPath(&info, layerID), importFolderPath, parentLayerPaths)
|
||||||
|
}
|
||||||
|
func LayerExists(info DriverInfo, id string) (bool, error) {
|
||||||
|
return wclayer.LayerExists(layerPath(&info, id))
|
||||||
|
}
|
||||||
|
func PrepareLayer(info DriverInfo, layerId string, parentLayerPaths []string) error {
|
||||||
|
return wclayer.PrepareLayer(layerPath(&info, layerId), parentLayerPaths)
|
||||||
|
}
|
||||||
|
func ProcessBaseLayer(path string) error {
|
||||||
|
return wclayer.ProcessBaseLayer(path)
|
||||||
|
}
|
||||||
|
func ProcessUtilityVMImage(path string) error {
|
||||||
|
return wclayer.ProcessUtilityVMImage(path)
|
||||||
|
}
|
||||||
|
func UnprepareLayer(info DriverInfo, layerId string) error {
|
||||||
|
return wclayer.UnprepareLayer(layerPath(&info, layerId))
|
||||||
|
}
|
||||||
|
|
||||||
|
type DriverInfo struct {
|
||||||
|
Flavour int
|
||||||
|
HomeDir string
|
||||||
|
}
|
||||||
|
|
||||||
|
type FilterLayerReader = wclayer.FilterLayerReader
|
||||||
|
type FilterLayerWriter = wclayer.FilterLayerWriter
|
||||||
|
|
||||||
|
type GUID [16]byte
|
||||||
|
|
||||||
|
func NameToGuid(name string) (id GUID, err error) {
|
||||||
|
g, err := wclayer.NameToGuid(name)
|
||||||
|
return GUID(g), err
|
||||||
|
}
|
||||||
|
|
||||||
|
func NewGUID(source string) *GUID {
|
||||||
|
h := sha1.Sum([]byte(source))
|
||||||
|
var g GUID
|
||||||
|
copy(g[0:], h[0:16])
|
||||||
|
return &g
|
||||||
|
}
|
||||||
|
|
||||||
|
func (g *GUID) ToString() string {
|
||||||
|
return (guid.GUID)(*g).String()
|
||||||
|
}
|
||||||
|
|
||||||
|
type LayerReader = wclayer.LayerReader
|
||||||
|
|
||||||
|
func NewLayerReader(info DriverInfo, layerID string, parentLayerPaths []string) (LayerReader, error) {
|
||||||
|
return wclayer.NewLayerReader(layerPath(&info, layerID), parentLayerPaths)
|
||||||
|
}
|
||||||
|
|
||||||
|
type LayerWriter = wclayer.LayerWriter
|
||||||
|
|
||||||
|
func NewLayerWriter(info DriverInfo, layerID string, parentLayerPaths []string) (LayerWriter, error) {
|
||||||
|
return wclayer.NewLayerWriter(layerPath(&info, layerID), parentLayerPaths)
|
||||||
|
}
|
||||||
|
|
||||||
|
type WC_LAYER_DESCRIPTOR = wclayer.WC_LAYER_DESCRIPTOR
|
|
@ -1,30 +0,0 @@
|
||||||
package hcsshim
|
|
||||||
|
|
||||||
import "github.com/sirupsen/logrus"
|
|
||||||
|
|
||||||
// LayerExists will return true if a layer with the given id exists and is known
|
|
||||||
// to the system.
|
|
||||||
func LayerExists(info DriverInfo, id string) (bool, error) {
|
|
||||||
title := "hcsshim::LayerExists "
|
|
||||||
logrus.Debugf(title+"Flavour %d ID %s", info.Flavour, id)
|
|
||||||
|
|
||||||
// Convert info to API calling convention
|
|
||||||
infop, err := convertDriverInfo(info)
|
|
||||||
if err != nil {
|
|
||||||
logrus.Error(err)
|
|
||||||
return false, err
|
|
||||||
}
|
|
||||||
|
|
||||||
// Call the procedure itself.
|
|
||||||
var exists uint32
|
|
||||||
|
|
||||||
err = layerExists(&infop, id, &exists)
|
|
||||||
if err != nil {
|
|
||||||
err = makeErrorf(err, title, "id=%s flavour=%d", id, info.Flavour)
|
|
||||||
logrus.Error(err)
|
|
||||||
return false, err
|
|
||||||
}
|
|
||||||
|
|
||||||
logrus.Debugf(title+"succeeded flavour=%d id=%s exists=%d", info.Flavour, id, exists)
|
|
||||||
return exists != 0, nil
|
|
||||||
}
|
|
|
@ -1,7 +0,0 @@
|
||||||
// +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
|
|
|
@ -1,7 +0,0 @@
|
||||||
// +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
|
|
|
@ -1,20 +0,0 @@
|
||||||
package hcsshim
|
|
||||||
|
|
||||||
import "github.com/sirupsen/logrus"
|
|
||||||
|
|
||||||
// NameToGuid converts the given string into a GUID using the algorithm in the
|
|
||||||
// Host Compute Service, ensuring GUIDs generated with the same string are common
|
|
||||||
// across all clients.
|
|
||||||
func NameToGuid(name string) (id GUID, err error) {
|
|
||||||
title := "hcsshim::NameToGuid "
|
|
||||||
logrus.Debugf(title+"Name %s", name)
|
|
||||||
|
|
||||||
err = nameToGuid(name, &id)
|
|
||||||
if err != nil {
|
|
||||||
err = makeErrorf(err, title, "name=%s", name)
|
|
||||||
logrus.Error(err)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
return
|
|
||||||
}
|
|
|
@ -1,384 +1,72 @@
|
||||||
package hcsshim
|
package hcsshim
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"encoding/json"
|
|
||||||
"io"
|
"io"
|
||||||
"sync"
|
|
||||||
"syscall"
|
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"github.com/sirupsen/logrus"
|
"github.com/Microsoft/hcsshim/internal/hcs"
|
||||||
)
|
)
|
||||||
|
|
||||||
// ContainerError is an error encountered in HCS
|
// ContainerError is an error encountered in HCS
|
||||||
type process struct {
|
type process struct {
|
||||||
handleLock sync.RWMutex
|
p *hcs.Process
|
||||||
handle hcsProcess
|
|
||||||
processID int
|
|
||||||
container *container
|
|
||||||
cachedPipes *cachedPipes
|
|
||||||
callbackNumber uintptr
|
|
||||||
}
|
}
|
||||||
|
|
||||||
type cachedPipes struct {
|
|
||||||
stdIn syscall.Handle
|
|
||||||
stdOut syscall.Handle
|
|
||||||
stdErr syscall.Handle
|
|
||||||
}
|
|
||||||
|
|
||||||
type processModifyRequest struct {
|
|
||||||
Operation string
|
|
||||||
ConsoleSize *consoleSize `json:",omitempty"`
|
|
||||||
CloseHandle *closeHandle `json:",omitempty"`
|
|
||||||
}
|
|
||||||
|
|
||||||
type consoleSize struct {
|
|
||||||
Height uint16
|
|
||||||
Width uint16
|
|
||||||
}
|
|
||||||
|
|
||||||
type closeHandle struct {
|
|
||||||
Handle string
|
|
||||||
}
|
|
||||||
|
|
||||||
type processStatus struct {
|
|
||||||
ProcessID uint32
|
|
||||||
Exited bool
|
|
||||||
ExitCode uint32
|
|
||||||
LastWaitResult int32
|
|
||||||
}
|
|
||||||
|
|
||||||
const (
|
|
||||||
stdIn string = "StdIn"
|
|
||||||
stdOut string = "StdOut"
|
|
||||||
stdErr string = "StdErr"
|
|
||||||
)
|
|
||||||
|
|
||||||
const (
|
|
||||||
modifyConsoleSize string = "ConsoleSize"
|
|
||||||
modifyCloseHandle string = "CloseHandle"
|
|
||||||
)
|
|
||||||
|
|
||||||
// Pid returns the process ID of the process within the container.
|
// Pid returns the process ID of the process within the container.
|
||||||
func (process *process) Pid() int {
|
func (process *process) Pid() int {
|
||||||
return process.processID
|
return process.p.Pid()
|
||||||
}
|
}
|
||||||
|
|
||||||
// Kill signals the process to terminate but does not wait for it to finish terminating.
|
// Kill signals the process to terminate but does not wait for it to finish terminating.
|
||||||
func (process *process) Kill() error {
|
func (process *process) Kill() error {
|
||||||
process.handleLock.RLock()
|
return convertProcessError(process.p.Kill(), process)
|
||||||
defer process.handleLock.RUnlock()
|
|
||||||
operation := "Kill"
|
|
||||||
title := "HCSShim::Process::" + operation
|
|
||||||
logrus.Debugf(title+" processid=%d", process.processID)
|
|
||||||
|
|
||||||
if process.handle == 0 {
|
|
||||||
return makeProcessError(process, operation, "", ErrAlreadyClosed)
|
|
||||||
}
|
|
||||||
|
|
||||||
var resultp *uint16
|
|
||||||
err := hcsTerminateProcess(process.handle, &resultp)
|
|
||||||
err = processHcsResult(err, resultp)
|
|
||||||
if err != nil {
|
|
||||||
return makeProcessError(process, operation, "", err)
|
|
||||||
}
|
|
||||||
|
|
||||||
logrus.Debugf(title+" succeeded processid=%d", process.processID)
|
|
||||||
return nil
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Wait waits for the process to exit.
|
// Wait waits for the process to exit.
|
||||||
func (process *process) Wait() error {
|
func (process *process) Wait() error {
|
||||||
operation := "Wait"
|
return convertProcessError(process.p.Wait(), process)
|
||||||
title := "HCSShim::Process::" + operation
|
|
||||||
logrus.Debugf(title+" processid=%d", process.processID)
|
|
||||||
|
|
||||||
err := waitForNotification(process.callbackNumber, hcsNotificationProcessExited, nil)
|
|
||||||
if err != nil {
|
|
||||||
return makeProcessError(process, operation, "", err)
|
|
||||||
}
|
|
||||||
|
|
||||||
logrus.Debugf(title+" succeeded processid=%d", process.processID)
|
|
||||||
return nil
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// WaitTimeout waits for the process to exit or the duration to elapse. It returns
|
// WaitTimeout waits for the process to exit or the duration to elapse. It returns
|
||||||
// false if timeout occurs.
|
// false if timeout occurs.
|
||||||
func (process *process) WaitTimeout(timeout time.Duration) error {
|
func (process *process) WaitTimeout(timeout time.Duration) error {
|
||||||
operation := "WaitTimeout"
|
return convertProcessError(process.p.WaitTimeout(timeout), process)
|
||||||
title := "HCSShim::Process::" + operation
|
|
||||||
logrus.Debugf(title+" processid=%d", process.processID)
|
|
||||||
|
|
||||||
err := waitForNotification(process.callbackNumber, hcsNotificationProcessExited, &timeout)
|
|
||||||
if err != nil {
|
|
||||||
return makeProcessError(process, operation, "", err)
|
|
||||||
}
|
|
||||||
|
|
||||||
logrus.Debugf(title+" succeeded processid=%d", process.processID)
|
|
||||||
return nil
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// ExitCode returns the exit code of the process. The process must have
|
// ExitCode returns the exit code of the process. The process must have
|
||||||
// already terminated.
|
// already terminated.
|
||||||
func (process *process) ExitCode() (int, error) {
|
func (process *process) ExitCode() (int, error) {
|
||||||
process.handleLock.RLock()
|
code, err := process.p.ExitCode()
|
||||||
defer process.handleLock.RUnlock()
|
|
||||||
operation := "ExitCode"
|
|
||||||
title := "HCSShim::Process::" + operation
|
|
||||||
logrus.Debugf(title+" processid=%d", process.processID)
|
|
||||||
|
|
||||||
if process.handle == 0 {
|
|
||||||
return 0, makeProcessError(process, operation, "", ErrAlreadyClosed)
|
|
||||||
}
|
|
||||||
|
|
||||||
properties, err := process.properties()
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return 0, makeProcessError(process, operation, "", err)
|
err = convertProcessError(err, process)
|
||||||
}
|
}
|
||||||
|
return code, err
|
||||||
if properties.Exited == false {
|
|
||||||
return 0, makeProcessError(process, operation, "", ErrInvalidProcessState)
|
|
||||||
}
|
|
||||||
|
|
||||||
if properties.LastWaitResult != 0 {
|
|
||||||
return 0, makeProcessError(process, operation, "", syscall.Errno(properties.LastWaitResult))
|
|
||||||
}
|
|
||||||
|
|
||||||
logrus.Debugf(title+" succeeded processid=%d exitCode=%d", process.processID, properties.ExitCode)
|
|
||||||
return int(properties.ExitCode), nil
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// ResizeConsole resizes the console of the process.
|
// ResizeConsole resizes the console of the process.
|
||||||
func (process *process) ResizeConsole(width, height uint16) error {
|
func (process *process) ResizeConsole(width, height uint16) error {
|
||||||
process.handleLock.RLock()
|
return convertProcessError(process.p.ResizeConsole(width, height), process)
|
||||||
defer process.handleLock.RUnlock()
|
|
||||||
operation := "ResizeConsole"
|
|
||||||
title := "HCSShim::Process::" + operation
|
|
||||||
logrus.Debugf(title+" processid=%d", process.processID)
|
|
||||||
|
|
||||||
if process.handle == 0 {
|
|
||||||
return makeProcessError(process, operation, "", ErrAlreadyClosed)
|
|
||||||
}
|
|
||||||
|
|
||||||
modifyRequest := processModifyRequest{
|
|
||||||
Operation: modifyConsoleSize,
|
|
||||||
ConsoleSize: &consoleSize{
|
|
||||||
Height: height,
|
|
||||||
Width: width,
|
|
||||||
},
|
|
||||||
}
|
|
||||||
|
|
||||||
modifyRequestb, err := json.Marshal(modifyRequest)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
modifyRequestStr := string(modifyRequestb)
|
|
||||||
|
|
||||||
var resultp *uint16
|
|
||||||
err = hcsModifyProcess(process.handle, modifyRequestStr, &resultp)
|
|
||||||
err = processHcsResult(err, resultp)
|
|
||||||
if err != nil {
|
|
||||||
return makeProcessError(process, operation, "", err)
|
|
||||||
}
|
|
||||||
|
|
||||||
logrus.Debugf(title+" succeeded processid=%d", process.processID)
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func (process *process) properties() (*processStatus, error) {
|
|
||||||
operation := "properties"
|
|
||||||
title := "HCSShim::Process::" + operation
|
|
||||||
logrus.Debugf(title+" processid=%d", process.processID)
|
|
||||||
|
|
||||||
var (
|
|
||||||
resultp *uint16
|
|
||||||
propertiesp *uint16
|
|
||||||
)
|
|
||||||
err := hcsGetProcessProperties(process.handle, &propertiesp, &resultp)
|
|
||||||
err = processHcsResult(err, resultp)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
if propertiesp == nil {
|
|
||||||
return nil, ErrUnexpectedValue
|
|
||||||
}
|
|
||||||
propertiesRaw := convertAndFreeCoTaskMemBytes(propertiesp)
|
|
||||||
|
|
||||||
properties := &processStatus{}
|
|
||||||
if err := json.Unmarshal(propertiesRaw, properties); err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
logrus.Debugf(title+" succeeded processid=%d, properties=%s", process.processID, propertiesRaw)
|
|
||||||
return properties, nil
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Stdio returns the stdin, stdout, and stderr pipes, respectively. Closing
|
// Stdio returns the stdin, stdout, and stderr pipes, respectively. Closing
|
||||||
// these pipes does not close the underlying pipes; it should be possible to
|
// these pipes does not close the underlying pipes; it should be possible to
|
||||||
// call this multiple times to get multiple interfaces.
|
// call this multiple times to get multiple interfaces.
|
||||||
func (process *process) Stdio() (io.WriteCloser, io.ReadCloser, io.ReadCloser, error) {
|
func (process *process) Stdio() (io.WriteCloser, io.ReadCloser, io.ReadCloser, error) {
|
||||||
process.handleLock.RLock()
|
stdin, stdout, stderr, err := process.p.Stdio()
|
||||||
defer process.handleLock.RUnlock()
|
|
||||||
operation := "Stdio"
|
|
||||||
title := "HCSShim::Process::" + operation
|
|
||||||
logrus.Debugf(title+" processid=%d", process.processID)
|
|
||||||
|
|
||||||
if process.handle == 0 {
|
|
||||||
return nil, nil, nil, makeProcessError(process, operation, "", ErrAlreadyClosed)
|
|
||||||
}
|
|
||||||
|
|
||||||
var stdIn, stdOut, stdErr syscall.Handle
|
|
||||||
|
|
||||||
if process.cachedPipes == nil {
|
|
||||||
var (
|
|
||||||
processInfo hcsProcessInformation
|
|
||||||
resultp *uint16
|
|
||||||
)
|
|
||||||
err := hcsGetProcessInfo(process.handle, &processInfo, &resultp)
|
|
||||||
err = processHcsResult(err, resultp)
|
|
||||||
if err != nil {
|
|
||||||
return nil, nil, nil, makeProcessError(process, operation, "", err)
|
|
||||||
}
|
|
||||||
|
|
||||||
stdIn, stdOut, stdErr = processInfo.StdInput, processInfo.StdOutput, processInfo.StdError
|
|
||||||
} else {
|
|
||||||
// Use cached pipes
|
|
||||||
stdIn, stdOut, stdErr = process.cachedPipes.stdIn, process.cachedPipes.stdOut, process.cachedPipes.stdErr
|
|
||||||
|
|
||||||
// Invalidate the cache
|
|
||||||
process.cachedPipes = nil
|
|
||||||
}
|
|
||||||
|
|
||||||
pipes, err := makeOpenFiles([]syscall.Handle{stdIn, stdOut, stdErr})
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, nil, nil, makeProcessError(process, operation, "", err)
|
err = convertProcessError(err, process)
|
||||||
}
|
}
|
||||||
|
return stdin, stdout, stderr, err
|
||||||
logrus.Debugf(title+" succeeded processid=%d", process.processID)
|
|
||||||
return pipes[0], pipes[1], pipes[2], nil
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// CloseStdin closes the write side of the stdin pipe so that the process is
|
// CloseStdin closes the write side of the stdin pipe so that the process is
|
||||||
// notified on the read side that there is no more data in stdin.
|
// notified on the read side that there is no more data in stdin.
|
||||||
func (process *process) CloseStdin() error {
|
func (process *process) CloseStdin() error {
|
||||||
process.handleLock.RLock()
|
return convertProcessError(process.p.CloseStdin(), process)
|
||||||
defer process.handleLock.RUnlock()
|
|
||||||
operation := "CloseStdin"
|
|
||||||
title := "HCSShim::Process::" + operation
|
|
||||||
logrus.Debugf(title+" processid=%d", process.processID)
|
|
||||||
|
|
||||||
if process.handle == 0 {
|
|
||||||
return makeProcessError(process, operation, "", ErrAlreadyClosed)
|
|
||||||
}
|
|
||||||
|
|
||||||
modifyRequest := processModifyRequest{
|
|
||||||
Operation: modifyCloseHandle,
|
|
||||||
CloseHandle: &closeHandle{
|
|
||||||
Handle: stdIn,
|
|
||||||
},
|
|
||||||
}
|
|
||||||
|
|
||||||
modifyRequestb, err := json.Marshal(modifyRequest)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
modifyRequestStr := string(modifyRequestb)
|
|
||||||
|
|
||||||
var resultp *uint16
|
|
||||||
err = hcsModifyProcess(process.handle, modifyRequestStr, &resultp)
|
|
||||||
err = processHcsResult(err, resultp)
|
|
||||||
if err != nil {
|
|
||||||
return makeProcessError(process, operation, "", err)
|
|
||||||
}
|
|
||||||
|
|
||||||
logrus.Debugf(title+" succeeded processid=%d", process.processID)
|
|
||||||
return nil
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Close cleans up any state associated with the process but does not kill
|
// Close cleans up any state associated with the process but does not kill
|
||||||
// or wait on it.
|
// or wait on it.
|
||||||
func (process *process) Close() error {
|
func (process *process) Close() error {
|
||||||
process.handleLock.Lock()
|
return convertProcessError(process.p.Close(), process)
|
||||||
defer process.handleLock.Unlock()
|
|
||||||
operation := "Close"
|
|
||||||
title := "HCSShim::Process::" + operation
|
|
||||||
logrus.Debugf(title+" processid=%d", process.processID)
|
|
||||||
|
|
||||||
// Don't double free this
|
|
||||||
if process.handle == 0 {
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
if err := process.unregisterCallback(); err != nil {
|
|
||||||
return makeProcessError(process, operation, "", err)
|
|
||||||
}
|
|
||||||
|
|
||||||
if err := hcsCloseProcess(process.handle); err != nil {
|
|
||||||
return makeProcessError(process, operation, "", err)
|
|
||||||
}
|
|
||||||
|
|
||||||
process.handle = 0
|
|
||||||
|
|
||||||
logrus.Debugf(title+" succeeded processid=%d", process.processID)
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func (process *process) registerCallback() error {
|
|
||||||
context := ¬ifcationWatcherContext{
|
|
||||||
channels: newChannels(),
|
|
||||||
}
|
|
||||||
|
|
||||||
callbackMapLock.Lock()
|
|
||||||
callbackNumber := nextCallback
|
|
||||||
nextCallback++
|
|
||||||
callbackMap[callbackNumber] = context
|
|
||||||
callbackMapLock.Unlock()
|
|
||||||
|
|
||||||
var callbackHandle hcsCallback
|
|
||||||
err := hcsRegisterProcessCallback(process.handle, notificationWatcherCallback, callbackNumber, &callbackHandle)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
context.handle = callbackHandle
|
|
||||||
process.callbackNumber = callbackNumber
|
|
||||||
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func (process *process) unregisterCallback() error {
|
|
||||||
callbackNumber := process.callbackNumber
|
|
||||||
|
|
||||||
callbackMapLock.RLock()
|
|
||||||
context := callbackMap[callbackNumber]
|
|
||||||
callbackMapLock.RUnlock()
|
|
||||||
|
|
||||||
if context == nil {
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
handle := context.handle
|
|
||||||
|
|
||||||
if handle == 0 {
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// hcsUnregisterProcessCallback has its own syncronization
|
|
||||||
// to wait for all callbacks to complete. We must NOT hold the callbackMapLock.
|
|
||||||
err := hcsUnregisterProcessCallback(handle)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
closeChannels(context.channels)
|
|
||||||
|
|
||||||
callbackMapLock.Lock()
|
|
||||||
callbackMap[callbackNumber] = nil
|
|
||||||
callbackMapLock.Unlock()
|
|
||||||
|
|
||||||
handle = 0
|
|
||||||
|
|
||||||
return nil
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,27 +0,0 @@
|
||||||
package hcsshim
|
|
||||||
|
|
||||||
import "github.com/sirupsen/logrus"
|
|
||||||
|
|
||||||
// UnprepareLayer disables the filesystem filter for the read-write layer with
|
|
||||||
// the given id.
|
|
||||||
func UnprepareLayer(info DriverInfo, layerId string) error {
|
|
||||||
title := "hcsshim::UnprepareLayer "
|
|
||||||
logrus.Debugf(title+"flavour %d layerId %s", info.Flavour, layerId)
|
|
||||||
|
|
||||||
// Convert info to API calling convention
|
|
||||||
infop, err := convertDriverInfo(info)
|
|
||||||
if err != nil {
|
|
||||||
logrus.Error(err)
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
err = unprepareLayer(&infop, layerId)
|
|
||||||
if err != nil {
|
|
||||||
err = makeErrorf(err, title, "layerId=%s flavour=%d", layerId, info.Flavour)
|
|
||||||
logrus.Error(err)
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
logrus.Debugf(title+"succeeded flavour %d layerId=%s", info.Flavour, layerId)
|
|
||||||
return nil
|
|
||||||
}
|
|
|
@ -2,6 +2,5 @@ package hcsshim
|
||||||
|
|
||||||
// IsTP4 returns whether the currently running Windows build is at least TP4.
|
// IsTP4 returns whether the currently running Windows build is at least TP4.
|
||||||
func IsTP4() bool {
|
func IsTP4() bool {
|
||||||
// HNSCall was not present in TP4
|
return false
|
||||||
return procHNSCall.Find() != nil
|
|
||||||
}
|
}
|
||||||
|
|
File diff suppressed because it is too large
Load Diff
|
@ -0,0 +1,52 @@
|
||||||
|
// MACHINE GENERATED BY 'go generate' COMMAND; DO NOT EDIT
|
||||||
|
|
||||||
|
package hcsshim
|
||||||
|
|
||||||
|
import (
|
||||||
|
"syscall"
|
||||||
|
"unsafe"
|
||||||
|
|
||||||
|
"github.com/Microsoft/hcsshim/internal/interop"
|
||||||
|
"golang.org/x/sys/windows"
|
||||||
|
)
|
||||||
|
|
||||||
|
var _ unsafe.Pointer
|
||||||
|
|
||||||
|
// Do the interface allocations only once for common
|
||||||
|
// Errno values.
|
||||||
|
const (
|
||||||
|
errnoERROR_IO_PENDING = 997
|
||||||
|
)
|
||||||
|
|
||||||
|
var (
|
||||||
|
errERROR_IO_PENDING error = syscall.Errno(errnoERROR_IO_PENDING)
|
||||||
|
)
|
||||||
|
|
||||||
|
// errnoErr returns common boxed Errno values, to prevent
|
||||||
|
// allocations at runtime.
|
||||||
|
func errnoErr(e syscall.Errno) error {
|
||||||
|
switch e {
|
||||||
|
case 0:
|
||||||
|
return nil
|
||||||
|
case errnoERROR_IO_PENDING:
|
||||||
|
return errERROR_IO_PENDING
|
||||||
|
}
|
||||||
|
// TODO: add more here, after collecting data on the common
|
||||||
|
// error values see on Windows. (perhaps when running
|
||||||
|
// all.bat?)
|
||||||
|
return e
|
||||||
|
}
|
||||||
|
|
||||||
|
var (
|
||||||
|
modiphlpapi = windows.NewLazySystemDLL("iphlpapi.dll")
|
||||||
|
|
||||||
|
procSetCurrentThreadCompartmentId = modiphlpapi.NewProc("SetCurrentThreadCompartmentId")
|
||||||
|
)
|
||||||
|
|
||||||
|
func SetCurrentThreadCompartmentId(compartmentId uint32) (hr error) {
|
||||||
|
r0, _, _ := syscall.Syscall(procSetCurrentThreadCompartmentId.Addr(), 1, uintptr(compartmentId), 0, 0)
|
||||||
|
if int32(r0) < 0 {
|
||||||
|
hr = interop.Win32FromHresult(r0)
|
||||||
|
}
|
||||||
|
return
|
||||||
|
}
|
|
@ -17,6 +17,7 @@
|
||||||
package console
|
package console
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"fmt"
|
||||||
"os"
|
"os"
|
||||||
|
|
||||||
"github.com/pkg/errors"
|
"github.com/pkg/errors"
|
||||||
|
@ -28,55 +29,90 @@ var (
|
||||||
ErrNotImplemented = errors.New("not implemented")
|
ErrNotImplemented = errors.New("not implemented")
|
||||||
)
|
)
|
||||||
|
|
||||||
func (m *master) init() {
|
func (m *master) initStdios() {
|
||||||
m.h = windows.Handle(m.f.Fd())
|
m.in = windows.Handle(os.Stdin.Fd())
|
||||||
if err := windows.GetConsoleMode(m.h, &m.mode); err == nil {
|
if err := windows.GetConsoleMode(m.in, &m.inMode); err == nil {
|
||||||
if m.f == os.Stdin {
|
// Validate that windows.ENABLE_VIRTUAL_TERMINAL_INPUT is supported, but do not set it.
|
||||||
// Validate that windows.ENABLE_VIRTUAL_TERMINAL_INPUT is supported, but do not set it.
|
if err = windows.SetConsoleMode(m.in, m.inMode|windows.ENABLE_VIRTUAL_TERMINAL_INPUT); err == nil {
|
||||||
if err = windows.SetConsoleMode(m.h, m.mode|windows.ENABLE_VIRTUAL_TERMINAL_INPUT); err == nil {
|
vtInputSupported = true
|
||||||
vtInputSupported = true
|
|
||||||
}
|
|
||||||
// Unconditionally set the console mode back even on failure because SetConsoleMode
|
|
||||||
// remembers invalid bits on input handles.
|
|
||||||
windows.SetConsoleMode(m.h, m.mode)
|
|
||||||
} else if err := windows.SetConsoleMode(m.h, m.mode|windows.ENABLE_VIRTUAL_TERMINAL_PROCESSING); err == nil {
|
|
||||||
m.mode |= windows.ENABLE_VIRTUAL_TERMINAL_PROCESSING
|
|
||||||
} else {
|
|
||||||
windows.SetConsoleMode(m.h, m.mode)
|
|
||||||
}
|
}
|
||||||
|
// Unconditionally set the console mode back even on failure because SetConsoleMode
|
||||||
|
// remembers invalid bits on input handles.
|
||||||
|
windows.SetConsoleMode(m.in, m.inMode)
|
||||||
|
} else {
|
||||||
|
fmt.Printf("failed to get console mode for stdin: %v\n", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
m.out = windows.Handle(os.Stdout.Fd())
|
||||||
|
if err := windows.GetConsoleMode(m.out, &m.outMode); err == nil {
|
||||||
|
if err := windows.SetConsoleMode(m.out, m.outMode|windows.ENABLE_VIRTUAL_TERMINAL_PROCESSING); err == nil {
|
||||||
|
m.outMode |= windows.ENABLE_VIRTUAL_TERMINAL_PROCESSING
|
||||||
|
} else {
|
||||||
|
windows.SetConsoleMode(m.out, m.outMode)
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
fmt.Printf("failed to get console mode for stdout: %v\n", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
m.err = windows.Handle(os.Stderr.Fd())
|
||||||
|
if err := windows.GetConsoleMode(m.err, &m.errMode); err == nil {
|
||||||
|
if err := windows.SetConsoleMode(m.err, m.errMode|windows.ENABLE_VIRTUAL_TERMINAL_PROCESSING); err == nil {
|
||||||
|
m.errMode |= windows.ENABLE_VIRTUAL_TERMINAL_PROCESSING
|
||||||
|
} else {
|
||||||
|
windows.SetConsoleMode(m.err, m.errMode)
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
fmt.Printf("failed to get console mode for stderr: %v\n", err)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
type master struct {
|
type master struct {
|
||||||
h windows.Handle
|
in windows.Handle
|
||||||
mode uint32
|
inMode uint32
|
||||||
f *os.File
|
|
||||||
|
out windows.Handle
|
||||||
|
outMode uint32
|
||||||
|
|
||||||
|
err windows.Handle
|
||||||
|
errMode uint32
|
||||||
}
|
}
|
||||||
|
|
||||||
func (m *master) SetRaw() error {
|
func (m *master) SetRaw() error {
|
||||||
if m.f == os.Stdin {
|
if err := makeInputRaw(m.in, m.inMode); err != nil {
|
||||||
if err := makeInputRaw(m.h, m.mode); err != nil {
|
return err
|
||||||
return err
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
// Set StdOut and StdErr to raw mode, we ignore failures since
|
|
||||||
// windows.DISABLE_NEWLINE_AUTO_RETURN might not be supported on this version of
|
|
||||||
// Windows.
|
|
||||||
windows.SetConsoleMode(m.h, m.mode|windows.DISABLE_NEWLINE_AUTO_RETURN)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Set StdOut and StdErr to raw mode, we ignore failures since
|
||||||
|
// windows.DISABLE_NEWLINE_AUTO_RETURN might not be supported on this version of
|
||||||
|
// Windows.
|
||||||
|
|
||||||
|
windows.SetConsoleMode(m.out, m.outMode|windows.DISABLE_NEWLINE_AUTO_RETURN)
|
||||||
|
|
||||||
|
windows.SetConsoleMode(m.err, m.errMode|windows.DISABLE_NEWLINE_AUTO_RETURN)
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (m *master) Reset() error {
|
func (m *master) Reset() error {
|
||||||
if err := windows.SetConsoleMode(m.h, m.mode); err != nil {
|
for _, s := range []struct {
|
||||||
return errors.Wrap(err, "unable to restore console mode")
|
fd windows.Handle
|
||||||
|
mode uint32
|
||||||
|
}{
|
||||||
|
{m.in, m.inMode},
|
||||||
|
{m.out, m.outMode},
|
||||||
|
{m.err, m.errMode},
|
||||||
|
} {
|
||||||
|
if err := windows.SetConsoleMode(s.fd, s.mode); err != nil {
|
||||||
|
return errors.Wrap(err, "unable to restore console mode")
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (m *master) Size() (WinSize, error) {
|
func (m *master) Size() (WinSize, error) {
|
||||||
var info windows.ConsoleScreenBufferInfo
|
var info windows.ConsoleScreenBufferInfo
|
||||||
err := windows.GetConsoleScreenBufferInfo(m.h, &info)
|
err := windows.GetConsoleScreenBufferInfo(m.out, &info)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return WinSize{}, errors.Wrap(err, "unable to get console info")
|
return WinSize{}, errors.Wrap(err, "unable to get console info")
|
||||||
}
|
}
|
||||||
|
@ -98,11 +134,11 @@ func (m *master) ResizeFrom(c Console) error {
|
||||||
}
|
}
|
||||||
|
|
||||||
func (m *master) DisableEcho() error {
|
func (m *master) DisableEcho() error {
|
||||||
mode := m.mode &^ windows.ENABLE_ECHO_INPUT
|
mode := m.inMode &^ windows.ENABLE_ECHO_INPUT
|
||||||
mode |= windows.ENABLE_PROCESSED_INPUT
|
mode |= windows.ENABLE_PROCESSED_INPUT
|
||||||
mode |= windows.ENABLE_LINE_INPUT
|
mode |= windows.ENABLE_LINE_INPUT
|
||||||
|
|
||||||
if err := windows.SetConsoleMode(m.h, mode); err != nil {
|
if err := windows.SetConsoleMode(m.in, mode); err != nil {
|
||||||
return errors.Wrap(err, "unable to set console to disable echo")
|
return errors.Wrap(err, "unable to set console to disable echo")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -114,15 +150,15 @@ func (m *master) Close() error {
|
||||||
}
|
}
|
||||||
|
|
||||||
func (m *master) Read(b []byte) (int, error) {
|
func (m *master) Read(b []byte) (int, error) {
|
||||||
return m.f.Read(b)
|
return os.Stdin.Read(b)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (m *master) Write(b []byte) (int, error) {
|
func (m *master) Write(b []byte) (int, error) {
|
||||||
return m.f.Write(b)
|
return os.Stdout.Write(b)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (m *master) Fd() uintptr {
|
func (m *master) Fd() uintptr {
|
||||||
return uintptr(m.h)
|
return uintptr(m.in)
|
||||||
}
|
}
|
||||||
|
|
||||||
// on windows, console can only be made from os.Std{in,out,err}, hence there
|
// on windows, console can only be made from os.Std{in,out,err}, hence there
|
||||||
|
@ -174,7 +210,7 @@ func newMaster(f *os.File) (Console, error) {
|
||||||
if f != os.Stdin && f != os.Stdout && f != os.Stderr {
|
if f != os.Stdin && f != os.Stdout && f != os.Stderr {
|
||||||
return nil, errors.New("creating a console from a file is not supported on windows")
|
return nil, errors.New("creating a console from a file is not supported on windows")
|
||||||
}
|
}
|
||||||
m := &master{f: f}
|
m := &master{}
|
||||||
m.init()
|
m.initStdios()
|
||||||
return m, nil
|
return m, nil
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
![banner](/docs/static/img/containerd-dark.png?raw=true)
|
![banner](https://github.com/containerd/containerd.io/blob/master/static/img/containerd-dark.png?raw=true)
|
||||||
|
|
||||||
[![GoDoc](https://godoc.org/github.com/containerd/containerd?status.svg)](https://godoc.org/github.com/containerd/containerd)
|
[![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)
|
[![Build Status](https://travis-ci.org/containerd/containerd.svg?branch=master)](https://travis-ci.org/containerd/containerd)
|
||||||
|
|
|
@ -259,7 +259,7 @@ func fileInfoFromHeader(hdr *tar.Header) (name string, size int64, fileInfo *win
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return "", 0, nil, err
|
return "", 0, nil, err
|
||||||
}
|
}
|
||||||
fileInfo.FileAttributes = uintptr(attr)
|
fileInfo.FileAttributes = uint32(attr)
|
||||||
} else {
|
} else {
|
||||||
if hdr.Typeflag == tar.TypeDir {
|
if hdr.Typeflag == tar.TypeDir {
|
||||||
fileInfo.FileAttributes |= syscall.FILE_ATTRIBUTE_DIRECTORY
|
fileInfo.FileAttributes |= syscall.FILE_ATTRIBUTE_DIRECTORY
|
||||||
|
|
|
@ -74,7 +74,7 @@ func copyIO(fifos *FIFOSet, ioset *Streams) (*cio, error) {
|
||||||
if fifos.Stdout != "" {
|
if fifos.Stdout != "" {
|
||||||
l, err := winio.ListenPipe(fifos.Stdout, nil)
|
l, err := winio.ListenPipe(fifos.Stdout, nil)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, errors.Wrapf(err, "failed to create stdin pipe %s", fifos.Stdout)
|
return nil, errors.Wrapf(err, "failed to create stdout pipe %s", fifos.Stdout)
|
||||||
}
|
}
|
||||||
defer func(l net.Listener) {
|
defer func(l net.Listener) {
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
@ -99,7 +99,7 @@ func copyIO(fifos *FIFOSet, ioset *Streams) (*cio, error) {
|
||||||
}()
|
}()
|
||||||
}
|
}
|
||||||
|
|
||||||
if !fifos.Terminal && fifos.Stderr != "" {
|
if fifos.Stderr != "" {
|
||||||
l, err := winio.ListenPipe(fifos.Stderr, nil)
|
l, err := winio.ListenPipe(fifos.Stderr, nil)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, errors.Wrapf(err, "failed to create stderr pipe %s", fifos.Stderr)
|
return nil, errors.Wrapf(err, "failed to create stderr pipe %s", fifos.Stderr)
|
||||||
|
|
|
@ -82,6 +82,9 @@ func New(address string, opts ...ClientOpt) (*Client, error) {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
if copts.timeout == 0 {
|
||||||
|
copts.timeout = 10 * time.Second
|
||||||
|
}
|
||||||
rt := fmt.Sprintf("%s.%s", plugin.RuntimePlugin, runtime.GOOS)
|
rt := fmt.Sprintf("%s.%s", plugin.RuntimePlugin, runtime.GOOS)
|
||||||
if copts.defaultRuntime != "" {
|
if copts.defaultRuntime != "" {
|
||||||
rt = copts.defaultRuntime
|
rt = copts.defaultRuntime
|
||||||
|
@ -115,7 +118,7 @@ func New(address string, opts ...ClientOpt) (*Client, error) {
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
connector := func() (*grpc.ClientConn, error) {
|
connector := func() (*grpc.ClientConn, error) {
|
||||||
ctx, cancel := context.WithTimeout(context.Background(), 60*time.Second)
|
ctx, cancel := context.WithTimeout(context.Background(), copts.timeout)
|
||||||
defer cancel()
|
defer cancel()
|
||||||
conn, err := grpc.DialContext(ctx, dialer.DialAddress(address), gopts...)
|
conn, err := grpc.DialContext(ctx, dialer.DialAddress(address), gopts...)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
@ -256,9 +259,10 @@ type RemoteContext struct {
|
||||||
// If no resolver is provided, defaults to Docker registry resolver.
|
// If no resolver is provided, defaults to Docker registry resolver.
|
||||||
Resolver remotes.Resolver
|
Resolver remotes.Resolver
|
||||||
|
|
||||||
// Platforms defines which platforms to handle when doing the image operation.
|
// PlatformMatcher is used to match the platforms for an image
|
||||||
// If this field is empty, content for all platforms will be pulled.
|
// operation and define the preference when a single match is required
|
||||||
Platforms []string
|
// from multiple platforms.
|
||||||
|
PlatformMatcher platforms.MatchComparer
|
||||||
|
|
||||||
// Unpack is done after an image is pulled to extract into a snapshotter.
|
// Unpack is done after an image is pulled to extract into a snapshotter.
|
||||||
// If an image is not unpacked on pull, it can be unpacked any time
|
// If an image is not unpacked on pull, it can be unpacked any time
|
||||||
|
@ -280,6 +284,12 @@ type RemoteContext struct {
|
||||||
// manifests. If this option is false then any image which resolves
|
// manifests. If this option is false then any image which resolves
|
||||||
// to schema 1 will return an error since schema 1 is not supported.
|
// to schema 1 will return an error since schema 1 is not supported.
|
||||||
ConvertSchema1 bool
|
ConvertSchema1 bool
|
||||||
|
|
||||||
|
// Platforms defines which platforms to handle when doing the image operation.
|
||||||
|
// Platforms is ignored when a PlatformMatcher is set, otherwise the
|
||||||
|
// platforms will be used to create a PlatformMatcher with no ordering
|
||||||
|
// preference.
|
||||||
|
Platforms []string
|
||||||
}
|
}
|
||||||
|
|
||||||
func defaultRemoteContext() *RemoteContext {
|
func defaultRemoteContext() *RemoteContext {
|
||||||
|
@ -305,13 +315,30 @@ func (c *Client) Fetch(ctx context.Context, ref string, opts ...RemoteOpt) (imag
|
||||||
return images.Image{}, errors.New("unpack on fetch not supported, try pull")
|
return images.Image{}, errors.New("unpack on fetch not supported, try pull")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if fetchCtx.PlatformMatcher == nil {
|
||||||
|
if len(fetchCtx.Platforms) == 0 {
|
||||||
|
fetchCtx.PlatformMatcher = platforms.All
|
||||||
|
} else {
|
||||||
|
var ps []ocispec.Platform
|
||||||
|
for _, s := range fetchCtx.Platforms {
|
||||||
|
p, err := platforms.Parse(s)
|
||||||
|
if err != nil {
|
||||||
|
return images.Image{}, errors.Wrapf(err, "invalid platform %s", s)
|
||||||
|
}
|
||||||
|
ps = append(ps, p)
|
||||||
|
}
|
||||||
|
|
||||||
|
fetchCtx.PlatformMatcher = platforms.Any(ps...)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
ctx, done, err := c.WithLease(ctx)
|
ctx, done, err := c.WithLease(ctx)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return images.Image{}, err
|
return images.Image{}, err
|
||||||
}
|
}
|
||||||
defer done(ctx)
|
defer done(ctx)
|
||||||
|
|
||||||
return c.fetch(ctx, fetchCtx, ref)
|
return c.fetch(ctx, fetchCtx, ref, 0)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Pull downloads the provided content into containerd's content store
|
// Pull downloads the provided content into containerd's content store
|
||||||
|
@ -324,10 +351,19 @@ func (c *Client) Pull(ctx context.Context, ref string, opts ...RemoteOpt) (Image
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if len(pullCtx.Platforms) > 1 {
|
if pullCtx.PlatformMatcher == nil {
|
||||||
return nil, errors.New("cannot pull multiplatform image locally, try Fetch")
|
if len(pullCtx.Platforms) > 1 {
|
||||||
} else if len(pullCtx.Platforms) == 0 {
|
return nil, errors.New("cannot pull multiplatform image locally, try Fetch")
|
||||||
pullCtx.Platforms = []string{platforms.Default()}
|
} else if len(pullCtx.Platforms) == 0 {
|
||||||
|
pullCtx.PlatformMatcher = platforms.Default()
|
||||||
|
} else {
|
||||||
|
p, err := platforms.Parse(pullCtx.Platforms[0])
|
||||||
|
if err != nil {
|
||||||
|
return nil, errors.Wrapf(err, "invalid platform %s", pullCtx.Platforms[0])
|
||||||
|
}
|
||||||
|
|
||||||
|
pullCtx.PlatformMatcher = platforms.Only(p)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
ctx, done, err := c.WithLease(ctx)
|
ctx, done, err := c.WithLease(ctx)
|
||||||
|
@ -336,12 +372,12 @@ func (c *Client) Pull(ctx context.Context, ref string, opts ...RemoteOpt) (Image
|
||||||
}
|
}
|
||||||
defer done(ctx)
|
defer done(ctx)
|
||||||
|
|
||||||
img, err := c.fetch(ctx, pullCtx, ref)
|
img, err := c.fetch(ctx, pullCtx, ref, 1)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
i := NewImageWithPlatform(c, img, pullCtx.Platforms[0])
|
i := NewImageWithPlatform(c, img, pullCtx.PlatformMatcher)
|
||||||
|
|
||||||
if pullCtx.Unpack {
|
if pullCtx.Unpack {
|
||||||
if err := i.Unpack(ctx, pullCtx.Snapshotter); err != nil {
|
if err := i.Unpack(ctx, pullCtx.Snapshotter); err != nil {
|
||||||
|
@ -352,7 +388,7 @@ func (c *Client) Pull(ctx context.Context, ref string, opts ...RemoteOpt) (Image
|
||||||
return i, nil
|
return i, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *Client) fetch(ctx context.Context, rCtx *RemoteContext, ref string) (images.Image, error) {
|
func (c *Client) fetch(ctx context.Context, rCtx *RemoteContext, ref string, limit int) (images.Image, error) {
|
||||||
store := c.ContentStore()
|
store := c.ContentStore()
|
||||||
name, desc, err := rCtx.Resolver.Resolve(ctx, ref)
|
name, desc, err := rCtx.Resolver.Resolve(ctx, ref)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
@ -377,7 +413,11 @@ func (c *Client) fetch(ctx context.Context, rCtx *RemoteContext, ref string) (im
|
||||||
// Set any children labels for that content
|
// Set any children labels for that content
|
||||||
childrenHandler = images.SetChildrenLabels(store, childrenHandler)
|
childrenHandler = images.SetChildrenLabels(store, childrenHandler)
|
||||||
// Filter children by platforms
|
// Filter children by platforms
|
||||||
childrenHandler = images.FilterPlatforms(childrenHandler, rCtx.Platforms...)
|
childrenHandler = images.FilterPlatforms(childrenHandler, rCtx.PlatformMatcher)
|
||||||
|
// Sort and limit manifests if a finite number is needed
|
||||||
|
if limit > 0 {
|
||||||
|
childrenHandler = images.LimitManifests(childrenHandler, rCtx.PlatformMatcher, limit)
|
||||||
|
}
|
||||||
|
|
||||||
handler = images.Handlers(append(rCtx.BaseHandlers,
|
handler = images.Handlers(append(rCtx.BaseHandlers,
|
||||||
remotes.FetchHandler(store, fetcher),
|
remotes.FetchHandler(store, fetcher),
|
||||||
|
@ -434,13 +474,28 @@ func (c *Client) Push(ctx context.Context, ref string, desc ocispec.Descriptor,
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
if pushCtx.PlatformMatcher == nil {
|
||||||
|
if len(pushCtx.Platforms) > 0 {
|
||||||
|
var ps []ocispec.Platform
|
||||||
|
for _, platform := range pushCtx.Platforms {
|
||||||
|
p, err := platforms.Parse(platform)
|
||||||
|
if err != nil {
|
||||||
|
return errors.Wrapf(err, "invalid platform %s", platform)
|
||||||
|
}
|
||||||
|
ps = append(ps, p)
|
||||||
|
}
|
||||||
|
pushCtx.PlatformMatcher = platforms.Any(ps...)
|
||||||
|
} else {
|
||||||
|
pushCtx.PlatformMatcher = platforms.All
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
pusher, err := pushCtx.Resolver.Pusher(ctx, ref)
|
pusher, err := pushCtx.Resolver.Pusher(ctx, ref)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
return remotes.PushContent(ctx, pusher, desc, c.ContentStore(), pushCtx.Platforms, pushCtx.BaseHandlers...)
|
return remotes.PushContent(ctx, pusher, desc, c.ContentStore(), pushCtx.PlatformMatcher, pushCtx.BaseHandlers...)
|
||||||
}
|
}
|
||||||
|
|
||||||
// GetImage returns an existing image
|
// GetImage returns an existing image
|
||||||
|
|
|
@ -17,6 +17,8 @@
|
||||||
package containerd
|
package containerd
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"time"
|
||||||
|
|
||||||
"github.com/containerd/containerd/images"
|
"github.com/containerd/containerd/images"
|
||||||
"github.com/containerd/containerd/platforms"
|
"github.com/containerd/containerd/platforms"
|
||||||
"github.com/containerd/containerd/remotes"
|
"github.com/containerd/containerd/remotes"
|
||||||
|
@ -28,6 +30,7 @@ type clientOpts struct {
|
||||||
defaultRuntime string
|
defaultRuntime string
|
||||||
services *services
|
services *services
|
||||||
dialOptions []grpc.DialOption
|
dialOptions []grpc.DialOption
|
||||||
|
timeout time.Duration
|
||||||
}
|
}
|
||||||
|
|
||||||
// ClientOpt allows callers to set options on the containerd client
|
// ClientOpt allows callers to set options on the containerd client
|
||||||
|
@ -71,6 +74,14 @@ func WithServices(opts ...ServicesOpt) ClientOpt {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// WithTimeout sets the connection timeout for the client
|
||||||
|
func WithTimeout(d time.Duration) ClientOpt {
|
||||||
|
return func(c *clientOpts) error {
|
||||||
|
c.timeout = d
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// RemoteOpt allows the caller to set distribution options for a remote
|
// RemoteOpt allows the caller to set distribution options for a remote
|
||||||
type RemoteOpt func(*Client, *RemoteContext) error
|
type RemoteOpt func(*Client, *RemoteContext) error
|
||||||
|
|
||||||
|
@ -78,7 +89,7 @@ type RemoteOpt func(*Client, *RemoteContext) error
|
||||||
// content for
|
// content for
|
||||||
func WithPlatform(platform string) RemoteOpt {
|
func WithPlatform(platform string) RemoteOpt {
|
||||||
if platform == "" {
|
if platform == "" {
|
||||||
platform = platforms.Default()
|
platform = platforms.DefaultString()
|
||||||
}
|
}
|
||||||
return func(_ *Client, c *RemoteContext) error {
|
return func(_ *Client, c *RemoteContext) error {
|
||||||
for _, p := range c.Platforms {
|
for _, p := range c.Platforms {
|
||||||
|
@ -92,6 +103,16 @@ func WithPlatform(platform string) RemoteOpt {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// WithPlatformMatcher specifies the matcher to use for
|
||||||
|
// determining which platforms to pull content for.
|
||||||
|
// This value supersedes anything set with `WithPlatform`.
|
||||||
|
func WithPlatformMatcher(m platforms.MatchComparer) RemoteOpt {
|
||||||
|
return func(_ *Client, c *RemoteContext) error {
|
||||||
|
c.PlatformMatcher = m
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// WithPullUnpack is used to unpack an image after pull. This
|
// WithPullUnpack is used to unpack an image after pull. This
|
||||||
// uses the snapshotter, content store, and diff service
|
// uses the snapshotter, content store, and diff service
|
||||||
// configured for the client.
|
// configured for the client.
|
||||||
|
|
|
@ -63,7 +63,7 @@ func NewImage(client *Client, i images.Image) Image {
|
||||||
}
|
}
|
||||||
|
|
||||||
// NewImageWithPlatform returns a client image object from the metadata image
|
// NewImageWithPlatform returns a client image object from the metadata image
|
||||||
func NewImageWithPlatform(client *Client, i images.Image, platform string) Image {
|
func NewImageWithPlatform(client *Client, i images.Image, platform platforms.MatchComparer) Image {
|
||||||
return &image{
|
return &image{
|
||||||
client: client,
|
client: client,
|
||||||
i: i,
|
i: i,
|
||||||
|
@ -75,7 +75,7 @@ type image struct {
|
||||||
client *Client
|
client *Client
|
||||||
|
|
||||||
i images.Image
|
i images.Image
|
||||||
platform string
|
platform platforms.MatchComparer
|
||||||
}
|
}
|
||||||
|
|
||||||
func (i *image) Name() string {
|
func (i *image) Name() string {
|
||||||
|
@ -186,7 +186,7 @@ func (i *image) Unpack(ctx context.Context, snapshotterName string) error {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (i *image) getLayers(ctx context.Context, platform string) ([]rootfs.Layer, error) {
|
func (i *image) getLayers(ctx context.Context, platform platforms.MatchComparer) ([]rootfs.Layer, error) {
|
||||||
cs := i.client.ContentStore()
|
cs := i.client.ContentStore()
|
||||||
|
|
||||||
manifest, err := images.Manifest(ctx, cs, i.i.Target, platform)
|
manifest, err := images.Manifest(ctx, cs, i.i.Target, platform)
|
||||||
|
|
|
@ -19,6 +19,7 @@ package images
|
||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
"fmt"
|
"fmt"
|
||||||
|
"sort"
|
||||||
|
|
||||||
"github.com/containerd/containerd/content"
|
"github.com/containerd/containerd/content"
|
||||||
"github.com/containerd/containerd/platforms"
|
"github.com/containerd/containerd/platforms"
|
||||||
|
@ -183,8 +184,8 @@ func SetChildrenLabels(manager content.Manager, f HandlerFunc) HandlerFunc {
|
||||||
}
|
}
|
||||||
|
|
||||||
// FilterPlatforms is a handler wrapper which limits the descriptors returned
|
// FilterPlatforms is a handler wrapper which limits the descriptors returned
|
||||||
// by a handler to the specified platforms.
|
// based on matching the specified platform matcher.
|
||||||
func FilterPlatforms(f HandlerFunc, platformList ...string) HandlerFunc {
|
func FilterPlatforms(f HandlerFunc, m platforms.Matcher) HandlerFunc {
|
||||||
return func(ctx context.Context, desc ocispec.Descriptor) ([]ocispec.Descriptor, error) {
|
return func(ctx context.Context, desc ocispec.Descriptor) ([]ocispec.Descriptor, error) {
|
||||||
children, err := f(ctx, desc)
|
children, err := f(ctx, desc)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
@ -193,20 +194,12 @@ func FilterPlatforms(f HandlerFunc, platformList ...string) HandlerFunc {
|
||||||
|
|
||||||
var descs []ocispec.Descriptor
|
var descs []ocispec.Descriptor
|
||||||
|
|
||||||
if len(platformList) == 0 {
|
if m == nil {
|
||||||
descs = children
|
descs = children
|
||||||
} else {
|
} else {
|
||||||
for _, platform := range platformList {
|
for _, d := range children {
|
||||||
p, err := platforms.Parse(platform)
|
if d.Platform == nil || m.Match(*d.Platform) {
|
||||||
if err != nil {
|
descs = append(descs, d)
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
matcher := platforms.NewMatcher(p)
|
|
||||||
|
|
||||||
for _, d := range children {
|
|
||||||
if d.Platform == nil || matcher.Match(*d.Platform) {
|
|
||||||
descs = append(descs, d)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -214,3 +207,37 @@ func FilterPlatforms(f HandlerFunc, platformList ...string) HandlerFunc {
|
||||||
return descs, nil
|
return descs, nil
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// LimitManifests is a handler wrapper which filters the manifest descriptors
|
||||||
|
// returned using the provided platform.
|
||||||
|
// The results will be ordered according to the comparison operator and
|
||||||
|
// use the ordering in the manifests for equal matches.
|
||||||
|
// A limit of 0 or less is considered no limit.
|
||||||
|
func LimitManifests(f HandlerFunc, m platforms.MatchComparer, n int) HandlerFunc {
|
||||||
|
return func(ctx context.Context, desc ocispec.Descriptor) ([]ocispec.Descriptor, error) {
|
||||||
|
children, err := f(ctx, desc)
|
||||||
|
if err != nil {
|
||||||
|
return children, err
|
||||||
|
}
|
||||||
|
|
||||||
|
switch desc.MediaType {
|
||||||
|
case ocispec.MediaTypeImageIndex, MediaTypeDockerSchema2ManifestList:
|
||||||
|
sort.SliceStable(children, func(i, j int) bool {
|
||||||
|
if children[i].Platform == nil {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
if children[j].Platform == nil {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
return m.Less(*children[i].Platform, *children[j].Platform)
|
||||||
|
})
|
||||||
|
|
||||||
|
if n > 0 && len(children) > n {
|
||||||
|
children = children[:n]
|
||||||
|
}
|
||||||
|
default:
|
||||||
|
// only limit manifests from an index
|
||||||
|
}
|
||||||
|
return children, nil
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
@ -19,6 +19,7 @@ package images
|
||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
"encoding/json"
|
"encoding/json"
|
||||||
|
"sort"
|
||||||
"strings"
|
"strings"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
|
@ -93,7 +94,7 @@ type Store interface {
|
||||||
//
|
//
|
||||||
// The caller can then use the descriptor to resolve and process the
|
// The caller can then use the descriptor to resolve and process the
|
||||||
// configuration of the image.
|
// configuration of the image.
|
||||||
func (image *Image) Config(ctx context.Context, provider content.Provider, platform string) (ocispec.Descriptor, error) {
|
func (image *Image) Config(ctx context.Context, provider content.Provider, platform platforms.MatchComparer) (ocispec.Descriptor, error) {
|
||||||
return Config(ctx, provider, image.Target, platform)
|
return Config(ctx, provider, image.Target, platform)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -101,7 +102,7 @@ func (image *Image) Config(ctx context.Context, provider content.Provider, platf
|
||||||
//
|
//
|
||||||
// These are used to verify that a set of layers unpacked to the expected
|
// These are used to verify that a set of layers unpacked to the expected
|
||||||
// values.
|
// values.
|
||||||
func (image *Image) RootFS(ctx context.Context, provider content.Provider, platform string) ([]digest.Digest, error) {
|
func (image *Image) RootFS(ctx context.Context, provider content.Provider, platform platforms.MatchComparer) ([]digest.Digest, error) {
|
||||||
desc, err := image.Config(ctx, provider, platform)
|
desc, err := image.Config(ctx, provider, platform)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
|
@ -110,7 +111,7 @@ func (image *Image) RootFS(ctx context.Context, provider content.Provider, platf
|
||||||
}
|
}
|
||||||
|
|
||||||
// Size returns the total size of an image's packed resources.
|
// Size returns the total size of an image's packed resources.
|
||||||
func (image *Image) Size(ctx context.Context, provider content.Provider, platform string) (int64, error) {
|
func (image *Image) Size(ctx context.Context, provider content.Provider, platform platforms.MatchComparer) (int64, error) {
|
||||||
var size int64
|
var size int64
|
||||||
return size, Walk(ctx, Handlers(HandlerFunc(func(ctx context.Context, desc ocispec.Descriptor) ([]ocispec.Descriptor, error) {
|
return size, Walk(ctx, Handlers(HandlerFunc(func(ctx context.Context, desc ocispec.Descriptor) ([]ocispec.Descriptor, error) {
|
||||||
if desc.Size < 0 {
|
if desc.Size < 0 {
|
||||||
|
@ -121,27 +122,22 @@ func (image *Image) Size(ctx context.Context, provider content.Provider, platfor
|
||||||
}), FilterPlatforms(ChildrenHandler(provider), platform)), image.Target)
|
}), FilterPlatforms(ChildrenHandler(provider), platform)), image.Target)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type platformManifest struct {
|
||||||
|
p *ocispec.Platform
|
||||||
|
m *ocispec.Manifest
|
||||||
|
}
|
||||||
|
|
||||||
// Manifest resolves a manifest from the image for the given platform.
|
// Manifest resolves a manifest from the image for the given platform.
|
||||||
//
|
//
|
||||||
// TODO(stevvooe): This violates the current platform agnostic approach to this
|
// TODO(stevvooe): This violates the current platform agnostic approach to this
|
||||||
// package by returning a specific manifest type. We'll need to refactor this
|
// package by returning a specific manifest type. We'll need to refactor this
|
||||||
// to return a manifest descriptor or decide that we want to bring the API in
|
// to return a manifest descriptor or decide that we want to bring the API in
|
||||||
// this direction because this abstraction is not needed.`
|
// this direction because this abstraction is not needed.`
|
||||||
func Manifest(ctx context.Context, provider content.Provider, image ocispec.Descriptor, platform string) (ocispec.Manifest, error) {
|
func Manifest(ctx context.Context, provider content.Provider, image ocispec.Descriptor, platform platforms.MatchComparer) (ocispec.Manifest, error) {
|
||||||
var (
|
var (
|
||||||
matcher platforms.Matcher
|
m []platformManifest
|
||||||
m *ocispec.Manifest
|
|
||||||
p ocispec.Platform
|
|
||||||
wasIndex bool
|
wasIndex bool
|
||||||
)
|
)
|
||||||
if platform != "" {
|
|
||||||
var err error
|
|
||||||
p, err = platforms.Parse(platform)
|
|
||||||
if err != nil {
|
|
||||||
return ocispec.Manifest{}, err
|
|
||||||
}
|
|
||||||
matcher = platforms.NewMatcher(p)
|
|
||||||
}
|
|
||||||
|
|
||||||
if err := Walk(ctx, HandlerFunc(func(ctx context.Context, desc ocispec.Descriptor) ([]ocispec.Descriptor, error) {
|
if err := Walk(ctx, HandlerFunc(func(ctx context.Context, desc ocispec.Descriptor) ([]ocispec.Descriptor, error) {
|
||||||
switch desc.MediaType {
|
switch desc.MediaType {
|
||||||
|
@ -156,8 +152,8 @@ func Manifest(ctx context.Context, provider content.Provider, image ocispec.Desc
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
if platform != "" {
|
if platform != nil {
|
||||||
if desc.Platform != nil && !matcher.Match(*desc.Platform) {
|
if desc.Platform != nil && !platform.Match(*desc.Platform) {
|
||||||
return nil, nil
|
return nil, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -172,14 +168,17 @@ func Manifest(ctx context.Context, provider content.Provider, image ocispec.Desc
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
if !matcher.Match(platforms.Normalize(ocispec.Platform{OS: image.OS, Architecture: image.Architecture})) {
|
if !platform.Match(platforms.Normalize(ocispec.Platform{OS: image.OS, Architecture: image.Architecture})) {
|
||||||
return nil, nil
|
return nil, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
m = &manifest
|
m = append(m, platformManifest{
|
||||||
|
p: desc.Platform,
|
||||||
|
m: &manifest,
|
||||||
|
})
|
||||||
|
|
||||||
return nil, nil
|
return nil, nil
|
||||||
case MediaTypeDockerSchema2ManifestList, ocispec.MediaTypeImageIndex:
|
case MediaTypeDockerSchema2ManifestList, ocispec.MediaTypeImageIndex:
|
||||||
|
@ -193,13 +192,13 @@ func Manifest(ctx context.Context, provider content.Provider, image ocispec.Desc
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
if platform == "" {
|
if platform == nil {
|
||||||
return idx.Manifests, nil
|
return idx.Manifests, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
var descs []ocispec.Descriptor
|
var descs []ocispec.Descriptor
|
||||||
for _, d := range idx.Manifests {
|
for _, d := range idx.Manifests {
|
||||||
if d.Platform == nil || matcher.Match(*d.Platform) {
|
if d.Platform == nil || platform.Match(*d.Platform) {
|
||||||
descs = append(descs, d)
|
descs = append(descs, d)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -214,15 +213,25 @@ func Manifest(ctx context.Context, provider content.Provider, image ocispec.Desc
|
||||||
return ocispec.Manifest{}, err
|
return ocispec.Manifest{}, err
|
||||||
}
|
}
|
||||||
|
|
||||||
if m == nil {
|
if len(m) == 0 {
|
||||||
err := errors.Wrapf(errdefs.ErrNotFound, "manifest %v", image.Digest)
|
err := errors.Wrapf(errdefs.ErrNotFound, "manifest %v", image.Digest)
|
||||||
if wasIndex {
|
if wasIndex {
|
||||||
err = errors.Wrapf(errdefs.ErrNotFound, "no match for current platform %s in manifest %v", platforms.Format(p), image.Digest)
|
err = errors.Wrapf(errdefs.ErrNotFound, "no match for platform in manifest %v", image.Digest)
|
||||||
}
|
}
|
||||||
return ocispec.Manifest{}, err
|
return ocispec.Manifest{}, err
|
||||||
}
|
}
|
||||||
|
|
||||||
return *m, nil
|
sort.SliceStable(m, func(i, j int) bool {
|
||||||
|
if m[i].p == nil {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
if m[j].p == nil {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
return platform.Less(*m[i].p, *m[j].p)
|
||||||
|
})
|
||||||
|
|
||||||
|
return *m[0].m, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// Config resolves the image configuration descriptor using a content provided
|
// Config resolves the image configuration descriptor using a content provided
|
||||||
|
@ -230,7 +239,7 @@ func Manifest(ctx context.Context, provider content.Provider, image ocispec.Desc
|
||||||
//
|
//
|
||||||
// The caller can then use the descriptor to resolve and process the
|
// The caller can then use the descriptor to resolve and process the
|
||||||
// configuration of the image.
|
// configuration of the image.
|
||||||
func Config(ctx context.Context, provider content.Provider, image ocispec.Descriptor, platform string) (ocispec.Descriptor, error) {
|
func Config(ctx context.Context, provider content.Provider, image ocispec.Descriptor, platform platforms.MatchComparer) (ocispec.Descriptor, error) {
|
||||||
manifest, err := Manifest(ctx, provider, image, platform)
|
manifest, err := Manifest(ctx, provider, image, platform)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return ocispec.Descriptor{}, err
|
return ocispec.Descriptor{}, err
|
||||||
|
@ -276,7 +285,7 @@ func Platforms(ctx context.Context, provider content.Provider, image ocispec.Des
|
||||||
// in the provider.
|
// in the provider.
|
||||||
//
|
//
|
||||||
// If there is a problem resolving content, an error will be returned.
|
// If there is a problem resolving content, an error will be returned.
|
||||||
func Check(ctx context.Context, provider content.Provider, image ocispec.Descriptor, platform string) (available bool, required, present, missing []ocispec.Descriptor, err error) {
|
func Check(ctx context.Context, provider content.Provider, image ocispec.Descriptor, platform platforms.MatchComparer) (available bool, required, present, missing []ocispec.Descriptor, err error) {
|
||||||
mfst, err := Manifest(ctx, provider, image, platform)
|
mfst, err := Manifest(ctx, provider, image, platform)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
if errdefs.IsNotFound(err) {
|
if errdefs.IsNotFound(err) {
|
||||||
|
|
|
@ -143,6 +143,7 @@ func WithImageConfigArgs(image Image, args []string) SpecOpts {
|
||||||
cmd = args
|
cmd = args
|
||||||
}
|
}
|
||||||
s.Process.Args = append(config.Entrypoint, cmd...)
|
s.Process.Args = append(config.Entrypoint, cmd...)
|
||||||
|
|
||||||
cwd := config.WorkingDir
|
cwd := config.WorkingDir
|
||||||
if cwd == "" {
|
if cwd == "" {
|
||||||
cwd = "/"
|
cwd = "/"
|
||||||
|
@ -485,6 +486,18 @@ func getAllCapabilities() []string {
|
||||||
return caps
|
return caps
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// WithAmbientCapabilities set the Linux ambient capabilities for the process
|
||||||
|
// Ambient capabilities should only be set for non-root users or the caller should
|
||||||
|
// understand how these capabilities are used and set
|
||||||
|
func WithAmbientCapabilities(caps []string) SpecOpts {
|
||||||
|
return func(_ context.Context, _ Client, _ *containers.Container, s *Spec) error {
|
||||||
|
setCapabilities(s)
|
||||||
|
|
||||||
|
s.Process.Capabilities.Ambient = caps
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
var errNoUsersFound = errors.New("no users found")
|
var errNoUsersFound = errors.New("no users found")
|
||||||
|
|
||||||
func getUIDGIDFromPath(root string, filter func(user.User) bool) (uid, gid uint32, err error) {
|
func getUIDGIDFromPath(root string, filter func(user.User) bool) (uid, gid uint32, err error) {
|
||||||
|
|
|
@ -0,0 +1,192 @@
|
||||||
|
/*
|
||||||
|
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 platforms
|
||||||
|
|
||||||
|
import specs "github.com/opencontainers/image-spec/specs-go/v1"
|
||||||
|
|
||||||
|
// MatchComparer is able to match and compare platforms to
|
||||||
|
// filter and sort platforms.
|
||||||
|
type MatchComparer interface {
|
||||||
|
Matcher
|
||||||
|
|
||||||
|
Less(specs.Platform, specs.Platform) bool
|
||||||
|
}
|
||||||
|
|
||||||
|
// Only returns a match comparer for a single platform
|
||||||
|
// using default resolution logic for the platform.
|
||||||
|
//
|
||||||
|
// For ARMv7, will also match ARMv6 and ARMv5
|
||||||
|
// For ARMv6, will also match ARMv5
|
||||||
|
func Only(platform specs.Platform) MatchComparer {
|
||||||
|
platform = Normalize(platform)
|
||||||
|
if platform.Architecture == "arm" {
|
||||||
|
if platform.Variant == "v7" {
|
||||||
|
return orderedPlatformComparer{
|
||||||
|
matchers: []Matcher{
|
||||||
|
&matcher{
|
||||||
|
Platform: platform,
|
||||||
|
},
|
||||||
|
&matcher{
|
||||||
|
Platform: specs.Platform{
|
||||||
|
Architecture: platform.Architecture,
|
||||||
|
OS: platform.OS,
|
||||||
|
OSVersion: platform.OSVersion,
|
||||||
|
OSFeatures: platform.OSFeatures,
|
||||||
|
Variant: "v6",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
&matcher{
|
||||||
|
Platform: specs.Platform{
|
||||||
|
Architecture: platform.Architecture,
|
||||||
|
OS: platform.OS,
|
||||||
|
OSVersion: platform.OSVersion,
|
||||||
|
OSFeatures: platform.OSFeatures,
|
||||||
|
Variant: "v5",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if platform.Variant == "v6" {
|
||||||
|
return orderedPlatformComparer{
|
||||||
|
matchers: []Matcher{
|
||||||
|
&matcher{
|
||||||
|
Platform: platform,
|
||||||
|
},
|
||||||
|
&matcher{
|
||||||
|
Platform: specs.Platform{
|
||||||
|
Architecture: platform.Architecture,
|
||||||
|
OS: platform.OS,
|
||||||
|
OSVersion: platform.OSVersion,
|
||||||
|
OSFeatures: platform.OSFeatures,
|
||||||
|
Variant: "v5",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return singlePlatformComparer{
|
||||||
|
Matcher: &matcher{
|
||||||
|
Platform: platform,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Ordered returns a platform MatchComparer which matches any of the platforms
|
||||||
|
// but orders them in order they are provided.
|
||||||
|
func Ordered(platforms ...specs.Platform) MatchComparer {
|
||||||
|
matchers := make([]Matcher, len(platforms))
|
||||||
|
for i := range platforms {
|
||||||
|
matchers[i] = NewMatcher(platforms[i])
|
||||||
|
}
|
||||||
|
return orderedPlatformComparer{
|
||||||
|
matchers: matchers,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Any returns a platform MatchComparer which matches any of the platforms
|
||||||
|
// with no preference for ordering.
|
||||||
|
func Any(platforms ...specs.Platform) MatchComparer {
|
||||||
|
matchers := make([]Matcher, len(platforms))
|
||||||
|
for i := range platforms {
|
||||||
|
matchers[i] = NewMatcher(platforms[i])
|
||||||
|
}
|
||||||
|
return anyPlatformComparer{
|
||||||
|
matchers: matchers,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// All is a platform MatchComparer which matches all platforms
|
||||||
|
// with preference for ordering.
|
||||||
|
var All MatchComparer = allPlatformComparer{}
|
||||||
|
|
||||||
|
type singlePlatformComparer struct {
|
||||||
|
Matcher
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c singlePlatformComparer) Less(p1, p2 specs.Platform) bool {
|
||||||
|
return c.Match(p1) && !c.Match(p2)
|
||||||
|
}
|
||||||
|
|
||||||
|
type orderedPlatformComparer struct {
|
||||||
|
matchers []Matcher
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c orderedPlatformComparer) Match(platform specs.Platform) bool {
|
||||||
|
for _, m := range c.matchers {
|
||||||
|
if m.Match(platform) {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c orderedPlatformComparer) Less(p1 specs.Platform, p2 specs.Platform) bool {
|
||||||
|
for _, m := range c.matchers {
|
||||||
|
p1m := m.Match(p1)
|
||||||
|
p2m := m.Match(p2)
|
||||||
|
if p1m && !p2m {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
if p1m || p2m {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
type anyPlatformComparer struct {
|
||||||
|
matchers []Matcher
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c anyPlatformComparer) Match(platform specs.Platform) bool {
|
||||||
|
for _, m := range c.matchers {
|
||||||
|
if m.Match(platform) {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c anyPlatformComparer) Less(p1, p2 specs.Platform) bool {
|
||||||
|
var p1m, p2m bool
|
||||||
|
for _, m := range c.matchers {
|
||||||
|
if !p1m && m.Match(p1) {
|
||||||
|
p1m = true
|
||||||
|
}
|
||||||
|
if !p2m && m.Match(p2) {
|
||||||
|
p2m = true
|
||||||
|
}
|
||||||
|
if p1m && p2m {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// If one matches, and the other does, sort match first
|
||||||
|
return p1m && !p2m
|
||||||
|
}
|
||||||
|
|
||||||
|
type allPlatformComparer struct{}
|
||||||
|
|
||||||
|
func (allPlatformComparer) Match(specs.Platform) bool {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
|
func (allPlatformComparer) Less(specs.Platform, specs.Platform) bool {
|
||||||
|
return false
|
||||||
|
}
|
|
@ -22,8 +22,13 @@ import (
|
||||||
specs "github.com/opencontainers/image-spec/specs-go/v1"
|
specs "github.com/opencontainers/image-spec/specs-go/v1"
|
||||||
)
|
)
|
||||||
|
|
||||||
// Default returns the default specifier for the platform.
|
// Default returns the default matcher for the platform.
|
||||||
func Default() string {
|
func Default() MatchComparer {
|
||||||
|
return Only(DefaultSpec())
|
||||||
|
}
|
||||||
|
|
||||||
|
// DefaultString returns the default string specifier for the platform.
|
||||||
|
func DefaultString() string {
|
||||||
return Format(DefaultSpec())
|
return Format(DefaultSpec())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -27,6 +27,7 @@ import (
|
||||||
"github.com/containerd/containerd/errdefs"
|
"github.com/containerd/containerd/errdefs"
|
||||||
"github.com/containerd/containerd/images"
|
"github.com/containerd/containerd/images"
|
||||||
"github.com/containerd/containerd/log"
|
"github.com/containerd/containerd/log"
|
||||||
|
"github.com/containerd/containerd/platforms"
|
||||||
ocispec "github.com/opencontainers/image-spec/specs-go/v1"
|
ocispec "github.com/opencontainers/image-spec/specs-go/v1"
|
||||||
"github.com/pkg/errors"
|
"github.com/pkg/errors"
|
||||||
"github.com/sirupsen/logrus"
|
"github.com/sirupsen/logrus"
|
||||||
|
@ -155,7 +156,7 @@ func push(ctx context.Context, provider content.Provider, pusher Pusher, desc oc
|
||||||
//
|
//
|
||||||
// Base handlers can be provided which will be called before any push specific
|
// Base handlers can be provided which will be called before any push specific
|
||||||
// handlers.
|
// handlers.
|
||||||
func PushContent(ctx context.Context, pusher Pusher, desc ocispec.Descriptor, provider content.Provider, platforms []string, baseHandlers ...images.Handler) error {
|
func PushContent(ctx context.Context, pusher Pusher, desc ocispec.Descriptor, provider content.Provider, platform platforms.MatchComparer, baseHandlers ...images.Handler) error {
|
||||||
var m sync.Mutex
|
var m sync.Mutex
|
||||||
manifestStack := []ocispec.Descriptor{}
|
manifestStack := []ocispec.Descriptor{}
|
||||||
|
|
||||||
|
@ -175,7 +176,7 @@ func PushContent(ctx context.Context, pusher Pusher, desc ocispec.Descriptor, pr
|
||||||
pushHandler := PushHandler(pusher, provider)
|
pushHandler := PushHandler(pusher, provider)
|
||||||
|
|
||||||
handlers := append(baseHandlers,
|
handlers := append(baseHandlers,
|
||||||
images.FilterPlatforms(images.ChildrenHandler(provider), platforms...),
|
images.FilterPlatforms(images.ChildrenHandler(provider), platform),
|
||||||
filterHandler,
|
filterHandler,
|
||||||
pushHandler,
|
pushHandler,
|
||||||
)
|
)
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
github.com/containerd/go-runc edcf3de1f4971445c42d61f20d506b30612aa031
|
github.com/containerd/go-runc acb7c88cac264acca9b5eae187a117f4d77a1292
|
||||||
github.com/containerd/console 4d8a41f4ce5b9bae77c41786ea2458330f43f081
|
github.com/containerd/console c12b1e7919c14469339a5d38f2f8ed9b64a9de23
|
||||||
github.com/containerd/cgroups 5e610833b72089b37d0e615de9a92dfc043757c2
|
github.com/containerd/cgroups 5e610833b72089b37d0e615de9a92dfc043757c2
|
||||||
github.com/containerd/typeurl a93fcdb778cd272c6e9b3028b2f42d813e785d40
|
github.com/containerd/typeurl a93fcdb778cd272c6e9b3028b2f42d813e785d40
|
||||||
github.com/containerd/fifo 3d5202aec260678c48179c56f40e6f38a095738c
|
github.com/containerd/fifo 3d5202aec260678c48179c56f40e6f38a095738c
|
||||||
|
@ -20,7 +20,7 @@ github.com/gogo/protobuf v1.0.0
|
||||||
github.com/gogo/googleapis 08a7655d27152912db7aaf4f983275eaf8d128ef
|
github.com/gogo/googleapis 08a7655d27152912db7aaf4f983275eaf8d128ef
|
||||||
github.com/golang/protobuf v1.1.0
|
github.com/golang/protobuf v1.1.0
|
||||||
github.com/opencontainers/runtime-spec d810dbc60d8c5aeeb3d054bd1132fab2121968ce # v1.0.1-43-gd810dbc
|
github.com/opencontainers/runtime-spec d810dbc60d8c5aeeb3d054bd1132fab2121968ce # v1.0.1-43-gd810dbc
|
||||||
github.com/opencontainers/runc 69663f0bd4b60df09991c08812a60108003fa340
|
github.com/opencontainers/runc 20aff4f0488c6d4b8df4d85b4f63f1f704c11abd
|
||||||
github.com/sirupsen/logrus v1.0.0
|
github.com/sirupsen/logrus v1.0.0
|
||||||
github.com/urfave/cli 7bc6a0acffa589f415f88aca16cc1de5ffd66f9c
|
github.com/urfave/cli 7bc6a0acffa589f415f88aca16cc1de5ffd66f9c
|
||||||
golang.org/x/net b3756b4b77d7b13260a0a2ec658753cf48922eac
|
golang.org/x/net b3756b4b77d7b13260a0a2ec658753cf48922eac
|
||||||
|
@ -32,8 +32,8 @@ github.com/opencontainers/image-spec v1.0.1
|
||||||
golang.org/x/sync 450f422ab23cf9881c94e2db30cac0eb1b7cf80c
|
golang.org/x/sync 450f422ab23cf9881c94e2db30cac0eb1b7cf80c
|
||||||
github.com/BurntSushi/toml a368813c5e648fee92e5f6c30e3944ff9d5e8895
|
github.com/BurntSushi/toml a368813c5e648fee92e5f6c30e3944ff9d5e8895
|
||||||
github.com/grpc-ecosystem/go-grpc-prometheus 6b7015e65d366bf3f19b2b2a000a831940f0f7e0
|
github.com/grpc-ecosystem/go-grpc-prometheus 6b7015e65d366bf3f19b2b2a000a831940f0f7e0
|
||||||
github.com/Microsoft/go-winio v0.4.7
|
github.com/Microsoft/go-winio v0.4.10
|
||||||
github.com/Microsoft/hcsshim v0.6.11
|
github.com/Microsoft/hcsshim 44c060121b68e8bdc40b411beba551f3b4ee9e55
|
||||||
github.com/boltdb/bolt e9cf4fae01b5a8ff89d0ec6b32f0d9c9f79aefdd
|
github.com/boltdb/bolt e9cf4fae01b5a8ff89d0ec6b32f0d9c9f79aefdd
|
||||||
google.golang.org/genproto d80a6e20e776b0b17a324d0ba1ab50a39c8e8944
|
google.golang.org/genproto d80a6e20e776b0b17a324d0ba1ab50a39c8e8944
|
||||||
golang.org/x/text 19e51611da83d6be54ddafce4a4af510cb3e9ea4
|
golang.org/x/text 19e51611da83d6be54ddafce4a4af510cb3e9ea4
|
||||||
|
|
|
@ -413,7 +413,7 @@ func (cli *Client) SetCustomHTTPHeaders(headers map[string]string) {
|
||||||
func (cli *Client) Dialer() func(context.Context) (net.Conn, error) {
|
func (cli *Client) Dialer() func(context.Context) (net.Conn, error) {
|
||||||
return func(ctx context.Context) (net.Conn, error) {
|
return func(ctx context.Context) (net.Conn, error) {
|
||||||
if transport, ok := cli.client.Transport.(*http.Transport); ok {
|
if transport, ok := cli.client.Transport.(*http.Transport); ok {
|
||||||
if transport.DialContext != nil {
|
if transport.DialContext != nil && transport.TLSClientConfig == nil {
|
||||||
return transport.DialContext(ctx, cli.proto, cli.addr)
|
return transport.DialContext(ctx, cli.proto, cli.addr)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
# the following lines are in sorted order, FYI
|
# the following lines are in sorted order, FYI
|
||||||
github.com/Azure/go-ansiterm d6e3b3328b783f23731bc4d058875b0371ff8109
|
github.com/Azure/go-ansiterm d6e3b3328b783f23731bc4d058875b0371ff8109
|
||||||
github.com/Microsoft/hcsshim v0.6.14
|
github.com/Microsoft/hcsshim 44c060121b68e8bdc40b411beba551f3b4ee9e55
|
||||||
github.com/Microsoft/go-winio v0.4.10
|
github.com/Microsoft/go-winio v0.4.10
|
||||||
github.com/docker/libtrust 9cbd2a1374f46905c68a4eb3694a130610adc62a
|
github.com/docker/libtrust 9cbd2a1374f46905c68a4eb3694a130610adc62a
|
||||||
github.com/go-check/check 4ed411733c5785b40214c70bce814c3a3a689609 https://github.com/cpuguy83/check.git
|
github.com/go-check/check 4ed411733c5785b40214c70bce814c3a3a689609 https://github.com/cpuguy83/check.git
|
||||||
|
@ -26,7 +26,7 @@ github.com/imdario/mergo v0.3.6
|
||||||
golang.org/x/sync 1d60e4601c6fd243af51cc01ddf169918a5407ca
|
golang.org/x/sync 1d60e4601c6fd243af51cc01ddf169918a5407ca
|
||||||
|
|
||||||
# buildkit
|
# buildkit
|
||||||
github.com/moby/buildkit e1cd06ad6b74e4b747306c4408c451b3b6d87a89
|
github.com/moby/buildkit 6812dac65e0440bb75affce1fb2175e640edc15d
|
||||||
github.com/tonistiigi/fsutil b19464cd1b6a00773b4f2eb7acf9c30426f9df42
|
github.com/tonistiigi/fsutil b19464cd1b6a00773b4f2eb7acf9c30426f9df42
|
||||||
github.com/grpc-ecosystem/grpc-opentracing 8e809c8a86450a29b90dcc9efbf062d0fe6d9746
|
github.com/grpc-ecosystem/grpc-opentracing 8e809c8a86450a29b90dcc9efbf062d0fe6d9746
|
||||||
github.com/opentracing/opentracing-go 1361b9cd60be79c4c3a7fa9841b3c132e40066a7
|
github.com/opentracing/opentracing-go 1361b9cd60be79c4c3a7fa9841b3c132e40066a7
|
||||||
|
@ -75,7 +75,7 @@ github.com/pborman/uuid v1.0
|
||||||
google.golang.org/grpc v1.12.0
|
google.golang.org/grpc v1.12.0
|
||||||
|
|
||||||
# This does not need to match RUNC_COMMIT as it is used for helper packages but should be newer or equal
|
# This does not need to match RUNC_COMMIT as it is used for helper packages but should be newer or equal
|
||||||
github.com/opencontainers/runc ad0f5255060d36872be04de22f8731f38ef2d7b1
|
github.com/opencontainers/runc 20aff4f0488c6d4b8df4d85b4f63f1f704c11abd
|
||||||
github.com/opencontainers/runtime-spec d810dbc60d8c5aeeb3d054bd1132fab2121968ce # v1.0.1-43-gd810dbc
|
github.com/opencontainers/runtime-spec d810dbc60d8c5aeeb3d054bd1132fab2121968ce # v1.0.1-43-gd810dbc
|
||||||
github.com/opencontainers/image-spec v1.0.1
|
github.com/opencontainers/image-spec v1.0.1
|
||||||
github.com/seccomp/libseccomp-golang 32f571b70023028bd57d9288c20efbcb237f3ce0
|
github.com/seccomp/libseccomp-golang 32f571b70023028bd57d9288c20efbcb237f3ce0
|
||||||
|
@ -114,11 +114,11 @@ github.com/googleapis/gax-go v2.0.0
|
||||||
google.golang.org/genproto 694d95ba50e67b2e363f3483057db5d4910c18f9
|
google.golang.org/genproto 694d95ba50e67b2e363f3483057db5d4910c18f9
|
||||||
|
|
||||||
# containerd
|
# containerd
|
||||||
github.com/containerd/containerd 3f42445e38d1081f4b8c3b8d7d1ed1860198ed7a
|
github.com/containerd/containerd v1.2.0-beta.2
|
||||||
github.com/containerd/fifo 3d5202aec260678c48179c56f40e6f38a095738c
|
github.com/containerd/fifo 3d5202aec260678c48179c56f40e6f38a095738c
|
||||||
github.com/containerd/continuity d3c23511c1bf5851696cba83143d9cbcd666869b
|
github.com/containerd/continuity d3c23511c1bf5851696cba83143d9cbcd666869b
|
||||||
github.com/containerd/cgroups 5e610833b72089b37d0e615de9a92dfc043757c2
|
github.com/containerd/cgroups 5e610833b72089b37d0e615de9a92dfc043757c2
|
||||||
github.com/containerd/console 4d8a41f4ce5b9bae77c41786ea2458330f43f081
|
github.com/containerd/console c12b1e7919c14469339a5d38f2f8ed9b64a9de23
|
||||||
github.com/containerd/go-runc edcf3de1f4971445c42d61f20d506b30612aa031
|
github.com/containerd/go-runc edcf3de1f4971445c42d61f20d506b30612aa031
|
||||||
github.com/containerd/typeurl a93fcdb778cd272c6e9b3028b2f42d813e785d40
|
github.com/containerd/typeurl a93fcdb778cd272c6e9b3028b2f42d813e785d40
|
||||||
github.com/containerd/ttrpc 94dde388801693c54f88a6596f713b51a8b30b2d
|
github.com/containerd/ttrpc 94dde388801693c54f88a6596f713b51a8b30b2d
|
||||||
|
|
|
@ -232,7 +232,7 @@ export JAEGER_TRACE=0.0.0.0:6831
|
||||||
|
|
||||||
### Supported runc version
|
### Supported runc version
|
||||||
|
|
||||||
During development, BuildKit is tested with the version of runc that is being used by the containerd repository. Please refer to [runc.md](https://github.com/containerd/containerd/blob/v1.1.0/RUNC.md) for more information.
|
During development, BuildKit is tested with the version of runc that is being used by the containerd repository. Please refer to [runc.md](https://github.com/containerd/containerd/blob/v1.1.3/RUNC.md) for more information.
|
||||||
|
|
||||||
### Running BuildKit without root privileges
|
### Running BuildKit without root privileges
|
||||||
|
|
||||||
|
|
|
@ -19,6 +19,7 @@ import (
|
||||||
opentracing "github.com/opentracing/opentracing-go"
|
opentracing "github.com/opentracing/opentracing-go"
|
||||||
"github.com/pkg/errors"
|
"github.com/pkg/errors"
|
||||||
"github.com/sirupsen/logrus"
|
"github.com/sirupsen/logrus"
|
||||||
|
"github.com/tonistiigi/fsutil"
|
||||||
"golang.org/x/sync/errgroup"
|
"golang.org/x/sync/errgroup"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@ -255,10 +256,16 @@ func prepareSyncedDirs(def *llb.Definition, localDirs map[string]string) ([]file
|
||||||
return nil, errors.Errorf("%s not a directory", d)
|
return nil, errors.Errorf("%s not a directory", d)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
resetUIDAndGID := func(st *fsutil.Stat) bool {
|
||||||
|
st.Uid = 0
|
||||||
|
st.Gid = 0
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
dirs := make([]filesync.SyncedDir, 0, len(localDirs))
|
dirs := make([]filesync.SyncedDir, 0, len(localDirs))
|
||||||
if def == nil {
|
if def == nil {
|
||||||
for name, d := range localDirs {
|
for name, d := range localDirs {
|
||||||
dirs = append(dirs, filesync.SyncedDir{Name: name, Dir: d})
|
dirs = append(dirs, filesync.SyncedDir{Name: name, Dir: d, Map: resetUIDAndGID})
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
for _, dt := range def.Def {
|
for _, dt := range def.Def {
|
||||||
|
@ -273,7 +280,7 @@ func prepareSyncedDirs(def *llb.Definition, localDirs map[string]string) ([]file
|
||||||
if !ok {
|
if !ok {
|
||||||
return nil, errors.Errorf("local directory %s not enabled", name)
|
return nil, errors.Errorf("local directory %s not enabled", name)
|
||||||
}
|
}
|
||||||
dirs = append(dirs, filesync.SyncedDir{Name: name, Dir: d}) // TODO: excludes
|
dirs = append(dirs, filesync.SyncedDir{Name: name, Dir: d, Map: resetUIDAndGID}) // TODO: excludes
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -9,8 +9,9 @@ import (
|
||||||
)
|
)
|
||||||
|
|
||||||
const (
|
const (
|
||||||
Address = "unix:///run/buildkit/buildkitd.sock"
|
Address = "unix:///run/buildkit/buildkitd.sock"
|
||||||
Root = "/var/lib/buildkit"
|
Root = "/var/lib/buildkit"
|
||||||
|
ConfigDir = "/etc/buildkit"
|
||||||
)
|
)
|
||||||
|
|
||||||
// UserAddress typically returns /run/user/$UID/buildkit/buildkitd.sock
|
// UserAddress typically returns /run/user/$UID/buildkit/buildkitd.sock
|
||||||
|
@ -53,3 +54,16 @@ func UserRoot() string {
|
||||||
}
|
}
|
||||||
return Root
|
return Root
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// UserConfigDir returns dir for storing config. /home/$USER/.config/buildkit/
|
||||||
|
func UserConfigDir() string {
|
||||||
|
xdgConfigHome := os.Getenv("XDG_CONFIG_HOME")
|
||||||
|
if xdgConfigHome != "" {
|
||||||
|
return filepath.Join(xdgConfigHome, "buildkit")
|
||||||
|
}
|
||||||
|
home := os.Getenv("HOME")
|
||||||
|
if home != "" {
|
||||||
|
return filepath.Join(home, ".config", "buildkit")
|
||||||
|
}
|
||||||
|
return ConfigDir
|
||||||
|
}
|
||||||
|
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue