2019-01-12 04:58:27 +00:00
|
|
|
package hcsshim
|
|
|
|
|
|
|
|
import (
|
2019-09-30 23:25:17 +00:00
|
|
|
"context"
|
2019-01-12 04:58:27 +00:00
|
|
|
"fmt"
|
|
|
|
"os"
|
2019-09-30 23:25:17 +00:00
|
|
|
"sync"
|
2019-01-12 04:58:27 +00:00
|
|
|
"time"
|
|
|
|
|
|
|
|
"github.com/Microsoft/hcsshim/internal/hcs"
|
|
|
|
"github.com/Microsoft/hcsshim/internal/mergemaps"
|
|
|
|
"github.com/Microsoft/hcsshim/internal/schema1"
|
|
|
|
)
|
|
|
|
|
|
|
|
// ContainerProperties holds the properties for a container and the processes running in that container
|
|
|
|
type ContainerProperties = schema1.ContainerProperties
|
|
|
|
|
|
|
|
// MemoryStats holds the memory statistics for a container
|
|
|
|
type MemoryStats = schema1.MemoryStats
|
|
|
|
|
|
|
|
// ProcessorStats holds the processor statistics for a container
|
|
|
|
type ProcessorStats = schema1.ProcessorStats
|
|
|
|
|
|
|
|
// StorageStats holds the storage statistics for a container
|
|
|
|
type StorageStats = schema1.StorageStats
|
|
|
|
|
|
|
|
// NetworkStats holds the network statistics for a container
|
|
|
|
type NetworkStats = schema1.NetworkStats
|
|
|
|
|
|
|
|
// Statistics is the structure returned by a statistics call on a container
|
|
|
|
type Statistics = schema1.Statistics
|
|
|
|
|
|
|
|
// ProcessList is the structure of an item returned by a ProcessList call on a container
|
|
|
|
type ProcessListItem = schema1.ProcessListItem
|
|
|
|
|
|
|
|
// MappedVirtualDiskController is the structure of an item returned by a MappedVirtualDiskList call on a container
|
|
|
|
type MappedVirtualDiskController = schema1.MappedVirtualDiskController
|
|
|
|
|
|
|
|
// Type of Request Support in ModifySystem
|
|
|
|
type RequestType = schema1.RequestType
|
|
|
|
|
|
|
|
// Type of Resource Support in ModifySystem
|
|
|
|
type ResourceType = schema1.ResourceType
|
|
|
|
|
|
|
|
// RequestType const
|
|
|
|
const (
|
|
|
|
Add = schema1.Add
|
|
|
|
Remove = schema1.Remove
|
|
|
|
Network = schema1.Network
|
|
|
|
)
|
|
|
|
|
|
|
|
// ResourceModificationRequestResponse is the structure used to send request to the container to modify the system
|
|
|
|
// Supported resource types are Network and Request Types are Add/Remove
|
|
|
|
type ResourceModificationRequestResponse = schema1.ResourceModificationRequestResponse
|
|
|
|
|
|
|
|
type container struct {
|
2019-09-30 23:25:17 +00:00
|
|
|
system *hcs.System
|
|
|
|
waitOnce sync.Once
|
|
|
|
waitErr error
|
|
|
|
waitCh chan struct{}
|
2019-01-12 04:58:27 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
// createComputeSystemAdditionalJSON is read from the environment at initialisation
|
|
|
|
// time. It allows an environment variable to define additional JSON which
|
|
|
|
// is merged in the CreateComputeSystem call to HCS.
|
|
|
|
var createContainerAdditionalJSON []byte
|
|
|
|
|
|
|
|
func init() {
|
|
|
|
createContainerAdditionalJSON = ([]byte)(os.Getenv("HCSSHIM_CREATECONTAINER_ADDITIONALJSON"))
|
|
|
|
}
|
|
|
|
|
|
|
|
// CreateContainer creates a new container with the given configuration but does not start it.
|
|
|
|
func CreateContainer(id string, c *ContainerConfig) (Container, error) {
|
|
|
|
fullConfig, err := mergemaps.MergeJSON(c, createContainerAdditionalJSON)
|
|
|
|
if err != nil {
|
|
|
|
return nil, fmt.Errorf("failed to merge additional JSON '%s': %s", createContainerAdditionalJSON, err)
|
|
|
|
}
|
|
|
|
|
2019-09-30 23:25:17 +00:00
|
|
|
system, err := hcs.CreateComputeSystem(context.Background(), id, fullConfig)
|
2019-01-12 04:58:27 +00:00
|
|
|
if err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
2019-09-30 23:25:17 +00:00
|
|
|
return &container{system: system}, err
|
2019-01-12 04:58:27 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
// OpenContainer opens an existing container by ID.
|
|
|
|
func OpenContainer(id string) (Container, error) {
|
2019-09-30 23:25:17 +00:00
|
|
|
system, err := hcs.OpenComputeSystem(context.Background(), id)
|
2019-01-12 04:58:27 +00:00
|
|
|
if err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
2019-09-30 23:25:17 +00:00
|
|
|
return &container{system: system}, err
|
2019-01-12 04:58:27 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
// GetContainers gets a list of the containers on the system that match the query
|
|
|
|
func GetContainers(q ComputeSystemQuery) ([]ContainerProperties, error) {
|
2019-09-30 23:25:17 +00:00
|
|
|
return hcs.GetComputeSystems(context.Background(), q)
|
2019-01-12 04:58:27 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
// Start synchronously starts the container.
|
|
|
|
func (container *container) Start() error {
|
2019-09-30 23:25:17 +00:00
|
|
|
return convertSystemError(container.system.Start(context.Background()), container)
|
2019-01-12 04:58:27 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
// Shutdown requests a container shutdown, but it may not actually be shutdown until Wait() succeeds.
|
|
|
|
func (container *container) Shutdown() error {
|
2019-09-30 23:25:17 +00:00
|
|
|
err := container.system.Shutdown(context.Background())
|
|
|
|
if err != nil {
|
|
|
|
return convertSystemError(err, container)
|
|
|
|
}
|
|
|
|
return &ContainerError{Container: container, Err: ErrVmcomputeOperationPending, Operation: "hcsshim::ComputeSystem::Shutdown"}
|
2019-01-12 04:58:27 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
// Terminate requests a container terminate, but it may not actually be terminated until Wait() succeeds.
|
|
|
|
func (container *container) Terminate() error {
|
2019-09-30 23:25:17 +00:00
|
|
|
err := container.system.Terminate(context.Background())
|
|
|
|
if err != nil {
|
|
|
|
return convertSystemError(err, container)
|
|
|
|
}
|
|
|
|
return &ContainerError{Container: container, Err: ErrVmcomputeOperationPending, Operation: "hcsshim::ComputeSystem::Terminate"}
|
2019-01-12 04:58:27 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
// Waits synchronously waits for the container to shutdown or terminate.
|
|
|
|
func (container *container) Wait() error {
|
2019-09-30 23:25:17 +00:00
|
|
|
err := container.system.Wait()
|
|
|
|
if err == nil {
|
|
|
|
err = container.system.ExitError()
|
|
|
|
}
|
|
|
|
return convertSystemError(err, container)
|
2019-01-12 04:58:27 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
// WaitTimeout synchronously waits for the container to terminate or the duration to elapse. It
|
|
|
|
// returns false if timeout occurs.
|
2019-09-30 23:25:17 +00:00
|
|
|
func (container *container) WaitTimeout(timeout time.Duration) error {
|
|
|
|
container.waitOnce.Do(func() {
|
|
|
|
container.waitCh = make(chan struct{})
|
|
|
|
go func() {
|
|
|
|
container.waitErr = container.Wait()
|
|
|
|
close(container.waitCh)
|
|
|
|
}()
|
|
|
|
})
|
|
|
|
t := time.NewTimer(timeout)
|
|
|
|
defer t.Stop()
|
|
|
|
select {
|
|
|
|
case <-t.C:
|
|
|
|
return &ContainerError{Container: container, Err: ErrTimeout, Operation: "hcsshim::ComputeSystem::Wait"}
|
|
|
|
case <-container.waitCh:
|
|
|
|
return container.waitErr
|
|
|
|
}
|
2019-01-12 04:58:27 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
// Pause pauses the execution of a container.
|
|
|
|
func (container *container) Pause() error {
|
2019-09-30 23:25:17 +00:00
|
|
|
return convertSystemError(container.system.Pause(context.Background()), container)
|
2019-01-12 04:58:27 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
// Resume resumes the execution of a container.
|
|
|
|
func (container *container) Resume() error {
|
2019-09-30 23:25:17 +00:00
|
|
|
return convertSystemError(container.system.Resume(context.Background()), container)
|
2019-01-12 04:58:27 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
// HasPendingUpdates returns true if the container has updates pending to install
|
|
|
|
func (container *container) HasPendingUpdates() (bool, error) {
|
|
|
|
return false, nil
|
|
|
|
}
|
|
|
|
|
|
|
|
// Statistics returns statistics for the container. This is a legacy v1 call
|
|
|
|
func (container *container) Statistics() (Statistics, error) {
|
2019-09-30 23:25:17 +00:00
|
|
|
properties, err := container.system.Properties(context.Background(), schema1.PropertyTypeStatistics)
|
2019-01-12 04:58:27 +00:00
|
|
|
if err != nil {
|
|
|
|
return Statistics{}, convertSystemError(err, container)
|
|
|
|
}
|
|
|
|
|
|
|
|
return properties.Statistics, nil
|
|
|
|
}
|
|
|
|
|
|
|
|
// ProcessList returns an array of ProcessListItems for the container. This is a legacy v1 call
|
|
|
|
func (container *container) ProcessList() ([]ProcessListItem, error) {
|
2019-09-30 23:25:17 +00:00
|
|
|
properties, err := container.system.Properties(context.Background(), schema1.PropertyTypeProcessList)
|
2019-01-12 04:58:27 +00:00
|
|
|
if err != nil {
|
|
|
|
return nil, convertSystemError(err, container)
|
|
|
|
}
|
|
|
|
|
|
|
|
return properties.ProcessList, nil
|
|
|
|
}
|
|
|
|
|
|
|
|
// This is a legacy v1 call
|
|
|
|
func (container *container) MappedVirtualDisks() (map[int]MappedVirtualDiskController, error) {
|
2019-09-30 23:25:17 +00:00
|
|
|
properties, err := container.system.Properties(context.Background(), schema1.PropertyTypeMappedVirtualDisk)
|
2019-01-12 04:58:27 +00:00
|
|
|
if err != nil {
|
|
|
|
return nil, convertSystemError(err, container)
|
|
|
|
}
|
|
|
|
|
|
|
|
return properties.MappedVirtualDiskControllers, nil
|
|
|
|
}
|
|
|
|
|
|
|
|
// CreateProcess launches a new process within the container.
|
|
|
|
func (container *container) CreateProcess(c *ProcessConfig) (Process, error) {
|
2020-08-10 17:43:49 +00:00
|
|
|
p, err := container.system.CreateProcess(context.Background(), c)
|
2019-01-12 04:58:27 +00:00
|
|
|
if err != nil {
|
|
|
|
return nil, convertSystemError(err, container)
|
|
|
|
}
|
2019-09-30 23:25:17 +00:00
|
|
|
return &process{p: p.(*hcs.Process)}, nil
|
2019-01-12 04:58:27 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
// OpenProcess gets an interface to an existing process within the container.
|
|
|
|
func (container *container) OpenProcess(pid int) (Process, error) {
|
2019-09-30 23:25:17 +00:00
|
|
|
p, err := container.system.OpenProcess(context.Background(), pid)
|
2019-01-12 04:58:27 +00:00
|
|
|
if err != nil {
|
|
|
|
return nil, convertSystemError(err, container)
|
|
|
|
}
|
2019-09-30 23:25:17 +00:00
|
|
|
return &process{p: p}, nil
|
2019-01-12 04:58:27 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
// Close cleans up any state associated with the container but does not terminate or wait for it.
|
|
|
|
func (container *container) Close() error {
|
|
|
|
return convertSystemError(container.system.Close(), container)
|
|
|
|
}
|
|
|
|
|
|
|
|
// Modify the System
|
|
|
|
func (container *container) Modify(config *ResourceModificationRequestResponse) error {
|
2019-09-30 23:25:17 +00:00
|
|
|
return convertSystemError(container.system.Modify(context.Background(), config), container)
|
2019-01-12 04:58:27 +00:00
|
|
|
}
|