1package hcsshim 2 3import ( 4 "context" 5 "fmt" 6 "os" 7 "sync" 8 "time" 9 10 "github.com/Microsoft/hcsshim/internal/hcs" 11 "github.com/Microsoft/hcsshim/internal/mergemaps" 12 "github.com/Microsoft/hcsshim/internal/schema1" 13) 14 15// ContainerProperties holds the properties for a container and the processes running in that container 16type ContainerProperties = schema1.ContainerProperties 17 18// MemoryStats holds the memory statistics for a container 19type MemoryStats = schema1.MemoryStats 20 21// ProcessorStats holds the processor statistics for a container 22type ProcessorStats = schema1.ProcessorStats 23 24// StorageStats holds the storage statistics for a container 25type StorageStats = schema1.StorageStats 26 27// NetworkStats holds the network statistics for a container 28type NetworkStats = schema1.NetworkStats 29 30// Statistics is the structure returned by a statistics call on a container 31type Statistics = schema1.Statistics 32 33// ProcessList is the structure of an item returned by a ProcessList call on a container 34type ProcessListItem = schema1.ProcessListItem 35 36// MappedVirtualDiskController is the structure of an item returned by a MappedVirtualDiskList call on a container 37type MappedVirtualDiskController = schema1.MappedVirtualDiskController 38 39// Type of Request Support in ModifySystem 40type RequestType = schema1.RequestType 41 42// Type of Resource Support in ModifySystem 43type ResourceType = schema1.ResourceType 44 45// RequestType const 46const ( 47 Add = schema1.Add 48 Remove = schema1.Remove 49 Network = schema1.Network 50) 51 52// ResourceModificationRequestResponse is the structure used to send request to the container to modify the system 53// Supported resource types are Network and Request Types are Add/Remove 54type ResourceModificationRequestResponse = schema1.ResourceModificationRequestResponse 55 56type container struct { 57 system *hcs.System 58 waitOnce sync.Once 59 waitErr error 60 waitCh chan struct{} 61} 62 63// createComputeSystemAdditionalJSON is read from the environment at initialisation 64// time. It allows an environment variable to define additional JSON which 65// is merged in the CreateComputeSystem call to HCS. 66var createContainerAdditionalJSON []byte 67 68func init() { 69 createContainerAdditionalJSON = ([]byte)(os.Getenv("HCSSHIM_CREATECONTAINER_ADDITIONALJSON")) 70} 71 72// CreateContainer creates a new container with the given configuration but does not start it. 73func CreateContainer(id string, c *ContainerConfig) (Container, error) { 74 fullConfig, err := mergemaps.MergeJSON(c, createContainerAdditionalJSON) 75 if err != nil { 76 return nil, fmt.Errorf("failed to merge additional JSON '%s': %s", createContainerAdditionalJSON, err) 77 } 78 79 system, err := hcs.CreateComputeSystem(context.Background(), id, fullConfig) 80 if err != nil { 81 return nil, err 82 } 83 return &container{system: system}, err 84} 85 86// OpenContainer opens an existing container by ID. 87func OpenContainer(id string) (Container, error) { 88 system, err := hcs.OpenComputeSystem(context.Background(), id) 89 if err != nil { 90 return nil, err 91 } 92 return &container{system: system}, err 93} 94 95// GetContainers gets a list of the containers on the system that match the query 96func GetContainers(q ComputeSystemQuery) ([]ContainerProperties, error) { 97 return hcs.GetComputeSystems(context.Background(), q) 98} 99 100// Start synchronously starts the container. 101func (container *container) Start() error { 102 return convertSystemError(container.system.Start(context.Background()), container) 103} 104 105// Shutdown requests a container shutdown, but it may not actually be shutdown until Wait() succeeds. 106func (container *container) Shutdown() error { 107 err := container.system.Shutdown(context.Background()) 108 if err != nil { 109 return convertSystemError(err, container) 110 } 111 return &ContainerError{Container: container, Err: ErrVmcomputeOperationPending, Operation: "hcsshim::ComputeSystem::Shutdown"} 112} 113 114// Terminate requests a container terminate, but it may not actually be terminated until Wait() succeeds. 115func (container *container) Terminate() error { 116 err := container.system.Terminate(context.Background()) 117 if err != nil { 118 return convertSystemError(err, container) 119 } 120 return &ContainerError{Container: container, Err: ErrVmcomputeOperationPending, Operation: "hcsshim::ComputeSystem::Terminate"} 121} 122 123// Waits synchronously waits for the container to shutdown or terminate. 124func (container *container) Wait() error { 125 err := container.system.Wait() 126 if err == nil { 127 err = container.system.ExitError() 128 } 129 return convertSystemError(err, container) 130} 131 132// WaitTimeout synchronously waits for the container to terminate or the duration to elapse. It 133// returns false if timeout occurs. 134func (container *container) WaitTimeout(timeout time.Duration) error { 135 container.waitOnce.Do(func() { 136 container.waitCh = make(chan struct{}) 137 go func() { 138 container.waitErr = container.Wait() 139 close(container.waitCh) 140 }() 141 }) 142 t := time.NewTimer(timeout) 143 defer t.Stop() 144 select { 145 case <-t.C: 146 return &ContainerError{Container: container, Err: ErrTimeout, Operation: "hcsshim::ComputeSystem::Wait"} 147 case <-container.waitCh: 148 return container.waitErr 149 } 150} 151 152// Pause pauses the execution of a container. 153func (container *container) Pause() error { 154 return convertSystemError(container.system.Pause(context.Background()), container) 155} 156 157// Resume resumes the execution of a container. 158func (container *container) Resume() error { 159 return convertSystemError(container.system.Resume(context.Background()), container) 160} 161 162// HasPendingUpdates returns true if the container has updates pending to install 163func (container *container) HasPendingUpdates() (bool, error) { 164 return false, nil 165} 166 167// Statistics returns statistics for the container. This is a legacy v1 call 168func (container *container) Statistics() (Statistics, error) { 169 properties, err := container.system.Properties(context.Background(), schema1.PropertyTypeStatistics) 170 if err != nil { 171 return Statistics{}, convertSystemError(err, container) 172 } 173 174 return properties.Statistics, nil 175} 176 177// ProcessList returns an array of ProcessListItems for the container. This is a legacy v1 call 178func (container *container) ProcessList() ([]ProcessListItem, error) { 179 properties, err := container.system.Properties(context.Background(), schema1.PropertyTypeProcessList) 180 if err != nil { 181 return nil, convertSystemError(err, container) 182 } 183 184 return properties.ProcessList, nil 185} 186 187// This is a legacy v1 call 188func (container *container) MappedVirtualDisks() (map[int]MappedVirtualDiskController, error) { 189 properties, err := container.system.Properties(context.Background(), schema1.PropertyTypeMappedVirtualDisk) 190 if err != nil { 191 return nil, convertSystemError(err, container) 192 } 193 194 return properties.MappedVirtualDiskControllers, nil 195} 196 197// CreateProcess launches a new process within the container. 198func (container *container) CreateProcess(c *ProcessConfig) (Process, error) { 199 p, err := container.system.CreateProcess(context.Background(), c) 200 if err != nil { 201 return nil, convertSystemError(err, container) 202 } 203 return &process{p: p.(*hcs.Process)}, nil 204} 205 206// OpenProcess gets an interface to an existing process within the container. 207func (container *container) OpenProcess(pid int) (Process, error) { 208 p, err := container.system.OpenProcess(context.Background(), pid) 209 if err != nil { 210 return nil, convertSystemError(err, container) 211 } 212 return &process{p: p}, nil 213} 214 215// Close cleans up any state associated with the container but does not terminate or wait for it. 216func (container *container) Close() error { 217 return convertSystemError(container.system.Close(), container) 218} 219 220// Modify the System 221func (container *container) Modify(config *ResourceModificationRequestResponse) error { 222 return convertSystemError(container.system.Modify(context.Background(), config), container) 223} 224