Merge pull request #946 from containernetworking/dependabot/go_modules/github.com/Microsoft/hcsshim-0.11.1

build(deps): bump github.com/Microsoft/hcsshim from 0.9.9 to 0.11.1
This commit is contained in:
Casey Callendrello 2023-10-16 17:23:25 +02:00 committed by GitHub
commit e727ad6697
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
339 changed files with 49928 additions and 3279 deletions

10
go.mod
View File

@ -3,7 +3,7 @@ module github.com/containernetworking/plugins
go 1.20 go 1.20
require ( require (
github.com/Microsoft/hcsshim v0.9.9 github.com/Microsoft/hcsshim v0.11.1
github.com/alexflint/go-filemutex v1.2.0 github.com/alexflint/go-filemutex v1.2.0
github.com/buger/jsonparser v1.1.1 github.com/buger/jsonparser v1.1.1
github.com/containernetworking/cni v1.1.2 github.com/containernetworking/cni v1.1.2
@ -24,12 +24,15 @@ require (
) )
require ( require (
github.com/Microsoft/go-winio v0.6.0 // indirect github.com/Microsoft/go-winio v0.6.1 // indirect
github.com/containerd/cgroups v1.1.0 // indirect github.com/containerd/cgroups v1.1.0 // indirect
github.com/containerd/containerd v1.6.23 // indirect
github.com/d2g/hardwareaddr v0.0.0-20190221164911-e7d9fbe030e4 // indirect
github.com/go-logr/logr v1.2.4 // indirect github.com/go-logr/logr v1.2.4 // indirect
github.com/go-task/slim-sprig v0.0.0-20230315185526-52ccab3ef572 // indirect github.com/go-task/slim-sprig v0.0.0-20230315185526-52ccab3ef572 // indirect
github.com/gogo/protobuf v1.3.2 // indirect github.com/gogo/protobuf v1.3.2 // indirect
github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da // indirect github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da // indirect
github.com/golang/protobuf v1.5.3 // indirect
github.com/google/go-cmp v0.5.9 // indirect github.com/google/go-cmp v0.5.9 // indirect
github.com/google/pprof v0.0.0-20230323073829-e72429f035bd // indirect github.com/google/pprof v0.0.0-20230323073829-e72429f035bd // indirect
github.com/pkg/errors v0.9.1 // indirect github.com/pkg/errors v0.9.1 // indirect
@ -40,5 +43,8 @@ require (
golang.org/x/net v0.10.0 // indirect golang.org/x/net v0.10.0 // indirect
golang.org/x/text v0.9.0 // indirect golang.org/x/text v0.9.0 // indirect
golang.org/x/tools v0.9.3 // indirect golang.org/x/tools v0.9.3 // indirect
google.golang.org/genproto v0.0.0-20220502173005-c8bf987b8c21 // indirect
google.golang.org/grpc v1.50.1 // indirect
google.golang.org/protobuf v1.29.1 // indirect
gopkg.in/yaml.v3 v3.0.1 // indirect gopkg.in/yaml.v3 v3.0.1 // indirect
) )

856
go.sum

File diff suppressed because it is too large Load Diff

View File

@ -8,12 +8,8 @@ linters:
- containedctx # struct contains a context - containedctx # struct contains a context
- dupl # duplicate code - dupl # duplicate code
- errname # erorrs are named correctly - errname # erorrs are named correctly
- goconst # strings that should be constants
- godot # comments end in a period
- misspell
- nolintlint # "//nolint" directives are properly explained - nolintlint # "//nolint" directives are properly explained
- revive # golint replacement - revive # golint replacement
- stylecheck # golint replacement, less configurable than revive
- unconvert # unnecessary conversions - unconvert # unnecessary conversions
- wastedassign - wastedassign
@ -23,10 +19,7 @@ linters:
- exhaustive # check exhaustiveness of enum switch statements - exhaustive # check exhaustiveness of enum switch statements
- gofmt # files are gofmt'ed - gofmt # files are gofmt'ed
- gosec # security - gosec # security
- nestif # deeply nested ifs
- nilerr # returns nil even with non-nil error - nilerr # returns nil even with non-nil error
- prealloc # slices that can be pre-allocated
- structcheck # unused struct fields
- unparam # unused function params - unparam # unused function params
issues: issues:
@ -42,6 +35,18 @@ issues:
text: "^line-length-limit: " text: "^line-length-limit: "
source: "^//(go:generate|sys) " source: "^//(go:generate|sys) "
#TODO: remove after upgrading to go1.18
# ignore comment spacing for nolint and sys directives
- linters:
- revive
text: "^comment-spacings: no space between comment delimiter and comment text"
source: "//(cspell:|nolint:|sys |todo)"
# not on go 1.18 yet, so no any
- linters:
- revive
text: "^use-any: since GO 1.18 'interface{}' can be replaced by 'any'"
# allow unjustified ignores of error checks in defer statements # allow unjustified ignores of error checks in defer statements
- linters: - linters:
- nolintlint - nolintlint
@ -56,6 +61,8 @@ issues:
linters-settings: linters-settings:
exhaustive:
default-signifies-exhaustive: true
govet: govet:
enable-all: true enable-all: true
disable: disable:
@ -98,6 +105,8 @@ linters-settings:
disabled: true disabled: true
- name: flag-parameter # excessive, and a common idiom we use - name: flag-parameter # excessive, and a common idiom we use
disabled: true disabled: true
- name: unhandled-error # warns over common fmt.Print* and io.Close; rely on errcheck instead
disabled: true
# general config # general config
- name: line-length-limit - name: line-length-limit
arguments: arguments:
@ -138,7 +147,3 @@ linters-settings:
- VPCI - VPCI
- WCOW - WCOW
- WIM - WIM
stylecheck:
checks:
- "all"
- "-ST1003" # use revive's var naming

View File

@ -23,7 +23,7 @@ import (
const afHVSock = 34 // AF_HYPERV const afHVSock = 34 // AF_HYPERV
// Well known Service and VM IDs // Well known Service and VM IDs
//https://docs.microsoft.com/en-us/virtualization/hyper-v-on-windows/user-guide/make-integration-service#vmid-wildcards // https://docs.microsoft.com/en-us/virtualization/hyper-v-on-windows/user-guide/make-integration-service#vmid-wildcards
// HvsockGUIDWildcard is the wildcard VmId for accepting connections from all partitions. // HvsockGUIDWildcard is the wildcard VmId for accepting connections from all partitions.
func HvsockGUIDWildcard() guid.GUID { // 00000000-0000-0000-0000-000000000000 func HvsockGUIDWildcard() guid.GUID { // 00000000-0000-0000-0000-000000000000
@ -31,7 +31,7 @@ func HvsockGUIDWildcard() guid.GUID { // 00000000-0000-0000-0000-000000000000
} }
// HvsockGUIDBroadcast is the wildcard VmId for broadcasting sends to all partitions. // HvsockGUIDBroadcast is the wildcard VmId for broadcasting sends to all partitions.
func HvsockGUIDBroadcast() guid.GUID { //ffffffff-ffff-ffff-ffff-ffffffffffff func HvsockGUIDBroadcast() guid.GUID { // ffffffff-ffff-ffff-ffff-ffffffffffff
return guid.GUID{ return guid.GUID{
Data1: 0xffffffff, Data1: 0xffffffff,
Data2: 0xffff, Data2: 0xffff,
@ -246,7 +246,7 @@ func (l *HvsockListener) Accept() (_ net.Conn, err error) {
var addrbuf [addrlen * 2]byte var addrbuf [addrlen * 2]byte
var bytes uint32 var bytes uint32
err = syscall.AcceptEx(l.sock.handle, sock.handle, &addrbuf[0], 0 /*rxdatalen*/, addrlen, addrlen, &bytes, &c.o) err = syscall.AcceptEx(l.sock.handle, sock.handle, &addrbuf[0], 0 /* rxdatalen */, addrlen, addrlen, &bytes, &c.o)
if _, err = l.sock.asyncIO(c, nil, bytes, err); err != nil { if _, err = l.sock.asyncIO(c, nil, bytes, err); err != nil {
return nil, l.opErr("accept", os.NewSyscallError("acceptex", err)) return nil, l.opErr("accept", os.NewSyscallError("acceptex", err))
} }

View File

@ -0,0 +1,2 @@
// This package contains Win32 filesystem functionality.
package fs

202
vendor/github.com/Microsoft/go-winio/internal/fs/fs.go generated vendored Normal file
View File

@ -0,0 +1,202 @@
//go:build windows
package fs
import (
"golang.org/x/sys/windows"
"github.com/Microsoft/go-winio/internal/stringbuffer"
)
//go:generate go run github.com/Microsoft/go-winio/tools/mkwinsyscall -output zsyscall_windows.go fs.go
// https://learn.microsoft.com/en-us/windows/win32/api/fileapi/nf-fileapi-createfilew
//sys CreateFile(name string, access AccessMask, mode FileShareMode, sa *syscall.SecurityAttributes, createmode FileCreationDisposition, attrs FileFlagOrAttribute, templatefile windows.Handle) (handle windows.Handle, err error) [failretval==windows.InvalidHandle] = CreateFileW
const NullHandle windows.Handle = 0
// AccessMask defines standard, specific, and generic rights.
//
// Bitmask:
// 3 3 2 2 2 2 2 2 2 2 2 2 1 1 1 1 1 1 1 1 1 1
// 1 0 9 8 7 6 5 4 3 2 1 0 9 8 7 6 5 4 3 2 1 0 9 8 7 6 5 4 3 2 1 0
// +---------------+---------------+-------------------------------+
// |G|G|G|G|Resvd|A| StandardRights| SpecificRights |
// |R|W|E|A| |S| | |
// +-+-------------+---------------+-------------------------------+
//
// GR Generic Read
// GW Generic Write
// GE Generic Exectue
// GA Generic All
// Resvd Reserved
// AS Access Security System
//
// https://learn.microsoft.com/en-us/windows/win32/secauthz/access-mask
//
// https://learn.microsoft.com/en-us/windows/win32/secauthz/generic-access-rights
//
// https://learn.microsoft.com/en-us/windows/win32/fileio/file-access-rights-constants
type AccessMask = windows.ACCESS_MASK
//nolint:revive // SNAKE_CASE is not idiomatic in Go, but aligned with Win32 API.
const (
// Not actually any.
//
// For CreateFile: "query certain metadata such as file, directory, or device attributes without accessing that file or device"
// https://learn.microsoft.com/en-us/windows/win32/api/fileapi/nf-fileapi-createfilew#parameters
FILE_ANY_ACCESS AccessMask = 0
// Specific Object Access
// from ntioapi.h
FILE_READ_DATA AccessMask = (0x0001) // file & pipe
FILE_LIST_DIRECTORY AccessMask = (0x0001) // directory
FILE_WRITE_DATA AccessMask = (0x0002) // file & pipe
FILE_ADD_FILE AccessMask = (0x0002) // directory
FILE_APPEND_DATA AccessMask = (0x0004) // file
FILE_ADD_SUBDIRECTORY AccessMask = (0x0004) // directory
FILE_CREATE_PIPE_INSTANCE AccessMask = (0x0004) // named pipe
FILE_READ_EA AccessMask = (0x0008) // file & directory
FILE_READ_PROPERTIES AccessMask = FILE_READ_EA
FILE_WRITE_EA AccessMask = (0x0010) // file & directory
FILE_WRITE_PROPERTIES AccessMask = FILE_WRITE_EA
FILE_EXECUTE AccessMask = (0x0020) // file
FILE_TRAVERSE AccessMask = (0x0020) // directory
FILE_DELETE_CHILD AccessMask = (0x0040) // directory
FILE_READ_ATTRIBUTES AccessMask = (0x0080) // all
FILE_WRITE_ATTRIBUTES AccessMask = (0x0100) // all
FILE_ALL_ACCESS AccessMask = (STANDARD_RIGHTS_REQUIRED | SYNCHRONIZE | 0x1FF)
FILE_GENERIC_READ AccessMask = (STANDARD_RIGHTS_READ | FILE_READ_DATA | FILE_READ_ATTRIBUTES | FILE_READ_EA | SYNCHRONIZE)
FILE_GENERIC_WRITE AccessMask = (STANDARD_RIGHTS_WRITE | FILE_WRITE_DATA | FILE_WRITE_ATTRIBUTES | FILE_WRITE_EA | FILE_APPEND_DATA | SYNCHRONIZE)
FILE_GENERIC_EXECUTE AccessMask = (STANDARD_RIGHTS_EXECUTE | FILE_READ_ATTRIBUTES | FILE_EXECUTE | SYNCHRONIZE)
SPECIFIC_RIGHTS_ALL AccessMask = 0x0000FFFF
// Standard Access
// from ntseapi.h
DELETE AccessMask = 0x0001_0000
READ_CONTROL AccessMask = 0x0002_0000
WRITE_DAC AccessMask = 0x0004_0000
WRITE_OWNER AccessMask = 0x0008_0000
SYNCHRONIZE AccessMask = 0x0010_0000
STANDARD_RIGHTS_REQUIRED AccessMask = 0x000F_0000
STANDARD_RIGHTS_READ AccessMask = READ_CONTROL
STANDARD_RIGHTS_WRITE AccessMask = READ_CONTROL
STANDARD_RIGHTS_EXECUTE AccessMask = READ_CONTROL
STANDARD_RIGHTS_ALL AccessMask = 0x001F_0000
)
type FileShareMode uint32
//nolint:revive // SNAKE_CASE is not idiomatic in Go, but aligned with Win32 API.
const (
FILE_SHARE_NONE FileShareMode = 0x00
FILE_SHARE_READ FileShareMode = 0x01
FILE_SHARE_WRITE FileShareMode = 0x02
FILE_SHARE_DELETE FileShareMode = 0x04
FILE_SHARE_VALID_FLAGS FileShareMode = 0x07
)
type FileCreationDisposition uint32
//nolint:revive // SNAKE_CASE is not idiomatic in Go, but aligned with Win32 API.
const (
// from winbase.h
CREATE_NEW FileCreationDisposition = 0x01
CREATE_ALWAYS FileCreationDisposition = 0x02
OPEN_EXISTING FileCreationDisposition = 0x03
OPEN_ALWAYS FileCreationDisposition = 0x04
TRUNCATE_EXISTING FileCreationDisposition = 0x05
)
// CreateFile and co. take flags or attributes together as one parameter.
// Define alias until we can use generics to allow both
// https://learn.microsoft.com/en-us/windows/win32/fileio/file-attribute-constants
type FileFlagOrAttribute uint32
//nolint:revive // SNAKE_CASE is not idiomatic in Go, but aligned with Win32 API.
const ( // from winnt.h
FILE_FLAG_WRITE_THROUGH FileFlagOrAttribute = 0x8000_0000
FILE_FLAG_OVERLAPPED FileFlagOrAttribute = 0x4000_0000
FILE_FLAG_NO_BUFFERING FileFlagOrAttribute = 0x2000_0000
FILE_FLAG_RANDOM_ACCESS FileFlagOrAttribute = 0x1000_0000
FILE_FLAG_SEQUENTIAL_SCAN FileFlagOrAttribute = 0x0800_0000
FILE_FLAG_DELETE_ON_CLOSE FileFlagOrAttribute = 0x0400_0000
FILE_FLAG_BACKUP_SEMANTICS FileFlagOrAttribute = 0x0200_0000
FILE_FLAG_POSIX_SEMANTICS FileFlagOrAttribute = 0x0100_0000
FILE_FLAG_OPEN_REPARSE_POINT FileFlagOrAttribute = 0x0020_0000
FILE_FLAG_OPEN_NO_RECALL FileFlagOrAttribute = 0x0010_0000
FILE_FLAG_FIRST_PIPE_INSTANCE FileFlagOrAttribute = 0x0008_0000
)
type FileSQSFlag = FileFlagOrAttribute
//nolint:revive // SNAKE_CASE is not idiomatic in Go, but aligned with Win32 API.
const ( // from winbase.h
SECURITY_ANONYMOUS FileSQSFlag = FileSQSFlag(SecurityAnonymous << 16)
SECURITY_IDENTIFICATION FileSQSFlag = FileSQSFlag(SecurityIdentification << 16)
SECURITY_IMPERSONATION FileSQSFlag = FileSQSFlag(SecurityImpersonation << 16)
SECURITY_DELEGATION FileSQSFlag = FileSQSFlag(SecurityDelegation << 16)
SECURITY_SQOS_PRESENT FileSQSFlag = 0x00100000
SECURITY_VALID_SQOS_FLAGS FileSQSFlag = 0x001F0000
)
// GetFinalPathNameByHandle flags
//
// https://learn.microsoft.com/en-us/windows/win32/api/fileapi/nf-fileapi-getfinalpathnamebyhandlew#parameters
type GetFinalPathFlag uint32
//nolint:revive // SNAKE_CASE is not idiomatic in Go, but aligned with Win32 API.
const (
GetFinalPathDefaultFlag GetFinalPathFlag = 0x0
FILE_NAME_NORMALIZED GetFinalPathFlag = 0x0
FILE_NAME_OPENED GetFinalPathFlag = 0x8
VOLUME_NAME_DOS GetFinalPathFlag = 0x0
VOLUME_NAME_GUID GetFinalPathFlag = 0x1
VOLUME_NAME_NT GetFinalPathFlag = 0x2
VOLUME_NAME_NONE GetFinalPathFlag = 0x4
)
// getFinalPathNameByHandle facilitates calling the Windows API GetFinalPathNameByHandle
// with the given handle and flags. It transparently takes care of creating a buffer of the
// correct size for the call.
//
// https://learn.microsoft.com/en-us/windows/win32/api/fileapi/nf-fileapi-getfinalpathnamebyhandlew
func GetFinalPathNameByHandle(h windows.Handle, flags GetFinalPathFlag) (string, error) {
b := stringbuffer.NewWString()
//TODO: can loop infinitely if Win32 keeps returning the same (or a larger) n?
for {
n, err := windows.GetFinalPathNameByHandle(h, b.Pointer(), b.Cap(), uint32(flags))
if err != nil {
return "", err
}
// If the buffer wasn't large enough, n will be the total size needed (including null terminator).
// Resize and try again.
if n > b.Cap() {
b.ResizeTo(n)
continue
}
// If the buffer is large enough, n will be the size not including the null terminator.
// Convert to a Go string and return.
return b.String(), nil
}
}

View File

@ -0,0 +1,12 @@
package fs
// https://learn.microsoft.com/en-us/windows/win32/api/winnt/ne-winnt-security_impersonation_level
type SecurityImpersonationLevel int32 // C default enums underlying type is `int`, which is Go `int32`
// Impersonation levels
const (
SecurityAnonymous SecurityImpersonationLevel = 0
SecurityIdentification SecurityImpersonationLevel = 1
SecurityImpersonation SecurityImpersonationLevel = 2
SecurityDelegation SecurityImpersonationLevel = 3
)

View File

@ -0,0 +1,64 @@
//go:build windows
// Code generated by 'go generate' using "github.com/Microsoft/go-winio/tools/mkwinsyscall"; DO NOT EDIT.
package fs
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 (
modkernel32 = windows.NewLazySystemDLL("kernel32.dll")
procCreateFileW = modkernel32.NewProc("CreateFileW")
)
func CreateFile(name string, access AccessMask, mode FileShareMode, sa *syscall.SecurityAttributes, createmode FileCreationDisposition, attrs FileFlagOrAttribute, templatefile windows.Handle) (handle windows.Handle, err error) {
var _p0 *uint16
_p0, err = syscall.UTF16PtrFromString(name)
if err != nil {
return
}
return _CreateFile(_p0, access, mode, sa, createmode, attrs, templatefile)
}
func _CreateFile(name *uint16, access AccessMask, mode FileShareMode, sa *syscall.SecurityAttributes, createmode FileCreationDisposition, attrs FileFlagOrAttribute, templatefile windows.Handle) (handle windows.Handle, err error) {
r0, _, e1 := syscall.Syscall9(procCreateFileW.Addr(), 7, uintptr(unsafe.Pointer(name)), uintptr(access), uintptr(mode), uintptr(unsafe.Pointer(sa)), uintptr(createmode), uintptr(attrs), uintptr(templatefile), 0, 0)
handle = windows.Handle(r0)
if handle == windows.InvalidHandle {
err = errnoErr(e1)
}
return
}

View File

@ -100,8 +100,8 @@ func (f *runtimeFunc) Load() error {
(*byte)(unsafe.Pointer(&f.addr)), (*byte)(unsafe.Pointer(&f.addr)),
uint32(unsafe.Sizeof(f.addr)), uint32(unsafe.Sizeof(f.addr)),
&n, &n,
nil, //overlapped nil, // overlapped
0, //completionRoutine 0, // completionRoutine
) )
}) })
return f.err return f.err

View File

@ -0,0 +1,132 @@
package stringbuffer
import (
"sync"
"unicode/utf16"
)
// TODO: worth exporting and using in mkwinsyscall?
// Uint16BufferSize is the buffer size in the pool, chosen somewhat arbitrarily to accommodate
// large path strings:
// MAX_PATH (260) + size of volume GUID prefix (49) + null terminator = 310.
const MinWStringCap = 310
// use *[]uint16 since []uint16 creates an extra allocation where the slice header
// is copied to heap and then referenced via pointer in the interface header that sync.Pool
// stores.
var pathPool = sync.Pool{ // if go1.18+ adds Pool[T], use that to store []uint16 directly
New: func() interface{} {
b := make([]uint16, MinWStringCap)
return &b
},
}
func newBuffer() []uint16 { return *(pathPool.Get().(*[]uint16)) }
// freeBuffer copies the slice header data, and puts a pointer to that in the pool.
// This avoids taking a pointer to the slice header in WString, which can be set to nil.
func freeBuffer(b []uint16) { pathPool.Put(&b) }
// WString is a wide string buffer ([]uint16) meant for storing UTF-16 encoded strings
// for interacting with Win32 APIs.
// Sizes are specified as uint32 and not int.
//
// It is not thread safe.
type WString struct {
// type-def allows casting to []uint16 directly, use struct to prevent that and allow adding fields in the future.
// raw buffer
b []uint16
}
// NewWString returns a [WString] allocated from a shared pool with an
// initial capacity of at least [MinWStringCap].
// Since the buffer may have been previously used, its contents are not guaranteed to be empty.
//
// The buffer should be freed via [WString.Free]
func NewWString() *WString {
return &WString{
b: newBuffer(),
}
}
func (b *WString) Free() {
if b.empty() {
return
}
freeBuffer(b.b)
b.b = nil
}
// ResizeTo grows the buffer to at least c and returns the new capacity, freeing the
// previous buffer back into pool.
func (b *WString) ResizeTo(c uint32) uint32 {
// allready sufficient (or n is 0)
if c <= b.Cap() {
return b.Cap()
}
if c <= MinWStringCap {
c = MinWStringCap
}
// allocate at-least double buffer size, as is done in [bytes.Buffer] and other places
if c <= 2*b.Cap() {
c = 2 * b.Cap()
}
b2 := make([]uint16, c)
if !b.empty() {
copy(b2, b.b)
freeBuffer(b.b)
}
b.b = b2
return c
}
// Buffer returns the underlying []uint16 buffer.
func (b *WString) Buffer() []uint16 {
if b.empty() {
return nil
}
return b.b
}
// Pointer returns a pointer to the first uint16 in the buffer.
// If the [WString.Free] has already been called, the pointer will be nil.
func (b *WString) Pointer() *uint16 {
if b.empty() {
return nil
}
return &b.b[0]
}
// String returns the returns the UTF-8 encoding of the UTF-16 string in the buffer.
//
// It assumes that the data is null-terminated.
func (b *WString) String() string {
// Using [windows.UTF16ToString] would require importing "golang.org/x/sys/windows"
// and would make this code Windows-only, which makes no sense.
// So copy UTF16ToString code into here.
// If other windows-specific code is added, switch to [windows.UTF16ToString]
s := b.b
for i, v := range s {
if v == 0 {
s = s[:i]
break
}
}
return string(utf16.Decode(s))
}
// Cap returns the underlying buffer capacity.
func (b *WString) Cap() uint32 {
if b.empty() {
return 0
}
return b.cap()
}
func (b *WString) cap() uint32 { return uint32(cap(b.b)) }
func (b *WString) empty() bool { return b == nil || b.cap() == 0 }

View File

@ -16,11 +16,12 @@ import (
"unsafe" "unsafe"
"golang.org/x/sys/windows" "golang.org/x/sys/windows"
"github.com/Microsoft/go-winio/internal/fs"
) )
//sys connectNamedPipe(pipe syscall.Handle, o *syscall.Overlapped) (err error) = ConnectNamedPipe //sys connectNamedPipe(pipe syscall.Handle, o *syscall.Overlapped) (err error) = ConnectNamedPipe
//sys createNamedPipe(name string, flags uint32, pipeMode uint32, maxInstances uint32, outSize uint32, inSize uint32, defaultTimeout uint32, sa *syscall.SecurityAttributes) (handle syscall.Handle, err error) [failretval==syscall.InvalidHandle] = CreateNamedPipeW //sys createNamedPipe(name string, flags uint32, pipeMode uint32, maxInstances uint32, outSize uint32, inSize uint32, defaultTimeout uint32, sa *syscall.SecurityAttributes) (handle syscall.Handle, err error) [failretval==syscall.InvalidHandle] = CreateNamedPipeW
//sys createFile(name string, access uint32, mode uint32, sa *syscall.SecurityAttributes, createmode uint32, attrs uint32, templatefile syscall.Handle) (handle syscall.Handle, err error) [failretval==syscall.InvalidHandle] = CreateFileW
//sys getNamedPipeInfo(pipe syscall.Handle, flags *uint32, outSize *uint32, inSize *uint32, maxInstances *uint32) (err error) = GetNamedPipeInfo //sys getNamedPipeInfo(pipe syscall.Handle, flags *uint32, outSize *uint32, inSize *uint32, maxInstances *uint32) (err error) = GetNamedPipeInfo
//sys getNamedPipeHandleState(pipe syscall.Handle, state *uint32, curInstances *uint32, maxCollectionCount *uint32, collectDataTimeout *uint32, userName *uint16, maxUserNameSize uint32) (err error) = GetNamedPipeHandleStateW //sys getNamedPipeHandleState(pipe syscall.Handle, state *uint32, curInstances *uint32, maxCollectionCount *uint32, collectDataTimeout *uint32, userName *uint16, maxUserNameSize uint32) (err error) = GetNamedPipeHandleStateW
//sys localAlloc(uFlags uint32, length uint32) (ptr uintptr) = LocalAlloc //sys localAlloc(uFlags uint32, length uint32) (ptr uintptr) = LocalAlloc
@ -163,19 +164,21 @@ func (s pipeAddress) String() string {
} }
// tryDialPipe attempts to dial the pipe at `path` until `ctx` cancellation or timeout. // tryDialPipe attempts to dial the pipe at `path` until `ctx` cancellation or timeout.
func tryDialPipe(ctx context.Context, path *string, access uint32) (syscall.Handle, error) { func tryDialPipe(ctx context.Context, path *string, access fs.AccessMask) (syscall.Handle, error) {
for { for {
select { select {
case <-ctx.Done(): case <-ctx.Done():
return syscall.Handle(0), ctx.Err() return syscall.Handle(0), ctx.Err()
default: default:
h, err := createFile(*path, wh, err := fs.CreateFile(*path,
access, access,
0, 0, // mode
nil, nil, // security attributes
syscall.OPEN_EXISTING, fs.OPEN_EXISTING,
windows.FILE_FLAG_OVERLAPPED|windows.SECURITY_SQOS_PRESENT|windows.SECURITY_ANONYMOUS, fs.FILE_FLAG_OVERLAPPED|fs.SECURITY_SQOS_PRESENT|fs.SECURITY_ANONYMOUS,
0) 0, // template file handle
)
h := syscall.Handle(wh)
if err == nil { if err == nil {
return h, nil return h, nil
} }
@ -219,7 +222,7 @@ func DialPipeContext(ctx context.Context, path string) (net.Conn, error) {
func DialPipeAccess(ctx context.Context, path string, access uint32) (net.Conn, error) { func DialPipeAccess(ctx context.Context, path string, access uint32) (net.Conn, error) {
var err error var err error
var h syscall.Handle var h syscall.Handle
h, err = tryDialPipe(ctx, &path, access) h, err = tryDialPipe(ctx, &path, fs.AccessMask(access))
if err != nil { if err != nil {
return nil, err return nil, err
} }
@ -279,6 +282,7 @@ func makeServerPipeHandle(path string, sd []byte, c *PipeConfig, first bool) (sy
} }
defer localFree(ntPath.Buffer) defer localFree(ntPath.Buffer)
oa.ObjectName = &ntPath oa.ObjectName = &ntPath
oa.Attributes = windows.OBJ_CASE_INSENSITIVE
// The security descriptor is only needed for the first pipe. // The security descriptor is only needed for the first pipe.
if first { if first {

View File

@ -0,0 +1,57 @@
/*
mkwinsyscall generates windows system call bodies
It parses all files specified on command line containing function
prototypes (like syscall_windows.go) and prints system call bodies
to standard output.
The prototypes are marked by lines beginning with "//sys" and read
like func declarations if //sys is replaced by func, but:
- The parameter lists must give a name for each argument. This
includes return parameters.
- The parameter lists must give a type for each argument:
the (x, y, z int) shorthand is not allowed.
- If the return parameter is an error number, it must be named err.
- If go func name needs to be different from its winapi dll name,
the winapi name could be specified at the end, after "=" sign, like
//sys LoadLibrary(libname string) (handle uint32, err error) = LoadLibraryA
- Each function that returns err needs to supply a condition, that
return value of winapi will be tested against to detect failure.
This would set err to windows "last-error", otherwise it will be nil.
The value can be provided at end of //sys declaration, like
//sys LoadLibrary(libname string) (handle uint32, err error) [failretval==-1] = LoadLibraryA
and is [failretval==0] by default.
- If the function name ends in a "?", then the function not existing is non-
fatal, and an error will be returned instead of panicking.
Usage:
mkwinsyscall [flags] [path ...]
Flags
-output string
Output file name (standard output if omitted).
-sort
Sort DLL and function declarations (default true).
Intended to help transition from older versions of mkwinsyscall by making diffs
easier to read and understand.
-systemdll
Whether all DLLs should be loaded from the Windows system directory (default true).
-trace
Generate print statement after every syscall.
-utf16
Encode string arguments as UTF-16 for syscalls not ending in 'A' or 'W' (default true).
-winio
Import this package ("github.com/Microsoft/go-winio").
*/
package main

File diff suppressed because it is too large Load Diff

View File

@ -63,7 +63,6 @@ var (
procBackupWrite = modkernel32.NewProc("BackupWrite") procBackupWrite = modkernel32.NewProc("BackupWrite")
procCancelIoEx = modkernel32.NewProc("CancelIoEx") procCancelIoEx = modkernel32.NewProc("CancelIoEx")
procConnectNamedPipe = modkernel32.NewProc("ConnectNamedPipe") procConnectNamedPipe = modkernel32.NewProc("ConnectNamedPipe")
procCreateFileW = modkernel32.NewProc("CreateFileW")
procCreateIoCompletionPort = modkernel32.NewProc("CreateIoCompletionPort") procCreateIoCompletionPort = modkernel32.NewProc("CreateIoCompletionPort")
procCreateNamedPipeW = modkernel32.NewProc("CreateNamedPipeW") procCreateNamedPipeW = modkernel32.NewProc("CreateNamedPipeW")
procGetCurrentThread = modkernel32.NewProc("GetCurrentThread") procGetCurrentThread = modkernel32.NewProc("GetCurrentThread")
@ -305,24 +304,6 @@ func connectNamedPipe(pipe syscall.Handle, o *syscall.Overlapped) (err error) {
return return
} }
func createFile(name string, access uint32, mode uint32, sa *syscall.SecurityAttributes, createmode uint32, attrs uint32, templatefile syscall.Handle) (handle syscall.Handle, err error) {
var _p0 *uint16
_p0, err = syscall.UTF16PtrFromString(name)
if err != nil {
return
}
return _createFile(_p0, access, mode, sa, createmode, attrs, templatefile)
}
func _createFile(name *uint16, access uint32, mode uint32, sa *syscall.SecurityAttributes, createmode uint32, attrs uint32, templatefile syscall.Handle) (handle syscall.Handle, err error) {
r0, _, e1 := syscall.Syscall9(procCreateFileW.Addr(), 7, uintptr(unsafe.Pointer(name)), uintptr(access), uintptr(mode), uintptr(unsafe.Pointer(sa)), uintptr(createmode), uintptr(attrs), uintptr(templatefile), 0, 0)
handle = syscall.Handle(r0)
if handle == syscall.InvalidHandle {
err = errnoErr(e1)
}
return
}
func createIoCompletionPort(file syscall.Handle, port syscall.Handle, key uintptr, threadCount uint32) (newport syscall.Handle, err error) { func createIoCompletionPort(file syscall.Handle, port syscall.Handle, key uintptr, threadCount uint32) (newport syscall.Handle, err error) {
r0, _, e1 := syscall.Syscall6(procCreateIoCompletionPort.Addr(), 4, uintptr(file), uintptr(port), uintptr(key), uintptr(threadCount), 0, 0) r0, _, e1 := syscall.Syscall6(procCreateIoCompletionPort.Addr(), 4, uintptr(file), uintptr(port), uintptr(key), uintptr(threadCount), 0, 0)
newport = syscall.Handle(r0) newport = syscall.Handle(r0)

View File

@ -1 +1,3 @@
* text=auto eol=lf * text=auto eol=lf
vendor/** -text
test/vendor/** -text

View File

@ -6,6 +6,7 @@
# Ignore vscode setting files # Ignore vscode setting files
.vscode/ .vscode/
.idea/
# Test binary, build with `go test -c` # Test binary, build with `go test -c`
*.test *.test
@ -23,16 +24,26 @@ service/pkg/
*.img *.img
*.vhd *.vhd
*.tar.gz *.tar.gz
*.tar
# Make stuff # Make stuff
.rootfs-done .rootfs-done
bin/* bin/*
rootfs/* rootfs/*
rootfs-conv/*
*.o *.o
/build/ /build/
deps/* deps/*
out/* out/*
.idea/ # test results
.vscode/ test/results
# go workspace files
go.work
go.work.sum
# keys and related artifacts
*.pem
*.cose

View File

@ -1,23 +1,51 @@
run: run:
timeout: 8m timeout: 8m
tests: true
build-tags:
- admin
- functional
- integration
skip-dirs:
# paths are relative to module root
- cri-containerd/test-images
linters: linters:
enable: enable:
- stylecheck # defaults:
# - errcheck
# - gosimple
# - govet
# - ineffassign
# - staticcheck
# - typecheck
# - unused
- gofmt # whether code was gofmt-ed
- nolintlint # ill-formed or insufficient nolint directives
- stylecheck # golint replacement
- thelper # test helpers without t.Helper()
linters-settings: linters-settings:
stylecheck: stylecheck:
# https://staticcheck.io/docs/checks # https://staticcheck.io/docs/checks
checks: ["all"] checks: ["all"]
issues: 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: exclude-rules:
# path is relative to module root, which is ./test/
- path: cri-containerd
linters:
- stylecheck
text: "^ST1003: should not use underscores in package names$"
source: "^package cri_containerd$"
# 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.
- path: layer.go - path: layer.go
linters: linters:
- stylecheck - stylecheck
@ -28,11 +56,21 @@ issues:
- stylecheck - stylecheck
Text: "ST1003:" Text: "ST1003:"
- path: internal\\hcs\\schema2\\ - path: cmd\\ncproxy\\nodenetsvc\\
linters: linters:
- stylecheck - stylecheck
Text: "ST1003:" Text: "ST1003:"
- path: cmd\\ncproxy_mock\\
linters:
- stylecheck
Text: "ST1003:"
- path: internal\\hcs\\schema2\\
linters:
- stylecheck
- gofmt
- path: internal\\wclayer\\ - path: internal\\wclayer\\
linters: linters:
- stylecheck - stylecheck
@ -96,4 +134,4 @@ issues:
- path: internal\\hcserror\\ - path: internal\\hcserror\\
linters: linters:
- stylecheck - stylecheck
Text: "ST1003:" Text: "ST1003:"

View File

@ -1,4 +1,5 @@
BASE:=base.tar.gz BASE:=base.tar.gz
DEV_BUILD:=0
GO:=go GO:=go
GO_FLAGS:=-ldflags "-s -w" # strip Go binaries GO_FLAGS:=-ldflags "-s -w" # strip Go binaries
@ -12,16 +13,31 @@ GO_FLAGS_EXTRA:=
ifeq "$(GOMODVENDOR)" "1" ifeq "$(GOMODVENDOR)" "1"
GO_FLAGS_EXTRA += -mod=vendor GO_FLAGS_EXTRA += -mod=vendor
endif endif
GO_BUILD_TAGS:=
ifneq ($(strip $(GO_BUILD_TAGS)),)
GO_FLAGS_EXTRA += -tags="$(GO_BUILD_TAGS)"
endif
GO_BUILD:=CGO_ENABLED=$(CGO_ENABLED) $(GO) build $(GO_FLAGS) $(GO_FLAGS_EXTRA) GO_BUILD:=CGO_ENABLED=$(CGO_ENABLED) $(GO) build $(GO_FLAGS) $(GO_FLAGS_EXTRA)
SRCROOT=$(dir $(abspath $(firstword $(MAKEFILE_LIST)))) SRCROOT=$(dir $(abspath $(firstword $(MAKEFILE_LIST))))
# additional directories to search for rule prerequisites and targets
VPATH=$(SRCROOT)
DELTA_TARGET=out/delta.tar.gz
ifeq "$(DEV_BUILD)" "1"
DELTA_TARGET=out/delta-dev.tar.gz
endif
# The link aliases for gcstools # The link aliases for gcstools
GCS_TOOLS=\ GCS_TOOLS=\
generichook generichook \
install-drivers
.PHONY: all always rootfs test .PHONY: all always rootfs test
.DEFAULT_GOAL := all
all: out/initrd.img out/rootfs.tar.gz all: out/initrd.img out/rootfs.tar.gz
clean: clean:
@ -29,21 +45,13 @@ clean:
rm -rf bin deps rootfs out rm -rf bin deps rootfs out
test: test:
cd $(SRCROOT) && go test -v ./internal/guest/... cd $(SRCROOT) && $(GO) test -v ./internal/guest/...
out/delta.tar.gz: bin/init bin/vsockexec bin/cmd/gcs bin/cmd/gcstools Makefile rootfs: out/rootfs.vhd
@mkdir -p out
rm -rf rootfs out/rootfs.vhd: out/rootfs.tar.gz bin/cmd/tar2ext4
mkdir -p rootfs/bin/ gzip -f -d ./out/rootfs.tar.gz
cp bin/init rootfs/ bin/cmd/tar2ext4 -vhd -i ./out/rootfs.tar -o $@
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 out/rootfs.tar.gz: out/initrd.img
rm -rf rootfs-conv rm -rf rootfs-conv
@ -52,27 +60,43 @@ out/rootfs.tar.gz: out/initrd.img
tar -zcf $@ -C rootfs-conv . tar -zcf $@ -C rootfs-conv .
rm -rf rootfs-conv rm -rf rootfs-conv
out/initrd.img: $(BASE) out/delta.tar.gz $(SRCROOT)/hack/catcpio.sh out/initrd.img: $(BASE) $(DELTA_TARGET) $(SRCROOT)/hack/catcpio.sh
$(SRCROOT)/hack/catcpio.sh "$(BASE)" out/delta.tar.gz > out/initrd.img.uncompressed $(SRCROOT)/hack/catcpio.sh "$(BASE)" $(DELTA_TARGET) > out/initrd.img.uncompressed
gzip -c out/initrd.img.uncompressed > $@ gzip -c out/initrd.img.uncompressed > $@
rm out/initrd.img.uncompressed rm out/initrd.img.uncompressed
-include deps/cmd/gcs.gomake # This target includes utilities which may be useful for testing purposes.
-include deps/cmd/gcstools.gomake out/delta-dev.tar.gz: out/delta.tar.gz bin/internal/tools/snp-report
rm -rf rootfs-dev
mkdir rootfs-dev
tar -xzf out/delta.tar.gz -C rootfs-dev
cp bin/internal/tools/snp-report rootfs-dev/bin/
tar -zcf $@ -C rootfs-dev .
rm -rf rootfs-dev
# Implicit rule for includes that define Go targets. out/delta.tar.gz: bin/init bin/vsockexec bin/cmd/gcs bin/cmd/gcstools bin/cmd/hooks/wait-paths Makefile
%.gomake: $(SRCROOT)/Makefile @mkdir -p out
rm -rf rootfs
mkdir -p rootfs/bin/
mkdir -p rootfs/info/
cp bin/init rootfs/
cp bin/vsockexec rootfs/bin/
cp bin/cmd/gcs rootfs/bin/
cp bin/cmd/gcstools rootfs/bin/
cp bin/cmd/hooks/wait-paths rootfs/bin/
for tool in $(GCS_TOOLS); do ln -s gcstools rootfs/bin/$$tool; done
git -C $(SRCROOT) rev-parse HEAD > rootfs/info/gcs.commit && \
git -C $(SRCROOT) rev-parse --abbrev-ref HEAD > rootfs/info/gcs.branch && \
date --iso-8601=minute --utc > rootfs/info/tar.date
$(if $(and $(realpath $(subst .tar,.testdata.json,$(BASE))), $(shell which jq)), \
jq -r '.IMAGE_NAME' $(subst .tar,.testdata.json,$(BASE)) 2>/dev/null > rootfs/info/image.name && \
jq -r '.DATETIME' $(subst .tar,.testdata.json,$(BASE)) 2>/dev/null > rootfs/info/build.date)
tar -zcf $@ -C rootfs .
rm -rf rootfs
bin/cmd/gcs bin/cmd/gcstools bin/cmd/hooks/wait-paths bin/cmd/tar2ext4 bin/internal/tools/snp-report:
@mkdir -p $(dir $@) @mkdir -p $(dir $@)
@/bin/echo $(@:deps/%.gomake=bin/%): $(SRCROOT)/hack/gomakedeps.sh > $@.new GOOS=linux $(GO_BUILD) -o $@ $(SRCROOT)/$(@:bin/%=%)
@/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 bin/vsockexec: vsockexec/vsockexec.o vsockexec/vsock.o
@mkdir -p bin @mkdir -p bin

View File

@ -1,4 +1,4 @@
version = "unstable" version = "1"
generator = "gogoctrd" generator = "gogoctrd"
plugins = ["grpc", "fieldpath"] plugins = ["grpc", "fieldpath"]
@ -14,11 +14,6 @@ plugins = ["grpc", "fieldpath"]
# target package. # target package.
packages = ["github.com/gogo/protobuf"] 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 # This section maps protobuf imports to Go packages. These will become
# `-M` directives in the call to the go protobuf generator. # `-M` directives in the call to the go protobuf generator.
[packages] [packages]
@ -36,6 +31,10 @@ plugins = ["grpc", "fieldpath"]
prefixes = ["github.com/Microsoft/hcsshim/internal/shimdiag"] prefixes = ["github.com/Microsoft/hcsshim/internal/shimdiag"]
plugins = ["ttrpc"] plugins = ["ttrpc"]
[[overrides]]
prefixes = ["github.com/Microsoft/hcsshim/internal/extendedtask"]
plugins = ["ttrpc"]
[[overrides]] [[overrides]]
prefixes = ["github.com/Microsoft/hcsshim/internal/computeagent"] prefixes = ["github.com/Microsoft/hcsshim/internal/computeagent"]
plugins = ["ttrpc"] plugins = ["ttrpc"]

View File

@ -75,24 +75,6 @@ certify they either authored the work themselves or otherwise have permission to
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 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. 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 ## Code of Conduct
This project has adopted the [Microsoft Open Source Code of Conduct](https://opensource.microsoft.com/codeofconduct/). This project has adopted the [Microsoft Open Source Code of Conduct](https://opensource.microsoft.com/codeofconduct/).
@ -101,7 +83,7 @@ contact [opencode@microsoft.com](mailto:opencode@microsoft.com) with any additio
## Dependencies ## Dependencies
This project requires Golang 1.9 or newer to build. This project requires Golang 1.17 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). 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).

41
vendor/github.com/Microsoft/hcsshim/SECURITY.md generated vendored Normal file
View File

@ -0,0 +1,41 @@
<!-- BEGIN MICROSOFT SECURITY.MD V0.0.7 BLOCK -->
## Security
Microsoft takes the security of our software products and services seriously, which includes all source code repositories managed through our GitHub organizations, which include [Microsoft](https://github.com/Microsoft), [Azure](https://github.com/Azure), [DotNet](https://github.com/dotnet), [AspNet](https://github.com/aspnet), [Xamarin](https://github.com/xamarin), and [our GitHub organizations](https://opensource.microsoft.com/).
If you believe you have found a security vulnerability in any Microsoft-owned repository that meets [Microsoft's definition of a security vulnerability](https://aka.ms/opensource/security/definition), please report it to us as described below.
## Reporting Security Issues
**Please do not report security vulnerabilities through public GitHub issues.**
Instead, please report them to the Microsoft Security Response Center (MSRC) at [https://msrc.microsoft.com/create-report](https://aka.ms/opensource/security/create-report).
If you prefer to submit without logging in, send email to [secure@microsoft.com](mailto:secure@microsoft.com). If possible, encrypt your message with our PGP key; please download it from the [Microsoft Security Response Center PGP Key page](https://aka.ms/opensource/security/pgpkey).
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. Additional information can be found at [microsoft.com/msrc](https://aka.ms/opensource/security/msrc).
Please include the requested information listed below (as much as you can provide) to help us better understand the nature and scope of the possible issue:
* Type of issue (e.g. buffer overflow, SQL injection, cross-site scripting, etc.)
* Full paths of source file(s) related to the manifestation of the issue
* The location of the affected source code (tag/branch/commit or direct URL)
* Any special configuration required to reproduce the issue
* Step-by-step instructions to reproduce the issue
* Proof-of-concept or exploit code (if possible)
* Impact of the issue, including how an attacker might exploit the issue
This information will help us triage your report more quickly.
If you are reporting for a bug bounty, more complete reports can contribute to a higher bounty award. Please visit our [Microsoft Bug Bounty Program](https://aka.ms/opensource/security/bounty) page for more details about our active programs.
## Preferred Languages
We prefer all communications to be in English.
## Policy
Microsoft follows the principle of [Coordinated Vulnerability Disclosure](https://aka.ms/opensource/security/cvd).
<!-- END MICROSOFT SECURITY.MD BLOCK -->

View File

@ -1,3 +1,5 @@
//go:build windows
package computestorage package computestorage
import ( import (
@ -17,8 +19,8 @@ import (
// //
// `layerData` is the parent read-only layer data. // `layerData` is the parent read-only layer data.
func AttachLayerStorageFilter(ctx context.Context, layerPath string, layerData LayerData) (err error) { func AttachLayerStorageFilter(ctx context.Context, layerPath string, layerData LayerData) (err error) {
title := "hcsshim.AttachLayerStorageFilter" title := "hcsshim::AttachLayerStorageFilter"
ctx, span := trace.StartSpan(ctx, title) //nolint:ineffassign,staticcheck ctx, span := oc.StartSpan(ctx, title) //nolint:ineffassign,staticcheck
defer span.End() defer span.End()
defer func() { oc.SetSpanStatus(span, err) }() defer func() { oc.SetSpanStatus(span, err) }()
span.AddAttributes( span.AddAttributes(

View File

@ -1,3 +1,5 @@
//go:build windows
package computestorage package computestorage
import ( import (
@ -12,8 +14,8 @@ import (
// //
// `layerPath` is a path to a directory containing the layer to export. // `layerPath` is a path to a directory containing the layer to export.
func DestroyLayer(ctx context.Context, layerPath string) (err error) { func DestroyLayer(ctx context.Context, layerPath string) (err error) {
title := "hcsshim.DestroyLayer" title := "hcsshim::DestroyLayer"
ctx, span := trace.StartSpan(ctx, title) //nolint:ineffassign,staticcheck ctx, span := oc.StartSpan(ctx, title) //nolint:ineffassign,staticcheck
defer span.End() defer span.End()
defer func() { oc.SetSpanStatus(span, err) }() defer func() { oc.SetSpanStatus(span, err) }()
span.AddAttributes(trace.StringAttribute("layerPath", layerPath)) span.AddAttributes(trace.StringAttribute("layerPath", layerPath))

View File

@ -1,3 +1,5 @@
//go:build windows
package computestorage package computestorage
import ( import (
@ -12,8 +14,8 @@ import (
// //
// `layerPath` is a path to a directory containing the layer to export. // `layerPath` is a path to a directory containing the layer to export.
func DetachLayerStorageFilter(ctx context.Context, layerPath string) (err error) { func DetachLayerStorageFilter(ctx context.Context, layerPath string) (err error) {
title := "hcsshim.DetachLayerStorageFilter" title := "hcsshim::DetachLayerStorageFilter"
ctx, span := trace.StartSpan(ctx, title) //nolint:ineffassign,staticcheck ctx, span := oc.StartSpan(ctx, title) //nolint:ineffassign,staticcheck
defer span.End() defer span.End()
defer func() { oc.SetSpanStatus(span, err) }() defer func() { oc.SetSpanStatus(span, err) }()
span.AddAttributes(trace.StringAttribute("layerPath", layerPath)) span.AddAttributes(trace.StringAttribute("layerPath", layerPath))

View File

@ -1,3 +1,5 @@
//go:build windows
package computestorage package computestorage
import ( import (
@ -19,8 +21,8 @@ import (
// //
// `options` are the export options applied to the exported layer. // `options` are the export options applied to the exported layer.
func ExportLayer(ctx context.Context, layerPath, exportFolderPath string, layerData LayerData, options ExportLayerOptions) (err error) { func ExportLayer(ctx context.Context, layerPath, exportFolderPath string, layerData LayerData, options ExportLayerOptions) (err error) {
title := "hcsshim.ExportLayer" title := "hcsshim::ExportLayer"
ctx, span := trace.StartSpan(ctx, title) //nolint:ineffassign,staticcheck ctx, span := oc.StartSpan(ctx, title) //nolint:ineffassign,staticcheck
defer span.End() defer span.End()
defer func() { oc.SetSpanStatus(span, err) }() defer func() { oc.SetSpanStatus(span, err) }()
span.AddAttributes( span.AddAttributes(
@ -28,17 +30,17 @@ func ExportLayer(ctx context.Context, layerPath, exportFolderPath string, layerD
trace.StringAttribute("exportFolderPath", exportFolderPath), trace.StringAttribute("exportFolderPath", exportFolderPath),
) )
ldbytes, err := json.Marshal(layerData) ldBytes, err := json.Marshal(layerData)
if err != nil { if err != nil {
return err return err
} }
obytes, err := json.Marshal(options) oBytes, err := json.Marshal(options)
if err != nil { if err != nil {
return err return err
} }
err = hcsExportLayer(layerPath, exportFolderPath, string(ldbytes), string(obytes)) err = hcsExportLayer(layerPath, exportFolderPath, string(ldBytes), string(oBytes))
if err != nil { if err != nil {
return errors.Wrap(err, "failed to export layer") return errors.Wrap(err, "failed to export layer")
} }

View File

@ -1,3 +1,5 @@
//go:build windows
package computestorage package computestorage
import ( import (
@ -5,16 +7,20 @@ import (
"github.com/Microsoft/hcsshim/internal/oc" "github.com/Microsoft/hcsshim/internal/oc"
"github.com/pkg/errors" "github.com/pkg/errors"
"go.opencensus.io/trace"
"golang.org/x/sys/windows" "golang.org/x/sys/windows"
) )
// FormatWritableLayerVhd formats a virtual disk for use as a writable container layer. // FormatWritableLayerVhd formats a virtual disk for use as a writable container layer.
// //
// If the VHD is not mounted it will be temporarily mounted. // If the VHD is not mounted it will be temporarily mounted.
//
// NOTE: This API had a breaking change in the operating system after Windows Server 2019.
// On ws2019 the API expects to get passed a file handle from CreateFile for the vhd that
// the caller wants to format. On > ws2019, its expected that the caller passes a vhd handle
// that can be obtained from the virtdisk APIs.
func FormatWritableLayerVhd(ctx context.Context, vhdHandle windows.Handle) (err error) { func FormatWritableLayerVhd(ctx context.Context, vhdHandle windows.Handle) (err error) {
title := "hcsshim.FormatWritableLayerVhd" title := "hcsshim::FormatWritableLayerVhd"
ctx, span := trace.StartSpan(ctx, title) //nolint:ineffassign,staticcheck ctx, span := oc.StartSpan(ctx, title) //nolint:ineffassign,staticcheck
defer span.End() defer span.End()
defer func() { oc.SetSpanStatus(span, err) }() defer func() { oc.SetSpanStatus(span, err) }()

View File

@ -1,3 +1,5 @@
//go:build windows
package computestorage package computestorage
import ( import (
@ -6,10 +8,12 @@ import (
"path/filepath" "path/filepath"
"syscall" "syscall"
"github.com/Microsoft/go-winio/pkg/security"
"github.com/Microsoft/go-winio/vhd" "github.com/Microsoft/go-winio/vhd"
"github.com/Microsoft/hcsshim/internal/memory"
"github.com/pkg/errors" "github.com/pkg/errors"
"golang.org/x/sys/windows" "golang.org/x/sys/windows"
"github.com/Microsoft/hcsshim/internal/security"
) )
const defaultVHDXBlockSizeInMB = 1 const defaultVHDXBlockSizeInMB = 1
@ -59,8 +63,8 @@ func SetupContainerBaseLayer(ctx context.Context, layerPath, baseVhdPath, diffVh
createParams := &vhd.CreateVirtualDiskParameters{ createParams := &vhd.CreateVirtualDiskParameters{
Version: 2, Version: 2,
Version2: vhd.CreateVersion2{ Version2: vhd.CreateVersion2{
MaximumSize: sizeInGB * 1024 * 1024 * 1024, MaximumSize: sizeInGB * memory.GiB,
BlockSizeInBytes: defaultVHDXBlockSizeInMB * 1024 * 1024, BlockSizeInBytes: defaultVHDXBlockSizeInMB * memory.MiB,
}, },
} }
handle, err := vhd.CreateVirtualDisk(baseVhdPath, vhd.VirtualDiskAccessNone, vhd.CreateVirtualDiskFlagNone, createParams) handle, err := vhd.CreateVirtualDisk(baseVhdPath, vhd.VirtualDiskAccessNone, vhd.CreateVirtualDiskFlagNone, createParams)
@ -135,8 +139,8 @@ func SetupUtilityVMBaseLayer(ctx context.Context, uvmPath, baseVhdPath, diffVhdP
createParams := &vhd.CreateVirtualDiskParameters{ createParams := &vhd.CreateVirtualDiskParameters{
Version: 2, Version: 2,
Version2: vhd.CreateVersion2{ Version2: vhd.CreateVersion2{
MaximumSize: sizeInGB * 1024 * 1024 * 1024, MaximumSize: sizeInGB * memory.GiB,
BlockSizeInBytes: defaultVHDXBlockSizeInMB * 1024 * 1024, BlockSizeInBytes: defaultVHDXBlockSizeInMB * memory.MiB,
}, },
} }
handle, err := vhd.CreateVirtualDisk(baseVhdPath, vhd.VirtualDiskAccessNone, vhd.CreateVirtualDiskFlagNone, createParams) handle, err := vhd.CreateVirtualDisk(baseVhdPath, vhd.VirtualDiskAccessNone, vhd.CreateVirtualDiskFlagNone, createParams)

View File

@ -1,3 +1,5 @@
//go:build windows
package computestorage package computestorage
import ( import (
@ -19,8 +21,8 @@ import (
// //
// `layerData` is the parent layer data. // `layerData` is the parent layer data.
func ImportLayer(ctx context.Context, layerPath, sourceFolderPath string, layerData LayerData) (err error) { func ImportLayer(ctx context.Context, layerPath, sourceFolderPath string, layerData LayerData) (err error) {
title := "hcsshim.ImportLayer" title := "hcsshim::ImportLayer"
ctx, span := trace.StartSpan(ctx, title) //nolint:ineffassign,staticcheck ctx, span := oc.StartSpan(ctx, title) //nolint:ineffassign,staticcheck
defer span.End() defer span.End()
defer func() { oc.SetSpanStatus(span, err) }() defer func() { oc.SetSpanStatus(span, err) }()
span.AddAttributes( span.AddAttributes(

View File

@ -1,3 +1,5 @@
//go:build windows
package computestorage package computestorage
import ( import (
@ -16,8 +18,8 @@ import (
// //
// `layerData` is the parent read-only layer data. // `layerData` is the parent read-only layer data.
func InitializeWritableLayer(ctx context.Context, layerPath string, layerData LayerData) (err error) { func InitializeWritableLayer(ctx context.Context, layerPath string, layerData LayerData) (err error) {
title := "hcsshim.InitializeWritableLayer" title := "hcsshim::InitializeWritableLayer"
ctx, span := trace.StartSpan(ctx, title) //nolint:ineffassign,staticcheck ctx, span := oc.StartSpan(ctx, title) //nolint:ineffassign,staticcheck
defer span.End() defer span.End()
defer func() { oc.SetSpanStatus(span, err) }() defer func() { oc.SetSpanStatus(span, err) }()
span.AddAttributes( span.AddAttributes(

View File

@ -1,3 +1,5 @@
//go:build windows
package computestorage package computestorage
import ( import (
@ -6,14 +8,13 @@ import (
"github.com/Microsoft/hcsshim/internal/interop" "github.com/Microsoft/hcsshim/internal/interop"
"github.com/Microsoft/hcsshim/internal/oc" "github.com/Microsoft/hcsshim/internal/oc"
"github.com/pkg/errors" "github.com/pkg/errors"
"go.opencensus.io/trace"
"golang.org/x/sys/windows" "golang.org/x/sys/windows"
) )
// GetLayerVhdMountPath returns the volume path for a virtual disk of a writable container layer. // 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) { func GetLayerVhdMountPath(ctx context.Context, vhdHandle windows.Handle) (path string, err error) {
title := "hcsshim.GetLayerVhdMountPath" title := "hcsshim::GetLayerVhdMountPath"
ctx, span := trace.StartSpan(ctx, title) //nolint:ineffassign,staticcheck ctx, span := oc.StartSpan(ctx, title) //nolint:ineffassign,staticcheck
defer span.End() defer span.End()
defer func() { oc.SetSpanStatus(span, err) }() defer func() { oc.SetSpanStatus(span, err) }()

View File

@ -1,3 +1,5 @@
//go:build windows
package computestorage package computestorage
import ( import (
@ -21,8 +23,8 @@ import (
// //
// `options` are the options applied while processing the layer. // `options` are the options applied while processing the layer.
func SetupBaseOSLayer(ctx context.Context, layerPath string, vhdHandle windows.Handle, options OsLayerOptions) (err error) { func SetupBaseOSLayer(ctx context.Context, layerPath string, vhdHandle windows.Handle, options OsLayerOptions) (err error) {
title := "hcsshim.SetupBaseOSLayer" title := "hcsshim::SetupBaseOSLayer"
ctx, span := trace.StartSpan(ctx, title) //nolint:ineffassign,staticcheck ctx, span := oc.StartSpan(ctx, title) //nolint:ineffassign,staticcheck
defer span.End() defer span.End()
defer func() { oc.SetSpanStatus(span, err) }() defer func() { oc.SetSpanStatus(span, err) }()
span.AddAttributes( span.AddAttributes(
@ -48,12 +50,16 @@ func SetupBaseOSLayer(ctx context.Context, layerPath string, vhdHandle windows.H
// `volumePath` is the path to the volume to be used for setup. // `volumePath` is the path to the volume to be used for setup.
// //
// `options` are the options applied while processing the layer. // `options` are the options applied while processing the layer.
//
// NOTE: This API is only available on builds of Windows greater than 19645. Inside we
// check if the hosts build has the API available by using 'GetVersion' which requires
// the calling application to be manifested. https://docs.microsoft.com/en-us/windows/win32/sbscs/manifests
func SetupBaseOSVolume(ctx context.Context, layerPath, volumePath string, options OsLayerOptions) (err error) { func SetupBaseOSVolume(ctx context.Context, layerPath, volumePath string, options OsLayerOptions) (err error) {
if osversion.Build() < 19645 { if osversion.Build() < 19645 {
return errors.New("SetupBaseOSVolume is not present on builds older than 19645") return errors.New("SetupBaseOSVolume is not present on builds older than 19645")
} }
title := "hcsshim.SetupBaseOSVolume" title := "hcsshim::SetupBaseOSVolume"
ctx, span := trace.StartSpan(ctx, title) //nolint:ineffassign,staticcheck ctx, span := oc.StartSpan(ctx, title) //nolint:ineffassign,staticcheck
defer span.End() defer span.End()
defer func() { oc.SetSpanStatus(span, err) }() defer func() { oc.SetSpanStatus(span, err) }()
span.AddAttributes( span.AddAttributes(

View File

@ -7,7 +7,7 @@ import (
hcsschema "github.com/Microsoft/hcsshim/internal/hcs/schema2" hcsschema "github.com/Microsoft/hcsshim/internal/hcs/schema2"
) )
//go:generate go run ../mksyscall_windows.go -output zsyscall_windows.go storage.go //go:generate go run github.com/Microsoft/go-winio/tools/mkwinsyscall -output zsyscall_windows.go storage.go
//sys hcsImportLayer(layerPath string, sourceFolderPath string, layerData string) (hr error) = computestorage.HcsImportLayer? //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 hcsExportLayer(layerPath string, exportFolderPath string, layerData string, options string) (hr error) = computestorage.HcsExportLayer?
@ -20,10 +20,13 @@ import (
//sys hcsGetLayerVhdMountPath(vhdHandle windows.Handle, mountPath **uint16) (hr error) = computestorage.HcsGetLayerVhdMountPath? //sys hcsGetLayerVhdMountPath(vhdHandle windows.Handle, mountPath **uint16) (hr error) = computestorage.HcsGetLayerVhdMountPath?
//sys hcsSetupBaseOSVolume(layerPath string, volumePath string, options string) (hr error) = computestorage.HcsSetupBaseOSVolume? //sys hcsSetupBaseOSVolume(layerPath string, volumePath string, options string) (hr error) = computestorage.HcsSetupBaseOSVolume?
type Version = hcsschema.Version
type Layer = hcsschema.Layer
// LayerData is the data used to describe parent layer information. // LayerData is the data used to describe parent layer information.
type LayerData struct { type LayerData struct {
SchemaVersion hcsschema.Version `json:"SchemaVersion,omitempty"` SchemaVersion Version `json:"SchemaVersion,omitempty"`
Layers []hcsschema.Layer `json:"Layers,omitempty"` Layers []Layer `json:"Layers,omitempty"`
} }
// ExportLayerOptions are the set of options that are used with the `computestorage.HcsExportLayer` syscall. // ExportLayerOptions are the set of options that are used with the `computestorage.HcsExportLayer` syscall.

View File

@ -1,4 +1,6 @@
// Code generated mksyscall_windows.exe DO NOT EDIT //go:build windows
// Code generated by 'go generate' using "github.com/Microsoft/go-winio/tools/mkwinsyscall"; DO NOT EDIT.
package computestorage package computestorage
@ -19,6 +21,7 @@ const (
var ( var (
errERROR_IO_PENDING error = syscall.Errno(errnoERROR_IO_PENDING) errERROR_IO_PENDING error = syscall.Errno(errnoERROR_IO_PENDING)
errERROR_EINVAL error = syscall.EINVAL
) )
// errnoErr returns common boxed Errno values, to prevent // errnoErr returns common boxed Errno values, to prevent
@ -26,7 +29,7 @@ var (
func errnoErr(e syscall.Errno) error { func errnoErr(e syscall.Errno) error {
switch e { switch e {
case 0: case 0:
return nil return errERROR_EINVAL
case errnoERROR_IO_PENDING: case errnoERROR_IO_PENDING:
return errERROR_IO_PENDING return errERROR_IO_PENDING
} }
@ -39,42 +42,86 @@ func errnoErr(e syscall.Errno) error {
var ( var (
modcomputestorage = windows.NewLazySystemDLL("computestorage.dll") 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") procHcsAttachLayerStorageFilter = modcomputestorage.NewProc("HcsAttachLayerStorageFilter")
procHcsDestoryLayer = modcomputestorage.NewProc("HcsDestoryLayer")
procHcsDetachLayerStorageFilter = modcomputestorage.NewProc("HcsDetachLayerStorageFilter") procHcsDetachLayerStorageFilter = modcomputestorage.NewProc("HcsDetachLayerStorageFilter")
procHcsExportLayer = modcomputestorage.NewProc("HcsExportLayer")
procHcsFormatWritableLayerVhd = modcomputestorage.NewProc("HcsFormatWritableLayerVhd") procHcsFormatWritableLayerVhd = modcomputestorage.NewProc("HcsFormatWritableLayerVhd")
procHcsGetLayerVhdMountPath = modcomputestorage.NewProc("HcsGetLayerVhdMountPath") procHcsGetLayerVhdMountPath = modcomputestorage.NewProc("HcsGetLayerVhdMountPath")
procHcsImportLayer = modcomputestorage.NewProc("HcsImportLayer")
procHcsInitializeWritableLayer = modcomputestorage.NewProc("HcsInitializeWritableLayer")
procHcsSetupBaseOSLayer = modcomputestorage.NewProc("HcsSetupBaseOSLayer")
procHcsSetupBaseOSVolume = modcomputestorage.NewProc("HcsSetupBaseOSVolume") procHcsSetupBaseOSVolume = modcomputestorage.NewProc("HcsSetupBaseOSVolume")
) )
func hcsImportLayer(layerPath string, sourceFolderPath string, layerData string) (hr error) { func hcsAttachLayerStorageFilter(layerPath string, layerData string) (hr error) {
var _p0 *uint16 var _p0 *uint16
_p0, hr = syscall.UTF16PtrFromString(layerPath) _p0, hr = syscall.UTF16PtrFromString(layerPath)
if hr != nil { if hr != nil {
return return
} }
var _p1 *uint16 var _p1 *uint16
_p1, hr = syscall.UTF16PtrFromString(sourceFolderPath) _p1, hr = syscall.UTF16PtrFromString(layerData)
if hr != nil { if hr != nil {
return return
} }
var _p2 *uint16 return _hcsAttachLayerStorageFilter(_p0, _p1)
_p2, hr = syscall.UTF16PtrFromString(layerData)
if hr != nil {
return
}
return _hcsImportLayer(_p0, _p1, _p2)
} }
func _hcsImportLayer(layerPath *uint16, sourceFolderPath *uint16, layerData *uint16) (hr error) { func _hcsAttachLayerStorageFilter(layerPath *uint16, layerData *uint16) (hr error) {
if hr = procHcsImportLayer.Find(); hr != nil { hr = procHcsAttachLayerStorageFilter.Find()
if hr != nil {
return return
} }
r0, _, _ := syscall.Syscall(procHcsImportLayer.Addr(), 3, uintptr(unsafe.Pointer(layerPath)), uintptr(unsafe.Pointer(sourceFolderPath)), uintptr(unsafe.Pointer(layerData))) 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 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) {
hr = procHcsDestoryLayer.Find()
if 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 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) {
hr = procHcsDetachLayerStorageFilter.Find()
if hr != nil {
return
}
r0, _, _ := syscall.Syscall(procHcsDetachLayerStorageFilter.Addr(), 1, uintptr(unsafe.Pointer(layerPath)), 0, 0)
if int32(r0) < 0 { if int32(r0) < 0 {
if r0&0x1fff0000 == 0x00070000 { if r0&0x1fff0000 == 0x00070000 {
r0 &= 0xffff r0 &= 0xffff
@ -109,7 +156,8 @@ func hcsExportLayer(layerPath string, exportFolderPath string, layerData string,
} }
func _hcsExportLayer(layerPath *uint16, exportFolderPath *uint16, layerData *uint16, options *uint16) (hr error) { func _hcsExportLayer(layerPath *uint16, exportFolderPath *uint16, layerData *uint16, options *uint16) (hr error) {
if hr = procHcsExportLayer.Find(); hr != nil { hr = procHcsExportLayer.Find()
if hr != nil {
return 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) r0, _, _ := syscall.Syscall6(procHcsExportLayer.Addr(), 4, uintptr(unsafe.Pointer(layerPath)), uintptr(unsafe.Pointer(exportFolderPath)), uintptr(unsafe.Pointer(layerData)), uintptr(unsafe.Pointer(options)), 0, 0)
@ -122,20 +170,12 @@ func _hcsExportLayer(layerPath *uint16, exportFolderPath *uint16, layerData *uin
return return
} }
func hcsDestroyLayer(layerPath string) (hr error) { func hcsFormatWritableLayerVhd(handle windows.Handle) (hr error) {
var _p0 *uint16 hr = procHcsFormatWritableLayerVhd.Find()
_p0, hr = syscall.UTF16PtrFromString(layerPath)
if hr != nil { if hr != nil {
return return
} }
return _hcsDestroyLayer(_p0) r0, _, _ := syscall.Syscall(procHcsFormatWritableLayerVhd.Addr(), 1, uintptr(handle), 0, 0)
}
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 int32(r0) < 0 {
if r0&0x1fff0000 == 0x00070000 { if r0&0x1fff0000 == 0x00070000 {
r0 &= 0xffff r0 &= 0xffff
@ -145,25 +185,46 @@ func _hcsDestroyLayer(layerPath *uint16) (hr error) {
return return
} }
func hcsSetupBaseOSLayer(layerPath string, handle windows.Handle, options string) (hr error) { func hcsGetLayerVhdMountPath(vhdHandle windows.Handle, mountPath **uint16) (hr error) {
hr = procHcsGetLayerVhdMountPath.Find()
if 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 hcsImportLayer(layerPath string, sourceFolderPath string, layerData string) (hr error) {
var _p0 *uint16 var _p0 *uint16
_p0, hr = syscall.UTF16PtrFromString(layerPath) _p0, hr = syscall.UTF16PtrFromString(layerPath)
if hr != nil { if hr != nil {
return return
} }
var _p1 *uint16 var _p1 *uint16
_p1, hr = syscall.UTF16PtrFromString(options) _p1, hr = syscall.UTF16PtrFromString(sourceFolderPath)
if hr != nil { if hr != nil {
return return
} }
return _hcsSetupBaseOSLayer(_p0, handle, _p1) var _p2 *uint16
} _p2, hr = syscall.UTF16PtrFromString(layerData)
if hr != nil {
func _hcsSetupBaseOSLayer(layerPath *uint16, handle windows.Handle, options *uint16) (hr error) {
if hr = procHcsSetupBaseOSLayer.Find(); hr != nil {
return return
} }
r0, _, _ := syscall.Syscall(procHcsSetupBaseOSLayer.Addr(), 3, uintptr(unsafe.Pointer(layerPath)), uintptr(handle), uintptr(unsafe.Pointer(options))) return _hcsImportLayer(_p0, _p1, _p2)
}
func _hcsImportLayer(layerPath *uint16, sourceFolderPath *uint16, layerData *uint16) (hr error) {
hr = procHcsImportLayer.Find()
if 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 int32(r0) < 0 {
if r0&0x1fff0000 == 0x00070000 { if r0&0x1fff0000 == 0x00070000 {
r0 &= 0xffff r0 &= 0xffff
@ -193,7 +254,8 @@ func hcsInitializeWritableLayer(writableLayerPath string, layerData string, opti
} }
func _hcsInitializeWritableLayer(writableLayerPath *uint16, layerData *uint16, options *uint16) (hr error) { func _hcsInitializeWritableLayer(writableLayerPath *uint16, layerData *uint16, options *uint16) (hr error) {
if hr = procHcsInitializeWritableLayer.Find(); hr != nil { hr = procHcsInitializeWritableLayer.Find()
if hr != nil {
return return
} }
r0, _, _ := syscall.Syscall(procHcsInitializeWritableLayer.Addr(), 3, uintptr(unsafe.Pointer(writableLayerPath)), uintptr(unsafe.Pointer(layerData)), uintptr(unsafe.Pointer(options))) r0, _, _ := syscall.Syscall(procHcsInitializeWritableLayer.Addr(), 3, uintptr(unsafe.Pointer(writableLayerPath)), uintptr(unsafe.Pointer(layerData)), uintptr(unsafe.Pointer(options)))
@ -206,76 +268,26 @@ func _hcsInitializeWritableLayer(writableLayerPath *uint16, layerData *uint16, o
return return
} }
func hcsAttachLayerStorageFilter(layerPath string, layerData string) (hr error) { func hcsSetupBaseOSLayer(layerPath string, handle windows.Handle, options string) (hr error) {
var _p0 *uint16 var _p0 *uint16
_p0, hr = syscall.UTF16PtrFromString(layerPath) _p0, hr = syscall.UTF16PtrFromString(layerPath)
if hr != nil { if hr != nil {
return return
} }
var _p1 *uint16 var _p1 *uint16
_p1, hr = syscall.UTF16PtrFromString(layerData) _p1, hr = syscall.UTF16PtrFromString(options)
if hr != nil { if hr != nil {
return return
} }
return _hcsAttachLayerStorageFilter(_p0, _p1) return _hcsSetupBaseOSLayer(_p0, handle, _p1)
} }
func _hcsAttachLayerStorageFilter(layerPath *uint16, layerData *uint16) (hr error) { func _hcsSetupBaseOSLayer(layerPath *uint16, handle windows.Handle, options *uint16) (hr error) {
if hr = procHcsAttachLayerStorageFilter.Find(); hr != nil { hr = procHcsSetupBaseOSLayer.Find()
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 { if hr != nil {
return return
} }
return _hcsDetachLayerStorageFilter(_p0) r0, _, _ := syscall.Syscall(procHcsSetupBaseOSLayer.Addr(), 3, uintptr(unsafe.Pointer(layerPath)), uintptr(handle), uintptr(unsafe.Pointer(options)))
}
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 int32(r0) < 0 {
if r0&0x1fff0000 == 0x00070000 { if r0&0x1fff0000 == 0x00070000 {
r0 &= 0xffff r0 &= 0xffff
@ -305,7 +317,8 @@ func hcsSetupBaseOSVolume(layerPath string, volumePath string, options string) (
} }
func _hcsSetupBaseOSVolume(layerPath *uint16, volumePath *uint16, options *uint16) (hr error) { func _hcsSetupBaseOSVolume(layerPath *uint16, volumePath *uint16, options *uint16) (hr error) {
if hr = procHcsSetupBaseOSVolume.Find(); hr != nil { hr = procHcsSetupBaseOSVolume.Find()
if hr != nil {
return return
} }
r0, _, _ := syscall.Syscall(procHcsSetupBaseOSVolume.Addr(), 3, uintptr(unsafe.Pointer(layerPath)), uintptr(unsafe.Pointer(volumePath)), uintptr(unsafe.Pointer(options))) r0, _, _ := syscall.Syscall(procHcsSetupBaseOSVolume.Addr(), 3, uintptr(unsafe.Pointer(layerPath)), uintptr(unsafe.Pointer(volumePath)), uintptr(unsafe.Pointer(options)))

View File

@ -1,3 +1,5 @@
//go:build windows
package hcsshim package hcsshim
import ( import (
@ -60,7 +62,7 @@ type container struct {
waitCh chan struct{} waitCh chan struct{}
} }
// createComputeSystemAdditionalJSON is read from the environment at initialisation // createContainerAdditionalJSON is read from the environment at initialization
// time. It allows an environment variable to define additional JSON which // time. It allows an environment variable to define additional JSON which
// is merged in the CreateComputeSystem call to HCS. // is merged in the CreateComputeSystem call to HCS.
var createContainerAdditionalJSON []byte var createContainerAdditionalJSON []byte

View File

@ -1,3 +1,5 @@
//go:build windows
package hcsshim package hcsshim
import ( import (
@ -50,6 +52,9 @@ var (
// ErrUnexpectedValue is an error encountered when hcs returns an invalid value // ErrUnexpectedValue is an error encountered when hcs returns an invalid value
ErrUnexpectedValue = hcs.ErrUnexpectedValue ErrUnexpectedValue = hcs.ErrUnexpectedValue
// ErrOperationDenied is an error when hcs attempts an operation that is explicitly denied
ErrOperationDenied = hcs.ErrOperationDenied
// ErrVmcomputeAlreadyStopped is an error encountered when a shutdown or terminate request is made on a stopped container // ErrVmcomputeAlreadyStopped is an error encountered when a shutdown or terminate request is made on a stopped container
ErrVmcomputeAlreadyStopped = hcs.ErrVmcomputeAlreadyStopped ErrVmcomputeAlreadyStopped = hcs.ErrVmcomputeAlreadyStopped

View File

@ -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

3
vendor/github.com/Microsoft/hcsshim/hcn/doc.go generated vendored Normal file
View File

@ -0,0 +1,3 @@
// Package hcn is a shim for the Host Compute Networking (HCN) service, which manages networking for Windows Server
// containers and Hyper-V containers. Previous to RS5, HCN was referred to as Host Networking Service (HNS).
package hcn

View File

@ -1,5 +1,5 @@
// Package hcn is a shim for the Host Compute Networking (HCN) service, which manages networking for Windows Server //go:build windows
// containers and Hyper-V containers. Previous to RS5, HCN was referred to as Host Networking Service (HNS).
package hcn package hcn
import ( import (
@ -10,7 +10,7 @@ import (
"github.com/Microsoft/go-winio/pkg/guid" "github.com/Microsoft/go-winio/pkg/guid"
) )
//go:generate go run ../mksyscall_windows.go -output zsyscall_windows.go hcn.go //go:generate go run github.com/Microsoft/go-winio/tools/mkwinsyscall -output zsyscall_windows.go hcn.go
/// HNS V1 API /// HNS V1 API
@ -228,7 +228,7 @@ func IPv6DualStackSupported() error {
return platformDoesNotSupportError("IPv6 DualStack") return platformDoesNotSupportError("IPv6 DualStack")
} }
//L4proxySupported returns an error if the HCN verison does not support L4Proxy // L4proxySupported returns an error if the HCN version does not support L4Proxy
func L4proxyPolicySupported() error { func L4proxyPolicySupported() error {
supported, err := GetCachedSupportedFeatures() supported, err := GetCachedSupportedFeatures()
if err != nil { if err != nil {
@ -240,7 +240,7 @@ func L4proxyPolicySupported() error {
return platformDoesNotSupportError("L4ProxyPolicy") return platformDoesNotSupportError("L4ProxyPolicy")
} }
// L4WfpProxySupported returns an error if the HCN verison does not support L4WfpProxy // L4WfpProxySupported returns an error if the HCN version does not support L4WfpProxy
func L4WfpProxyPolicySupported() error { func L4WfpProxyPolicySupported() error {
supported, err := GetCachedSupportedFeatures() supported, err := GetCachedSupportedFeatures()
if err != nil { if err != nil {

View File

@ -1,3 +1,5 @@
//go:build windows
package hcn package hcn
import ( import (
@ -9,7 +11,7 @@ import (
"github.com/sirupsen/logrus" "github.com/sirupsen/logrus"
) )
// IpConfig is assoicated with an endpoint // IpConfig is associated with an endpoint
type IpConfig struct { type IpConfig struct {
IpAddress string `json:",omitempty"` IpAddress string `json:",omitempty"`
PrefixLength uint8 `json:",omitempty"` PrefixLength uint8 `json:",omitempty"`
@ -70,14 +72,14 @@ type PolicyEndpointRequest struct {
Policies []EndpointPolicy `json:",omitempty"` Policies []EndpointPolicy `json:",omitempty"`
} }
func getEndpoint(endpointGuid guid.GUID, query string) (*HostComputeEndpoint, error) { func getEndpoint(endpointGUID guid.GUID, query string) (*HostComputeEndpoint, error) {
// Open endpoint. // Open endpoint.
var ( var (
endpointHandle hcnEndpoint endpointHandle hcnEndpoint
resultBuffer *uint16 resultBuffer *uint16
propertiesBuffer *uint16 propertiesBuffer *uint16
) )
hr := hcnOpenEndpoint(&endpointGuid, &endpointHandle, &resultBuffer) hr := hcnOpenEndpoint(&endpointGUID, &endpointHandle, &resultBuffer)
if err := checkForErrors("hcnOpenEndpoint", hr, resultBuffer); err != nil { if err := checkForErrors("hcnOpenEndpoint", hr, resultBuffer); err != nil {
return nil, err return nil, err
} }
@ -119,8 +121,8 @@ func enumerateEndpoints(query string) ([]HostComputeEndpoint, error) {
} }
var outputEndpoints []HostComputeEndpoint var outputEndpoints []HostComputeEndpoint
for _, endpointGuid := range endpointIds { for _, endpointGUID := range endpointIds {
endpoint, err := getEndpoint(endpointGuid, query) endpoint, err := getEndpoint(endpointGUID, query)
if err != nil { if err != nil {
return nil, err return nil, err
} }
@ -129,22 +131,22 @@ func enumerateEndpoints(query string) ([]HostComputeEndpoint, error) {
return outputEndpoints, nil return outputEndpoints, nil
} }
func createEndpoint(networkId string, endpointSettings string) (*HostComputeEndpoint, error) { func createEndpoint(networkID string, endpointSettings string) (*HostComputeEndpoint, error) {
networkGuid, err := guid.FromString(networkId) networkGUID, err := guid.FromString(networkID)
if err != nil { if err != nil {
return nil, errInvalidNetworkID return nil, errInvalidNetworkID
} }
// Open network. // Open network.
var networkHandle hcnNetwork var networkHandle hcnNetwork
var resultBuffer *uint16 var resultBuffer *uint16
hr := hcnOpenNetwork(&networkGuid, &networkHandle, &resultBuffer) hr := hcnOpenNetwork(&networkGUID, &networkHandle, &resultBuffer)
if err := checkForErrors("hcnOpenNetwork", hr, resultBuffer); err != nil { if err := checkForErrors("hcnOpenNetwork", hr, resultBuffer); err != nil {
return nil, err return nil, err
} }
// Create endpoint. // Create endpoint.
endpointId := guid.GUID{} endpointID := guid.GUID{}
var endpointHandle hcnEndpoint var endpointHandle hcnEndpoint
hr = hcnCreateEndpoint(networkHandle, &endpointId, endpointSettings, &endpointHandle, &resultBuffer) hr = hcnCreateEndpoint(networkHandle, &endpointID, endpointSettings, &endpointHandle, &resultBuffer)
if err := checkForErrors("hcnCreateEndpoint", hr, resultBuffer); err != nil { if err := checkForErrors("hcnCreateEndpoint", hr, resultBuffer); err != nil {
return nil, err return nil, err
} }
@ -178,8 +180,8 @@ func createEndpoint(networkId string, endpointSettings string) (*HostComputeEndp
return &outputEndpoint, nil return &outputEndpoint, nil
} }
func modifyEndpoint(endpointId string, settings string) (*HostComputeEndpoint, error) { func modifyEndpoint(endpointID string, settings string) (*HostComputeEndpoint, error) {
endpointGuid, err := guid.FromString(endpointId) endpointGUID, err := guid.FromString(endpointID)
if err != nil { if err != nil {
return nil, errInvalidEndpointID return nil, errInvalidEndpointID
} }
@ -189,7 +191,7 @@ func modifyEndpoint(endpointId string, settings string) (*HostComputeEndpoint, e
resultBuffer *uint16 resultBuffer *uint16
propertiesBuffer *uint16 propertiesBuffer *uint16
) )
hr := hcnOpenEndpoint(&endpointGuid, &endpointHandle, &resultBuffer) hr := hcnOpenEndpoint(&endpointGUID, &endpointHandle, &resultBuffer)
if err := checkForErrors("hcnOpenEndpoint", hr, resultBuffer); err != nil { if err := checkForErrors("hcnOpenEndpoint", hr, resultBuffer); err != nil {
return nil, err return nil, err
} }
@ -222,13 +224,13 @@ func modifyEndpoint(endpointId string, settings string) (*HostComputeEndpoint, e
return &outputEndpoint, nil return &outputEndpoint, nil
} }
func deleteEndpoint(endpointId string) error { func deleteEndpoint(endpointID string) error {
endpointGuid, err := guid.FromString(endpointId) endpointGUID, err := guid.FromString(endpointID)
if err != nil { if err != nil {
return errInvalidEndpointID return errInvalidEndpointID
} }
var resultBuffer *uint16 var resultBuffer *uint16
hr := hcnDeleteEndpoint(&endpointGuid, &resultBuffer) hr := hcnDeleteEndpoint(&endpointGUID, &resultBuffer)
if err := checkForErrors("hcnDeleteEndpoint", hr, resultBuffer); err != nil { if err := checkForErrors("hcnDeleteEndpoint", hr, resultBuffer); err != nil {
return err return err
} }
@ -247,12 +249,12 @@ func ListEndpoints() ([]HostComputeEndpoint, error) {
// ListEndpointsQuery makes a call to query the list of available endpoints. // ListEndpointsQuery makes a call to query the list of available endpoints.
func ListEndpointsQuery(query HostComputeQuery) ([]HostComputeEndpoint, error) { func ListEndpointsQuery(query HostComputeQuery) ([]HostComputeEndpoint, error) {
queryJson, err := json.Marshal(query) queryJSON, err := json.Marshal(query)
if err != nil { if err != nil {
return nil, err return nil, err
} }
endpoints, err := enumerateEndpoints(string(queryJson)) endpoints, err := enumerateEndpoints(string(queryJSON))
if err != nil { if err != nil {
return nil, err return nil, err
} }
@ -260,10 +262,10 @@ func ListEndpointsQuery(query HostComputeQuery) ([]HostComputeEndpoint, error) {
} }
// ListEndpointsOfNetwork queries the list of endpoints on a network. // ListEndpointsOfNetwork queries the list of endpoints on a network.
func ListEndpointsOfNetwork(networkId string) ([]HostComputeEndpoint, error) { func ListEndpointsOfNetwork(networkID string) ([]HostComputeEndpoint, error) {
hcnQuery := defaultQuery() hcnQuery := defaultQuery()
// TODO: Once query can convert schema, change to {HostComputeNetwork:networkId} // TODO: Once query can convert schema, change to {HostComputeNetwork:networkId}
mapA := map[string]string{"VirtualNetwork": networkId} mapA := map[string]string{"VirtualNetwork": networkID}
filter, err := json.Marshal(mapA) filter, err := json.Marshal(mapA)
if err != nil { if err != nil {
return nil, err return nil, err
@ -274,9 +276,9 @@ func ListEndpointsOfNetwork(networkId string) ([]HostComputeEndpoint, error) {
} }
// GetEndpointByID returns an endpoint specified by Id // GetEndpointByID returns an endpoint specified by Id
func GetEndpointByID(endpointId string) (*HostComputeEndpoint, error) { func GetEndpointByID(endpointID string) (*HostComputeEndpoint, error) {
hcnQuery := defaultQuery() hcnQuery := defaultQuery()
mapA := map[string]string{"ID": endpointId} mapA := map[string]string{"ID": endpointID}
filter, err := json.Marshal(mapA) filter, err := json.Marshal(mapA)
if err != nil { if err != nil {
return nil, err return nil, err
@ -288,7 +290,7 @@ func GetEndpointByID(endpointId string) (*HostComputeEndpoint, error) {
return nil, err return nil, err
} }
if len(endpoints) == 0 { if len(endpoints) == 0 {
return nil, EndpointNotFoundError{EndpointID: endpointId} return nil, EndpointNotFoundError{EndpointID: endpointID}
} }
return &endpoints[0], err return &endpoints[0], err
} }
@ -345,15 +347,15 @@ func (endpoint *HostComputeEndpoint) Delete() error {
} }
// ModifyEndpointSettings updates the Port/Policy of an Endpoint. // ModifyEndpointSettings updates the Port/Policy of an Endpoint.
func ModifyEndpointSettings(endpointId string, request *ModifyEndpointSettingRequest) error { func ModifyEndpointSettings(endpointID string, request *ModifyEndpointSettingRequest) error {
logrus.Debugf("hcn::HostComputeEndpoint::ModifyEndpointSettings id=%s", endpointId) logrus.Debugf("hcn::HostComputeEndpoint::ModifyEndpointSettings id=%s", endpointID)
endpointSettingsRequest, err := json.Marshal(request) endpointSettingsRequest, err := json.Marshal(request)
if err != nil { if err != nil {
return err return err
} }
_, err = modifyEndpoint(endpointId, string(endpointSettingsRequest)) _, err = modifyEndpoint(endpointID, string(endpointSettingsRequest))
if err != nil { if err != nil {
return err return err
} }
@ -364,25 +366,25 @@ func ModifyEndpointSettings(endpointId string, request *ModifyEndpointSettingReq
func (endpoint *HostComputeEndpoint) ApplyPolicy(requestType RequestType, endpointPolicy PolicyEndpointRequest) error { func (endpoint *HostComputeEndpoint) ApplyPolicy(requestType RequestType, endpointPolicy PolicyEndpointRequest) error {
logrus.Debugf("hcn::HostComputeEndpoint::ApplyPolicy id=%s", endpoint.Id) logrus.Debugf("hcn::HostComputeEndpoint::ApplyPolicy id=%s", endpoint.Id)
settingsJson, err := json.Marshal(endpointPolicy) settingsJSON, err := json.Marshal(endpointPolicy)
if err != nil { if err != nil {
return err return err
} }
requestMessage := &ModifyEndpointSettingRequest{ requestMessage := &ModifyEndpointSettingRequest{
ResourceType: EndpointResourceTypePolicy, ResourceType: EndpointResourceTypePolicy,
RequestType: requestType, RequestType: requestType,
Settings: settingsJson, Settings: settingsJSON,
} }
return ModifyEndpointSettings(endpoint.Id, requestMessage) return ModifyEndpointSettings(endpoint.Id, requestMessage)
} }
// NamespaceAttach modifies a Namespace to add an endpoint. // NamespaceAttach modifies a Namespace to add an endpoint.
func (endpoint *HostComputeEndpoint) NamespaceAttach(namespaceId string) error { func (endpoint *HostComputeEndpoint) NamespaceAttach(namespaceID string) error {
return AddNamespaceEndpoint(namespaceId, endpoint.Id) return AddNamespaceEndpoint(namespaceID, endpoint.Id)
} }
// NamespaceDetach modifies a Namespace to remove an endpoint. // NamespaceDetach modifies a Namespace to remove an endpoint.
func (endpoint *HostComputeEndpoint) NamespaceDetach(namespaceId string) error { func (endpoint *HostComputeEndpoint) NamespaceDetach(namespaceID string) error {
return RemoveNamespaceEndpoint(namespaceId, endpoint.Id) return RemoveNamespaceEndpoint(namespaceID, endpoint.Id)
} }

View File

@ -1,5 +1,5 @@
// Package hcn is a shim for the Host Compute Networking (HCN) service, which manages networking for Windows Server //go:build windows
// containers and Hyper-V containers. Previous to RS5, HCN was referred to as Host Networking Service (HNS).
package hcn package hcn
import ( import (
@ -10,6 +10,7 @@ import (
"github.com/Microsoft/hcsshim/internal/hcserror" "github.com/Microsoft/hcsshim/internal/hcserror"
"github.com/Microsoft/hcsshim/internal/interop" "github.com/Microsoft/hcsshim/internal/interop"
"github.com/sirupsen/logrus" "github.com/sirupsen/logrus"
"golang.org/x/sys/windows"
) )
var ( var (
@ -48,8 +49,8 @@ type ErrorCode uint32
// For common errors, define the error as it is in windows, so we can quickly determine it later // For common errors, define the error as it is in windows, so we can quickly determine it later
const ( const (
ERROR_NOT_FOUND = 0x490 ERROR_NOT_FOUND = ErrorCode(windows.ERROR_NOT_FOUND)
HCN_E_PORT_ALREADY_EXISTS ErrorCode = 0x803b0013 HCN_E_PORT_ALREADY_EXISTS ErrorCode = ErrorCode(windows.HCN_E_PORT_ALREADY_EXISTS)
) )
type HcnError struct { type HcnError struct {
@ -87,10 +88,10 @@ func new(hr error, title string, rest string) error {
// //
// Note that the below errors are not errors returned by hcn itself // Note that the below errors are not errors returned by hcn itself
// we wish to seperate them as they are shim usage error // we wish to separate them as they are shim usage error
// //
// NetworkNotFoundError results from a failed seach for a network by Id or Name // NetworkNotFoundError results from a failed search for a network by Id or Name
type NetworkNotFoundError struct { type NetworkNotFoundError struct {
NetworkName string NetworkName string
NetworkID string NetworkID string
@ -103,7 +104,7 @@ func (e NetworkNotFoundError) Error() string {
return fmt.Sprintf("Network ID %q not found", e.NetworkID) return fmt.Sprintf("Network ID %q not found", e.NetworkID)
} }
// EndpointNotFoundError results from a failed seach for an endpoint by Id or Name // EndpointNotFoundError results from a failed search for an endpoint by Id or Name
type EndpointNotFoundError struct { type EndpointNotFoundError struct {
EndpointName string EndpointName string
EndpointID string EndpointID string
@ -116,7 +117,7 @@ func (e EndpointNotFoundError) Error() string {
return fmt.Sprintf("Endpoint ID %q not found", e.EndpointID) return fmt.Sprintf("Endpoint ID %q not found", e.EndpointID)
} }
// NamespaceNotFoundError results from a failed seach for a namsepace by Id // NamespaceNotFoundError results from a failed search for a namsepace by Id
type NamespaceNotFoundError struct { type NamespaceNotFoundError struct {
NamespaceID string NamespaceID string
} }
@ -125,7 +126,7 @@ func (e NamespaceNotFoundError) Error() string {
return fmt.Sprintf("Namespace ID %q not found", e.NamespaceID) return fmt.Sprintf("Namespace ID %q not found", e.NamespaceID)
} }
// LoadBalancerNotFoundError results from a failed seach for a loadbalancer by Id // LoadBalancerNotFoundError results from a failed search for a loadbalancer by Id
type LoadBalancerNotFoundError struct { type LoadBalancerNotFoundError struct {
LoadBalancerId string LoadBalancerId string
} }
@ -134,7 +135,7 @@ func (e LoadBalancerNotFoundError) Error() string {
return fmt.Sprintf("LoadBalancer %q not found", e.LoadBalancerId) return fmt.Sprintf("LoadBalancer %q not found", e.LoadBalancerId)
} }
// RouteNotFoundError results from a failed seach for a route by Id // RouteNotFoundError results from a failed search for a route by Id
type RouteNotFoundError struct { type RouteNotFoundError struct {
RouteId string RouteId string
} }

View File

@ -1,3 +1,5 @@
//go:build windows
package hcn package hcn
import ( import (

View File

@ -1,3 +1,5 @@
//go:build windows
package hcn package hcn
import ( import (
@ -28,14 +30,14 @@ type HostComputeLoadBalancer struct {
Flags LoadBalancerFlags `json:",omitempty"` // 0: None, 1: EnableDirectServerReturn Flags LoadBalancerFlags `json:",omitempty"` // 0: None, 1: EnableDirectServerReturn
} }
//LoadBalancerFlags modify settings for a loadbalancer. // LoadBalancerFlags modify settings for a loadbalancer.
type LoadBalancerFlags uint32 type LoadBalancerFlags uint32
var ( var (
// LoadBalancerFlagsNone is the default. // LoadBalancerFlagsNone is the default.
LoadBalancerFlagsNone LoadBalancerFlags = 0 LoadBalancerFlagsNone LoadBalancerFlags = 0
// LoadBalancerFlagsDSR enables Direct Server Return (DSR) // LoadBalancerFlagsDSR enables Direct Server Return (DSR)
LoadBalancerFlagsDSR LoadBalancerFlags = 1 LoadBalancerFlagsDSR LoadBalancerFlags = 1
LoadBalancerFlagsIPv6 LoadBalancerFlags = 2 LoadBalancerFlagsIPv6 LoadBalancerFlags = 2
) )
@ -67,14 +69,14 @@ var (
LoadBalancerDistributionSourceIP LoadBalancerDistribution = 2 LoadBalancerDistributionSourceIP LoadBalancerDistribution = 2
) )
func getLoadBalancer(loadBalancerGuid guid.GUID, query string) (*HostComputeLoadBalancer, error) { func getLoadBalancer(loadBalancerGUID guid.GUID, query string) (*HostComputeLoadBalancer, error) {
// Open loadBalancer. // Open loadBalancer.
var ( var (
loadBalancerHandle hcnLoadBalancer loadBalancerHandle hcnLoadBalancer
resultBuffer *uint16 resultBuffer *uint16
propertiesBuffer *uint16 propertiesBuffer *uint16
) )
hr := hcnOpenLoadBalancer(&loadBalancerGuid, &loadBalancerHandle, &resultBuffer) hr := hcnOpenLoadBalancer(&loadBalancerGUID, &loadBalancerHandle, &resultBuffer)
if err := checkForErrors("hcnOpenLoadBalancer", hr, resultBuffer); err != nil { if err := checkForErrors("hcnOpenLoadBalancer", hr, resultBuffer); err != nil {
return nil, err return nil, err
} }
@ -115,8 +117,8 @@ func enumerateLoadBalancers(query string) ([]HostComputeLoadBalancer, error) {
} }
var outputLoadBalancers []HostComputeLoadBalancer var outputLoadBalancers []HostComputeLoadBalancer
for _, loadBalancerGuid := range loadBalancerIds { for _, loadBalancerGUID := range loadBalancerIds {
loadBalancer, err := getLoadBalancer(loadBalancerGuid, query) loadBalancer, err := getLoadBalancer(loadBalancerGUID, query)
if err != nil { if err != nil {
return nil, err return nil, err
} }
@ -132,8 +134,8 @@ func createLoadBalancer(settings string) (*HostComputeLoadBalancer, error) {
resultBuffer *uint16 resultBuffer *uint16
propertiesBuffer *uint16 propertiesBuffer *uint16
) )
loadBalancerGuid := guid.GUID{} loadBalancerGUID := guid.GUID{}
hr := hcnCreateLoadBalancer(&loadBalancerGuid, settings, &loadBalancerHandle, &resultBuffer) hr := hcnCreateLoadBalancer(&loadBalancerGUID, settings, &loadBalancerHandle, &resultBuffer)
if err := checkForErrors("hcnCreateLoadBalancer", hr, resultBuffer); err != nil { if err := checkForErrors("hcnCreateLoadBalancer", hr, resultBuffer); err != nil {
return nil, err return nil, err
} }
@ -161,13 +163,13 @@ func createLoadBalancer(settings string) (*HostComputeLoadBalancer, error) {
return &outputLoadBalancer, nil return &outputLoadBalancer, nil
} }
func deleteLoadBalancer(loadBalancerId string) error { func deleteLoadBalancer(loadBalancerID string) error {
loadBalancerGuid, err := guid.FromString(loadBalancerId) loadBalancerGUID, err := guid.FromString(loadBalancerID)
if err != nil { if err != nil {
return errInvalidLoadBalancerID return errInvalidLoadBalancerID
} }
var resultBuffer *uint16 var resultBuffer *uint16
hr := hcnDeleteLoadBalancer(&loadBalancerGuid, &resultBuffer) hr := hcnDeleteLoadBalancer(&loadBalancerGUID, &resultBuffer)
if err := checkForErrors("hcnDeleteLoadBalancer", hr, resultBuffer); err != nil { if err := checkForErrors("hcnDeleteLoadBalancer", hr, resultBuffer); err != nil {
return err return err
} }
@ -186,12 +188,12 @@ func ListLoadBalancers() ([]HostComputeLoadBalancer, error) {
// ListLoadBalancersQuery makes a call to query the list of available loadBalancers. // ListLoadBalancersQuery makes a call to query the list of available loadBalancers.
func ListLoadBalancersQuery(query HostComputeQuery) ([]HostComputeLoadBalancer, error) { func ListLoadBalancersQuery(query HostComputeQuery) ([]HostComputeLoadBalancer, error) {
queryJson, err := json.Marshal(query) queryJSON, err := json.Marshal(query)
if err != nil { if err != nil {
return nil, err return nil, err
} }
loadBalancers, err := enumerateLoadBalancers(string(queryJson)) loadBalancers, err := enumerateLoadBalancers(string(queryJSON))
if err != nil { if err != nil {
return nil, err return nil, err
} }
@ -199,9 +201,9 @@ func ListLoadBalancersQuery(query HostComputeQuery) ([]HostComputeLoadBalancer,
} }
// GetLoadBalancerByID returns the LoadBalancer specified by Id. // GetLoadBalancerByID returns the LoadBalancer specified by Id.
func GetLoadBalancerByID(loadBalancerId string) (*HostComputeLoadBalancer, error) { func GetLoadBalancerByID(loadBalancerID string) (*HostComputeLoadBalancer, error) {
hcnQuery := defaultQuery() hcnQuery := defaultQuery()
mapA := map[string]string{"ID": loadBalancerId} mapA := map[string]string{"ID": loadBalancerID}
filter, err := json.Marshal(mapA) filter, err := json.Marshal(mapA)
if err != nil { if err != nil {
return nil, err return nil, err
@ -213,7 +215,7 @@ func GetLoadBalancerByID(loadBalancerId string) (*HostComputeLoadBalancer, error
return nil, err return nil, err
} }
if len(loadBalancers) == 0 { if len(loadBalancers) == 0 {
return nil, LoadBalancerNotFoundError{LoadBalancerId: loadBalancerId} return nil, LoadBalancerNotFoundError{LoadBalancerId: loadBalancerID}
} }
return &loadBalancers[0], err return &loadBalancers[0], err
} }

View File

@ -1,3 +1,5 @@
//go:build windows
package hcn package hcn
import ( import (
@ -27,7 +29,7 @@ type NamespaceResourceContainer struct {
type NamespaceResourceType string type NamespaceResourceType string
var ( var (
// NamespaceResourceTypeContainer are contianers associated with a Namespace. // NamespaceResourceTypeContainer are containers associated with a Namespace.
NamespaceResourceTypeContainer NamespaceResourceType = "Container" NamespaceResourceTypeContainer NamespaceResourceType = "Container"
// NamespaceResourceTypeEndpoint are endpoints associated with a Namespace. // NamespaceResourceTypeEndpoint are endpoints associated with a Namespace.
NamespaceResourceTypeEndpoint NamespaceResourceType = "Endpoint" NamespaceResourceTypeEndpoint NamespaceResourceType = "Endpoint"
@ -70,14 +72,14 @@ type ModifyNamespaceSettingRequest struct {
Settings json.RawMessage `json:",omitempty"` Settings json.RawMessage `json:",omitempty"`
} }
func getNamespace(namespaceGuid guid.GUID, query string) (*HostComputeNamespace, error) { func getNamespace(namespaceGUID guid.GUID, query string) (*HostComputeNamespace, error) {
// Open namespace. // Open namespace.
var ( var (
namespaceHandle hcnNamespace namespaceHandle hcnNamespace
resultBuffer *uint16 resultBuffer *uint16
propertiesBuffer *uint16 propertiesBuffer *uint16
) )
hr := hcnOpenNamespace(&namespaceGuid, &namespaceHandle, &resultBuffer) hr := hcnOpenNamespace(&namespaceGUID, &namespaceHandle, &resultBuffer)
if err := checkForErrors("hcnOpenNamespace", hr, resultBuffer); err != nil { if err := checkForErrors("hcnOpenNamespace", hr, resultBuffer); err != nil {
return nil, err return nil, err
} }
@ -118,8 +120,8 @@ func enumerateNamespaces(query string) ([]HostComputeNamespace, error) {
} }
var outputNamespaces []HostComputeNamespace var outputNamespaces []HostComputeNamespace
for _, namespaceGuid := range namespaceIds { for _, namespaceGUID := range namespaceIds {
namespace, err := getNamespace(namespaceGuid, query) namespace, err := getNamespace(namespaceGUID, query)
if err != nil { if err != nil {
return nil, err return nil, err
} }
@ -135,8 +137,8 @@ func createNamespace(settings string) (*HostComputeNamespace, error) {
resultBuffer *uint16 resultBuffer *uint16
propertiesBuffer *uint16 propertiesBuffer *uint16
) )
namespaceGuid := guid.GUID{} namespaceGUID := guid.GUID{}
hr := hcnCreateNamespace(&namespaceGuid, settings, &namespaceHandle, &resultBuffer) hr := hcnCreateNamespace(&namespaceGUID, settings, &namespaceHandle, &resultBuffer)
if err := checkForErrors("hcnCreateNamespace", hr, resultBuffer); err != nil { if err := checkForErrors("hcnCreateNamespace", hr, resultBuffer); err != nil {
return nil, err return nil, err
} }
@ -164,8 +166,8 @@ func createNamespace(settings string) (*HostComputeNamespace, error) {
return &outputNamespace, nil return &outputNamespace, nil
} }
func modifyNamespace(namespaceId string, settings string) (*HostComputeNamespace, error) { func modifyNamespace(namespaceID string, settings string) (*HostComputeNamespace, error) {
namespaceGuid, err := guid.FromString(namespaceId) namespaceGUID, err := guid.FromString(namespaceID)
if err != nil { if err != nil {
return nil, errInvalidNamespaceID return nil, errInvalidNamespaceID
} }
@ -175,7 +177,7 @@ func modifyNamespace(namespaceId string, settings string) (*HostComputeNamespace
resultBuffer *uint16 resultBuffer *uint16
propertiesBuffer *uint16 propertiesBuffer *uint16
) )
hr := hcnOpenNamespace(&namespaceGuid, &namespaceHandle, &resultBuffer) hr := hcnOpenNamespace(&namespaceGUID, &namespaceHandle, &resultBuffer)
if err := checkForErrors("hcnOpenNamespace", hr, resultBuffer); err != nil { if err := checkForErrors("hcnOpenNamespace", hr, resultBuffer); err != nil {
return nil, err return nil, err
} }
@ -208,13 +210,13 @@ func modifyNamespace(namespaceId string, settings string) (*HostComputeNamespace
return &outputNamespace, nil return &outputNamespace, nil
} }
func deleteNamespace(namespaceId string) error { func deleteNamespace(namespaceID string) error {
namespaceGuid, err := guid.FromString(namespaceId) namespaceGUID, err := guid.FromString(namespaceID)
if err != nil { if err != nil {
return errInvalidNamespaceID return errInvalidNamespaceID
} }
var resultBuffer *uint16 var resultBuffer *uint16
hr := hcnDeleteNamespace(&namespaceGuid, &resultBuffer) hr := hcnDeleteNamespace(&namespaceGUID, &resultBuffer)
if err := checkForErrors("hcnDeleteNamespace", hr, resultBuffer); err != nil { if err := checkForErrors("hcnDeleteNamespace", hr, resultBuffer); err != nil {
return err return err
} }
@ -233,12 +235,12 @@ func ListNamespaces() ([]HostComputeNamespace, error) {
// ListNamespacesQuery makes a call to query the list of available namespaces. // ListNamespacesQuery makes a call to query the list of available namespaces.
func ListNamespacesQuery(query HostComputeQuery) ([]HostComputeNamespace, error) { func ListNamespacesQuery(query HostComputeQuery) ([]HostComputeNamespace, error) {
queryJson, err := json.Marshal(query) queryJSON, err := json.Marshal(query)
if err != nil { if err != nil {
return nil, err return nil, err
} }
namespaces, err := enumerateNamespaces(string(queryJson)) namespaces, err := enumerateNamespaces(string(queryJSON))
if err != nil { if err != nil {
return nil, err return nil, err
} }
@ -246,9 +248,9 @@ func ListNamespacesQuery(query HostComputeQuery) ([]HostComputeNamespace, error)
} }
// GetNamespaceByID returns the Namespace specified by Id. // GetNamespaceByID returns the Namespace specified by Id.
func GetNamespaceByID(namespaceId string) (*HostComputeNamespace, error) { func GetNamespaceByID(namespaceID string) (*HostComputeNamespace, error) {
hcnQuery := defaultQuery() hcnQuery := defaultQuery()
mapA := map[string]string{"ID": namespaceId} mapA := map[string]string{"ID": namespaceID}
filter, err := json.Marshal(mapA) filter, err := json.Marshal(mapA)
if err != nil { if err != nil {
return nil, err return nil, err
@ -260,15 +262,15 @@ func GetNamespaceByID(namespaceId string) (*HostComputeNamespace, error) {
return nil, err return nil, err
} }
if len(namespaces) == 0 { if len(namespaces) == 0 {
return nil, NamespaceNotFoundError{NamespaceID: namespaceId} return nil, NamespaceNotFoundError{NamespaceID: namespaceID}
} }
return &namespaces[0], err return &namespaces[0], err
} }
// GetNamespaceEndpointIds returns the endpoints of the Namespace specified by Id. // GetNamespaceEndpointIds returns the endpoints of the Namespace specified by Id.
func GetNamespaceEndpointIds(namespaceId string) ([]string, error) { func GetNamespaceEndpointIds(namespaceID string) ([]string, error) {
namespace, err := GetNamespaceByID(namespaceId) namespace, err := GetNamespaceByID(namespaceID)
if err != nil { if err != nil {
return nil, err return nil, err
} }
@ -286,19 +288,19 @@ func GetNamespaceEndpointIds(namespaceId string) ([]string, error) {
} }
// GetNamespaceContainerIds returns the containers of the Namespace specified by Id. // GetNamespaceContainerIds returns the containers of the Namespace specified by Id.
func GetNamespaceContainerIds(namespaceId string) ([]string, error) { func GetNamespaceContainerIds(namespaceID string) ([]string, error) {
namespace, err := GetNamespaceByID(namespaceId) namespace, err := GetNamespaceByID(namespaceID)
if err != nil { if err != nil {
return nil, err return nil, err
} }
var containerIds []string var containerIds []string
for _, resource := range namespace.Resources { for _, resource := range namespace.Resources {
if resource.Type == "Container" { if resource.Type == "Container" {
var contaienrResource NamespaceResourceContainer var containerResource NamespaceResourceContainer
if err := json.Unmarshal([]byte(resource.Data), &contaienrResource); err != nil { if err := json.Unmarshal([]byte(resource.Data), &containerResource); err != nil {
return nil, err return nil, err
} }
containerIds = append(containerIds, contaienrResource.Id) containerIds = append(containerIds, containerResource.Id)
} }
} }
return containerIds, nil return containerIds, nil
@ -375,7 +377,7 @@ func (namespace *HostComputeNamespace) Sync() error {
} }
shimPath := runhcs.VMPipePath(cfg.HostUniqueID) shimPath := runhcs.VMPipePath(cfg.HostUniqueID)
if err := runhcs.IssueVMRequest(shimPath, &req); err != nil { if err := runhcs.IssueVMRequest(shimPath, &req); err != nil {
// The shim is likey gone. Simply ignore the sync as if it didn't exist. // The shim is likely gone. Simply ignore the sync as if it didn't exist.
if perr, ok := err.(*os.PathError); ok && perr.Err == syscall.ERROR_FILE_NOT_FOUND { if perr, ok := err.(*os.PathError); ok && perr.Err == syscall.ERROR_FILE_NOT_FOUND {
// Remove the reg key there is no point to try again // Remove the reg key there is no point to try again
_ = cfg.Remove() _ = cfg.Remove()
@ -394,15 +396,15 @@ func (namespace *HostComputeNamespace) Sync() error {
} }
// ModifyNamespaceSettings updates the Endpoints/Containers of a Namespace. // ModifyNamespaceSettings updates the Endpoints/Containers of a Namespace.
func ModifyNamespaceSettings(namespaceId string, request *ModifyNamespaceSettingRequest) error { func ModifyNamespaceSettings(namespaceID string, request *ModifyNamespaceSettingRequest) error {
logrus.Debugf("hcn::HostComputeNamespace::ModifyNamespaceSettings id=%s", namespaceId) logrus.Debugf("hcn::HostComputeNamespace::ModifyNamespaceSettings id=%s", namespaceID)
namespaceSettings, err := json.Marshal(request) namespaceSettings, err := json.Marshal(request)
if err != nil { if err != nil {
return err return err
} }
_, err = modifyNamespace(namespaceId, string(namespaceSettings)) _, err = modifyNamespace(namespaceID, string(namespaceSettings))
if err != nil { if err != nil {
return err return err
} }
@ -410,37 +412,37 @@ func ModifyNamespaceSettings(namespaceId string, request *ModifyNamespaceSetting
} }
// AddNamespaceEndpoint adds an endpoint to a Namespace. // AddNamespaceEndpoint adds an endpoint to a Namespace.
func AddNamespaceEndpoint(namespaceId string, endpointId string) error { func AddNamespaceEndpoint(namespaceID string, endpointID string) error {
logrus.Debugf("hcn::HostComputeEndpoint::AddNamespaceEndpoint id=%s", endpointId) logrus.Debugf("hcn::HostComputeEndpoint::AddNamespaceEndpoint id=%s", endpointID)
mapA := map[string]string{"EndpointId": endpointId} mapA := map[string]string{"EndpointId": endpointID}
settingsJson, err := json.Marshal(mapA) settingsJSON, err := json.Marshal(mapA)
if err != nil { if err != nil {
return err return err
} }
requestMessage := &ModifyNamespaceSettingRequest{ requestMessage := &ModifyNamespaceSettingRequest{
ResourceType: NamespaceResourceTypeEndpoint, ResourceType: NamespaceResourceTypeEndpoint,
RequestType: RequestTypeAdd, RequestType: RequestTypeAdd,
Settings: settingsJson, Settings: settingsJSON,
} }
return ModifyNamespaceSettings(namespaceId, requestMessage) return ModifyNamespaceSettings(namespaceID, requestMessage)
} }
// RemoveNamespaceEndpoint removes an endpoint from a Namespace. // RemoveNamespaceEndpoint removes an endpoint from a Namespace.
func RemoveNamespaceEndpoint(namespaceId string, endpointId string) error { func RemoveNamespaceEndpoint(namespaceID string, endpointID string) error {
logrus.Debugf("hcn::HostComputeNamespace::RemoveNamespaceEndpoint id=%s", endpointId) logrus.Debugf("hcn::HostComputeNamespace::RemoveNamespaceEndpoint id=%s", endpointID)
mapA := map[string]string{"EndpointId": endpointId} mapA := map[string]string{"EndpointId": endpointID}
settingsJson, err := json.Marshal(mapA) settingsJSON, err := json.Marshal(mapA)
if err != nil { if err != nil {
return err return err
} }
requestMessage := &ModifyNamespaceSettingRequest{ requestMessage := &ModifyNamespaceSettingRequest{
ResourceType: NamespaceResourceTypeEndpoint, ResourceType: NamespaceResourceTypeEndpoint,
RequestType: RequestTypeRemove, RequestType: RequestTypeRemove,
Settings: settingsJson, Settings: settingsJSON,
} }
return ModifyNamespaceSettings(namespaceId, requestMessage) return ModifyNamespaceSettings(namespaceID, requestMessage)
} }

View File

@ -1,3 +1,5 @@
//go:build windows
package hcn package hcn
import ( import (
@ -110,14 +112,14 @@ type PolicyNetworkRequest struct {
Policies []NetworkPolicy `json:",omitempty"` Policies []NetworkPolicy `json:",omitempty"`
} }
func getNetwork(networkGuid guid.GUID, query string) (*HostComputeNetwork, error) { func getNetwork(networkGUID guid.GUID, query string) (*HostComputeNetwork, error) {
// Open network. // Open network.
var ( var (
networkHandle hcnNetwork networkHandle hcnNetwork
resultBuffer *uint16 resultBuffer *uint16
propertiesBuffer *uint16 propertiesBuffer *uint16
) )
hr := hcnOpenNetwork(&networkGuid, &networkHandle, &resultBuffer) hr := hcnOpenNetwork(&networkGUID, &networkHandle, &resultBuffer)
if err := checkForErrors("hcnOpenNetwork", hr, resultBuffer); err != nil { if err := checkForErrors("hcnOpenNetwork", hr, resultBuffer); err != nil {
return nil, err return nil, err
} }
@ -164,8 +166,8 @@ func enumerateNetworks(query string) ([]HostComputeNetwork, error) {
} }
var outputNetworks []HostComputeNetwork var outputNetworks []HostComputeNetwork
for _, networkGuid := range networkIds { for _, networkGUID := range networkIds {
network, err := getNetwork(networkGuid, query) network, err := getNetwork(networkGUID, query)
if err != nil { if err != nil {
return nil, err return nil, err
} }
@ -181,8 +183,8 @@ func createNetwork(settings string) (*HostComputeNetwork, error) {
resultBuffer *uint16 resultBuffer *uint16
propertiesBuffer *uint16 propertiesBuffer *uint16
) )
networkGuid := guid.GUID{} networkGUID := guid.GUID{}
hr := hcnCreateNetwork(&networkGuid, settings, &networkHandle, &resultBuffer) hr := hcnCreateNetwork(&networkGUID, settings, &networkHandle, &resultBuffer)
if err := checkForErrors("hcnCreateNetwork", hr, resultBuffer); err != nil { if err := checkForErrors("hcnCreateNetwork", hr, resultBuffer); err != nil {
return nil, err return nil, err
} }
@ -216,8 +218,8 @@ func createNetwork(settings string) (*HostComputeNetwork, error) {
return &outputNetwork, nil return &outputNetwork, nil
} }
func modifyNetwork(networkId string, settings string) (*HostComputeNetwork, error) { func modifyNetwork(networkID string, settings string) (*HostComputeNetwork, error) {
networkGuid, err := guid.FromString(networkId) networkGUID, err := guid.FromString(networkID)
if err != nil { if err != nil {
return nil, errInvalidNetworkID return nil, errInvalidNetworkID
} }
@ -227,7 +229,7 @@ func modifyNetwork(networkId string, settings string) (*HostComputeNetwork, erro
resultBuffer *uint16 resultBuffer *uint16
propertiesBuffer *uint16 propertiesBuffer *uint16
) )
hr := hcnOpenNetwork(&networkGuid, &networkHandle, &resultBuffer) hr := hcnOpenNetwork(&networkGUID, &networkHandle, &resultBuffer)
if err := checkForErrors("hcnOpenNetwork", hr, resultBuffer); err != nil { if err := checkForErrors("hcnOpenNetwork", hr, resultBuffer); err != nil {
return nil, err return nil, err
} }
@ -266,13 +268,13 @@ func modifyNetwork(networkId string, settings string) (*HostComputeNetwork, erro
return &outputNetwork, nil return &outputNetwork, nil
} }
func deleteNetwork(networkId string) error { func deleteNetwork(networkID string) error {
networkGuid, err := guid.FromString(networkId) networkGUID, err := guid.FromString(networkID)
if err != nil { if err != nil {
return errInvalidNetworkID return errInvalidNetworkID
} }
var resultBuffer *uint16 var resultBuffer *uint16
hr := hcnDeleteNetwork(&networkGuid, &resultBuffer) hr := hcnDeleteNetwork(&networkGUID, &resultBuffer)
if err := checkForErrors("hcnDeleteNetwork", hr, resultBuffer); err != nil { if err := checkForErrors("hcnDeleteNetwork", hr, resultBuffer); err != nil {
return err return err
} }
@ -291,12 +293,12 @@ func ListNetworks() ([]HostComputeNetwork, error) {
// ListNetworksQuery makes a call to query the list of available networks. // ListNetworksQuery makes a call to query the list of available networks.
func ListNetworksQuery(query HostComputeQuery) ([]HostComputeNetwork, error) { func ListNetworksQuery(query HostComputeQuery) ([]HostComputeNetwork, error) {
queryJson, err := json.Marshal(query) queryJSON, err := json.Marshal(query)
if err != nil { if err != nil {
return nil, err return nil, err
} }
networks, err := enumerateNetworks(string(queryJson)) networks, err := enumerateNetworks(string(queryJSON))
if err != nil { if err != nil {
return nil, err return nil, err
} }
@ -408,14 +410,14 @@ func (network *HostComputeNetwork) ModifyNetworkSettings(request *ModifyNetworkS
func (network *HostComputeNetwork) AddPolicy(networkPolicy PolicyNetworkRequest) error { func (network *HostComputeNetwork) AddPolicy(networkPolicy PolicyNetworkRequest) error {
logrus.Debugf("hcn::HostComputeNetwork::AddPolicy id=%s", network.Id) logrus.Debugf("hcn::HostComputeNetwork::AddPolicy id=%s", network.Id)
settingsJson, err := json.Marshal(networkPolicy) settingsJSON, err := json.Marshal(networkPolicy)
if err != nil { if err != nil {
return err return err
} }
requestMessage := &ModifyNetworkSettingRequest{ requestMessage := &ModifyNetworkSettingRequest{
ResourceType: NetworkResourceTypePolicy, ResourceType: NetworkResourceTypePolicy,
RequestType: RequestTypeAdd, RequestType: RequestTypeAdd,
Settings: settingsJson, Settings: settingsJSON,
} }
return network.ModifyNetworkSettings(requestMessage) return network.ModifyNetworkSettings(requestMessage)
@ -425,14 +427,14 @@ func (network *HostComputeNetwork) AddPolicy(networkPolicy PolicyNetworkRequest)
func (network *HostComputeNetwork) RemovePolicy(networkPolicy PolicyNetworkRequest) error { func (network *HostComputeNetwork) RemovePolicy(networkPolicy PolicyNetworkRequest) error {
logrus.Debugf("hcn::HostComputeNetwork::RemovePolicy id=%s", network.Id) logrus.Debugf("hcn::HostComputeNetwork::RemovePolicy id=%s", network.Id)
settingsJson, err := json.Marshal(networkPolicy) settingsJSON, err := json.Marshal(networkPolicy)
if err != nil { if err != nil {
return err return err
} }
requestMessage := &ModifyNetworkSettingRequest{ requestMessage := &ModifyNetworkSettingRequest{
ResourceType: NetworkResourceTypePolicy, ResourceType: NetworkResourceTypePolicy,
RequestType: RequestTypeRemove, RequestType: RequestTypeRemove,
Settings: settingsJson, Settings: settingsJSON,
} }
return network.ModifyNetworkSettings(requestMessage) return network.ModifyNetworkSettings(requestMessage)

View File

@ -1,3 +1,5 @@
//go:build windows
package hcn package hcn
import ( import (
@ -23,7 +25,7 @@ const (
// Endpoint and Network have InterfaceConstraint and ProviderAddress // Endpoint and Network have InterfaceConstraint and ProviderAddress
NetworkProviderAddress EndpointPolicyType = "ProviderAddress" NetworkProviderAddress EndpointPolicyType = "ProviderAddress"
NetworkInterfaceConstraint EndpointPolicyType = "InterfaceConstraint" NetworkInterfaceConstraint EndpointPolicyType = "InterfaceConstraint"
TierAcl EndpointPolicyType = "TierAcl" TierAcl EndpointPolicyType = "TierAcl"
) )
// EndpointPolicy is a collection of Policy settings for an Endpoint. // EndpointPolicy is a collection of Policy settings for an Endpoint.
@ -133,7 +135,7 @@ type AclPolicySetting struct {
RemotePorts string `json:",omitempty"` RemotePorts string `json:",omitempty"`
RuleType RuleType `json:",omitempty"` RuleType RuleType `json:",omitempty"`
Priority uint16 `json:",omitempty"` Priority uint16 `json:",omitempty"`
} }
// QosPolicySetting sets Quality of Service bandwidth caps on an Endpoint. // QosPolicySetting sets Quality of Service bandwidth caps on an Endpoint.
type QosPolicySetting struct { type QosPolicySetting struct {
@ -166,7 +168,7 @@ type NetworkACLPolicySetting struct {
RemotePorts string `json:",omitempty"` RemotePorts string `json:",omitempty"`
RuleType RuleType `json:",omitempty"` RuleType RuleType `json:",omitempty"`
Priority uint16 `json:",omitempty"` Priority uint16 `json:",omitempty"`
} }
// FiveTuple is nested in L4ProxyPolicySetting for WFP support. // FiveTuple is nested in L4ProxyPolicySetting for WFP support.
type FiveTuple struct { type FiveTuple struct {
@ -284,7 +286,7 @@ type RemoteSubnetRoutePolicySetting struct {
type SetPolicyType string type SetPolicyType string
const ( const (
SetPolicyTypeIpSet SetPolicyType = "IPSET" SetPolicyTypeIpSet SetPolicyType = "IPSET"
SetPolicyTypeNestedIpSet SetPolicyType = "NESTEDIPSET" SetPolicyTypeNestedIpSet SetPolicyType = "NESTEDIPSET"
) )
@ -292,7 +294,7 @@ const (
type SetPolicySetting struct { type SetPolicySetting struct {
Id string Id string
Name string Name string
Type SetPolicyType Type SetPolicyType `json:"PolicyType"`
Values string Values string
} }
@ -313,32 +315,32 @@ const (
ProtocolTypeICMPv6 ProtocolType = 58 ProtocolTypeICMPv6 ProtocolType = 58
) )
//L4ProxyPolicySetting applies proxy policy on network/endpoint // L4ProxyPolicySetting applies proxy policy on network/endpoint
type L4ProxyPolicySetting struct { type L4ProxyPolicySetting struct {
IP string `json:",omitempty"` IP string `json:",omitempty"`
Port string `json:",omitempty"` Port string `json:",omitempty"`
Protocol ProtocolType `json:",omitempty"` Protocol ProtocolType `json:",omitempty"`
Exceptions []string `json:",omitempty"` Exceptions []string `json:",omitempty"`
Destination string Destination string
OutboundNAT bool `json:",omitempty"` OutboundNAT bool `json:",omitempty"`
} }
// TierAclRule represents an ACL within TierAclPolicySetting // TierAclRule represents an ACL within TierAclPolicySetting
type TierAclRule struct { type TierAclRule struct {
Id string `json:",omitempty"` Id string `json:",omitempty"`
Protocols string `json:",omitempty"` Protocols string `json:",omitempty"`
TierAclRuleAction ActionType `json:","` TierAclRuleAction ActionType `json:","`
LocalAddresses string `json:",omitempty"` LocalAddresses string `json:",omitempty"`
RemoteAddresses string `json:",omitempty"` RemoteAddresses string `json:",omitempty"`
LocalPorts string `json:",omitempty"` LocalPorts string `json:",omitempty"`
RemotePorts string `json:",omitempty"` RemotePorts string `json:",omitempty"`
Priority uint16 `json:",omitempty"` Priority uint16 `json:",omitempty"`
} }
// TierAclPolicySetting represents a Tier containing ACLs // TierAclPolicySetting represents a Tier containing ACLs
type TierAclPolicySetting struct { type TierAclPolicySetting struct {
Name string `json:","` Name string `json:","`
Direction DirectionType `json:","` Direction DirectionType `json:","`
Order uint16 `json:""` Order uint16 `json:""`
TierAclRules []TierAclRule `json:",omitempty"` TierAclRules []TierAclRule `json:",omitempty"`
} }

View File

@ -1,3 +1,5 @@
//go:build windows
package hcn package hcn
import ( import (

View File

@ -1,11 +1,14 @@
//go:build windows
package hcn package hcn
import ( import (
"fmt"
"sync" "sync"
"github.com/pkg/errors" "github.com/pkg/errors"
"github.com/sirupsen/logrus" "github.com/sirupsen/logrus"
"github.com/Microsoft/hcsshim/internal/log"
) )
var ( var (
@ -112,9 +115,9 @@ func getSupportedFeatures() (SupportedFeatures, error) {
features.NetworkACL = isFeatureSupported(globals.Version, NetworkACLPolicyVersion) features.NetworkACL = isFeatureSupported(globals.Version, NetworkACLPolicyVersion)
features.NestedIpSet = isFeatureSupported(globals.Version, NestedIpSetVersion) features.NestedIpSet = isFeatureSupported(globals.Version, NestedIpSetVersion)
logrus.WithFields(logrus.Fields{ log.L.WithFields(logrus.Fields{
"version": fmt.Sprintf("%+v", globals.Version), "version": globals.Version,
"supportedFeatures": fmt.Sprintf("%+v", features), "supportedFeatures": features,
}).Info("HCN feature check") }).Info("HCN feature check")
return features, nil return features, nil

File diff suppressed because it is too large Load Diff

View File

@ -1,15 +1,17 @@
//go:build windows
// Shim for the Host Compute Service (HCS) to manage Windows Server // Shim for the Host Compute Service (HCS) to manage Windows Server
// containers and Hyper-V containers. // containers and Hyper-V containers.
package hcsshim package hcsshim
import ( import (
"syscall" "golang.org/x/sys/windows"
"github.com/Microsoft/hcsshim/internal/hcserror" "github.com/Microsoft/hcsshim/internal/hcserror"
) )
//go:generate go run mksyscall_windows.go -output zsyscall_windows.go hcsshim.go //go:generate go run github.com/Microsoft/go-winio/tools/mkwinsyscall -output zsyscall_windows.go hcsshim.go
//sys SetCurrentThreadCompartmentId(compartmentId uint32) (hr error) = iphlpapi.SetCurrentThreadCompartmentId //sys SetCurrentThreadCompartmentId(compartmentId uint32) (hr error) = iphlpapi.SetCurrentThreadCompartmentId
@ -17,9 +19,9 @@ const (
// Specific user-visible exit codes // Specific user-visible exit codes
WaitErrExecFailed = 32767 WaitErrExecFailed = 32767
ERROR_GEN_FAILURE = hcserror.ERROR_GEN_FAILURE ERROR_GEN_FAILURE = windows.ERROR_GEN_FAILURE
ERROR_SHUTDOWN_IN_PROGRESS = syscall.Errno(1115) ERROR_SHUTDOWN_IN_PROGRESS = windows.ERROR_SHUTDOWN_IN_PROGRESS
WSAEINVAL = syscall.Errno(10022) WSAEINVAL = windows.WSAEINVAL
// Timeout on wait calls // Timeout on wait calls
TimeoutInfinite = 0xFFFFFFFF TimeoutInfinite = 0xFFFFFFFF

View File

@ -1,3 +1,5 @@
//go:build windows
package hcsshim package hcsshim
import ( import (
@ -13,7 +15,7 @@ type HNSEndpointStats = hns.EndpointStats
// Namespace represents a Compartment. // Namespace represents a Compartment.
type Namespace = hns.Namespace type Namespace = hns.Namespace
//SystemType represents the type of the system on which actions are done // SystemType represents the type of the system on which actions are done
type SystemType string type SystemType string
// SystemType const // SystemType const

View File

@ -1,3 +1,5 @@
//go:build windows
package hcsshim package hcsshim
import ( import (

View File

@ -1,14 +1,16 @@
//go:build windows
package hcsshim package hcsshim
import ( import (
"github.com/Microsoft/hcsshim/internal/hns" "github.com/Microsoft/hcsshim/internal/hns"
) )
// Subnet is assoicated with a network and represents a list // Subnet is associated with a network and represents a list
// of subnets available to the network // of subnets available to the network
type Subnet = hns.Subnet type Subnet = hns.Subnet
// MacPool is assoicated with a network and represents a list // MacPool is associated with a network and represents a list
// of macaddresses available to the network // of macaddresses available to the network
type MacPool = hns.MacPool type MacPool = hns.MacPool

View File

@ -1,3 +1,5 @@
//go:build windows
package hcsshim package hcsshim
import ( import (

View File

@ -1,3 +1,5 @@
//go:build windows
package hcsshim package hcsshim
import ( import (

View File

@ -1,3 +1,5 @@
//go:build windows
package hcsshim package hcsshim
import ( import (

View File

@ -0,0 +1 @@
package cni

View File

@ -1,3 +1,5 @@
//go:build windows
package cni package cni
import ( import (
@ -84,7 +86,7 @@ func (pnc *PersistedNamespaceConfig) Store() error {
} }
// Remove removes any persisted state associated with this config. If the config // Remove removes any persisted state associated with this config. If the config
// is not found in the registery `Remove` returns no error. // is not found in the registry `Remove` returns no error.
func (pnc *PersistedNamespaceConfig) Remove() error { func (pnc *PersistedNamespaceConfig) Remove() error {
if pnc.stored { if pnc.stored {
sk, err := regstate.Open(cniRoot, false) sk, err := regstate.Open(cniRoot, false)

View File

@ -1,3 +1,5 @@
//go:build windows
package cow package cow
import ( import (

View File

@ -1,3 +1,5 @@
//go:build windows
package hcs package hcs
import ( import (

View File

@ -0,0 +1 @@
package hcs

View File

@ -1,3 +1,5 @@
//go:build windows
package hcs package hcs
import ( import (
@ -51,6 +53,9 @@ var (
// ErrUnexpectedValue is an error encountered when hcs returns an invalid value // ErrUnexpectedValue is an error encountered when hcs returns an invalid value
ErrUnexpectedValue = errors.New("unexpected value returned from hcs") ErrUnexpectedValue = errors.New("unexpected value returned from hcs")
// ErrOperationDenied is an error when hcs attempts an operation that is explicitly denied
ErrOperationDenied = errors.New("operation denied")
// ErrVmcomputeAlreadyStopped is an error encountered when a shutdown or terminate request is made on a stopped container // ErrVmcomputeAlreadyStopped is an error encountered when a shutdown or terminate request is made on a stopped container
ErrVmcomputeAlreadyStopped = syscall.Errno(0xc0370110) ErrVmcomputeAlreadyStopped = syscall.Errno(0xc0370110)
@ -82,7 +87,7 @@ var (
// ErrProcessAlreadyStopped is returned by hcs if the process we're trying to kill has already been stopped. // ErrProcessAlreadyStopped is returned by hcs if the process we're trying to kill has already been stopped.
ErrProcessAlreadyStopped = syscall.Errno(0x8037011f) 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 // ErrInvalidHandle is an error that can be encountered when querying the properties of a compute system when the handle to that
// compute system has already been closed. // compute system has already been closed.
ErrInvalidHandle = syscall.Errno(0x6) ErrInvalidHandle = syscall.Errno(0x6)
) )
@ -152,33 +157,38 @@ func (e *HcsError) Error() string {
return s return s
} }
func (e *HcsError) Is(target error) bool {
return errors.Is(e.Err, target)
}
// unwrap isnt really needed, but helpful convince function
func (e *HcsError) Unwrap() error {
return e.Err
}
// Deprecated: net.Error.Temporary is deprecated.
func (e *HcsError) Temporary() bool { func (e *HcsError) Temporary() bool {
err, ok := e.Err.(net.Error) err := e.netError()
return ok && err.Temporary() //nolint:staticcheck return (err != nil) && err.Temporary()
} }
func (e *HcsError) Timeout() bool { func (e *HcsError) Timeout() bool {
err, ok := e.Err.(net.Error) err := e.netError()
return ok && err.Timeout() return (err != nil) && err.Timeout()
} }
// ProcessError is an error encountered in HCS during an operation on a Process object func (e *HcsError) netError() (err net.Error) {
type ProcessError struct { if errors.As(e.Unwrap(), &err) {
SystemID string return err
Pid int }
Op string return nil
Err error
Events []ErrorEvent
} }
var _ net.Error = &ProcessError{}
// SystemError is an error encountered in HCS during an operation on a Container object // SystemError is an error encountered in HCS during an operation on a Container object
type SystemError struct { type SystemError struct {
ID string HcsError
Op string ID string
Err error
Events []ErrorEvent
} }
var _ net.Error = &SystemError{} var _ net.Error = &SystemError{}
@ -191,29 +201,32 @@ func (e *SystemError) Error() string {
return s 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 { func makeSystemError(system *System, op string, err error, events []ErrorEvent) error {
// Don't double wrap errors // Don't double wrap errors
if _, ok := err.(*SystemError); ok { var e *SystemError
if errors.As(err, &e) {
return err return err
} }
return &SystemError{ return &SystemError{
ID: system.ID(), ID: system.ID(),
Op: op, HcsError: HcsError{
Err: err, Op: op,
Events: events, Err: err,
Events: events,
},
} }
} }
// ProcessError is an error encountered in HCS during an operation on a Process object
type ProcessError struct {
HcsError
SystemID string
Pid int
}
var _ net.Error = &ProcessError{}
func (e *ProcessError) Error() string { func (e *ProcessError) Error() string {
s := fmt.Sprintf("%s %s:%d: %s", e.Op, e.SystemID, e.Pid, e.Err.Error()) s := fmt.Sprintf("%s %s:%d: %s", e.Op, e.SystemID, e.Pid, e.Err.Error())
for _, ev := range e.Events { for _, ev := range e.Events {
@ -222,27 +235,20 @@ func (e *ProcessError) Error() string {
return s 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 { func makeProcessError(process *Process, op string, err error, events []ErrorEvent) error {
// Don't double wrap errors // Don't double wrap errors
if _, ok := err.(*ProcessError); ok { var e *ProcessError
if errors.As(err, &e) {
return err return err
} }
return &ProcessError{ return &ProcessError{
Pid: process.Pid(), Pid: process.Pid(),
SystemID: process.SystemID(), SystemID: process.SystemID(),
Op: op, HcsError: HcsError{
Err: err, Op: op,
Events: events, Err: err,
Events: events,
},
} }
} }
@ -251,41 +257,41 @@ func makeProcessError(process *Process, op string, err error, events []ErrorEven
// already exited, or does not exist. Both IsAlreadyStopped and IsNotExist // already exited, or does not exist. Both IsAlreadyStopped and IsNotExist
// will currently return true when the error is ErrElementNotFound. // will currently return true when the error is ErrElementNotFound.
func IsNotExist(err error) bool { func IsNotExist(err error) bool {
err = getInnerError(err) return IsAny(err, ErrComputeSystemDoesNotExist, ErrElementNotFound)
return err == ErrComputeSystemDoesNotExist ||
err == ErrElementNotFound
} }
// IsErrorInvalidHandle checks whether the error is the result of an operation carried // 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 // 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. // stats on a container in the process of being stopped.
func IsErrorInvalidHandle(err error) bool { func IsErrorInvalidHandle(err error) bool {
err = getInnerError(err) return errors.Is(err, ErrInvalidHandle)
return err == ErrInvalidHandle
} }
// IsAlreadyClosed checks if an error is caused by the Container or Process having been // IsAlreadyClosed checks if an error is caused by the Container or Process having been
// already closed by a call to the Close() method. // already closed by a call to the Close() method.
func IsAlreadyClosed(err error) bool { func IsAlreadyClosed(err error) bool {
err = getInnerError(err) return errors.Is(err, ErrAlreadyClosed)
return err == ErrAlreadyClosed
} }
// IsPending returns a boolean indicating whether the error is that // IsPending returns a boolean indicating whether the error is that
// the requested operation is being completed in the background. // the requested operation is being completed in the background.
func IsPending(err error) bool { func IsPending(err error) bool {
err = getInnerError(err) return errors.Is(err, ErrVmcomputeOperationPending)
return err == ErrVmcomputeOperationPending
} }
// IsTimeout returns a boolean indicating whether the error is caused by // IsTimeout returns a boolean indicating whether the error is caused by
// a timeout waiting for the operation to complete. // a timeout waiting for the operation to complete.
func IsTimeout(err error) bool { func IsTimeout(err error) bool {
if err, ok := err.(net.Error); ok && err.Timeout() { // HcsError and co. implement Timeout regardless of whether the errors they wrap do,
// so `errors.As(err, net.Error)`` will always be true.
// Using `errors.As(err.Unwrap(), net.Err)` wont work for general errors.
// So first check if there an `ErrTimeout` in the chain, then convert to a net error.
if errors.Is(err, ErrTimeout) {
return true return true
} }
err = getInnerError(err)
return err == ErrTimeout var nerr net.Error
return errors.As(err, &nerr) && nerr.Timeout()
} }
// IsAlreadyStopped returns a boolean indicating whether the error is caused by // IsAlreadyStopped returns a boolean indicating whether the error is caused by
@ -294,10 +300,7 @@ func IsTimeout(err error) bool {
// already exited, or does not exist. Both IsAlreadyStopped and IsNotExist // already exited, or does not exist. Both IsAlreadyStopped and IsNotExist
// will currently return true when the error is ErrElementNotFound. // will currently return true when the error is ErrElementNotFound.
func IsAlreadyStopped(err error) bool { func IsAlreadyStopped(err error) bool {
err = getInnerError(err) return IsAny(err, ErrVmcomputeAlreadyStopped, ErrProcessAlreadyStopped, ErrElementNotFound)
return err == ErrVmcomputeAlreadyStopped ||
err == ErrProcessAlreadyStopped ||
err == ErrElementNotFound
} }
// IsNotSupported returns a boolean indicating whether the error is caused by // IsNotSupported returns a boolean indicating whether the error is caused by
@ -306,38 +309,28 @@ func IsAlreadyStopped(err error) bool {
// ErrVmcomputeInvalidJSON, ErrInvalidData, ErrNotSupported or ErrVmcomputeUnknownMessage // ErrVmcomputeInvalidJSON, ErrInvalidData, ErrNotSupported or ErrVmcomputeUnknownMessage
// is thrown from the Platform // is thrown from the Platform
func IsNotSupported(err error) bool { func IsNotSupported(err error) bool {
err = getInnerError(err)
// If Platform doesn't recognize or support the request sent, below errors are seen // If Platform doesn't recognize or support the request sent, below errors are seen
return err == ErrVmcomputeInvalidJSON || return IsAny(err, ErrVmcomputeInvalidJSON, ErrInvalidData, ErrNotSupported, ErrVmcomputeUnknownMessage)
err == ErrInvalidData ||
err == ErrNotSupported ||
err == ErrVmcomputeUnknownMessage
} }
// IsOperationInvalidState returns true when err is caused by // IsOperationInvalidState returns true when err is caused by
// `ErrVmcomputeOperationInvalidState`. // `ErrVmcomputeOperationInvalidState`.
func IsOperationInvalidState(err error) bool { func IsOperationInvalidState(err error) bool {
err = getInnerError(err) return errors.Is(err, ErrVmcomputeOperationInvalidState)
return err == ErrVmcomputeOperationInvalidState
} }
// IsAccessIsDenied returns true when err is caused by // IsAccessIsDenied returns true when err is caused by
// `ErrVmcomputeOperationAccessIsDenied`. // `ErrVmcomputeOperationAccessIsDenied`.
func IsAccessIsDenied(err error) bool { func IsAccessIsDenied(err error) bool {
err = getInnerError(err) return errors.Is(err, ErrVmcomputeOperationAccessIsDenied)
return err == ErrVmcomputeOperationAccessIsDenied
} }
func getInnerError(err error) error { // IsAny is a vectorized version of [errors.Is], it returns true if err is one of targets.
switch pe := err.(type) { func IsAny(err error, targets ...error) bool {
case nil: for _, e := range targets {
return nil if errors.Is(err, e) {
case *HcsError: return true
err = pe.Err }
case *SystemError:
err = pe.Err
case *ProcessError:
err = pe.Err
} }
return err return false
} }

View File

@ -1,3 +1,5 @@
//go:build windows
package hcs package hcs
import ( import (
@ -10,6 +12,7 @@ import (
"syscall" "syscall"
"time" "time"
"github.com/Microsoft/hcsshim/internal/cow"
"github.com/Microsoft/hcsshim/internal/log" "github.com/Microsoft/hcsshim/internal/log"
"github.com/Microsoft/hcsshim/internal/oc" "github.com/Microsoft/hcsshim/internal/oc"
"github.com/Microsoft/hcsshim/internal/vmcompute" "github.com/Microsoft/hcsshim/internal/vmcompute"
@ -36,6 +39,8 @@ type Process struct {
waitError error waitError error
} }
var _ cow.Process = &Process{}
func newProcess(process vmcompute.HcsProcess, processID int, computeSystem *System) *Process { func newProcess(process vmcompute.HcsProcess, processID int, computeSystem *System) *Process {
return &Process{ return &Process{
handle: process, handle: process,
@ -89,10 +94,7 @@ func (process *Process) processSignalResult(ctx context.Context, err error) (boo
case nil: case nil:
return true, nil return true, nil
case ErrVmcomputeOperationInvalidState, ErrComputeSystemDoesNotExist, ErrElementNotFound: case ErrVmcomputeOperationInvalidState, ErrComputeSystemDoesNotExist, ErrElementNotFound:
select { if !process.stopped() {
case <-process.waitBlock:
// The process exit notification has already arrived.
default:
// The process should be gone, but we have not received the notification. // 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 // After a second, force unblock the process wait to work around a possible
// deadlock in the HCS. // deadlock in the HCS.
@ -114,9 +116,9 @@ func (process *Process) processSignalResult(ctx context.Context, err error) (boo
// Signal signals the process with `options`. // Signal signals the process with `options`.
// //
// For LCOW `guestrequest.SignalProcessOptionsLCOW`. // For LCOW `guestresource.SignalProcessOptionsLCOW`.
// //
// For WCOW `guestrequest.SignalProcessOptionsWCOW`. // For WCOW `guestresource.SignalProcessOptionsWCOW`.
func (process *Process) Signal(ctx context.Context, options interface{}) (bool, error) { func (process *Process) Signal(ctx context.Context, options interface{}) (bool, error) {
process.handleLock.RLock() process.handleLock.RLock()
defer process.handleLock.RUnlock() defer process.handleLock.RUnlock()
@ -152,6 +154,10 @@ func (process *Process) Kill(ctx context.Context) (bool, error) {
return false, makeProcessError(process, operation, ErrAlreadyClosed, nil) return false, makeProcessError(process, operation, ErrAlreadyClosed, nil)
} }
if process.stopped() {
return false, makeProcessError(process, operation, ErrProcessAlreadyStopped, nil)
}
if process.killSignalDelivered { if process.killSignalDelivered {
// A kill signal has already been sent to this process. Sending a second // A kill signal has already been sent to this process. Sending a second
// one offers no real benefit, as processes cannot stop themselves from // one offers no real benefit, as processes cannot stop themselves from
@ -233,7 +239,7 @@ func (process *Process) Kill(ctx context.Context) (bool, error) {
// call multiple times. // call multiple times.
func (process *Process) waitBackground() { func (process *Process) waitBackground() {
operation := "hcs::Process::waitBackground" operation := "hcs::Process::waitBackground"
ctx, span := trace.StartSpan(context.Background(), operation) ctx, span := oc.StartSpan(context.Background(), operation)
defer span.End() defer span.End()
span.AddAttributes( span.AddAttributes(
trace.StringAttribute("cid", process.SystemID()), trace.StringAttribute("cid", process.SystemID()),
@ -259,12 +265,12 @@ func (process *Process) waitBackground() {
propertiesJSON, resultJSON, err = vmcompute.HcsGetProcessProperties(ctx, process.handle) propertiesJSON, resultJSON, err = vmcompute.HcsGetProcessProperties(ctx, process.handle)
events := processHcsResult(ctx, resultJSON) events := processHcsResult(ctx, resultJSON)
if err != nil { if err != nil {
err = makeProcessError(process, operation, err, events) //nolint:ineffassign err = makeProcessError(process, operation, err, events)
} else { } else {
properties := &processStatus{} properties := &processStatus{}
err = json.Unmarshal([]byte(propertiesJSON), properties) err = json.Unmarshal([]byte(propertiesJSON), properties)
if err != nil { if err != nil {
err = makeProcessError(process, operation, err, nil) //nolint:ineffassign err = makeProcessError(process, operation, err, nil)
} else { } else {
if properties.LastWaitResult != 0 { if properties.LastWaitResult != 0 {
log.G(ctx).WithField("wait-result", properties.LastWaitResult).Warning("non-zero last wait result") log.G(ctx).WithField("wait-result", properties.LastWaitResult).Warning("non-zero last wait result")
@ -286,12 +292,22 @@ func (process *Process) waitBackground() {
} }
// Wait waits for the process to exit. If the process has already exited returns // Wait waits for the process to exit. If the process has already exited returns
// the pervious error (if any). // the previous error (if any).
func (process *Process) Wait() error { func (process *Process) Wait() error {
<-process.waitBlock <-process.waitBlock
return process.waitError return process.waitError
} }
// Exited returns if the process has stopped
func (process *Process) stopped() bool {
select {
case <-process.waitBlock:
return true
default:
return false
}
}
// ResizeConsole resizes the console of the process. // ResizeConsole resizes the console of the process.
func (process *Process) ResizeConsole(ctx context.Context, width, height uint16) error { func (process *Process) ResizeConsole(ctx context.Context, width, height uint16) error {
process.handleLock.RLock() process.handleLock.RLock()
@ -328,15 +344,13 @@ func (process *Process) ResizeConsole(ctx context.Context, width, height uint16)
// ExitCode returns the exit code of the process. The process must have // ExitCode returns the exit code of the process. The process must have
// already terminated. // already terminated.
func (process *Process) ExitCode() (int, error) { func (process *Process) ExitCode() (int, error) {
select { if !process.stopped() {
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) return -1, makeProcessError(process, "hcs::Process::ExitCode", ErrInvalidProcessState, nil)
} }
if process.waitError != nil {
return -1, process.waitError
}
return process.exitCode, nil
} }
// StdioLegacy returns the stdin, stdout, and stderr pipes, respectively. Closing // StdioLegacy returns the stdin, stdout, and stderr pipes, respectively. Closing
@ -344,7 +358,7 @@ func (process *Process) ExitCode() (int, error) {
// are the responsibility of the caller to close. // are the responsibility of the caller to close.
func (process *Process) StdioLegacy() (_ io.WriteCloser, _ io.ReadCloser, _ io.ReadCloser, err error) { func (process *Process) StdioLegacy() (_ io.WriteCloser, _ io.ReadCloser, _ io.ReadCloser, err error) {
operation := "hcs::Process::StdioLegacy" operation := "hcs::Process::StdioLegacy"
ctx, span := trace.StartSpan(context.Background(), operation) ctx, span := oc.StartSpan(context.Background(), operation)
defer span.End() defer span.End()
defer func() { oc.SetSpanStatus(span, err) }() defer func() { oc.SetSpanStatus(span, err) }()
span.AddAttributes( span.AddAttributes(
@ -382,7 +396,7 @@ func (process *Process) StdioLegacy() (_ io.WriteCloser, _ io.ReadCloser, _ io.R
} }
// Stdio returns the stdin, stdout, and stderr pipes, respectively. // Stdio returns the stdin, stdout, and stderr pipes, respectively.
// To close them, close the process handle. // To close them, close the process handle, or use the `CloseStd*` functions.
func (process *Process) Stdio() (stdin io.Writer, stdout, stderr io.Reader) { func (process *Process) Stdio() (stdin io.Writer, stdout, stderr io.Reader) {
process.stdioLock.Lock() process.stdioLock.Lock()
defer process.stdioLock.Unlock() defer process.stdioLock.Unlock()
@ -391,46 +405,55 @@ func (process *Process) Stdio() (stdin io.Writer, stdout, stderr io.Reader) {
// CloseStdin closes the write side of the stdin pipe so that the process is // CloseStdin closes the write side of the stdin pipe so that the process is
// notified on the read side that there is no more data in stdin. // notified on the read side that there is no more data in stdin.
func (process *Process) CloseStdin(ctx context.Context) error { func (process *Process) CloseStdin(ctx context.Context) (err error) {
operation := "hcs::Process::CloseStdin"
ctx, span := trace.StartSpan(ctx, 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() process.handleLock.RLock()
defer process.handleLock.RUnlock() defer process.handleLock.RUnlock()
operation := "hcs::Process::CloseStdin"
if process.handle == 0 { if process.handle == 0 {
return makeProcessError(process, operation, ErrAlreadyClosed, nil) return makeProcessError(process, operation, ErrAlreadyClosed, nil)
} }
modifyRequest := processModifyRequest{ //HcsModifyProcess request to close stdin will fail if the process has already exited
Operation: modifyCloseHandle, if !process.stopped() {
CloseHandle: &closeHandle{ modifyRequest := processModifyRequest{
Handle: stdIn, Operation: modifyCloseHandle,
}, CloseHandle: &closeHandle{
} Handle: stdIn,
},
}
modifyRequestb, err := json.Marshal(modifyRequest) modifyRequestb, err := json.Marshal(modifyRequest)
if err != nil { if err != nil {
return err return err
} }
resultJSON, err := vmcompute.HcsModifyProcess(ctx, process.handle, string(modifyRequestb)) resultJSON, err := vmcompute.HcsModifyProcess(ctx, process.handle, string(modifyRequestb))
events := processHcsResult(ctx, resultJSON) events := processHcsResult(ctx, resultJSON)
if err != nil { if err != nil {
return makeProcessError(process, operation, err, events) return makeProcessError(process, operation, err, events)
}
} }
process.stdioLock.Lock() process.stdioLock.Lock()
defer process.stdioLock.Unlock()
if process.stdin != nil { if process.stdin != nil {
process.stdin.Close() process.stdin.Close()
process.stdin = nil process.stdin = nil
} }
process.stdioLock.Unlock()
return nil return nil
} }
func (process *Process) CloseStdout(ctx context.Context) (err error) { func (process *Process) CloseStdout(ctx context.Context) (err error) {
ctx, span := trace.StartSpan(ctx, "hcs::Process::CloseStdout") //nolint:ineffassign,staticcheck ctx, span := oc.StartSpan(ctx, "hcs::Process::CloseStdout") //nolint:ineffassign,staticcheck
defer span.End() defer span.End()
defer func() { oc.SetSpanStatus(span, err) }() defer func() { oc.SetSpanStatus(span, err) }()
span.AddAttributes( span.AddAttributes(
@ -454,7 +477,7 @@ func (process *Process) CloseStdout(ctx context.Context) (err error) {
} }
func (process *Process) CloseStderr(ctx context.Context) (err error) { func (process *Process) CloseStderr(ctx context.Context) (err error) {
ctx, span := trace.StartSpan(ctx, "hcs::Process::CloseStderr") //nolint:ineffassign,staticcheck ctx, span := oc.StartSpan(ctx, "hcs::Process::CloseStderr") //nolint:ineffassign,staticcheck
defer span.End() defer span.End()
defer func() { oc.SetSpanStatus(span, err) }() defer func() { oc.SetSpanStatus(span, err) }()
span.AddAttributes( span.AddAttributes(
@ -473,7 +496,6 @@ func (process *Process) CloseStderr(ctx context.Context) (err error) {
if process.stderr != nil { if process.stderr != nil {
process.stderr.Close() process.stderr.Close()
process.stderr = nil process.stderr = nil
} }
return nil return nil
} }
@ -482,7 +504,7 @@ func (process *Process) CloseStderr(ctx context.Context) (err error) {
// or wait on it. // or wait on it.
func (process *Process) Close() (err error) { func (process *Process) Close() (err error) {
operation := "hcs::Process::Close" operation := "hcs::Process::Close"
ctx, span := trace.StartSpan(context.Background(), operation) ctx, span := oc.StartSpan(context.Background(), operation)
defer span.End() defer span.End()
defer func() { oc.SetSpanStatus(span, err) }() defer func() { oc.SetSpanStatus(span, err) }()
span.AddAttributes( span.AddAttributes(

View File

@ -1,3 +1,5 @@
//go:build windows
package schema1 package schema1
import ( import (
@ -101,7 +103,7 @@ type ContainerConfig struct {
HvRuntime *HvRuntime `json:",omitempty"` // Hyper-V container settings. Used by Hyper-V containers only. Format ImagePath=%root%\BaseLayerID\UtilityVM 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 Servicing bool `json:",omitempty"` // True if this container is for servicing
AllowUnqualifiedDNSQuery bool `json:",omitempty"` // True to allow unqualified DNS name resolution 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 DNSSearchList string `json:",omitempty"` // Comma separated list of DNS suffixes to use for name resolution
ContainerType string `json:",omitempty"` // "Linux" for Linux containers on Windows. Omitted otherwise. 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 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 MappedVirtualDisks []MappedVirtualDisk `json:",omitempty"` // Array of virtual disks to mount at start

View File

@ -9,6 +9,14 @@
package hcsschema package hcsschema
type CPUGroupPropertyCode uint32
const (
CPUCapacityProperty = 0x00010000
CPUSchedulingPriorityProperty = 0x00020000
IdleLPReserveProperty = 0x00030000
)
type CpuGroupProperty struct { type CpuGroupProperty struct {
PropertyCode uint32 `json:"PropertyCode,omitempty"` PropertyCode uint32 `json:"PropertyCode,omitempty"`
PropertyValue uint32 `json:"PropertyValue,omitempty"` PropertyValue uint32 `json:"PropertyValue,omitempty"`

View File

@ -0,0 +1,22 @@
/*
* 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 DebugOptions struct {
// BugcheckSavedStateFileName is the path for the file in which the guest VM state will be saved when
// the guest crashes.
BugcheckSavedStateFileName string `json:"BugcheckSavedStateFileName,omitempty"`
// BugcheckNoCrashdumpSavedStateFileName is the path of the file in which the guest VM state will be
// saved when the guest crashes but the guest isn't able to generate the crash dump. This usually
// happens in early boot failures.
BugcheckNoCrashdumpSavedStateFileName string `json:"BugcheckNoCrashdumpSavedStateFileName,omitempty"`
TripleFaultSavedStateFileName string `json:"TripleFaultSavedStateFileName,omitempty"`
FirmwareDumpFileName string `json:"FirmwareDumpFileName,omitempty"`
}

View File

@ -14,6 +14,9 @@ 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. // 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"` GuestStateFilePath string `json:"GuestStateFilePath,omitempty"`
// The guest state file type affected by different guest isolation modes - whether a file or block storage.
GuestStateFileType string `json:"GuestStateFileType,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. // 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"` RuntimeStateFilePath string `json:"RuntimeStateFilePath,omitempty"`

View File

@ -0,0 +1,21 @@
/*
* 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 IsolationSettings struct {
// Guest isolation type options to decide virtual trust levels of virtual machine
IsolationType string `json:"IsolationType,omitempty"`
// Configuration to debug HCL layer for HCS VM TODO: Task 31102306: Miss the way to prevent the exposure of private debug configuration in HCS TODO: Think about the secret configurations which are private in VMMS VM (only edit by hvsedit)
DebugHost string `json:"DebugHost,omitempty"`
DebugPort int64 `json:"DebugPort,omitempty"`
// Optional data passed by host on isolated virtual machine start
LaunchData string `json:"LaunchData,omitempty"`
HclEnabled bool `json:"HclEnabled,omitempty"`
}

View File

@ -9,10 +9,12 @@
package hcsschema package hcsschema
import "github.com/Microsoft/hcsshim/internal/protocol/guestrequest"
type ModifySettingRequest struct { type ModifySettingRequest struct {
ResourcePath string `json:"ResourcePath,omitempty"` ResourcePath string `json:"ResourcePath,omitempty"`
RequestType string `json:"RequestType,omitempty"` RequestType guestrequest.RequestType `json:"RequestType,omitempty"` // NOTE: Swagger generated as string. Locally updated.
Settings interface{} `json:"Settings,omitempty"` // NOTE: Swagger generated as *interface{}. Locally updated Settings interface{} `json:"Settings,omitempty"` // NOTE: Swagger generated as *interface{}. Locally updated

View File

@ -0,0 +1,16 @@
/*
* 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 SecuritySettings struct {
// Enablement of Trusted Platform Module on the computer system
EnableTpm bool `json:"EnableTpm,omitempty"`
Isolation *IsolationSettings `json:"Isolation,omitempty"`
}

View File

@ -0,0 +1,28 @@
/*
* 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 SystemTime struct {
Year int32 `json:"Year,omitempty"`
Month int32 `json:"Month,omitempty"`
DayOfWeek int32 `json:"DayOfWeek,omitempty"`
Day int32 `json:"Day,omitempty"`
Hour int32 `json:"Hour,omitempty"`
Minute int32 `json:"Minute,omitempty"`
Second int32 `json:"Second,omitempty"`
Milliseconds int32 `json:"Milliseconds,omitempty"`
}

View File

@ -0,0 +1,26 @@
/*
* 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 TimeZoneInformation struct {
Bias int32 `json:"Bias,omitempty"`
StandardName string `json:"StandardName,omitempty"`
StandardDate *SystemTime `json:"StandardDate,omitempty"`
StandardBias int32 `json:"StandardBias,omitempty"`
DaylightName string `json:"DaylightName,omitempty"`
DaylightDate *SystemTime `json:"DaylightDate,omitempty"`
DaylightBias int32 `json:"DaylightBias,omitempty"`
}

View File

@ -12,6 +12,8 @@ package hcsschema
type Uefi struct { type Uefi struct {
EnableDebugger bool `json:"EnableDebugger,omitempty"` EnableDebugger bool `json:"EnableDebugger,omitempty"`
ApplySecureBootTemplate string `json:"ApplySecureBootTemplate,omitempty"`
SecureBootTemplateId string `json:"SecureBootTemplateId,omitempty"` SecureBootTemplateId string `json:"SecureBootTemplateId,omitempty"`
BootThis *UefiBootEntry `json:"BootThis,omitempty"` BootThis *UefiBootEntry `json:"BootThis,omitempty"`

View File

@ -29,4 +29,8 @@ type VirtualMachine struct {
StorageQoS *StorageQoS `json:"StorageQoS,omitempty"` StorageQoS *StorageQoS `json:"StorageQoS,omitempty"`
GuestConnection *GuestConnection `json:"GuestConnection,omitempty"` GuestConnection *GuestConnection `json:"GuestConnection,omitempty"`
SecuritySettings *SecuritySettings `json:"SecuritySettings,omitempty"`
DebugOptions *DebugOptions `json:"DebugOptions,omitempty"`
} }

View File

@ -1,3 +1,5 @@
//go:build windows
package hcs package hcs
import ( import (

View File

@ -1,3 +1,5 @@
//go:build windows
package hcs package hcs
import ( import (
@ -37,6 +39,9 @@ type System struct {
startTime time.Time startTime time.Time
} }
var _ cow.Container = &System{}
var _ cow.ProcessHost = &System{}
func newSystem(id string) *System { func newSystem(id string) *System {
return &System{ return &System{
id: id, id: id,
@ -55,7 +60,7 @@ func CreateComputeSystem(ctx context.Context, id string, hcsDocumentInterface in
// hcsCreateComputeSystemContext is an async operation. Start the outer span // hcsCreateComputeSystemContext is an async operation. Start the outer span
// here to measure the full create time. // here to measure the full create time.
ctx, span := trace.StartSpan(ctx, operation) ctx, span := oc.StartSpan(ctx, operation)
defer span.End() defer span.End()
defer func() { oc.SetSpanStatus(span, err) }() defer func() { oc.SetSpanStatus(span, err) }()
span.AddAttributes(trace.StringAttribute("cid", id)) span.AddAttributes(trace.StringAttribute("cid", id))
@ -89,7 +94,8 @@ func CreateComputeSystem(ctx context.Context, id string, hcsDocumentInterface in
} }
} }
events, err := processAsyncHcsResult(ctx, createError, resultJSON, computeSystem.callbackNumber, hcsNotificationSystemCreateCompleted, &timeout.SystemCreate) events, err := processAsyncHcsResult(ctx, createError, resultJSON, computeSystem.callbackNumber,
hcsNotificationSystemCreateCompleted, &timeout.SystemCreate)
if err != nil { if err != nil {
if err == ErrTimeout { if err == ErrTimeout {
// Terminate the compute system if it still exists. We're okay to // Terminate the compute system if it still exists. We're okay to
@ -190,7 +196,7 @@ func (computeSystem *System) Start(ctx context.Context) (err error) {
// hcsStartComputeSystemContext is an async operation. Start the outer span // hcsStartComputeSystemContext is an async operation. Start the outer span
// here to measure the full start time. // here to measure the full start time.
ctx, span := trace.StartSpan(ctx, operation) ctx, span := oc.StartSpan(ctx, operation)
defer span.End() defer span.End()
defer func() { oc.SetSpanStatus(span, err) }() defer func() { oc.SetSpanStatus(span, err) }()
span.AddAttributes(trace.StringAttribute("cid", computeSystem.id)) span.AddAttributes(trace.StringAttribute("cid", computeSystem.id))
@ -198,12 +204,15 @@ func (computeSystem *System) Start(ctx context.Context) (err error) {
computeSystem.handleLock.RLock() computeSystem.handleLock.RLock()
defer computeSystem.handleLock.RUnlock() defer computeSystem.handleLock.RUnlock()
// prevent starting an exited system because waitblock we do not recreate waitBlock
// or rerun waitBackground, so we have no way to be notified of it closing again
if computeSystem.handle == 0 { if computeSystem.handle == 0 {
return makeSystemError(computeSystem, operation, ErrAlreadyClosed, nil) return makeSystemError(computeSystem, operation, ErrAlreadyClosed, nil)
} }
resultJSON, err := vmcompute.HcsStartComputeSystem(ctx, computeSystem.handle, "") resultJSON, err := vmcompute.HcsStartComputeSystem(ctx, computeSystem.handle, "")
events, err := processAsyncHcsResult(ctx, err, resultJSON, computeSystem.callbackNumber, hcsNotificationSystemStartCompleted, &timeout.SystemStart) events, err := processAsyncHcsResult(ctx, err, resultJSON, computeSystem.callbackNumber,
hcsNotificationSystemStartCompleted, &timeout.SystemStart)
if err != nil { if err != nil {
return makeSystemError(computeSystem, operation, err, events) return makeSystemError(computeSystem, operation, err, events)
} }
@ -223,7 +232,7 @@ func (computeSystem *System) Shutdown(ctx context.Context) error {
operation := "hcs::System::Shutdown" operation := "hcs::System::Shutdown"
if computeSystem.handle == 0 { if computeSystem.handle == 0 || computeSystem.stopped() {
return nil return nil
} }
@ -244,7 +253,7 @@ func (computeSystem *System) Terminate(ctx context.Context) error {
operation := "hcs::System::Terminate" operation := "hcs::System::Terminate"
if computeSystem.handle == 0 { if computeSystem.handle == 0 || computeSystem.stopped() {
return nil return nil
} }
@ -265,7 +274,7 @@ func (computeSystem *System) Terminate(ctx context.Context) error {
// safe to call multiple times. // safe to call multiple times.
func (computeSystem *System) waitBackground() { func (computeSystem *System) waitBackground() {
operation := "hcs::System::waitBackground" operation := "hcs::System::waitBackground"
ctx, span := trace.StartSpan(context.Background(), operation) ctx, span := oc.StartSpan(context.Background(), operation)
defer span.End() defer span.End()
span.AddAttributes(trace.StringAttribute("cid", computeSystem.id)) span.AddAttributes(trace.StringAttribute("cid", computeSystem.id))
@ -302,17 +311,25 @@ func (computeSystem *System) Wait() error {
return computeSystem.WaitError() return computeSystem.WaitError()
} }
// ExitError returns an error describing the reason the compute system terminated. // stopped returns true if the compute system stopped.
func (computeSystem *System) ExitError() error { func (computeSystem *System) stopped() bool {
select { select {
case <-computeSystem.waitBlock: case <-computeSystem.waitBlock:
if computeSystem.waitError != nil { return true
return computeSystem.waitError
}
return computeSystem.exitError
default: default:
}
return false
}
// ExitError returns an error describing the reason the compute system terminated.
func (computeSystem *System) ExitError() error {
if !computeSystem.stopped() {
return errors.New("container not exited") return errors.New("container not exited")
} }
if computeSystem.waitError != nil {
return computeSystem.waitError
}
return computeSystem.exitError
} }
// Properties returns the requested container properties targeting a V1 schema container. // Properties returns the requested container properties targeting a V1 schema container.
@ -322,6 +339,10 @@ func (computeSystem *System) Properties(ctx context.Context, types ...schema1.Pr
operation := "hcs::System::Properties" operation := "hcs::System::Properties"
if computeSystem.handle == 0 {
return nil, makeSystemError(computeSystem, operation, ErrAlreadyClosed, nil)
}
queryBytes, err := json.Marshal(schema1.PropertyQuery{PropertyTypes: types}) queryBytes, err := json.Marshal(schema1.PropertyQuery{PropertyTypes: types})
if err != nil { if err != nil {
return nil, makeSystemError(computeSystem, operation, err, nil) return nil, makeSystemError(computeSystem, operation, err, nil)
@ -349,7 +370,11 @@ func (computeSystem *System) Properties(ctx context.Context, types ...schema1.Pr
// failed to be queried they will be tallied up and returned in as the first return value. Failures on // failed to be queried they will be tallied up and returned in as the first return value. Failures on
// query are NOT considered errors; the only failure case for this method is if the containers job object // query are NOT considered errors; the only failure case for this method is if the containers job object
// cannot be opened. // cannot be opened.
func (computeSystem *System) queryInProc(ctx context.Context, props *hcsschema.Properties, types []hcsschema.PropertyType) ([]hcsschema.PropertyType, error) { func (computeSystem *System) queryInProc(
ctx context.Context,
props *hcsschema.Properties,
types []hcsschema.PropertyType,
) ([]hcsschema.PropertyType, error) {
// In the future we can make use of some new functionality in the HCS that allows you // In the future we can make use of some new functionality in the HCS that allows you
// to pass a job object for HCS to use for the container. Currently, the only way we'll // to pass a job object for HCS to use for the container. Currently, the only way we'll
// be able to open the job/silo is if we're running as SYSTEM. // be able to open the job/silo is if we're running as SYSTEM.
@ -415,7 +440,7 @@ func (computeSystem *System) statisticsInProc(job *jobobject.JobObject) (*hcssch
// as well which isn't great and is wasted work to fetch. // as well which isn't great and is wasted work to fetch.
// //
// HCS only let's you grab statistics in an all or nothing fashion, so we can't just grab the private // HCS only let's you grab statistics in an all or nothing fashion, so we can't just grab the private
// working set ourselves and ask for everything else seperately. The optimization we can make here is // working set ourselves and ask for everything else separately. The optimization we can make here is
// to open the silo ourselves and do the same queries for the rest of the info, as well as calculating // to open the silo ourselves and do the same queries for the rest of the info, as well as calculating
// the private working set in a more efficient manner by: // the private working set in a more efficient manner by:
// //
@ -455,6 +480,10 @@ func (computeSystem *System) statisticsInProc(job *jobobject.JobObject) (*hcssch
func (computeSystem *System) hcsPropertiesV2Query(ctx context.Context, types []hcsschema.PropertyType) (*hcsschema.Properties, error) { func (computeSystem *System) hcsPropertiesV2Query(ctx context.Context, types []hcsschema.PropertyType) (*hcsschema.Properties, error) {
operation := "hcs::System::PropertiesV2" operation := "hcs::System::PropertiesV2"
if computeSystem.handle == 0 {
return nil, makeSystemError(computeSystem, operation, ErrAlreadyClosed, nil)
}
queryBytes, err := json.Marshal(hcsschema.PropertyQuery{PropertyTypes: types}) queryBytes, err := json.Marshal(hcsschema.PropertyQuery{PropertyTypes: types})
if err != nil { if err != nil {
return nil, makeSystemError(computeSystem, operation, err, nil) return nil, makeSystemError(computeSystem, operation, err, nil)
@ -503,7 +532,7 @@ func (computeSystem *System) PropertiesV2(ctx context.Context, types ...hcsschem
if err == nil && len(fallbackTypes) == 0 { if err == nil && len(fallbackTypes) == 0 {
return properties, nil return properties, nil
} else if err != nil { } else if err != nil {
logEntry.WithError(fmt.Errorf("failed to query compute system properties in-proc: %w", err)) logEntry = logEntry.WithError(fmt.Errorf("failed to query compute system properties in-proc: %w", err))
fallbackTypes = types fallbackTypes = types
} }
@ -535,9 +564,9 @@ func (computeSystem *System) PropertiesV2(ctx context.Context, types ...hcsschem
func (computeSystem *System) Pause(ctx context.Context) (err error) { func (computeSystem *System) Pause(ctx context.Context) (err error) {
operation := "hcs::System::Pause" operation := "hcs::System::Pause"
// hcsPauseComputeSystemContext is an async peration. Start the outer span // hcsPauseComputeSystemContext is an async operation. Start the outer span
// here to measure the full pause time. // here to measure the full pause time.
ctx, span := trace.StartSpan(ctx, operation) ctx, span := oc.StartSpan(ctx, operation)
defer span.End() defer span.End()
defer func() { oc.SetSpanStatus(span, err) }() defer func() { oc.SetSpanStatus(span, err) }()
span.AddAttributes(trace.StringAttribute("cid", computeSystem.id)) span.AddAttributes(trace.StringAttribute("cid", computeSystem.id))
@ -550,7 +579,8 @@ func (computeSystem *System) Pause(ctx context.Context) (err error) {
} }
resultJSON, err := vmcompute.HcsPauseComputeSystem(ctx, computeSystem.handle, "") resultJSON, err := vmcompute.HcsPauseComputeSystem(ctx, computeSystem.handle, "")
events, err := processAsyncHcsResult(ctx, err, resultJSON, computeSystem.callbackNumber, hcsNotificationSystemPauseCompleted, &timeout.SystemPause) events, err := processAsyncHcsResult(ctx, err, resultJSON, computeSystem.callbackNumber,
hcsNotificationSystemPauseCompleted, &timeout.SystemPause)
if err != nil { if err != nil {
return makeSystemError(computeSystem, operation, err, events) return makeSystemError(computeSystem, operation, err, events)
} }
@ -564,7 +594,7 @@ func (computeSystem *System) Resume(ctx context.Context) (err error) {
// hcsResumeComputeSystemContext is an async operation. Start the outer span // hcsResumeComputeSystemContext is an async operation. Start the outer span
// here to measure the full restore time. // here to measure the full restore time.
ctx, span := trace.StartSpan(ctx, operation) ctx, span := oc.StartSpan(ctx, operation)
defer span.End() defer span.End()
defer func() { oc.SetSpanStatus(span, err) }() defer func() { oc.SetSpanStatus(span, err) }()
span.AddAttributes(trace.StringAttribute("cid", computeSystem.id)) span.AddAttributes(trace.StringAttribute("cid", computeSystem.id))
@ -577,7 +607,8 @@ func (computeSystem *System) Resume(ctx context.Context) (err error) {
} }
resultJSON, err := vmcompute.HcsResumeComputeSystem(ctx, computeSystem.handle, "") resultJSON, err := vmcompute.HcsResumeComputeSystem(ctx, computeSystem.handle, "")
events, err := processAsyncHcsResult(ctx, err, resultJSON, computeSystem.callbackNumber, hcsNotificationSystemResumeCompleted, &timeout.SystemResume) events, err := processAsyncHcsResult(ctx, err, resultJSON, computeSystem.callbackNumber,
hcsNotificationSystemResumeCompleted, &timeout.SystemResume)
if err != nil { if err != nil {
return makeSystemError(computeSystem, operation, err, events) return makeSystemError(computeSystem, operation, err, events)
} }
@ -589,9 +620,9 @@ func (computeSystem *System) Resume(ctx context.Context) (err error) {
func (computeSystem *System) Save(ctx context.Context, options interface{}) (err error) { func (computeSystem *System) Save(ctx context.Context, options interface{}) (err error) {
operation := "hcs::System::Save" operation := "hcs::System::Save"
// hcsSaveComputeSystemContext is an async peration. Start the outer span // hcsSaveComputeSystemContext is an async operation. Start the outer span
// here to measure the full save time. // here to measure the full save time.
ctx, span := trace.StartSpan(ctx, operation) ctx, span := oc.StartSpan(ctx, operation)
defer span.End() defer span.End()
defer func() { oc.SetSpanStatus(span, err) }() defer func() { oc.SetSpanStatus(span, err) }()
span.AddAttributes(trace.StringAttribute("cid", computeSystem.id)) span.AddAttributes(trace.StringAttribute("cid", computeSystem.id))
@ -609,7 +640,8 @@ func (computeSystem *System) Save(ctx context.Context, options interface{}) (err
} }
result, err := vmcompute.HcsSaveComputeSystem(ctx, computeSystem.handle, string(saveOptions)) result, err := vmcompute.HcsSaveComputeSystem(ctx, computeSystem.handle, string(saveOptions))
events, err := processAsyncHcsResult(ctx, err, result, computeSystem.callbackNumber, hcsNotificationSystemSaveCompleted, &timeout.SystemSave) events, err := processAsyncHcsResult(ctx, err, result, computeSystem.callbackNumber,
hcsNotificationSystemSaveCompleted, &timeout.SystemSave)
if err != nil { if err != nil {
return makeSystemError(computeSystem, operation, err, events) return makeSystemError(computeSystem, operation, err, events)
} }
@ -634,6 +666,11 @@ func (computeSystem *System) createProcess(ctx context.Context, operation string
processInfo, processHandle, resultJSON, err := vmcompute.HcsCreateProcess(ctx, computeSystem.handle, configuration) processInfo, processHandle, resultJSON, err := vmcompute.HcsCreateProcess(ctx, computeSystem.handle, configuration)
events := processHcsResult(ctx, resultJSON) events := processHcsResult(ctx, resultJSON)
if err != nil { if err != nil {
if v2, ok := c.(*hcsschema.ProcessParameters); ok {
operation += ": " + v2.CommandLine
} else if v1, ok := c.(*schema1.ProcessConfig); ok {
operation += ": " + v1.CommandLine
}
return nil, nil, makeSystemError(computeSystem, operation, err, events) return nil, nil, makeSystemError(computeSystem, operation, err, events)
} }
@ -700,7 +737,7 @@ func (computeSystem *System) OpenProcess(ctx context.Context, pid int) (*Process
// Close cleans up any state associated with the compute system but does not terminate or wait for it. // Close cleans up any state associated with the compute system but does not terminate or wait for it.
func (computeSystem *System) Close() (err error) { func (computeSystem *System) Close() (err error) {
operation := "hcs::System::Close" operation := "hcs::System::Close"
ctx, span := trace.StartSpan(context.Background(), operation) ctx, span := oc.StartSpan(context.Background(), operation)
defer span.End() defer span.End()
defer func() { oc.SetSpanStatus(span, err) }() defer func() { oc.SetSpanStatus(span, err) }()
span.AddAttributes(trace.StringAttribute("cid", computeSystem.id)) span.AddAttributes(trace.StringAttribute("cid", computeSystem.id))
@ -743,7 +780,8 @@ func (computeSystem *System) registerCallback(ctx context.Context) error {
callbackMap[callbackNumber] = callbackContext callbackMap[callbackNumber] = callbackContext
callbackMapLock.Unlock() callbackMapLock.Unlock()
callbackHandle, err := vmcompute.HcsRegisterComputeSystemCallback(ctx, computeSystem.handle, notificationWatcherCallback, callbackNumber) callbackHandle, err := vmcompute.HcsRegisterComputeSystemCallback(ctx, computeSystem.handle,
notificationWatcherCallback, callbackNumber)
if err != nil { if err != nil {
return err return err
} }
@ -770,7 +808,7 @@ func (computeSystem *System) unregisterCallback(ctx context.Context) error {
return nil return nil
} }
// hcsUnregisterComputeSystemCallback has its own syncronization // hcsUnregisterComputeSystemCallback has its own synchronization
// to wait for all callbacks to complete. We must NOT hold the callbackMapLock. // to wait for all callbacks to complete. We must NOT hold the callbackMapLock.
err := vmcompute.HcsUnregisterComputeSystemCallback(ctx, handle) err := vmcompute.HcsUnregisterComputeSystemCallback(ctx, handle)
if err != nil { if err != nil {

View File

@ -1,3 +1,5 @@
//go:build windows
package hcs package hcs
import ( import (

View File

@ -1,3 +1,5 @@
//go:build windows
package hcs package hcs
import ( import (
@ -7,7 +9,14 @@ import (
"github.com/Microsoft/hcsshim/internal/log" "github.com/Microsoft/hcsshim/internal/log"
) )
func processAsyncHcsResult(ctx context.Context, err error, resultJSON string, callbackNumber uintptr, expectedNotification hcsNotification, timeout *time.Duration) ([]ErrorEvent, error) { func processAsyncHcsResult(
ctx context.Context,
err error,
resultJSON string,
callbackNumber uintptr,
expectedNotification hcsNotification,
timeout *time.Duration,
) ([]ErrorEvent, error) {
events := processHcsResult(ctx, resultJSON) events := processHcsResult(ctx, resultJSON)
if IsPending(err) { if IsPending(err) {
return nil, waitForNotification(ctx, callbackNumber, expectedNotification, timeout) return nil, waitForNotification(ctx, callbackNumber, expectedNotification, timeout)
@ -16,7 +25,12 @@ func processAsyncHcsResult(ctx context.Context, err error, resultJSON string, ca
return events, err return events, err
} }
func waitForNotification(ctx context.Context, callbackNumber uintptr, expectedNotification hcsNotification, timeout *time.Duration) error { func waitForNotification(
ctx context.Context,
callbackNumber uintptr,
expectedNotification hcsNotification,
timeout *time.Duration,
) error {
callbackMapLock.RLock() callbackMapLock.RLock()
if _, ok := callbackMap[callbackNumber]; !ok { if _, ok := callbackMap[callbackNumber]; !ok {
callbackMapLock.RUnlock() callbackMapLock.RUnlock()

View File

@ -0,0 +1 @@
package hcserror

View File

@ -1,11 +1,13 @@
//go:build windows
package hcserror package hcserror
import ( import (
"errors"
"fmt" "fmt"
"syscall"
)
const ERROR_GEN_FAILURE = syscall.Errno(31) "golang.org/x/sys/windows"
)
type HcsError struct { type HcsError struct {
title string title string
@ -30,18 +32,21 @@ func (e *HcsError) Error() string {
func New(err error, title, rest string) error { func New(err error, title, rest string) error {
// Pass through DLL errors directly since they do not originate from HCS. // Pass through DLL errors directly since they do not originate from HCS.
if _, ok := err.(*syscall.DLLError); ok { var e *windows.DLLError
if errors.As(err, &e) {
return err return err
} }
return &HcsError{title, rest, err} return &HcsError{title, rest, err}
} }
func Win32FromError(err error) uint32 { func Win32FromError(err error) uint32 {
if herr, ok := err.(*HcsError); ok { var herr *HcsError
if errors.As(err, &herr) {
return Win32FromError(herr.Err) return Win32FromError(herr.Err)
} }
if code, ok := err.(syscall.Errno); ok { var code windows.Errno
if errors.As(err, &code) {
return uint32(code) return uint32(code)
} }
return uint32(ERROR_GEN_FAILURE) return uint32(windows.ERROR_GEN_FAILURE)
} }

View File

@ -0,0 +1 @@
package hns

View File

@ -2,7 +2,7 @@ package hns
import "fmt" import "fmt"
//go:generate go run ../../mksyscall_windows.go -output zsyscall_windows.go hns.go //go:generate go run github.com/Microsoft/go-winio/tools/mkwinsyscall -output zsyscall_windows.go hns.go
//sys _hnsCall(method string, path string, object string, response **uint16) (hr error) = vmcompute.HNSCall? //sys _hnsCall(method string, path string, object string, response **uint16) (hr error) = vmcompute.HNSCall?

View File

@ -1,3 +1,5 @@
//go:build windows
package hns package hns
import ( import (
@ -34,7 +36,7 @@ type HNSEndpoint struct {
SharedContainers []string `json:",omitempty"` SharedContainers []string `json:",omitempty"`
} }
//SystemType represents the type of the system on which actions are done // SystemType represents the type of the system on which actions are done
type SystemType string type SystemType string
// SystemType const // SystemType const
@ -146,7 +148,6 @@ func (endpoint *HNSEndpoint) IsAttached(vID string) (bool, error) {
} }
return false, nil return false, nil
} }
// Create Endpoint by sending EndpointRequest to HNS. TODO: Create a separate HNS interface to place all these methods // Create Endpoint by sending EndpointRequest to HNS. TODO: Create a separate HNS interface to place all these methods
@ -281,7 +282,6 @@ func (endpoint *HNSEndpoint) HostAttach(compartmentID uint16) error {
return err return err
} }
return hnsCall("POST", "/endpoints/"+endpoint.Id+"/attach", string(jsonString), &response) return hnsCall("POST", "/endpoints/"+endpoint.Id+"/attach", string(jsonString), &response)
} }
// HostDetach detaches a nic on the host // HostDetach detaches a nic on the host

View File

@ -1,3 +1,5 @@
//go:build windows
package hns package hns
import ( import (

View File

@ -1,3 +1,5 @@
//go:build windows
package hns package hns
type HNSGlobals struct { type HNSGlobals struct {

View File

@ -1,13 +1,16 @@
//go:build windows
package hns package hns
import ( import (
"encoding/json" "encoding/json"
"errors" "errors"
"github.com/sirupsen/logrus"
"net" "net"
"github.com/sirupsen/logrus"
) )
// Subnet is assoicated with a network and represents a list // Subnet is associated with a network and represents a list
// of subnets available to the network // of subnets available to the network
type Subnet struct { type Subnet struct {
AddressPrefix string `json:",omitempty"` AddressPrefix string `json:",omitempty"`
@ -15,7 +18,7 @@ type Subnet struct {
Policies []json.RawMessage `json:",omitempty"` Policies []json.RawMessage `json:",omitempty"`
} }
// MacPool is assoicated with a network and represents a list // MacPool is associated with a network and represents a list
// of macaddresses available to the network // of macaddresses available to the network
type MacPool struct { type MacPool struct {
StartMacAddress string `json:",omitempty"` StartMacAddress string `json:",omitempty"`

View File

@ -94,15 +94,15 @@ type ACLPolicy struct {
InternalPort uint16 `json:",omitempty"` InternalPort uint16 `json:",omitempty"`
Action ActionType Action ActionType
Direction DirectionType Direction DirectionType
LocalAddresses string `json:",omitempty"` LocalAddresses string `json:",omitempty"`
RemoteAddresses string `json:",omitempty"` RemoteAddresses string `json:",omitempty"`
LocalPorts string `json:"LocalPorts,omitempty"` LocalPorts string `json:"LocalPorts,omitempty"`
LocalPort uint16 `json:",omitempty"` LocalPort uint16 `json:",omitempty"`
RemotePorts string `json:"RemotePorts,omitempty"` RemotePorts string `json:"RemotePorts,omitempty"`
RemotePort uint16 `json:",omitempty"` RemotePort uint16 `json:",omitempty"`
RuleType RuleType `json:"RuleType,omitempty"` RuleType RuleType `json:"RuleType,omitempty"`
Priority uint16 `json:",omitempty"` Priority uint16 `json:",omitempty"`
ServiceName string `json:",omitempty"` ServiceName string `json:",omitempty"`
} }
type Policy struct { type Policy struct {

View File

@ -1,3 +1,5 @@
//go:build windows
package hns package hns
import ( import (

View File

@ -1,3 +1,5 @@
//go:build windows
package hns package hns
import ( import (

View File

@ -1,3 +1,5 @@
//go:build windows
package hns package hns
import ( import (

View File

@ -1,4 +1,6 @@
// Code generated mksyscall_windows.exe DO NOT EDIT //go:build windows
// Code generated by 'go generate' using "github.com/Microsoft/go-winio/tools/mkwinsyscall"; DO NOT EDIT.
package hns package hns
@ -19,6 +21,7 @@ const (
var ( var (
errERROR_IO_PENDING error = syscall.Errno(errnoERROR_IO_PENDING) errERROR_IO_PENDING error = syscall.Errno(errnoERROR_IO_PENDING)
errERROR_EINVAL error = syscall.EINVAL
) )
// errnoErr returns common boxed Errno values, to prevent // errnoErr returns common boxed Errno values, to prevent
@ -26,7 +29,7 @@ var (
func errnoErr(e syscall.Errno) error { func errnoErr(e syscall.Errno) error {
switch e { switch e {
case 0: case 0:
return nil return errERROR_EINVAL
case errnoERROR_IO_PENDING: case errnoERROR_IO_PENDING:
return errERROR_IO_PENDING return errERROR_IO_PENDING
} }
@ -62,7 +65,8 @@ func _hnsCall(method string, path string, object string, response **uint16) (hr
} }
func __hnsCall(method *uint16, path *uint16, object *uint16, response **uint16) (hr error) { func __hnsCall(method *uint16, path *uint16, object *uint16, response **uint16) (hr error) {
if hr = procHNSCall.Find(); hr != nil { hr = procHNSCall.Find()
if hr != nil {
return return
} }
r0, _, _ := syscall.Syscall6(procHNSCall.Addr(), 4, uintptr(unsafe.Pointer(method)), uintptr(unsafe.Pointer(path)), uintptr(unsafe.Pointer(object)), uintptr(unsafe.Pointer(response)), 0, 0) r0, _, _ := syscall.Syscall6(procHNSCall.Addr(), 4, uintptr(unsafe.Pointer(method)), uintptr(unsafe.Pointer(path)), uintptr(unsafe.Pointer(object)), uintptr(unsafe.Pointer(response)), 0, 0)

View File

@ -0,0 +1 @@
package interop

View File

@ -1,3 +1,5 @@
//go:build windows
package interop package interop
import ( import (
@ -5,7 +7,7 @@ import (
"unsafe" "unsafe"
) )
//go:generate go run ../../mksyscall_windows.go -output zsyscall_windows.go interop.go //go:generate go run github.com/Microsoft/go-winio/tools/mkwinsyscall -output zsyscall_windows.go interop.go
//sys coTaskMemFree(buffer unsafe.Pointer) = api_ms_win_core_com_l1_1_0.CoTaskMemFree //sys coTaskMemFree(buffer unsafe.Pointer) = api_ms_win_core_com_l1_1_0.CoTaskMemFree

View File

@ -1,4 +1,6 @@
// Code generated mksyscall_windows.exe DO NOT EDIT //go:build windows
// Code generated by 'go generate' using "github.com/Microsoft/go-winio/tools/mkwinsyscall"; DO NOT EDIT.
package interop package interop
@ -19,6 +21,7 @@ const (
var ( var (
errERROR_IO_PENDING error = syscall.Errno(errnoERROR_IO_PENDING) errERROR_IO_PENDING error = syscall.Errno(errnoERROR_IO_PENDING)
errERROR_EINVAL error = syscall.EINVAL
) )
// errnoErr returns common boxed Errno values, to prevent // errnoErr returns common boxed Errno values, to prevent
@ -26,7 +29,7 @@ var (
func errnoErr(e syscall.Errno) error { func errnoErr(e syscall.Errno) error {
switch e { switch e {
case 0: case 0:
return nil return errERROR_EINVAL
case errnoERROR_IO_PENDING: case errnoERROR_IO_PENDING:
return errERROR_IO_PENDING return errERROR_IO_PENDING
} }

View File

@ -0,0 +1,8 @@
// This package provides higher level constructs for the win32 job object API.
// Most of the core creation and management functions are already present in "golang.org/x/sys/windows"
// (CreateJobObject, AssignProcessToJobObject, etc.) as well as most of the limit information
// structs and associated limit flags. Whatever is not present from the job object API
// in golang.org/x/sys/windows is located in /internal/winapi.
//
// https://docs.microsoft.com/en-us/windows/win32/procthread/job-objects
package jobobject

View File

@ -1,3 +1,5 @@
//go:build windows
package jobobject package jobobject
import ( import (

View File

@ -1,10 +1,15 @@
//go:build windows
package jobobject package jobobject
import ( import (
"context" "context"
"errors" "errors"
"fmt" "fmt"
"os"
"path/filepath"
"sync" "sync"
"sync/atomic"
"unsafe" "unsafe"
"github.com/Microsoft/hcsshim/internal/queue" "github.com/Microsoft/hcsshim/internal/queue"
@ -12,19 +17,14 @@ import (
"golang.org/x/sys/windows" "golang.org/x/sys/windows"
) )
// This file provides higher level constructs for the win32 job object API.
// Most of the core creation and management functions are already present in "golang.org/x/sys/windows"
// (CreateJobObject, AssignProcessToJobObject, etc.) as well as most of the limit information
// structs and associated limit flags. Whatever is not present from the job object API
// in golang.org/x/sys/windows is located in /internal/winapi.
//
// https://docs.microsoft.com/en-us/windows/win32/procthread/job-objects
// JobObject is a high level wrapper around a Windows job object. Holds a handle to // JobObject is a high level wrapper around a Windows job object. Holds a handle to
// the job, a queue to receive iocp notifications about the lifecycle // the job, a queue to receive iocp notifications about the lifecycle
// of the job and a mutex for synchronized handle access. // of the job and a mutex for synchronized handle access.
type JobObject struct { type JobObject struct {
handle windows.Handle handle windows.Handle
// All accesses to this MUST be done atomically except in `Open` as the object
// is being created in the function. 1 signifies that this job is currently a silo.
silo uint32
mq *queue.MessageQueue mq *queue.MessageQueue
handleLock sync.RWMutex handleLock sync.RWMutex
} }
@ -56,6 +56,7 @@ const (
var ( var (
ErrAlreadyClosed = errors.New("the handle has already been closed") ErrAlreadyClosed = errors.New("the handle has already been closed")
ErrNotRegistered = errors.New("job is not registered to receive notifications") ErrNotRegistered = errors.New("job is not registered to receive notifications")
ErrNotSilo = errors.New("job is not a silo")
) )
// Options represents the set of configurable options when making or opening a job object. // Options represents the set of configurable options when making or opening a job object.
@ -68,6 +69,9 @@ type Options struct {
// `UseNTVariant` specifies if we should use the `Nt` variant of Open/CreateJobObject. // `UseNTVariant` specifies if we should use the `Nt` variant of Open/CreateJobObject.
// Defaults to false. // Defaults to false.
UseNTVariant bool UseNTVariant bool
// `Silo` specifies to promote the job to a silo. This additionally sets the flag
// JOB_OBJECT_LIMIT_KILL_ON_JOB_CLOSE as it is required for the upgrade to complete.
Silo bool
// `IOTracking` enables tracking I/O statistics on the job object. More specifically this // `IOTracking` enables tracking I/O statistics on the job object. More specifically this
// calls SetInformationJobObject with the JobObjectIoAttribution class. // calls SetInformationJobObject with the JobObjectIoAttribution class.
EnableIOTracking bool EnableIOTracking bool
@ -143,6 +147,16 @@ func Create(ctx context.Context, options *Options) (_ *JobObject, err error) {
} }
} }
if options.Silo {
// This is a required setting for upgrading to a silo.
if err := job.SetTerminateOnLastHandleClose(); err != nil {
return nil, err
}
if err := job.PromoteToSilo(); err != nil {
return nil, err
}
}
return job, nil return job, nil
} }
@ -163,7 +177,7 @@ func Open(ctx context.Context, options *Options) (_ *JobObject, err error) {
} }
var jobHandle windows.Handle var jobHandle windows.Handle
if options != nil && options.UseNTVariant { if options.UseNTVariant {
oa := winapi.ObjectAttributes{ oa := winapi.ObjectAttributes{
Length: unsafe.Sizeof(winapi.ObjectAttributes{}), Length: unsafe.Sizeof(winapi.ObjectAttributes{}),
ObjectName: unicodeJobName, ObjectName: unicodeJobName,
@ -174,7 +188,7 @@ func Open(ctx context.Context, options *Options) (_ *JobObject, err error) {
return nil, winapi.RtlNtStatusToDosError(status) return nil, winapi.RtlNtStatusToDosError(status)
} }
} else { } else {
jobHandle, err = winapi.OpenJobObject(winapi.JOB_OBJECT_ALL_ACCESS, false, unicodeJobName.Buffer) jobHandle, err = winapi.OpenJobObject(winapi.JOB_OBJECT_ALL_ACCESS, 0, unicodeJobName.Buffer)
if err != nil { if err != nil {
return nil, err return nil, err
} }
@ -190,9 +204,13 @@ func Open(ctx context.Context, options *Options) (_ *JobObject, err error) {
handle: jobHandle, handle: jobHandle,
} }
if isJobSilo(jobHandle) {
job.silo = 1
}
// If the IOCP we'll be using to receive messages for all jobs hasn't been // If the IOCP we'll be using to receive messages for all jobs hasn't been
// created, create it and start polling. // created, create it and start polling.
if options != nil && options.Notifications { if options.Notifications {
mq, err := setupNotifications(ctx, job) mq, err := setupNotifications(ctx, job)
if err != nil { if err != nil {
return nil, err return nil, err
@ -450,6 +468,119 @@ func (job *JobObject) QueryStorageStats() (*winapi.JOBOBJECT_IO_ATTRIBUTION_INFO
return &info, nil return &info, nil
} }
// ApplyFileBinding makes a file binding using the Bind Filter from target to root. If the job has
// not been upgraded to a silo this call will fail. The binding is only applied and visible for processes
// running in the job, any processes on the host or in another job will not be able to see the binding.
func (job *JobObject) ApplyFileBinding(root, target string, readOnly bool) error {
job.handleLock.RLock()
defer job.handleLock.RUnlock()
if job.handle == 0 {
return ErrAlreadyClosed
}
if !job.isSilo() {
return ErrNotSilo
}
// The parent directory needs to exist for the bind to work. MkdirAll stats and
// returns nil if the directory exists internally so we should be fine to mkdirall
// every time.
if err := os.MkdirAll(filepath.Dir(root), 0); err != nil {
return err
}
rootPtr, err := windows.UTF16PtrFromString(root)
if err != nil {
return err
}
targetPtr, err := windows.UTF16PtrFromString(target)
if err != nil {
return err
}
flags := winapi.BINDFLT_FLAG_USE_CURRENT_SILO_MAPPING
if readOnly {
flags |= winapi.BINDFLT_FLAG_READ_ONLY_MAPPING
}
if err := winapi.BfSetupFilter(
job.handle,
flags,
rootPtr,
targetPtr,
nil,
0,
); err != nil {
return fmt.Errorf("failed to bind target %q to root %q for job object: %w", target, root, err)
}
return nil
}
// isJobSilo is a helper to determine if a job object that was opened is a silo. This should ONLY be called
// from `Open` and any callers in this package afterwards should use `job.isSilo()`
func isJobSilo(h windows.Handle) bool {
// None of the information from the structure that this info class expects will be used, this is just used as
// the call will fail if the job hasn't been upgraded to a silo so we can use this to tell when we open a job
// if it's a silo or not. Because none of the info matters simply define a dummy struct with the size that the call
// expects which is 16 bytes.
type isSiloObj struct {
_ [16]byte
}
var siloInfo isSiloObj
err := winapi.QueryInformationJobObject(
h,
winapi.JobObjectSiloBasicInformation,
unsafe.Pointer(&siloInfo),
uint32(unsafe.Sizeof(siloInfo)),
nil,
)
return err == nil
}
// PromoteToSilo promotes a job object to a silo. There must be no running processess
// in the job for this to succeed. If the job is already a silo this is a no-op.
func (job *JobObject) PromoteToSilo() error {
job.handleLock.RLock()
defer job.handleLock.RUnlock()
if job.handle == 0 {
return ErrAlreadyClosed
}
if job.isSilo() {
return nil
}
pids, err := job.Pids()
if err != nil {
return err
}
if len(pids) != 0 {
return fmt.Errorf("job cannot have running processes to be promoted to a silo, found %d running processes", len(pids))
}
_, err = windows.SetInformationJobObject(
job.handle,
winapi.JobObjectCreateSilo,
0,
0,
)
if err != nil {
return fmt.Errorf("failed to promote job to silo: %w", err)
}
atomic.StoreUint32(&job.silo, 1)
return nil
}
// isSilo returns if the job object is a silo.
func (job *JobObject) isSilo() bool {
return atomic.LoadUint32(&job.silo) == 1
}
// QueryPrivateWorkingSet returns the private working set size for the job. This is calculated by adding up the // QueryPrivateWorkingSet returns the private working set size for the job. This is calculated by adding up the
// private working set for every process running in the job. // private working set for every process running in the job.
func (job *JobObject) QueryPrivateWorkingSet() (uint64, error) { func (job *JobObject) QueryPrivateWorkingSet() (uint64, error) {

View File

@ -1,3 +1,5 @@
//go:build windows
package jobobject package jobobject
import ( import (

View File

@ -0,0 +1,118 @@
package log
import (
"context"
"github.com/sirupsen/logrus"
"go.opencensus.io/trace"
)
type entryContextKeyType int
const _entryContextKey entryContextKeyType = iota
var (
// L is the default, blank logging entry. WithField and co. all return a copy
// of the original entry, so this will not leak fields between calls.
//
// Do NOT modify fields directly, as that will corrupt state for all users and
// is not thread safe.
// Instead, use `L.With*` or `L.Dup()`. Or `G(context.Background())`.
L = logrus.NewEntry(logrus.StandardLogger())
// G is an alias for GetEntry
G = GetEntry
// S is an alias for SetEntry
S = SetEntry
// U is an alias for UpdateContext
U = UpdateContext
)
// GetEntry returns a `logrus.Entry` stored in the context, if one exists.
// Otherwise, it returns a default entry that points to the current context.
//
// Note: if the a new entry is returned, it will reference the passed in context.
// However, existing contexts may be stored in parent contexts and additionally reference
// earlier contexts.
// Use `UpdateContext` to update the entry and context.
func GetEntry(ctx context.Context) *logrus.Entry {
entry := fromContext(ctx)
if entry == nil {
entry = L.WithContext(ctx)
}
return entry
}
// SetEntry updates the log entry in the context with the provided fields, and
// returns both. It is equivalent to:
//
// entry := GetEntry(ctx).WithFields(fields)
// ctx = WithContext(ctx, entry)
//
// See WithContext for more information.
func SetEntry(ctx context.Context, fields logrus.Fields) (context.Context, *logrus.Entry) {
e := GetEntry(ctx)
if len(fields) > 0 {
e = e.WithFields(fields)
}
return WithContext(ctx, e)
}
// UpdateContext extracts the log entry from the context, and, if the entry's
// context points to a parent's of the current context, ands the entry
// to the most recent context. It is equivalent to:
//
// entry := GetEntry(ctx)
// ctx = WithContext(ctx, entry)
//
// This allows the entry to reference the most recent context and any new
// values (such as span contexts) added to it.
//
// See WithContext for more information.
func UpdateContext(ctx context.Context) context.Context {
// there is no way to check its ctx (and not one of its parents) that contains `e`
// so, at a slight cost, force add `e` to the context
ctx, _ = WithContext(ctx, GetEntry(ctx))
return ctx
}
// WithContext returns a context that contains the provided log entry.
// The entry can be extracted with `GetEntry` (`G`)
//
// The entry in the context is a copy of `entry` (generated by `entry.WithContext`)
func WithContext(ctx context.Context, entry *logrus.Entry) (context.Context, *logrus.Entry) {
// regardless of the order, entry.Context != GetEntry(ctx)
// here, the returned entry will reference the supplied context
entry = entry.WithContext(ctx)
ctx = context.WithValue(ctx, _entryContextKey, entry)
return ctx, entry
}
// Copy extracts the tracing Span and logging entry from the src Context, if they
// exist, and adds them to the dst Context.
//
// This is useful to share tracing and logging between contexts, but not the
// cancellation. For example, if the src Context has been cancelled but cleanup
// operations triggered by the cancellation require a non-cancelled context to
// execute.
func Copy(dst context.Context, src context.Context) context.Context {
if s := trace.FromContext(src); s != nil {
dst = trace.NewContext(dst, s)
}
if e := fromContext(src); e != nil {
dst, _ = WithContext(dst, e)
}
return dst
}
func fromContext(ctx context.Context) *logrus.Entry {
e, _ := ctx.Value(_entryContextKey).(*logrus.Entry)
return e
}

View File

@ -0,0 +1,85 @@
package log
import (
"bytes"
"context"
"encoding/json"
"fmt"
"net"
"reflect"
"time"
"github.com/containerd/containerd/log"
)
const TimeFormat = log.RFC3339NanoFixed
func FormatTime(t time.Time) string {
return t.Format(TimeFormat)
}
// DurationFormat formats a [time.Duration] log entry.
//
// A nil value signals an error with the formatting.
type DurationFormat func(time.Duration) interface{}
func DurationFormatString(d time.Duration) interface{} { return d.String() }
func DurationFormatSeconds(d time.Duration) interface{} { return d.Seconds() }
func DurationFormatMilliseconds(d time.Duration) interface{} { return d.Milliseconds() }
// FormatIO formats net.Conn and other types that have an `Addr()` or `Name()`.
//
// See FormatEnabled for more information.
func FormatIO(ctx context.Context, v interface{}) string {
m := make(map[string]string)
m["type"] = reflect.TypeOf(v).String()
switch t := v.(type) {
case net.Conn:
m["localAddress"] = formatAddr(t.LocalAddr())
m["remoteAddress"] = formatAddr(t.RemoteAddr())
case interface{ Addr() net.Addr }:
m["address"] = formatAddr(t.Addr())
default:
return Format(ctx, t)
}
return Format(ctx, m)
}
func formatAddr(a net.Addr) string {
return a.Network() + "://" + a.String()
}
// Format formats an object into a JSON string, without any indendtation or
// HTML escapes.
// Context is used to output a log waring if the conversion fails.
//
// This is intended primarily for `trace.StringAttribute()`
func Format(ctx context.Context, v interface{}) string {
b, err := encode(v)
if err != nil {
G(ctx).WithError(err).Warning("could not format value")
return ""
}
return string(b)
}
func encode(v interface{}) ([]byte, error) {
return encodeBuffer(&bytes.Buffer{}, v)
}
func encodeBuffer(buf *bytes.Buffer, v interface{}) ([]byte, error) {
enc := json.NewEncoder(buf)
enc.SetEscapeHTML(false)
enc.SetIndent("", "")
if err := enc.Encode(v); err != nil {
err = fmt.Errorf("could not marshall %T to JSON for logging: %w", v, err)
return nil, err
}
// encoder.Encode appends a newline to the end
return bytes.TrimSpace(buf.Bytes()), nil
}

View File

@ -1,23 +0,0 @@
package log
import (
"context"
"github.com/sirupsen/logrus"
"go.opencensus.io/trace"
)
// G returns a `logrus.Entry` with the `TraceID, SpanID` from `ctx` if `ctx`
// contains an OpenCensus `trace.Span`.
func G(ctx context.Context) *logrus.Entry {
span := trace.FromContext(ctx)
if span != nil {
sctx := span.SpanContext()
return logrus.WithFields(logrus.Fields{
"traceID": sctx.TraceID.String(),
"spanID": sctx.SpanID.String(),
// "parentSpanID": TODO: JTERRY75 - Try to convince OC to export this?
})
}
return logrus.NewEntry(logrus.StandardLogger())
}

Some files were not shown because too many files have changed in this diff Show More