mirror of https://github.com/docker/cli.git
Merge pull request #3154 from thaJeztah/update_containerd_deps
vendor: github.com/containerd/containerd v1.5.3 to reduce indirect dependencies
This commit is contained in:
commit
f84487ed5b
|
@ -2,9 +2,8 @@ cloud.google.com/go ceeb313ad77b789a7fa5287b36a1
|
||||||
github.com/Azure/go-ansiterm d185dfc1b5a126116ea5a19e148e29d16b4574c9
|
github.com/Azure/go-ansiterm d185dfc1b5a126116ea5a19e148e29d16b4574c9
|
||||||
github.com/beorn7/perks 37c8de3658fcb183f997c4e13e8337516ab753e6 # v1.0.1
|
github.com/beorn7/perks 37c8de3658fcb183f997c4e13e8337516ab753e6 # v1.0.1
|
||||||
github.com/cespare/xxhash/v2 d7df74196a9e781ede915320c11c378c1b2f3a1f # v2.1.1
|
github.com/cespare/xxhash/v2 d7df74196a9e781ede915320c11c378c1b2f3a1f # v2.1.1
|
||||||
github.com/containerd/cgroups b9de8a2212026c07cec67baf3323f1fc0121e048 # v1.0.1
|
|
||||||
github.com/containerd/console 2f1e3d2b6afd18e8b2077816c711205a0b4d8769 # v1.0.2
|
github.com/containerd/console 2f1e3d2b6afd18e8b2077816c711205a0b4d8769 # v1.0.2
|
||||||
github.com/containerd/containerd 36cc874494a56a253cd181a1a685b44b58a2e34a # v1.5.2
|
github.com/containerd/containerd 0e8719f54c6dc6571fc1170da75a85e86c17636b # v1.5.3
|
||||||
github.com/containerd/continuity bce1c3f9669b6f3e7f6656ee715b0b4d75fa64a6 # v0.1.0
|
github.com/containerd/continuity bce1c3f9669b6f3e7f6656ee715b0b4d75fa64a6 # v0.1.0
|
||||||
github.com/containerd/typeurl 5e43fb8b75ed2f2305fc04e6918c8d10636771bc # v1.0.2
|
github.com/containerd/typeurl 5e43fb8b75ed2f2305fc04e6918c8d10636771bc # v1.0.2
|
||||||
github.com/coreos/etcd 2c834459e1aab78a5d5219c7dfe42335fc4b617a # v3.3.25
|
github.com/coreos/etcd 2c834459e1aab78a5d5219c7dfe42335fc4b617a # v3.3.25
|
||||||
|
@ -27,7 +26,6 @@ github.com/gofrs/flock 6caa7350c26b838538005fae7dbe
|
||||||
github.com/gogo/googleapis 01e0f9cca9b92166042241267ee2a5cdf5cff46c # v1.3.2
|
github.com/gogo/googleapis 01e0f9cca9b92166042241267ee2a5cdf5cff46c # v1.3.2
|
||||||
github.com/gogo/protobuf b03c65ea87cdc3521ede29f62fe3ce239267c1bc # v1.3.2
|
github.com/gogo/protobuf b03c65ea87cdc3521ede29f62fe3ce239267c1bc # v1.3.2
|
||||||
github.com/golang/glog 23def4e6c14b4da8ac2ed8007337bc5eb5007998
|
github.com/golang/glog 23def4e6c14b4da8ac2ed8007337bc5eb5007998
|
||||||
github.com/golang/groupcache 869f871628b6baa9cfbc11732cdf6546b17c1298
|
|
||||||
github.com/golang/protobuf 84668698ea25b64748563aa20726db66a6b8d299 # v1.3.5
|
github.com/golang/protobuf 84668698ea25b64748563aa20726db66a6b8d299 # v1.3.5
|
||||||
github.com/google/go-cmp 3af367b6b30c263d47e8895973edcca9a49cf029 # v0.2.0
|
github.com/google/go-cmp 3af367b6b30c263d47e8895973edcca9a49cf029 # v0.2.0
|
||||||
github.com/google/gofuzz 24818f796faf91cd76ec7bddd72458fbced7a6c1
|
github.com/google/gofuzz 24818f796faf91cd76ec7bddd72458fbced7a6c1
|
||||||
|
@ -44,7 +42,6 @@ github.com/jaguilar/vt100 ad4c4a5743050fb7f88ce968dca9
|
||||||
github.com/json-iterator/go a1ca0830781e007c66b225121d2cdb3a649421f6 # v1.1.10
|
github.com/json-iterator/go a1ca0830781e007c66b225121d2cdb3a649421f6 # v1.1.10
|
||||||
github.com/matttproud/golang_protobuf_extensions c12348ce28de40eed0136aa2b644d0ee0650e56c # v1.0.1
|
github.com/matttproud/golang_protobuf_extensions c12348ce28de40eed0136aa2b644d0ee0650e56c # v1.0.1
|
||||||
github.com/Microsoft/go-winio 5c2e05d71961716a6c392a06ada435aaf5d5302c # v0.4.19
|
github.com/Microsoft/go-winio 5c2e05d71961716a6c392a06ada435aaf5d5302c # v0.4.19
|
||||||
github.com/Microsoft/hcsshim e811ee705ec77df2ae28857ade553043fb564d91 # v0.8.16
|
|
||||||
github.com/miekg/pkcs11 210dc1e16747c5ba98a03bcbcf728c38086ea357 # v1.0.3
|
github.com/miekg/pkcs11 210dc1e16747c5ba98a03bcbcf728c38086ea357 # v1.0.3
|
||||||
github.com/mitchellh/mapstructure d16e9488127408e67948eb43b6d3fbb9f222da10 # v1.3.2
|
github.com/mitchellh/mapstructure d16e9488127408e67948eb43b6d3fbb9f222da10 # v1.3.2
|
||||||
github.com/moby/buildkit 9f254e18360a24c2ae47b26f772c3c89533bcbb7 # master / v0.9.0-dev
|
github.com/moby/buildkit 9f254e18360a24c2ae47b26f772c3c89533bcbb7 # master / v0.9.0-dev
|
||||||
|
@ -74,7 +71,6 @@ github.com/tonistiigi/units 6950e57a87eaf136bbe44ef2ec8e
|
||||||
github.com/xeipuuv/gojsonpointer 02993c407bfbf5f6dae44c4f4b1cf6a39b5fc5bb
|
github.com/xeipuuv/gojsonpointer 02993c407bfbf5f6dae44c4f4b1cf6a39b5fc5bb
|
||||||
github.com/xeipuuv/gojsonreference bd5ef7bd5415a7ac448318e64f11a24cd21e594b
|
github.com/xeipuuv/gojsonreference bd5ef7bd5415a7ac448318e64f11a24cd21e594b
|
||||||
github.com/xeipuuv/gojsonschema 82fcdeb203eb6ab2a67d0a623d9c19e5e5a64927 # v1.2.0
|
github.com/xeipuuv/gojsonschema 82fcdeb203eb6ab2a67d0a623d9c19e5e5a64927 # v1.2.0
|
||||||
go.opencensus.io d835ff86be02193d324330acdb7d65546b05f814 # v0.22.3
|
|
||||||
golang.org/x/crypto 0c34fe9e7dc2486962ef9867e3edb3503537209f
|
golang.org/x/crypto 0c34fe9e7dc2486962ef9867e3edb3503537209f
|
||||||
golang.org/x/net e18ecbb051101a46fc263334b127c89bc7bff7ea
|
golang.org/x/net e18ecbb051101a46fc263334b127c89bc7bff7ea
|
||||||
golang.org/x/oauth2 bf48bf16ab8d622ce64ec6ce98d2c98f916b6303
|
golang.org/x/oauth2 bf48bf16ab8d622ce64ec6ce98d2c98f916b6303
|
||||||
|
|
|
@ -1,161 +0,0 @@
|
||||||
// +build windows
|
|
||||||
|
|
||||||
package security
|
|
||||||
|
|
||||||
import (
|
|
||||||
"os"
|
|
||||||
"syscall"
|
|
||||||
"unsafe"
|
|
||||||
|
|
||||||
"github.com/pkg/errors"
|
|
||||||
)
|
|
||||||
|
|
||||||
type (
|
|
||||||
accessMask uint32
|
|
||||||
accessMode uint32
|
|
||||||
desiredAccess uint32
|
|
||||||
inheritMode uint32
|
|
||||||
objectType uint32
|
|
||||||
shareMode uint32
|
|
||||||
securityInformation uint32
|
|
||||||
trusteeForm uint32
|
|
||||||
trusteeType uint32
|
|
||||||
|
|
||||||
explicitAccess struct {
|
|
||||||
accessPermissions accessMask
|
|
||||||
accessMode accessMode
|
|
||||||
inheritance inheritMode
|
|
||||||
trustee trustee
|
|
||||||
}
|
|
||||||
|
|
||||||
trustee struct {
|
|
||||||
multipleTrustee *trustee
|
|
||||||
multipleTrusteeOperation int32
|
|
||||||
trusteeForm trusteeForm
|
|
||||||
trusteeType trusteeType
|
|
||||||
name uintptr
|
|
||||||
}
|
|
||||||
)
|
|
||||||
|
|
||||||
const (
|
|
||||||
accessMaskDesiredPermission accessMask = 1 << 31 // GENERIC_READ
|
|
||||||
|
|
||||||
accessModeGrant accessMode = 1
|
|
||||||
|
|
||||||
desiredAccessReadControl desiredAccess = 0x20000
|
|
||||||
desiredAccessWriteDac desiredAccess = 0x40000
|
|
||||||
|
|
||||||
gvmga = "GrantVmGroupAccess:"
|
|
||||||
|
|
||||||
inheritModeNoInheritance inheritMode = 0x0
|
|
||||||
inheritModeSubContainersAndObjectsInherit inheritMode = 0x3
|
|
||||||
|
|
||||||
objectTypeFileObject objectType = 0x1
|
|
||||||
|
|
||||||
securityInformationDACL securityInformation = 0x4
|
|
||||||
|
|
||||||
shareModeRead shareMode = 0x1
|
|
||||||
shareModeWrite shareMode = 0x2
|
|
||||||
|
|
||||||
sidVmGroup = "S-1-5-83-0"
|
|
||||||
|
|
||||||
trusteeFormIsSid trusteeForm = 0
|
|
||||||
|
|
||||||
trusteeTypeWellKnownGroup trusteeType = 5
|
|
||||||
)
|
|
||||||
|
|
||||||
// GrantVMGroupAccess sets the DACL for a specified file or directory to
|
|
||||||
// include Grant ACE entries for the VM Group SID. This is a golang re-
|
|
||||||
// implementation of the same function in vmcompute, just not exported in
|
|
||||||
// RS5. Which kind of sucks. Sucks a lot :/
|
|
||||||
func GrantVmGroupAccess(name string) error {
|
|
||||||
// Stat (to determine if `name` is a directory).
|
|
||||||
s, err := os.Stat(name)
|
|
||||||
if err != nil {
|
|
||||||
return errors.Wrapf(err, "%s os.Stat %s", gvmga, name)
|
|
||||||
}
|
|
||||||
|
|
||||||
// Get a handle to the file/directory. Must defer Close on success.
|
|
||||||
fd, err := createFile(name, s.IsDir())
|
|
||||||
if err != nil {
|
|
||||||
return err // Already wrapped
|
|
||||||
}
|
|
||||||
defer syscall.CloseHandle(fd)
|
|
||||||
|
|
||||||
// Get the current DACL and Security Descriptor. Must defer LocalFree on success.
|
|
||||||
ot := objectTypeFileObject
|
|
||||||
si := securityInformationDACL
|
|
||||||
sd := uintptr(0)
|
|
||||||
origDACL := uintptr(0)
|
|
||||||
if err := getSecurityInfo(fd, uint32(ot), uint32(si), nil, nil, &origDACL, nil, &sd); err != nil {
|
|
||||||
return errors.Wrapf(err, "%s GetSecurityInfo %s", gvmga, name)
|
|
||||||
}
|
|
||||||
defer syscall.LocalFree((syscall.Handle)(unsafe.Pointer(sd)))
|
|
||||||
|
|
||||||
// Generate a new DACL which is the current DACL with the required ACEs added.
|
|
||||||
// Must defer LocalFree on success.
|
|
||||||
newDACL, err := generateDACLWithAcesAdded(name, s.IsDir(), origDACL)
|
|
||||||
if err != nil {
|
|
||||||
return err // Already wrapped
|
|
||||||
}
|
|
||||||
defer syscall.LocalFree((syscall.Handle)(unsafe.Pointer(newDACL)))
|
|
||||||
|
|
||||||
// And finally use SetSecurityInfo to apply the updated DACL.
|
|
||||||
if err := setSecurityInfo(fd, uint32(ot), uint32(si), uintptr(0), uintptr(0), newDACL, uintptr(0)); err != nil {
|
|
||||||
return errors.Wrapf(err, "%s SetSecurityInfo %s", gvmga, name)
|
|
||||||
}
|
|
||||||
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// createFile is a helper function to call [Nt]CreateFile to get a handle to
|
|
||||||
// the file or directory.
|
|
||||||
func createFile(name string, isDir bool) (syscall.Handle, error) {
|
|
||||||
namep := syscall.StringToUTF16(name)
|
|
||||||
da := uint32(desiredAccessReadControl | desiredAccessWriteDac)
|
|
||||||
sm := uint32(shareModeRead | shareModeWrite)
|
|
||||||
fa := uint32(syscall.FILE_ATTRIBUTE_NORMAL)
|
|
||||||
if isDir {
|
|
||||||
fa = uint32(fa | syscall.FILE_FLAG_BACKUP_SEMANTICS)
|
|
||||||
}
|
|
||||||
fd, err := syscall.CreateFile(&namep[0], da, sm, nil, syscall.OPEN_EXISTING, fa, 0)
|
|
||||||
if err != nil {
|
|
||||||
return 0, errors.Wrapf(err, "%s syscall.CreateFile %s", gvmga, name)
|
|
||||||
}
|
|
||||||
return fd, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// generateDACLWithAcesAdded generates a new DACL with the two needed ACEs added.
|
|
||||||
// The caller is responsible for LocalFree of the returned DACL on success.
|
|
||||||
func generateDACLWithAcesAdded(name string, isDir bool, origDACL uintptr) (uintptr, error) {
|
|
||||||
// Generate pointers to the SIDs based on the string SIDs
|
|
||||||
sid, err := syscall.StringToSid(sidVmGroup)
|
|
||||||
if err != nil {
|
|
||||||
return 0, errors.Wrapf(err, "%s syscall.StringToSid %s %s", gvmga, name, sidVmGroup)
|
|
||||||
}
|
|
||||||
|
|
||||||
inheritance := inheritModeNoInheritance
|
|
||||||
if isDir {
|
|
||||||
inheritance = inheritModeSubContainersAndObjectsInherit
|
|
||||||
}
|
|
||||||
|
|
||||||
eaArray := []explicitAccess{
|
|
||||||
explicitAccess{
|
|
||||||
accessPermissions: accessMaskDesiredPermission,
|
|
||||||
accessMode: accessModeGrant,
|
|
||||||
inheritance: inheritance,
|
|
||||||
trustee: trustee{
|
|
||||||
trusteeForm: trusteeFormIsSid,
|
|
||||||
trusteeType: trusteeTypeWellKnownGroup,
|
|
||||||
name: uintptr(unsafe.Pointer(sid)),
|
|
||||||
},
|
|
||||||
},
|
|
||||||
}
|
|
||||||
|
|
||||||
modifiedDACL := uintptr(0)
|
|
||||||
if err := setEntriesInAcl(uintptr(uint32(1)), uintptr(unsafe.Pointer(&eaArray[0])), origDACL, &modifiedDACL); err != nil {
|
|
||||||
return 0, errors.Wrapf(err, "%s SetEntriesInAcl %s", gvmga, name)
|
|
||||||
}
|
|
||||||
|
|
||||||
return modifiedDACL, nil
|
|
||||||
}
|
|
|
@ -1,7 +0,0 @@
|
||||||
package security
|
|
||||||
|
|
||||||
//go:generate go run mksyscall_windows.go -output zsyscall_windows.go syscall_windows.go
|
|
||||||
|
|
||||||
//sys getSecurityInfo(handle syscall.Handle, objectType uint32, si uint32, ppsidOwner **uintptr, ppsidGroup **uintptr, ppDacl *uintptr, ppSacl *uintptr, ppSecurityDescriptor *uintptr) (err error) [failretval!=0] = advapi32.GetSecurityInfo
|
|
||||||
//sys setSecurityInfo(handle syscall.Handle, objectType uint32, si uint32, psidOwner uintptr, psidGroup uintptr, pDacl uintptr, pSacl uintptr) (err error) [failretval!=0] = advapi32.SetSecurityInfo
|
|
||||||
//sys setEntriesInAcl(count uintptr, pListOfEEs uintptr, oldAcl uintptr, newAcl *uintptr) (err error) [failretval!=0] = advapi32.SetEntriesInAclW
|
|
|
@ -1,70 +0,0 @@
|
||||||
// Code generated by 'go generate'; DO NOT EDIT.
|
|
||||||
|
|
||||||
package security
|
|
||||||
|
|
||||||
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)
|
|
||||||
errERROR_EINVAL error = syscall.EINVAL
|
|
||||||
)
|
|
||||||
|
|
||||||
// errnoErr returns common boxed Errno values, to prevent
|
|
||||||
// allocations at runtime.
|
|
||||||
func errnoErr(e syscall.Errno) error {
|
|
||||||
switch e {
|
|
||||||
case 0:
|
|
||||||
return errERROR_EINVAL
|
|
||||||
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 (
|
|
||||||
modadvapi32 = windows.NewLazySystemDLL("advapi32.dll")
|
|
||||||
|
|
||||||
procGetSecurityInfo = modadvapi32.NewProc("GetSecurityInfo")
|
|
||||||
procSetEntriesInAclW = modadvapi32.NewProc("SetEntriesInAclW")
|
|
||||||
procSetSecurityInfo = modadvapi32.NewProc("SetSecurityInfo")
|
|
||||||
)
|
|
||||||
|
|
||||||
func getSecurityInfo(handle syscall.Handle, objectType uint32, si uint32, ppsidOwner **uintptr, ppsidGroup **uintptr, ppDacl *uintptr, ppSacl *uintptr, ppSecurityDescriptor *uintptr) (err error) {
|
|
||||||
r1, _, e1 := syscall.Syscall9(procGetSecurityInfo.Addr(), 8, uintptr(handle), uintptr(objectType), uintptr(si), uintptr(unsafe.Pointer(ppsidOwner)), uintptr(unsafe.Pointer(ppsidGroup)), uintptr(unsafe.Pointer(ppDacl)), uintptr(unsafe.Pointer(ppSacl)), uintptr(unsafe.Pointer(ppSecurityDescriptor)), 0)
|
|
||||||
if r1 != 0 {
|
|
||||||
err = errnoErr(e1)
|
|
||||||
}
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
func setEntriesInAcl(count uintptr, pListOfEEs uintptr, oldAcl uintptr, newAcl *uintptr) (err error) {
|
|
||||||
r1, _, e1 := syscall.Syscall6(procSetEntriesInAclW.Addr(), 4, uintptr(count), uintptr(pListOfEEs), uintptr(oldAcl), uintptr(unsafe.Pointer(newAcl)), 0, 0)
|
|
||||||
if r1 != 0 {
|
|
||||||
err = errnoErr(e1)
|
|
||||||
}
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
func setSecurityInfo(handle syscall.Handle, objectType uint32, si uint32, psidOwner uintptr, psidGroup uintptr, pDacl uintptr, pSacl uintptr) (err error) {
|
|
||||||
r1, _, e1 := syscall.Syscall9(procSetSecurityInfo.Addr(), 7, uintptr(handle), uintptr(objectType), uintptr(si), uintptr(psidOwner), uintptr(psidGroup), uintptr(pDacl), uintptr(pSacl), 0, 0)
|
|
||||||
if r1 != 0 {
|
|
||||||
err = errnoErr(e1)
|
|
||||||
}
|
|
||||||
return
|
|
||||||
}
|
|
|
@ -1,323 +0,0 @@
|
||||||
// +build windows
|
|
||||||
|
|
||||||
package vhd
|
|
||||||
|
|
||||||
import (
|
|
||||||
"fmt"
|
|
||||||
"syscall"
|
|
||||||
|
|
||||||
"github.com/Microsoft/go-winio/pkg/guid"
|
|
||||||
"github.com/pkg/errors"
|
|
||||||
"golang.org/x/sys/windows"
|
|
||||||
)
|
|
||||||
|
|
||||||
//go:generate go run mksyscall_windows.go -output zvhd_windows.go vhd.go
|
|
||||||
|
|
||||||
//sys createVirtualDisk(virtualStorageType *VirtualStorageType, path string, virtualDiskAccessMask uint32, securityDescriptor *uintptr, createVirtualDiskFlags uint32, providerSpecificFlags uint32, parameters *CreateVirtualDiskParameters, overlapped *syscall.Overlapped, handle *syscall.Handle) (err error) [failretval != 0] = virtdisk.CreateVirtualDisk
|
|
||||||
//sys openVirtualDisk(virtualStorageType *VirtualStorageType, path string, virtualDiskAccessMask uint32, openVirtualDiskFlags uint32, parameters *OpenVirtualDiskParameters, handle *syscall.Handle) (err error) [failretval != 0] = virtdisk.OpenVirtualDisk
|
|
||||||
//sys attachVirtualDisk(handle syscall.Handle, securityDescriptor *uintptr, attachVirtualDiskFlag uint32, providerSpecificFlags uint32, parameters *AttachVirtualDiskParameters, overlapped *syscall.Overlapped) (err error) [failretval != 0] = virtdisk.AttachVirtualDisk
|
|
||||||
//sys detachVirtualDisk(handle syscall.Handle, detachVirtualDiskFlags uint32, providerSpecificFlags uint32) (err error) [failretval != 0] = virtdisk.DetachVirtualDisk
|
|
||||||
//sys getVirtualDiskPhysicalPath(handle syscall.Handle, diskPathSizeInBytes *uint32, buffer *uint16) (err error) [failretval != 0] = virtdisk.GetVirtualDiskPhysicalPath
|
|
||||||
|
|
||||||
type (
|
|
||||||
CreateVirtualDiskFlag uint32
|
|
||||||
VirtualDiskFlag uint32
|
|
||||||
AttachVirtualDiskFlag uint32
|
|
||||||
DetachVirtualDiskFlag uint32
|
|
||||||
VirtualDiskAccessMask uint32
|
|
||||||
)
|
|
||||||
|
|
||||||
type VirtualStorageType struct {
|
|
||||||
DeviceID uint32
|
|
||||||
VendorID guid.GUID
|
|
||||||
}
|
|
||||||
|
|
||||||
type CreateVersion2 struct {
|
|
||||||
UniqueID guid.GUID
|
|
||||||
MaximumSize uint64
|
|
||||||
BlockSizeInBytes uint32
|
|
||||||
SectorSizeInBytes uint32
|
|
||||||
PhysicalSectorSizeInByte uint32
|
|
||||||
ParentPath *uint16 // string
|
|
||||||
SourcePath *uint16 // string
|
|
||||||
OpenFlags uint32
|
|
||||||
ParentVirtualStorageType VirtualStorageType
|
|
||||||
SourceVirtualStorageType VirtualStorageType
|
|
||||||
ResiliencyGUID guid.GUID
|
|
||||||
}
|
|
||||||
|
|
||||||
type CreateVirtualDiskParameters struct {
|
|
||||||
Version uint32 // Must always be set to 2
|
|
||||||
Version2 CreateVersion2
|
|
||||||
}
|
|
||||||
|
|
||||||
type OpenVersion2 struct {
|
|
||||||
GetInfoOnly bool
|
|
||||||
ReadOnly bool
|
|
||||||
ResiliencyGUID guid.GUID
|
|
||||||
}
|
|
||||||
|
|
||||||
type OpenVirtualDiskParameters struct {
|
|
||||||
Version uint32 // Must always be set to 2
|
|
||||||
Version2 OpenVersion2
|
|
||||||
}
|
|
||||||
|
|
||||||
type AttachVersion2 struct {
|
|
||||||
RestrictedOffset uint64
|
|
||||||
RestrictedLength uint64
|
|
||||||
}
|
|
||||||
|
|
||||||
type AttachVirtualDiskParameters struct {
|
|
||||||
Version uint32 // Must always be set to 2
|
|
||||||
Version2 AttachVersion2
|
|
||||||
}
|
|
||||||
|
|
||||||
const (
|
|
||||||
VIRTUAL_STORAGE_TYPE_DEVICE_VHDX = 0x3
|
|
||||||
|
|
||||||
// Access Mask for opening a VHD
|
|
||||||
VirtualDiskAccessNone VirtualDiskAccessMask = 0x00000000
|
|
||||||
VirtualDiskAccessAttachRO VirtualDiskAccessMask = 0x00010000
|
|
||||||
VirtualDiskAccessAttachRW VirtualDiskAccessMask = 0x00020000
|
|
||||||
VirtualDiskAccessDetach VirtualDiskAccessMask = 0x00040000
|
|
||||||
VirtualDiskAccessGetInfo VirtualDiskAccessMask = 0x00080000
|
|
||||||
VirtualDiskAccessCreate VirtualDiskAccessMask = 0x00100000
|
|
||||||
VirtualDiskAccessMetaOps VirtualDiskAccessMask = 0x00200000
|
|
||||||
VirtualDiskAccessRead VirtualDiskAccessMask = 0x000d0000
|
|
||||||
VirtualDiskAccessAll VirtualDiskAccessMask = 0x003f0000
|
|
||||||
VirtualDiskAccessWritable VirtualDiskAccessMask = 0x00320000
|
|
||||||
|
|
||||||
// Flags for creating a VHD
|
|
||||||
CreateVirtualDiskFlagNone CreateVirtualDiskFlag = 0x0
|
|
||||||
CreateVirtualDiskFlagFullPhysicalAllocation CreateVirtualDiskFlag = 0x1
|
|
||||||
CreateVirtualDiskFlagPreventWritesToSourceDisk CreateVirtualDiskFlag = 0x2
|
|
||||||
CreateVirtualDiskFlagDoNotCopyMetadataFromParent CreateVirtualDiskFlag = 0x4
|
|
||||||
CreateVirtualDiskFlagCreateBackingStorage CreateVirtualDiskFlag = 0x8
|
|
||||||
CreateVirtualDiskFlagUseChangeTrackingSourceLimit CreateVirtualDiskFlag = 0x10
|
|
||||||
CreateVirtualDiskFlagPreserveParentChangeTrackingState CreateVirtualDiskFlag = 0x20
|
|
||||||
CreateVirtualDiskFlagVhdSetUseOriginalBackingStorage CreateVirtualDiskFlag = 0x40
|
|
||||||
CreateVirtualDiskFlagSparseFile CreateVirtualDiskFlag = 0x80
|
|
||||||
CreateVirtualDiskFlagPmemCompatible CreateVirtualDiskFlag = 0x100
|
|
||||||
CreateVirtualDiskFlagSupportCompressedVolumes CreateVirtualDiskFlag = 0x200
|
|
||||||
|
|
||||||
// Flags for opening a VHD
|
|
||||||
OpenVirtualDiskFlagNone VirtualDiskFlag = 0x00000000
|
|
||||||
OpenVirtualDiskFlagNoParents VirtualDiskFlag = 0x00000001
|
|
||||||
OpenVirtualDiskFlagBlankFile VirtualDiskFlag = 0x00000002
|
|
||||||
OpenVirtualDiskFlagBootDrive VirtualDiskFlag = 0x00000004
|
|
||||||
OpenVirtualDiskFlagCachedIO VirtualDiskFlag = 0x00000008
|
|
||||||
OpenVirtualDiskFlagCustomDiffChain VirtualDiskFlag = 0x00000010
|
|
||||||
OpenVirtualDiskFlagParentCachedIO VirtualDiskFlag = 0x00000020
|
|
||||||
OpenVirtualDiskFlagVhdsetFileOnly VirtualDiskFlag = 0x00000040
|
|
||||||
OpenVirtualDiskFlagIgnoreRelativeParentLocator VirtualDiskFlag = 0x00000080
|
|
||||||
OpenVirtualDiskFlagNoWriteHardening VirtualDiskFlag = 0x00000100
|
|
||||||
OpenVirtualDiskFlagSupportCompressedVolumes VirtualDiskFlag = 0x00000200
|
|
||||||
|
|
||||||
// Flags for attaching a VHD
|
|
||||||
AttachVirtualDiskFlagNone AttachVirtualDiskFlag = 0x00000000
|
|
||||||
AttachVirtualDiskFlagReadOnly AttachVirtualDiskFlag = 0x00000001
|
|
||||||
AttachVirtualDiskFlagNoDriveLetter AttachVirtualDiskFlag = 0x00000002
|
|
||||||
AttachVirtualDiskFlagPermanentLifetime AttachVirtualDiskFlag = 0x00000004
|
|
||||||
AttachVirtualDiskFlagNoLocalHost AttachVirtualDiskFlag = 0x00000008
|
|
||||||
AttachVirtualDiskFlagNoSecurityDescriptor AttachVirtualDiskFlag = 0x00000010
|
|
||||||
AttachVirtualDiskFlagBypassDefaultEncryptionPolicy AttachVirtualDiskFlag = 0x00000020
|
|
||||||
AttachVirtualDiskFlagNonPnp AttachVirtualDiskFlag = 0x00000040
|
|
||||||
AttachVirtualDiskFlagRestrictedRange AttachVirtualDiskFlag = 0x00000080
|
|
||||||
AttachVirtualDiskFlagSinglePartition AttachVirtualDiskFlag = 0x00000100
|
|
||||||
AttachVirtualDiskFlagRegisterVolume AttachVirtualDiskFlag = 0x00000200
|
|
||||||
|
|
||||||
// Flags for detaching a VHD
|
|
||||||
DetachVirtualDiskFlagNone DetachVirtualDiskFlag = 0x0
|
|
||||||
)
|
|
||||||
|
|
||||||
// CreateVhdx is a helper function to create a simple vhdx file at the given path using
|
|
||||||
// default values.
|
|
||||||
func CreateVhdx(path string, maxSizeInGb, blockSizeInMb uint32) error {
|
|
||||||
params := CreateVirtualDiskParameters{
|
|
||||||
Version: 2,
|
|
||||||
Version2: CreateVersion2{
|
|
||||||
MaximumSize: uint64(maxSizeInGb) * 1024 * 1024 * 1024,
|
|
||||||
BlockSizeInBytes: blockSizeInMb * 1024 * 1024,
|
|
||||||
},
|
|
||||||
}
|
|
||||||
|
|
||||||
handle, err := CreateVirtualDisk(path, VirtualDiskAccessNone, CreateVirtualDiskFlagNone, ¶ms)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
if err := syscall.CloseHandle(handle); err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// DetachVirtualDisk detaches a virtual hard disk by handle.
|
|
||||||
func DetachVirtualDisk(handle syscall.Handle) (err error) {
|
|
||||||
if err := detachVirtualDisk(handle, 0, 0); err != nil {
|
|
||||||
return errors.Wrap(err, "failed to detach virtual disk")
|
|
||||||
}
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// DetachVhd detaches a vhd found at `path`.
|
|
||||||
func DetachVhd(path string) error {
|
|
||||||
handle, err := OpenVirtualDisk(
|
|
||||||
path,
|
|
||||||
VirtualDiskAccessNone,
|
|
||||||
OpenVirtualDiskFlagCachedIO|OpenVirtualDiskFlagIgnoreRelativeParentLocator,
|
|
||||||
)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
defer syscall.CloseHandle(handle)
|
|
||||||
return DetachVirtualDisk(handle)
|
|
||||||
}
|
|
||||||
|
|
||||||
// AttachVirtualDisk attaches a virtual hard disk for use.
|
|
||||||
func AttachVirtualDisk(handle syscall.Handle, attachVirtualDiskFlag AttachVirtualDiskFlag, parameters *AttachVirtualDiskParameters) (err error) {
|
|
||||||
// Supports both version 1 and 2 of the attach parameters as version 2 wasn't present in RS5.
|
|
||||||
if err := attachVirtualDisk(
|
|
||||||
handle,
|
|
||||||
nil,
|
|
||||||
uint32(attachVirtualDiskFlag),
|
|
||||||
0,
|
|
||||||
parameters,
|
|
||||||
nil,
|
|
||||||
); err != nil {
|
|
||||||
return errors.Wrap(err, "failed to attach virtual disk")
|
|
||||||
}
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// AttachVhd attaches a virtual hard disk at `path` for use. Attaches using version 2
|
|
||||||
// of the ATTACH_VIRTUAL_DISK_PARAMETERS.
|
|
||||||
func AttachVhd(path string) (err error) {
|
|
||||||
handle, err := OpenVirtualDisk(
|
|
||||||
path,
|
|
||||||
VirtualDiskAccessNone,
|
|
||||||
OpenVirtualDiskFlagCachedIO|OpenVirtualDiskFlagIgnoreRelativeParentLocator,
|
|
||||||
)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
defer syscall.CloseHandle(handle)
|
|
||||||
params := AttachVirtualDiskParameters{Version: 2}
|
|
||||||
if err := AttachVirtualDisk(
|
|
||||||
handle,
|
|
||||||
AttachVirtualDiskFlagNone,
|
|
||||||
¶ms,
|
|
||||||
); err != nil {
|
|
||||||
return errors.Wrap(err, "failed to attach virtual disk")
|
|
||||||
}
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// OpenVirtualDisk obtains a handle to a VHD opened with supplied access mask and flags.
|
|
||||||
func OpenVirtualDisk(vhdPath string, virtualDiskAccessMask VirtualDiskAccessMask, openVirtualDiskFlags VirtualDiskFlag) (syscall.Handle, error) {
|
|
||||||
parameters := OpenVirtualDiskParameters{Version: 2}
|
|
||||||
handle, err := OpenVirtualDiskWithParameters(
|
|
||||||
vhdPath,
|
|
||||||
virtualDiskAccessMask,
|
|
||||||
openVirtualDiskFlags,
|
|
||||||
¶meters,
|
|
||||||
)
|
|
||||||
if err != nil {
|
|
||||||
return 0, err
|
|
||||||
}
|
|
||||||
return handle, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// OpenVirtualDiskWithParameters obtains a handle to a VHD opened with supplied access mask, flags and parameters.
|
|
||||||
func OpenVirtualDiskWithParameters(vhdPath string, virtualDiskAccessMask VirtualDiskAccessMask, openVirtualDiskFlags VirtualDiskFlag, parameters *OpenVirtualDiskParameters) (syscall.Handle, error) {
|
|
||||||
var (
|
|
||||||
handle syscall.Handle
|
|
||||||
defaultType VirtualStorageType
|
|
||||||
)
|
|
||||||
if parameters.Version != 2 {
|
|
||||||
return handle, fmt.Errorf("only version 2 VHDs are supported, found version: %d", parameters.Version)
|
|
||||||
}
|
|
||||||
if err := openVirtualDisk(
|
|
||||||
&defaultType,
|
|
||||||
vhdPath,
|
|
||||||
uint32(virtualDiskAccessMask),
|
|
||||||
uint32(openVirtualDiskFlags),
|
|
||||||
parameters,
|
|
||||||
&handle,
|
|
||||||
); err != nil {
|
|
||||||
return 0, errors.Wrap(err, "failed to open virtual disk")
|
|
||||||
}
|
|
||||||
return handle, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// CreateVirtualDisk creates a virtual harddisk and returns a handle to the disk.
|
|
||||||
func CreateVirtualDisk(path string, virtualDiskAccessMask VirtualDiskAccessMask, createVirtualDiskFlags CreateVirtualDiskFlag, parameters *CreateVirtualDiskParameters) (syscall.Handle, error) {
|
|
||||||
var (
|
|
||||||
handle syscall.Handle
|
|
||||||
defaultType VirtualStorageType
|
|
||||||
)
|
|
||||||
if parameters.Version != 2 {
|
|
||||||
return handle, fmt.Errorf("only version 2 VHDs are supported, found version: %d", parameters.Version)
|
|
||||||
}
|
|
||||||
|
|
||||||
if err := createVirtualDisk(
|
|
||||||
&defaultType,
|
|
||||||
path,
|
|
||||||
uint32(virtualDiskAccessMask),
|
|
||||||
nil,
|
|
||||||
uint32(createVirtualDiskFlags),
|
|
||||||
0,
|
|
||||||
parameters,
|
|
||||||
nil,
|
|
||||||
&handle,
|
|
||||||
); err != nil {
|
|
||||||
return handle, errors.Wrap(err, "failed to create virtual disk")
|
|
||||||
}
|
|
||||||
return handle, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// GetVirtualDiskPhysicalPath takes a handle to a virtual hard disk and returns the physical
|
|
||||||
// path of the disk on the machine. This path is in the form \\.\PhysicalDriveX where X is an integer
|
|
||||||
// that represents the particular enumeration of the physical disk on the caller's system.
|
|
||||||
func GetVirtualDiskPhysicalPath(handle syscall.Handle) (_ string, err error) {
|
|
||||||
var (
|
|
||||||
diskPathSizeInBytes uint32 = 256 * 2 // max path length 256 wide chars
|
|
||||||
diskPhysicalPathBuf [256]uint16
|
|
||||||
)
|
|
||||||
if err := getVirtualDiskPhysicalPath(
|
|
||||||
handle,
|
|
||||||
&diskPathSizeInBytes,
|
|
||||||
&diskPhysicalPathBuf[0],
|
|
||||||
); err != nil {
|
|
||||||
return "", errors.Wrap(err, "failed to get disk physical path")
|
|
||||||
}
|
|
||||||
return windows.UTF16ToString(diskPhysicalPathBuf[:]), nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// CreateDiffVhd is a helper function to create a differencing virtual disk.
|
|
||||||
func CreateDiffVhd(diffVhdPath, baseVhdPath string, blockSizeInMB uint32) error {
|
|
||||||
// Setting `ParentPath` is how to signal to create a differencing disk.
|
|
||||||
createParams := &CreateVirtualDiskParameters{
|
|
||||||
Version: 2,
|
|
||||||
Version2: CreateVersion2{
|
|
||||||
ParentPath: windows.StringToUTF16Ptr(baseVhdPath),
|
|
||||||
BlockSizeInBytes: blockSizeInMB * 1024 * 1024,
|
|
||||||
OpenFlags: uint32(OpenVirtualDiskFlagCachedIO),
|
|
||||||
},
|
|
||||||
}
|
|
||||||
|
|
||||||
vhdHandle, err := CreateVirtualDisk(
|
|
||||||
diffVhdPath,
|
|
||||||
VirtualDiskAccessNone,
|
|
||||||
CreateVirtualDiskFlagNone,
|
|
||||||
createParams,
|
|
||||||
)
|
|
||||||
if err != nil {
|
|
||||||
return fmt.Errorf("failed to create differencing vhd: %s", err)
|
|
||||||
}
|
|
||||||
if err := syscall.CloseHandle(vhdHandle); err != nil {
|
|
||||||
return fmt.Errorf("failed to close differencing vhd handle: %s", err)
|
|
||||||
}
|
|
||||||
return nil
|
|
||||||
}
|
|
|
@ -1,106 +0,0 @@
|
||||||
// Code generated by 'go generate'; DO NOT EDIT.
|
|
||||||
|
|
||||||
package vhd
|
|
||||||
|
|
||||||
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)
|
|
||||||
errERROR_EINVAL error = syscall.EINVAL
|
|
||||||
)
|
|
||||||
|
|
||||||
// errnoErr returns common boxed Errno values, to prevent
|
|
||||||
// allocations at runtime.
|
|
||||||
func errnoErr(e syscall.Errno) error {
|
|
||||||
switch e {
|
|
||||||
case 0:
|
|
||||||
return errERROR_EINVAL
|
|
||||||
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 (
|
|
||||||
modvirtdisk = windows.NewLazySystemDLL("virtdisk.dll")
|
|
||||||
|
|
||||||
procAttachVirtualDisk = modvirtdisk.NewProc("AttachVirtualDisk")
|
|
||||||
procCreateVirtualDisk = modvirtdisk.NewProc("CreateVirtualDisk")
|
|
||||||
procDetachVirtualDisk = modvirtdisk.NewProc("DetachVirtualDisk")
|
|
||||||
procGetVirtualDiskPhysicalPath = modvirtdisk.NewProc("GetVirtualDiskPhysicalPath")
|
|
||||||
procOpenVirtualDisk = modvirtdisk.NewProc("OpenVirtualDisk")
|
|
||||||
)
|
|
||||||
|
|
||||||
func attachVirtualDisk(handle syscall.Handle, securityDescriptor *uintptr, attachVirtualDiskFlag uint32, providerSpecificFlags uint32, parameters *AttachVirtualDiskParameters, overlapped *syscall.Overlapped) (err error) {
|
|
||||||
r1, _, e1 := syscall.Syscall6(procAttachVirtualDisk.Addr(), 6, uintptr(handle), uintptr(unsafe.Pointer(securityDescriptor)), uintptr(attachVirtualDiskFlag), uintptr(providerSpecificFlags), uintptr(unsafe.Pointer(parameters)), uintptr(unsafe.Pointer(overlapped)))
|
|
||||||
if r1 != 0 {
|
|
||||||
err = errnoErr(e1)
|
|
||||||
}
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
func createVirtualDisk(virtualStorageType *VirtualStorageType, path string, virtualDiskAccessMask uint32, securityDescriptor *uintptr, createVirtualDiskFlags uint32, providerSpecificFlags uint32, parameters *CreateVirtualDiskParameters, overlapped *syscall.Overlapped, handle *syscall.Handle) (err error) {
|
|
||||||
var _p0 *uint16
|
|
||||||
_p0, err = syscall.UTF16PtrFromString(path)
|
|
||||||
if err != nil {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
return _createVirtualDisk(virtualStorageType, _p0, virtualDiskAccessMask, securityDescriptor, createVirtualDiskFlags, providerSpecificFlags, parameters, overlapped, handle)
|
|
||||||
}
|
|
||||||
|
|
||||||
func _createVirtualDisk(virtualStorageType *VirtualStorageType, path *uint16, virtualDiskAccessMask uint32, securityDescriptor *uintptr, createVirtualDiskFlags uint32, providerSpecificFlags uint32, parameters *CreateVirtualDiskParameters, overlapped *syscall.Overlapped, handle *syscall.Handle) (err error) {
|
|
||||||
r1, _, e1 := syscall.Syscall9(procCreateVirtualDisk.Addr(), 9, uintptr(unsafe.Pointer(virtualStorageType)), uintptr(unsafe.Pointer(path)), uintptr(virtualDiskAccessMask), uintptr(unsafe.Pointer(securityDescriptor)), uintptr(createVirtualDiskFlags), uintptr(providerSpecificFlags), uintptr(unsafe.Pointer(parameters)), uintptr(unsafe.Pointer(overlapped)), uintptr(unsafe.Pointer(handle)))
|
|
||||||
if r1 != 0 {
|
|
||||||
err = errnoErr(e1)
|
|
||||||
}
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
func detachVirtualDisk(handle syscall.Handle, detachVirtualDiskFlags uint32, providerSpecificFlags uint32) (err error) {
|
|
||||||
r1, _, e1 := syscall.Syscall(procDetachVirtualDisk.Addr(), 3, uintptr(handle), uintptr(detachVirtualDiskFlags), uintptr(providerSpecificFlags))
|
|
||||||
if r1 != 0 {
|
|
||||||
err = errnoErr(e1)
|
|
||||||
}
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
func getVirtualDiskPhysicalPath(handle syscall.Handle, diskPathSizeInBytes *uint32, buffer *uint16) (err error) {
|
|
||||||
r1, _, e1 := syscall.Syscall(procGetVirtualDiskPhysicalPath.Addr(), 3, uintptr(handle), uintptr(unsafe.Pointer(diskPathSizeInBytes)), uintptr(unsafe.Pointer(buffer)))
|
|
||||||
if r1 != 0 {
|
|
||||||
err = errnoErr(e1)
|
|
||||||
}
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
func openVirtualDisk(virtualStorageType *VirtualStorageType, path string, virtualDiskAccessMask uint32, openVirtualDiskFlags uint32, parameters *OpenVirtualDiskParameters, handle *syscall.Handle) (err error) {
|
|
||||||
var _p0 *uint16
|
|
||||||
_p0, err = syscall.UTF16PtrFromString(path)
|
|
||||||
if err != nil {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
return _openVirtualDisk(virtualStorageType, _p0, virtualDiskAccessMask, openVirtualDiskFlags, parameters, handle)
|
|
||||||
}
|
|
||||||
|
|
||||||
func _openVirtualDisk(virtualStorageType *VirtualStorageType, path *uint16, virtualDiskAccessMask uint32, openVirtualDiskFlags uint32, parameters *OpenVirtualDiskParameters, handle *syscall.Handle) (err error) {
|
|
||||||
r1, _, e1 := syscall.Syscall6(procOpenVirtualDisk.Addr(), 6, uintptr(unsafe.Pointer(virtualStorageType)), uintptr(unsafe.Pointer(path)), uintptr(virtualDiskAccessMask), uintptr(openVirtualDiskFlags), uintptr(unsafe.Pointer(parameters)), uintptr(unsafe.Pointer(handle)))
|
|
||||||
if r1 != 0 {
|
|
||||||
err = errnoErr(e1)
|
|
||||||
}
|
|
||||||
return
|
|
||||||
}
|
|
|
@ -1,21 +0,0 @@
|
||||||
The MIT License (MIT)
|
|
||||||
|
|
||||||
Copyright (c) 2015 Microsoft
|
|
||||||
|
|
||||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
||||||
of this software and associated documentation files (the "Software"), to deal
|
|
||||||
in the Software without restriction, including without limitation the rights
|
|
||||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
||||||
copies of the Software, and to permit persons to whom the Software is
|
|
||||||
furnished to do so, subject to the following conditions:
|
|
||||||
|
|
||||||
The above copyright notice and this permission notice shall be included in all
|
|
||||||
copies or substantial portions of the Software.
|
|
||||||
|
|
||||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
||||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
||||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
||||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
||||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
||||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
||||||
SOFTWARE.
|
|
|
@ -1,46 +0,0 @@
|
||||||
# hcsshim
|
|
||||||
|
|
||||||
[![Build status](https://github.com/microsoft/hcsshim/actions/workflows/ci.yml/badge.svg?branch=master)](https://github.com/microsoft/hcsshim/actions?query=branch%3Amaster)
|
|
||||||
|
|
||||||
This package contains the Golang interface for using the Windows [Host Compute Service](https://techcommunity.microsoft.com/t5/containers/introducing-the-host-compute-service-hcs/ba-p/382332) (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
|
|
||||||
|
|
||||||
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
|
|
||||||
the rights to use your contribution. For details, visit https://cla.microsoft.com.
|
|
||||||
|
|
||||||
When you submit a pull request, a CLA-bot will automatically determine whether you need to provide
|
|
||||||
a CLA and decorate the PR appropriately (e.g., label, comment). Simply follow the instructions
|
|
||||||
provided by the bot. You will only need to do this once across all repos using our CLA.
|
|
||||||
|
|
||||||
We also ask that contributors [sign their commits](https://git-scm.com/docs/git-commit) using `git commit -s` or `git commit --signoff` to certify they either authored the work themselves or otherwise have permission to use it in this project.
|
|
||||||
|
|
||||||
|
|
||||||
## Code of Conduct
|
|
||||||
|
|
||||||
This project has adopted the [Microsoft Open Source Code of Conduct](https://opensource.microsoft.com/codeofconduct/).
|
|
||||||
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.
|
|
||||||
|
|
||||||
## 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
|
|
||||||
|
|
||||||
Security issues and bugs should be reported privately, via email, to the Microsoft Security
|
|
||||||
Response Center (MSRC) at [secure@microsoft.com](mailto:secure@microsoft.com). You should
|
|
||||||
receive a response within 24 hours. If for some reason you do not, please follow up via
|
|
||||||
email to ensure we received your original message. Further information, including the
|
|
||||||
[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).
|
|
||||||
|
|
||||||
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.
|
|
|
@ -1,38 +0,0 @@
|
||||||
package computestorage
|
|
||||||
|
|
||||||
import (
|
|
||||||
"context"
|
|
||||||
"encoding/json"
|
|
||||||
|
|
||||||
"github.com/Microsoft/hcsshim/internal/oc"
|
|
||||||
"github.com/pkg/errors"
|
|
||||||
"go.opencensus.io/trace"
|
|
||||||
)
|
|
||||||
|
|
||||||
// AttachLayerStorageFilter sets up the layer storage filter on a writable
|
|
||||||
// container layer.
|
|
||||||
//
|
|
||||||
// `layerPath` is a path to a directory the writable layer is mounted. If the
|
|
||||||
// path does not end in a `\` the platform will append it automatically.
|
|
||||||
//
|
|
||||||
// `layerData` is the parent read-only layer data.
|
|
||||||
func AttachLayerStorageFilter(ctx context.Context, layerPath string, layerData LayerData) (err error) {
|
|
||||||
title := "hcsshim.AttachLayerStorageFilter"
|
|
||||||
ctx, span := trace.StartSpan(ctx, title) //nolint:ineffassign,staticcheck
|
|
||||||
defer span.End()
|
|
||||||
defer func() { oc.SetSpanStatus(span, err) }()
|
|
||||||
span.AddAttributes(
|
|
||||||
trace.StringAttribute("layerPath", layerPath),
|
|
||||||
)
|
|
||||||
|
|
||||||
bytes, err := json.Marshal(layerData)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
err = hcsAttachLayerStorageFilter(layerPath, string(bytes))
|
|
||||||
if err != nil {
|
|
||||||
return errors.Wrap(err, "failed to attach layer storage filter")
|
|
||||||
}
|
|
||||||
return nil
|
|
||||||
}
|
|
|
@ -1,26 +0,0 @@
|
||||||
package computestorage
|
|
||||||
|
|
||||||
import (
|
|
||||||
"context"
|
|
||||||
|
|
||||||
"github.com/Microsoft/hcsshim/internal/oc"
|
|
||||||
"github.com/pkg/errors"
|
|
||||||
"go.opencensus.io/trace"
|
|
||||||
)
|
|
||||||
|
|
||||||
// DestroyLayer deletes a container layer.
|
|
||||||
//
|
|
||||||
// `layerPath` is a path to a directory containing the layer to export.
|
|
||||||
func DestroyLayer(ctx context.Context, layerPath string) (err error) {
|
|
||||||
title := "hcsshim.DestroyLayer"
|
|
||||||
ctx, span := trace.StartSpan(ctx, title) //nolint:ineffassign,staticcheck
|
|
||||||
defer span.End()
|
|
||||||
defer func() { oc.SetSpanStatus(span, err) }()
|
|
||||||
span.AddAttributes(trace.StringAttribute("layerPath", layerPath))
|
|
||||||
|
|
||||||
err = hcsDestroyLayer(layerPath)
|
|
||||||
if err != nil {
|
|
||||||
return errors.Wrap(err, "failed to destroy layer")
|
|
||||||
}
|
|
||||||
return nil
|
|
||||||
}
|
|
|
@ -1,26 +0,0 @@
|
||||||
package computestorage
|
|
||||||
|
|
||||||
import (
|
|
||||||
"context"
|
|
||||||
|
|
||||||
"github.com/Microsoft/hcsshim/internal/oc"
|
|
||||||
"github.com/pkg/errors"
|
|
||||||
"go.opencensus.io/trace"
|
|
||||||
)
|
|
||||||
|
|
||||||
// DetachLayerStorageFilter detaches the layer storage filter on a writable container layer.
|
|
||||||
//
|
|
||||||
// `layerPath` is a path to a directory containing the layer to export.
|
|
||||||
func DetachLayerStorageFilter(ctx context.Context, layerPath string) (err error) {
|
|
||||||
title := "hcsshim.DetachLayerStorageFilter"
|
|
||||||
ctx, span := trace.StartSpan(ctx, title) //nolint:ineffassign,staticcheck
|
|
||||||
defer span.End()
|
|
||||||
defer func() { oc.SetSpanStatus(span, err) }()
|
|
||||||
span.AddAttributes(trace.StringAttribute("layerPath", layerPath))
|
|
||||||
|
|
||||||
err = hcsDetachLayerStorageFilter(layerPath)
|
|
||||||
if err != nil {
|
|
||||||
return errors.Wrap(err, "failed to detach layer storage filter")
|
|
||||||
}
|
|
||||||
return nil
|
|
||||||
}
|
|
|
@ -1,46 +0,0 @@
|
||||||
package computestorage
|
|
||||||
|
|
||||||
import (
|
|
||||||
"context"
|
|
||||||
"encoding/json"
|
|
||||||
|
|
||||||
"github.com/Microsoft/hcsshim/internal/oc"
|
|
||||||
"github.com/pkg/errors"
|
|
||||||
"go.opencensus.io/trace"
|
|
||||||
)
|
|
||||||
|
|
||||||
// ExportLayer exports a container layer.
|
|
||||||
//
|
|
||||||
// `layerPath` is a path to a directory containing the layer to export.
|
|
||||||
//
|
|
||||||
// `exportFolderPath` is a pre-existing folder to export the layer to.
|
|
||||||
//
|
|
||||||
// `layerData` is the parent layer data.
|
|
||||||
//
|
|
||||||
// `options` are the export options applied to the exported layer.
|
|
||||||
func ExportLayer(ctx context.Context, layerPath, exportFolderPath string, layerData LayerData, options ExportLayerOptions) (err error) {
|
|
||||||
title := "hcsshim.ExportLayer"
|
|
||||||
ctx, span := trace.StartSpan(ctx, title) //nolint:ineffassign,staticcheck
|
|
||||||
defer span.End()
|
|
||||||
defer func() { oc.SetSpanStatus(span, err) }()
|
|
||||||
span.AddAttributes(
|
|
||||||
trace.StringAttribute("layerPath", layerPath),
|
|
||||||
trace.StringAttribute("exportFolderPath", exportFolderPath),
|
|
||||||
)
|
|
||||||
|
|
||||||
ldbytes, err := json.Marshal(layerData)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
obytes, err := json.Marshal(options)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
err = hcsExportLayer(layerPath, exportFolderPath, string(ldbytes), string(obytes))
|
|
||||||
if err != nil {
|
|
||||||
return errors.Wrap(err, "failed to export layer")
|
|
||||||
}
|
|
||||||
return nil
|
|
||||||
}
|
|
|
@ -1,26 +0,0 @@
|
||||||
package computestorage
|
|
||||||
|
|
||||||
import (
|
|
||||||
"context"
|
|
||||||
|
|
||||||
"github.com/Microsoft/hcsshim/internal/oc"
|
|
||||||
"github.com/pkg/errors"
|
|
||||||
"go.opencensus.io/trace"
|
|
||||||
"golang.org/x/sys/windows"
|
|
||||||
)
|
|
||||||
|
|
||||||
// FormatWritableLayerVhd formats a virtual disk for use as a writable container layer.
|
|
||||||
//
|
|
||||||
// If the VHD is not mounted it will be temporarily mounted.
|
|
||||||
func FormatWritableLayerVhd(ctx context.Context, vhdHandle windows.Handle) (err error) {
|
|
||||||
title := "hcsshim.FormatWritableLayerVhd"
|
|
||||||
ctx, span := trace.StartSpan(ctx, title) //nolint:ineffassign,staticcheck
|
|
||||||
defer span.End()
|
|
||||||
defer func() { oc.SetSpanStatus(span, err) }()
|
|
||||||
|
|
||||||
err = hcsFormatWritableLayerVhd(vhdHandle)
|
|
||||||
if err != nil {
|
|
||||||
return errors.Wrap(err, "failed to format writable layer vhd")
|
|
||||||
}
|
|
||||||
return nil
|
|
||||||
}
|
|
|
@ -1,193 +0,0 @@
|
||||||
package computestorage
|
|
||||||
|
|
||||||
import (
|
|
||||||
"context"
|
|
||||||
"os"
|
|
||||||
"path/filepath"
|
|
||||||
"syscall"
|
|
||||||
|
|
||||||
"github.com/Microsoft/go-winio/pkg/security"
|
|
||||||
"github.com/Microsoft/go-winio/vhd"
|
|
||||||
"github.com/pkg/errors"
|
|
||||||
"golang.org/x/sys/windows"
|
|
||||||
)
|
|
||||||
|
|
||||||
const defaultVHDXBlockSizeInMB = 1
|
|
||||||
|
|
||||||
// SetupContainerBaseLayer is a helper to setup a containers scratch. It
|
|
||||||
// will create and format the vhdx's inside and the size is configurable with the sizeInGB
|
|
||||||
// parameter.
|
|
||||||
//
|
|
||||||
// `layerPath` is the path to the base container layer on disk.
|
|
||||||
//
|
|
||||||
// `baseVhdPath` is the path to where the base vhdx for the base layer should be created.
|
|
||||||
//
|
|
||||||
// `diffVhdPath` is the path where the differencing disk for the base layer should be created.
|
|
||||||
//
|
|
||||||
// `sizeInGB` is the size in gigabytes to make the base vhdx.
|
|
||||||
func SetupContainerBaseLayer(ctx context.Context, layerPath, baseVhdPath, diffVhdPath string, sizeInGB uint64) (err error) {
|
|
||||||
var (
|
|
||||||
hivesPath = filepath.Join(layerPath, "Hives")
|
|
||||||
layoutPath = filepath.Join(layerPath, "Layout")
|
|
||||||
)
|
|
||||||
|
|
||||||
// We need to remove the hives directory and layout file as `SetupBaseOSLayer` fails if these files
|
|
||||||
// already exist. `SetupBaseOSLayer` will create these files internally. We also remove the base and
|
|
||||||
// differencing disks if they exist in case we're asking for a different size.
|
|
||||||
if _, err := os.Stat(hivesPath); err == nil {
|
|
||||||
if err := os.RemoveAll(hivesPath); err != nil {
|
|
||||||
return errors.Wrap(err, "failed to remove prexisting hives directory")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if _, err := os.Stat(layoutPath); err == nil {
|
|
||||||
if err := os.RemoveAll(layoutPath); err != nil {
|
|
||||||
return errors.Wrap(err, "failed to remove prexisting layout file")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if _, err := os.Stat(baseVhdPath); err == nil {
|
|
||||||
if err := os.RemoveAll(baseVhdPath); err != nil {
|
|
||||||
return errors.Wrap(err, "failed to remove base vhdx path")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if _, err := os.Stat(diffVhdPath); err == nil {
|
|
||||||
if err := os.RemoveAll(diffVhdPath); err != nil {
|
|
||||||
return errors.Wrap(err, "failed to remove differencing vhdx")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
createParams := &vhd.CreateVirtualDiskParameters{
|
|
||||||
Version: 2,
|
|
||||||
Version2: vhd.CreateVersion2{
|
|
||||||
MaximumSize: sizeInGB * 1024 * 1024 * 1024,
|
|
||||||
BlockSizeInBytes: defaultVHDXBlockSizeInMB * 1024 * 1024,
|
|
||||||
},
|
|
||||||
}
|
|
||||||
handle, err := vhd.CreateVirtualDisk(baseVhdPath, vhd.VirtualDiskAccessNone, vhd.CreateVirtualDiskFlagNone, createParams)
|
|
||||||
if err != nil {
|
|
||||||
return errors.Wrap(err, "failed to create vhdx")
|
|
||||||
}
|
|
||||||
|
|
||||||
defer func() {
|
|
||||||
if err != nil {
|
|
||||||
_ = syscall.CloseHandle(handle)
|
|
||||||
os.RemoveAll(baseVhdPath)
|
|
||||||
os.RemoveAll(diffVhdPath)
|
|
||||||
}
|
|
||||||
}()
|
|
||||||
|
|
||||||
if err = FormatWritableLayerVhd(ctx, windows.Handle(handle)); err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
// Base vhd handle must be closed before calling SetupBaseLayer in case of Container layer
|
|
||||||
if err = syscall.CloseHandle(handle); err != nil {
|
|
||||||
return errors.Wrap(err, "failed to close vhdx handle")
|
|
||||||
}
|
|
||||||
|
|
||||||
options := OsLayerOptions{
|
|
||||||
Type: OsLayerTypeContainer,
|
|
||||||
}
|
|
||||||
|
|
||||||
// SetupBaseOSLayer expects an empty vhd handle for a container layer and will
|
|
||||||
// error out otherwise.
|
|
||||||
if err = SetupBaseOSLayer(ctx, layerPath, 0, options); err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
// Create the differencing disk that will be what's copied for the final rw layer
|
|
||||||
// for a container.
|
|
||||||
if err = vhd.CreateDiffVhd(diffVhdPath, baseVhdPath, defaultVHDXBlockSizeInMB); err != nil {
|
|
||||||
return errors.Wrap(err, "failed to create differencing disk")
|
|
||||||
}
|
|
||||||
|
|
||||||
if err = security.GrantVmGroupAccess(baseVhdPath); err != nil {
|
|
||||||
return errors.Wrapf(err, "failed to grant vm group access to %s", baseVhdPath)
|
|
||||||
}
|
|
||||||
if err = security.GrantVmGroupAccess(diffVhdPath); err != nil {
|
|
||||||
return errors.Wrapf(err, "failed to grant vm group access to %s", diffVhdPath)
|
|
||||||
}
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// SetupUtilityVMBaseLayer is a helper to setup a UVMs scratch space. It will create and format
|
|
||||||
// the vhdx inside and the size is configurable by the sizeInGB parameter.
|
|
||||||
//
|
|
||||||
// `uvmPath` is the path to the UtilityVM filesystem.
|
|
||||||
//
|
|
||||||
// `baseVhdPath` is the path to where the base vhdx for the UVM should be created.
|
|
||||||
//
|
|
||||||
// `diffVhdPath` is the path where the differencing disk for the UVM should be created.
|
|
||||||
//
|
|
||||||
// `sizeInGB` specifies the size in gigabytes to make the base vhdx.
|
|
||||||
func SetupUtilityVMBaseLayer(ctx context.Context, uvmPath, baseVhdPath, diffVhdPath string, sizeInGB uint64) (err error) {
|
|
||||||
// Remove the base and differencing disks if they exist in case we're asking for a different size.
|
|
||||||
if _, err := os.Stat(baseVhdPath); err == nil {
|
|
||||||
if err := os.RemoveAll(baseVhdPath); err != nil {
|
|
||||||
return errors.Wrap(err, "failed to remove base vhdx")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if _, err := os.Stat(diffVhdPath); err == nil {
|
|
||||||
if err := os.RemoveAll(diffVhdPath); err != nil {
|
|
||||||
return errors.Wrap(err, "failed to remove differencing vhdx")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Just create the vhdx for utilityVM layer, no need to format it.
|
|
||||||
createParams := &vhd.CreateVirtualDiskParameters{
|
|
||||||
Version: 2,
|
|
||||||
Version2: vhd.CreateVersion2{
|
|
||||||
MaximumSize: sizeInGB * 1024 * 1024 * 1024,
|
|
||||||
BlockSizeInBytes: defaultVHDXBlockSizeInMB * 1024 * 1024,
|
|
||||||
},
|
|
||||||
}
|
|
||||||
handle, err := vhd.CreateVirtualDisk(baseVhdPath, vhd.VirtualDiskAccessNone, vhd.CreateVirtualDiskFlagNone, createParams)
|
|
||||||
if err != nil {
|
|
||||||
return errors.Wrap(err, "failed to create vhdx")
|
|
||||||
}
|
|
||||||
|
|
||||||
defer func() {
|
|
||||||
if err != nil {
|
|
||||||
_ = syscall.CloseHandle(handle)
|
|
||||||
os.RemoveAll(baseVhdPath)
|
|
||||||
os.RemoveAll(diffVhdPath)
|
|
||||||
}
|
|
||||||
}()
|
|
||||||
|
|
||||||
// If it is a UtilityVM layer then the base vhdx must be attached when calling
|
|
||||||
// `SetupBaseOSLayer`
|
|
||||||
attachParams := &vhd.AttachVirtualDiskParameters{
|
|
||||||
Version: 2,
|
|
||||||
}
|
|
||||||
if err := vhd.AttachVirtualDisk(handle, vhd.AttachVirtualDiskFlagNone, attachParams); err != nil {
|
|
||||||
return errors.Wrapf(err, "failed to attach virtual disk")
|
|
||||||
}
|
|
||||||
|
|
||||||
options := OsLayerOptions{
|
|
||||||
Type: OsLayerTypeVM,
|
|
||||||
}
|
|
||||||
if err := SetupBaseOSLayer(ctx, uvmPath, windows.Handle(handle), options); err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
// Detach and close the handle after setting up the layer as we don't need the handle
|
|
||||||
// for anything else and we no longer need to be attached either.
|
|
||||||
if err = vhd.DetachVirtualDisk(handle); err != nil {
|
|
||||||
return errors.Wrap(err, "failed to detach vhdx")
|
|
||||||
}
|
|
||||||
if err = syscall.CloseHandle(handle); err != nil {
|
|
||||||
return errors.Wrap(err, "failed to close vhdx handle")
|
|
||||||
}
|
|
||||||
|
|
||||||
// Create the differencing disk that will be what's copied for the final rw layer
|
|
||||||
// for a container.
|
|
||||||
if err = vhd.CreateDiffVhd(diffVhdPath, baseVhdPath, defaultVHDXBlockSizeInMB); err != nil {
|
|
||||||
return errors.Wrap(err, "failed to create differencing disk")
|
|
||||||
}
|
|
||||||
|
|
||||||
if err := security.GrantVmGroupAccess(baseVhdPath); err != nil {
|
|
||||||
return errors.Wrapf(err, "failed to grant vm group access to %s", baseVhdPath)
|
|
||||||
}
|
|
||||||
if err := security.GrantVmGroupAccess(diffVhdPath); err != nil {
|
|
||||||
return errors.Wrapf(err, "failed to grant vm group access to %s", diffVhdPath)
|
|
||||||
}
|
|
||||||
return nil
|
|
||||||
}
|
|
|
@ -1,41 +0,0 @@
|
||||||
package computestorage
|
|
||||||
|
|
||||||
import (
|
|
||||||
"context"
|
|
||||||
"encoding/json"
|
|
||||||
|
|
||||||
"github.com/Microsoft/hcsshim/internal/oc"
|
|
||||||
"github.com/pkg/errors"
|
|
||||||
"go.opencensus.io/trace"
|
|
||||||
)
|
|
||||||
|
|
||||||
// ImportLayer imports a container layer.
|
|
||||||
//
|
|
||||||
// `layerPath` is a path to a directory to import the layer to. If the directory
|
|
||||||
// does not exist it will be automatically created.
|
|
||||||
//
|
|
||||||
// `sourceFolderpath` is a pre-existing folder that contains the layer to
|
|
||||||
// import.
|
|
||||||
//
|
|
||||||
// `layerData` is the parent layer data.
|
|
||||||
func ImportLayer(ctx context.Context, layerPath, sourceFolderPath string, layerData LayerData) (err error) {
|
|
||||||
title := "hcsshim.ImportLayer"
|
|
||||||
ctx, span := trace.StartSpan(ctx, title) //nolint:ineffassign,staticcheck
|
|
||||||
defer span.End()
|
|
||||||
defer func() { oc.SetSpanStatus(span, err) }()
|
|
||||||
span.AddAttributes(
|
|
||||||
trace.StringAttribute("layerPath", layerPath),
|
|
||||||
trace.StringAttribute("sourceFolderPath", sourceFolderPath),
|
|
||||||
)
|
|
||||||
|
|
||||||
bytes, err := json.Marshal(layerData)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
err = hcsImportLayer(layerPath, sourceFolderPath, string(bytes))
|
|
||||||
if err != nil {
|
|
||||||
return errors.Wrap(err, "failed to import layer")
|
|
||||||
}
|
|
||||||
return nil
|
|
||||||
}
|
|
|
@ -1,38 +0,0 @@
|
||||||
package computestorage
|
|
||||||
|
|
||||||
import (
|
|
||||||
"context"
|
|
||||||
"encoding/json"
|
|
||||||
|
|
||||||
"github.com/Microsoft/hcsshim/internal/oc"
|
|
||||||
"github.com/pkg/errors"
|
|
||||||
"go.opencensus.io/trace"
|
|
||||||
)
|
|
||||||
|
|
||||||
// InitializeWritableLayer initializes a writable layer for a container.
|
|
||||||
//
|
|
||||||
// `layerPath` is a path to a directory the layer is mounted. If the
|
|
||||||
// path does not end in a `\` the platform will append it automatically.
|
|
||||||
//
|
|
||||||
// `layerData` is the parent read-only layer data.
|
|
||||||
func InitializeWritableLayer(ctx context.Context, layerPath string, layerData LayerData) (err error) {
|
|
||||||
title := "hcsshim.InitializeWritableLayer"
|
|
||||||
ctx, span := trace.StartSpan(ctx, title) //nolint:ineffassign,staticcheck
|
|
||||||
defer span.End()
|
|
||||||
defer func() { oc.SetSpanStatus(span, err) }()
|
|
||||||
span.AddAttributes(
|
|
||||||
trace.StringAttribute("layerPath", layerPath),
|
|
||||||
)
|
|
||||||
|
|
||||||
bytes, err := json.Marshal(layerData)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
// Options are not used in the platform as of RS5
|
|
||||||
err = hcsInitializeWritableLayer(layerPath, string(bytes), "")
|
|
||||||
if err != nil {
|
|
||||||
return errors.Wrap(err, "failed to intitialize container layer")
|
|
||||||
}
|
|
||||||
return nil
|
|
||||||
}
|
|
|
@ -1,27 +0,0 @@
|
||||||
package computestorage
|
|
||||||
|
|
||||||
import (
|
|
||||||
"context"
|
|
||||||
|
|
||||||
"github.com/Microsoft/hcsshim/internal/interop"
|
|
||||||
"github.com/Microsoft/hcsshim/internal/oc"
|
|
||||||
"github.com/pkg/errors"
|
|
||||||
"go.opencensus.io/trace"
|
|
||||||
"golang.org/x/sys/windows"
|
|
||||||
)
|
|
||||||
|
|
||||||
// GetLayerVhdMountPath returns the volume path for a virtual disk of a writable container layer.
|
|
||||||
func GetLayerVhdMountPath(ctx context.Context, vhdHandle windows.Handle) (path string, err error) {
|
|
||||||
title := "hcsshim.GetLayerVhdMountPath"
|
|
||||||
ctx, span := trace.StartSpan(ctx, title) //nolint:ineffassign,staticcheck
|
|
||||||
defer span.End()
|
|
||||||
defer func() { oc.SetSpanStatus(span, err) }()
|
|
||||||
|
|
||||||
var mountPath *uint16
|
|
||||||
err = hcsGetLayerVhdMountPath(vhdHandle, &mountPath)
|
|
||||||
if err != nil {
|
|
||||||
return "", errors.Wrap(err, "failed to get vhd mount path")
|
|
||||||
}
|
|
||||||
path = interop.ConvertAndFreeCoTaskMemString(mountPath)
|
|
||||||
return path, nil
|
|
||||||
}
|
|
|
@ -1,74 +0,0 @@
|
||||||
package computestorage
|
|
||||||
|
|
||||||
import (
|
|
||||||
"context"
|
|
||||||
"encoding/json"
|
|
||||||
|
|
||||||
"github.com/Microsoft/hcsshim/internal/oc"
|
|
||||||
"github.com/Microsoft/hcsshim/osversion"
|
|
||||||
"github.com/pkg/errors"
|
|
||||||
"go.opencensus.io/trace"
|
|
||||||
"golang.org/x/sys/windows"
|
|
||||||
)
|
|
||||||
|
|
||||||
// SetupBaseOSLayer sets up a layer that contains a base OS for a container.
|
|
||||||
//
|
|
||||||
// `layerPath` is a path to a directory containing the layer.
|
|
||||||
//
|
|
||||||
// `vhdHandle` is an empty file handle of `options.Type == OsLayerTypeContainer`
|
|
||||||
// or else it is a file handle to the 'SystemTemplateBase.vhdx' if `options.Type
|
|
||||||
// == OsLayerTypeVm`.
|
|
||||||
//
|
|
||||||
// `options` are the options applied while processing the layer.
|
|
||||||
func SetupBaseOSLayer(ctx context.Context, layerPath string, vhdHandle windows.Handle, options OsLayerOptions) (err error) {
|
|
||||||
title := "hcsshim.SetupBaseOSLayer"
|
|
||||||
ctx, span := trace.StartSpan(ctx, title) //nolint:ineffassign,staticcheck
|
|
||||||
defer span.End()
|
|
||||||
defer func() { oc.SetSpanStatus(span, err) }()
|
|
||||||
span.AddAttributes(
|
|
||||||
trace.StringAttribute("layerPath", layerPath),
|
|
||||||
)
|
|
||||||
|
|
||||||
bytes, err := json.Marshal(options)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
err = hcsSetupBaseOSLayer(layerPath, vhdHandle, string(bytes))
|
|
||||||
if err != nil {
|
|
||||||
return errors.Wrap(err, "failed to setup base OS layer")
|
|
||||||
}
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// SetupBaseOSVolume sets up a volume that contains a base OS for a container.
|
|
||||||
//
|
|
||||||
// `layerPath` is a path to a directory containing the layer.
|
|
||||||
//
|
|
||||||
// `volumePath` is the path to the volume to be used for setup.
|
|
||||||
//
|
|
||||||
// `options` are the options applied while processing the layer.
|
|
||||||
func SetupBaseOSVolume(ctx context.Context, layerPath, volumePath string, options OsLayerOptions) (err error) {
|
|
||||||
if osversion.Get().Build < 19645 {
|
|
||||||
return errors.New("SetupBaseOSVolume is not present on builds older than 19645")
|
|
||||||
}
|
|
||||||
title := "hcsshim.SetupBaseOSVolume"
|
|
||||||
ctx, span := trace.StartSpan(ctx, title) //nolint:ineffassign,staticcheck
|
|
||||||
defer span.End()
|
|
||||||
defer func() { oc.SetSpanStatus(span, err) }()
|
|
||||||
span.AddAttributes(
|
|
||||||
trace.StringAttribute("layerPath", layerPath),
|
|
||||||
trace.StringAttribute("volumePath", volumePath),
|
|
||||||
)
|
|
||||||
|
|
||||||
bytes, err := json.Marshal(options)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
err = hcsSetupBaseOSVolume(layerPath, volumePath, string(bytes))
|
|
||||||
if err != nil {
|
|
||||||
return errors.Wrap(err, "failed to setup base OS layer")
|
|
||||||
}
|
|
||||||
return nil
|
|
||||||
}
|
|
|
@ -1,50 +0,0 @@
|
||||||
// Package computestorage is a wrapper around the HCS storage APIs. These are new storage APIs introduced
|
|
||||||
// separate from the original graphdriver calls intended to give more freedom around creating
|
|
||||||
// and managing container layers and scratch spaces.
|
|
||||||
package computestorage
|
|
||||||
|
|
||||||
import (
|
|
||||||
hcsschema "github.com/Microsoft/hcsshim/internal/schema2"
|
|
||||||
)
|
|
||||||
|
|
||||||
//go:generate go run ../mksyscall_windows.go -output zsyscall_windows.go storage.go
|
|
||||||
|
|
||||||
//sys hcsImportLayer(layerPath string, sourceFolderPath string, layerData string) (hr error) = computestorage.HcsImportLayer?
|
|
||||||
//sys hcsExportLayer(layerPath string, exportFolderPath string, layerData string, options string) (hr error) = computestorage.HcsExportLayer?
|
|
||||||
//sys hcsDestroyLayer(layerPath string) (hr error) = computestorage.HcsDestoryLayer?
|
|
||||||
//sys hcsSetupBaseOSLayer(layerPath string, handle windows.Handle, options string) (hr error) = computestorage.HcsSetupBaseOSLayer?
|
|
||||||
//sys hcsInitializeWritableLayer(writableLayerPath string, layerData string, options string) (hr error) = computestorage.HcsInitializeWritableLayer?
|
|
||||||
//sys hcsAttachLayerStorageFilter(layerPath string, layerData string) (hr error) = computestorage.HcsAttachLayerStorageFilter?
|
|
||||||
//sys hcsDetachLayerStorageFilter(layerPath string) (hr error) = computestorage.HcsDetachLayerStorageFilter?
|
|
||||||
//sys hcsFormatWritableLayerVhd(handle windows.Handle) (hr error) = computestorage.HcsFormatWritableLayerVhd?
|
|
||||||
//sys hcsGetLayerVhdMountPath(vhdHandle windows.Handle, mountPath **uint16) (hr error) = computestorage.HcsGetLayerVhdMountPath?
|
|
||||||
//sys hcsSetupBaseOSVolume(layerPath string, volumePath string, options string) (hr error) = computestorage.HcsSetupBaseOSVolume?
|
|
||||||
|
|
||||||
// LayerData is the data used to describe parent layer information.
|
|
||||||
type LayerData struct {
|
|
||||||
SchemaVersion hcsschema.Version `json:"SchemaVersion,omitempty"`
|
|
||||||
Layers []hcsschema.Layer `json:"Layers,omitempty"`
|
|
||||||
}
|
|
||||||
|
|
||||||
// ExportLayerOptions are the set of options that are used with the `computestorage.HcsExportLayer` syscall.
|
|
||||||
type ExportLayerOptions struct {
|
|
||||||
IsWritableLayer bool `json:"IsWritableLayer,omitempty"`
|
|
||||||
}
|
|
||||||
|
|
||||||
// OsLayerType is the type of layer being operated on.
|
|
||||||
type OsLayerType string
|
|
||||||
|
|
||||||
const (
|
|
||||||
// OsLayerTypeContainer is a container layer.
|
|
||||||
OsLayerTypeContainer OsLayerType = "Container"
|
|
||||||
// OsLayerTypeVM is a virtual machine layer.
|
|
||||||
OsLayerTypeVM OsLayerType = "Vm"
|
|
||||||
)
|
|
||||||
|
|
||||||
// OsLayerOptions are the set of options that are used with the `SetupBaseOSLayer` and
|
|
||||||
// `SetupBaseOSVolume` calls.
|
|
||||||
type OsLayerOptions struct {
|
|
||||||
Type OsLayerType `json:"Type,omitempty"`
|
|
||||||
DisableCiCacheOptimization bool `json:"DisableCiCacheOptimization,omitempty"`
|
|
||||||
SkipUpdateBcdForBoot bool `json:"SkipUpdateBcdForBoot,omitempty"`
|
|
||||||
}
|
|
|
@ -1,319 +0,0 @@
|
||||||
// Code generated mksyscall_windows.exe DO NOT EDIT
|
|
||||||
|
|
||||||
package computestorage
|
|
||||||
|
|
||||||
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 (
|
|
||||||
modcomputestorage = windows.NewLazySystemDLL("computestorage.dll")
|
|
||||||
|
|
||||||
procHcsImportLayer = modcomputestorage.NewProc("HcsImportLayer")
|
|
||||||
procHcsExportLayer = modcomputestorage.NewProc("HcsExportLayer")
|
|
||||||
procHcsDestoryLayer = modcomputestorage.NewProc("HcsDestoryLayer")
|
|
||||||
procHcsSetupBaseOSLayer = modcomputestorage.NewProc("HcsSetupBaseOSLayer")
|
|
||||||
procHcsInitializeWritableLayer = modcomputestorage.NewProc("HcsInitializeWritableLayer")
|
|
||||||
procHcsAttachLayerStorageFilter = modcomputestorage.NewProc("HcsAttachLayerStorageFilter")
|
|
||||||
procHcsDetachLayerStorageFilter = modcomputestorage.NewProc("HcsDetachLayerStorageFilter")
|
|
||||||
procHcsFormatWritableLayerVhd = modcomputestorage.NewProc("HcsFormatWritableLayerVhd")
|
|
||||||
procHcsGetLayerVhdMountPath = modcomputestorage.NewProc("HcsGetLayerVhdMountPath")
|
|
||||||
procHcsSetupBaseOSVolume = modcomputestorage.NewProc("HcsSetupBaseOSVolume")
|
|
||||||
)
|
|
||||||
|
|
||||||
func hcsImportLayer(layerPath string, sourceFolderPath string, layerData string) (hr error) {
|
|
||||||
var _p0 *uint16
|
|
||||||
_p0, hr = syscall.UTF16PtrFromString(layerPath)
|
|
||||||
if hr != nil {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
var _p1 *uint16
|
|
||||||
_p1, hr = syscall.UTF16PtrFromString(sourceFolderPath)
|
|
||||||
if hr != nil {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
var _p2 *uint16
|
|
||||||
_p2, hr = syscall.UTF16PtrFromString(layerData)
|
|
||||||
if hr != nil {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
return _hcsImportLayer(_p0, _p1, _p2)
|
|
||||||
}
|
|
||||||
|
|
||||||
func _hcsImportLayer(layerPath *uint16, sourceFolderPath *uint16, layerData *uint16) (hr error) {
|
|
||||||
if hr = procHcsImportLayer.Find(); hr != nil {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
r0, _, _ := syscall.Syscall(procHcsImportLayer.Addr(), 3, uintptr(unsafe.Pointer(layerPath)), uintptr(unsafe.Pointer(sourceFolderPath)), uintptr(unsafe.Pointer(layerData)))
|
|
||||||
if int32(r0) < 0 {
|
|
||||||
if r0&0x1fff0000 == 0x00070000 {
|
|
||||||
r0 &= 0xffff
|
|
||||||
}
|
|
||||||
hr = syscall.Errno(r0)
|
|
||||||
}
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
func hcsExportLayer(layerPath string, exportFolderPath string, layerData string, options string) (hr error) {
|
|
||||||
var _p0 *uint16
|
|
||||||
_p0, hr = syscall.UTF16PtrFromString(layerPath)
|
|
||||||
if hr != nil {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
var _p1 *uint16
|
|
||||||
_p1, hr = syscall.UTF16PtrFromString(exportFolderPath)
|
|
||||||
if hr != nil {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
var _p2 *uint16
|
|
||||||
_p2, hr = syscall.UTF16PtrFromString(layerData)
|
|
||||||
if hr != nil {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
var _p3 *uint16
|
|
||||||
_p3, hr = syscall.UTF16PtrFromString(options)
|
|
||||||
if hr != nil {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
return _hcsExportLayer(_p0, _p1, _p2, _p3)
|
|
||||||
}
|
|
||||||
|
|
||||||
func _hcsExportLayer(layerPath *uint16, exportFolderPath *uint16, layerData *uint16, options *uint16) (hr error) {
|
|
||||||
if hr = procHcsExportLayer.Find(); hr != nil {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
r0, _, _ := syscall.Syscall6(procHcsExportLayer.Addr(), 4, uintptr(unsafe.Pointer(layerPath)), uintptr(unsafe.Pointer(exportFolderPath)), uintptr(unsafe.Pointer(layerData)), uintptr(unsafe.Pointer(options)), 0, 0)
|
|
||||||
if int32(r0) < 0 {
|
|
||||||
if r0&0x1fff0000 == 0x00070000 {
|
|
||||||
r0 &= 0xffff
|
|
||||||
}
|
|
||||||
hr = syscall.Errno(r0)
|
|
||||||
}
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
func hcsDestroyLayer(layerPath string) (hr error) {
|
|
||||||
var _p0 *uint16
|
|
||||||
_p0, hr = syscall.UTF16PtrFromString(layerPath)
|
|
||||||
if hr != nil {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
return _hcsDestroyLayer(_p0)
|
|
||||||
}
|
|
||||||
|
|
||||||
func _hcsDestroyLayer(layerPath *uint16) (hr error) {
|
|
||||||
if hr = procHcsDestoryLayer.Find(); hr != nil {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
r0, _, _ := syscall.Syscall(procHcsDestoryLayer.Addr(), 1, uintptr(unsafe.Pointer(layerPath)), 0, 0)
|
|
||||||
if int32(r0) < 0 {
|
|
||||||
if r0&0x1fff0000 == 0x00070000 {
|
|
||||||
r0 &= 0xffff
|
|
||||||
}
|
|
||||||
hr = syscall.Errno(r0)
|
|
||||||
}
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
func hcsSetupBaseOSLayer(layerPath string, handle windows.Handle, options string) (hr error) {
|
|
||||||
var _p0 *uint16
|
|
||||||
_p0, hr = syscall.UTF16PtrFromString(layerPath)
|
|
||||||
if hr != nil {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
var _p1 *uint16
|
|
||||||
_p1, hr = syscall.UTF16PtrFromString(options)
|
|
||||||
if hr != nil {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
return _hcsSetupBaseOSLayer(_p0, handle, _p1)
|
|
||||||
}
|
|
||||||
|
|
||||||
func _hcsSetupBaseOSLayer(layerPath *uint16, handle windows.Handle, options *uint16) (hr error) {
|
|
||||||
if hr = procHcsSetupBaseOSLayer.Find(); hr != nil {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
r0, _, _ := syscall.Syscall(procHcsSetupBaseOSLayer.Addr(), 3, uintptr(unsafe.Pointer(layerPath)), uintptr(handle), uintptr(unsafe.Pointer(options)))
|
|
||||||
if int32(r0) < 0 {
|
|
||||||
if r0&0x1fff0000 == 0x00070000 {
|
|
||||||
r0 &= 0xffff
|
|
||||||
}
|
|
||||||
hr = syscall.Errno(r0)
|
|
||||||
}
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
func hcsInitializeWritableLayer(writableLayerPath string, layerData string, options string) (hr error) {
|
|
||||||
var _p0 *uint16
|
|
||||||
_p0, hr = syscall.UTF16PtrFromString(writableLayerPath)
|
|
||||||
if hr != nil {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
var _p1 *uint16
|
|
||||||
_p1, hr = syscall.UTF16PtrFromString(layerData)
|
|
||||||
if hr != nil {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
var _p2 *uint16
|
|
||||||
_p2, hr = syscall.UTF16PtrFromString(options)
|
|
||||||
if hr != nil {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
return _hcsInitializeWritableLayer(_p0, _p1, _p2)
|
|
||||||
}
|
|
||||||
|
|
||||||
func _hcsInitializeWritableLayer(writableLayerPath *uint16, layerData *uint16, options *uint16) (hr error) {
|
|
||||||
if hr = procHcsInitializeWritableLayer.Find(); hr != nil {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
r0, _, _ := syscall.Syscall(procHcsInitializeWritableLayer.Addr(), 3, uintptr(unsafe.Pointer(writableLayerPath)), uintptr(unsafe.Pointer(layerData)), uintptr(unsafe.Pointer(options)))
|
|
||||||
if int32(r0) < 0 {
|
|
||||||
if r0&0x1fff0000 == 0x00070000 {
|
|
||||||
r0 &= 0xffff
|
|
||||||
}
|
|
||||||
hr = syscall.Errno(r0)
|
|
||||||
}
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
func hcsAttachLayerStorageFilter(layerPath string, layerData string) (hr error) {
|
|
||||||
var _p0 *uint16
|
|
||||||
_p0, hr = syscall.UTF16PtrFromString(layerPath)
|
|
||||||
if hr != nil {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
var _p1 *uint16
|
|
||||||
_p1, hr = syscall.UTF16PtrFromString(layerData)
|
|
||||||
if hr != nil {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
return _hcsAttachLayerStorageFilter(_p0, _p1)
|
|
||||||
}
|
|
||||||
|
|
||||||
func _hcsAttachLayerStorageFilter(layerPath *uint16, layerData *uint16) (hr error) {
|
|
||||||
if hr = procHcsAttachLayerStorageFilter.Find(); hr != nil {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
r0, _, _ := syscall.Syscall(procHcsAttachLayerStorageFilter.Addr(), 2, uintptr(unsafe.Pointer(layerPath)), uintptr(unsafe.Pointer(layerData)), 0)
|
|
||||||
if int32(r0) < 0 {
|
|
||||||
if r0&0x1fff0000 == 0x00070000 {
|
|
||||||
r0 &= 0xffff
|
|
||||||
}
|
|
||||||
hr = syscall.Errno(r0)
|
|
||||||
}
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
func hcsDetachLayerStorageFilter(layerPath string) (hr error) {
|
|
||||||
var _p0 *uint16
|
|
||||||
_p0, hr = syscall.UTF16PtrFromString(layerPath)
|
|
||||||
if hr != nil {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
return _hcsDetachLayerStorageFilter(_p0)
|
|
||||||
}
|
|
||||||
|
|
||||||
func _hcsDetachLayerStorageFilter(layerPath *uint16) (hr error) {
|
|
||||||
if hr = procHcsDetachLayerStorageFilter.Find(); hr != nil {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
r0, _, _ := syscall.Syscall(procHcsDetachLayerStorageFilter.Addr(), 1, uintptr(unsafe.Pointer(layerPath)), 0, 0)
|
|
||||||
if int32(r0) < 0 {
|
|
||||||
if r0&0x1fff0000 == 0x00070000 {
|
|
||||||
r0 &= 0xffff
|
|
||||||
}
|
|
||||||
hr = syscall.Errno(r0)
|
|
||||||
}
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
func hcsFormatWritableLayerVhd(handle windows.Handle) (hr error) {
|
|
||||||
if hr = procHcsFormatWritableLayerVhd.Find(); hr != nil {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
r0, _, _ := syscall.Syscall(procHcsFormatWritableLayerVhd.Addr(), 1, uintptr(handle), 0, 0)
|
|
||||||
if int32(r0) < 0 {
|
|
||||||
if r0&0x1fff0000 == 0x00070000 {
|
|
||||||
r0 &= 0xffff
|
|
||||||
}
|
|
||||||
hr = syscall.Errno(r0)
|
|
||||||
}
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
func hcsGetLayerVhdMountPath(vhdHandle windows.Handle, mountPath **uint16) (hr error) {
|
|
||||||
if hr = procHcsGetLayerVhdMountPath.Find(); hr != nil {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
r0, _, _ := syscall.Syscall(procHcsGetLayerVhdMountPath.Addr(), 2, uintptr(vhdHandle), uintptr(unsafe.Pointer(mountPath)), 0)
|
|
||||||
if int32(r0) < 0 {
|
|
||||||
if r0&0x1fff0000 == 0x00070000 {
|
|
||||||
r0 &= 0xffff
|
|
||||||
}
|
|
||||||
hr = syscall.Errno(r0)
|
|
||||||
}
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
func hcsSetupBaseOSVolume(layerPath string, volumePath string, options string) (hr error) {
|
|
||||||
var _p0 *uint16
|
|
||||||
_p0, hr = syscall.UTF16PtrFromString(layerPath)
|
|
||||||
if hr != nil {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
var _p1 *uint16
|
|
||||||
_p1, hr = syscall.UTF16PtrFromString(volumePath)
|
|
||||||
if hr != nil {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
var _p2 *uint16
|
|
||||||
_p2, hr = syscall.UTF16PtrFromString(options)
|
|
||||||
if hr != nil {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
return _hcsSetupBaseOSVolume(_p0, _p1, _p2)
|
|
||||||
}
|
|
||||||
|
|
||||||
func _hcsSetupBaseOSVolume(layerPath *uint16, volumePath *uint16, options *uint16) (hr error) {
|
|
||||||
if hr = procHcsSetupBaseOSVolume.Find(); hr != nil {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
r0, _, _ := syscall.Syscall(procHcsSetupBaseOSVolume.Addr(), 3, uintptr(unsafe.Pointer(layerPath)), uintptr(unsafe.Pointer(volumePath)), uintptr(unsafe.Pointer(options)))
|
|
||||||
if int32(r0) < 0 {
|
|
||||||
if r0&0x1fff0000 == 0x00070000 {
|
|
||||||
r0 &= 0xffff
|
|
||||||
}
|
|
||||||
hr = syscall.Errno(r0)
|
|
||||||
}
|
|
||||||
return
|
|
||||||
}
|
|
|
@ -1,223 +0,0 @@
|
||||||
package hcsshim
|
|
||||||
|
|
||||||
import (
|
|
||||||
"context"
|
|
||||||
"fmt"
|
|
||||||
"os"
|
|
||||||
"sync"
|
|
||||||
"time"
|
|
||||||
|
|
||||||
"github.com/Microsoft/hcsshim/internal/hcs"
|
|
||||||
"github.com/Microsoft/hcsshim/internal/mergemaps"
|
|
||||||
"github.com/Microsoft/hcsshim/internal/schema1"
|
|
||||||
)
|
|
||||||
|
|
||||||
// ContainerProperties holds the properties for a container and the processes running in that container
|
|
||||||
type ContainerProperties = schema1.ContainerProperties
|
|
||||||
|
|
||||||
// MemoryStats holds the memory statistics for a container
|
|
||||||
type MemoryStats = schema1.MemoryStats
|
|
||||||
|
|
||||||
// ProcessorStats holds the processor statistics for a container
|
|
||||||
type ProcessorStats = schema1.ProcessorStats
|
|
||||||
|
|
||||||
// StorageStats holds the storage statistics for a container
|
|
||||||
type StorageStats = schema1.StorageStats
|
|
||||||
|
|
||||||
// NetworkStats holds the network statistics for a container
|
|
||||||
type NetworkStats = schema1.NetworkStats
|
|
||||||
|
|
||||||
// Statistics is the structure returned by a statistics call on a container
|
|
||||||
type Statistics = schema1.Statistics
|
|
||||||
|
|
||||||
// ProcessList is the structure of an item returned by a ProcessList call on a container
|
|
||||||
type ProcessListItem = schema1.ProcessListItem
|
|
||||||
|
|
||||||
// MappedVirtualDiskController is the structure of an item returned by a MappedVirtualDiskList call on a container
|
|
||||||
type MappedVirtualDiskController = schema1.MappedVirtualDiskController
|
|
||||||
|
|
||||||
// Type of Request Support in ModifySystem
|
|
||||||
type RequestType = schema1.RequestType
|
|
||||||
|
|
||||||
// Type of Resource Support in ModifySystem
|
|
||||||
type ResourceType = schema1.ResourceType
|
|
||||||
|
|
||||||
// RequestType const
|
|
||||||
const (
|
|
||||||
Add = schema1.Add
|
|
||||||
Remove = schema1.Remove
|
|
||||||
Network = schema1.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 = schema1.ResourceModificationRequestResponse
|
|
||||||
|
|
||||||
type container struct {
|
|
||||||
system *hcs.System
|
|
||||||
waitOnce sync.Once
|
|
||||||
waitErr error
|
|
||||||
waitCh chan struct{}
|
|
||||||
}
|
|
||||||
|
|
||||||
// createComputeSystemAdditionalJSON is read from the environment at initialisation
|
|
||||||
// time. It allows an environment variable to define additional JSON which
|
|
||||||
// is merged in the CreateComputeSystem call to HCS.
|
|
||||||
var createContainerAdditionalJSON []byte
|
|
||||||
|
|
||||||
func init() {
|
|
||||||
createContainerAdditionalJSON = ([]byte)(os.Getenv("HCSSHIM_CREATECONTAINER_ADDITIONALJSON"))
|
|
||||||
}
|
|
||||||
|
|
||||||
// CreateContainer creates a new container with the given configuration but does not start it.
|
|
||||||
func CreateContainer(id string, c *ContainerConfig) (Container, error) {
|
|
||||||
fullConfig, err := mergemaps.MergeJSON(c, createContainerAdditionalJSON)
|
|
||||||
if err != nil {
|
|
||||||
return nil, fmt.Errorf("failed to merge additional JSON '%s': %s", createContainerAdditionalJSON, err)
|
|
||||||
}
|
|
||||||
|
|
||||||
system, err := hcs.CreateComputeSystem(context.Background(), id, fullConfig)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
return &container{system: system}, err
|
|
||||||
}
|
|
||||||
|
|
||||||
// OpenContainer opens an existing container by ID.
|
|
||||||
func OpenContainer(id string) (Container, error) {
|
|
||||||
system, err := hcs.OpenComputeSystem(context.Background(), id)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
return &container{system: system}, err
|
|
||||||
}
|
|
||||||
|
|
||||||
// GetContainers gets a list of the containers on the system that match the query
|
|
||||||
func GetContainers(q ComputeSystemQuery) ([]ContainerProperties, error) {
|
|
||||||
return hcs.GetComputeSystems(context.Background(), q)
|
|
||||||
}
|
|
||||||
|
|
||||||
// Start synchronously starts the container.
|
|
||||||
func (container *container) Start() error {
|
|
||||||
return convertSystemError(container.system.Start(context.Background()), container)
|
|
||||||
}
|
|
||||||
|
|
||||||
// Shutdown requests a container shutdown, but it may not actually be shutdown until Wait() succeeds.
|
|
||||||
func (container *container) Shutdown() error {
|
|
||||||
err := container.system.Shutdown(context.Background())
|
|
||||||
if err != nil {
|
|
||||||
return convertSystemError(err, container)
|
|
||||||
}
|
|
||||||
return &ContainerError{Container: container, Err: ErrVmcomputeOperationPending, Operation: "hcsshim::ComputeSystem::Shutdown"}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Terminate requests a container terminate, but it may not actually be terminated until Wait() succeeds.
|
|
||||||
func (container *container) Terminate() error {
|
|
||||||
err := container.system.Terminate(context.Background())
|
|
||||||
if err != nil {
|
|
||||||
return convertSystemError(err, container)
|
|
||||||
}
|
|
||||||
return &ContainerError{Container: container, Err: ErrVmcomputeOperationPending, Operation: "hcsshim::ComputeSystem::Terminate"}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Waits synchronously waits for the container to shutdown or terminate.
|
|
||||||
func (container *container) Wait() error {
|
|
||||||
err := container.system.Wait()
|
|
||||||
if err == nil {
|
|
||||||
err = container.system.ExitError()
|
|
||||||
}
|
|
||||||
return convertSystemError(err, container)
|
|
||||||
}
|
|
||||||
|
|
||||||
// WaitTimeout synchronously waits for the container to terminate or the duration to elapse. It
|
|
||||||
// returns false if timeout occurs.
|
|
||||||
func (container *container) WaitTimeout(timeout time.Duration) error {
|
|
||||||
container.waitOnce.Do(func() {
|
|
||||||
container.waitCh = make(chan struct{})
|
|
||||||
go func() {
|
|
||||||
container.waitErr = container.Wait()
|
|
||||||
close(container.waitCh)
|
|
||||||
}()
|
|
||||||
})
|
|
||||||
t := time.NewTimer(timeout)
|
|
||||||
defer t.Stop()
|
|
||||||
select {
|
|
||||||
case <-t.C:
|
|
||||||
return &ContainerError{Container: container, Err: ErrTimeout, Operation: "hcsshim::ComputeSystem::Wait"}
|
|
||||||
case <-container.waitCh:
|
|
||||||
return container.waitErr
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Pause pauses the execution of a container.
|
|
||||||
func (container *container) Pause() error {
|
|
||||||
return convertSystemError(container.system.Pause(context.Background()), container)
|
|
||||||
}
|
|
||||||
|
|
||||||
// Resume resumes the execution of a container.
|
|
||||||
func (container *container) Resume() error {
|
|
||||||
return convertSystemError(container.system.Resume(context.Background()), container)
|
|
||||||
}
|
|
||||||
|
|
||||||
// HasPendingUpdates returns true if the container has updates pending to install
|
|
||||||
func (container *container) HasPendingUpdates() (bool, error) {
|
|
||||||
return false, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// Statistics returns statistics for the container. This is a legacy v1 call
|
|
||||||
func (container *container) Statistics() (Statistics, error) {
|
|
||||||
properties, err := container.system.Properties(context.Background(), schema1.PropertyTypeStatistics)
|
|
||||||
if err != nil {
|
|
||||||
return Statistics{}, convertSystemError(err, container)
|
|
||||||
}
|
|
||||||
|
|
||||||
return properties.Statistics, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// ProcessList returns an array of ProcessListItems for the container. This is a legacy v1 call
|
|
||||||
func (container *container) ProcessList() ([]ProcessListItem, error) {
|
|
||||||
properties, err := container.system.Properties(context.Background(), schema1.PropertyTypeProcessList)
|
|
||||||
if err != nil {
|
|
||||||
return nil, convertSystemError(err, container)
|
|
||||||
}
|
|
||||||
|
|
||||||
return properties.ProcessList, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// This is a legacy v1 call
|
|
||||||
func (container *container) MappedVirtualDisks() (map[int]MappedVirtualDiskController, error) {
|
|
||||||
properties, err := container.system.Properties(context.Background(), schema1.PropertyTypeMappedVirtualDisk)
|
|
||||||
if err != nil {
|
|
||||||
return nil, convertSystemError(err, container)
|
|
||||||
}
|
|
||||||
|
|
||||||
return properties.MappedVirtualDiskControllers, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// CreateProcess launches a new process within the container.
|
|
||||||
func (container *container) CreateProcess(c *ProcessConfig) (Process, error) {
|
|
||||||
p, err := container.system.CreateProcess(context.Background(), c)
|
|
||||||
if err != nil {
|
|
||||||
return nil, convertSystemError(err, container)
|
|
||||||
}
|
|
||||||
return &process{p: p.(*hcs.Process)}, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// OpenProcess gets an interface to an existing process within the container.
|
|
||||||
func (container *container) OpenProcess(pid int) (Process, error) {
|
|
||||||
p, err := container.system.OpenProcess(context.Background(), pid)
|
|
||||||
if err != nil {
|
|
||||||
return nil, convertSystemError(err, container)
|
|
||||||
}
|
|
||||||
return &process{p: p}, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// Close cleans up any state associated with the container but does not terminate or wait for it.
|
|
||||||
func (container *container) Close() error {
|
|
||||||
return convertSystemError(container.system.Close(), container)
|
|
||||||
}
|
|
||||||
|
|
||||||
// Modify the System
|
|
||||||
func (container *container) Modify(config *ResourceModificationRequestResponse) error {
|
|
||||||
return convertSystemError(container.system.Modify(context.Background(), config), container)
|
|
||||||
}
|
|
|
@ -1,245 +0,0 @@
|
||||||
package hcsshim
|
|
||||||
|
|
||||||
import (
|
|
||||||
"fmt"
|
|
||||||
"syscall"
|
|
||||||
|
|
||||||
"github.com/Microsoft/hcsshim/internal/hns"
|
|
||||||
|
|
||||||
"github.com/Microsoft/hcsshim/internal/hcs"
|
|
||||||
"github.com/Microsoft/hcsshim/internal/hcserror"
|
|
||||||
)
|
|
||||||
|
|
||||||
var (
|
|
||||||
// ErrComputeSystemDoesNotExist is an error encountered when the container being operated on no longer exists = hcs.exist
|
|
||||||
ErrComputeSystemDoesNotExist = hcs.ErrComputeSystemDoesNotExist
|
|
||||||
|
|
||||||
// ErrElementNotFound is an error encountered when the object being referenced does not exist
|
|
||||||
ErrElementNotFound = hcs.ErrElementNotFound
|
|
||||||
|
|
||||||
// ErrElementNotFound is an error encountered when the object being referenced does not exist
|
|
||||||
ErrNotSupported = hcs.ErrNotSupported
|
|
||||||
|
|
||||||
// ErrInvalidData is an error encountered when the request being sent to hcs is invalid/unsupported
|
|
||||||
// decimal -2147024883 / hex 0x8007000d
|
|
||||||
ErrInvalidData = hcs.ErrInvalidData
|
|
||||||
|
|
||||||
// ErrHandleClose is an error encountered when the handle generating the notification being waited on has been closed
|
|
||||||
ErrHandleClose = hcs.ErrHandleClose
|
|
||||||
|
|
||||||
// ErrAlreadyClosed is an error encountered when using a handle that has been closed by the Close method
|
|
||||||
ErrAlreadyClosed = hcs.ErrAlreadyClosed
|
|
||||||
|
|
||||||
// ErrInvalidNotificationType is an error encountered when an invalid notification type is used
|
|
||||||
ErrInvalidNotificationType = hcs.ErrInvalidNotificationType
|
|
||||||
|
|
||||||
// ErrInvalidProcessState is an error encountered when the process is not in a valid state for the requested operation
|
|
||||||
ErrInvalidProcessState = hcs.ErrInvalidProcessState
|
|
||||||
|
|
||||||
// ErrTimeout is an error encountered when waiting on a notification times out
|
|
||||||
ErrTimeout = hcs.ErrTimeout
|
|
||||||
|
|
||||||
// ErrUnexpectedContainerExit is the error encountered when a container exits while waiting for
|
|
||||||
// a different expected notification
|
|
||||||
ErrUnexpectedContainerExit = hcs.ErrUnexpectedContainerExit
|
|
||||||
|
|
||||||
// ErrUnexpectedProcessAbort is the error encountered when communication with the compute service
|
|
||||||
// is lost while waiting for a notification
|
|
||||||
ErrUnexpectedProcessAbort = hcs.ErrUnexpectedProcessAbort
|
|
||||||
|
|
||||||
// ErrUnexpectedValue is an error encountered when hcs returns an invalid value
|
|
||||||
ErrUnexpectedValue = hcs.ErrUnexpectedValue
|
|
||||||
|
|
||||||
// ErrVmcomputeAlreadyStopped is an error encountered when a shutdown or terminate request is made on a stopped container
|
|
||||||
ErrVmcomputeAlreadyStopped = hcs.ErrVmcomputeAlreadyStopped
|
|
||||||
|
|
||||||
// ErrVmcomputeOperationPending is an error encountered when the operation is being completed asynchronously
|
|
||||||
ErrVmcomputeOperationPending = hcs.ErrVmcomputeOperationPending
|
|
||||||
|
|
||||||
// ErrVmcomputeOperationInvalidState is an error encountered when the compute system is not in a valid state for the requested operation
|
|
||||||
ErrVmcomputeOperationInvalidState = hcs.ErrVmcomputeOperationInvalidState
|
|
||||||
|
|
||||||
// ErrProcNotFound is an error encountered when the the process cannot be found
|
|
||||||
ErrProcNotFound = hcs.ErrProcNotFound
|
|
||||||
|
|
||||||
// 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 = hcs.ErrVmcomputeOperationAccessIsDenied
|
|
||||||
|
|
||||||
// ErrVmcomputeInvalidJSON is an error encountered when the compute system does not support/understand the messages sent by management
|
|
||||||
ErrVmcomputeInvalidJSON = hcs.ErrVmcomputeInvalidJSON
|
|
||||||
|
|
||||||
// ErrVmcomputeUnknownMessage is an error encountered guest compute system doesn't support the message
|
|
||||||
ErrVmcomputeUnknownMessage = hcs.ErrVmcomputeUnknownMessage
|
|
||||||
|
|
||||||
// ErrNotSupported is an error encountered when hcs doesn't support the request
|
|
||||||
ErrPlatformNotSupported = hcs.ErrPlatformNotSupported
|
|
||||||
)
|
|
||||||
|
|
||||||
type EndpointNotFoundError = hns.EndpointNotFoundError
|
|
||||||
type NetworkNotFoundError = hns.NetworkNotFoundError
|
|
||||||
|
|
||||||
// ProcessError is an error encountered in HCS during an operation on a Process object
|
|
||||||
type ProcessError struct {
|
|
||||||
Process *process
|
|
||||||
Operation string
|
|
||||||
Err error
|
|
||||||
Events []hcs.ErrorEvent
|
|
||||||
}
|
|
||||||
|
|
||||||
// ContainerError is an error encountered in HCS during an operation on a Container object
|
|
||||||
type ContainerError struct {
|
|
||||||
Container *container
|
|
||||||
Operation string
|
|
||||||
Err error
|
|
||||||
Events []hcs.ErrorEvent
|
|
||||||
}
|
|
||||||
|
|
||||||
func (e *ContainerError) Error() string {
|
|
||||||
if e == nil {
|
|
||||||
return "<nil>"
|
|
||||||
}
|
|
||||||
|
|
||||||
if e.Container == nil {
|
|
||||||
return "unexpected nil container for error: " + e.Err.Error()
|
|
||||||
}
|
|
||||||
|
|
||||||
s := "container " + e.Container.system.ID()
|
|
||||||
|
|
||||||
if e.Operation != "" {
|
|
||||||
s += " encountered an error during " + e.Operation
|
|
||||||
}
|
|
||||||
|
|
||||||
switch e.Err.(type) {
|
|
||||||
case nil:
|
|
||||||
break
|
|
||||||
case syscall.Errno:
|
|
||||||
s += fmt.Sprintf(": failure in a Windows system call: %s (0x%x)", e.Err, hcserror.Win32FromError(e.Err))
|
|
||||||
default:
|
|
||||||
s += fmt.Sprintf(": %s", e.Err.Error())
|
|
||||||
}
|
|
||||||
|
|
||||||
for _, ev := range e.Events {
|
|
||||||
s += "\n" + ev.String()
|
|
||||||
}
|
|
||||||
|
|
||||||
return s
|
|
||||||
}
|
|
||||||
|
|
||||||
func (e *ProcessError) Error() string {
|
|
||||||
if e == nil {
|
|
||||||
return "<nil>"
|
|
||||||
}
|
|
||||||
|
|
||||||
if e.Process == nil {
|
|
||||||
return "Unexpected nil process for error: " + e.Err.Error()
|
|
||||||
}
|
|
||||||
|
|
||||||
s := fmt.Sprintf("process %d in container %s", e.Process.p.Pid(), e.Process.p.SystemID())
|
|
||||||
if e.Operation != "" {
|
|
||||||
s += " encountered an error during " + e.Operation
|
|
||||||
}
|
|
||||||
|
|
||||||
switch e.Err.(type) {
|
|
||||||
case nil:
|
|
||||||
break
|
|
||||||
case syscall.Errno:
|
|
||||||
s += fmt.Sprintf(": failure in a Windows system call: %s (0x%x)", e.Err, hcserror.Win32FromError(e.Err))
|
|
||||||
default:
|
|
||||||
s += fmt.Sprintf(": %s", e.Err.Error())
|
|
||||||
}
|
|
||||||
|
|
||||||
for _, ev := range e.Events {
|
|
||||||
s += "\n" + ev.String()
|
|
||||||
}
|
|
||||||
|
|
||||||
return s
|
|
||||||
}
|
|
||||||
|
|
||||||
// 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 {
|
|
||||||
if _, ok := err.(EndpointNotFoundError); ok {
|
|
||||||
return true
|
|
||||||
}
|
|
||||||
if _, ok := err.(NetworkNotFoundError); ok {
|
|
||||||
return true
|
|
||||||
}
|
|
||||||
return hcs.IsNotExist(getInnerError(err))
|
|
||||||
}
|
|
||||||
|
|
||||||
// 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 {
|
|
||||||
return hcs.IsAlreadyClosed(getInnerError(err))
|
|
||||||
}
|
|
||||||
|
|
||||||
// IsPending returns a boolean indicating whether the error is that
|
|
||||||
// the requested operation is being completed in the background.
|
|
||||||
func IsPending(err error) bool {
|
|
||||||
return hcs.IsPending(getInnerError(err))
|
|
||||||
}
|
|
||||||
|
|
||||||
// IsTimeout returns a boolean indicating whether the error is caused by
|
|
||||||
// a timeout waiting for the operation to complete.
|
|
||||||
func IsTimeout(err error) bool {
|
|
||||||
return hcs.IsTimeout(getInnerError(err))
|
|
||||||
}
|
|
||||||
|
|
||||||
// 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 {
|
|
||||||
return hcs.IsAlreadyStopped(getInnerError(err))
|
|
||||||
}
|
|
||||||
|
|
||||||
// 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 {
|
|
||||||
return hcs.IsNotSupported(getInnerError(err))
|
|
||||||
}
|
|
||||||
|
|
||||||
// IsOperationInvalidState returns true when err is caused by
|
|
||||||
// `ErrVmcomputeOperationInvalidState`.
|
|
||||||
func IsOperationInvalidState(err error) bool {
|
|
||||||
return hcs.IsOperationInvalidState(getInnerError(err))
|
|
||||||
}
|
|
||||||
|
|
||||||
// IsAccessIsDenied returns true when err is caused by
|
|
||||||
// `ErrVmcomputeOperationAccessIsDenied`.
|
|
||||||
func IsAccessIsDenied(err error) bool {
|
|
||||||
return hcs.IsAccessIsDenied(getInnerError(err))
|
|
||||||
}
|
|
||||||
|
|
||||||
func getInnerError(err error) error {
|
|
||||||
switch pe := err.(type) {
|
|
||||||
case nil:
|
|
||||||
return nil
|
|
||||||
case *ContainerError:
|
|
||||||
err = pe.Err
|
|
||||||
case *ProcessError:
|
|
||||||
err = pe.Err
|
|
||||||
}
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
func convertSystemError(err error, c *container) error {
|
|
||||||
if serr, ok := err.(*hcs.SystemError); ok {
|
|
||||||
return &ContainerError{Container: c, Operation: serr.Op, 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,22 +0,0 @@
|
||||||
module github.com/Microsoft/hcsshim
|
|
||||||
|
|
||||||
go 1.13
|
|
||||||
|
|
||||||
require (
|
|
||||||
github.com/Microsoft/go-winio v0.4.17-0.20210211115548-6eac466e5fa3
|
|
||||||
github.com/containerd/cgroups v0.0.0-20210114181951-8a68de567b68
|
|
||||||
github.com/containerd/console v1.0.1
|
|
||||||
github.com/containerd/containerd v1.5.0-beta.4
|
|
||||||
github.com/containerd/go-runc v0.0.0-20201020171139-16b287bc67d0
|
|
||||||
github.com/containerd/ttrpc v1.0.2
|
|
||||||
github.com/containerd/typeurl v1.0.1
|
|
||||||
github.com/gogo/protobuf v1.3.2
|
|
||||||
github.com/opencontainers/runtime-spec v1.0.3-0.20200929063507-e6143ca7d51d
|
|
||||||
github.com/pkg/errors v0.9.1
|
|
||||||
github.com/sirupsen/logrus v1.7.0
|
|
||||||
github.com/urfave/cli v1.22.2
|
|
||||||
go.opencensus.io v0.22.3
|
|
||||||
golang.org/x/sync v0.0.0-20201207232520-09787c993a3a
|
|
||||||
golang.org/x/sys v0.0.0-20210324051608-47abb6519492
|
|
||||||
google.golang.org/grpc v1.33.2
|
|
||||||
)
|
|
|
@ -1,28 +0,0 @@
|
||||||
// Shim for the Host Compute Service (HCS) to manage Windows Server
|
|
||||||
// containers and Hyper-V containers.
|
|
||||||
|
|
||||||
package hcsshim
|
|
||||||
|
|
||||||
import (
|
|
||||||
"syscall"
|
|
||||||
|
|
||||||
"github.com/Microsoft/hcsshim/internal/hcserror"
|
|
||||||
)
|
|
||||||
|
|
||||||
//go:generate go run mksyscall_windows.go -output zsyscall_windows.go hcsshim.go
|
|
||||||
|
|
||||||
//sys SetCurrentThreadCompartmentId(compartmentId uint32) (hr error) = iphlpapi.SetCurrentThreadCompartmentId
|
|
||||||
|
|
||||||
const (
|
|
||||||
// Specific user-visible exit codes
|
|
||||||
WaitErrExecFailed = 32767
|
|
||||||
|
|
||||||
ERROR_GEN_FAILURE = hcserror.ERROR_GEN_FAILURE
|
|
||||||
ERROR_SHUTDOWN_IN_PROGRESS = syscall.Errno(1115)
|
|
||||||
WSAEINVAL = syscall.Errno(10022)
|
|
||||||
|
|
||||||
// Timeout on wait calls
|
|
||||||
TimeoutInfinite = 0xFFFFFFFF
|
|
||||||
)
|
|
||||||
|
|
||||||
type HcsError = hcserror.HcsError
|
|
|
@ -1,110 +0,0 @@
|
||||||
package hcsshim
|
|
||||||
|
|
||||||
import (
|
|
||||||
"github.com/Microsoft/hcsshim/internal/hns"
|
|
||||||
)
|
|
||||||
|
|
||||||
// HNSEndpoint represents a network endpoint in HNS
|
|
||||||
type HNSEndpoint = hns.HNSEndpoint
|
|
||||||
|
|
||||||
// Namespace represents a Compartment.
|
|
||||||
type Namespace = hns.Namespace
|
|
||||||
|
|
||||||
//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 = hns.EndpointAttachDetachRequest
|
|
||||||
|
|
||||||
// EndpointResquestResponse is object to get the endpoint request response
|
|
||||||
type EndpointResquestResponse = hns.EndpointResquestResponse
|
|
||||||
|
|
||||||
// HNSEndpointRequest makes a HNS call to modify/query a network endpoint
|
|
||||||
func HNSEndpointRequest(method, path, request string) (*HNSEndpoint, error) {
|
|
||||||
return hns.HNSEndpointRequest(method, path, request)
|
|
||||||
}
|
|
||||||
|
|
||||||
// HNSListEndpointRequest makes a HNS call to query the list of available endpoints
|
|
||||||
func HNSListEndpointRequest() ([]HNSEndpoint, error) {
|
|
||||||
return hns.HNSListEndpointRequest()
|
|
||||||
}
|
|
||||||
|
|
||||||
// HotAttachEndpoint makes a HCS Call to attach the endpoint to the container
|
|
||||||
func HotAttachEndpoint(containerID string, endpointID string) error {
|
|
||||||
endpoint, err := GetHNSEndpointByID(endpointID)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
isAttached, err := endpoint.IsAttached(containerID)
|
|
||||||
if isAttached {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
return modifyNetworkEndpoint(containerID, endpointID, Add)
|
|
||||||
}
|
|
||||||
|
|
||||||
// HotDetachEndpoint makes a HCS Call to detach the endpoint from the container
|
|
||||||
func HotDetachEndpoint(containerID string, endpointID string) error {
|
|
||||||
endpoint, err := GetHNSEndpointByID(endpointID)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
isAttached, err := endpoint.IsAttached(containerID)
|
|
||||||
if !isAttached {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
return modifyNetworkEndpoint(containerID, endpointID, Remove)
|
|
||||||
}
|
|
||||||
|
|
||||||
// ModifyContainer corresponding to the container id, by sending a request
|
|
||||||
func modifyContainer(id string, request *ResourceModificationRequestResponse) error {
|
|
||||||
container, err := OpenContainer(id)
|
|
||||||
if err != nil {
|
|
||||||
if IsNotExist(err) {
|
|
||||||
return ErrComputeSystemDoesNotExist
|
|
||||||
}
|
|
||||||
return getInnerError(err)
|
|
||||||
}
|
|
||||||
defer container.Close()
|
|
||||||
err = container.Modify(request)
|
|
||||||
if err != nil {
|
|
||||||
if IsNotSupported(err) {
|
|
||||||
return ErrPlatformNotSupported
|
|
||||||
}
|
|
||||||
return getInnerError(err)
|
|
||||||
}
|
|
||||||
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func modifyNetworkEndpoint(containerID string, endpointID string, request RequestType) error {
|
|
||||||
requestMessage := &ResourceModificationRequestResponse{
|
|
||||||
Resource: Network,
|
|
||||||
Request: request,
|
|
||||||
Data: endpointID,
|
|
||||||
}
|
|
||||||
err := modifyContainer(containerID, requestMessage)
|
|
||||||
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// GetHNSEndpointByID get the Endpoint by ID
|
|
||||||
func GetHNSEndpointByID(endpointID string) (*HNSEndpoint, error) {
|
|
||||||
return hns.GetHNSEndpointByID(endpointID)
|
|
||||||
}
|
|
||||||
|
|
||||||
// GetHNSEndpointByName gets the endpoint filtered by Name
|
|
||||||
func GetHNSEndpointByName(endpointName string) (*HNSEndpoint, error) {
|
|
||||||
return hns.GetHNSEndpointByName(endpointName)
|
|
||||||
}
|
|
|
@ -1,16 +0,0 @@
|
||||||
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,36 +0,0 @@
|
||||||
package hcsshim
|
|
||||||
|
|
||||||
import (
|
|
||||||
"github.com/Microsoft/hcsshim/internal/hns"
|
|
||||||
)
|
|
||||||
|
|
||||||
// Subnet is assoicated with a network and represents a list
|
|
||||||
// of subnets available to the network
|
|
||||||
type Subnet = hns.Subnet
|
|
||||||
|
|
||||||
// MacPool is assoicated with a network and represents a list
|
|
||||||
// of macaddresses available to the network
|
|
||||||
type MacPool = hns.MacPool
|
|
||||||
|
|
||||||
// HNSNetwork represents a network in HNS
|
|
||||||
type HNSNetwork = hns.HNSNetwork
|
|
||||||
|
|
||||||
// HNSNetworkRequest makes a call into HNS to update/query a single network
|
|
||||||
func HNSNetworkRequest(method, path, request string) (*HNSNetwork, error) {
|
|
||||||
return hns.HNSNetworkRequest(method, path, request)
|
|
||||||
}
|
|
||||||
|
|
||||||
// HNSListNetworkRequest makes a HNS call to query the list of available networks
|
|
||||||
func HNSListNetworkRequest(method, path, request string) ([]HNSNetwork, error) {
|
|
||||||
return hns.HNSListNetworkRequest(method, path, request)
|
|
||||||
}
|
|
||||||
|
|
||||||
// GetHNSNetworkByID
|
|
||||||
func GetHNSNetworkByID(networkID string) (*HNSNetwork, error) {
|
|
||||||
return hns.GetHNSNetworkByID(networkID)
|
|
||||||
}
|
|
||||||
|
|
||||||
// GetHNSNetworkName filtered by Name
|
|
||||||
func GetHNSNetworkByName(networkName string) (*HNSNetwork, error) {
|
|
||||||
return hns.GetHNSNetworkByName(networkName)
|
|
||||||
}
|
|
|
@ -1,60 +0,0 @@
|
||||||
package hcsshim
|
|
||||||
|
|
||||||
import (
|
|
||||||
"github.com/Microsoft/hcsshim/internal/hns"
|
|
||||||
)
|
|
||||||
|
|
||||||
// Type of Request Support in ModifySystem
|
|
||||||
type PolicyType = hns.PolicyType
|
|
||||||
|
|
||||||
// RequestType const
|
|
||||||
const (
|
|
||||||
Nat = hns.Nat
|
|
||||||
ACL = hns.ACL
|
|
||||||
PA = hns.PA
|
|
||||||
VLAN = hns.VLAN
|
|
||||||
VSID = hns.VSID
|
|
||||||
VNet = hns.VNet
|
|
||||||
L2Driver = hns.L2Driver
|
|
||||||
Isolation = hns.Isolation
|
|
||||||
QOS = hns.QOS
|
|
||||||
OutboundNat = hns.OutboundNat
|
|
||||||
ExternalLoadBalancer = hns.ExternalLoadBalancer
|
|
||||||
Route = hns.Route
|
|
||||||
Proxy = hns.Proxy
|
|
||||||
)
|
|
||||||
|
|
||||||
type ProxyPolicy = hns.ProxyPolicy
|
|
||||||
|
|
||||||
type NatPolicy = hns.NatPolicy
|
|
||||||
|
|
||||||
type QosPolicy = hns.QosPolicy
|
|
||||||
|
|
||||||
type IsolationPolicy = hns.IsolationPolicy
|
|
||||||
|
|
||||||
type VlanPolicy = hns.VlanPolicy
|
|
||||||
|
|
||||||
type VsidPolicy = hns.VsidPolicy
|
|
||||||
|
|
||||||
type PaPolicy = hns.PaPolicy
|
|
||||||
|
|
||||||
type OutboundNatPolicy = hns.OutboundNatPolicy
|
|
||||||
|
|
||||||
type ActionType = hns.ActionType
|
|
||||||
type DirectionType = hns.DirectionType
|
|
||||||
type RuleType = hns.RuleType
|
|
||||||
|
|
||||||
const (
|
|
||||||
Allow = hns.Allow
|
|
||||||
Block = hns.Block
|
|
||||||
|
|
||||||
In = hns.In
|
|
||||||
Out = hns.Out
|
|
||||||
|
|
||||||
Host = hns.Host
|
|
||||||
Switch = hns.Switch
|
|
||||||
)
|
|
||||||
|
|
||||||
type ACLPolicy = hns.ACLPolicy
|
|
||||||
|
|
||||||
type Policy = hns.Policy
|
|
|
@ -1,47 +0,0 @@
|
||||||
package hcsshim
|
|
||||||
|
|
||||||
import (
|
|
||||||
"github.com/Microsoft/hcsshim/internal/hns"
|
|
||||||
)
|
|
||||||
|
|
||||||
// RoutePolicy is a structure defining schema for Route based Policy
|
|
||||||
type RoutePolicy = hns.RoutePolicy
|
|
||||||
|
|
||||||
// ELBPolicy is a structure defining schema for ELB LoadBalancing based Policy
|
|
||||||
type ELBPolicy = hns.ELBPolicy
|
|
||||||
|
|
||||||
// LBPolicy is a structure defining schema for LoadBalancing based Policy
|
|
||||||
type LBPolicy = hns.LBPolicy
|
|
||||||
|
|
||||||
// PolicyList is a structure defining schema for Policy list request
|
|
||||||
type PolicyList = hns.PolicyList
|
|
||||||
|
|
||||||
// HNSPolicyListRequest makes a call into HNS to update/query a single network
|
|
||||||
func HNSPolicyListRequest(method, path, request string) (*PolicyList, error) {
|
|
||||||
return hns.HNSPolicyListRequest(method, path, request)
|
|
||||||
}
|
|
||||||
|
|
||||||
// HNSListPolicyListRequest gets all the policy list
|
|
||||||
func HNSListPolicyListRequest() ([]PolicyList, error) {
|
|
||||||
return hns.HNSListPolicyListRequest()
|
|
||||||
}
|
|
||||||
|
|
||||||
// PolicyListRequest makes a HNS call to modify/query a network policy list
|
|
||||||
func PolicyListRequest(method, path, request string) (*PolicyList, error) {
|
|
||||||
return hns.PolicyListRequest(method, path, request)
|
|
||||||
}
|
|
||||||
|
|
||||||
// GetPolicyListByID get the policy list by ID
|
|
||||||
func GetPolicyListByID(policyListID string) (*PolicyList, error) {
|
|
||||||
return hns.GetPolicyListByID(policyListID)
|
|
||||||
}
|
|
||||||
|
|
||||||
// AddLoadBalancer policy list for the specified endpoints
|
|
||||||
func AddLoadBalancer(endpoints []HNSEndpoint, isILB bool, sourceVIP, vip string, protocol uint16, internalPort uint16, externalPort uint16) (*PolicyList, error) {
|
|
||||||
return hns.AddLoadBalancer(endpoints, isILB, sourceVIP, vip, protocol, internalPort, externalPort)
|
|
||||||
}
|
|
||||||
|
|
||||||
// AddRoute adds route policy list for the specified endpoints
|
|
||||||
func AddRoute(endpoints []HNSEndpoint, destinationPrefix string, nextHop string, encapEnabled bool) (*PolicyList, error) {
|
|
||||||
return hns.AddRoute(endpoints, destinationPrefix, nextHop, encapEnabled)
|
|
||||||
}
|
|
|
@ -1,13 +0,0 @@
|
||||||
package hcsshim
|
|
||||||
|
|
||||||
import (
|
|
||||||
"github.com/Microsoft/hcsshim/internal/hns"
|
|
||||||
)
|
|
||||||
|
|
||||||
type HNSSupportedFeatures = hns.HNSSupportedFeatures
|
|
||||||
|
|
||||||
type HNSAclFeatures = hns.HNSAclFeatures
|
|
||||||
|
|
||||||
func GetHNSSupportedFeatures() HNSSupportedFeatures {
|
|
||||||
return hns.GetHNSSupportedFeatures()
|
|
||||||
}
|
|
|
@ -1,114 +0,0 @@
|
||||||
package hcsshim
|
|
||||||
|
|
||||||
import (
|
|
||||||
"io"
|
|
||||||
"time"
|
|
||||||
|
|
||||||
"github.com/Microsoft/hcsshim/internal/schema1"
|
|
||||||
)
|
|
||||||
|
|
||||||
// ProcessConfig is used as both the input of Container.CreateProcess
|
|
||||||
// and to convert the parameters to JSON for passing onto the HCS
|
|
||||||
type ProcessConfig = schema1.ProcessConfig
|
|
||||||
|
|
||||||
type Layer = schema1.Layer
|
|
||||||
type MappedDir = schema1.MappedDir
|
|
||||||
type MappedPipe = schema1.MappedPipe
|
|
||||||
type HvRuntime = schema1.HvRuntime
|
|
||||||
type MappedVirtualDisk = schema1.MappedVirtualDisk
|
|
||||||
|
|
||||||
// AssignedDevice represents a device that has been directly assigned to a container
|
|
||||||
//
|
|
||||||
// NOTE: Support added in RS5
|
|
||||||
type AssignedDevice = schema1.AssignedDevice
|
|
||||||
|
|
||||||
// ContainerConfig is used as both the input of CreateContainer
|
|
||||||
// and to convert the parameters to JSON for passing onto the HCS
|
|
||||||
type ContainerConfig = schema1.ContainerConfig
|
|
||||||
|
|
||||||
type ComputeSystemQuery = schema1.ComputeSystemQuery
|
|
||||||
|
|
||||||
// Container represents a created (but not necessarily running) container.
|
|
||||||
type Container interface {
|
|
||||||
// Start synchronously starts the container.
|
|
||||||
Start() error
|
|
||||||
|
|
||||||
// Shutdown requests a container shutdown, but it may not actually be shutdown until Wait() succeeds.
|
|
||||||
Shutdown() error
|
|
||||||
|
|
||||||
// Terminate requests a container terminate, but it may not actually be terminated until Wait() succeeds.
|
|
||||||
Terminate() error
|
|
||||||
|
|
||||||
// Waits synchronously waits for the container to shutdown or terminate.
|
|
||||||
Wait() error
|
|
||||||
|
|
||||||
// WaitTimeout synchronously waits for the container to terminate or the duration to elapse. It
|
|
||||||
// returns false if timeout occurs.
|
|
||||||
WaitTimeout(time.Duration) error
|
|
||||||
|
|
||||||
// Pause pauses the execution of a container.
|
|
||||||
Pause() error
|
|
||||||
|
|
||||||
// Resume resumes the execution of a container.
|
|
||||||
Resume() error
|
|
||||||
|
|
||||||
// HasPendingUpdates returns true if the container has updates pending to install.
|
|
||||||
HasPendingUpdates() (bool, error)
|
|
||||||
|
|
||||||
// Statistics returns statistics for a container.
|
|
||||||
Statistics() (Statistics, error)
|
|
||||||
|
|
||||||
// ProcessList returns details for the processes in a container.
|
|
||||||
ProcessList() ([]ProcessListItem, error)
|
|
||||||
|
|
||||||
// MappedVirtualDisks returns virtual disks mapped to a utility VM, indexed by controller
|
|
||||||
MappedVirtualDisks() (map[int]MappedVirtualDiskController, error)
|
|
||||||
|
|
||||||
// CreateProcess launches a new process within the container.
|
|
||||||
CreateProcess(c *ProcessConfig) (Process, error)
|
|
||||||
|
|
||||||
// OpenProcess gets an interface to an existing process within the container.
|
|
||||||
OpenProcess(pid int) (Process, error)
|
|
||||||
|
|
||||||
// Close cleans up any state associated with the container but does not terminate or wait for it.
|
|
||||||
Close() error
|
|
||||||
|
|
||||||
// Modify the System
|
|
||||||
Modify(config *ResourceModificationRequestResponse) error
|
|
||||||
}
|
|
||||||
|
|
||||||
// Process represents a running or exited process.
|
|
||||||
type Process interface {
|
|
||||||
// Pid returns the process ID of the process within the container.
|
|
||||||
Pid() int
|
|
||||||
|
|
||||||
// Kill signals the process to terminate but does not wait for it to finish terminating.
|
|
||||||
Kill() error
|
|
||||||
|
|
||||||
// Wait waits for the process to exit.
|
|
||||||
Wait() error
|
|
||||||
|
|
||||||
// WaitTimeout waits for the process to exit or the duration to elapse. It returns
|
|
||||||
// false if timeout occurs.
|
|
||||||
WaitTimeout(time.Duration) error
|
|
||||||
|
|
||||||
// ExitCode returns the exit code of the process. The process must have
|
|
||||||
// already terminated.
|
|
||||||
ExitCode() (int, error)
|
|
||||||
|
|
||||||
// ResizeConsole resizes the console of the process.
|
|
||||||
ResizeConsole(width, height uint16) error
|
|
||||||
|
|
||||||
// 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.
|
|
||||||
Stdio() (io.WriteCloser, io.ReadCloser, io.ReadCloser, error)
|
|
||||||
|
|
||||||
// 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.
|
|
||||||
CloseStdin() error
|
|
||||||
|
|
||||||
// Close cleans up any state associated with the process but does not kill
|
|
||||||
// or wait on it.
|
|
||||||
Close() error
|
|
||||||
}
|
|
|
@ -1,85 +0,0 @@
|
||||||
package cow
|
|
||||||
|
|
||||||
import (
|
|
||||||
"context"
|
|
||||||
"io"
|
|
||||||
|
|
||||||
"github.com/Microsoft/hcsshim/internal/schema1"
|
|
||||||
hcsschema "github.com/Microsoft/hcsshim/internal/schema2"
|
|
||||||
)
|
|
||||||
|
|
||||||
// Process is the interface for an OS process running in a container or utility VM.
|
|
||||||
type Process interface {
|
|
||||||
// Close releases resources associated with the process and closes the
|
|
||||||
// writer and readers returned by Stdio. Depending on the implementation,
|
|
||||||
// this may also terminate the process.
|
|
||||||
Close() error
|
|
||||||
// CloseStdin causes the process's stdin handle to receive EOF/EPIPE/whatever
|
|
||||||
// is appropriate to indicate that no more data is available.
|
|
||||||
CloseStdin(ctx context.Context) error
|
|
||||||
// Pid returns the process ID.
|
|
||||||
Pid() int
|
|
||||||
// Stdio returns the stdio streams for a process. These may be nil if a stream
|
|
||||||
// was not requested during CreateProcess.
|
|
||||||
Stdio() (_ io.Writer, _ io.Reader, _ io.Reader)
|
|
||||||
// ResizeConsole resizes the virtual terminal associated with the process.
|
|
||||||
ResizeConsole(ctx context.Context, width, height uint16) error
|
|
||||||
// Kill sends a SIGKILL or equivalent signal to the process and returns whether
|
|
||||||
// the signal was delivered. It does not wait for the process to terminate.
|
|
||||||
Kill(ctx context.Context) (bool, error)
|
|
||||||
// Signal sends a signal to the process and returns whether the signal was
|
|
||||||
// delivered. The input is OS specific (either
|
|
||||||
// guestrequest.SignalProcessOptionsWCOW or
|
|
||||||
// guestrequest.SignalProcessOptionsLCOW). It does not wait for the process
|
|
||||||
// to terminate.
|
|
||||||
Signal(ctx context.Context, options interface{}) (bool, error)
|
|
||||||
// Wait waits for the process to complete, or for a connection to the process to be
|
|
||||||
// terminated by some error condition (including calling Close).
|
|
||||||
Wait() error
|
|
||||||
// ExitCode returns the exit code of the process. Returns an error if the process is
|
|
||||||
// not running.
|
|
||||||
ExitCode() (int, error)
|
|
||||||
}
|
|
||||||
|
|
||||||
// ProcessHost is the interface for creating processes.
|
|
||||||
type ProcessHost interface {
|
|
||||||
// CreateProcess creates a process. The configuration is host specific
|
|
||||||
// (either hcsschema.ProcessParameters or lcow.ProcessParameters).
|
|
||||||
CreateProcess(ctx context.Context, config interface{}) (Process, error)
|
|
||||||
// OS returns the host's operating system, "linux" or "windows".
|
|
||||||
OS() string
|
|
||||||
// IsOCI specifies whether this is an OCI-compliant process host. If true,
|
|
||||||
// then the configuration passed to CreateProcess should have an OCI process
|
|
||||||
// spec (or nil if this is the initial process in an OCI container).
|
|
||||||
// Otherwise, it should have the HCS-specific process parameters.
|
|
||||||
IsOCI() bool
|
|
||||||
}
|
|
||||||
|
|
||||||
// Container is the interface for container objects, either running on the host or
|
|
||||||
// in a utility VM.
|
|
||||||
type Container interface {
|
|
||||||
ProcessHost
|
|
||||||
// Close releases the resources associated with the container. Depending on
|
|
||||||
// the implementation, this may also terminate the container.
|
|
||||||
Close() error
|
|
||||||
// ID returns the container ID.
|
|
||||||
ID() string
|
|
||||||
// Properties returns the requested container properties targeting a V1 schema container.
|
|
||||||
Properties(ctx context.Context, types ...schema1.PropertyType) (*schema1.ContainerProperties, error)
|
|
||||||
// PropertiesV2 returns the requested container properties targeting a V2 schema container.
|
|
||||||
PropertiesV2(ctx context.Context, types ...hcsschema.PropertyType) (*hcsschema.Properties, error)
|
|
||||||
// Start starts a container.
|
|
||||||
Start(ctx context.Context) error
|
|
||||||
// Shutdown sends a shutdown request to the container (but does not wait for
|
|
||||||
// the shutdown to complete).
|
|
||||||
Shutdown(ctx context.Context) error
|
|
||||||
// Terminate sends a terminate request to the container (but does not wait
|
|
||||||
// for the terminate to complete).
|
|
||||||
Terminate(ctx context.Context) error
|
|
||||||
// Wait waits for the container to terminate, or for the connection to the
|
|
||||||
// container to be terminated by some error condition (including calling
|
|
||||||
// Close).
|
|
||||||
Wait() error
|
|
||||||
// Modify sends a request to modify container resources
|
|
||||||
Modify(ctx context.Context, config interface{}) error
|
|
||||||
}
|
|
|
@ -1,161 +0,0 @@
|
||||||
package hcs
|
|
||||||
|
|
||||||
import (
|
|
||||||
"fmt"
|
|
||||||
"sync"
|
|
||||||
"syscall"
|
|
||||||
|
|
||||||
"github.com/Microsoft/hcsshim/internal/interop"
|
|
||||||
"github.com/Microsoft/hcsshim/internal/logfields"
|
|
||||||
"github.com/Microsoft/hcsshim/internal/vmcompute"
|
|
||||||
"github.com/sirupsen/logrus"
|
|
||||||
)
|
|
||||||
|
|
||||||
var (
|
|
||||||
nextCallback uintptr
|
|
||||||
callbackMap = map[uintptr]*notifcationWatcherContext{}
|
|
||||||
callbackMapLock = sync.RWMutex{}
|
|
||||||
|
|
||||||
notificationWatcherCallback = syscall.NewCallback(notificationWatcher)
|
|
||||||
|
|
||||||
// Notifications for HCS_SYSTEM handles
|
|
||||||
hcsNotificationSystemExited hcsNotification = 0x00000001
|
|
||||||
hcsNotificationSystemCreateCompleted hcsNotification = 0x00000002
|
|
||||||
hcsNotificationSystemStartCompleted hcsNotification = 0x00000003
|
|
||||||
hcsNotificationSystemPauseCompleted hcsNotification = 0x00000004
|
|
||||||
hcsNotificationSystemResumeCompleted hcsNotification = 0x00000005
|
|
||||||
hcsNotificationSystemCrashReport hcsNotification = 0x00000006
|
|
||||||
hcsNotificationSystemSiloJobCreated hcsNotification = 0x00000007
|
|
||||||
hcsNotificationSystemSaveCompleted hcsNotification = 0x00000008
|
|
||||||
hcsNotificationSystemRdpEnhancedModeStateChanged hcsNotification = 0x00000009
|
|
||||||
hcsNotificationSystemShutdownFailed hcsNotification = 0x0000000A
|
|
||||||
hcsNotificationSystemGetPropertiesCompleted hcsNotification = 0x0000000B
|
|
||||||
hcsNotificationSystemModifyCompleted hcsNotification = 0x0000000C
|
|
||||||
hcsNotificationSystemCrashInitiated hcsNotification = 0x0000000D
|
|
||||||
hcsNotificationSystemGuestConnectionClosed hcsNotification = 0x0000000E
|
|
||||||
|
|
||||||
// Notifications for HCS_PROCESS handles
|
|
||||||
hcsNotificationProcessExited hcsNotification = 0x00010000
|
|
||||||
|
|
||||||
// Common notifications
|
|
||||||
hcsNotificationInvalid hcsNotification = 0x00000000
|
|
||||||
hcsNotificationServiceDisconnect hcsNotification = 0x01000000
|
|
||||||
)
|
|
||||||
|
|
||||||
type hcsNotification uint32
|
|
||||||
|
|
||||||
func (hn hcsNotification) String() string {
|
|
||||||
switch hn {
|
|
||||||
case hcsNotificationSystemExited:
|
|
||||||
return "SystemExited"
|
|
||||||
case hcsNotificationSystemCreateCompleted:
|
|
||||||
return "SystemCreateCompleted"
|
|
||||||
case hcsNotificationSystemStartCompleted:
|
|
||||||
return "SystemStartCompleted"
|
|
||||||
case hcsNotificationSystemPauseCompleted:
|
|
||||||
return "SystemPauseCompleted"
|
|
||||||
case hcsNotificationSystemResumeCompleted:
|
|
||||||
return "SystemResumeCompleted"
|
|
||||||
case hcsNotificationSystemCrashReport:
|
|
||||||
return "SystemCrashReport"
|
|
||||||
case hcsNotificationSystemSiloJobCreated:
|
|
||||||
return "SystemSiloJobCreated"
|
|
||||||
case hcsNotificationSystemSaveCompleted:
|
|
||||||
return "SystemSaveCompleted"
|
|
||||||
case hcsNotificationSystemRdpEnhancedModeStateChanged:
|
|
||||||
return "SystemRdpEnhancedModeStateChanged"
|
|
||||||
case hcsNotificationSystemShutdownFailed:
|
|
||||||
return "SystemShutdownFailed"
|
|
||||||
case hcsNotificationSystemGetPropertiesCompleted:
|
|
||||||
return "SystemGetPropertiesCompleted"
|
|
||||||
case hcsNotificationSystemModifyCompleted:
|
|
||||||
return "SystemModifyCompleted"
|
|
||||||
case hcsNotificationSystemCrashInitiated:
|
|
||||||
return "SystemCrashInitiated"
|
|
||||||
case hcsNotificationSystemGuestConnectionClosed:
|
|
||||||
return "SystemGuestConnectionClosed"
|
|
||||||
case hcsNotificationProcessExited:
|
|
||||||
return "ProcessExited"
|
|
||||||
case hcsNotificationInvalid:
|
|
||||||
return "Invalid"
|
|
||||||
case hcsNotificationServiceDisconnect:
|
|
||||||
return "ServiceDisconnect"
|
|
||||||
default:
|
|
||||||
return fmt.Sprintf("Unknown: %d", hn)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
type notificationChannel chan error
|
|
||||||
|
|
||||||
type notifcationWatcherContext struct {
|
|
||||||
channels notificationChannels
|
|
||||||
handle vmcompute.HcsCallback
|
|
||||||
|
|
||||||
systemID string
|
|
||||||
processID int
|
|
||||||
}
|
|
||||||
|
|
||||||
type notificationChannels map[hcsNotification]notificationChannel
|
|
||||||
|
|
||||||
func newSystemChannels() notificationChannels {
|
|
||||||
channels := make(notificationChannels)
|
|
||||||
for _, notif := range []hcsNotification{
|
|
||||||
hcsNotificationServiceDisconnect,
|
|
||||||
hcsNotificationSystemExited,
|
|
||||||
hcsNotificationSystemCreateCompleted,
|
|
||||||
hcsNotificationSystemStartCompleted,
|
|
||||||
hcsNotificationSystemPauseCompleted,
|
|
||||||
hcsNotificationSystemResumeCompleted,
|
|
||||||
hcsNotificationSystemSaveCompleted,
|
|
||||||
} {
|
|
||||||
channels[notif] = make(notificationChannel, 1)
|
|
||||||
}
|
|
||||||
return channels
|
|
||||||
}
|
|
||||||
|
|
||||||
func newProcessChannels() notificationChannels {
|
|
||||||
channels := make(notificationChannels)
|
|
||||||
for _, notif := range []hcsNotification{
|
|
||||||
hcsNotificationServiceDisconnect,
|
|
||||||
hcsNotificationProcessExited,
|
|
||||||
} {
|
|
||||||
channels[notif] = make(notificationChannel, 1)
|
|
||||||
}
|
|
||||||
return channels
|
|
||||||
}
|
|
||||||
|
|
||||||
func closeChannels(channels notificationChannels) {
|
|
||||||
for _, c := range channels {
|
|
||||||
close(c)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func notificationWatcher(notificationType hcsNotification, callbackNumber uintptr, notificationStatus uintptr, notificationData *uint16) uintptr {
|
|
||||||
var result error
|
|
||||||
if int32(notificationStatus) < 0 {
|
|
||||||
result = interop.Win32FromHresult(notificationStatus)
|
|
||||||
}
|
|
||||||
|
|
||||||
callbackMapLock.RLock()
|
|
||||||
context := callbackMap[callbackNumber]
|
|
||||||
callbackMapLock.RUnlock()
|
|
||||||
|
|
||||||
if context == nil {
|
|
||||||
return 0
|
|
||||||
}
|
|
||||||
|
|
||||||
log := logrus.WithFields(logrus.Fields{
|
|
||||||
"notification-type": notificationType.String(),
|
|
||||||
"system-id": context.systemID,
|
|
||||||
})
|
|
||||||
if context.processID != 0 {
|
|
||||||
log.Data[logfields.ProcessID] = context.processID
|
|
||||||
}
|
|
||||||
log.Debug("HCS notification")
|
|
||||||
|
|
||||||
if channel, ok := context.channels[notificationType]; ok {
|
|
||||||
channel <- result
|
|
||||||
}
|
|
||||||
|
|
||||||
return 0
|
|
||||||
}
|
|
|
@ -1,329 +0,0 @@
|
||||||
package hcs
|
|
||||||
|
|
||||||
import (
|
|
||||||
"context"
|
|
||||||
"encoding/json"
|
|
||||||
"errors"
|
|
||||||
"fmt"
|
|
||||||
"net"
|
|
||||||
"syscall"
|
|
||||||
|
|
||||||
"github.com/Microsoft/hcsshim/internal/log"
|
|
||||||
)
|
|
||||||
|
|
||||||
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)
|
|
||||||
|
|
||||||
// ErrVmcomputeUnexpectedExit is an error encountered when the compute system terminates unexpectedly
|
|
||||||
ErrVmcomputeUnexpectedExit = syscall.Errno(0xC0370106)
|
|
||||||
|
|
||||||
// ErrNotSupported is an error encountered when hcs doesn't support the request
|
|
||||||
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(ctx context.Context, resultJSON string) []ErrorEvent {
|
|
||||||
if resultJSON != "" {
|
|
||||||
result := &hcsResult{}
|
|
||||||
if err := json.Unmarshal([]byte(resultJSON), result); err != nil {
|
|
||||||
log.G(ctx).WithError(err).Warning("Could not unmarshal HCS result")
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
return result.ErrorEvents
|
|
||||||
}
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
type HcsError struct {
|
|
||||||
Op string
|
|
||||||
Err error
|
|
||||||
Events []ErrorEvent
|
|
||||||
}
|
|
||||||
|
|
||||||
var _ net.Error = &HcsError{}
|
|
||||||
|
|
||||||
func (e *HcsError) Error() string {
|
|
||||||
s := e.Op + ": " + e.Err.Error()
|
|
||||||
for _, ev := range e.Events {
|
|
||||||
s += "\n" + ev.String()
|
|
||||||
}
|
|
||||||
return s
|
|
||||||
}
|
|
||||||
|
|
||||||
func (e *HcsError) Temporary() bool {
|
|
||||||
err, ok := e.Err.(net.Error)
|
|
||||||
return ok && err.Temporary()
|
|
||||||
}
|
|
||||||
|
|
||||||
func (e *HcsError) Timeout() bool {
|
|
||||||
err, ok := e.Err.(net.Error)
|
|
||||||
return ok && err.Timeout()
|
|
||||||
}
|
|
||||||
|
|
||||||
// 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
|
|
||||||
}
|
|
||||||
|
|
||||||
var _ net.Error = &ProcessError{}
|
|
||||||
|
|
||||||
// SystemError is an error encountered in HCS during an operation on a Container object
|
|
||||||
type SystemError struct {
|
|
||||||
ID string
|
|
||||||
Op string
|
|
||||||
Err error
|
|
||||||
Events []ErrorEvent
|
|
||||||
}
|
|
||||||
|
|
||||||
var _ net.Error = &SystemError{}
|
|
||||||
|
|
||||||
func (e *SystemError) Error() string {
|
|
||||||
s := e.Op + " " + e.ID + ": " + e.Err.Error()
|
|
||||||
for _, ev := range e.Events {
|
|
||||||
s += "\n" + ev.String()
|
|
||||||
}
|
|
||||||
return s
|
|
||||||
}
|
|
||||||
|
|
||||||
func (e *SystemError) Temporary() bool {
|
|
||||||
err, ok := e.Err.(net.Error)
|
|
||||||
return ok && err.Temporary()
|
|
||||||
}
|
|
||||||
|
|
||||||
func (e *SystemError) Timeout() bool {
|
|
||||||
err, ok := e.Err.(net.Error)
|
|
||||||
return ok && err.Timeout()
|
|
||||||
}
|
|
||||||
|
|
||||||
func makeSystemError(system *System, op 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,
|
|
||||||
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 (e *ProcessError) Temporary() bool {
|
|
||||||
err, ok := e.Err.(net.Error)
|
|
||||||
return ok && err.Temporary()
|
|
||||||
}
|
|
||||||
|
|
||||||
func (e *ProcessError) Timeout() bool {
|
|
||||||
err, ok := e.Err.(net.Error)
|
|
||||||
return ok && err.Timeout()
|
|
||||||
}
|
|
||||||
|
|
||||||
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 {
|
|
||||||
if err, ok := err.(net.Error); ok && err.Timeout() {
|
|
||||||
return true
|
|
||||||
}
|
|
||||||
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
|
|
||||||
}
|
|
||||||
|
|
||||||
// IsOperationInvalidState returns true when err is caused by
|
|
||||||
// `ErrVmcomputeOperationInvalidState`.
|
|
||||||
func IsOperationInvalidState(err error) bool {
|
|
||||||
err = getInnerError(err)
|
|
||||||
return err == ErrVmcomputeOperationInvalidState
|
|
||||||
}
|
|
||||||
|
|
||||||
// IsAccessIsDenied returns true when err is caused by
|
|
||||||
// `ErrVmcomputeOperationAccessIsDenied`.
|
|
||||||
func IsAccessIsDenied(err error) bool {
|
|
||||||
err = getInnerError(err)
|
|
||||||
return err == ErrVmcomputeOperationAccessIsDenied
|
|
||||||
}
|
|
||||||
|
|
||||||
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
|
|
||||||
}
|
|
|
@ -1,472 +0,0 @@
|
||||||
package hcs
|
|
||||||
|
|
||||||
import (
|
|
||||||
"context"
|
|
||||||
"encoding/json"
|
|
||||||
"io"
|
|
||||||
"sync"
|
|
||||||
"syscall"
|
|
||||||
"time"
|
|
||||||
|
|
||||||
"github.com/Microsoft/hcsshim/internal/log"
|
|
||||||
"github.com/Microsoft/hcsshim/internal/oc"
|
|
||||||
"github.com/Microsoft/hcsshim/internal/vmcompute"
|
|
||||||
"go.opencensus.io/trace"
|
|
||||||
)
|
|
||||||
|
|
||||||
// ContainerError is an error encountered in HCS
|
|
||||||
type Process struct {
|
|
||||||
handleLock sync.RWMutex
|
|
||||||
handle vmcompute.HcsProcess
|
|
||||||
processID int
|
|
||||||
system *System
|
|
||||||
hasCachedStdio bool
|
|
||||||
stdioLock sync.Mutex
|
|
||||||
stdin io.WriteCloser
|
|
||||||
stdout io.ReadCloser
|
|
||||||
stderr io.ReadCloser
|
|
||||||
callbackNumber uintptr
|
|
||||||
|
|
||||||
closedWaitOnce sync.Once
|
|
||||||
waitBlock chan struct{}
|
|
||||||
exitCode int
|
|
||||||
waitError error
|
|
||||||
}
|
|
||||||
|
|
||||||
func newProcess(process vmcompute.HcsProcess, processID int, computeSystem *System) *Process {
|
|
||||||
return &Process{
|
|
||||||
handle: process,
|
|
||||||
processID: processID,
|
|
||||||
system: computeSystem,
|
|
||||||
waitBlock: make(chan struct{}),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
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"
|
|
||||||
|
|
||||||
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()
|
|
||||||
}
|
|
||||||
|
|
||||||
func (process *Process) processSignalResult(ctx context.Context, err error) (bool, error) {
|
|
||||||
switch err {
|
|
||||||
case nil:
|
|
||||||
return true, nil
|
|
||||||
case ErrVmcomputeOperationInvalidState, ErrComputeSystemDoesNotExist, ErrElementNotFound:
|
|
||||||
select {
|
|
||||||
case <-process.waitBlock:
|
|
||||||
// The process exit notification has already arrived.
|
|
||||||
default:
|
|
||||||
// The process should be gone, but we have not received the notification.
|
|
||||||
// After a second, force unblock the process wait to work around a possible
|
|
||||||
// deadlock in the HCS.
|
|
||||||
go func() {
|
|
||||||
time.Sleep(time.Second)
|
|
||||||
process.closedWaitOnce.Do(func() {
|
|
||||||
log.G(ctx).WithError(err).Warn("force unblocking process waits")
|
|
||||||
process.exitCode = -1
|
|
||||||
process.waitError = err
|
|
||||||
close(process.waitBlock)
|
|
||||||
})
|
|
||||||
}()
|
|
||||||
}
|
|
||||||
return false, nil
|
|
||||||
default:
|
|
||||||
return false, err
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Signal signals the process with `options`.
|
|
||||||
//
|
|
||||||
// For LCOW `guestrequest.SignalProcessOptionsLCOW`.
|
|
||||||
//
|
|
||||||
// For WCOW `guestrequest.SignalProcessOptionsWCOW`.
|
|
||||||
func (process *Process) Signal(ctx context.Context, options interface{}) (bool, error) {
|
|
||||||
process.handleLock.RLock()
|
|
||||||
defer process.handleLock.RUnlock()
|
|
||||||
|
|
||||||
operation := "hcsshim::Process::Signal"
|
|
||||||
|
|
||||||
if process.handle == 0 {
|
|
||||||
return false, makeProcessError(process, operation, ErrAlreadyClosed, nil)
|
|
||||||
}
|
|
||||||
|
|
||||||
optionsb, err := json.Marshal(options)
|
|
||||||
if err != nil {
|
|
||||||
return false, err
|
|
||||||
}
|
|
||||||
|
|
||||||
resultJSON, err := vmcompute.HcsSignalProcess(ctx, process.handle, string(optionsb))
|
|
||||||
events := processHcsResult(ctx, resultJSON)
|
|
||||||
delivered, err := process.processSignalResult(ctx, err)
|
|
||||||
if err != nil {
|
|
||||||
err = makeProcessError(process, operation, err, events)
|
|
||||||
}
|
|
||||||
return delivered, err
|
|
||||||
}
|
|
||||||
|
|
||||||
// Kill signals the process to terminate but does not wait for it to finish terminating.
|
|
||||||
func (process *Process) Kill(ctx context.Context) (bool, error) {
|
|
||||||
process.handleLock.RLock()
|
|
||||||
defer process.handleLock.RUnlock()
|
|
||||||
|
|
||||||
operation := "hcsshim::Process::Kill"
|
|
||||||
|
|
||||||
if process.handle == 0 {
|
|
||||||
return false, makeProcessError(process, operation, ErrAlreadyClosed, nil)
|
|
||||||
}
|
|
||||||
|
|
||||||
resultJSON, err := vmcompute.HcsTerminateProcess(ctx, process.handle)
|
|
||||||
events := processHcsResult(ctx, resultJSON)
|
|
||||||
delivered, err := process.processSignalResult(ctx, err)
|
|
||||||
if err != nil {
|
|
||||||
err = makeProcessError(process, operation, err, events)
|
|
||||||
}
|
|
||||||
return delivered, err
|
|
||||||
}
|
|
||||||
|
|
||||||
// waitBackground waits for the process exit notification. Once received sets
|
|
||||||
// `process.waitError` (if any) and unblocks all `Wait` calls.
|
|
||||||
//
|
|
||||||
// This MUST be called exactly once per `process.handle` but `Wait` is safe to
|
|
||||||
// call multiple times.
|
|
||||||
func (process *Process) waitBackground() {
|
|
||||||
operation := "hcsshim::Process::waitBackground"
|
|
||||||
ctx, span := trace.StartSpan(context.Background(), operation)
|
|
||||||
defer span.End()
|
|
||||||
span.AddAttributes(
|
|
||||||
trace.StringAttribute("cid", process.SystemID()),
|
|
||||||
trace.Int64Attribute("pid", int64(process.processID)))
|
|
||||||
|
|
||||||
var (
|
|
||||||
err error
|
|
||||||
exitCode = -1
|
|
||||||
propertiesJSON string
|
|
||||||
resultJSON string
|
|
||||||
)
|
|
||||||
|
|
||||||
err = waitForNotification(ctx, process.callbackNumber, hcsNotificationProcessExited, nil)
|
|
||||||
if err != nil {
|
|
||||||
err = makeProcessError(process, operation, err, nil)
|
|
||||||
log.G(ctx).WithError(err).Error("failed wait")
|
|
||||||
} else {
|
|
||||||
process.handleLock.RLock()
|
|
||||||
defer process.handleLock.RUnlock()
|
|
||||||
|
|
||||||
// Make sure we didnt race with Close() here
|
|
||||||
if process.handle != 0 {
|
|
||||||
propertiesJSON, resultJSON, err = vmcompute.HcsGetProcessProperties(ctx, process.handle)
|
|
||||||
events := processHcsResult(ctx, resultJSON)
|
|
||||||
if err != nil {
|
|
||||||
err = makeProcessError(process, operation, err, events) //nolint:ineffassign
|
|
||||||
} else {
|
|
||||||
properties := &processStatus{}
|
|
||||||
err = json.Unmarshal([]byte(propertiesJSON), properties)
|
|
||||||
if err != nil {
|
|
||||||
err = makeProcessError(process, operation, err, nil) //nolint:ineffassign
|
|
||||||
} else {
|
|
||||||
if properties.LastWaitResult != 0 {
|
|
||||||
log.G(ctx).WithField("wait-result", properties.LastWaitResult).Warning("non-zero last wait result")
|
|
||||||
} else {
|
|
||||||
exitCode = int(properties.ExitCode)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
log.G(ctx).WithField("exitCode", exitCode).Debug("process exited")
|
|
||||||
|
|
||||||
process.closedWaitOnce.Do(func() {
|
|
||||||
process.exitCode = exitCode
|
|
||||||
process.waitError = err
|
|
||||||
close(process.waitBlock)
|
|
||||||
})
|
|
||||||
oc.SetSpanStatus(span, err)
|
|
||||||
}
|
|
||||||
|
|
||||||
// Wait waits for the process to exit. If the process has already exited returns
|
|
||||||
// the pervious error (if any).
|
|
||||||
func (process *Process) Wait() error {
|
|
||||||
<-process.waitBlock
|
|
||||||
return process.waitError
|
|
||||||
}
|
|
||||||
|
|
||||||
// ResizeConsole resizes the console of the process.
|
|
||||||
func (process *Process) ResizeConsole(ctx context.Context, width, height uint16) error {
|
|
||||||
process.handleLock.RLock()
|
|
||||||
defer process.handleLock.RUnlock()
|
|
||||||
|
|
||||||
operation := "hcsshim::Process::ResizeConsole"
|
|
||||||
|
|
||||||
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
|
|
||||||
}
|
|
||||||
|
|
||||||
resultJSON, err := vmcompute.HcsModifyProcess(ctx, process.handle, string(modifyRequestb))
|
|
||||||
events := processHcsResult(ctx, resultJSON)
|
|
||||||
if err != nil {
|
|
||||||
return makeProcessError(process, operation, err, events)
|
|
||||||
}
|
|
||||||
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// ExitCode returns the exit code of the process. The process must have
|
|
||||||
// already terminated.
|
|
||||||
func (process *Process) ExitCode() (int, error) {
|
|
||||||
select {
|
|
||||||
case <-process.waitBlock:
|
|
||||||
if process.waitError != nil {
|
|
||||||
return -1, process.waitError
|
|
||||||
}
|
|
||||||
return process.exitCode, nil
|
|
||||||
default:
|
|
||||||
return -1, makeProcessError(process, "hcsshim::Process::ExitCode", ErrInvalidProcessState, nil)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// StdioLegacy returns the stdin, stdout, and stderr pipes, respectively. Closing
|
|
||||||
// these pipes does not close the underlying pipes. Once returned, these pipes
|
|
||||||
// are the responsibility of the caller to close.
|
|
||||||
func (process *Process) StdioLegacy() (_ io.WriteCloser, _ io.ReadCloser, _ io.ReadCloser, err error) {
|
|
||||||
operation := "hcsshim::Process::StdioLegacy"
|
|
||||||
ctx, span := trace.StartSpan(context.Background(), operation)
|
|
||||||
defer span.End()
|
|
||||||
defer func() { oc.SetSpanStatus(span, err) }()
|
|
||||||
span.AddAttributes(
|
|
||||||
trace.StringAttribute("cid", process.SystemID()),
|
|
||||||
trace.Int64Attribute("pid", int64(process.processID)))
|
|
||||||
|
|
||||||
process.handleLock.RLock()
|
|
||||||
defer process.handleLock.RUnlock()
|
|
||||||
|
|
||||||
if process.handle == 0 {
|
|
||||||
return nil, nil, nil, makeProcessError(process, operation, ErrAlreadyClosed, nil)
|
|
||||||
}
|
|
||||||
|
|
||||||
process.stdioLock.Lock()
|
|
||||||
defer process.stdioLock.Unlock()
|
|
||||||
if process.hasCachedStdio {
|
|
||||||
stdin, stdout, stderr := process.stdin, process.stdout, process.stderr
|
|
||||||
process.stdin, process.stdout, process.stderr = nil, nil, nil
|
|
||||||
process.hasCachedStdio = false
|
|
||||||
return stdin, stdout, stderr, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
processInfo, resultJSON, err := vmcompute.HcsGetProcessInfo(ctx, process.handle)
|
|
||||||
events := processHcsResult(ctx, resultJSON)
|
|
||||||
if err != nil {
|
|
||||||
return nil, nil, nil, makeProcessError(process, operation, err, events)
|
|
||||||
}
|
|
||||||
|
|
||||||
pipes, err := makeOpenFiles([]syscall.Handle{processInfo.StdInput, processInfo.StdOutput, processInfo.StdError})
|
|
||||||
if err != nil {
|
|
||||||
return nil, nil, nil, makeProcessError(process, operation, err, nil)
|
|
||||||
}
|
|
||||||
|
|
||||||
return pipes[0], pipes[1], pipes[2], nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// Stdio returns the stdin, stdout, and stderr pipes, respectively.
|
|
||||||
// To close them, close the process handle.
|
|
||||||
func (process *Process) Stdio() (stdin io.Writer, stdout, stderr io.Reader) {
|
|
||||||
process.stdioLock.Lock()
|
|
||||||
defer process.stdioLock.Unlock()
|
|
||||||
return process.stdin, process.stdout, process.stderr
|
|
||||||
}
|
|
||||||
|
|
||||||
// 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(ctx context.Context) error {
|
|
||||||
process.handleLock.RLock()
|
|
||||||
defer process.handleLock.RUnlock()
|
|
||||||
|
|
||||||
operation := "hcsshim::Process::CloseStdin"
|
|
||||||
|
|
||||||
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
|
|
||||||
}
|
|
||||||
|
|
||||||
resultJSON, err := vmcompute.HcsModifyProcess(ctx, process.handle, string(modifyRequestb))
|
|
||||||
events := processHcsResult(ctx, resultJSON)
|
|
||||||
if err != nil {
|
|
||||||
return makeProcessError(process, operation, err, events)
|
|
||||||
}
|
|
||||||
|
|
||||||
process.stdioLock.Lock()
|
|
||||||
if process.stdin != nil {
|
|
||||||
process.stdin.Close()
|
|
||||||
process.stdin = nil
|
|
||||||
}
|
|
||||||
process.stdioLock.Unlock()
|
|
||||||
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// Close cleans up any state associated with the process but does not kill
|
|
||||||
// or wait on it.
|
|
||||||
func (process *Process) Close() (err error) {
|
|
||||||
operation := "hcsshim::Process::Close"
|
|
||||||
ctx, span := trace.StartSpan(context.Background(), operation)
|
|
||||||
defer span.End()
|
|
||||||
defer func() { oc.SetSpanStatus(span, err) }()
|
|
||||||
span.AddAttributes(
|
|
||||||
trace.StringAttribute("cid", process.SystemID()),
|
|
||||||
trace.Int64Attribute("pid", int64(process.processID)))
|
|
||||||
|
|
||||||
process.handleLock.Lock()
|
|
||||||
defer process.handleLock.Unlock()
|
|
||||||
|
|
||||||
// Don't double free this
|
|
||||||
if process.handle == 0 {
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
process.stdioLock.Lock()
|
|
||||||
if process.stdin != nil {
|
|
||||||
process.stdin.Close()
|
|
||||||
process.stdin = nil
|
|
||||||
}
|
|
||||||
if process.stdout != nil {
|
|
||||||
process.stdout.Close()
|
|
||||||
process.stdout = nil
|
|
||||||
}
|
|
||||||
if process.stderr != nil {
|
|
||||||
process.stderr.Close()
|
|
||||||
process.stderr = nil
|
|
||||||
}
|
|
||||||
process.stdioLock.Unlock()
|
|
||||||
|
|
||||||
if err = process.unregisterCallback(ctx); err != nil {
|
|
||||||
return makeProcessError(process, operation, err, nil)
|
|
||||||
}
|
|
||||||
|
|
||||||
if err = vmcompute.HcsCloseProcess(ctx, process.handle); err != nil {
|
|
||||||
return makeProcessError(process, operation, err, nil)
|
|
||||||
}
|
|
||||||
|
|
||||||
process.handle = 0
|
|
||||||
process.closedWaitOnce.Do(func() {
|
|
||||||
process.exitCode = -1
|
|
||||||
process.waitError = ErrAlreadyClosed
|
|
||||||
close(process.waitBlock)
|
|
||||||
})
|
|
||||||
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func (process *Process) registerCallback(ctx context.Context) error {
|
|
||||||
callbackContext := ¬ifcationWatcherContext{
|
|
||||||
channels: newProcessChannels(),
|
|
||||||
systemID: process.SystemID(),
|
|
||||||
processID: process.processID,
|
|
||||||
}
|
|
||||||
|
|
||||||
callbackMapLock.Lock()
|
|
||||||
callbackNumber := nextCallback
|
|
||||||
nextCallback++
|
|
||||||
callbackMap[callbackNumber] = callbackContext
|
|
||||||
callbackMapLock.Unlock()
|
|
||||||
|
|
||||||
callbackHandle, err := vmcompute.HcsRegisterProcessCallback(ctx, process.handle, notificationWatcherCallback, callbackNumber)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
callbackContext.handle = callbackHandle
|
|
||||||
process.callbackNumber = callbackNumber
|
|
||||||
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func (process *Process) unregisterCallback(ctx context.Context) error {
|
|
||||||
callbackNumber := process.callbackNumber
|
|
||||||
|
|
||||||
callbackMapLock.RLock()
|
|
||||||
callbackContext := callbackMap[callbackNumber]
|
|
||||||
callbackMapLock.RUnlock()
|
|
||||||
|
|
||||||
if callbackContext == nil {
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
handle := callbackContext.handle
|
|
||||||
|
|
||||||
if handle == 0 {
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// vmcompute.HcsUnregisterProcessCallback has its own synchronization to
|
|
||||||
// wait for all callbacks to complete. We must NOT hold the callbackMapLock.
|
|
||||||
err := vmcompute.HcsUnregisterProcessCallback(ctx, handle)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
closeChannels(callbackContext.channels)
|
|
||||||
|
|
||||||
callbackMapLock.Lock()
|
|
||||||
delete(callbackMap, callbackNumber)
|
|
||||||
callbackMapLock.Unlock()
|
|
||||||
|
|
||||||
handle = 0 //nolint:ineffassign
|
|
||||||
|
|
||||||
return nil
|
|
||||||
}
|
|
|
@ -1,49 +0,0 @@
|
||||||
package hcs
|
|
||||||
|
|
||||||
import (
|
|
||||||
"context"
|
|
||||||
"encoding/json"
|
|
||||||
|
|
||||||
hcsschema "github.com/Microsoft/hcsshim/internal/schema2"
|
|
||||||
"github.com/Microsoft/hcsshim/internal/vmcompute"
|
|
||||||
)
|
|
||||||
|
|
||||||
// GetServiceProperties returns properties of the host compute service.
|
|
||||||
func GetServiceProperties(ctx context.Context, q hcsschema.PropertyQuery) (*hcsschema.ServiceProperties, error) {
|
|
||||||
operation := "hcsshim::GetServiceProperties"
|
|
||||||
|
|
||||||
queryb, err := json.Marshal(q)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
propertiesJSON, resultJSON, err := vmcompute.HcsGetServiceProperties(ctx, string(queryb))
|
|
||||||
events := processHcsResult(ctx, resultJSON)
|
|
||||||
if err != nil {
|
|
||||||
return nil, &HcsError{Op: operation, Err: err, Events: events}
|
|
||||||
}
|
|
||||||
|
|
||||||
if propertiesJSON == "" {
|
|
||||||
return nil, ErrUnexpectedValue
|
|
||||||
}
|
|
||||||
properties := &hcsschema.ServiceProperties{}
|
|
||||||
if err := json.Unmarshal([]byte(propertiesJSON), properties); err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
return properties, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// ModifyServiceSettings modifies settings of the host compute service.
|
|
||||||
func ModifyServiceSettings(ctx context.Context, settings hcsschema.ModificationRequest) error {
|
|
||||||
operation := "hcsshim::ModifyServiceSettings"
|
|
||||||
|
|
||||||
settingsJSON, err := json.Marshal(settings)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
resultJSON, err := vmcompute.HcsModifyServiceSettings(ctx, string(settingsJSON))
|
|
||||||
events := processHcsResult(ctx, resultJSON)
|
|
||||||
if err != nil {
|
|
||||||
return &HcsError{Op: operation, Err: err, Events: events}
|
|
||||||
}
|
|
||||||
return nil
|
|
||||||
}
|
|
|
@ -1,637 +0,0 @@
|
||||||
package hcs
|
|
||||||
|
|
||||||
import (
|
|
||||||
"context"
|
|
||||||
"encoding/json"
|
|
||||||
"errors"
|
|
||||||
"strings"
|
|
||||||
"sync"
|
|
||||||
"syscall"
|
|
||||||
|
|
||||||
"github.com/Microsoft/hcsshim/internal/cow"
|
|
||||||
"github.com/Microsoft/hcsshim/internal/log"
|
|
||||||
"github.com/Microsoft/hcsshim/internal/oc"
|
|
||||||
"github.com/Microsoft/hcsshim/internal/schema1"
|
|
||||||
hcsschema "github.com/Microsoft/hcsshim/internal/schema2"
|
|
||||||
"github.com/Microsoft/hcsshim/internal/timeout"
|
|
||||||
"github.com/Microsoft/hcsshim/internal/vmcompute"
|
|
||||||
"go.opencensus.io/trace"
|
|
||||||
)
|
|
||||||
|
|
||||||
type System struct {
|
|
||||||
handleLock sync.RWMutex
|
|
||||||
handle vmcompute.HcsSystem
|
|
||||||
id string
|
|
||||||
callbackNumber uintptr
|
|
||||||
|
|
||||||
closedWaitOnce sync.Once
|
|
||||||
waitBlock chan struct{}
|
|
||||||
waitError error
|
|
||||||
exitError error
|
|
||||||
os, typ string
|
|
||||||
}
|
|
||||||
|
|
||||||
func newSystem(id string) *System {
|
|
||||||
return &System{
|
|
||||||
id: id,
|
|
||||||
waitBlock: make(chan struct{}),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// CreateComputeSystem creates a new compute system with the given configuration but does not start it.
|
|
||||||
func CreateComputeSystem(ctx context.Context, id string, hcsDocumentInterface interface{}) (_ *System, err error) {
|
|
||||||
operation := "hcsshim::CreateComputeSystem"
|
|
||||||
|
|
||||||
// hcsCreateComputeSystemContext is an async operation. Start the outer span
|
|
||||||
// here to measure the full create time.
|
|
||||||
ctx, span := trace.StartSpan(ctx, operation)
|
|
||||||
defer span.End()
|
|
||||||
defer func() { oc.SetSpanStatus(span, err) }()
|
|
||||||
span.AddAttributes(trace.StringAttribute("cid", id))
|
|
||||||
|
|
||||||
computeSystem := newSystem(id)
|
|
||||||
|
|
||||||
hcsDocumentB, err := json.Marshal(hcsDocumentInterface)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
hcsDocument := string(hcsDocumentB)
|
|
||||||
|
|
||||||
var (
|
|
||||||
identity syscall.Handle
|
|
||||||
resultJSON string
|
|
||||||
createError error
|
|
||||||
)
|
|
||||||
computeSystem.handle, resultJSON, createError = vmcompute.HcsCreateComputeSystem(ctx, id, hcsDocument, identity)
|
|
||||||
if createError == nil || IsPending(createError) {
|
|
||||||
defer func() {
|
|
||||||
if err != nil {
|
|
||||||
computeSystem.Close()
|
|
||||||
}
|
|
||||||
}()
|
|
||||||
if err = computeSystem.registerCallback(ctx); err != nil {
|
|
||||||
// Terminate the compute system if it still exists. We're okay to
|
|
||||||
// ignore a failure here.
|
|
||||||
_ = computeSystem.Terminate(ctx)
|
|
||||||
return nil, makeSystemError(computeSystem, operation, err, nil)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
events, err := processAsyncHcsResult(ctx, createError, resultJSON, computeSystem.callbackNumber, hcsNotificationSystemCreateCompleted, &timeout.SystemCreate)
|
|
||||||
if err != nil {
|
|
||||||
if err == ErrTimeout {
|
|
||||||
// Terminate the compute system if it still exists. We're okay to
|
|
||||||
// ignore a failure here.
|
|
||||||
_ = computeSystem.Terminate(ctx)
|
|
||||||
}
|
|
||||||
return nil, makeSystemError(computeSystem, operation, err, events)
|
|
||||||
}
|
|
||||||
go computeSystem.waitBackground()
|
|
||||||
if err = computeSystem.getCachedProperties(ctx); err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
return computeSystem, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// OpenComputeSystem opens an existing compute system by ID.
|
|
||||||
func OpenComputeSystem(ctx context.Context, id string) (*System, error) {
|
|
||||||
operation := "hcsshim::OpenComputeSystem"
|
|
||||||
|
|
||||||
computeSystem := newSystem(id)
|
|
||||||
handle, resultJSON, err := vmcompute.HcsOpenComputeSystem(ctx, id)
|
|
||||||
events := processHcsResult(ctx, resultJSON)
|
|
||||||
if err != nil {
|
|
||||||
return nil, makeSystemError(computeSystem, operation, err, events)
|
|
||||||
}
|
|
||||||
computeSystem.handle = handle
|
|
||||||
defer func() {
|
|
||||||
if err != nil {
|
|
||||||
computeSystem.Close()
|
|
||||||
}
|
|
||||||
}()
|
|
||||||
if err = computeSystem.registerCallback(ctx); err != nil {
|
|
||||||
return nil, makeSystemError(computeSystem, operation, err, nil)
|
|
||||||
}
|
|
||||||
go computeSystem.waitBackground()
|
|
||||||
if err = computeSystem.getCachedProperties(ctx); err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
return computeSystem, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func (computeSystem *System) getCachedProperties(ctx context.Context) error {
|
|
||||||
props, err := computeSystem.Properties(ctx)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
computeSystem.typ = strings.ToLower(props.SystemType)
|
|
||||||
computeSystem.os = strings.ToLower(props.RuntimeOSType)
|
|
||||||
if computeSystem.os == "" && computeSystem.typ == "container" {
|
|
||||||
// Pre-RS5 HCS did not return the OS, but it only supported containers
|
|
||||||
// that ran Windows.
|
|
||||||
computeSystem.os = "windows"
|
|
||||||
}
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// OS returns the operating system of the compute system, "linux" or "windows".
|
|
||||||
func (computeSystem *System) OS() string {
|
|
||||||
return computeSystem.os
|
|
||||||
}
|
|
||||||
|
|
||||||
// IsOCI returns whether processes in the compute system should be created via
|
|
||||||
// OCI.
|
|
||||||
func (computeSystem *System) IsOCI() bool {
|
|
||||||
return computeSystem.os == "linux" && computeSystem.typ == "container"
|
|
||||||
}
|
|
||||||
|
|
||||||
// GetComputeSystems gets a list of the compute systems on the system that match the query
|
|
||||||
func GetComputeSystems(ctx context.Context, q schema1.ComputeSystemQuery) ([]schema1.ContainerProperties, error) {
|
|
||||||
operation := "hcsshim::GetComputeSystems"
|
|
||||||
|
|
||||||
queryb, err := json.Marshal(q)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
computeSystemsJSON, resultJSON, err := vmcompute.HcsEnumerateComputeSystems(ctx, string(queryb))
|
|
||||||
events := processHcsResult(ctx, resultJSON)
|
|
||||||
if err != nil {
|
|
||||||
return nil, &HcsError{Op: operation, Err: err, Events: events}
|
|
||||||
}
|
|
||||||
|
|
||||||
if computeSystemsJSON == "" {
|
|
||||||
return nil, ErrUnexpectedValue
|
|
||||||
}
|
|
||||||
computeSystems := []schema1.ContainerProperties{}
|
|
||||||
if err = json.Unmarshal([]byte(computeSystemsJSON), &computeSystems); err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
return computeSystems, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// Start synchronously starts the computeSystem.
|
|
||||||
func (computeSystem *System) Start(ctx context.Context) (err error) {
|
|
||||||
operation := "hcsshim::System::Start"
|
|
||||||
|
|
||||||
// hcsStartComputeSystemContext is an async operation. Start the outer span
|
|
||||||
// here to measure the full start time.
|
|
||||||
ctx, span := trace.StartSpan(ctx, operation)
|
|
||||||
defer span.End()
|
|
||||||
defer func() { oc.SetSpanStatus(span, err) }()
|
|
||||||
span.AddAttributes(trace.StringAttribute("cid", computeSystem.id))
|
|
||||||
|
|
||||||
computeSystem.handleLock.RLock()
|
|
||||||
defer computeSystem.handleLock.RUnlock()
|
|
||||||
|
|
||||||
if computeSystem.handle == 0 {
|
|
||||||
return makeSystemError(computeSystem, operation, ErrAlreadyClosed, nil)
|
|
||||||
}
|
|
||||||
|
|
||||||
resultJSON, err := vmcompute.HcsStartComputeSystem(ctx, computeSystem.handle, "")
|
|
||||||
events, err := processAsyncHcsResult(ctx, err, resultJSON, computeSystem.callbackNumber, hcsNotificationSystemStartCompleted, &timeout.SystemStart)
|
|
||||||
if err != nil {
|
|
||||||
return makeSystemError(computeSystem, operation, err, events)
|
|
||||||
}
|
|
||||||
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// ID returns the compute system's identifier.
|
|
||||||
func (computeSystem *System) ID() string {
|
|
||||||
return computeSystem.id
|
|
||||||
}
|
|
||||||
|
|
||||||
// Shutdown requests a compute system shutdown.
|
|
||||||
func (computeSystem *System) Shutdown(ctx context.Context) error {
|
|
||||||
computeSystem.handleLock.RLock()
|
|
||||||
defer computeSystem.handleLock.RUnlock()
|
|
||||||
|
|
||||||
operation := "hcsshim::System::Shutdown"
|
|
||||||
|
|
||||||
if computeSystem.handle == 0 {
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
resultJSON, err := vmcompute.HcsShutdownComputeSystem(ctx, computeSystem.handle, "")
|
|
||||||
events := processHcsResult(ctx, resultJSON)
|
|
||||||
switch err {
|
|
||||||
case nil, ErrVmcomputeAlreadyStopped, ErrComputeSystemDoesNotExist, ErrVmcomputeOperationPending:
|
|
||||||
default:
|
|
||||||
return makeSystemError(computeSystem, operation, err, events)
|
|
||||||
}
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// Terminate requests a compute system terminate.
|
|
||||||
func (computeSystem *System) Terminate(ctx context.Context) error {
|
|
||||||
computeSystem.handleLock.RLock()
|
|
||||||
defer computeSystem.handleLock.RUnlock()
|
|
||||||
|
|
||||||
operation := "hcsshim::System::Terminate"
|
|
||||||
|
|
||||||
if computeSystem.handle == 0 {
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
resultJSON, err := vmcompute.HcsTerminateComputeSystem(ctx, computeSystem.handle, "")
|
|
||||||
events := processHcsResult(ctx, resultJSON)
|
|
||||||
switch err {
|
|
||||||
case nil, ErrVmcomputeAlreadyStopped, ErrComputeSystemDoesNotExist, ErrVmcomputeOperationPending:
|
|
||||||
default:
|
|
||||||
return makeSystemError(computeSystem, operation, err, events)
|
|
||||||
}
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// waitBackground waits for the compute system exit notification. Once received
|
|
||||||
// sets `computeSystem.waitError` (if any) and unblocks all `Wait` calls.
|
|
||||||
//
|
|
||||||
// This MUST be called exactly once per `computeSystem.handle` but `Wait` is
|
|
||||||
// safe to call multiple times.
|
|
||||||
func (computeSystem *System) waitBackground() {
|
|
||||||
operation := "hcsshim::System::waitBackground"
|
|
||||||
ctx, span := trace.StartSpan(context.Background(), operation)
|
|
||||||
defer span.End()
|
|
||||||
span.AddAttributes(trace.StringAttribute("cid", computeSystem.id))
|
|
||||||
|
|
||||||
err := waitForNotification(ctx, computeSystem.callbackNumber, hcsNotificationSystemExited, nil)
|
|
||||||
switch err {
|
|
||||||
case nil:
|
|
||||||
log.G(ctx).Debug("system exited")
|
|
||||||
case ErrVmcomputeUnexpectedExit:
|
|
||||||
log.G(ctx).Debug("unexpected system exit")
|
|
||||||
computeSystem.exitError = makeSystemError(computeSystem, operation, err, nil)
|
|
||||||
err = nil
|
|
||||||
default:
|
|
||||||
err = makeSystemError(computeSystem, operation, err, nil)
|
|
||||||
}
|
|
||||||
computeSystem.closedWaitOnce.Do(func() {
|
|
||||||
computeSystem.waitError = err
|
|
||||||
close(computeSystem.waitBlock)
|
|
||||||
})
|
|
||||||
oc.SetSpanStatus(span, err)
|
|
||||||
}
|
|
||||||
|
|
||||||
// Wait synchronously waits for the compute system to shutdown or terminate. If
|
|
||||||
// the compute system has already exited returns the previous error (if any).
|
|
||||||
func (computeSystem *System) Wait() error {
|
|
||||||
<-computeSystem.waitBlock
|
|
||||||
return computeSystem.waitError
|
|
||||||
}
|
|
||||||
|
|
||||||
// ExitError returns an error describing the reason the compute system terminated.
|
|
||||||
func (computeSystem *System) ExitError() error {
|
|
||||||
select {
|
|
||||||
case <-computeSystem.waitBlock:
|
|
||||||
if computeSystem.waitError != nil {
|
|
||||||
return computeSystem.waitError
|
|
||||||
}
|
|
||||||
return computeSystem.exitError
|
|
||||||
default:
|
|
||||||
return errors.New("container not exited")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Properties returns the requested container properties targeting a V1 schema container.
|
|
||||||
func (computeSystem *System) Properties(ctx context.Context, types ...schema1.PropertyType) (*schema1.ContainerProperties, error) {
|
|
||||||
computeSystem.handleLock.RLock()
|
|
||||||
defer computeSystem.handleLock.RUnlock()
|
|
||||||
|
|
||||||
operation := "hcsshim::System::Properties"
|
|
||||||
|
|
||||||
queryBytes, err := json.Marshal(schema1.PropertyQuery{PropertyTypes: types})
|
|
||||||
if err != nil {
|
|
||||||
return nil, makeSystemError(computeSystem, operation, err, nil)
|
|
||||||
}
|
|
||||||
|
|
||||||
propertiesJSON, resultJSON, err := vmcompute.HcsGetComputeSystemProperties(ctx, computeSystem.handle, string(queryBytes))
|
|
||||||
events := processHcsResult(ctx, resultJSON)
|
|
||||||
if err != nil {
|
|
||||||
return nil, makeSystemError(computeSystem, operation, err, events)
|
|
||||||
}
|
|
||||||
|
|
||||||
if propertiesJSON == "" {
|
|
||||||
return nil, ErrUnexpectedValue
|
|
||||||
}
|
|
||||||
properties := &schema1.ContainerProperties{}
|
|
||||||
if err := json.Unmarshal([]byte(propertiesJSON), properties); err != nil {
|
|
||||||
return nil, makeSystemError(computeSystem, operation, err, nil)
|
|
||||||
}
|
|
||||||
|
|
||||||
return properties, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// PropertiesV2 returns the requested container properties targeting a V2 schema container.
|
|
||||||
func (computeSystem *System) PropertiesV2(ctx context.Context, types ...hcsschema.PropertyType) (*hcsschema.Properties, error) {
|
|
||||||
computeSystem.handleLock.RLock()
|
|
||||||
defer computeSystem.handleLock.RUnlock()
|
|
||||||
|
|
||||||
operation := "hcsshim::System::PropertiesV2"
|
|
||||||
|
|
||||||
queryBytes, err := json.Marshal(hcsschema.PropertyQuery{PropertyTypes: types})
|
|
||||||
if err != nil {
|
|
||||||
return nil, makeSystemError(computeSystem, operation, err, nil)
|
|
||||||
}
|
|
||||||
|
|
||||||
propertiesJSON, resultJSON, err := vmcompute.HcsGetComputeSystemProperties(ctx, computeSystem.handle, string(queryBytes))
|
|
||||||
events := processHcsResult(ctx, resultJSON)
|
|
||||||
if err != nil {
|
|
||||||
return nil, makeSystemError(computeSystem, operation, err, events)
|
|
||||||
}
|
|
||||||
|
|
||||||
if propertiesJSON == "" {
|
|
||||||
return nil, ErrUnexpectedValue
|
|
||||||
}
|
|
||||||
properties := &hcsschema.Properties{}
|
|
||||||
if err := json.Unmarshal([]byte(propertiesJSON), properties); err != nil {
|
|
||||||
return nil, makeSystemError(computeSystem, operation, err, nil)
|
|
||||||
}
|
|
||||||
|
|
||||||
return properties, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// Pause pauses the execution of the computeSystem. This feature is not enabled in TP5.
|
|
||||||
func (computeSystem *System) Pause(ctx context.Context) (err error) {
|
|
||||||
operation := "hcsshim::System::Pause"
|
|
||||||
|
|
||||||
// hcsPauseComputeSystemContext is an async peration. Start the outer span
|
|
||||||
// here to measure the full pause time.
|
|
||||||
ctx, span := trace.StartSpan(ctx, operation)
|
|
||||||
defer span.End()
|
|
||||||
defer func() { oc.SetSpanStatus(span, err) }()
|
|
||||||
span.AddAttributes(trace.StringAttribute("cid", computeSystem.id))
|
|
||||||
|
|
||||||
computeSystem.handleLock.RLock()
|
|
||||||
defer computeSystem.handleLock.RUnlock()
|
|
||||||
|
|
||||||
if computeSystem.handle == 0 {
|
|
||||||
return makeSystemError(computeSystem, operation, ErrAlreadyClosed, nil)
|
|
||||||
}
|
|
||||||
|
|
||||||
resultJSON, err := vmcompute.HcsPauseComputeSystem(ctx, computeSystem.handle, "")
|
|
||||||
events, err := processAsyncHcsResult(ctx, err, resultJSON, computeSystem.callbackNumber, hcsNotificationSystemPauseCompleted, &timeout.SystemPause)
|
|
||||||
if err != nil {
|
|
||||||
return makeSystemError(computeSystem, operation, err, events)
|
|
||||||
}
|
|
||||||
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// Resume resumes the execution of the computeSystem. This feature is not enabled in TP5.
|
|
||||||
func (computeSystem *System) Resume(ctx context.Context) (err error) {
|
|
||||||
operation := "hcsshim::System::Resume"
|
|
||||||
|
|
||||||
// hcsResumeComputeSystemContext is an async operation. Start the outer span
|
|
||||||
// here to measure the full restore time.
|
|
||||||
ctx, span := trace.StartSpan(ctx, operation)
|
|
||||||
defer span.End()
|
|
||||||
defer func() { oc.SetSpanStatus(span, err) }()
|
|
||||||
span.AddAttributes(trace.StringAttribute("cid", computeSystem.id))
|
|
||||||
|
|
||||||
computeSystem.handleLock.RLock()
|
|
||||||
defer computeSystem.handleLock.RUnlock()
|
|
||||||
|
|
||||||
if computeSystem.handle == 0 {
|
|
||||||
return makeSystemError(computeSystem, operation, ErrAlreadyClosed, nil)
|
|
||||||
}
|
|
||||||
|
|
||||||
resultJSON, err := vmcompute.HcsResumeComputeSystem(ctx, computeSystem.handle, "")
|
|
||||||
events, err := processAsyncHcsResult(ctx, err, resultJSON, computeSystem.callbackNumber, hcsNotificationSystemResumeCompleted, &timeout.SystemResume)
|
|
||||||
if err != nil {
|
|
||||||
return makeSystemError(computeSystem, operation, err, events)
|
|
||||||
}
|
|
||||||
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// Save the compute system
|
|
||||||
func (computeSystem *System) Save(ctx context.Context, options interface{}) (err error) {
|
|
||||||
operation := "hcsshim::System::Save"
|
|
||||||
|
|
||||||
// hcsSaveComputeSystemContext is an async peration. Start the outer span
|
|
||||||
// here to measure the full save time.
|
|
||||||
ctx, span := trace.StartSpan(ctx, operation)
|
|
||||||
defer span.End()
|
|
||||||
defer func() { oc.SetSpanStatus(span, err) }()
|
|
||||||
span.AddAttributes(trace.StringAttribute("cid", computeSystem.id))
|
|
||||||
|
|
||||||
saveOptions, err := json.Marshal(options)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
computeSystem.handleLock.RLock()
|
|
||||||
defer computeSystem.handleLock.RUnlock()
|
|
||||||
|
|
||||||
if computeSystem.handle == 0 {
|
|
||||||
return makeSystemError(computeSystem, operation, ErrAlreadyClosed, nil)
|
|
||||||
}
|
|
||||||
|
|
||||||
result, err := vmcompute.HcsSaveComputeSystem(ctx, computeSystem.handle, string(saveOptions))
|
|
||||||
events, err := processAsyncHcsResult(ctx, err, result, computeSystem.callbackNumber, hcsNotificationSystemSaveCompleted, &timeout.SystemSave)
|
|
||||||
if err != nil {
|
|
||||||
return makeSystemError(computeSystem, operation, err, events)
|
|
||||||
}
|
|
||||||
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func (computeSystem *System) createProcess(ctx context.Context, operation string, c interface{}) (*Process, *vmcompute.HcsProcessInformation, error) {
|
|
||||||
computeSystem.handleLock.RLock()
|
|
||||||
defer computeSystem.handleLock.RUnlock()
|
|
||||||
|
|
||||||
if computeSystem.handle == 0 {
|
|
||||||
return nil, nil, makeSystemError(computeSystem, operation, ErrAlreadyClosed, nil)
|
|
||||||
}
|
|
||||||
|
|
||||||
configurationb, err := json.Marshal(c)
|
|
||||||
if err != nil {
|
|
||||||
return nil, nil, makeSystemError(computeSystem, operation, err, nil)
|
|
||||||
}
|
|
||||||
|
|
||||||
configuration := string(configurationb)
|
|
||||||
processInfo, processHandle, resultJSON, err := vmcompute.HcsCreateProcess(ctx, computeSystem.handle, configuration)
|
|
||||||
events := processHcsResult(ctx, resultJSON)
|
|
||||||
if err != nil {
|
|
||||||
return nil, nil, makeSystemError(computeSystem, operation, err, events)
|
|
||||||
}
|
|
||||||
|
|
||||||
log.G(ctx).WithField("pid", processInfo.ProcessId).Debug("created process pid")
|
|
||||||
return newProcess(processHandle, int(processInfo.ProcessId), computeSystem), &processInfo, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// CreateProcess launches a new process within the computeSystem.
|
|
||||||
func (computeSystem *System) CreateProcess(ctx context.Context, c interface{}) (cow.Process, error) {
|
|
||||||
operation := "hcsshim::System::CreateProcess"
|
|
||||||
process, processInfo, err := computeSystem.createProcess(ctx, operation, c)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
defer func() {
|
|
||||||
if err != nil {
|
|
||||||
process.Close()
|
|
||||||
}
|
|
||||||
}()
|
|
||||||
|
|
||||||
pipes, err := makeOpenFiles([]syscall.Handle{processInfo.StdInput, processInfo.StdOutput, processInfo.StdError})
|
|
||||||
if err != nil {
|
|
||||||
return nil, makeSystemError(computeSystem, operation, err, nil)
|
|
||||||
}
|
|
||||||
process.stdin = pipes[0]
|
|
||||||
process.stdout = pipes[1]
|
|
||||||
process.stderr = pipes[2]
|
|
||||||
process.hasCachedStdio = true
|
|
||||||
|
|
||||||
if err = process.registerCallback(ctx); err != nil {
|
|
||||||
return nil, makeSystemError(computeSystem, operation, err, nil)
|
|
||||||
}
|
|
||||||
go process.waitBackground()
|
|
||||||
|
|
||||||
return process, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// OpenProcess gets an interface to an existing process within the computeSystem.
|
|
||||||
func (computeSystem *System) OpenProcess(ctx context.Context, pid int) (*Process, error) {
|
|
||||||
computeSystem.handleLock.RLock()
|
|
||||||
defer computeSystem.handleLock.RUnlock()
|
|
||||||
|
|
||||||
operation := "hcsshim::System::OpenProcess"
|
|
||||||
|
|
||||||
if computeSystem.handle == 0 {
|
|
||||||
return nil, makeSystemError(computeSystem, operation, ErrAlreadyClosed, nil)
|
|
||||||
}
|
|
||||||
|
|
||||||
processHandle, resultJSON, err := vmcompute.HcsOpenProcess(ctx, computeSystem.handle, uint32(pid))
|
|
||||||
events := processHcsResult(ctx, resultJSON)
|
|
||||||
if err != nil {
|
|
||||||
return nil, makeSystemError(computeSystem, operation, err, events)
|
|
||||||
}
|
|
||||||
|
|
||||||
process := newProcess(processHandle, pid, computeSystem)
|
|
||||||
if err = process.registerCallback(ctx); err != nil {
|
|
||||||
return nil, makeSystemError(computeSystem, operation, err, nil)
|
|
||||||
}
|
|
||||||
go process.waitBackground()
|
|
||||||
|
|
||||||
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() (err error) {
|
|
||||||
operation := "hcsshim::System::Close"
|
|
||||||
ctx, span := trace.StartSpan(context.Background(), operation)
|
|
||||||
defer span.End()
|
|
||||||
defer func() { oc.SetSpanStatus(span, err) }()
|
|
||||||
span.AddAttributes(trace.StringAttribute("cid", computeSystem.id))
|
|
||||||
|
|
||||||
computeSystem.handleLock.Lock()
|
|
||||||
defer computeSystem.handleLock.Unlock()
|
|
||||||
|
|
||||||
// Don't double free this
|
|
||||||
if computeSystem.handle == 0 {
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
if err = computeSystem.unregisterCallback(ctx); err != nil {
|
|
||||||
return makeSystemError(computeSystem, operation, err, nil)
|
|
||||||
}
|
|
||||||
|
|
||||||
err = vmcompute.HcsCloseComputeSystem(ctx, computeSystem.handle)
|
|
||||||
if err != nil {
|
|
||||||
return makeSystemError(computeSystem, operation, err, nil)
|
|
||||||
}
|
|
||||||
|
|
||||||
computeSystem.handle = 0
|
|
||||||
computeSystem.closedWaitOnce.Do(func() {
|
|
||||||
computeSystem.waitError = ErrAlreadyClosed
|
|
||||||
close(computeSystem.waitBlock)
|
|
||||||
})
|
|
||||||
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func (computeSystem *System) registerCallback(ctx context.Context) error {
|
|
||||||
callbackContext := ¬ifcationWatcherContext{
|
|
||||||
channels: newSystemChannels(),
|
|
||||||
systemID: computeSystem.id,
|
|
||||||
}
|
|
||||||
|
|
||||||
callbackMapLock.Lock()
|
|
||||||
callbackNumber := nextCallback
|
|
||||||
nextCallback++
|
|
||||||
callbackMap[callbackNumber] = callbackContext
|
|
||||||
callbackMapLock.Unlock()
|
|
||||||
|
|
||||||
callbackHandle, err := vmcompute.HcsRegisterComputeSystemCallback(ctx, computeSystem.handle, notificationWatcherCallback, callbackNumber)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
callbackContext.handle = callbackHandle
|
|
||||||
computeSystem.callbackNumber = callbackNumber
|
|
||||||
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func (computeSystem *System) unregisterCallback(ctx context.Context) error {
|
|
||||||
callbackNumber := computeSystem.callbackNumber
|
|
||||||
|
|
||||||
callbackMapLock.RLock()
|
|
||||||
callbackContext := callbackMap[callbackNumber]
|
|
||||||
callbackMapLock.RUnlock()
|
|
||||||
|
|
||||||
if callbackContext == nil {
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
handle := callbackContext.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 := vmcompute.HcsUnregisterComputeSystemCallback(ctx, handle)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
closeChannels(callbackContext.channels)
|
|
||||||
|
|
||||||
callbackMapLock.Lock()
|
|
||||||
delete(callbackMap, callbackNumber)
|
|
||||||
callbackMapLock.Unlock()
|
|
||||||
|
|
||||||
handle = 0 //nolint:ineffassign
|
|
||||||
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// Modify the System by sending a request to HCS
|
|
||||||
func (computeSystem *System) Modify(ctx context.Context, config interface{}) error {
|
|
||||||
computeSystem.handleLock.RLock()
|
|
||||||
defer computeSystem.handleLock.RUnlock()
|
|
||||||
|
|
||||||
operation := "hcsshim::System::Modify"
|
|
||||||
|
|
||||||
if computeSystem.handle == 0 {
|
|
||||||
return makeSystemError(computeSystem, operation, ErrAlreadyClosed, nil)
|
|
||||||
}
|
|
||||||
|
|
||||||
requestBytes, err := json.Marshal(config)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
requestJSON := string(requestBytes)
|
|
||||||
resultJSON, err := vmcompute.HcsModifyComputeSystem(ctx, computeSystem.handle, requestJSON)
|
|
||||||
events := processHcsResult(ctx, resultJSON)
|
|
||||||
if err != nil {
|
|
||||||
return makeSystemError(computeSystem, operation, err, events)
|
|
||||||
}
|
|
||||||
|
|
||||||
return nil
|
|
||||||
}
|
|
|
@ -1,62 +0,0 @@
|
||||||
package hcs
|
|
||||||
|
|
||||||
import (
|
|
||||||
"context"
|
|
||||||
"io"
|
|
||||||
"syscall"
|
|
||||||
|
|
||||||
"github.com/Microsoft/go-winio"
|
|
||||||
diskutil "github.com/Microsoft/go-winio/vhd"
|
|
||||||
"github.com/Microsoft/hcsshim/computestorage"
|
|
||||||
"github.com/pkg/errors"
|
|
||||||
"golang.org/x/sys/windows"
|
|
||||||
)
|
|
||||||
|
|
||||||
// makeOpenFiles calls winio.MakeOpenFile for each handle in a slice but closes all the handles
|
|
||||||
// if there is an error.
|
|
||||||
func makeOpenFiles(hs []syscall.Handle) (_ []io.ReadWriteCloser, err error) {
|
|
||||||
fs := make([]io.ReadWriteCloser, len(hs))
|
|
||||||
for i, h := range hs {
|
|
||||||
if h != syscall.Handle(0) {
|
|
||||||
if err == nil {
|
|
||||||
fs[i], err = winio.MakeOpenFile(h)
|
|
||||||
}
|
|
||||||
if err != nil {
|
|
||||||
syscall.Close(h)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if err != nil {
|
|
||||||
for _, f := range fs {
|
|
||||||
if f != nil {
|
|
||||||
f.Close()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
return fs, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// CreateNTFSVHD creates a VHD formatted with NTFS of size `sizeGB` at the given `vhdPath`.
|
|
||||||
func CreateNTFSVHD(ctx context.Context, vhdPath string, sizeGB uint32) (err error) {
|
|
||||||
if err := diskutil.CreateVhdx(vhdPath, sizeGB, 1); err != nil {
|
|
||||||
return errors.Wrap(err, "failed to create VHD")
|
|
||||||
}
|
|
||||||
|
|
||||||
vhd, err := diskutil.OpenVirtualDisk(vhdPath, diskutil.VirtualDiskAccessNone, diskutil.OpenVirtualDiskFlagNone)
|
|
||||||
if err != nil {
|
|
||||||
return errors.Wrap(err, "failed to open VHD")
|
|
||||||
}
|
|
||||||
defer func() {
|
|
||||||
err2 := windows.CloseHandle(windows.Handle(vhd))
|
|
||||||
if err == nil {
|
|
||||||
err = errors.Wrap(err2, "failed to close VHD")
|
|
||||||
}
|
|
||||||
}()
|
|
||||||
|
|
||||||
if err := computestorage.FormatWritableLayerVhd(ctx, windows.Handle(vhd)); err != nil {
|
|
||||||
return errors.Wrap(err, "failed to format VHD")
|
|
||||||
}
|
|
||||||
|
|
||||||
return nil
|
|
||||||
}
|
|
|
@ -1,68 +0,0 @@
|
||||||
package hcs
|
|
||||||
|
|
||||||
import (
|
|
||||||
"context"
|
|
||||||
"time"
|
|
||||||
|
|
||||||
"github.com/Microsoft/hcsshim/internal/log"
|
|
||||||
)
|
|
||||||
|
|
||||||
func processAsyncHcsResult(ctx context.Context, err error, resultJSON string, callbackNumber uintptr, expectedNotification hcsNotification, timeout *time.Duration) ([]ErrorEvent, error) {
|
|
||||||
events := processHcsResult(ctx, resultJSON)
|
|
||||||
if IsPending(err) {
|
|
||||||
return nil, waitForNotification(ctx, callbackNumber, expectedNotification, timeout)
|
|
||||||
}
|
|
||||||
|
|
||||||
return events, err
|
|
||||||
}
|
|
||||||
|
|
||||||
func waitForNotification(ctx context.Context, callbackNumber uintptr, expectedNotification hcsNotification, timeout *time.Duration) error {
|
|
||||||
callbackMapLock.RLock()
|
|
||||||
if _, ok := callbackMap[callbackNumber]; !ok {
|
|
||||||
callbackMapLock.RUnlock()
|
|
||||||
log.G(ctx).WithField("callbackNumber", callbackNumber).Error("failed to waitForNotification: callbackNumber does not exist in callbackMap")
|
|
||||||
return ErrHandleClose
|
|
||||||
}
|
|
||||||
channels := callbackMap[callbackNumber].channels
|
|
||||||
callbackMapLock.RUnlock()
|
|
||||||
|
|
||||||
expectedChannel := channels[expectedNotification]
|
|
||||||
if expectedChannel == nil {
|
|
||||||
log.G(ctx).WithField("type", expectedNotification).Error("unknown notification type in waitForNotification")
|
|
||||||
return ErrInvalidNotificationType
|
|
||||||
}
|
|
||||||
|
|
||||||
var c <-chan time.Time
|
|
||||||
if timeout != nil {
|
|
||||||
timer := time.NewTimer(*timeout)
|
|
||||||
c = timer.C
|
|
||||||
defer timer.Stop()
|
|
||||||
}
|
|
||||||
|
|
||||||
select {
|
|
||||||
case err, ok := <-expectedChannel:
|
|
||||||
if !ok {
|
|
||||||
return ErrHandleClose
|
|
||||||
}
|
|
||||||
return err
|
|
||||||
case err, ok := <-channels[hcsNotificationSystemExited]:
|
|
||||||
if !ok {
|
|
||||||
return ErrHandleClose
|
|
||||||
}
|
|
||||||
// If the expected notification is hcsNotificationSystemExited which of the two selects
|
|
||||||
// chosen is random. Return the raw error if hcsNotificationSystemExited is expected
|
|
||||||
if channels[hcsNotificationSystemExited] == expectedChannel {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
return ErrUnexpectedContainerExit
|
|
||||||
case _, ok := <-channels[hcsNotificationServiceDisconnect]:
|
|
||||||
if !ok {
|
|
||||||
return ErrHandleClose
|
|
||||||
}
|
|
||||||
// hcsNotificationServiceDisconnect should never be an expected notification
|
|
||||||
// it does not need the same handling as hcsNotificationSystemExited
|
|
||||||
return ErrUnexpectedProcessAbort
|
|
||||||
case <-c:
|
|
||||||
return ErrTimeout
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,47 +0,0 @@
|
||||||
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 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)
|
|
||||||
}
|
|
|
@ -1,23 +0,0 @@
|
||||||
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)
|
|
||||||
}
|
|
|
@ -1,308 +0,0 @@
|
||||||
package hns
|
|
||||||
|
|
||||||
import (
|
|
||||||
"encoding/json"
|
|
||||||
"net"
|
|
||||||
"strings"
|
|
||||||
|
|
||||||
"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"`
|
|
||||||
IPv6Address net.IP `json:",omitempty"`
|
|
||||||
DNSSuffix string `json:",omitempty"`
|
|
||||||
DNSServerList string `json:",omitempty"`
|
|
||||||
GatewayAddress string `json:",omitempty"`
|
|
||||||
GatewayAddressV6 string `json:",omitempty"`
|
|
||||||
EnableInternalDNS bool `json:",omitempty"`
|
|
||||||
DisableICC bool `json:",omitempty"`
|
|
||||||
PrefixLength uint8 `json:",omitempty"`
|
|
||||||
IPv6PrefixLength uint8 `json:",omitempty"`
|
|
||||||
IsRemoteEndpoint bool `json:",omitempty"`
|
|
||||||
EnableLowMetric bool `json:",omitempty"`
|
|
||||||
Namespace *Namespace `json:",omitempty"`
|
|
||||||
EncapOverhead uint16 `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}
|
|
||||||
}
|
|
||||||
|
|
||||||
type endpointAttachInfo struct {
|
|
||||||
SharedContainers json.RawMessage `json:",omitempty"`
|
|
||||||
}
|
|
||||||
|
|
||||||
func (endpoint *HNSEndpoint) IsAttached(vID string) (bool, error) {
|
|
||||||
attachInfo := endpointAttachInfo{}
|
|
||||||
err := hnsCall("GET", "/endpoints/"+endpoint.Id, "", &attachInfo)
|
|
||||||
|
|
||||||
// Return false allows us to just return the err
|
|
||||||
if err != nil {
|
|
||||||
return false, err
|
|
||||||
}
|
|
||||||
|
|
||||||
if strings.Contains(strings.ToLower(string(attachInfo.SharedContainers)), strings.ToLower(vID)) {
|
|
||||||
return true, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
return false, nil
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
// 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
|
|
||||||
}
|
|
||||||
|
|
||||||
// ApplyProxyPolicy applies a set of Proxy Policies on the Endpoint
|
|
||||||
func (endpoint *HNSEndpoint) ApplyProxyPolicy(policies ...*ProxyPolicy) error {
|
|
||||||
operation := "ApplyProxyPolicy"
|
|
||||||
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,49 +0,0 @@
|
||||||
package hns
|
|
||||||
|
|
||||||
import (
|
|
||||||
"encoding/json"
|
|
||||||
"fmt"
|
|
||||||
|
|
||||||
"github.com/Microsoft/hcsshim/internal/hcserror"
|
|
||||||
"github.com/Microsoft/hcsshim/internal/interop"
|
|
||||||
"github.com/sirupsen/logrus"
|
|
||||||
)
|
|
||||||
|
|
||||||
func hnsCallRawResponse(method, path, request string) (*hnsResponse, error) {
|
|
||||||
var responseBuffer *uint16
|
|
||||||
logrus.Debugf("[%s]=>[%s] Request : %s", method, path, request)
|
|
||||||
|
|
||||||
err := _hnsCall(method, path, request, &responseBuffer)
|
|
||||||
if err != nil {
|
|
||||||
return nil, hcserror.New(err, "hnsCall ", "")
|
|
||||||
}
|
|
||||||
response := interop.ConvertAndFreeCoTaskMemString(responseBuffer)
|
|
||||||
|
|
||||||
hnsresponse := &hnsResponse{}
|
|
||||||
if err = json.Unmarshal([]byte(response), &hnsresponse); err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
return hnsresponse, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func hnsCall(method, path, request string, returnResponse interface{}) error {
|
|
||||||
hnsresponse, err := hnsCallRawResponse(method, path, request)
|
|
||||||
if err != nil {
|
|
||||||
return fmt.Errorf("failed during hnsCallRawResponse: %v", err)
|
|
||||||
}
|
|
||||||
if !hnsresponse.Success {
|
|
||||||
return fmt.Errorf("hns failed with error : %s", hnsresponse.Error)
|
|
||||||
}
|
|
||||||
|
|
||||||
if len(hnsresponse.Output) == 0 {
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
logrus.Debugf("Network Response : %s", hnsresponse.Output)
|
|
||||||
err = json.Unmarshal(hnsresponse.Output, returnResponse)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
return nil
|
|
||||||
}
|
|
|
@ -1,28 +0,0 @@
|
||||||
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
|
|
||||||
}
|
|
|
@ -1,141 +0,0 @@
|
||||||
package hns
|
|
||||||
|
|
||||||
import (
|
|
||||||
"encoding/json"
|
|
||||||
"errors"
|
|
||||||
"github.com/sirupsen/logrus"
|
|
||||||
"net"
|
|
||||||
)
|
|
||||||
|
|
||||||
// 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 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)
|
|
||||||
|
|
||||||
for _, subnet := range network.Subnets {
|
|
||||||
if (subnet.AddressPrefix != "") && (subnet.GatewayAddress == "") {
|
|
||||||
return nil, errors.New("network create error, subnet has address prefix but no gateway specified")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
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,109 +0,0 @@
|
||||||
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"
|
|
||||||
Proxy PolicyType = "PROXY"
|
|
||||||
)
|
|
||||||
|
|
||||||
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"`
|
|
||||||
Destinations []string `json:",omitempty"`
|
|
||||||
}
|
|
||||||
|
|
||||||
type ProxyPolicy struct {
|
|
||||||
Type PolicyType `json:"Type"`
|
|
||||||
IP string `json:",omitempty"`
|
|
||||||
Port string `json:",omitempty"`
|
|
||||||
ExceptionList []string `json:",omitempty"`
|
|
||||||
Destination string `json:",omitempty"`
|
|
||||||
OutboundNat bool `json:",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"`
|
|
||||||
}
|
|
|
@ -1,201 +0,0 @@
|
||||||
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"`
|
|
||||||
DSR bool `json:"IsDSR,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()
|
|
||||||
}
|
|
|
@ -1,49 +0,0 @@
|
||||||
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
|
|
||||||
}
|
|
|
@ -1,111 +0,0 @@
|
||||||
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"`
|
|
||||||
CompartmentId uint32 `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
|
|
||||||
}
|
|
|
@ -1,76 +0,0 @@
|
||||||
// Code generated mksyscall_windows.exe DO NOT EDIT
|
|
||||||
|
|
||||||
package hns
|
|
||||||
|
|
||||||
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 (
|
|
||||||
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 {
|
|
||||||
if r0&0x1fff0000 == 0x00070000 {
|
|
||||||
r0 &= 0xffff
|
|
||||||
}
|
|
||||||
hr = syscall.Errno(r0)
|
|
||||||
}
|
|
||||||
return
|
|
||||||
}
|
|
|
@ -1,23 +0,0 @@
|
||||||
package interop
|
|
||||||
|
|
||||||
import (
|
|
||||||
"syscall"
|
|
||||||
"unsafe"
|
|
||||||
)
|
|
||||||
|
|
||||||
//go:generate go run ../../mksyscall_windows.go -output zsyscall_windows.go interop.go
|
|
||||||
|
|
||||||
//sys coTaskMemFree(buffer unsafe.Pointer) = api_ms_win_core_com_l1_1_0.CoTaskMemFree
|
|
||||||
|
|
||||||
func ConvertAndFreeCoTaskMemString(buffer *uint16) string {
|
|
||||||
str := syscall.UTF16ToString((*[1 << 29]uint16)(unsafe.Pointer(buffer))[:])
|
|
||||||
coTaskMemFree(unsafe.Pointer(buffer))
|
|
||||||
return str
|
|
||||||
}
|
|
||||||
|
|
||||||
func Win32FromHresult(hr uintptr) syscall.Errno {
|
|
||||||
if hr&0x1fff0000 == 0x00070000 {
|
|
||||||
return syscall.Errno(hr & 0xffff)
|
|
||||||
}
|
|
||||||
return syscall.Errno(hr)
|
|
||||||
}
|
|
|
@ -1,48 +0,0 @@
|
||||||
// Code generated mksyscall_windows.exe 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 (
|
|
||||||
modapi_ms_win_core_com_l1_1_0 = windows.NewLazySystemDLL("api-ms-win-core-com-l1-1-0.dll")
|
|
||||||
|
|
||||||
procCoTaskMemFree = modapi_ms_win_core_com_l1_1_0.NewProc("CoTaskMemFree")
|
|
||||||
)
|
|
||||||
|
|
||||||
func coTaskMemFree(buffer unsafe.Pointer) {
|
|
||||||
syscall.Syscall(procCoTaskMemFree.Addr(), 1, uintptr(buffer), 0, 0)
|
|
||||||
return
|
|
||||||
}
|
|
|
@ -1,23 +0,0 @@
|
||||||
package log
|
|
||||||
|
|
||||||
import (
|
|
||||||
"context"
|
|
||||||
|
|
||||||
"github.com/sirupsen/logrus"
|
|
||||||
"go.opencensus.io/trace"
|
|
||||||
)
|
|
||||||
|
|
||||||
// G returns a `logrus.Entry` with the `TraceID, SpanID` from `ctx` if `ctx`
|
|
||||||
// contains an OpenCensus `trace.Span`.
|
|
||||||
func G(ctx context.Context) *logrus.Entry {
|
|
||||||
span := trace.FromContext(ctx)
|
|
||||||
if span != nil {
|
|
||||||
sctx := span.SpanContext()
|
|
||||||
return logrus.WithFields(logrus.Fields{
|
|
||||||
"traceID": sctx.TraceID.String(),
|
|
||||||
"spanID": sctx.SpanID.String(),
|
|
||||||
// "parentSpanID": TODO: JTERRY75 - Try to convince OC to export this?
|
|
||||||
})
|
|
||||||
}
|
|
||||||
return logrus.NewEntry(logrus.StandardLogger())
|
|
||||||
}
|
|
|
@ -1,32 +0,0 @@
|
||||||
package logfields
|
|
||||||
|
|
||||||
const (
|
|
||||||
// Identifiers
|
|
||||||
|
|
||||||
ContainerID = "cid"
|
|
||||||
UVMID = "uvm-id"
|
|
||||||
ProcessID = "pid"
|
|
||||||
|
|
||||||
// Common Misc
|
|
||||||
|
|
||||||
// Timeout represents an operation timeout.
|
|
||||||
Timeout = "timeout"
|
|
||||||
JSON = "json"
|
|
||||||
|
|
||||||
// Keys/values
|
|
||||||
|
|
||||||
Field = "field"
|
|
||||||
OCIAnnotation = "oci-annotation"
|
|
||||||
Value = "value"
|
|
||||||
|
|
||||||
// Golang type's
|
|
||||||
|
|
||||||
ExpectedType = "expected-type"
|
|
||||||
Bool = "bool"
|
|
||||||
Uint32 = "uint32"
|
|
||||||
Uint64 = "uint64"
|
|
||||||
|
|
||||||
// runhcs
|
|
||||||
|
|
||||||
VMShimOperation = "vmshim-op"
|
|
||||||
)
|
|
|
@ -1,24 +0,0 @@
|
||||||
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
|
|
||||||
}
|
|
|
@ -1,52 +0,0 @@
|
||||||
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,43 +0,0 @@
|
||||||
package oc
|
|
||||||
|
|
||||||
import (
|
|
||||||
"github.com/sirupsen/logrus"
|
|
||||||
"go.opencensus.io/trace"
|
|
||||||
)
|
|
||||||
|
|
||||||
var _ = (trace.Exporter)(&LogrusExporter{})
|
|
||||||
|
|
||||||
// LogrusExporter is an OpenCensus `trace.Exporter` that exports
|
|
||||||
// `trace.SpanData` to logrus output.
|
|
||||||
type LogrusExporter struct {
|
|
||||||
}
|
|
||||||
|
|
||||||
// ExportSpan exports `s` based on the the following rules:
|
|
||||||
//
|
|
||||||
// 1. All output will contain `s.Attributes`, `s.TraceID`, `s.SpanID`,
|
|
||||||
// `s.ParentSpanID` for correlation
|
|
||||||
//
|
|
||||||
// 2. Any calls to .Annotate will not be supported.
|
|
||||||
//
|
|
||||||
// 3. The span itself will be written at `logrus.InfoLevel` unless
|
|
||||||
// `s.Status.Code != 0` in which case it will be written at `logrus.ErrorLevel`
|
|
||||||
// providing `s.Status.Message` as the error value.
|
|
||||||
func (le *LogrusExporter) ExportSpan(s *trace.SpanData) {
|
|
||||||
// Combine all span annotations with traceID, spanID, parentSpanID
|
|
||||||
baseEntry := logrus.WithFields(logrus.Fields(s.Attributes))
|
|
||||||
baseEntry.Data["traceID"] = s.TraceID.String()
|
|
||||||
baseEntry.Data["spanID"] = s.SpanID.String()
|
|
||||||
baseEntry.Data["parentSpanID"] = s.ParentSpanID.String()
|
|
||||||
baseEntry.Data["startTime"] = s.StartTime
|
|
||||||
baseEntry.Data["endTime"] = s.EndTime
|
|
||||||
baseEntry.Data["duration"] = s.EndTime.Sub(s.StartTime).String()
|
|
||||||
baseEntry.Data["name"] = s.Name
|
|
||||||
baseEntry.Time = s.StartTime
|
|
||||||
|
|
||||||
level := logrus.InfoLevel
|
|
||||||
if s.Status.Code != 0 {
|
|
||||||
level = logrus.ErrorLevel
|
|
||||||
baseEntry.Data[logrus.ErrorKey] = s.Status.Message
|
|
||||||
}
|
|
||||||
baseEntry.Log(level, "Span")
|
|
||||||
}
|
|
|
@ -1,17 +0,0 @@
|
||||||
package oc
|
|
||||||
|
|
||||||
import (
|
|
||||||
"go.opencensus.io/trace"
|
|
||||||
)
|
|
||||||
|
|
||||||
// SetSpanStatus sets `span.SetStatus` to the proper status depending on `err`. If
|
|
||||||
// `err` is `nil` assumes `trace.StatusCodeOk`.
|
|
||||||
func SetSpanStatus(span *trace.Span, err error) {
|
|
||||||
status := trace.Status{}
|
|
||||||
if err != nil {
|
|
||||||
// TODO: JTERRY75 - Handle errors in a non-generic way
|
|
||||||
status.Code = trace.StatusCodeUnknown
|
|
||||||
status.Message = err.Error()
|
|
||||||
}
|
|
||||||
span.SetStatus(status)
|
|
||||||
}
|
|
|
@ -1,375 +0,0 @@
|
||||||
package safefile
|
|
||||||
|
|
||||||
import (
|
|
||||||
"errors"
|
|
||||||
"io"
|
|
||||||
"os"
|
|
||||||
"path/filepath"
|
|
||||||
"strings"
|
|
||||||
"syscall"
|
|
||||||
"unicode/utf16"
|
|
||||||
"unsafe"
|
|
||||||
|
|
||||||
"github.com/Microsoft/hcsshim/internal/longpath"
|
|
||||||
"github.com/Microsoft/hcsshim/internal/winapi"
|
|
||||||
|
|
||||||
winio "github.com/Microsoft/go-winio"
|
|
||||||
)
|
|
||||||
|
|
||||||
func OpenRoot(path string) (*os.File, error) {
|
|
||||||
longpath, err := longpath.LongAbs(path)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
return winio.OpenForBackup(longpath, syscall.GENERIC_READ, syscall.FILE_SHARE_READ|syscall.FILE_SHARE_WRITE|syscall.FILE_SHARE_DELETE, syscall.OPEN_EXISTING)
|
|
||||||
}
|
|
||||||
|
|
||||||
func cleanGoStringRelativePath(path string) (string, error) {
|
|
||||||
path = filepath.Clean(path)
|
|
||||||
if strings.Contains(path, ":") {
|
|
||||||
// Since alternate data streams must follow the file they
|
|
||||||
// are attached to, finding one here (out of order) is invalid.
|
|
||||||
return "", errors.New("path contains invalid character `:`")
|
|
||||||
}
|
|
||||||
fspath := filepath.FromSlash(path)
|
|
||||||
if len(fspath) > 0 && fspath[0] == '\\' {
|
|
||||||
return "", errors.New("expected relative path")
|
|
||||||
}
|
|
||||||
return fspath, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func ntRelativePath(path string) ([]uint16, error) {
|
|
||||||
fspath, err := cleanGoStringRelativePath(path)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
path16 := utf16.Encode(([]rune)(fspath))
|
|
||||||
if len(path16) > 32767 {
|
|
||||||
return nil, syscall.ENAMETOOLONG
|
|
||||||
}
|
|
||||||
|
|
||||||
return path16, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// openRelativeInternal opens a relative path from the given root, failing if
|
|
||||||
// any of the intermediate path components are reparse points.
|
|
||||||
func openRelativeInternal(path string, root *os.File, accessMask uint32, shareFlags uint32, createDisposition uint32, flags uint32) (*os.File, error) {
|
|
||||||
var (
|
|
||||||
h uintptr
|
|
||||||
iosb winapi.IOStatusBlock
|
|
||||||
oa winapi.ObjectAttributes
|
|
||||||
)
|
|
||||||
|
|
||||||
cleanRelativePath, err := cleanGoStringRelativePath(path)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
if root == nil || root.Fd() == 0 {
|
|
||||||
return nil, errors.New("missing root directory")
|
|
||||||
}
|
|
||||||
|
|
||||||
pathUnicode, err := winapi.NewUnicodeString(cleanRelativePath)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
oa.Length = unsafe.Sizeof(oa)
|
|
||||||
oa.ObjectName = pathUnicode
|
|
||||||
oa.RootDirectory = uintptr(root.Fd())
|
|
||||||
oa.Attributes = winapi.OBJ_DONT_REPARSE
|
|
||||||
status := winapi.NtCreateFile(
|
|
||||||
&h,
|
|
||||||
accessMask|syscall.SYNCHRONIZE,
|
|
||||||
&oa,
|
|
||||||
&iosb,
|
|
||||||
nil,
|
|
||||||
0,
|
|
||||||
shareFlags,
|
|
||||||
createDisposition,
|
|
||||||
winapi.FILE_OPEN_FOR_BACKUP_INTENT|winapi.FILE_SYNCHRONOUS_IO_NONALERT|flags,
|
|
||||||
nil,
|
|
||||||
0,
|
|
||||||
)
|
|
||||||
if status != 0 {
|
|
||||||
return nil, winapi.RtlNtStatusToDosError(status)
|
|
||||||
}
|
|
||||||
|
|
||||||
fullPath, err := longpath.LongAbs(filepath.Join(root.Name(), path))
|
|
||||||
if err != nil {
|
|
||||||
syscall.Close(syscall.Handle(h))
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
return os.NewFile(h, fullPath), nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// OpenRelative opens a relative path from the given root, failing if
|
|
||||||
// any of the intermediate path components are reparse points.
|
|
||||||
func OpenRelative(path string, root *os.File, accessMask uint32, shareFlags uint32, createDisposition uint32, flags uint32) (*os.File, error) {
|
|
||||||
f, err := openRelativeInternal(path, root, accessMask, shareFlags, createDisposition, flags)
|
|
||||||
if err != nil {
|
|
||||||
err = &os.PathError{Op: "open", Path: filepath.Join(root.Name(), path), Err: err}
|
|
||||||
}
|
|
||||||
return f, err
|
|
||||||
}
|
|
||||||
|
|
||||||
// LinkRelative creates a hard link from oldname to newname (relative to oldroot
|
|
||||||
// and newroot), failing if any of the intermediate path components are reparse
|
|
||||||
// points.
|
|
||||||
func LinkRelative(oldname string, oldroot *os.File, newname string, newroot *os.File) error {
|
|
||||||
// Open the old file.
|
|
||||||
oldf, err := openRelativeInternal(
|
|
||||||
oldname,
|
|
||||||
oldroot,
|
|
||||||
syscall.FILE_WRITE_ATTRIBUTES,
|
|
||||||
syscall.FILE_SHARE_READ|syscall.FILE_SHARE_WRITE|syscall.FILE_SHARE_DELETE,
|
|
||||||
winapi.FILE_OPEN,
|
|
||||||
0,
|
|
||||||
)
|
|
||||||
if err != nil {
|
|
||||||
return &os.LinkError{Op: "link", Old: filepath.Join(oldroot.Name(), oldname), New: filepath.Join(newroot.Name(), newname), Err: err}
|
|
||||||
}
|
|
||||||
defer oldf.Close()
|
|
||||||
|
|
||||||
// Open the parent of the new file.
|
|
||||||
var parent *os.File
|
|
||||||
parentPath := filepath.Dir(newname)
|
|
||||||
if parentPath != "." {
|
|
||||||
parent, err = openRelativeInternal(
|
|
||||||
parentPath,
|
|
||||||
newroot,
|
|
||||||
syscall.GENERIC_READ,
|
|
||||||
syscall.FILE_SHARE_READ|syscall.FILE_SHARE_WRITE|syscall.FILE_SHARE_DELETE,
|
|
||||||
winapi.FILE_OPEN,
|
|
||||||
winapi.FILE_DIRECTORY_FILE)
|
|
||||||
if err != nil {
|
|
||||||
return &os.LinkError{Op: "link", Old: oldf.Name(), New: filepath.Join(newroot.Name(), newname), Err: err}
|
|
||||||
}
|
|
||||||
defer parent.Close()
|
|
||||||
|
|
||||||
fi, err := winio.GetFileBasicInfo(parent)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
if (fi.FileAttributes & syscall.FILE_ATTRIBUTE_REPARSE_POINT) != 0 {
|
|
||||||
return &os.LinkError{Op: "link", Old: oldf.Name(), New: filepath.Join(newroot.Name(), newname), Err: winapi.RtlNtStatusToDosError(winapi.STATUS_REPARSE_POINT_ENCOUNTERED)}
|
|
||||||
}
|
|
||||||
|
|
||||||
} else {
|
|
||||||
parent = newroot
|
|
||||||
}
|
|
||||||
|
|
||||||
// Issue an NT call to create the link. This will be safe because NT will
|
|
||||||
// not open any more directories to create the link, so it cannot walk any
|
|
||||||
// more reparse points.
|
|
||||||
newbase := filepath.Base(newname)
|
|
||||||
newbase16, err := ntRelativePath(newbase)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
size := int(unsafe.Offsetof(winapi.FileLinkInformation{}.FileName)) + len(newbase16)*2
|
|
||||||
linkinfoBuffer := winapi.LocalAlloc(0, size)
|
|
||||||
defer winapi.LocalFree(linkinfoBuffer)
|
|
||||||
|
|
||||||
linkinfo := (*winapi.FileLinkInformation)(unsafe.Pointer(linkinfoBuffer))
|
|
||||||
linkinfo.RootDirectory = parent.Fd()
|
|
||||||
linkinfo.FileNameLength = uint32(len(newbase16) * 2)
|
|
||||||
copy(winapi.Uint16BufferToSlice(&linkinfo.FileName[0], len(newbase16)), newbase16)
|
|
||||||
|
|
||||||
var iosb winapi.IOStatusBlock
|
|
||||||
status := winapi.NtSetInformationFile(
|
|
||||||
oldf.Fd(),
|
|
||||||
&iosb,
|
|
||||||
linkinfoBuffer,
|
|
||||||
uint32(size),
|
|
||||||
winapi.FileLinkInformationClass,
|
|
||||||
)
|
|
||||||
if status != 0 {
|
|
||||||
return &os.LinkError{Op: "link", Old: oldf.Name(), New: filepath.Join(parent.Name(), newbase), Err: winapi.RtlNtStatusToDosError(status)}
|
|
||||||
}
|
|
||||||
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// deleteOnClose marks a file to be deleted when the handle is closed.
|
|
||||||
func deleteOnClose(f *os.File) error {
|
|
||||||
disposition := winapi.FileDispositionInformationEx{Flags: winapi.FILE_DISPOSITION_DELETE}
|
|
||||||
var iosb winapi.IOStatusBlock
|
|
||||||
status := winapi.NtSetInformationFile(
|
|
||||||
f.Fd(),
|
|
||||||
&iosb,
|
|
||||||
uintptr(unsafe.Pointer(&disposition)),
|
|
||||||
uint32(unsafe.Sizeof(disposition)),
|
|
||||||
winapi.FileDispositionInformationExClass,
|
|
||||||
)
|
|
||||||
if status != 0 {
|
|
||||||
return winapi.RtlNtStatusToDosError(status)
|
|
||||||
}
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// clearReadOnly clears the readonly attribute on a file.
|
|
||||||
func clearReadOnly(f *os.File) error {
|
|
||||||
bi, err := winio.GetFileBasicInfo(f)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
if bi.FileAttributes&syscall.FILE_ATTRIBUTE_READONLY == 0 {
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
sbi := winio.FileBasicInfo{
|
|
||||||
FileAttributes: bi.FileAttributes &^ syscall.FILE_ATTRIBUTE_READONLY,
|
|
||||||
}
|
|
||||||
if sbi.FileAttributes == 0 {
|
|
||||||
sbi.FileAttributes = syscall.FILE_ATTRIBUTE_NORMAL
|
|
||||||
}
|
|
||||||
return winio.SetFileBasicInfo(f, &sbi)
|
|
||||||
}
|
|
||||||
|
|
||||||
// RemoveRelative removes a file or directory relative to a root, failing if any
|
|
||||||
// intermediate path components are reparse points.
|
|
||||||
func RemoveRelative(path string, root *os.File) error {
|
|
||||||
f, err := openRelativeInternal(
|
|
||||||
path,
|
|
||||||
root,
|
|
||||||
winapi.FILE_READ_ATTRIBUTES|winapi.FILE_WRITE_ATTRIBUTES|winapi.DELETE,
|
|
||||||
syscall.FILE_SHARE_READ|syscall.FILE_SHARE_WRITE|syscall.FILE_SHARE_DELETE,
|
|
||||||
winapi.FILE_OPEN,
|
|
||||||
winapi.FILE_OPEN_REPARSE_POINT)
|
|
||||||
if err == nil {
|
|
||||||
defer f.Close()
|
|
||||||
err = deleteOnClose(f)
|
|
||||||
if err == syscall.ERROR_ACCESS_DENIED {
|
|
||||||
// Maybe the file is marked readonly. Clear the bit and retry.
|
|
||||||
_ = clearReadOnly(f)
|
|
||||||
err = deleteOnClose(f)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if err != nil {
|
|
||||||
return &os.PathError{Op: "remove", Path: filepath.Join(root.Name(), path), Err: err}
|
|
||||||
}
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// RemoveAllRelative removes a directory tree relative to a root, failing if any
|
|
||||||
// intermediate path components are reparse points.
|
|
||||||
func RemoveAllRelative(path string, root *os.File) error {
|
|
||||||
fi, err := LstatRelative(path, root)
|
|
||||||
if err != nil {
|
|
||||||
if os.IsNotExist(err) {
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
fileAttributes := fi.Sys().(*syscall.Win32FileAttributeData).FileAttributes
|
|
||||||
if fileAttributes&syscall.FILE_ATTRIBUTE_DIRECTORY == 0 || fileAttributes&syscall.FILE_ATTRIBUTE_REPARSE_POINT != 0 {
|
|
||||||
// If this is a reparse point, it can't have children. Simple remove will do.
|
|
||||||
err := RemoveRelative(path, root)
|
|
||||||
if err == nil || os.IsNotExist(err) {
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
// It is necessary to use os.Open as Readdirnames does not work with
|
|
||||||
// OpenRelative. This is safe because the above lstatrelative fails
|
|
||||||
// if the target is outside the root, and we know this is not a
|
|
||||||
// symlink from the above FILE_ATTRIBUTE_REPARSE_POINT check.
|
|
||||||
fd, err := os.Open(filepath.Join(root.Name(), path))
|
|
||||||
if err != nil {
|
|
||||||
if os.IsNotExist(err) {
|
|
||||||
// Race. It was deleted between the Lstat and Open.
|
|
||||||
// Return nil per RemoveAll's docs.
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
// Remove contents & return first error.
|
|
||||||
for {
|
|
||||||
names, err1 := fd.Readdirnames(100)
|
|
||||||
for _, name := range names {
|
|
||||||
err1 := RemoveAllRelative(path+string(os.PathSeparator)+name, root)
|
|
||||||
if err == nil {
|
|
||||||
err = err1
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if err1 == io.EOF {
|
|
||||||
break
|
|
||||||
}
|
|
||||||
// If Readdirnames returned an error, use it.
|
|
||||||
if err == nil {
|
|
||||||
err = err1
|
|
||||||
}
|
|
||||||
if len(names) == 0 {
|
|
||||||
break
|
|
||||||
}
|
|
||||||
}
|
|
||||||
fd.Close()
|
|
||||||
|
|
||||||
// Remove directory.
|
|
||||||
err1 := RemoveRelative(path, root)
|
|
||||||
if err1 == nil || os.IsNotExist(err1) {
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
if err == nil {
|
|
||||||
err = err1
|
|
||||||
}
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
// MkdirRelative creates a directory relative to a root, failing if any
|
|
||||||
// intermediate path components are reparse points.
|
|
||||||
func MkdirRelative(path string, root *os.File) error {
|
|
||||||
f, err := openRelativeInternal(
|
|
||||||
path,
|
|
||||||
root,
|
|
||||||
0,
|
|
||||||
syscall.FILE_SHARE_READ|syscall.FILE_SHARE_WRITE|syscall.FILE_SHARE_DELETE,
|
|
||||||
winapi.FILE_CREATE,
|
|
||||||
winapi.FILE_DIRECTORY_FILE)
|
|
||||||
if err == nil {
|
|
||||||
f.Close()
|
|
||||||
} else {
|
|
||||||
err = &os.PathError{Op: "mkdir", Path: filepath.Join(root.Name(), path), Err: err}
|
|
||||||
}
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
// LstatRelative performs a stat operation on a file relative to a root, failing
|
|
||||||
// if any intermediate path components are reparse points.
|
|
||||||
func LstatRelative(path string, root *os.File) (os.FileInfo, error) {
|
|
||||||
f, err := openRelativeInternal(
|
|
||||||
path,
|
|
||||||
root,
|
|
||||||
winapi.FILE_READ_ATTRIBUTES,
|
|
||||||
syscall.FILE_SHARE_READ|syscall.FILE_SHARE_WRITE|syscall.FILE_SHARE_DELETE,
|
|
||||||
winapi.FILE_OPEN,
|
|
||||||
winapi.FILE_OPEN_REPARSE_POINT)
|
|
||||||
if err != nil {
|
|
||||||
return nil, &os.PathError{Op: "stat", Path: filepath.Join(root.Name(), path), Err: err}
|
|
||||||
}
|
|
||||||
defer f.Close()
|
|
||||||
return f.Stat()
|
|
||||||
}
|
|
||||||
|
|
||||||
// EnsureNotReparsePointRelative validates that a given file (relative to a
|
|
||||||
// root) and all intermediate path components are not a reparse points.
|
|
||||||
func EnsureNotReparsePointRelative(path string, root *os.File) error {
|
|
||||||
// Perform an open with OBJ_DONT_REPARSE but without specifying FILE_OPEN_REPARSE_POINT.
|
|
||||||
f, err := OpenRelative(
|
|
||||||
path,
|
|
||||||
root,
|
|
||||||
0,
|
|
||||||
syscall.FILE_SHARE_READ|syscall.FILE_SHARE_WRITE|syscall.FILE_SHARE_DELETE,
|
|
||||||
winapi.FILE_OPEN,
|
|
||||||
0)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
f.Close()
|
|
||||||
return nil
|
|
||||||
}
|
|
|
@ -1,250 +0,0 @@
|
||||||
package schema1
|
|
||||||
|
|
||||||
import (
|
|
||||||
"encoding/json"
|
|
||||||
"time"
|
|
||||||
|
|
||||||
"github.com/Microsoft/go-winio/pkg/guid"
|
|
||||||
hcsschema "github.com/Microsoft/hcsshim/internal/schema2"
|
|
||||||
)
|
|
||||||
|
|
||||||
// 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" // V1 and V2
|
|
||||||
PropertyTypeProcessList PropertyType = "ProcessList" // V1 and V2
|
|
||||||
PropertyTypeMappedVirtualDisk PropertyType = "MappedVirtualDisk" // Not supported in V2 schema call
|
|
||||||
PropertyTypeGuestConnection PropertyType = "GuestConnection" // V1 and V2. Nil return from HCS before RS5
|
|
||||||
)
|
|
||||||
|
|
||||||
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
|
|
||||||
RuntimeOSType string `json:"RuntimeOsType,omitempty"`
|
|
||||||
Owner string
|
|
||||||
SiloGUID string `json:"SiloGuid,omitempty"`
|
|
||||||
RuntimeID guid.GUID `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"`
|
|
||||||
GuestConnectionInfo GuestConnectionInfo `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"`
|
|
||||||
}
|
|
||||||
|
|
||||||
// GuestDefinedCapabilities is part of the GuestConnectionInfo returned by a GuestConnection call on a utility VM
|
|
||||||
type GuestDefinedCapabilities struct {
|
|
||||||
NamespaceAddRequestSupported bool `json:",omitempty"`
|
|
||||||
SignalProcessSupported bool `json:",omitempty"`
|
|
||||||
DumpStacksSupported bool `json:",omitempty"`
|
|
||||||
DeleteContainerStateSupported bool `json:",omitempty"`
|
|
||||||
UpdateContainerSupported bool `json:",omitempty"`
|
|
||||||
}
|
|
||||||
|
|
||||||
// GuestConnectionInfo is the structure of an iterm return by a GuestConnection call on a utility VM
|
|
||||||
type GuestConnectionInfo struct {
|
|
||||||
SupportedSchemaVersions []hcsschema.Version `json:",omitempty"`
|
|
||||||
ProtocolVersion uint32 `json:",omitempty"`
|
|
||||||
GuestDefinedCapabilities GuestDefinedCapabilities `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"`
|
|
||||||
}
|
|
|
@ -1,30 +0,0 @@
|
||||||
/*
|
|
||||||
* HCS API
|
|
||||||
*
|
|
||||||
* No description provided (generated by Swagger Codegen https://github.com/swagger-api/swagger-codegen)
|
|
||||||
*
|
|
||||||
* API version: 2.1
|
|
||||||
* Generated by: Swagger Codegen (https://github.com/swagger-api/swagger-codegen.git)
|
|
||||||
*/
|
|
||||||
|
|
||||||
package hcsschema
|
|
||||||
|
|
||||||
type Attachment struct {
|
|
||||||
Type_ string `json:"Type,omitempty"`
|
|
||||||
|
|
||||||
Path string `json:"Path,omitempty"`
|
|
||||||
|
|
||||||
IgnoreFlushes bool `json:"IgnoreFlushes,omitempty"`
|
|
||||||
|
|
||||||
CachingMode string `json:"CachingMode,omitempty"`
|
|
||||||
|
|
||||||
NoWriteHardening bool `json:"NoWriteHardening,omitempty"`
|
|
||||||
|
|
||||||
DisableExpansionOptimization bool `json:"DisableExpansionOptimization,omitempty"`
|
|
||||||
|
|
||||||
IgnoreRelativeLocator bool `json:"IgnoreRelativeLocator,omitempty"`
|
|
||||||
|
|
||||||
CaptureIoAttributionContext bool `json:"CaptureIoAttributionContext,omitempty"`
|
|
||||||
|
|
||||||
ReadOnly bool `json:"ReadOnly,omitempty"`
|
|
||||||
}
|
|
|
@ -1,13 +0,0 @@
|
||||||
/*
|
|
||||||
* HCS API
|
|
||||||
*
|
|
||||||
* No description provided (generated by Swagger Codegen https://github.com/swagger-api/swagger-codegen)
|
|
||||||
*
|
|
||||||
* API version: 2.1
|
|
||||||
* Generated by: Swagger Codegen (https://github.com/swagger-api/swagger-codegen.git)
|
|
||||||
*/
|
|
||||||
|
|
||||||
package hcsschema
|
|
||||||
|
|
||||||
type Battery struct {
|
|
||||||
}
|
|
18
vendor/github.com/Microsoft/hcsshim/internal/schema2/cache_query_stats_response.go
generated
vendored
18
vendor/github.com/Microsoft/hcsshim/internal/schema2/cache_query_stats_response.go
generated
vendored
|
@ -1,18 +0,0 @@
|
||||||
/*
|
|
||||||
* HCS API
|
|
||||||
*
|
|
||||||
* No description provided (generated by Swagger Codegen https://github.com/swagger-api/swagger-codegen)
|
|
||||||
*
|
|
||||||
* API version: 2.1
|
|
||||||
* Generated by: Swagger Codegen (https://github.com/swagger-api/swagger-codegen.git)
|
|
||||||
*/
|
|
||||||
|
|
||||||
package hcsschema
|
|
||||||
|
|
||||||
type CacheQueryStatsResponse struct {
|
|
||||||
L3OccupancyBytes int32 `json:"L3OccupancyBytes,omitempty"`
|
|
||||||
|
|
||||||
L3TotalBwBytes int32 `json:"L3TotalBwBytes,omitempty"`
|
|
||||||
|
|
||||||
L3LocalBwBytes int32 `json:"L3LocalBwBytes,omitempty"`
|
|
||||||
}
|
|
|
@ -1,27 +0,0 @@
|
||||||
/*
|
|
||||||
* HCS API
|
|
||||||
*
|
|
||||||
* No description provided (generated by Swagger Codegen https://github.com/swagger-api/swagger-codegen)
|
|
||||||
*
|
|
||||||
* API version: 2.1
|
|
||||||
* Generated by: Swagger Codegen (https://github.com/swagger-api/swagger-codegen.git)
|
|
||||||
*/
|
|
||||||
|
|
||||||
package hcsschema
|
|
||||||
|
|
||||||
type Chipset struct {
|
|
||||||
Uefi *Uefi `json:"Uefi,omitempty"`
|
|
||||||
|
|
||||||
IsNumLockDisabled bool `json:"IsNumLockDisabled,omitempty"`
|
|
||||||
|
|
||||||
BaseBoardSerialNumber string `json:"BaseBoardSerialNumber,omitempty"`
|
|
||||||
|
|
||||||
ChassisSerialNumber string `json:"ChassisSerialNumber,omitempty"`
|
|
||||||
|
|
||||||
ChassisAssetTag string `json:"ChassisAssetTag,omitempty"`
|
|
||||||
|
|
||||||
UseUtc bool `json:"UseUtc,omitempty"`
|
|
||||||
|
|
||||||
// LinuxKernelDirect - Added in v2.2 Builds >=181117
|
|
||||||
LinuxKernelDirect *LinuxKernelDirect `json:"LinuxKernelDirect,omitempty"`
|
|
||||||
}
|
|
|
@ -1,14 +0,0 @@
|
||||||
/*
|
|
||||||
* HCS API
|
|
||||||
*
|
|
||||||
* No description provided (generated by Swagger Codegen https://github.com/swagger-api/swagger-codegen)
|
|
||||||
*
|
|
||||||
* API version: 2.1
|
|
||||||
* Generated by: Swagger Codegen (https://github.com/swagger-api/swagger-codegen.git)
|
|
||||||
*/
|
|
||||||
|
|
||||||
package hcsschema
|
|
||||||
|
|
||||||
type CloseHandle struct {
|
|
||||||
Handle string `json:"Handle,omitempty"`
|
|
||||||
}
|
|
|
@ -1,17 +0,0 @@
|
||||||
/*
|
|
||||||
* HCS API
|
|
||||||
*
|
|
||||||
* No description provided (generated by Swagger Codegen https://github.com/swagger-api/swagger-codegen)
|
|
||||||
*
|
|
||||||
* API version: 2.1
|
|
||||||
* Generated by: Swagger Codegen (https://github.com/swagger-api/swagger-codegen.git)
|
|
||||||
*/
|
|
||||||
|
|
||||||
package hcsschema
|
|
||||||
|
|
||||||
// ComPort specifies the named pipe that will be used for the port, with empty string indicating a disconnected port.
|
|
||||||
type ComPort struct {
|
|
||||||
NamedPipe string `json:"NamedPipe,omitempty"`
|
|
||||||
|
|
||||||
OptimizeForDebugger bool `json:"OptimizeForDebugger,omitempty"`
|
|
||||||
}
|
|
|
@ -1,26 +0,0 @@
|
||||||
/*
|
|
||||||
* HCS API
|
|
||||||
*
|
|
||||||
* No description provided (generated by Swagger Codegen https://github.com/swagger-api/swagger-codegen)
|
|
||||||
*
|
|
||||||
* API version: 2.1
|
|
||||||
* Generated by: Swagger Codegen (https://github.com/swagger-api/swagger-codegen.git)
|
|
||||||
*/
|
|
||||||
|
|
||||||
package hcsschema
|
|
||||||
|
|
||||||
type ComputeSystem struct {
|
|
||||||
Owner string `json:"Owner,omitempty"`
|
|
||||||
|
|
||||||
SchemaVersion *Version `json:"SchemaVersion,omitempty"`
|
|
||||||
|
|
||||||
HostingSystemId string `json:"HostingSystemId,omitempty"`
|
|
||||||
|
|
||||||
HostedSystem interface{} `json:"HostedSystem,omitempty"`
|
|
||||||
|
|
||||||
Container *Container `json:"Container,omitempty"`
|
|
||||||
|
|
||||||
VirtualMachine *VirtualMachine `json:"VirtualMachine,omitempty"`
|
|
||||||
|
|
||||||
ShouldTerminateOnLastHandleClosed bool `json:"ShouldTerminateOnLastHandleClosed,omitempty"`
|
|
||||||
}
|
|
|
@ -1,72 +0,0 @@
|
||||||
/*
|
|
||||||
* HCS API
|
|
||||||
*
|
|
||||||
* No description provided (generated by Swagger Codegen https://github.com/swagger-api/swagger-codegen)
|
|
||||||
*
|
|
||||||
* API version: 2.1
|
|
||||||
* Generated by: Swagger Codegen (https://github.com/swagger-api/swagger-codegen.git)
|
|
||||||
*/
|
|
||||||
|
|
||||||
package hcsschema
|
|
||||||
|
|
||||||
import (
|
|
||||||
"net/http"
|
|
||||||
)
|
|
||||||
|
|
||||||
// contextKeys are used to identify the type of value in the context.
|
|
||||||
// Since these are string, it is possible to get a short description of the
|
|
||||||
// context key for logging and debugging using key.String().
|
|
||||||
|
|
||||||
type contextKey string
|
|
||||||
|
|
||||||
func (c contextKey) String() string {
|
|
||||||
return "auth " + string(c)
|
|
||||||
}
|
|
||||||
|
|
||||||
var (
|
|
||||||
// ContextOAuth2 takes a oauth2.TokenSource as authentication for the request.
|
|
||||||
ContextOAuth2 = contextKey("token")
|
|
||||||
|
|
||||||
// ContextBasicAuth takes BasicAuth as authentication for the request.
|
|
||||||
ContextBasicAuth = contextKey("basic")
|
|
||||||
|
|
||||||
// ContextAccessToken takes a string oauth2 access token as authentication for the request.
|
|
||||||
ContextAccessToken = contextKey("accesstoken")
|
|
||||||
|
|
||||||
// ContextAPIKey takes an APIKey as authentication for the request
|
|
||||||
ContextAPIKey = contextKey("apikey")
|
|
||||||
)
|
|
||||||
|
|
||||||
// BasicAuth provides basic http authentication to a request passed via context using ContextBasicAuth
|
|
||||||
type BasicAuth struct {
|
|
||||||
UserName string `json:"userName,omitempty"`
|
|
||||||
Password string `json:"password,omitempty"`
|
|
||||||
}
|
|
||||||
|
|
||||||
// APIKey provides API key based authentication to a request passed via context using ContextAPIKey
|
|
||||||
type APIKey struct {
|
|
||||||
Key string
|
|
||||||
Prefix string
|
|
||||||
}
|
|
||||||
|
|
||||||
type Configuration struct {
|
|
||||||
BasePath string `json:"basePath,omitempty"`
|
|
||||||
Host string `json:"host,omitempty"`
|
|
||||||
Scheme string `json:"scheme,omitempty"`
|
|
||||||
DefaultHeader map[string]string `json:"defaultHeader,omitempty"`
|
|
||||||
UserAgent string `json:"userAgent,omitempty"`
|
|
||||||
HTTPClient *http.Client
|
|
||||||
}
|
|
||||||
|
|
||||||
func NewConfiguration() *Configuration {
|
|
||||||
cfg := &Configuration{
|
|
||||||
BasePath: "https://localhost",
|
|
||||||
DefaultHeader: make(map[string]string),
|
|
||||||
UserAgent: "Swagger-Codegen/2.1.0/go",
|
|
||||||
}
|
|
||||||
return cfg
|
|
||||||
}
|
|
||||||
|
|
||||||
func (c *Configuration) AddDefaultHeader(key string, value string) {
|
|
||||||
c.DefaultHeader[key] = value
|
|
||||||
}
|
|
|
@ -1,16 +0,0 @@
|
||||||
/*
|
|
||||||
* HCS API
|
|
||||||
*
|
|
||||||
* No description provided (generated by Swagger Codegen https://github.com/swagger-api/swagger-codegen)
|
|
||||||
*
|
|
||||||
* API version: 2.1
|
|
||||||
* Generated by: Swagger Codegen (https://github.com/swagger-api/swagger-codegen.git)
|
|
||||||
*/
|
|
||||||
|
|
||||||
package hcsschema
|
|
||||||
|
|
||||||
type ConsoleSize struct {
|
|
||||||
Height int32 `json:"Height,omitempty"`
|
|
||||||
|
|
||||||
Width int32 `json:"Width,omitempty"`
|
|
||||||
}
|
|
|
@ -1,34 +0,0 @@
|
||||||
/*
|
|
||||||
* HCS API
|
|
||||||
*
|
|
||||||
* No description provided (generated by Swagger Codegen https://github.com/swagger-api/swagger-codegen)
|
|
||||||
*
|
|
||||||
* API version: 2.1
|
|
||||||
* Generated by: Swagger Codegen (https://github.com/swagger-api/swagger-codegen.git)
|
|
||||||
*/
|
|
||||||
|
|
||||||
package hcsschema
|
|
||||||
|
|
||||||
type Container struct {
|
|
||||||
GuestOs *GuestOs `json:"GuestOs,omitempty"`
|
|
||||||
|
|
||||||
Storage *Storage `json:"Storage,omitempty"`
|
|
||||||
|
|
||||||
MappedDirectories []MappedDirectory `json:"MappedDirectories,omitempty"`
|
|
||||||
|
|
||||||
MappedPipes []MappedPipe `json:"MappedPipes,omitempty"`
|
|
||||||
|
|
||||||
Memory *Memory `json:"Memory,omitempty"`
|
|
||||||
|
|
||||||
Processor *Processor `json:"Processor,omitempty"`
|
|
||||||
|
|
||||||
Networking *Networking `json:"Networking,omitempty"`
|
|
||||||
|
|
||||||
HvSocket *HvSocket `json:"HvSocket,omitempty"`
|
|
||||||
|
|
||||||
ContainerCredentialGuard *ContainerCredentialGuardState `json:"ContainerCredentialGuard,omitempty"`
|
|
||||||
|
|
||||||
RegistryChanges *RegistryChanges `json:"RegistryChanges,omitempty"`
|
|
||||||
|
|
||||||
AssignedDevices []Device `json:"AssignedDevices,omitempty"`
|
|
||||||
}
|
|
|
@ -1,16 +0,0 @@
|
||||||
/*
|
|
||||||
* HCS API
|
|
||||||
*
|
|
||||||
* No description provided (generated by Swagger Codegen https://github.com/swagger-api/swagger-codegen)
|
|
||||||
*
|
|
||||||
* API version: 2.4
|
|
||||||
* Generated by: Swagger Codegen (https://github.com/swagger-api/swagger-codegen.git)
|
|
||||||
*/
|
|
||||||
|
|
||||||
package hcsschema
|
|
||||||
|
|
||||||
type ContainerCredentialGuardAddInstanceRequest struct {
|
|
||||||
Id string `json:"Id,omitempty"`
|
|
||||||
CredentialSpec string `json:"CredentialSpec,omitempty"`
|
|
||||||
Transport string `json:"Transport,omitempty"`
|
|
||||||
}
|
|
|
@ -1,15 +0,0 @@
|
||||||
/*
|
|
||||||
* HCS API
|
|
||||||
*
|
|
||||||
* No description provided (generated by Swagger Codegen https://github.com/swagger-api/swagger-codegen)
|
|
||||||
*
|
|
||||||
* API version: 2.4
|
|
||||||
* Generated by: Swagger Codegen (https://github.com/swagger-api/swagger-codegen.git)
|
|
||||||
*/
|
|
||||||
|
|
||||||
package hcsschema
|
|
||||||
|
|
||||||
type ContainerCredentialGuardHvSocketServiceConfig struct {
|
|
||||||
ServiceId string `json:"ServiceId,omitempty"`
|
|
||||||
ServiceConfig *HvSocketServiceConfig `json:"ServiceConfig,omitempty"`
|
|
||||||
}
|
|
|
@ -1,16 +0,0 @@
|
||||||
/*
|
|
||||||
* HCS API
|
|
||||||
*
|
|
||||||
* No description provided (generated by Swagger Codegen https://github.com/swagger-api/swagger-codegen)
|
|
||||||
*
|
|
||||||
* API version: 2.4
|
|
||||||
* Generated by: Swagger Codegen (https://github.com/swagger-api/swagger-codegen.git)
|
|
||||||
*/
|
|
||||||
|
|
||||||
package hcsschema
|
|
||||||
|
|
||||||
type ContainerCredentialGuardInstance struct {
|
|
||||||
Id string `json:"Id,omitempty"`
|
|
||||||
CredentialGuard *ContainerCredentialGuardState `json:"CredentialGuard,omitempty"`
|
|
||||||
HvSocketConfig *ContainerCredentialGuardHvSocketServiceConfig `json:"HvSocketConfig,omitempty"`
|
|
||||||
}
|
|
|
@ -1,17 +0,0 @@
|
||||||
/*
|
|
||||||
* HCS API
|
|
||||||
*
|
|
||||||
* No description provided (generated by Swagger Codegen https://github.com/swagger-api/swagger-codegen)
|
|
||||||
*
|
|
||||||
* API version: 2.4
|
|
||||||
* Generated by: Swagger Codegen (https://github.com/swagger-api/swagger-codegen.git)
|
|
||||||
*/
|
|
||||||
|
|
||||||
package hcsschema
|
|
||||||
|
|
||||||
type ContainerCredentialGuardModifyOperation string
|
|
||||||
|
|
||||||
const (
|
|
||||||
AddInstance ContainerCredentialGuardModifyOperation = "AddInstance"
|
|
||||||
RemoveInstance ContainerCredentialGuardModifyOperation = "RemoveInstance"
|
|
||||||
)
|
|
|
@ -1,15 +0,0 @@
|
||||||
/*
|
|
||||||
* HCS API
|
|
||||||
*
|
|
||||||
* No description provided (generated by Swagger Codegen https://github.com/swagger-api/swagger-codegen)
|
|
||||||
*
|
|
||||||
* API version: 2.4
|
|
||||||
* Generated by: Swagger Codegen (https://github.com/swagger-api/swagger-codegen.git)
|
|
||||||
*/
|
|
||||||
|
|
||||||
package hcsschema
|
|
||||||
|
|
||||||
type ContainerCredentialGuardOperationRequest struct {
|
|
||||||
Operation ContainerCredentialGuardModifyOperation `json:"Operation,omitempty"`
|
|
||||||
OperationDetails interface{} `json:"OperationDetails,omitempty"`
|
|
||||||
}
|
|
|
@ -1,14 +0,0 @@
|
||||||
/*
|
|
||||||
* HCS API
|
|
||||||
*
|
|
||||||
* No description provided (generated by Swagger Codegen https://github.com/swagger-api/swagger-codegen)
|
|
||||||
*
|
|
||||||
* API version: 2.4
|
|
||||||
* Generated by: Swagger Codegen (https://github.com/swagger-api/swagger-codegen.git)
|
|
||||||
*/
|
|
||||||
|
|
||||||
package hcsschema
|
|
||||||
|
|
||||||
type ContainerCredentialGuardRemoveInstanceRequest struct {
|
|
||||||
Id string `json:"Id,omitempty"`
|
|
||||||
}
|
|
25
vendor/github.com/Microsoft/hcsshim/internal/schema2/container_credential_guard_state.go
generated
vendored
25
vendor/github.com/Microsoft/hcsshim/internal/schema2/container_credential_guard_state.go
generated
vendored
|
@ -1,25 +0,0 @@
|
||||||
/*
|
|
||||||
* HCS API
|
|
||||||
*
|
|
||||||
* No description provided (generated by Swagger Codegen https://github.com/swagger-api/swagger-codegen)
|
|
||||||
*
|
|
||||||
* API version: 2.1
|
|
||||||
* Generated by: Swagger Codegen (https://github.com/swagger-api/swagger-codegen.git)
|
|
||||||
*/
|
|
||||||
|
|
||||||
package hcsschema
|
|
||||||
|
|
||||||
type ContainerCredentialGuardState struct {
|
|
||||||
|
|
||||||
// Authentication cookie for calls to a Container Credential Guard instance.
|
|
||||||
Cookie string `json:"Cookie,omitempty"`
|
|
||||||
|
|
||||||
// Name of the RPC endpoint of the Container Credential Guard instance.
|
|
||||||
RpcEndpoint string `json:"RpcEndpoint,omitempty"`
|
|
||||||
|
|
||||||
// Transport used for the configured Container Credential Guard instance.
|
|
||||||
Transport string `json:"Transport,omitempty"`
|
|
||||||
|
|
||||||
// Credential spec used for the configured Container Credential Guard instance.
|
|
||||||
CredentialSpec string `json:"CredentialSpec,omitempty"`
|
|
||||||
}
|
|
|
@ -1,14 +0,0 @@
|
||||||
/*
|
|
||||||
* HCS API
|
|
||||||
*
|
|
||||||
* No description provided (generated by Swagger Codegen https://github.com/swagger-api/swagger-codegen)
|
|
||||||
*
|
|
||||||
* API version: 2.4
|
|
||||||
* Generated by: Swagger Codegen (https://github.com/swagger-api/swagger-codegen.git)
|
|
||||||
*/
|
|
||||||
|
|
||||||
package hcsschema
|
|
||||||
|
|
||||||
type ContainerCredentialGuardSystemInfo struct {
|
|
||||||
Instances []ContainerCredentialGuardInstance `json:"Instances,omitempty"`
|
|
||||||
}
|
|
25
vendor/github.com/Microsoft/hcsshim/internal/schema2/container_memory_information.go
generated
vendored
25
vendor/github.com/Microsoft/hcsshim/internal/schema2/container_memory_information.go
generated
vendored
|
@ -1,25 +0,0 @@
|
||||||
/*
|
|
||||||
* HCS API
|
|
||||||
*
|
|
||||||
* No description provided (generated by Swagger Codegen https://github.com/swagger-api/swagger-codegen)
|
|
||||||
*
|
|
||||||
* API version: 2.1
|
|
||||||
* Generated by: Swagger Codegen (https://github.com/swagger-api/swagger-codegen.git)
|
|
||||||
*/
|
|
||||||
|
|
||||||
package hcsschema
|
|
||||||
|
|
||||||
// memory usage as viewed from within the container
|
|
||||||
type ContainerMemoryInformation struct {
|
|
||||||
TotalPhysicalBytes int32 `json:"TotalPhysicalBytes,omitempty"`
|
|
||||||
|
|
||||||
TotalUsage int32 `json:"TotalUsage,omitempty"`
|
|
||||||
|
|
||||||
CommittedBytes int32 `json:"CommittedBytes,omitempty"`
|
|
||||||
|
|
||||||
SharedCommittedBytes int32 `json:"SharedCommittedBytes,omitempty"`
|
|
||||||
|
|
||||||
CommitLimitBytes int32 `json:"CommitLimitBytes,omitempty"`
|
|
||||||
|
|
||||||
PeakCommitmentBytes int32 `json:"PeakCommitmentBytes,omitempty"`
|
|
||||||
}
|
|
|
@ -1,15 +0,0 @@
|
||||||
/*
|
|
||||||
* HCS API
|
|
||||||
*
|
|
||||||
* No description provided (generated by Swagger Codegen https://github.com/swagger-api/swagger-codegen)
|
|
||||||
*
|
|
||||||
* API version: 2.4
|
|
||||||
* Generated by: Swagger Codegen (https://github.com/swagger-api/swagger-codegen.git)
|
|
||||||
*/
|
|
||||||
|
|
||||||
package hcsschema
|
|
||||||
|
|
||||||
// CPU groups allow Hyper-V administrators to better manage and allocate the host's CPU resources across guest virtual machines
|
|
||||||
type CpuGroup struct {
|
|
||||||
Id string `json:"Id,omitempty"`
|
|
||||||
}
|
|
|
@ -1,15 +0,0 @@
|
||||||
/*
|
|
||||||
* HCS API
|
|
||||||
*
|
|
||||||
* No description provided (generated by Swagger Codegen https://github.com/swagger-api/swagger-codegen)
|
|
||||||
*
|
|
||||||
* API version: 2.4
|
|
||||||
* Generated by: Swagger Codegen (https://github.com/swagger-api/swagger-codegen.git)
|
|
||||||
*/
|
|
||||||
|
|
||||||
package hcsschema
|
|
||||||
|
|
||||||
type CpuGroupAffinity struct {
|
|
||||||
LogicalProcessorCount int32 `json:"LogicalProcessorCount,omitempty"`
|
|
||||||
LogicalProcessors []int32 `json:"LogicalProcessors,omitempty"`
|
|
||||||
}
|
|
|
@ -1,18 +0,0 @@
|
||||||
/*
|
|
||||||
* HCS API
|
|
||||||
*
|
|
||||||
* No description provided (generated by Swagger Codegen https://github.com/swagger-api/swagger-codegen)
|
|
||||||
*
|
|
||||||
* API version: 2.4
|
|
||||||
* Generated by: Swagger Codegen (https://github.com/swagger-api/swagger-codegen.git)
|
|
||||||
*/
|
|
||||||
|
|
||||||
package hcsschema
|
|
||||||
|
|
||||||
type CpuGroupConfig struct {
|
|
||||||
GroupId string `json:"GroupId,omitempty"`
|
|
||||||
Affinity *CpuGroupAffinity `json:"Affinity,omitempty"`
|
|
||||||
GroupProperties []CpuGroupProperty `json:"GroupProperties,omitempty"`
|
|
||||||
// Hypervisor CPU group IDs exposed to clients
|
|
||||||
HypervisorGroupId int32 `json:"HypervisorGroupId,omitempty"`
|
|
||||||
}
|
|
15
vendor/github.com/Microsoft/hcsshim/internal/schema2/cpu_group_configurations.go
generated
vendored
15
vendor/github.com/Microsoft/hcsshim/internal/schema2/cpu_group_configurations.go
generated
vendored
|
@ -1,15 +0,0 @@
|
||||||
/*
|
|
||||||
* HCS API
|
|
||||||
*
|
|
||||||
* No description provided (generated by Swagger Codegen https://github.com/swagger-api/swagger-codegen)
|
|
||||||
*
|
|
||||||
* API version: 2.4
|
|
||||||
* Generated by: Swagger Codegen (https://github.com/swagger-api/swagger-codegen.git)
|
|
||||||
*/
|
|
||||||
|
|
||||||
package hcsschema
|
|
||||||
|
|
||||||
// Structure used to return cpu groups for a Service property query
|
|
||||||
type CpuGroupConfigurations struct {
|
|
||||||
CpuGroups []CpuGroupConfig `json:"CpuGroups,omitempty"`
|
|
||||||
}
|
|
|
@ -1,18 +0,0 @@
|
||||||
/*
|
|
||||||
* HCS API
|
|
||||||
*
|
|
||||||
* No description provided (generated by Swagger Codegen https://github.com/swagger-api/swagger-codegen)
|
|
||||||
*
|
|
||||||
* API version: 2.4
|
|
||||||
* Generated by: Swagger Codegen (https://github.com/swagger-api/swagger-codegen.git)
|
|
||||||
*/
|
|
||||||
|
|
||||||
package hcsschema
|
|
||||||
|
|
||||||
type CPUGroupOperation string
|
|
||||||
|
|
||||||
const (
|
|
||||||
CreateGroup CPUGroupOperation = "CreateGroup"
|
|
||||||
DeleteGroup CPUGroupOperation = "DeleteGroup"
|
|
||||||
SetProperty CPUGroupOperation = "SetProperty"
|
|
||||||
)
|
|
|
@ -1,15 +0,0 @@
|
||||||
/*
|
|
||||||
* HCS API
|
|
||||||
*
|
|
||||||
* No description provided (generated by Swagger Codegen https://github.com/swagger-api/swagger-codegen)
|
|
||||||
*
|
|
||||||
* API version: 2.4
|
|
||||||
* Generated by: Swagger Codegen (https://github.com/swagger-api/swagger-codegen.git)
|
|
||||||
*/
|
|
||||||
|
|
||||||
package hcsschema
|
|
||||||
|
|
||||||
type CpuGroupProperty struct {
|
|
||||||
PropertyCode uint32 `json:"PropertyCode,omitempty"`
|
|
||||||
PropertyValue uint32 `json:"PropertyValue,omitempty"`
|
|
||||||
}
|
|
17
vendor/github.com/Microsoft/hcsshim/internal/schema2/create_group_operation.go
generated
vendored
17
vendor/github.com/Microsoft/hcsshim/internal/schema2/create_group_operation.go
generated
vendored
|
@ -1,17 +0,0 @@
|
||||||
/*
|
|
||||||
* HCS API
|
|
||||||
*
|
|
||||||
* No description provided (generated by Swagger Codegen https://github.com/swagger-api/swagger-codegen)
|
|
||||||
*
|
|
||||||
* API version: 2.4
|
|
||||||
* Generated by: Swagger Codegen (https://github.com/swagger-api/swagger-codegen.git)
|
|
||||||
*/
|
|
||||||
|
|
||||||
package hcsschema
|
|
||||||
|
|
||||||
// Create group operation settings
|
|
||||||
type CreateGroupOperation struct {
|
|
||||||
GroupId string `json:"GroupId,omitempty"`
|
|
||||||
LogicalProcessorCount uint32 `json:"LogicalProcessorCount,omitempty"`
|
|
||||||
LogicalProcessors []uint32 `json:"LogicalProcessors,omitempty"`
|
|
||||||
}
|
|
15
vendor/github.com/Microsoft/hcsshim/internal/schema2/delete_group_operation.go
generated
vendored
15
vendor/github.com/Microsoft/hcsshim/internal/schema2/delete_group_operation.go
generated
vendored
|
@ -1,15 +0,0 @@
|
||||||
/*
|
|
||||||
* HCS API
|
|
||||||
*
|
|
||||||
* No description provided (generated by Swagger Codegen https://github.com/swagger-api/swagger-codegen)
|
|
||||||
*
|
|
||||||
* API version: 2.4
|
|
||||||
* Generated by: Swagger Codegen (https://github.com/swagger-api/swagger-codegen.git)
|
|
||||||
*/
|
|
||||||
|
|
||||||
package hcsschema
|
|
||||||
|
|
||||||
// Delete group operation settings
|
|
||||||
type DeleteGroupOperation struct {
|
|
||||||
GroupId string `json:"GroupId,omitempty"`
|
|
||||||
}
|
|
|
@ -1,27 +0,0 @@
|
||||||
/*
|
|
||||||
* HCS API
|
|
||||||
*
|
|
||||||
* No description provided (generated by Swagger Codegen https://github.com/swagger-api/swagger-codegen)
|
|
||||||
*
|
|
||||||
* API version: 2.1
|
|
||||||
* Generated by: Swagger Codegen (https://github.com/swagger-api/swagger-codegen.git)
|
|
||||||
*/
|
|
||||||
|
|
||||||
package hcsschema
|
|
||||||
|
|
||||||
type DeviceType string
|
|
||||||
|
|
||||||
const (
|
|
||||||
ClassGUID DeviceType = "ClassGuid"
|
|
||||||
DeviceInstance DeviceType = "DeviceInstance"
|
|
||||||
GPUMirror DeviceType = "GpuMirror"
|
|
||||||
)
|
|
||||||
|
|
||||||
type Device struct {
|
|
||||||
// The type of device to assign to the container.
|
|
||||||
Type DeviceType `json:"Type,omitempty"`
|
|
||||||
// The interface class guid of the device interfaces to assign to the container. Only used when Type is ClassGuid.
|
|
||||||
InterfaceClassGuid string `json:"InterfaceClassGuid,omitempty"`
|
|
||||||
// The location path of the device to assign to the container. Only used when Type is DeviceInstance.
|
|
||||||
LocationPath string `json:"LocationPath,omitempty"`
|
|
||||||
}
|
|
|
@ -1,46 +0,0 @@
|
||||||
/*
|
|
||||||
* HCS API
|
|
||||||
*
|
|
||||||
* No description provided (generated by Swagger Codegen https://github.com/swagger-api/swagger-codegen)
|
|
||||||
*
|
|
||||||
* API version: 2.1
|
|
||||||
* Generated by: Swagger Codegen (https://github.com/swagger-api/swagger-codegen.git)
|
|
||||||
*/
|
|
||||||
|
|
||||||
package hcsschema
|
|
||||||
|
|
||||||
type Devices struct {
|
|
||||||
ComPorts map[string]ComPort `json:"ComPorts,omitempty"`
|
|
||||||
|
|
||||||
Scsi map[string]Scsi `json:"Scsi,omitempty"`
|
|
||||||
|
|
||||||
VirtualPMem *VirtualPMemController `json:"VirtualPMem,omitempty"`
|
|
||||||
|
|
||||||
NetworkAdapters map[string]NetworkAdapter `json:"NetworkAdapters,omitempty"`
|
|
||||||
|
|
||||||
VideoMonitor *VideoMonitor `json:"VideoMonitor,omitempty"`
|
|
||||||
|
|
||||||
Keyboard *Keyboard `json:"Keyboard,omitempty"`
|
|
||||||
|
|
||||||
Mouse *Mouse `json:"Mouse,omitempty"`
|
|
||||||
|
|
||||||
HvSocket *HvSocket2 `json:"HvSocket,omitempty"`
|
|
||||||
|
|
||||||
EnhancedModeVideo *EnhancedModeVideo `json:"EnhancedModeVideo,omitempty"`
|
|
||||||
|
|
||||||
GuestCrashReporting *GuestCrashReporting `json:"GuestCrashReporting,omitempty"`
|
|
||||||
|
|
||||||
VirtualSmb *VirtualSmb `json:"VirtualSmb,omitempty"`
|
|
||||||
|
|
||||||
Plan9 *Plan9 `json:"Plan9,omitempty"`
|
|
||||||
|
|
||||||
Battery *Battery `json:"Battery,omitempty"`
|
|
||||||
|
|
||||||
FlexibleIov map[string]FlexibleIoDevice `json:"FlexibleIov,omitempty"`
|
|
||||||
|
|
||||||
SharedMemory *SharedMemoryConfiguration `json:"SharedMemory,omitempty"`
|
|
||||||
|
|
||||||
// TODO: This is pre-release support in schema 2.3. Need to add build number
|
|
||||||
// docs when a public build with this is out.
|
|
||||||
VirtualPci map[string]VirtualPciDevice `json:",omitempty"`
|
|
||||||
}
|
|
|
@ -1,14 +0,0 @@
|
||||||
/*
|
|
||||||
* HCS API
|
|
||||||
*
|
|
||||||
* No description provided (generated by Swagger Codegen https://github.com/swagger-api/swagger-codegen)
|
|
||||||
*
|
|
||||||
* API version: 2.1
|
|
||||||
* Generated by: Swagger Codegen (https://github.com/swagger-api/swagger-codegen.git)
|
|
||||||
*/
|
|
||||||
|
|
||||||
package hcsschema
|
|
||||||
|
|
||||||
type EnhancedModeVideo struct {
|
|
||||||
ConnectionOptions *RdpConnectionOptions `json:"ConnectionOptions,omitempty"`
|
|
||||||
}
|
|
|
@ -1,18 +0,0 @@
|
||||||
/*
|
|
||||||
* HCS API
|
|
||||||
*
|
|
||||||
* No description provided (generated by Swagger Codegen https://github.com/swagger-api/swagger-codegen)
|
|
||||||
*
|
|
||||||
* API version: 2.1
|
|
||||||
* Generated by: Swagger Codegen (https://github.com/swagger-api/swagger-codegen.git)
|
|
||||||
*/
|
|
||||||
|
|
||||||
package hcsschema
|
|
||||||
|
|
||||||
type FlexibleIoDevice struct {
|
|
||||||
EmulatorId string `json:"EmulatorId,omitempty"`
|
|
||||||
|
|
||||||
HostingModel string `json:"HostingModel,omitempty"`
|
|
||||||
|
|
||||||
Configuration []string `json:"Configuration,omitempty"`
|
|
||||||
}
|
|
|
@ -1,19 +0,0 @@
|
||||||
/*
|
|
||||||
* HCS API
|
|
||||||
*
|
|
||||||
* No description provided (generated by Swagger Codegen https://github.com/swagger-api/swagger-codegen)
|
|
||||||
*
|
|
||||||
* API version: 2.1
|
|
||||||
* Generated by: Swagger Codegen (https://github.com/swagger-api/swagger-codegen.git)
|
|
||||||
*/
|
|
||||||
|
|
||||||
package hcsschema
|
|
||||||
|
|
||||||
type GuestConnection struct {
|
|
||||||
|
|
||||||
// Use Vsock rather than Hyper-V sockets to communicate with the guest service.
|
|
||||||
UseVsock bool `json:"UseVsock,omitempty"`
|
|
||||||
|
|
||||||
// Don't disconnect the guest connection when pausing the virtual machine.
|
|
||||||
UseConnectedSuspend bool `json:"UseConnectedSuspend,omitempty"`
|
|
||||||
}
|
|
|
@ -1,21 +0,0 @@
|
||||||
/*
|
|
||||||
* HCS API
|
|
||||||
*
|
|
||||||
* No description provided (generated by Swagger Codegen https://github.com/swagger-api/swagger-codegen)
|
|
||||||
*
|
|
||||||
* API version: 2.1
|
|
||||||
* Generated by: Swagger Codegen (https://github.com/swagger-api/swagger-codegen.git)
|
|
||||||
*/
|
|
||||||
|
|
||||||
package hcsschema
|
|
||||||
|
|
||||||
// Information about the guest.
|
|
||||||
type GuestConnectionInfo struct {
|
|
||||||
|
|
||||||
// Each schema version x.y stands for the range of versions a.b where a==x and b<=y. This list comes from the SupportedSchemaVersions field in GcsCapabilities.
|
|
||||||
SupportedSchemaVersions []Version `json:"SupportedSchemaVersions,omitempty"`
|
|
||||||
|
|
||||||
ProtocolVersion int32 `json:"ProtocolVersion,omitempty"`
|
|
||||||
|
|
||||||
GuestDefinedCapabilities *interface{} `json:"GuestDefinedCapabilities,omitempty"`
|
|
||||||
}
|
|
|
@ -1,14 +0,0 @@
|
||||||
/*
|
|
||||||
* HCS API
|
|
||||||
*
|
|
||||||
* No description provided (generated by Swagger Codegen https://github.com/swagger-api/swagger-codegen)
|
|
||||||
*
|
|
||||||
* API version: 2.1
|
|
||||||
* Generated by: Swagger Codegen (https://github.com/swagger-api/swagger-codegen.git)
|
|
||||||
*/
|
|
||||||
|
|
||||||
package hcsschema
|
|
||||||
|
|
||||||
type GuestCrashReporting struct {
|
|
||||||
WindowsCrashSettings *WindowsCrashReporting `json:"WindowsCrashSettings,omitempty"`
|
|
||||||
}
|
|
|
@ -1,14 +0,0 @@
|
||||||
/*
|
|
||||||
* HCS API
|
|
||||||
*
|
|
||||||
* No description provided (generated by Swagger Codegen https://github.com/swagger-api/swagger-codegen)
|
|
||||||
*
|
|
||||||
* API version: 2.1
|
|
||||||
* Generated by: Swagger Codegen (https://github.com/swagger-api/swagger-codegen.git)
|
|
||||||
*/
|
|
||||||
|
|
||||||
package hcsschema
|
|
||||||
|
|
||||||
type GuestOs struct {
|
|
||||||
HostName string `json:"HostName,omitempty"`
|
|
||||||
}
|
|
|
@ -1,22 +0,0 @@
|
||||||
/*
|
|
||||||
* HCS API
|
|
||||||
*
|
|
||||||
* No description provided (generated by Swagger Codegen https://github.com/swagger-api/swagger-codegen)
|
|
||||||
*
|
|
||||||
* API version: 2.1
|
|
||||||
* Generated by: Swagger Codegen (https://github.com/swagger-api/swagger-codegen.git)
|
|
||||||
*/
|
|
||||||
|
|
||||||
package hcsschema
|
|
||||||
|
|
||||||
type GuestState struct {
|
|
||||||
|
|
||||||
// The path to an existing file uses for persistent guest state storage. An empty string indicates the system should initialize new transient, in-memory guest state.
|
|
||||||
GuestStateFilePath string `json:"GuestStateFilePath,omitempty"`
|
|
||||||
|
|
||||||
// The path to an existing file for persistent runtime state storage. An empty string indicates the system should initialize new transient, in-memory runtime state.
|
|
||||||
RuntimeStateFilePath string `json:"RuntimeStateFilePath,omitempty"`
|
|
||||||
|
|
||||||
// If true, the guest state and runtime state files will be used as templates to populate transient, in-memory state instead of using the files as persistent backing store.
|
|
||||||
ForceTransientState bool `json:"ForceTransientState,omitempty"`
|
|
||||||
}
|
|
16
vendor/github.com/Microsoft/hcsshim/internal/schema2/host_processor_modify_request.go
generated
vendored
16
vendor/github.com/Microsoft/hcsshim/internal/schema2/host_processor_modify_request.go
generated
vendored
|
@ -1,16 +0,0 @@
|
||||||
/*
|
|
||||||
* HCS API
|
|
||||||
*
|
|
||||||
* No description provided (generated by Swagger Codegen https://github.com/swagger-api/swagger-codegen)
|
|
||||||
*
|
|
||||||
* API version: 2.4
|
|
||||||
* Generated by: Swagger Codegen (https://github.com/swagger-api/swagger-codegen.git)
|
|
||||||
*/
|
|
||||||
|
|
||||||
package hcsschema
|
|
||||||
|
|
||||||
// Structure used to request a service processor modification
|
|
||||||
type HostProcessorModificationRequest struct {
|
|
||||||
Operation CPUGroupOperation `json:"Operation,omitempty"`
|
|
||||||
OperationDetails interface{} `json:"OperationDetails,omitempty"`
|
|
||||||
}
|
|
|
@ -1,16 +0,0 @@
|
||||||
/*
|
|
||||||
* HCS API
|
|
||||||
*
|
|
||||||
* No description provided (generated by Swagger Codegen https://github.com/swagger-api/swagger-codegen)
|
|
||||||
*
|
|
||||||
* API version: 2.1
|
|
||||||
* Generated by: Swagger Codegen (https://github.com/swagger-api/swagger-codegen.git)
|
|
||||||
*/
|
|
||||||
|
|
||||||
package hcsschema
|
|
||||||
|
|
||||||
type HostedSystem struct {
|
|
||||||
SchemaVersion *Version `json:"SchemaVersion,omitempty"`
|
|
||||||
|
|
||||||
Container *Container `json:"Container,omitempty"`
|
|
||||||
}
|
|
|
@ -1,16 +0,0 @@
|
||||||
/*
|
|
||||||
* HCS API
|
|
||||||
*
|
|
||||||
* No description provided (generated by Swagger Codegen https://github.com/swagger-api/swagger-codegen)
|
|
||||||
*
|
|
||||||
* API version: 2.1
|
|
||||||
* Generated by: Swagger Codegen (https://github.com/swagger-api/swagger-codegen.git)
|
|
||||||
*/
|
|
||||||
|
|
||||||
package hcsschema
|
|
||||||
|
|
||||||
type HvSocket struct {
|
|
||||||
Config *HvSocketSystemConfig `json:"Config,omitempty"`
|
|
||||||
|
|
||||||
EnablePowerShellDirect bool `json:"EnablePowerShellDirect,omitempty"`
|
|
||||||
}
|
|
|
@ -1,15 +0,0 @@
|
||||||
/*
|
|
||||||
* HCS API
|
|
||||||
*
|
|
||||||
* No description provided (generated by Swagger Codegen https://github.com/swagger-api/swagger-codegen)
|
|
||||||
*
|
|
||||||
* API version: 2.1
|
|
||||||
* Generated by: Swagger Codegen (https://github.com/swagger-api/swagger-codegen.git)
|
|
||||||
*/
|
|
||||||
|
|
||||||
package hcsschema
|
|
||||||
|
|
||||||
// HvSocket configuration for a VM
|
|
||||||
type HvSocket2 struct {
|
|
||||||
HvSocketConfig *HvSocketSystemConfig `json:"HvSocketConfig,omitempty"`
|
|
||||||
}
|
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue