gitee.com/leisunstar/runtime@v0.0.0-20200521203717-5cef3e7b53f9/virtcontainers/types/sandbox.go (about) 1 // Copyright (c) 2018 Intel Corporation 2 // 3 // SPDX-License-Identifier: Apache-2.0 4 // 5 6 package types 7 8 import ( 9 "fmt" 10 "os" 11 "strings" 12 13 "github.com/opencontainers/runtime-spec/specs-go" 14 ) 15 16 // StateString is a string representing a sandbox state. 17 type StateString string 18 19 const ( 20 // StateReady represents a sandbox/container that's ready to be run 21 StateReady StateString = "ready" 22 23 // StateRunning represents a sandbox/container that's currently running. 24 StateRunning StateString = "running" 25 26 // StatePaused represents a sandbox/container that has been paused. 27 StatePaused StateString = "paused" 28 29 // StateStopped represents a sandbox/container that has been stopped. 30 StateStopped StateString = "stopped" 31 ) 32 33 const ( 34 HybridVSockScheme = "hvsock" 35 VSockScheme = "vsock" 36 ) 37 38 // SandboxState is a sandbox state structure 39 type SandboxState struct { 40 State StateString `json:"state"` 41 42 // Index map of the block device passed to hypervisor. 43 BlockIndexMap map[int]struct{} `json:"blockIndexMap"` 44 45 // GuestMemoryBlockSizeMB is the size of memory block of guestos 46 GuestMemoryBlockSizeMB uint32 `json:"guestMemoryBlockSize"` 47 48 // GuestMemoryHotplugProbe determines whether guest kernel supports memory hotplug probe interface 49 GuestMemoryHotplugProbe bool `json:"guestMemoryHotplugProbe"` 50 51 // CgroupPath is the cgroup hierarchy where sandbox's processes 52 // including the hypervisor are placed. 53 CgroupPath string `json:"cgroupPath,omitempty"` 54 55 // Path to all the cgroups setup for a container. Key is cgroup subsystem name 56 // with the value as the path. 57 CgroupPaths map[string]string `json:"cgroupPaths"` 58 59 // PersistVersion indicates current storage api version. 60 // It's also known as ABI version of kata-runtime. 61 // Note: it won't be written to disk 62 PersistVersion uint `json:"-"` 63 } 64 65 // Valid checks that the sandbox state is valid. 66 func (state *SandboxState) Valid() bool { 67 return state.State.valid() 68 } 69 70 // ValidTransition returns an error if we want to move to 71 // an unreachable state. 72 func (state *SandboxState) ValidTransition(oldState StateString, newState StateString) error { 73 return state.State.validTransition(oldState, newState) 74 } 75 76 func (state *StateString) valid() bool { 77 for _, validState := range []StateString{StateReady, StateRunning, StatePaused, StateStopped} { 78 if *state == validState { 79 return true 80 } 81 } 82 83 return false 84 } 85 86 func (state *StateString) validTransition(oldState StateString, newState StateString) error { 87 if *state != oldState { 88 return fmt.Errorf("Invalid state %v (Expecting %v)", state, oldState) 89 } 90 91 switch *state { 92 case StateReady: 93 if newState == StateRunning || newState == StateStopped { 94 return nil 95 } 96 97 case StateRunning: 98 if newState == StatePaused || newState == StateStopped { 99 return nil 100 } 101 102 case StatePaused: 103 if newState == StateRunning || newState == StateStopped { 104 return nil 105 } 106 107 case StateStopped: 108 if newState == StateRunning { 109 return nil 110 } 111 } 112 113 return fmt.Errorf("Can not move from %v to %v", 114 state, newState) 115 } 116 117 // Volume is a shared volume between the host and the VM, 118 // defined by its mount tag and its host path. 119 type Volume struct { 120 // MountTag is a label used as a hint to the guest. 121 MountTag string 122 123 // HostPath is the host filesystem path for this volume. 124 HostPath string 125 } 126 127 // Volumes is a Volume list. 128 type Volumes []Volume 129 130 // Set assigns volume values from string to a Volume. 131 func (v *Volumes) Set(volStr string) error { 132 if volStr == "" { 133 return fmt.Errorf("volStr cannot be empty") 134 } 135 136 volSlice := strings.Split(volStr, " ") 137 const expectedVolLen = 2 138 const volDelimiter = ":" 139 140 for _, vol := range volSlice { 141 volArgs := strings.Split(vol, volDelimiter) 142 143 if len(volArgs) != expectedVolLen { 144 return fmt.Errorf("Wrong string format: %s, expecting only %v parameters separated with %q", 145 vol, expectedVolLen, volDelimiter) 146 } 147 148 if volArgs[0] == "" || volArgs[1] == "" { 149 return fmt.Errorf("Volume parameters cannot be empty") 150 } 151 152 volume := Volume{ 153 MountTag: volArgs[0], 154 HostPath: volArgs[1], 155 } 156 157 *v = append(*v, volume) 158 } 159 160 return nil 161 } 162 163 // String converts a Volume to a string. 164 func (v *Volumes) String() string { 165 var volSlice []string 166 167 for _, volume := range *v { 168 volSlice = append(volSlice, fmt.Sprintf("%s:%s", volume.MountTag, volume.HostPath)) 169 } 170 171 return strings.Join(volSlice, " ") 172 } 173 174 // VSock defines a virtio-socket to communicate between 175 // the host and any process inside the VM. 176 // This kind of socket is not supported in all hypervisors. 177 type VSock struct { 178 ContextID uint64 179 Port uint32 180 VhostFd *os.File 181 } 182 183 func (s *VSock) String() string { 184 return fmt.Sprintf("%s://%d:%d", VSockScheme, s.ContextID, s.Port) 185 } 186 187 // HybridVSock defines a hybrid vsocket to communicate between 188 // the host and any process inside the VM. 189 // This is a virtio-vsock implementation based on AF_VSOCK on the 190 // guest side and multiple AF_UNIX sockets on the host side. 191 // This kind of socket is not supported in all hypervisors. 192 // Firecracker supports it. 193 type HybridVSock struct { 194 UdsPath string 195 ContextID uint64 196 Port uint32 197 } 198 199 func (s *HybridVSock) String() string { 200 return fmt.Sprintf("%s://%s:%d", HybridVSockScheme, s.UdsPath, s.Port) 201 } 202 203 // Socket defines a socket to communicate between 204 // the host and any process inside the VM. 205 type Socket struct { 206 DeviceID string 207 ID string 208 HostPath string 209 Name string 210 } 211 212 // Sockets is a Socket list. 213 type Sockets []Socket 214 215 // Set assigns socket values from string to a Socket. 216 func (s *Sockets) Set(sockStr string) error { 217 if sockStr == "" { 218 return fmt.Errorf("sockStr cannot be empty") 219 } 220 221 sockSlice := strings.Split(sockStr, " ") 222 const expectedSockCount = 4 223 const sockDelimiter = ":" 224 225 for _, sock := range sockSlice { 226 sockArgs := strings.Split(sock, sockDelimiter) 227 228 if len(sockArgs) != expectedSockCount { 229 return fmt.Errorf("Wrong string format: %s, expecting only %v parameters separated with %q", sock, expectedSockCount, sockDelimiter) 230 } 231 232 for _, a := range sockArgs { 233 if a == "" { 234 return fmt.Errorf("Socket parameters cannot be empty") 235 } 236 } 237 238 socket := Socket{ 239 DeviceID: sockArgs[0], 240 ID: sockArgs[1], 241 HostPath: sockArgs[2], 242 Name: sockArgs[3], 243 } 244 245 *s = append(*s, socket) 246 } 247 248 return nil 249 } 250 251 // String converts a Socket to a string. 252 func (s *Sockets) String() string { 253 var sockSlice []string 254 255 for _, sock := range *s { 256 sockSlice = append(sockSlice, fmt.Sprintf("%s:%s:%s:%s", sock.DeviceID, sock.ID, sock.HostPath, sock.Name)) 257 } 258 259 return strings.Join(sockSlice, " ") 260 } 261 262 // EnvVar is a key/value structure representing a command 263 // environment variable. 264 type EnvVar struct { 265 Var string 266 Value string 267 } 268 269 // Cmd represents a command to execute in a running container. 270 type Cmd struct { 271 Args []string 272 Envs []EnvVar 273 SupplementaryGroups []string 274 275 // Note that these fields *MUST* remain as strings. 276 // 277 // The reason being that we want runtimes to be able to support CLI 278 // operations like "exec --user=". That option allows the 279 // specification of a user (either as a string username or a numeric 280 // UID), and may optionally also include a group (groupame or GID). 281 // 282 // Since this type is the interface to allow the runtime to specify 283 // the user and group the workload can run as, these user and group 284 // fields cannot be encoded as integer values since that would imply 285 // the runtime itself would need to perform a UID/GID lookup on the 286 // user-specified username/groupname. But that isn't practically 287 // possible given that to do so would require the runtime to access 288 // the image to allow it to interrogate the appropriate databases to 289 // convert the username/groupnames to UID/GID values. 290 // 291 // Note that this argument applies solely to the _runtime_ supporting 292 // a "--user=" option when running in a "standalone mode" - there is 293 // no issue when the runtime is called by a container manager since 294 // all the user and group mapping is handled by the container manager 295 // and specified to the runtime in terms of UID/GID's in the 296 // configuration file generated by the container manager. 297 User string 298 PrimaryGroup string 299 WorkDir string 300 Console string 301 Capabilities *specs.LinuxCapabilities 302 303 Interactive bool 304 Detach bool 305 NoNewPrivileges bool 306 } 307 308 // Resources describes VM resources configuration. 309 type Resources struct { 310 // Memory is the amount of available memory in MiB. 311 Memory uint 312 MemorySlots uint8 313 }