// Copyright (c) 2018 Intel Corporation // // SPDX-License-Identifier: Apache-2.0 // package types import ( "fmt" "strings" ) // StateString is a string representing a sandbox state. type StateString string const ( // StateReady represents a sandbox/container that's ready to be run StateReady StateString = "ready" // StateRunning represents a sandbox/container that's currently running. StateRunning StateString = "running" // StatePaused represents a sandbox/container that has been paused. StatePaused StateString = "paused" // StateStopped represents a sandbox/container that has been stopped. StateStopped StateString = "stopped" ) // State is a sandbox state structure. type State struct { State StateString `json:"state"` BlockDeviceID string // Index of the block device passed to hypervisor. BlockIndex int `json:"blockIndex"` // File system of the rootfs incase it is block device Fstype string `json:"fstype"` // Pid is the process id of the sandbox container which is the first // container to be started. Pid int `json:"pid"` // GuestMemoryBlockSizeMB is the size of memory block of guestos GuestMemoryBlockSizeMB uint32 `json:"guestMemoryBlockSize"` } // Valid checks that the sandbox state is valid. func (state *State) Valid() bool { for _, validState := range []StateString{StateReady, StateRunning, StatePaused, StateStopped} { if state.State == validState { return true } } return false } // ValidTransition returns an error if we want to move to // an unreachable state. func (state *State) ValidTransition(oldState StateString, newState StateString) error { if state.State != oldState { return fmt.Errorf("Invalid state %s (Expecting %s)", state.State, oldState) } switch state.State { case StateReady: if newState == StateRunning || newState == StateStopped { return nil } case StateRunning: if newState == StatePaused || newState == StateStopped { return nil } case StatePaused: if newState == StateRunning || newState == StateStopped { return nil } case StateStopped: if newState == StateRunning { return nil } } return fmt.Errorf("Can not move from %s to %s", state.State, newState) } // Volume is a shared volume between the host and the VM, // defined by its mount tag and its host path. type Volume struct { // MountTag is a label used as a hint to the guest. MountTag string // HostPath is the host filesystem path for this volume. HostPath string } // Volumes is a Volume list. type Volumes []Volume // Set assigns volume values from string to a Volume. func (v *Volumes) Set(volStr string) error { if volStr == "" { return fmt.Errorf("volStr cannot be empty") } volSlice := strings.Split(volStr, " ") const expectedVolLen = 2 const volDelimiter = ":" for _, vol := range volSlice { volArgs := strings.Split(vol, volDelimiter) if len(volArgs) != expectedVolLen { return fmt.Errorf("Wrong string format: %s, expecting only %v parameters separated with %q", vol, expectedVolLen, volDelimiter) } if volArgs[0] == "" || volArgs[1] == "" { return fmt.Errorf("Volume parameters cannot be empty") } volume := Volume{ MountTag: volArgs[0], HostPath: volArgs[1], } *v = append(*v, volume) } return nil } // String converts a Volume to a string. func (v *Volumes) String() string { var volSlice []string for _, volume := range *v { volSlice = append(volSlice, fmt.Sprintf("%s:%s", volume.MountTag, volume.HostPath)) } return strings.Join(volSlice, " ") } // Socket defines a socket to communicate between // the host and any process inside the VM. type Socket struct { DeviceID string ID string HostPath string Name string } // Sockets is a Socket list. type Sockets []Socket // Set assigns socket values from string to a Socket. func (s *Sockets) Set(sockStr string) error { if sockStr == "" { return fmt.Errorf("sockStr cannot be empty") } sockSlice := strings.Split(sockStr, " ") const expectedSockCount = 4 const sockDelimiter = ":" for _, sock := range sockSlice { sockArgs := strings.Split(sock, sockDelimiter) if len(sockArgs) != expectedSockCount { return fmt.Errorf("Wrong string format: %s, expecting only %v parameters separated with %q", sock, expectedSockCount, sockDelimiter) } for _, a := range sockArgs { if a == "" { return fmt.Errorf("Socket parameters cannot be empty") } } socket := Socket{ DeviceID: sockArgs[0], ID: sockArgs[1], HostPath: sockArgs[2], Name: sockArgs[3], } *s = append(*s, socket) } return nil } // String converts a Socket to a string. func (s *Sockets) String() string { var sockSlice []string for _, sock := range *s { sockSlice = append(sockSlice, fmt.Sprintf("%s:%s:%s:%s", sock.DeviceID, sock.ID, sock.HostPath, sock.Name)) } return strings.Join(sockSlice, " ") } // EnvVar is a key/value structure representing a command // environment variable. type EnvVar struct { Var string Value string } // LinuxCapabilities specify the capabilities to keep when executing // the process inside the container. type LinuxCapabilities struct { // Bounding is the set of capabilities checked by the kernel. Bounding []string // Effective is the set of capabilities checked by the kernel. Effective []string // Inheritable is the capabilities preserved across execve. Inheritable []string // Permitted is the limiting superset for effective capabilities. Permitted []string // Ambient is the ambient set of capabilities that are kept. Ambient []string } // Cmd represents a command to execute in a running container. type Cmd struct { Args []string Envs []EnvVar SupplementaryGroups []string // Note that these fields *MUST* remain as strings. // // The reason being that we want runtimes to be able to support CLI // operations like "exec --user=". That option allows the // specification of a user (either as a string username or a numeric // UID), and may optionally also include a group (groupame or GID). // // Since this type is the interface to allow the runtime to specify // the user and group the workload can run as, these user and group // fields cannot be encoded as integer values since that would imply // the runtime itself would need to perform a UID/GID lookup on the // user-specified username/groupname. But that isn't practically // possible given that to do so would require the runtime to access // the image to allow it to interrogate the appropriate databases to // convert the username/groupnames to UID/GID values. // // Note that this argument applies solely to the _runtime_ supporting // a "--user=" option when running in a "standalone mode" - there is // no issue when the runtime is called by a container manager since // all the user and group mapping is handled by the container manager // and specified to the runtime in terms of UID/GID's in the // configuration file generated by the container manager. User string PrimaryGroup string WorkDir string Console string Capabilities LinuxCapabilities Interactive bool Detach bool NoNewPrivileges bool } // Resources describes VM resources configuration. type Resources struct { // Memory is the amount of available memory in MiB. Memory uint MemorySlots uint8 }