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  }