mirror of https://github.com/k3d-io/k3d
parent
338672522a
commit
48839bf602
@ -1,169 +0,0 @@ |
|||||||
//go:build windows
|
|
||||||
// +build windows
|
|
||||||
|
|
||||||
package security |
|
||||||
|
|
||||||
import ( |
|
||||||
"fmt" |
|
||||||
"os" |
|
||||||
"syscall" |
|
||||||
"unsafe" |
|
||||||
) |
|
||||||
|
|
||||||
type ( |
|
||||||
accessMask uint32 |
|
||||||
accessMode uint32 |
|
||||||
desiredAccess uint32 |
|
||||||
inheritMode uint32 |
|
||||||
objectType uint32 |
|
||||||
shareMode uint32 |
|
||||||
securityInformation uint32 |
|
||||||
trusteeForm uint32 |
|
||||||
trusteeType uint32 |
|
||||||
|
|
||||||
//nolint:structcheck // structcheck thinks fields are unused, but the are used to pass data to OS
|
|
||||||
explicitAccess struct { |
|
||||||
accessPermissions accessMask |
|
||||||
accessMode accessMode |
|
||||||
inheritance inheritMode |
|
||||||
trustee trustee |
|
||||||
} |
|
||||||
|
|
||||||
//nolint:structcheck,unused // structcheck thinks fields are unused, but the are used to pass data to OS
|
|
||||||
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 |
|
||||||
|
|
||||||
//cspell:disable-next-line
|
|
||||||
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 :/
|
|
||||||
//
|
|
||||||
//revive:disable-next-line:var-naming VM, not Vm
|
|
||||||
func GrantVmGroupAccess(name string) error { |
|
||||||
// Stat (to determine if `name` is a directory).
|
|
||||||
s, err := os.Stat(name) |
|
||||||
if err != nil { |
|
||||||
return fmt.Errorf("%s os.Stat %s: %w", gvmga, name, err) |
|
||||||
} |
|
||||||
|
|
||||||
// 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) //nolint:errcheck
|
|
||||||
|
|
||||||
// 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 fmt.Errorf("%s GetSecurityInfo %s: %w", gvmga, name, err) |
|
||||||
} |
|
||||||
defer syscall.LocalFree((syscall.Handle)(unsafe.Pointer(sd))) //nolint:errcheck
|
|
||||||
|
|
||||||
// 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))) //nolint:errcheck
|
|
||||||
|
|
||||||
// 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 fmt.Errorf("%s SetSecurityInfo %s: %w", gvmga, name, err) |
|
||||||
} |
|
||||||
|
|
||||||
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, err := syscall.UTF16FromString(name) |
|
||||||
if err != nil { |
|
||||||
return syscall.InvalidHandle, fmt.Errorf("could not convernt name to UTF-16: %w", err) |
|
||||||
} |
|
||||||
da := uint32(desiredAccessReadControl | desiredAccessWriteDac) |
|
||||||
sm := uint32(shareModeRead | shareModeWrite) |
|
||||||
fa := uint32(syscall.FILE_ATTRIBUTE_NORMAL) |
|
||||||
if isDir { |
|
||||||
fa |= syscall.FILE_FLAG_BACKUP_SEMANTICS |
|
||||||
} |
|
||||||
fd, err := syscall.CreateFile(&namep[0], da, sm, nil, syscall.OPEN_EXISTING, fa, 0) |
|
||||||
if err != nil { |
|
||||||
return syscall.InvalidHandle, fmt.Errorf("%s syscall.CreateFile %s: %w", gvmga, name, err) |
|
||||||
} |
|
||||||
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, fmt.Errorf("%s syscall.StringToSid %s %s: %w", gvmga, name, sidVMGroup, err) |
|
||||||
} |
|
||||||
|
|
||||||
inheritance := inheritModeNoInheritance |
|
||||||
if isDir { |
|
||||||
inheritance = inheritModeSubContainersAndObjectsInherit |
|
||||||
} |
|
||||||
|
|
||||||
eaArray := []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, fmt.Errorf("%s SetEntriesInAcl %s: %w", gvmga, name, err) |
|
||||||
} |
|
||||||
|
|
||||||
return modifiedDACL, nil |
|
||||||
} |
|
@ -1,7 +0,0 @@ |
|||||||
package security |
|
||||||
|
|
||||||
//go:generate go run github.com/Microsoft/go-winio/tools/mkwinsyscall -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) (win32err error) = advapi32.GetSecurityInfo
|
|
||||||
//sys setSecurityInfo(handle syscall.Handle, objectType uint32, si uint32, psidOwner uintptr, psidGroup uintptr, pDacl uintptr, pSacl uintptr) (win32err error) = advapi32.SetSecurityInfo
|
|
||||||
//sys setEntriesInAcl(count uintptr, pListOfEEs uintptr, oldAcl uintptr, newAcl *uintptr) (win32err error) = advapi32.SetEntriesInAclW
|
|
@ -1,72 +0,0 @@ |
|||||||
//go:build windows
|
|
||||||
|
|
||||||
// Code generated by 'go generate' using "github.com/Microsoft/go-winio/tools/mkwinsyscall"; 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) (win32err error) { |
|
||||||
r0, _, _ := 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 r0 != 0 { |
|
||||||
win32err = syscall.Errno(r0) |
|
||||||
} |
|
||||||
return |
|
||||||
} |
|
||||||
|
|
||||||
func setEntriesInAcl(count uintptr, pListOfEEs uintptr, oldAcl uintptr, newAcl *uintptr) (win32err error) { |
|
||||||
r0, _, _ := syscall.Syscall6(procSetEntriesInAclW.Addr(), 4, uintptr(count), uintptr(pListOfEEs), uintptr(oldAcl), uintptr(unsafe.Pointer(newAcl)), 0, 0) |
|
||||||
if r0 != 0 { |
|
||||||
win32err = syscall.Errno(r0) |
|
||||||
} |
|
||||||
return |
|
||||||
} |
|
||||||
|
|
||||||
func setSecurityInfo(handle syscall.Handle, objectType uint32, si uint32, psidOwner uintptr, psidGroup uintptr, pDacl uintptr, pSacl uintptr) (win32err error) { |
|
||||||
r0, _, _ := syscall.Syscall9(procSetSecurityInfo.Addr(), 7, uintptr(handle), uintptr(objectType), uintptr(si), uintptr(psidOwner), uintptr(psidGroup), uintptr(pDacl), uintptr(pSacl), 0, 0) |
|
||||||
if r0 != 0 { |
|
||||||
win32err = syscall.Errno(r0) |
|
||||||
} |
|
||||||
return |
|
||||||
} |
|
@ -1,377 +0,0 @@ |
|||||||
//go:build windows
|
|
||||||
// +build windows
|
|
||||||
|
|
||||||
package vhd |
|
||||||
|
|
||||||
import ( |
|
||||||
"fmt" |
|
||||||
"syscall" |
|
||||||
|
|
||||||
"github.com/Microsoft/go-winio/pkg/guid" |
|
||||||
"golang.org/x/sys/windows" |
|
||||||
) |
|
||||||
|
|
||||||
//go:generate go run github.com/Microsoft/go-winio/tools/mkwinsyscall -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) (win32err error) = virtdisk.CreateVirtualDisk
|
|
||||||
//sys openVirtualDisk(virtualStorageType *VirtualStorageType, path string, virtualDiskAccessMask uint32, openVirtualDiskFlags uint32, parameters *openVirtualDiskParameters, handle *syscall.Handle) (win32err error) = virtdisk.OpenVirtualDisk
|
|
||||||
//sys attachVirtualDisk(handle syscall.Handle, securityDescriptor *uintptr, attachVirtualDiskFlag uint32, providerSpecificFlags uint32, parameters *AttachVirtualDiskParameters, overlapped *syscall.Overlapped) (win32err error) = virtdisk.AttachVirtualDisk
|
|
||||||
//sys detachVirtualDisk(handle syscall.Handle, detachVirtualDiskFlags uint32, providerSpecificFlags uint32) (win32err error) = virtdisk.DetachVirtualDisk
|
|
||||||
//sys getVirtualDiskPhysicalPath(handle syscall.Handle, diskPathSizeInBytes *uint32, buffer *uint16) (win32err error) = 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 |
|
||||||
} |
|
||||||
|
|
||||||
// The higher level `OpenVersion2` struct uses `bool`s to refer to `GetInfoOnly` and `ReadOnly` for ease of use. However,
|
|
||||||
// the internal windows structure uses `BOOL`s aka int32s for these types. `openVersion2` is used for translating
|
|
||||||
// `OpenVersion2` fields to the correct windows internal field types on the `Open____` methods.
|
|
||||||
type openVersion2 struct { |
|
||||||
getInfoOnly int32 |
|
||||||
readOnly int32 |
|
||||||
resiliencyGUID guid.GUID |
|
||||||
} |
|
||||||
|
|
||||||
type openVirtualDiskParameters struct { |
|
||||||
version uint32 |
|
||||||
version2 openVersion2 |
|
||||||
} |
|
||||||
|
|
||||||
type AttachVersion2 struct { |
|
||||||
RestrictedOffset uint64 |
|
||||||
RestrictedLength uint64 |
|
||||||
} |
|
||||||
|
|
||||||
type AttachVirtualDiskParameters struct { |
|
||||||
Version uint32 |
|
||||||
Version2 AttachVersion2 |
|
||||||
} |
|
||||||
|
|
||||||
const ( |
|
||||||
//revive:disable-next-line:var-naming ALL_CAPS
|
|
||||||
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 //revive:disable-line:var-naming VHD, not Vhd
|
|
||||||
CreateVirtualDiskFlagSparseFile CreateVirtualDiskFlag = 0x80 |
|
||||||
CreateVirtualDiskFlagPmemCompatible CreateVirtualDiskFlag = 0x100 //revive:disable-line:var-naming PMEM, not Pmem
|
|
||||||
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.
|
|
||||||
//
|
|
||||||
//revive:disable-next-line:var-naming VHDX, not Vhdx
|
|
||||||
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 |
|
||||||
} |
|
||||||
|
|
||||||
return syscall.CloseHandle(handle) |
|
||||||
} |
|
||||||
|
|
||||||
// DetachVirtualDisk detaches a virtual hard disk by handle.
|
|
||||||
func DetachVirtualDisk(handle syscall.Handle) (err error) { |
|
||||||
if err := detachVirtualDisk(handle, 0, 0); err != nil { |
|
||||||
return fmt.Errorf("failed to detach virtual disk: %w", err) |
|
||||||
} |
|
||||||
return nil |
|
||||||
} |
|
||||||
|
|
||||||
// DetachVhd detaches a vhd found at `path`.
|
|
||||||
//
|
|
||||||
//revive:disable-next-line:var-naming VHD, not Vhd
|
|
||||||
func DetachVhd(path string) error { |
|
||||||
handle, err := OpenVirtualDisk( |
|
||||||
path, |
|
||||||
VirtualDiskAccessNone, |
|
||||||
OpenVirtualDiskFlagCachedIO|OpenVirtualDiskFlagIgnoreRelativeParentLocator, |
|
||||||
) |
|
||||||
if err != nil { |
|
||||||
return err |
|
||||||
} |
|
||||||
defer syscall.CloseHandle(handle) //nolint:errcheck
|
|
||||||
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 fmt.Errorf("failed to attach virtual disk: %w", err) |
|
||||||
} |
|
||||||
return nil |
|
||||||
} |
|
||||||
|
|
||||||
// AttachVhd attaches a virtual hard disk at `path` for use. Attaches using version 2
|
|
||||||
// of the ATTACH_VIRTUAL_DISK_PARAMETERS.
|
|
||||||
//
|
|
||||||
//revive:disable-next-line:var-naming VHD, not Vhd
|
|
||||||
func AttachVhd(path string) (err error) { |
|
||||||
handle, err := OpenVirtualDisk( |
|
||||||
path, |
|
||||||
VirtualDiskAccessNone, |
|
||||||
OpenVirtualDiskFlagCachedIO|OpenVirtualDiskFlagIgnoreRelativeParentLocator, |
|
||||||
) |
|
||||||
if err != nil { |
|
||||||
return err |
|
||||||
} |
|
||||||
|
|
||||||
defer syscall.CloseHandle(handle) //nolint:errcheck
|
|
||||||
params := AttachVirtualDiskParameters{Version: 2} |
|
||||||
if err := AttachVirtualDisk( |
|
||||||
handle, |
|
||||||
AttachVirtualDiskFlagNone, |
|
||||||
¶ms, |
|
||||||
); err != nil { |
|
||||||
return fmt.Errorf("failed to attach virtual disk: %w", err) |
|
||||||
} |
|
||||||
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 |
|
||||||
getInfoOnly int32 |
|
||||||
readOnly int32 |
|
||||||
) |
|
||||||
if parameters.Version != 2 { |
|
||||||
return handle, fmt.Errorf("only version 2 VHDs are supported, found version: %d", parameters.Version) |
|
||||||
} |
|
||||||
if parameters.Version2.GetInfoOnly { |
|
||||||
getInfoOnly = 1 |
|
||||||
} |
|
||||||
if parameters.Version2.ReadOnly { |
|
||||||
readOnly = 1 |
|
||||||
} |
|
||||||
params := &openVirtualDiskParameters{ |
|
||||||
version: parameters.Version, |
|
||||||
version2: openVersion2{ |
|
||||||
getInfoOnly, |
|
||||||
readOnly, |
|
||||||
parameters.Version2.ResiliencyGUID, |
|
||||||
}, |
|
||||||
} |
|
||||||
if err := openVirtualDisk( |
|
||||||
&defaultType, |
|
||||||
vhdPath, |
|
||||||
uint32(virtualDiskAccessMask), |
|
||||||
uint32(openVirtualDiskFlags), |
|
||||||
params, |
|
||||||
&handle, |
|
||||||
); err != nil { |
|
||||||
return 0, fmt.Errorf("failed to open virtual disk: %w", err) |
|
||||||
} |
|
||||||
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, fmt.Errorf("failed to create virtual disk: %w", err) |
|
||||||
} |
|
||||||
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 "", fmt.Errorf("failed to get disk physical path: %w", err) |
|
||||||
} |
|
||||||
return windows.UTF16ToString(diskPhysicalPathBuf[:]), nil |
|
||||||
} |
|
||||||
|
|
||||||
// CreateDiffVhd is a helper function to create a differencing virtual disk.
|
|
||||||
//
|
|
||||||
//revive:disable-next-line:var-naming VHD, not Vhd
|
|
||||||
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: %w", err) |
|
||||||
} |
|
||||||
if err := syscall.CloseHandle(vhdHandle); err != nil { |
|
||||||
return fmt.Errorf("failed to close differencing vhd handle: %w", err) |
|
||||||
} |
|
||||||
return nil |
|
||||||
} |
|
@ -1,108 +0,0 @@ |
|||||||
//go:build windows
|
|
||||||
|
|
||||||
// Code generated by 'go generate' using "github.com/Microsoft/go-winio/tools/mkwinsyscall"; 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) (win32err error) { |
|
||||||
r0, _, _ := syscall.Syscall6(procAttachVirtualDisk.Addr(), 6, uintptr(handle), uintptr(unsafe.Pointer(securityDescriptor)), uintptr(attachVirtualDiskFlag), uintptr(providerSpecificFlags), uintptr(unsafe.Pointer(parameters)), uintptr(unsafe.Pointer(overlapped))) |
|
||||||
if r0 != 0 { |
|
||||||
win32err = syscall.Errno(r0) |
|
||||||
} |
|
||||||
return |
|
||||||
} |
|
||||||
|
|
||||||
func createVirtualDisk(virtualStorageType *VirtualStorageType, path string, virtualDiskAccessMask uint32, securityDescriptor *uintptr, createVirtualDiskFlags uint32, providerSpecificFlags uint32, parameters *CreateVirtualDiskParameters, overlapped *syscall.Overlapped, handle *syscall.Handle) (win32err error) { |
|
||||||
var _p0 *uint16 |
|
||||||
_p0, win32err = syscall.UTF16PtrFromString(path) |
|
||||||
if win32err != 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) (win32err error) { |
|
||||||
r0, _, _ := 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 r0 != 0 { |
|
||||||
win32err = syscall.Errno(r0) |
|
||||||
} |
|
||||||
return |
|
||||||
} |
|
||||||
|
|
||||||
func detachVirtualDisk(handle syscall.Handle, detachVirtualDiskFlags uint32, providerSpecificFlags uint32) (win32err error) { |
|
||||||
r0, _, _ := syscall.Syscall(procDetachVirtualDisk.Addr(), 3, uintptr(handle), uintptr(detachVirtualDiskFlags), uintptr(providerSpecificFlags)) |
|
||||||
if r0 != 0 { |
|
||||||
win32err = syscall.Errno(r0) |
|
||||||
} |
|
||||||
return |
|
||||||
} |
|
||||||
|
|
||||||
func getVirtualDiskPhysicalPath(handle syscall.Handle, diskPathSizeInBytes *uint32, buffer *uint16) (win32err error) { |
|
||||||
r0, _, _ := syscall.Syscall(procGetVirtualDiskPhysicalPath.Addr(), 3, uintptr(handle), uintptr(unsafe.Pointer(diskPathSizeInBytes)), uintptr(unsafe.Pointer(buffer))) |
|
||||||
if r0 != 0 { |
|
||||||
win32err = syscall.Errno(r0) |
|
||||||
} |
|
||||||
return |
|
||||||
} |
|
||||||
|
|
||||||
func openVirtualDisk(virtualStorageType *VirtualStorageType, path string, virtualDiskAccessMask uint32, openVirtualDiskFlags uint32, parameters *openVirtualDiskParameters, handle *syscall.Handle) (win32err error) { |
|
||||||
var _p0 *uint16 |
|
||||||
_p0, win32err = syscall.UTF16PtrFromString(path) |
|
||||||
if win32err != 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) (win32err error) { |
|
||||||
r0, _, _ := 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 r0 != 0 { |
|
||||||
win32err = syscall.Errno(r0) |
|
||||||
} |
|
||||||
return |
|
||||||
} |
|
@ -1 +0,0 @@ |
|||||||
* text=auto eol=lf |
|
@ -1,38 +0,0 @@ |
|||||||
# Binaries for programs and plugins |
|
||||||
*.exe |
|
||||||
*.dll |
|
||||||
*.so |
|
||||||
*.dylib |
|
||||||
|
|
||||||
# Ignore vscode setting files |
|
||||||
.vscode/ |
|
||||||
|
|
||||||
# Test binary, build with `go test -c` |
|
||||||
*.test |
|
||||||
|
|
||||||
# Output of the go coverage tool, specifically when used with LiteIDE |
|
||||||
*.out |
|
||||||
|
|
||||||
# Project-local glide cache, RE: https://github.com/Masterminds/glide/issues/736 |
|
||||||
.glide/ |
|
||||||
|
|
||||||
# Ignore gcs bin directory |
|
||||||
service/bin/ |
|
||||||
service/pkg/ |
|
||||||
|
|
||||||
*.img |
|
||||||
*.vhd |
|
||||||
*.tar.gz |
|
||||||
|
|
||||||
# Make stuff |
|
||||||
.rootfs-done |
|
||||||
bin/* |
|
||||||
rootfs/* |
|
||||||
*.o |
|
||||||
/build/ |
|
||||||
|
|
||||||
deps/* |
|
||||||
out/* |
|
||||||
|
|
||||||
.idea/ |
|
||||||
.vscode/ |
|
@ -1,99 +0,0 @@ |
|||||||
run: |
|
||||||
timeout: 8m |
|
||||||
|
|
||||||
linters: |
|
||||||
enable: |
|
||||||
- stylecheck |
|
||||||
|
|
||||||
linters-settings: |
|
||||||
stylecheck: |
|
||||||
# https://staticcheck.io/docs/checks |
|
||||||
checks: ["all"] |
|
||||||
|
|
||||||
|
|
||||||
issues: |
|
||||||
# This repo has a LOT of generated schema files, operating system bindings, and other things that ST1003 from stylecheck won't like |
|
||||||
# (screaming case Windows api constants for example). There's also some structs that we *could* change the initialisms to be Go |
|
||||||
# friendly (Id -> ID) but they're exported and it would be a breaking change. This makes it so that most new code, code that isn't |
|
||||||
# supposed to be a pretty faithful mapping to an OS call/constants, or non-generated code still checks if we're following idioms, |
|
||||||
# while ignoring the things that are just noise or would be more of a hassle than it'd be worth to change. |
|
||||||
exclude-rules: |
|
||||||
- path: layer.go |
|
||||||
linters: |
|
||||||
- stylecheck |
|
||||||
Text: "ST1003:" |
|
||||||
|
|
||||||
- path: hcsshim.go |
|
||||||
linters: |
|
||||||
- stylecheck |
|
||||||
Text: "ST1003:" |
|
||||||
|
|
||||||
- path: internal\\hcs\\schema2\\ |
|
||||||
linters: |
|
||||||
- stylecheck |
|
||||||
Text: "ST1003:" |
|
||||||
|
|
||||||
- path: internal\\wclayer\\ |
|
||||||
linters: |
|
||||||
- stylecheck |
|
||||||
Text: "ST1003:" |
|
||||||
|
|
||||||
- path: hcn\\ |
|
||||||
linters: |
|
||||||
- stylecheck |
|
||||||
Text: "ST1003:" |
|
||||||
|
|
||||||
- path: internal\\hcs\\schema1\\ |
|
||||||
linters: |
|
||||||
- stylecheck |
|
||||||
Text: "ST1003:" |
|
||||||
|
|
||||||
- path: internal\\hns\\ |
|
||||||
linters: |
|
||||||
- stylecheck |
|
||||||
Text: "ST1003:" |
|
||||||
|
|
||||||
- path: ext4\\internal\\compactext4\\ |
|
||||||
linters: |
|
||||||
- stylecheck |
|
||||||
Text: "ST1003:" |
|
||||||
|
|
||||||
- path: ext4\\internal\\format\\ |
|
||||||
linters: |
|
||||||
- stylecheck |
|
||||||
Text: "ST1003:" |
|
||||||
|
|
||||||
- path: internal\\guestrequest\\ |
|
||||||
linters: |
|
||||||
- stylecheck |
|
||||||
Text: "ST1003:" |
|
||||||
|
|
||||||
- path: internal\\guest\\prot\\ |
|
||||||
linters: |
|
||||||
- stylecheck |
|
||||||
Text: "ST1003:" |
|
||||||
|
|
||||||
- path: internal\\windevice\\ |
|
||||||
linters: |
|
||||||
- stylecheck |
|
||||||
Text: "ST1003:" |
|
||||||
|
|
||||||
- path: internal\\winapi\\ |
|
||||||
linters: |
|
||||||
- stylecheck |
|
||||||
Text: "ST1003:" |
|
||||||
|
|
||||||
- path: internal\\vmcompute\\ |
|
||||||
linters: |
|
||||||
- stylecheck |
|
||||||
Text: "ST1003:" |
|
||||||
|
|
||||||
- path: internal\\regstate\\ |
|
||||||
linters: |
|
||||||
- stylecheck |
|
||||||
Text: "ST1003:" |
|
||||||
|
|
||||||
- path: internal\\hcserror\\ |
|
||||||
linters: |
|
||||||
- stylecheck |
|
||||||
Text: "ST1003:" |
|
@ -1 +0,0 @@ |
|||||||
* @microsoft/containerplat |
|
@ -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,87 +0,0 @@ |
|||||||
BASE:=base.tar.gz
|
|
||||||
|
|
||||||
GO:=go
|
|
||||||
GO_FLAGS:=-ldflags "-s -w" # strip Go binaries
|
|
||||||
CGO_ENABLED:=0
|
|
||||||
GOMODVENDOR:=
|
|
||||||
|
|
||||||
CFLAGS:=-O2 -Wall
|
|
||||||
LDFLAGS:=-static -s # strip C binaries
|
|
||||||
|
|
||||||
GO_FLAGS_EXTRA:=
|
|
||||||
ifeq "$(GOMODVENDOR)" "1" |
|
||||||
GO_FLAGS_EXTRA += -mod=vendor
|
|
||||||
endif |
|
||||||
GO_BUILD:=CGO_ENABLED=$(CGO_ENABLED) $(GO) build $(GO_FLAGS) $(GO_FLAGS_EXTRA)
|
|
||||||
|
|
||||||
SRCROOT=$(dir $(abspath $(firstword $(MAKEFILE_LIST))))
|
|
||||||
|
|
||||||
# The link aliases for gcstools
|
|
||||||
GCS_TOOLS=\
|
|
||||||
generichook
|
|
||||||
|
|
||||||
.PHONY: all always rootfs test |
|
||||||
|
|
||||||
all: out/initrd.img out/rootfs.tar.gz |
|
||||||
|
|
||||||
clean: |
|
||||||
find -name '*.o' -print0 | xargs -0 -r rm
|
|
||||||
rm -rf bin deps rootfs out
|
|
||||||
|
|
||||||
test: |
|
||||||
cd $(SRCROOT) && go test -v ./internal/guest/...
|
|
||||||
|
|
||||||
out/delta.tar.gz: bin/init bin/vsockexec bin/cmd/gcs bin/cmd/gcstools Makefile |
|
||||||
@mkdir -p out
|
|
||||||
rm -rf rootfs
|
|
||||||
mkdir -p rootfs/bin/
|
|
||||||
cp bin/init rootfs/
|
|
||||||
cp bin/vsockexec rootfs/bin/
|
|
||||||
cp bin/cmd/gcs rootfs/bin/
|
|
||||||
cp bin/cmd/gcstools rootfs/bin/
|
|
||||||
for tool in $(GCS_TOOLS); do ln -s gcstools rootfs/bin/$$tool; done
|
|
||||||
git -C $(SRCROOT) rev-parse HEAD > rootfs/gcs.commit && \
|
|
||||||
git -C $(SRCROOT) rev-parse --abbrev-ref HEAD > rootfs/gcs.branch
|
|
||||||
tar -zcf $@ -C rootfs .
|
|
||||||
rm -rf rootfs
|
|
||||||
|
|
||||||
out/rootfs.tar.gz: out/initrd.img |
|
||||||
rm -rf rootfs-conv
|
|
||||||
mkdir rootfs-conv
|
|
||||||
gunzip -c out/initrd.img | (cd rootfs-conv && cpio -imd)
|
|
||||||
tar -zcf $@ -C rootfs-conv .
|
|
||||||
rm -rf rootfs-conv
|
|
||||||
|
|
||||||
out/initrd.img: $(BASE) out/delta.tar.gz $(SRCROOT)/hack/catcpio.sh |
|
||||||
$(SRCROOT)/hack/catcpio.sh "$(BASE)" out/delta.tar.gz > out/initrd.img.uncompressed
|
|
||||||
gzip -c out/initrd.img.uncompressed > $@
|
|
||||||
rm out/initrd.img.uncompressed
|
|
||||||
|
|
||||||
-include deps/cmd/gcs.gomake |
|
||||||
-include deps/cmd/gcstools.gomake |
|
||||||
|
|
||||||
# Implicit rule for includes that define Go targets.
|
|
||||||
%.gomake: $(SRCROOT)/Makefile |
|
||||||
@mkdir -p $(dir $@)
|
|
||||||
@/bin/echo $(@:deps/%.gomake=bin/%): $(SRCROOT)/hack/gomakedeps.sh > $@.new
|
|
||||||
@/bin/echo -e '\t@mkdir -p $$(dir $$@) $(dir $@)' >> $@.new
|
|
||||||
@/bin/echo -e '\t$$(GO_BUILD) -o $$@.new $$(SRCROOT)/$$(@:bin/%=%)' >> $@.new
|
|
||||||
@/bin/echo -e '\tGO="$(GO)" $$(SRCROOT)/hack/gomakedeps.sh $$@ $$(SRCROOT)/$$(@:bin/%=%) $$(GO_FLAGS) $$(GO_FLAGS_EXTRA) > $(@:%.gomake=%.godeps).new' >> $@.new
|
|
||||||
@/bin/echo -e '\tmv $(@:%.gomake=%.godeps).new $(@:%.gomake=%.godeps)' >> $@.new
|
|
||||||
@/bin/echo -e '\tmv $$@.new $$@' >> $@.new
|
|
||||||
@/bin/echo -e '-include $(@:%.gomake=%.godeps)' >> $@.new
|
|
||||||
mv $@.new $@
|
|
||||||
|
|
||||||
VPATH=$(SRCROOT)
|
|
||||||
|
|
||||||
bin/vsockexec: vsockexec/vsockexec.o vsockexec/vsock.o |
|
||||||
@mkdir -p bin
|
|
||||||
$(CC) $(LDFLAGS) -o $@ $^
|
|
||||||
|
|
||||||
bin/init: init/init.o vsockexec/vsock.o |
|
||||||
@mkdir -p bin
|
|
||||||
$(CC) $(LDFLAGS) -o $@ $^
|
|
||||||
|
|
||||||
%.o: %.c |
|
||||||
@mkdir -p $(dir $@)
|
|
||||||
$(CC) $(CFLAGS) $(CPPFLAGS) -c -o $@ $<
|
|
@ -1,49 +0,0 @@ |
|||||||
version = "unstable" |
|
||||||
generator = "gogoctrd" |
|
||||||
plugins = ["grpc", "fieldpath"] |
|
||||||
|
|
||||||
# Control protoc include paths. Below are usually some good defaults, but feel |
|
||||||
# free to try it without them if it works for your project. |
|
||||||
[includes] |
|
||||||
# Include paths that will be added before all others. Typically, you want to |
|
||||||
# treat the root of the project as an include, but this may not be necessary. |
|
||||||
before = ["./protobuf"] |
|
||||||
|
|
||||||
# Paths that should be treated as include roots in relation to the vendor |
|
||||||
# directory. These will be calculated with the vendor directory nearest the |
|
||||||
# target package. |
|
||||||
packages = ["github.com/gogo/protobuf"] |
|
||||||
|
|
||||||
# Paths that will be added untouched to the end of the includes. We use |
|
||||||
# `/usr/local/include` to pickup the common install location of protobuf. |
|
||||||
# This is the default. |
|
||||||
after = ["/usr/local/include"] |
|
||||||
|
|
||||||
# This section maps protobuf imports to Go packages. These will become |
|
||||||
# `-M` directives in the call to the go protobuf generator. |
|
||||||
[packages] |
|
||||||
"gogoproto/gogo.proto" = "github.com/gogo/protobuf/gogoproto" |
|
||||||
"google/protobuf/any.proto" = "github.com/gogo/protobuf/types" |
|
||||||
"google/protobuf/empty.proto" = "github.com/gogo/protobuf/types" |
|
||||||
"google/protobuf/struct.proto" = "github.com/gogo/protobuf/types" |
|
||||||
"google/protobuf/descriptor.proto" = "github.com/gogo/protobuf/protoc-gen-gogo/descriptor" |
|
||||||
"google/protobuf/field_mask.proto" = "github.com/gogo/protobuf/types" |
|
||||||
"google/protobuf/timestamp.proto" = "github.com/gogo/protobuf/types" |
|
||||||
"google/protobuf/duration.proto" = "github.com/gogo/protobuf/types" |
|
||||||
"github/containerd/cgroups/stats/v1/metrics.proto" = "github.com/containerd/cgroups/stats/v1" |
|
||||||
|
|
||||||
[[overrides]] |
|
||||||
prefixes = ["github.com/Microsoft/hcsshim/internal/shimdiag"] |
|
||||||
plugins = ["ttrpc"] |
|
||||||
|
|
||||||
[[overrides]] |
|
||||||
prefixes = ["github.com/Microsoft/hcsshim/internal/computeagent"] |
|
||||||
plugins = ["ttrpc"] |
|
||||||
|
|
||||||
[[overrides]] |
|
||||||
prefixes = ["github.com/Microsoft/hcsshim/internal/ncproxyttrpc"] |
|
||||||
plugins = ["ttrpc"] |
|
||||||
|
|
||||||
[[overrides]] |
|
||||||
prefixes = ["github.com/Microsoft/hcsshim/internal/vmservice"] |
|
||||||
plugins = ["ttrpc"] |
|
@ -1,120 +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), as well as code for the [guest agent](./internal/guest/README.md) (commonly referred to as the GCS or Guest Compute Service in the codebase) used to support running Linux Hyper-V containers. |
|
||||||
|
|
||||||
It is primarily used in the [Moby](https://github.com/moby/moby) and [Containerd](https://github.com/containerd/containerd) projects, but it can be freely used by other projects as well. |
|
||||||
|
|
||||||
## Building |
|
||||||
|
|
||||||
While this repository can be used as a library of sorts to call the HCS apis, there are a couple binaries built out of the repository as well. The main ones being the Linux guest agent, and an implementation of the [runtime v2 containerd shim api](https://github.com/containerd/containerd/blob/master/runtime/v2/README.md). |
|
||||||
### Linux Hyper-V Container Guest Agent |
|
||||||
|
|
||||||
To build the Linux guest agent itself all that's needed is to set your GOOS to "Linux" and build out of ./cmd/gcs. |
|
||||||
```powershell |
|
||||||
C:\> $env:GOOS="linux" |
|
||||||
C:\> go build .\cmd\gcs\ |
|
||||||
``` |
|
||||||
|
|
||||||
or on a Linux machine |
|
||||||
```sh |
|
||||||
> go build ./cmd/gcs |
|
||||||
``` |
|
||||||
|
|
||||||
If you want it to be packaged inside of a rootfs to boot with alongside all of the other tools then you'll need to provide a rootfs that it can be packaged inside of. An easy way is to export the rootfs of a container. |
|
||||||
|
|
||||||
```sh |
|
||||||
docker pull busybox |
|
||||||
docker run --name base_image_container busybox |
|
||||||
docker export base_image_container | gzip > base.tar.gz |
|
||||||
BASE=./base.tar.gz |
|
||||||
make all |
|
||||||
``` |
|
||||||
|
|
||||||
If the build is successful, in the `./out` folder you should see: |
|
||||||
```sh |
|
||||||
> ls ./out/ |
|
||||||
delta.tar.gz initrd.img rootfs.tar.gz |
|
||||||
``` |
|
||||||
|
|
||||||
### Containerd Shim |
|
||||||
For info on the Runtime V2 API: https://github.com/containerd/containerd/blob/master/runtime/v2/README.md. |
|
||||||
|
|
||||||
Contrary to the typical Linux architecture of shim -> runc, the runhcs shim is used both to launch and manage the lifetime of containers. |
|
||||||
|
|
||||||
```powershell |
|
||||||
C:\> $env:GOOS="windows" |
|
||||||
C:\> go build .\cmd\containerd-shim-runhcs-v1 |
|
||||||
``` |
|
||||||
|
|
||||||
Then place the binary in the same directory that Containerd is located at in your environment. A default Containerd configuration file can be generated by running: |
|
||||||
```powershell |
|
||||||
.\containerd.exe config default | Out-File "C:\Program Files\containerd\config.toml" -Encoding ascii |
|
||||||
``` |
|
||||||
|
|
||||||
This config file will already have the shim set as the default runtime for cri interactions. |
|
||||||
|
|
||||||
To trial using the shim out with ctr.exe: |
|
||||||
```powershell |
|
||||||
C:\> ctr.exe run --runtime io.containerd.runhcs.v1 --rm mcr.microsoft.com/windows/nanoserver:2004 windows-test cmd /c "echo Hello World!" |
|
||||||
``` |
|
||||||
|
|
||||||
## 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 require 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. Please see https://developercertificate.org/ for |
|
||||||
more info, as well as to make sure that you can attest to the rules listed. Our CI uses the [DCO Github app](https://github.com/apps/dco) to ensure |
|
||||||
that all commits in a given PR are signed-off. |
|
||||||
|
|
||||||
### Test Directory (Important to note) |
|
||||||
|
|
||||||
This project has tried to trim some dependencies from the root Go modules file that would be cumbersome to get transitively included if this |
|
||||||
project is being vendored/used as a library. Some of these dependencies were only being used for tests, so the /test directory in this project also has |
|
||||||
its own go.mod file where these are now included to get around this issue. Our tests rely on the code in this project to run, so the test Go modules file |
|
||||||
has a relative path replace directive to pull in the latest hcsshim code that the tests actually touch from this project |
|
||||||
(which is the repo itself on your disk). |
|
||||||
|
|
||||||
``` |
|
||||||
replace ( |
|
||||||
github.com/Microsoft/hcsshim => ../ |
|
||||||
) |
|
||||||
``` |
|
||||||
|
|
||||||
Because of this, for most code changes you may need to run `go mod vendor` + `go mod tidy` in the /test directory in this repository, as the |
|
||||||
CI in this project will check if the files are out of date and will fail if this is true. |
|
||||||
|
|
||||||
|
|
||||||
## 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.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/hcs/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/hcs/schema1" |
|
||||||
"github.com/Microsoft/hcsshim/internal/mergemaps" |
|
||||||
) |
|
||||||
|
|
||||||
// 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 a procedure look up fails.
|
|
||||||
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.
|
|
||||||
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.
|
|
||||||
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,12 +0,0 @@ |
|||||||
# Requirements so far: |
|
||||||
# dockerd running |
|
||||||
# - image microsoft/nanoserver (matching host base image) docker load -i c:\baseimages\nanoserver.tar |
|
||||||
# - image alpine (linux) docker pull --platform=linux alpine |
|
||||||
|
|
||||||
|
|
||||||
# TODO: Add this a parameter for debugging. ie "functional-tests -debug=$true" |
|
||||||
#$env:HCSSHIM_FUNCTIONAL_TESTS_DEBUG="yes please" |
|
||||||
|
|
||||||
#pushd uvm |
|
||||||
go test -v -tags "functional uvmcreate uvmscratch uvmscsi uvmvpmem uvmvsmb uvmp9" ./... |
|
||||||
#popd |
|
@ -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,118 +0,0 @@ |
|||||||
package hcsshim |
|
||||||
|
|
||||||
import ( |
|
||||||
"github.com/Microsoft/hcsshim/internal/hns" |
|
||||||
) |
|
||||||
|
|
||||||
// HNSEndpoint represents a network endpoint in HNS
|
|
||||||
type HNSEndpoint = hns.HNSEndpoint |
|
||||||
|
|
||||||
// HNSEndpointStats represent the stats for an networkendpoint in HNS
|
|
||||||
type HNSEndpointStats = hns.EndpointStats |
|
||||||
|
|
||||||
// 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) |
|
||||||
} |
|
||||||
|
|
||||||
// GetHNSEndpointStats gets the endpoint stats by ID
|
|
||||||
func GetHNSEndpointStats(endpointName string) (*HNSEndpointStats, error) { |
|
||||||
return hns.GetHNSEndpointStats(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/hcs/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,97 +0,0 @@ |
|||||||
package cow |
|
||||||
|
|
||||||
import ( |
|
||||||
"context" |
|
||||||
"io" |
|
||||||
|
|
||||||
"github.com/Microsoft/hcsshim/internal/hcs/schema1" |
|
||||||
hcsschema "github.com/Microsoft/hcsshim/internal/hcs/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 |
|
||||||
// CloseStdout closes the stdout connection to the process. It is used to indicate
|
|
||||||
// that we are done receiving output on the shim side.
|
|
||||||
CloseStdout(ctx context.Context) error |
|
||||||
// CloseStderr closes the stderr connection to the process. It is used to indicate
|
|
||||||
// that we are done receiving output on the shim side.
|
|
||||||
CloseStderr(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 |
|
||||||
// WaitChannel returns the wait channel of the container
|
|
||||||
WaitChannel() <-chan struct{} |
|
||||||
// WaitError returns the container termination error.
|
|
||||||
// This function should only be called after the channel in WaitChannel()
|
|
||||||
// is closed. Otherwise it is not thread safe.
|
|
||||||
WaitError() 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]*notificationWatcherContext{} |
|
||||||
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 notificationWatcherContext 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,343 +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 a procedure look up fails.
|
|
||||||
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") |
|
||||||
|
|
||||||
// ErrProcessAlreadyStopped is returned by hcs if the process we're trying to kill has already been stopped.
|
|
||||||
ErrProcessAlreadyStopped = syscall.Errno(0x8037011f) |
|
||||||
|
|
||||||
// ErrInvalidHandle is an error that can be encountrered when querying the properties of a compute system when the handle to that
|
|
||||||
// compute system has already been closed.
|
|
||||||
ErrInvalidHandle = syscall.Errno(0x6) |
|
||||||
) |
|
||||||
|
|
||||||
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() //nolint:staticcheck
|
|
||||||
} |
|
||||||
|
|
||||||
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() //nolint:staticcheck
|
|
||||||
} |
|
||||||
|
|
||||||
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() //nolint:staticcheck
|
|
||||||
} |
|
||||||
|
|
||||||
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.
|
|
||||||
func IsNotExist(err error) bool { |
|
||||||
err = getInnerError(err) |
|
||||||
return err == ErrComputeSystemDoesNotExist || |
|
||||||
err == ErrElementNotFound |
|
||||||
} |
|
||||||
|
|
||||||
// IsErrorInvalidHandle checks whether the error is the result of an operation carried
|
|
||||||
// out on a handle that is invalid/closed. This error popped up while trying to query
|
|
||||||
// stats on a container in the process of being stopped.
|
|
||||||
func IsErrorInvalidHandle(err error) bool { |
|
||||||
err = getInnerError(err) |
|
||||||
return err == ErrInvalidHandle |
|
||||||
} |
|
||||||
|
|
||||||
// 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.
|
|
||||||
func IsAlreadyStopped(err error) bool { |
|
||||||
err = getInnerError(err) |
|
||||||
return err == ErrVmcomputeAlreadyStopped || |
|
||||||
err == ErrProcessAlreadyStopped || |
|
||||||
err == ErrElementNotFound |
|
||||||
} |
|
||||||
|
|
||||||
// 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,557 +0,0 @@ |
|||||||
package hcs |
|
||||||
|
|
||||||
import ( |
|
||||||
"context" |
|
||||||
"encoding/json" |
|
||||||
"errors" |
|
||||||
"io" |
|
||||||
"os" |
|
||||||
"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 |
|
||||||
killSignalDelivered bool |
|
||||||
|
|
||||||
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 := "hcs::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 := "hcs::Process::Kill" |
|
||||||
|
|
||||||
if process.handle == 0 { |
|
||||||
return false, makeProcessError(process, operation, ErrAlreadyClosed, nil) |
|
||||||
} |
|
||||||
|
|
||||||
if process.killSignalDelivered { |
|
||||||
// A kill signal has already been sent to this process. Sending a second
|
|
||||||
// one offers no real benefit, as processes cannot stop themselves from
|
|
||||||
// being terminated, once a TerminateProcess has been issued. Sending a
|
|
||||||
// second kill may result in a number of errors (two of which detailed bellow)
|
|
||||||
// and which we can avoid handling.
|
|
||||||
return true, nil |
|
||||||
} |
|
||||||
|
|
||||||
resultJSON, err := vmcompute.HcsTerminateProcess(ctx, process.handle) |
|
||||||
if err != nil { |
|
||||||
// We still need to check these two cases, as processes may still be killed by an
|
|
||||||
// external actor (human operator, OOM, random script etc).
|
|
||||||
if errors.Is(err, os.ErrPermission) || IsAlreadyStopped(err) { |
|
||||||
// There are two cases where it should be safe to ignore an error returned
|
|
||||||
// by HcsTerminateProcess. The first one is cause by the fact that
|
|
||||||
// HcsTerminateProcess ends up calling TerminateProcess in the context
|
|
||||||
// of a container. According to the TerminateProcess documentation:
|
|
||||||
// https://docs.microsoft.com/en-us/windows/win32/api/processthreadsapi/nf-processthreadsapi-terminateprocess#remarks
|
|
||||||
// After a process has terminated, call to TerminateProcess with open
|
|
||||||
// handles to the process fails with ERROR_ACCESS_DENIED (5) error code.
|
|
||||||
// It's safe to ignore this error here. HCS should always have permissions
|
|
||||||
// to kill processes inside any container. So an ERROR_ACCESS_DENIED
|
|
||||||
// is unlikely to be anything else than what the ending remarks in the
|
|
||||||
// documentation states.
|
|
||||||
//
|
|
||||||
// The second case is generated by hcs itself, if for any reason HcsTerminateProcess
|
|
||||||
// is called twice in a very short amount of time. In such cases, hcs may return
|
|
||||||
// HCS_E_PROCESS_ALREADY_STOPPED.
|
|
||||||
return true, nil |
|
||||||
} |
|
||||||
} |
|
||||||
events := processHcsResult(ctx, resultJSON) |
|
||||||
delivered, err := process.processSignalResult(ctx, err) |
|
||||||
if err != nil { |
|
||||||
err = makeProcessError(process, operation, err, events) |
|
||||||
} |
|
||||||
|
|
||||||
process.killSignalDelivered = delivered |
|
||||||
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 := "hcs::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 := "hcs::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, "hcs::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 := "hcs::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 := "hcs::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 |
|
||||||
} |
|
||||||
|
|
||||||
func (process *Process) CloseStdout(ctx context.Context) (err error) { |
|
||||||
ctx, span := trace.StartSpan(ctx, "hcs::Process::CloseStdout") //nolint:ineffassign,staticcheck
|
|
||||||
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() |
|
||||||
|
|
||||||
if process.handle == 0 { |
|
||||||
return nil |
|
||||||
} |
|
||||||
|
|
||||||
process.stdioLock.Lock() |
|
||||||
defer process.stdioLock.Unlock() |
|
||||||
if process.stdout != nil { |
|
||||||
process.stdout.Close() |
|
||||||
process.stdout = nil |
|
||||||
} |
|
||||||
return nil |
|
||||||
} |
|
||||||
|
|
||||||
func (process *Process) CloseStderr(ctx context.Context) (err error) { |
|
||||||
ctx, span := trace.StartSpan(ctx, "hcs::Process::CloseStderr") //nolint:ineffassign,staticcheck
|
|
||||||
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() |
|
||||||
|
|
||||||
if process.handle == 0 { |
|
||||||
return nil |
|
||||||
} |
|
||||||
|
|
||||||
process.stdioLock.Lock() |
|
||||||
defer process.stdioLock.Unlock() |
|
||||||
if process.stderr != nil { |
|
||||||
process.stderr.Close() |
|
||||||
process.stderr = nil |
|
||||||
|
|
||||||
} |
|
||||||
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 := "hcs::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 := ¬ificationWatcherContext{ |
|
||||||
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,250 +0,0 @@ |
|||||||
package schema1 |
|
||||||
|
|
||||||
import ( |
|
||||||
"encoding/json" |
|
||||||
"time" |
|
||||||
|
|
||||||
"github.com/Microsoft/go-winio/pkg/guid" |
|
||||||
hcsschema "github.com/Microsoft/hcsshim/internal/hcs/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,36 +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"` |
|
||||||
|
|
||||||
SupportCompressedVolumes bool `json:"SupportCompressedVolumes,omitempty"` |
|
||||||
|
|
||||||
AlwaysAllowSparseFiles bool `json:"AlwaysAllowSparseFiles,omitempty"` |
|
||||||
|
|
||||||
ExtensibleVirtualDiskType string `json:"ExtensibleVirtualDiskType,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/hcs/schema2/cache_query_stats_response.go
generated
vendored
18
vendor/github.com/Microsoft/hcsshim/internal/hcs/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,36 +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"` |
|
||||||
|
|
||||||
AdditionalDeviceNamespace *ContainerDefinitionDevice `json:"AdditionalDeviceNamespace,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"` |
|
||||||
} |
|
@ -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/hcs/schema2/container_memory_information.go
generated
vendored
25
vendor/github.com/Microsoft/hcsshim/internal/hcs/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"` |
|
||||||
} |
|
15
vendor/github.com/Microsoft/hcsshim/internal/hcs/schema2/cpu_group_affinity.go
generated
vendored
15
vendor/github.com/Microsoft/hcsshim/internal/hcs/schema2/cpu_group_affinity.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 |
|
||||||
|
|
||||||
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 uint64 `json:"HypervisorGroupId,omitempty"` |
|
||||||
} |
|
15
vendor/github.com/Microsoft/hcsshim/internal/hcs/schema2/cpu_group_configurations.go
generated
vendored
15
vendor/github.com/Microsoft/hcsshim/internal/hcs/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"` |
|
||||||
} |
|
18
vendor/github.com/Microsoft/hcsshim/internal/hcs/schema2/cpu_group_operations.go
generated
vendored
18
vendor/github.com/Microsoft/hcsshim/internal/hcs/schema2/cpu_group_operations.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.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" |
|
||||||
) |
|
15
vendor/github.com/Microsoft/hcsshim/internal/hcs/schema2/cpu_group_property.go
generated
vendored
15
vendor/github.com/Microsoft/hcsshim/internal/hcs/schema2/cpu_group_property.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 |
|
||||||
|
|
||||||
type CpuGroupProperty struct { |
|
||||||
PropertyCode uint32 `json:"PropertyCode,omitempty"` |
|
||||||
PropertyValue uint32 `json:"PropertyValue,omitempty"` |
|
||||||
} |
|
17
vendor/github.com/Microsoft/hcsshim/internal/hcs/schema2/create_group_operation.go
generated
vendored
17
vendor/github.com/Microsoft/hcsshim/internal/hcs/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/hcs/schema2/delete_group_operation.go
generated
vendored
15
vendor/github.com/Microsoft/hcsshim/internal/hcs/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" |
|
||||||
DeviceInstanceID 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 DeviceInstanceID.
|
|
||||||
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"` |
|
||||||
} |
|
14
vendor/github.com/Microsoft/hcsshim/internal/hcs/schema2/enhanced_mode_video.go
generated
vendored
14
vendor/github.com/Microsoft/hcsshim/internal/hcs/schema2/enhanced_mode_video.go
generated
vendored
@ -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"` |
|
||||||
} |
|
18
vendor/github.com/Microsoft/hcsshim/internal/hcs/schema2/flexible_io_device.go
generated
vendored
18
vendor/github.com/Microsoft/hcsshim/internal/hcs/schema2/flexible_io_device.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 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"` |
|
||||||
} |
|
21
vendor/github.com/Microsoft/hcsshim/internal/hcs/schema2/guest_connection_info.go
generated
vendored
21
vendor/github.com/Microsoft/hcsshim/internal/hcs/schema2/guest_connection_info.go
generated
vendored
@ -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"` |
|
||||||
} |
|
14
vendor/github.com/Microsoft/hcsshim/internal/hcs/schema2/guest_crash_reporting.go
generated
vendored
14
vendor/github.com/Microsoft/hcsshim/internal/hcs/schema2/guest_crash_reporting.go
generated
vendored
@ -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"` |
|
||||||
} |
|
@ -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"` |
|
||||||
} |
|
@ -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 |
|
||||||
|
|
||||||
// This class defines address settings applied to a VM
|
|
||||||
// by the GCS every time a VM starts or restores.
|
|
||||||
type HvSocketAddress struct { |
|
||||||
LocalAddress string `json:"LocalAddress,omitempty"` |
|
||||||
ParentAddress string `json:"ParentAddress,omitempty"` |
|
||||||
} |
|
28
vendor/github.com/Microsoft/hcsshim/internal/hcs/schema2/hv_socket_service_config.go
generated
vendored
28
vendor/github.com/Microsoft/hcsshim/internal/hcs/schema2/hv_socket_service_config.go
generated
vendored
@ -1,28 +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 HvSocketServiceConfig struct { |
|
||||||
|
|
||||||
// SDDL string that HvSocket will check before allowing a host process to bind to this specific service. If not specified, defaults to the system DefaultBindSecurityDescriptor, defined in HvSocketSystemWpConfig in V1.
|
|
||||||
BindSecurityDescriptor string `json:"BindSecurityDescriptor,omitempty"` |
|
||||||
|
|
||||||
// SDDL string that HvSocket will check before allowing a host process to connect to this specific service. If not specified, defaults to the system DefaultConnectSecurityDescriptor, defined in HvSocketSystemWpConfig in V1.
|
|
||||||
ConnectSecurityDescriptor string `json:"ConnectSecurityDescriptor,omitempty"` |
|
||||||
|
|
||||||
// If true, HvSocket will process wildcard binds for this service/system combination. Wildcard binds are secured in the registry at SOFTWARE/Microsoft/Windows NT/CurrentVersion/Virtualization/HvSocket/WildcardDescriptors
|
|
||||||
AllowWildcardBinds bool `json:"AllowWildcardBinds,omitempty"` |
|
||||||
|
|
||||||
// Disabled controls whether the HvSocket service is accepting connection requests.
|
|
||||||
// This set to true will make the service refuse all incoming connections as well as cancel
|
|
||||||
// any connections already established. The service itself will still be active however
|
|
||||||
// and can be re-enabled at a future time.
|
|
||||||
Disabled bool `json:"Disabled,omitempty"` |
|
||||||
} |
|
22
vendor/github.com/Microsoft/hcsshim/internal/hcs/schema2/hv_socket_system_config.go
generated
vendored
22
vendor/github.com/Microsoft/hcsshim/internal/hcs/schema2/hv_socket_system_config.go
generated
vendored
@ -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 |
|
||||||
|
|
||||||
// This is the HCS Schema version of the HvSocket configuration. The VMWP version is located in Config.Devices.IC in V1.
|
|
||||||
type HvSocketSystemConfig struct { |
|
||||||
|
|
||||||
// SDDL string that HvSocket will check before allowing a host process to bind to an unlisted service for this specific container/VM (not wildcard binds).
|
|
||||||
DefaultBindSecurityDescriptor string `json:"DefaultBindSecurityDescriptor,omitempty"` |
|
||||||
|
|
||||||
// SDDL string that HvSocket will check before allowing a host process to connect to an unlisted service in the VM/container.
|
|
||||||
DefaultConnectSecurityDescriptor string `json:"DefaultConnectSecurityDescriptor,omitempty"` |
|
||||||
|
|
||||||
ServiceTable map[string]HvSocketServiceConfig `json:"ServiceTable,omitempty"` |
|
||||||
} |
|
42
vendor/github.com/Microsoft/hcsshim/internal/hcs/schema2/interrupt_moderation_mode.go
generated
vendored
42
vendor/github.com/Microsoft/hcsshim/internal/hcs/schema2/interrupt_moderation_mode.go
generated
vendored
@ -1,42 +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 InterruptModerationName string |
|
||||||
|
|
||||||
// The valid interrupt moderation modes for I/O virtualization (IOV) offloading.
|
|
||||||
const ( |
|
||||||
DefaultName InterruptModerationName = "Default" |
|
||||||
AdaptiveName InterruptModerationName = "Adaptive" |
|
||||||
OffName InterruptModerationName = "Off" |
|
||||||
LowName InterruptModerationName = "Low" |
|
||||||
MediumName InterruptModerationName = "Medium" |
|
||||||
HighName InterruptModerationName = "High" |
|
||||||
) |
|
||||||
|
|
||||||
type InterruptModerationValue uint32 |
|
||||||
|
|
||||||
const ( |
|
||||||
DefaultValue InterruptModerationValue = iota |
|
||||||
AdaptiveValue |
|
||||||
OffValue |
|
||||||
LowValue InterruptModerationValue = 100 |
|
||||||
MediumValue InterruptModerationValue = 200 |
|
||||||
HighValue InterruptModerationValue = 300 |
|
||||||
) |
|
||||||
|
|
||||||
var InterruptModerationValueToName = map[InterruptModerationValue]InterruptModerationName{ |
|
||||||
DefaultValue: DefaultName, |
|
||||||
AdaptiveValue: AdaptiveName, |
|
||||||
OffValue: OffName, |
|
||||||
LowValue: LowName, |
|
||||||
MediumValue: MediumName, |
|
||||||
HighValue: HighName, |
|
||||||
} |
|
@ -1,22 +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 IovSettings struct { |
|
||||||
// The weight assigned to this port for I/O virtualization (IOV) offloading.
|
|
||||||
// Setting this to 0 disables IOV offloading.
|
|
||||||
OffloadWeight *uint32 `json:"OffloadWeight,omitempty"` |
|
||||||
|
|
||||||
// The number of queue pairs requested for this port for I/O virtualization (IOV) offloading.
|
|
||||||
QueuePairsRequested *uint32 `json:"QueuePairsRequested,omitempty"` |
|
||||||
|
|
||||||
// The interrupt moderation mode for I/O virtualization (IOV) offloading.
|
|
||||||
InterruptModeration *InterruptModerationName `json:"InterruptModeration,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 Keyboard struct { |
|
||||||
} |
|
@ -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 |
|
||||||
|
|
||||||
type Layer struct { |
|
||||||
Id string `json:"Id,omitempty"` |
|
||||||
|
|
||||||
Path string `json:"Path,omitempty"` |
|
||||||
|
|
||||||
PathType string `json:"PathType,omitempty"` |
|
||||||
|
|
||||||
// Unspecified defaults to Enabled
|
|
||||||
Cache string `json:"Cache,omitempty"` |
|
||||||
} |
|
18
vendor/github.com/Microsoft/hcsshim/internal/hcs/schema2/linux_kernel_direct.go
generated
vendored
18
vendor/github.com/Microsoft/hcsshim/internal/hcs/schema2/linux_kernel_direct.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.2 |
|
||||||
* Generated by: Swagger Codegen (https://github.com/swagger-api/swagger-codegen.git)
|
|
||||||
*/ |
|
||||||
|
|
||||||
package hcsschema |
|
||||||
|
|
||||||
type LinuxKernelDirect struct { |
|
||||||
KernelFilePath string `json:"KernelFilePath,omitempty"` |
|
||||||
|
|
||||||
InitRdPath string `json:"InitRdPath,omitempty"` |
|
||||||
|
|
||||||
KernelCmdLine string `json:"KernelCmdLine,omitempty"` |
|
||||||
} |
|
@ -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 LogicalProcessor struct { |
|
||||||
LpIndex uint32 `json:"LpIndex,omitempty"` |
|
||||||
NodeNumber uint8 `json:"NodeNumber,omitempty"` |
|
||||||
PackageId uint32 `json:"PackageId,omitempty"` |
|
||||||
CoreId uint32 `json:"CoreId,omitempty"` |
|
||||||
RootVpIndex int32 `json:"RootVpIndex,omitempty"` |
|
||||||
} |
|
@ -1,20 +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 MappedDirectory struct { |
|
||||||
HostPath string `json:"HostPath,omitempty"` |
|
||||||
|
|
||||||
HostPathType string `json:"HostPathType,omitempty"` |
|
||||||
|
|
||||||
ContainerPath string `json:"ContainerPath,omitempty"` |
|
||||||
|
|
||||||
ReadOnly bool `json:"ReadOnly,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 MappedPipe struct { |
|
||||||
ContainerPipeName string `json:"ContainerPipeName,omitempty"` |
|
||||||
|
|
||||||
HostPath string `json:"HostPath,omitempty"` |
|
||||||
|
|
||||||
HostPathType string `json:"HostPathType,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 Memory struct { |
|
||||||
SizeInMB uint64 `json:"SizeInMB,omitempty"` |
|
||||||
} |
|
@ -1,49 +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 Memory2 struct { |
|
||||||
SizeInMB uint64 `json:"SizeInMB,omitempty"` |
|
||||||
|
|
||||||
AllowOvercommit bool `json:"AllowOvercommit,omitempty"` |
|
||||||
|
|
||||||
EnableHotHint bool `json:"EnableHotHint,omitempty"` |
|
||||||
|
|
||||||
EnableColdHint bool `json:"EnableColdHint,omitempty"` |
|
||||||
|
|
||||||
EnableEpf bool `json:"EnableEpf,omitempty"` |
|
||||||
|
|
||||||
// EnableDeferredCommit is private in the schema. If regenerated need to add back.
|
|
||||||
EnableDeferredCommit bool `json:"EnableDeferredCommit,omitempty"` |
|
||||||
|
|
||||||
// EnableColdDiscardHint if enabled, then the memory cold discard hint feature is exposed
|
|
||||||
// to the VM, allowing it to trim non-zeroed pages from the working set (if supported by
|
|
||||||
// the guest operating system).
|
|
||||||
EnableColdDiscardHint bool `json:"EnableColdDiscardHint,omitempty"` |
|
||||||
|
|
||||||
// LowMmioGapInMB is the low MMIO region allocated below 4GB.
|
|
||||||
//
|
|
||||||
// TODO: This is pre-release support in schema 2.3. Need to add build number
|
|
||||||
// docs when a public build with this is out.
|
|
||||||
LowMMIOGapInMB uint64 `json:"LowMmioGapInMB,omitempty"` |
|
||||||
|
|
||||||
// HighMmioBaseInMB is the high MMIO region allocated above 4GB (base and
|
|
||||||
// size).
|
|
||||||
//
|
|
||||||
// TODO: This is pre-release support in schema 2.3. Need to add build number
|
|
||||||
// docs when a public build with this is out.
|
|
||||||
HighMMIOBaseInMB uint64 `json:"HighMmioBaseInMB,omitempty"` |
|
||||||
|
|
||||||
// HighMmioGapInMB is the high MMIO region.
|
|
||||||
//
|
|
||||||
// TODO: This is pre-release support in schema 2.3. Need to add build number
|
|
||||||
// docs when a public build with this is out.
|
|
||||||
HighMMIOGapInMB uint64 `json:"HighMmioGapInMB,omitempty"` |
|
||||||
} |
|
18
vendor/github.com/Microsoft/hcsshim/internal/hcs/schema2/memory_information_for_vm.go
generated
vendored
18
vendor/github.com/Microsoft/hcsshim/internal/hcs/schema2/memory_information_for_vm.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 MemoryInformationForVm struct { |
|
||||||
VirtualNodeCount uint32 `json:"VirtualNodeCount,omitempty"` |
|
||||||
|
|
||||||
VirtualMachineMemory *VmMemory `json:"VirtualMachineMemory,omitempty"` |
|
||||||
|
|
||||||
VirtualNodes []VirtualNodeInfo `json:"VirtualNodes,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 |
|
||||||
|
|
||||||
// Memory runtime statistics
|
|
||||||
type MemoryStats struct { |
|
||||||
MemoryUsageCommitBytes uint64 `json:"MemoryUsageCommitBytes,omitempty"` |
|
||||||
|
|
||||||
MemoryUsageCommitPeakBytes uint64 `json:"MemoryUsageCommitPeakBytes,omitempty"` |
|
||||||
|
|
||||||
MemoryUsagePrivateWorkingSetBytes uint64 `json:"MemoryUsagePrivateWorkingSetBytes,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 ContainerDefinitionDevice struct { |
|
||||||
DeviceExtension []DeviceExtension `json:"device_extension,omitempty"` |
|
||||||
} |
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in new issue