Signed-off-by: John Howard <jhoward@microsoft.com>
| ... | ... |
@@ -1,6 +1,6 @@ |
| 1 | 1 |
# the following lines are in sorted order, FYI |
| 2 | 2 |
github.com/Azure/go-ansiterm 388960b655244e76e24c75f48631564eaefade62 |
| 3 |
-github.com/Microsoft/hcsshim v0.5.2 |
|
| 3 |
+github.com/Microsoft/hcsshim v0.5.7 |
|
| 4 | 4 |
github.com/Microsoft/go-winio v0.3.5 |
| 5 | 5 |
github.com/Sirupsen/logrus f76d643702a30fbffecdfe50831e11881c96ceb3 https://github.com/aaronlehmann/logrus |
| 6 | 6 |
github.com/davecgh/go-spew 6d212800a42e8ab5c146b8ace3490ee17e5225f9 |
| ... | ... |
@@ -27,7 +27,8 @@ type container struct {
|
| 27 | 27 |
callbackNumber uintptr |
| 28 | 28 |
} |
| 29 | 29 |
|
| 30 |
-type containerProperties struct {
|
|
| 30 |
+// ContainerProperties holds the properties for a container and the processes running in that container |
|
| 31 |
+type ContainerProperties struct {
|
|
| 31 | 32 |
ID string `json:"Id"` |
| 32 | 33 |
Name string |
| 33 | 34 |
SystemType string |
| ... | ... |
@@ -35,6 +36,8 @@ type containerProperties struct {
|
| 35 | 35 |
SiloGUID string `json:"SiloGuid,omitempty"` |
| 36 | 36 |
IsDummy bool `json:",omitempty"` |
| 37 | 37 |
RuntimeID string `json:"RuntimeId,omitempty"` |
| 38 |
+ IsRuntimeTemplate bool `json:",omitempty"` |
|
| 39 |
+ RuntimeImagePath string `json:",omitempty"` |
|
| 38 | 40 |
Stopped bool `json:",omitempty"` |
| 39 | 41 |
ExitType string `json:",omitempty"` |
| 40 | 42 |
AreUpdatesPending bool `json:",omitempty"` |
| ... | ... |
@@ -161,11 +164,47 @@ func OpenContainer(id string) (Container, error) {
|
| 161 | 161 |
|
| 162 | 162 |
container.handle = handle |
| 163 | 163 |
|
| 164 |
+ if err := container.registerCallback(); err != nil {
|
|
| 165 |
+ return nil, makeContainerError(container, operation, "", err) |
|
| 166 |
+ } |
|
| 167 |
+ |
|
| 164 | 168 |
logrus.Debugf(title+" succeeded id=%s handle=%d", id, handle) |
| 165 | 169 |
runtime.SetFinalizer(container, closeContainer) |
| 166 | 170 |
return container, nil |
| 167 | 171 |
} |
| 168 | 172 |
|
| 173 |
+// GetContainers gets a list of the containers on the system that match the query |
|
| 174 |
+func GetContainers(q ComputeSystemQuery) ([]ContainerProperties, error) {
|
|
| 175 |
+ operation := "GetContainers" |
|
| 176 |
+ title := "HCSShim::" + operation |
|
| 177 |
+ |
|
| 178 |
+ queryb, err := json.Marshal(q) |
|
| 179 |
+ if err != nil {
|
|
| 180 |
+ return nil, err |
|
| 181 |
+ } |
|
| 182 |
+ |
|
| 183 |
+ query := string(queryb) |
|
| 184 |
+ logrus.Debugf(title+" query=%s", query) |
|
| 185 |
+ |
|
| 186 |
+ var ( |
|
| 187 |
+ resultp *uint16 |
|
| 188 |
+ computeSystemsp *uint16 |
|
| 189 |
+ ) |
|
| 190 |
+ err = hcsEnumerateComputeSystems(query, &computeSystemsp, &resultp) |
|
| 191 |
+ err = processHcsResult(err, resultp) |
|
| 192 |
+ if computeSystemsp == nil {
|
|
| 193 |
+ return nil, ErrUnexpectedValue |
|
| 194 |
+ } |
|
| 195 |
+ computeSystemsRaw := convertAndFreeCoTaskMemBytes(computeSystemsp) |
|
| 196 |
+ computeSystems := []ContainerProperties{}
|
|
| 197 |
+ if err := json.Unmarshal(computeSystemsRaw, &computeSystems); err != nil {
|
|
| 198 |
+ return nil, err |
|
| 199 |
+ } |
|
| 200 |
+ |
|
| 201 |
+ logrus.Debugf(title + " succeeded") |
|
| 202 |
+ return computeSystems, nil |
|
| 203 |
+} |
|
| 204 |
+ |
|
| 169 | 205 |
// Start synchronously starts the container. |
| 170 | 206 |
func (container *container) Start() error {
|
| 171 | 207 |
container.handleLock.RLock() |
| ... | ... |
@@ -175,7 +214,7 @@ func (container *container) Start() error {
|
| 175 | 175 |
logrus.Debugf(title+" id=%s", container.id) |
| 176 | 176 |
|
| 177 | 177 |
if container.handle == 0 {
|
| 178 |
- return makeContainerError(container, operation, "", ErrInvalidHandle) |
|
| 178 |
+ return makeContainerError(container, operation, "", ErrAlreadyClosed) |
|
| 179 | 179 |
} |
| 180 | 180 |
|
| 181 | 181 |
var resultp *uint16 |
| ... | ... |
@@ -199,7 +238,7 @@ func (container *container) Shutdown() error {
|
| 199 | 199 |
logrus.Debugf(title+" id=%s", container.id) |
| 200 | 200 |
|
| 201 | 201 |
if container.handle == 0 {
|
| 202 |
- return makeContainerError(container, operation, "", ErrInvalidHandle) |
|
| 202 |
+ return makeContainerError(container, operation, "", ErrAlreadyClosed) |
|
| 203 | 203 |
} |
| 204 | 204 |
|
| 205 | 205 |
var resultp *uint16 |
| ... | ... |
@@ -223,7 +262,7 @@ func (container *container) Terminate() error {
|
| 223 | 223 |
logrus.Debugf(title+" id=%s", container.id) |
| 224 | 224 |
|
| 225 | 225 |
if container.handle == 0 {
|
| 226 |
- return makeContainerError(container, operation, "", ErrInvalidHandle) |
|
| 226 |
+ return makeContainerError(container, operation, "", ErrAlreadyClosed) |
|
| 227 | 227 |
} |
| 228 | 228 |
|
| 229 | 229 |
var resultp *uint16 |
| ... | ... |
@@ -268,7 +307,7 @@ func (container *container) WaitTimeout(timeout time.Duration) error {
|
| 268 | 268 |
return nil |
| 269 | 269 |
} |
| 270 | 270 |
|
| 271 |
-func (container *container) properties(query string) (*containerProperties, error) {
|
|
| 271 |
+func (container *container) properties(query string) (*ContainerProperties, error) {
|
|
| 272 | 272 |
var ( |
| 273 | 273 |
resultp *uint16 |
| 274 | 274 |
propertiesp *uint16 |
| ... | ... |
@@ -283,7 +322,7 @@ func (container *container) properties(query string) (*containerProperties, erro |
| 283 | 283 |
return nil, ErrUnexpectedValue |
| 284 | 284 |
} |
| 285 | 285 |
propertiesRaw := convertAndFreeCoTaskMemBytes(propertiesp) |
| 286 |
- properties := &containerProperties{}
|
|
| 286 |
+ properties := &ContainerProperties{}
|
|
| 287 | 287 |
if err := json.Unmarshal(propertiesRaw, properties); err != nil {
|
| 288 | 288 |
return nil, err |
| 289 | 289 |
} |
| ... | ... |
@@ -299,7 +338,7 @@ func (container *container) HasPendingUpdates() (bool, error) {
|
| 299 | 299 |
logrus.Debugf(title+" id=%s", container.id) |
| 300 | 300 |
|
| 301 | 301 |
if container.handle == 0 {
|
| 302 |
- return false, makeContainerError(container, operation, "", ErrInvalidHandle) |
|
| 302 |
+ return false, makeContainerError(container, operation, "", ErrAlreadyClosed) |
|
| 303 | 303 |
} |
| 304 | 304 |
|
| 305 | 305 |
properties, err := container.properties(pendingUpdatesQuery) |
| ... | ... |
@@ -320,7 +359,7 @@ func (container *container) Statistics() (Statistics, error) {
|
| 320 | 320 |
logrus.Debugf(title+" id=%s", container.id) |
| 321 | 321 |
|
| 322 | 322 |
if container.handle == 0 {
|
| 323 |
- return Statistics{}, makeContainerError(container, operation, "", ErrInvalidHandle)
|
|
| 323 |
+ return Statistics{}, makeContainerError(container, operation, "", ErrAlreadyClosed)
|
|
| 324 | 324 |
} |
| 325 | 325 |
|
| 326 | 326 |
properties, err := container.properties(statisticsQuery) |
| ... | ... |
@@ -341,7 +380,7 @@ func (container *container) ProcessList() ([]ProcessListItem, error) {
|
| 341 | 341 |
logrus.Debugf(title+" id=%s", container.id) |
| 342 | 342 |
|
| 343 | 343 |
if container.handle == 0 {
|
| 344 |
- return nil, makeContainerError(container, operation, "", ErrInvalidHandle) |
|
| 344 |
+ return nil, makeContainerError(container, operation, "", ErrAlreadyClosed) |
|
| 345 | 345 |
} |
| 346 | 346 |
|
| 347 | 347 |
properties, err := container.properties(processListQuery) |
| ... | ... |
@@ -362,7 +401,7 @@ func (container *container) Pause() error {
|
| 362 | 362 |
logrus.Debugf(title+" id=%s", container.id) |
| 363 | 363 |
|
| 364 | 364 |
if container.handle == 0 {
|
| 365 |
- return makeContainerError(container, operation, "", ErrInvalidHandle) |
|
| 365 |
+ return makeContainerError(container, operation, "", ErrAlreadyClosed) |
|
| 366 | 366 |
} |
| 367 | 367 |
|
| 368 | 368 |
var resultp *uint16 |
| ... | ... |
@@ -385,7 +424,7 @@ func (container *container) Resume() error {
|
| 385 | 385 |
logrus.Debugf(title+" id=%s", container.id) |
| 386 | 386 |
|
| 387 | 387 |
if container.handle == 0 {
|
| 388 |
- return makeContainerError(container, operation, "", ErrInvalidHandle) |
|
| 388 |
+ return makeContainerError(container, operation, "", ErrAlreadyClosed) |
|
| 389 | 389 |
} |
| 390 | 390 |
|
| 391 | 391 |
var resultp *uint16 |
| ... | ... |
@@ -412,7 +451,7 @@ func (container *container) CreateProcess(c *ProcessConfig) (Process, error) {
|
| 412 | 412 |
) |
| 413 | 413 |
|
| 414 | 414 |
if container.handle == 0 {
|
| 415 |
- return nil, makeContainerError(container, operation, "", ErrInvalidHandle) |
|
| 415 |
+ return nil, makeContainerError(container, operation, "", ErrAlreadyClosed) |
|
| 416 | 416 |
} |
| 417 | 417 |
|
| 418 | 418 |
// If we are not emulating a console, ignore any console size passed to us |
| ... | ... |
@@ -468,7 +507,7 @@ func (container *container) OpenProcess(pid int) (Process, error) {
|
| 468 | 468 |
) |
| 469 | 469 |
|
| 470 | 470 |
if container.handle == 0 {
|
| 471 |
- return nil, makeContainerError(container, operation, "", ErrInvalidHandle) |
|
| 471 |
+ return nil, makeContainerError(container, operation, "", ErrAlreadyClosed) |
|
| 472 | 472 |
} |
| 473 | 473 |
|
| 474 | 474 |
err := hcsOpenProcess(container.handle, uint32(pid), &processHandle, &resultp) |
| ... | ... |
@@ -514,6 +553,7 @@ func (container *container) Close() error {
|
| 514 | 514 |
} |
| 515 | 515 |
|
| 516 | 516 |
container.handle = 0 |
| 517 |
+ runtime.SetFinalizer(container, nil) |
|
| 517 | 518 |
|
| 518 | 519 |
logrus.Debugf(title+" succeeded id=%s", container.id) |
| 519 | 520 |
return nil |
| ... | ... |
@@ -16,8 +16,8 @@ var ( |
| 16 | 16 |
// ErrHandleClose is an error encountered when the handle generating the notification being waited on has been closed |
| 17 | 17 |
ErrHandleClose = errors.New("hcsshim: the handle generating this notification has been closed")
|
| 18 | 18 |
|
| 19 |
- // ErrInvalidHandle is an error encountered when using an invalid handle |
|
| 20 |
- ErrInvalidHandle = errors.New("hcsshim: the handle is invalid")
|
|
| 19 |
+ // ErrAlreadyClosed is an error encountered when using a handle that has been closed by the Close method |
|
| 20 |
+ ErrAlreadyClosed = errors.New("hcsshim: the handle has already been closed")
|
|
| 21 | 21 |
|
| 22 | 22 |
// ErrInvalidNotificationType is an error encountered when an invalid notification type is used |
| 23 | 23 |
ErrInvalidNotificationType = errors.New("hcsshim: invalid notification type")
|
| ... | ... |
@@ -159,6 +159,13 @@ func IsNotExist(err error) bool {
|
| 159 | 159 |
err == ErrProcNotFound |
| 160 | 160 |
} |
| 161 | 161 |
|
| 162 |
+// IsAlreadyClosed checks if an error is caused by the Container or Process having been |
|
| 163 |
+// already closed by a call to the Close() method. |
|
| 164 |
+func IsAlreadyClosed(err error) bool {
|
|
| 165 |
+ err = getInnerError(err) |
|
| 166 |
+ return err == ErrAlreadyClosed |
|
| 167 |
+} |
|
| 168 |
+ |
|
| 162 | 169 |
// IsPending returns a boolean indicating whether the error is that |
| 163 | 170 |
// the requested operation is being completed in the background. |
| 164 | 171 |
func IsPending(err error) bool {
|
| ... | ... |
@@ -52,7 +52,7 @@ type MacPool struct {
|
| 52 | 52 |
|
| 53 | 53 |
// HNSNetwork represents a network in HNS |
| 54 | 54 |
type HNSNetwork struct {
|
| 55 |
- Id string `json:",omitempty"` |
|
| 55 |
+ Id string `json:"ID,omitempty"` |
|
| 56 | 56 |
Name string `json:",omitempty"` |
| 57 | 57 |
Type string `json:",omitempty"` |
| 58 | 58 |
NetworkAdapterName string `json:",omitempty"` |
| ... | ... |
@@ -68,7 +68,7 @@ type HNSNetwork struct {
|
| 68 | 68 |
|
| 69 | 69 |
// HNSEndpoint represents a network endpoint in HNS |
| 70 | 70 |
type HNSEndpoint struct {
|
| 71 |
- Id string `json:",omitempty"` |
|
| 71 |
+ Id string `json:"ID,omitempty"` |
|
| 72 | 72 |
Name string `json:",omitempty"` |
| 73 | 73 |
VirtualNetwork string `json:",omitempty"` |
| 74 | 74 |
VirtualNetworkName string `json:",omitempty"` |
| ... | ... |
@@ -79,6 +79,7 @@ type HNSEndpoint struct {
|
| 79 | 79 |
DNSServerList string `json:",omitempty"` |
| 80 | 80 |
GatewayAddress string `json:",omitempty"` |
| 81 | 81 |
EnableInternalDNS bool `json:",omitempty"` |
| 82 |
+ DisableICC bool `json:",omitempty"` |
|
| 82 | 83 |
PrefixLength uint8 `json:",omitempty"` |
| 83 | 84 |
IsRemoteEndpoint bool `json:",omitempty"` |
| 84 | 85 |
} |
| ... | ... |
@@ -10,6 +10,7 @@ import ( |
| 10 | 10 |
type ProcessConfig struct {
|
| 11 | 11 |
ApplicationName string |
| 12 | 12 |
CommandLine string |
| 13 |
+ User string |
|
| 13 | 14 |
WorkingDirectory string |
| 14 | 15 |
Environment map[string]string |
| 15 | 16 |
EmulateConsole bool |
| ... | ... |
@@ -66,6 +67,13 @@ type ContainerConfig struct {
|
| 66 | 66 |
AllowUnqualifiedDNSQuery bool // True to allow unqualified DNS name resolution |
| 67 | 67 |
} |
| 68 | 68 |
|
| 69 |
+type ComputeSystemQuery struct {
|
|
| 70 |
+ IDs []string `json:"Ids,omitempty"` |
|
| 71 |
+ Types []string `json:",omitempty"` |
|
| 72 |
+ Names []string `json:",omitempty"` |
|
| 73 |
+ Owners []string `json:",omitempty"` |
|
| 74 |
+} |
|
| 75 |
+ |
|
| 69 | 76 |
// Container represents a created (but not necessarily running) container. |
| 70 | 77 |
type Container interface {
|
| 71 | 78 |
// Start synchronously starts the container. |
| ... | ... |
@@ -3,6 +3,7 @@ package hcsshim |
| 3 | 3 |
import ( |
| 4 | 4 |
"encoding/json" |
| 5 | 5 |
"io" |
| 6 |
+ "runtime" |
|
| 6 | 7 |
"sync" |
| 7 | 8 |
"syscall" |
| 8 | 9 |
"time" |
| ... | ... |
@@ -73,7 +74,7 @@ func (process *process) Kill() error {
|
| 73 | 73 |
logrus.Debugf(title+" processid=%d", process.processID) |
| 74 | 74 |
|
| 75 | 75 |
if process.handle == 0 {
|
| 76 |
- return makeProcessError(process, operation, "", ErrInvalidHandle) |
|
| 76 |
+ return makeProcessError(process, operation, "", ErrAlreadyClosed) |
|
| 77 | 77 |
} |
| 78 | 78 |
|
| 79 | 79 |
var resultp *uint16 |
| ... | ... |
@@ -128,7 +129,7 @@ func (process *process) ExitCode() (int, error) {
|
| 128 | 128 |
logrus.Debugf(title+" processid=%d", process.processID) |
| 129 | 129 |
|
| 130 | 130 |
if process.handle == 0 {
|
| 131 |
- return 0, makeProcessError(process, operation, "", ErrInvalidHandle) |
|
| 131 |
+ return 0, makeProcessError(process, operation, "", ErrAlreadyClosed) |
|
| 132 | 132 |
} |
| 133 | 133 |
|
| 134 | 134 |
properties, err := process.properties() |
| ... | ... |
@@ -157,7 +158,7 @@ func (process *process) ResizeConsole(width, height uint16) error {
|
| 157 | 157 |
logrus.Debugf(title+" processid=%d", process.processID) |
| 158 | 158 |
|
| 159 | 159 |
if process.handle == 0 {
|
| 160 |
- return makeProcessError(process, operation, "", ErrInvalidHandle) |
|
| 160 |
+ return makeProcessError(process, operation, "", ErrAlreadyClosed) |
|
| 161 | 161 |
} |
| 162 | 162 |
|
| 163 | 163 |
modifyRequest := processModifyRequest{
|
| ... | ... |
@@ -226,7 +227,7 @@ func (process *process) Stdio() (io.WriteCloser, io.ReadCloser, io.ReadCloser, e |
| 226 | 226 |
logrus.Debugf(title+" processid=%d", process.processID) |
| 227 | 227 |
|
| 228 | 228 |
if process.handle == 0 {
|
| 229 |
- return nil, nil, nil, makeProcessError(process, operation, "", ErrInvalidHandle) |
|
| 229 |
+ return nil, nil, nil, makeProcessError(process, operation, "", ErrAlreadyClosed) |
|
| 230 | 230 |
} |
| 231 | 231 |
|
| 232 | 232 |
var stdIn, stdOut, stdErr syscall.Handle |
| ... | ... |
@@ -270,7 +271,7 @@ func (process *process) CloseStdin() error {
|
| 270 | 270 |
logrus.Debugf(title+" processid=%d", process.processID) |
| 271 | 271 |
|
| 272 | 272 |
if process.handle == 0 {
|
| 273 |
- return makeProcessError(process, operation, "", ErrInvalidHandle) |
|
| 273 |
+ return makeProcessError(process, operation, "", ErrAlreadyClosed) |
|
| 274 | 274 |
} |
| 275 | 275 |
|
| 276 | 276 |
modifyRequest := processModifyRequest{
|
| ... | ... |
@@ -321,6 +322,7 @@ func (process *process) Close() error {
|
| 321 | 321 |
} |
| 322 | 322 |
|
| 323 | 323 |
process.handle = 0 |
| 324 |
+ runtime.SetFinalizer(process, nil) |
|
| 324 | 325 |
|
| 325 | 326 |
logrus.Debugf(title+" succeeded processid=%d", process.processID) |
| 326 | 327 |
return nil |
| ... | ... |
@@ -26,37 +26,13 @@ func waitForNotification(callbackNumber uintptr, expectedNotification hcsNotific |
| 26 | 26 |
return ErrInvalidNotificationType |
| 27 | 27 |
} |
| 28 | 28 |
|
| 29 |
+ var c <-chan time.Time |
|
| 29 | 30 |
if timeout != nil {
|
| 30 | 31 |
timer := time.NewTimer(*timeout) |
| 32 |
+ c = timer.C |
|
| 31 | 33 |
defer timer.Stop() |
| 32 |
- |
|
| 33 |
- select {
|
|
| 34 |
- case err, ok := <-expectedChannel: |
|
| 35 |
- if !ok {
|
|
| 36 |
- return ErrHandleClose |
|
| 37 |
- } |
|
| 38 |
- return err |
|
| 39 |
- case err, ok := <-channels[hcsNotificationSystemExited]: |
|
| 40 |
- if !ok {
|
|
| 41 |
- return ErrHandleClose |
|
| 42 |
- } |
|
| 43 |
- // If the expected notification is hcsNotificationSystemExited which of the two selects |
|
| 44 |
- // chosen is random. Return the raw error if hcsNotificationSystemExited is expected |
|
| 45 |
- if channels[hcsNotificationSystemExited] == expectedChannel {
|
|
| 46 |
- return err |
|
| 47 |
- } |
|
| 48 |
- return ErrUnexpectedContainerExit |
|
| 49 |
- case _, ok := <-channels[hcsNotificationServiceDisconnect]: |
|
| 50 |
- if !ok {
|
|
| 51 |
- return ErrHandleClose |
|
| 52 |
- } |
|
| 53 |
- // hcsNotificationServiceDisconnect should never be an expected notification |
|
| 54 |
- // it does not need the same handling as hcsNotificationSystemExited |
|
| 55 |
- return ErrUnexpectedProcessAbort |
|
| 56 |
- case <-timer.C: |
|
| 57 |
- return ErrTimeout |
|
| 58 |
- } |
|
| 59 | 34 |
} |
| 35 |
+ |
|
| 60 | 36 |
select {
|
| 61 | 37 |
case err, ok := <-expectedChannel: |
| 62 | 38 |
if !ok {
|
| ... | ... |
@@ -80,5 +56,7 @@ func waitForNotification(callbackNumber uintptr, expectedNotification hcsNotific |
| 80 | 80 |
// hcsNotificationServiceDisconnect should never be an expected notification |
| 81 | 81 |
// it does not need the same handling as hcsNotificationSystemExited |
| 82 | 82 |
return ErrUnexpectedProcessAbort |
| 83 |
+ case <-c: |
|
| 84 |
+ return ErrTimeout |
|
| 83 | 85 |
} |
| 84 | 86 |
} |