github.com/kata-containers/runtime@v0.0.0-20210505125100-04f29832a923/virtcontainers/api.go (about)

     1  // Copyright (c) 2016 Intel Corporation
     2  //
     3  // SPDX-License-Identifier: Apache-2.0
     4  //
     5  
     6  package virtcontainers
     7  
     8  import (
     9  	"context"
    10  	"os"
    11  	"runtime"
    12  	"syscall"
    13  
    14  	deviceApi "github.com/kata-containers/runtime/virtcontainers/device/api"
    15  	deviceConfig "github.com/kata-containers/runtime/virtcontainers/device/config"
    16  	"github.com/kata-containers/runtime/virtcontainers/persist"
    17  	"github.com/kata-containers/runtime/virtcontainers/pkg/cgroups"
    18  	"github.com/kata-containers/runtime/virtcontainers/pkg/compatoci"
    19  	vcTypes "github.com/kata-containers/runtime/virtcontainers/pkg/types"
    20  	"github.com/kata-containers/runtime/virtcontainers/store"
    21  	"github.com/kata-containers/runtime/virtcontainers/types"
    22  	specs "github.com/opencontainers/runtime-spec/specs-go"
    23  	opentracing "github.com/opentracing/opentracing-go"
    24  	"github.com/sirupsen/logrus"
    25  )
    26  
    27  func init() {
    28  	runtime.LockOSThread()
    29  }
    30  
    31  var virtLog = logrus.WithField("source", "virtcontainers")
    32  
    33  // trace creates a new tracing span based on the specified name and parent
    34  // context.
    35  func trace(parent context.Context, name string) (opentracing.Span, context.Context) {
    36  	span, ctx := opentracing.StartSpanFromContext(parent, name)
    37  
    38  	// Should not need to be changed (again).
    39  	span.SetTag("source", "virtcontainers")
    40  	span.SetTag("component", "virtcontainers")
    41  
    42  	// Should be reset as new subsystems are entered.
    43  	span.SetTag("subsystem", "api")
    44  
    45  	return span, ctx
    46  }
    47  
    48  // SetLogger sets the logger for virtcontainers package.
    49  func SetLogger(ctx context.Context, logger *logrus.Entry) {
    50  	fields := virtLog.Data
    51  	virtLog = logger.WithFields(fields)
    52  
    53  	deviceApi.SetLogger(virtLog)
    54  	compatoci.SetLogger(virtLog)
    55  	store.SetLogger(virtLog)
    56  	deviceConfig.SetLogger(virtLog)
    57  	cgroups.SetLogger(virtLog)
    58  }
    59  
    60  // CreateSandbox is the virtcontainers sandbox creation entry point.
    61  // CreateSandbox creates a sandbox and its containers. It does not start them.
    62  func CreateSandbox(ctx context.Context, sandboxConfig SandboxConfig, factory Factory) (VCSandbox, error) {
    63  	span, ctx := trace(ctx, "CreateSandbox")
    64  	defer span.Finish()
    65  
    66  	s, err := createSandboxFromConfig(ctx, sandboxConfig, factory)
    67  	if err == nil {
    68  		s.releaseStatelessSandbox()
    69  	}
    70  
    71  	return s, err
    72  }
    73  
    74  func createSandboxFromConfig(ctx context.Context, sandboxConfig SandboxConfig, factory Factory) (_ *Sandbox, err error) {
    75  	span, ctx := trace(ctx, "createSandboxFromConfig")
    76  	defer span.Finish()
    77  
    78  	// Create the sandbox.
    79  	s, err := createSandbox(ctx, sandboxConfig, factory)
    80  	if err != nil {
    81  		return nil, err
    82  	}
    83  
    84  	// cleanup sandbox resources in case of any failure
    85  	defer func() {
    86  		if err != nil {
    87  			s.Delete()
    88  		}
    89  	}()
    90  
    91  	// Create the sandbox network
    92  	if err = s.createNetwork(); err != nil {
    93  		return nil, err
    94  	}
    95  
    96  	// network rollback
    97  	defer func() {
    98  		if err != nil {
    99  			s.removeNetwork()
   100  		}
   101  	}()
   102  
   103  	// Move runtime to sandbox cgroup so all process are created there.
   104  	if s.config.SandboxCgroupOnly {
   105  		if err := s.createCgroupManager(); err != nil {
   106  			return nil, err
   107  		}
   108  
   109  		if err := s.setupSandboxCgroup(); err != nil {
   110  			return nil, err
   111  		}
   112  	}
   113  
   114  	// Start the VM
   115  	if err = s.startVM(); err != nil {
   116  		return nil, err
   117  	}
   118  
   119  	// rollback to stop VM if error occurs
   120  	defer func() {
   121  		if err != nil {
   122  			s.stopVM()
   123  		}
   124  	}()
   125  
   126  	s.postCreatedNetwork()
   127  
   128  	if err = s.getAndStoreGuestDetails(); err != nil {
   129  		return nil, err
   130  	}
   131  
   132  	// Create Containers
   133  	if err = s.createContainers(); err != nil {
   134  		return nil, err
   135  	}
   136  
   137  	// The sandbox is completely created now, we can store it.
   138  	if err = s.storeSandbox(); err != nil {
   139  		return nil, err
   140  	}
   141  
   142  	return s, nil
   143  }
   144  
   145  // DeleteSandbox is the virtcontainers sandbox deletion entry point.
   146  // DeleteSandbox will stop an already running container and then delete it.
   147  func DeleteSandbox(ctx context.Context, sandboxID string) (VCSandbox, error) {
   148  	span, ctx := trace(ctx, "DeleteSandbox")
   149  	defer span.Finish()
   150  
   151  	if sandboxID == "" {
   152  		return nil, vcTypes.ErrNeedSandboxID
   153  	}
   154  
   155  	unlock, err := rwLockSandbox(sandboxID)
   156  	if err != nil {
   157  		return nil, err
   158  	}
   159  	defer unlock()
   160  
   161  	// Fetch the sandbox from storage and create it.
   162  	s, err := fetchSandbox(ctx, sandboxID)
   163  	if err != nil {
   164  		return nil, err
   165  	}
   166  	defer s.releaseStatelessSandbox()
   167  
   168  	// Delete it.
   169  	if err := s.Delete(); err != nil {
   170  		return nil, err
   171  	}
   172  
   173  	return s, nil
   174  }
   175  
   176  // FetchSandbox is the virtcontainers sandbox fetching entry point.
   177  // FetchSandbox will find out and connect to an existing sandbox and
   178  // return the sandbox structure. The caller is responsible of calling
   179  // VCSandbox.Release() after done with it.
   180  func FetchSandbox(ctx context.Context, sandboxID string) (VCSandbox, error) {
   181  	span, ctx := trace(ctx, "FetchSandbox")
   182  	defer span.Finish()
   183  
   184  	if sandboxID == "" {
   185  		return nil, vcTypes.ErrNeedSandboxID
   186  	}
   187  
   188  	unlock, err := rwLockSandbox(sandboxID)
   189  	if err != nil {
   190  		return nil, err
   191  	}
   192  	defer unlock()
   193  
   194  	// Fetch the sandbox from storage and create it.
   195  	s, err := fetchSandbox(ctx, sandboxID)
   196  	if err != nil {
   197  		return nil, err
   198  	}
   199  
   200  	// If the agent is long live connection, it needs to restart the proxy to
   201  	// watch the guest console if it hadn't been watched.
   202  	if s.agent.longLiveConn() {
   203  		err = s.startProxy()
   204  		if err != nil {
   205  			s.Release()
   206  			return nil, err
   207  		}
   208  	}
   209  
   210  	return s, nil
   211  }
   212  
   213  // StartSandbox is the virtcontainers sandbox starting entry point.
   214  // StartSandbox will talk to the given hypervisor to start an existing
   215  // sandbox and all its containers.
   216  // It returns the sandbox ID.
   217  func StartSandbox(ctx context.Context, sandboxID string) (VCSandbox, error) {
   218  	span, ctx := trace(ctx, "StartSandbox")
   219  	defer span.Finish()
   220  
   221  	if sandboxID == "" {
   222  		return nil, vcTypes.ErrNeedSandboxID
   223  	}
   224  
   225  	unlock, err := rwLockSandbox(sandboxID)
   226  	if err != nil {
   227  		return nil, err
   228  	}
   229  	defer unlock()
   230  
   231  	// Fetch the sandbox from storage and create it.
   232  	s, err := fetchSandbox(ctx, sandboxID)
   233  	if err != nil {
   234  		return nil, err
   235  	}
   236  	defer s.releaseStatelessSandbox()
   237  
   238  	// Start it
   239  	err = s.Start()
   240  	if err != nil {
   241  		return nil, err
   242  	}
   243  
   244  	if err = s.storeSandbox(); err != nil {
   245  		return nil, err
   246  	}
   247  
   248  	return s, nil
   249  }
   250  
   251  // StopSandbox is the virtcontainers sandbox stopping entry point.
   252  // StopSandbox will talk to the given agent to stop an existing sandbox and destroy all containers within that sandbox.
   253  func StopSandbox(ctx context.Context, sandboxID string, force bool) (VCSandbox, error) {
   254  	span, ctx := trace(ctx, "StopSandbox")
   255  	defer span.Finish()
   256  
   257  	if sandboxID == "" {
   258  		return nil, vcTypes.ErrNeedSandbox
   259  	}
   260  
   261  	unlock, err := rwLockSandbox(sandboxID)
   262  	if err != nil {
   263  		return nil, err
   264  	}
   265  	defer unlock()
   266  
   267  	// Fetch the sandbox from storage and create it.
   268  	s, err := fetchSandbox(ctx, sandboxID)
   269  	if err != nil {
   270  		return nil, err
   271  	}
   272  	defer s.releaseStatelessSandbox()
   273  
   274  	// Stop it.
   275  	err = s.Stop(force)
   276  	if err != nil {
   277  		return nil, err
   278  	}
   279  
   280  	if err = s.storeSandbox(); err != nil {
   281  		return nil, err
   282  	}
   283  
   284  	return s, nil
   285  }
   286  
   287  // RunSandbox is the virtcontainers sandbox running entry point.
   288  // RunSandbox creates a sandbox and its containers and then it starts them.
   289  func RunSandbox(ctx context.Context, sandboxConfig SandboxConfig, factory Factory) (VCSandbox, error) {
   290  	span, ctx := trace(ctx, "RunSandbox")
   291  	defer span.Finish()
   292  
   293  	// Create the sandbox
   294  	s, err := createSandboxFromConfig(ctx, sandboxConfig, factory)
   295  	if err != nil {
   296  		return nil, err
   297  	}
   298  	defer s.releaseStatelessSandbox()
   299  
   300  	unlock, err := rwLockSandbox(s.id)
   301  	if err != nil {
   302  		return nil, err
   303  	}
   304  	defer unlock()
   305  
   306  	// Start the sandbox
   307  	err = s.Start()
   308  	if err != nil {
   309  		return nil, err
   310  	}
   311  
   312  	return s, nil
   313  }
   314  
   315  // ListSandbox is the virtcontainers sandbox listing entry point.
   316  func ListSandbox(ctx context.Context) ([]SandboxStatus, error) {
   317  	span, ctx := trace(ctx, "ListSandbox")
   318  	defer span.Finish()
   319  
   320  	store, err := persist.GetDriver()
   321  	if err != nil {
   322  		return []SandboxStatus{}, err
   323  	}
   324  
   325  	dir, err := os.Open(store.RunStoragePath())
   326  	if err != nil {
   327  		if os.IsNotExist(err) {
   328  			// No sandbox directory is not an error
   329  			return []SandboxStatus{}, nil
   330  		}
   331  		return []SandboxStatus{}, err
   332  	}
   333  
   334  	defer dir.Close()
   335  
   336  	sandboxesID, err := dir.Readdirnames(0)
   337  	if err != nil {
   338  		return []SandboxStatus{}, err
   339  	}
   340  
   341  	var sandboxStatusList []SandboxStatus
   342  
   343  	for _, sandboxID := range sandboxesID {
   344  		sandboxStatus, err := StatusSandbox(ctx, sandboxID)
   345  		if err != nil {
   346  			continue
   347  		}
   348  
   349  		sandboxStatusList = append(sandboxStatusList, sandboxStatus)
   350  	}
   351  
   352  	return sandboxStatusList, nil
   353  }
   354  
   355  // StatusSandbox is the virtcontainers sandbox status entry point.
   356  func StatusSandbox(ctx context.Context, sandboxID string) (SandboxStatus, error) {
   357  	span, ctx := trace(ctx, "StatusSandbox")
   358  	defer span.Finish()
   359  
   360  	if sandboxID == "" {
   361  		return SandboxStatus{}, vcTypes.ErrNeedSandboxID
   362  	}
   363  
   364  	unlock, err := rwLockSandbox(sandboxID)
   365  	if err != nil {
   366  		return SandboxStatus{}, err
   367  	}
   368  	defer unlock()
   369  
   370  	s, err := fetchSandbox(ctx, sandboxID)
   371  	if err != nil {
   372  		return SandboxStatus{}, err
   373  	}
   374  	defer s.releaseStatelessSandbox()
   375  
   376  	var contStatusList []ContainerStatus
   377  	for _, container := range s.containers {
   378  		contStatus, err := statusContainer(s, container.id)
   379  		if err != nil {
   380  			return SandboxStatus{}, err
   381  		}
   382  
   383  		contStatusList = append(contStatusList, contStatus)
   384  	}
   385  
   386  	sandboxStatus := SandboxStatus{
   387  		ID:               s.id,
   388  		State:            s.state,
   389  		Hypervisor:       s.config.HypervisorType,
   390  		HypervisorConfig: s.config.HypervisorConfig,
   391  		Agent:            s.config.AgentType,
   392  		ContainersStatus: contStatusList,
   393  		Annotations:      s.config.Annotations,
   394  	}
   395  
   396  	return sandboxStatus, nil
   397  }
   398  
   399  // CreateContainer is the virtcontainers container creation entry point.
   400  // CreateContainer creates a container on a given sandbox.
   401  func CreateContainer(ctx context.Context, sandboxID string, containerConfig ContainerConfig) (VCSandbox, VCContainer, error) {
   402  	span, ctx := trace(ctx, "CreateContainer")
   403  	defer span.Finish()
   404  
   405  	if sandboxID == "" {
   406  		return nil, nil, vcTypes.ErrNeedSandboxID
   407  	}
   408  
   409  	unlock, err := rwLockSandbox(sandboxID)
   410  	if err != nil {
   411  		return nil, nil, err
   412  	}
   413  	defer unlock()
   414  
   415  	s, err := fetchSandbox(ctx, sandboxID)
   416  	if err != nil {
   417  		return nil, nil, err
   418  	}
   419  	defer s.releaseStatelessSandbox()
   420  
   421  	c, err := s.CreateContainer(containerConfig)
   422  	if err != nil {
   423  		return nil, nil, err
   424  	}
   425  
   426  	if err = s.storeSandbox(); err != nil {
   427  		return nil, nil, err
   428  	}
   429  
   430  	return s, c, nil
   431  }
   432  
   433  // DeleteContainer is the virtcontainers container deletion entry point.
   434  // DeleteContainer deletes a Container from a Sandbox. If the container is running,
   435  // it needs to be stopped first.
   436  func DeleteContainer(ctx context.Context, sandboxID, containerID string) (VCContainer, error) {
   437  	span, ctx := trace(ctx, "DeleteContainer")
   438  	defer span.Finish()
   439  
   440  	if sandboxID == "" {
   441  		return nil, vcTypes.ErrNeedSandboxID
   442  	}
   443  
   444  	if containerID == "" {
   445  		return nil, vcTypes.ErrNeedContainerID
   446  	}
   447  
   448  	unlock, err := rwLockSandbox(sandboxID)
   449  	if err != nil {
   450  		return nil, err
   451  	}
   452  	defer unlock()
   453  
   454  	s, err := fetchSandbox(ctx, sandboxID)
   455  	if err != nil {
   456  		return nil, err
   457  	}
   458  	defer s.releaseStatelessSandbox()
   459  
   460  	return s.DeleteContainer(containerID)
   461  }
   462  
   463  // StartContainer is the virtcontainers container starting entry point.
   464  // StartContainer starts an already created container.
   465  func StartContainer(ctx context.Context, sandboxID, containerID string) (VCContainer, error) {
   466  	span, ctx := trace(ctx, "StartContainer")
   467  	defer span.Finish()
   468  
   469  	if sandboxID == "" {
   470  		return nil, vcTypes.ErrNeedSandboxID
   471  	}
   472  
   473  	if containerID == "" {
   474  		return nil, vcTypes.ErrNeedContainerID
   475  	}
   476  
   477  	unlock, err := rwLockSandbox(sandboxID)
   478  	if err != nil {
   479  		return nil, err
   480  	}
   481  	defer unlock()
   482  
   483  	s, err := fetchSandbox(ctx, sandboxID)
   484  	if err != nil {
   485  		return nil, err
   486  	}
   487  	defer s.releaseStatelessSandbox()
   488  
   489  	return s.StartContainer(containerID)
   490  }
   491  
   492  // StopContainer is the virtcontainers container stopping entry point.
   493  // StopContainer stops an already running container.
   494  func StopContainer(ctx context.Context, sandboxID, containerID string) (VCContainer, error) {
   495  	span, ctx := trace(ctx, "StopContainer")
   496  	defer span.Finish()
   497  
   498  	if sandboxID == "" {
   499  		return nil, vcTypes.ErrNeedSandboxID
   500  	}
   501  
   502  	if containerID == "" {
   503  		return nil, vcTypes.ErrNeedContainerID
   504  	}
   505  
   506  	unlock, err := rwLockSandbox(sandboxID)
   507  	if err != nil {
   508  		return nil, err
   509  	}
   510  	defer unlock()
   511  
   512  	s, err := fetchSandbox(ctx, sandboxID)
   513  	if err != nil {
   514  		return nil, err
   515  	}
   516  	defer s.releaseStatelessSandbox()
   517  
   518  	return s.StopContainer(containerID, false)
   519  }
   520  
   521  // EnterContainer is the virtcontainers container command execution entry point.
   522  // EnterContainer enters an already running container and runs a given command.
   523  func EnterContainer(ctx context.Context, sandboxID, containerID string, cmd types.Cmd) (VCSandbox, VCContainer, *Process, error) {
   524  	span, ctx := trace(ctx, "EnterContainer")
   525  	defer span.Finish()
   526  
   527  	if sandboxID == "" {
   528  		return nil, nil, nil, vcTypes.ErrNeedSandboxID
   529  	}
   530  
   531  	if containerID == "" {
   532  		return nil, nil, nil, vcTypes.ErrNeedContainerID
   533  	}
   534  
   535  	unlock, err := rLockSandbox(sandboxID)
   536  	if err != nil {
   537  		return nil, nil, nil, err
   538  	}
   539  	defer unlock()
   540  
   541  	s, err := fetchSandbox(ctx, sandboxID)
   542  	if err != nil {
   543  		return nil, nil, nil, err
   544  	}
   545  	defer s.releaseStatelessSandbox()
   546  
   547  	c, process, err := s.EnterContainer(containerID, cmd)
   548  	if err != nil {
   549  		return nil, nil, nil, err
   550  	}
   551  
   552  	return s, c, process, nil
   553  }
   554  
   555  // StatusContainer is the virtcontainers container status entry point.
   556  // StatusContainer returns a detailed container status.
   557  func StatusContainer(ctx context.Context, sandboxID, containerID string) (ContainerStatus, error) {
   558  	span, ctx := trace(ctx, "StatusContainer")
   559  	defer span.Finish()
   560  
   561  	if sandboxID == "" {
   562  		return ContainerStatus{}, vcTypes.ErrNeedSandboxID
   563  	}
   564  
   565  	if containerID == "" {
   566  		return ContainerStatus{}, vcTypes.ErrNeedContainerID
   567  	}
   568  
   569  	unlock, err := rwLockSandbox(sandboxID)
   570  	if err != nil {
   571  		return ContainerStatus{}, err
   572  	}
   573  	defer unlock()
   574  
   575  	s, err := fetchSandbox(ctx, sandboxID)
   576  	if err != nil {
   577  		return ContainerStatus{}, err
   578  	}
   579  	defer s.releaseStatelessSandbox()
   580  
   581  	return statusContainer(s, containerID)
   582  }
   583  
   584  // This function might have to stop the container if it realizes the shim
   585  // process is not running anymore. This might be caused by two different
   586  // reasons, either the process inside the VM exited and the shim terminated
   587  // accordingly, or the shim has been killed directly and we need to make sure
   588  // that we properly stop the container process inside the VM.
   589  //
   590  // When a container needs to be stopped because of those reasons, we want this
   591  // to happen atomically from a sandbox perspective. That's why we cannot afford
   592  // to take a read or read/write lock based on the situation, as it would break
   593  // the initial locking from the caller. Instead, a read/write lock has to be
   594  // taken from the caller, even if we simply return the container status without
   595  // taking any action regarding the container.
   596  func statusContainer(sandbox *Sandbox, containerID string) (ContainerStatus, error) {
   597  	if container, ok := sandbox.containers[containerID]; ok {
   598  		// We have to check for the process state to make sure
   599  		// we update the status in case the process is supposed
   600  		// to be running but has been killed or terminated.
   601  		if (container.state.State == types.StateReady ||
   602  			container.state.State == types.StateRunning ||
   603  			container.state.State == types.StatePaused) &&
   604  			container.process.Pid > 0 {
   605  
   606  			running, err := isShimRunning(container.process.Pid)
   607  			if err != nil {
   608  				return ContainerStatus{}, err
   609  			}
   610  
   611  			if !running {
   612  				virtLog.WithFields(logrus.Fields{
   613  					"state": container.state.State,
   614  					"pid":   container.process.Pid}).
   615  					Info("container isn't running")
   616  				if err := container.stop(true); err != nil {
   617  					return ContainerStatus{}, err
   618  				}
   619  			}
   620  		}
   621  
   622  		return ContainerStatus{
   623  			ID:          container.id,
   624  			State:       container.state,
   625  			PID:         container.process.Pid,
   626  			StartTime:   container.process.StartTime,
   627  			RootFs:      container.config.RootFs.Target,
   628  			Spec:        container.GetPatchedOCISpec(),
   629  			Annotations: container.config.Annotations,
   630  		}, nil
   631  	}
   632  
   633  	// No matching containers in the sandbox
   634  	return ContainerStatus{}, nil
   635  }
   636  
   637  // KillContainer is the virtcontainers entry point to send a signal
   638  // to a container running inside a sandbox. If all is true, all processes in
   639  // the container will be sent the signal.
   640  func KillContainer(ctx context.Context, sandboxID, containerID string, signal syscall.Signal, all bool) error {
   641  	span, ctx := trace(ctx, "KillContainer")
   642  	defer span.Finish()
   643  
   644  	if sandboxID == "" {
   645  		return vcTypes.ErrNeedSandboxID
   646  	}
   647  
   648  	if containerID == "" {
   649  		return vcTypes.ErrNeedContainerID
   650  	}
   651  
   652  	unlock, err := rwLockSandbox(sandboxID)
   653  	if err != nil {
   654  		return err
   655  	}
   656  	defer unlock()
   657  
   658  	s, err := fetchSandbox(ctx, sandboxID)
   659  	if err != nil {
   660  		return err
   661  	}
   662  	defer s.releaseStatelessSandbox()
   663  
   664  	return s.KillContainer(containerID, signal, all)
   665  }
   666  
   667  // ProcessListContainer is the virtcontainers entry point to list
   668  // processes running inside a container
   669  func ProcessListContainer(ctx context.Context, sandboxID, containerID string, options ProcessListOptions) (ProcessList, error) {
   670  	span, ctx := trace(ctx, "ProcessListContainer")
   671  	defer span.Finish()
   672  
   673  	if sandboxID == "" {
   674  		return nil, vcTypes.ErrNeedSandboxID
   675  	}
   676  
   677  	if containerID == "" {
   678  		return nil, vcTypes.ErrNeedContainerID
   679  	}
   680  
   681  	unlock, err := rLockSandbox(sandboxID)
   682  	if err != nil {
   683  		return nil, err
   684  	}
   685  	defer unlock()
   686  
   687  	s, err := fetchSandbox(ctx, sandboxID)
   688  	if err != nil {
   689  		return nil, err
   690  	}
   691  	defer s.releaseStatelessSandbox()
   692  
   693  	return s.ProcessListContainer(containerID, options)
   694  }
   695  
   696  // UpdateContainer is the virtcontainers entry point to update
   697  // container's resources.
   698  func UpdateContainer(ctx context.Context, sandboxID, containerID string, resources specs.LinuxResources) error {
   699  	span, ctx := trace(ctx, "UpdateContainer")
   700  	defer span.Finish()
   701  
   702  	if sandboxID == "" {
   703  		return vcTypes.ErrNeedSandboxID
   704  	}
   705  
   706  	if containerID == "" {
   707  		return vcTypes.ErrNeedContainerID
   708  	}
   709  
   710  	unlock, err := rwLockSandbox(sandboxID)
   711  	if err != nil {
   712  		return err
   713  	}
   714  	defer unlock()
   715  
   716  	s, err := fetchSandbox(ctx, sandboxID)
   717  	if err != nil {
   718  		return err
   719  	}
   720  	defer s.releaseStatelessSandbox()
   721  
   722  	return s.UpdateContainer(containerID, resources)
   723  }
   724  
   725  // StatsContainer is the virtcontainers container stats entry point.
   726  // StatsContainer returns a detailed container stats.
   727  func StatsContainer(ctx context.Context, sandboxID, containerID string) (ContainerStats, error) {
   728  	span, ctx := trace(ctx, "StatsContainer")
   729  	defer span.Finish()
   730  
   731  	if sandboxID == "" {
   732  		return ContainerStats{}, vcTypes.ErrNeedSandboxID
   733  	}
   734  
   735  	if containerID == "" {
   736  		return ContainerStats{}, vcTypes.ErrNeedContainerID
   737  	}
   738  
   739  	unlock, err := rLockSandbox(sandboxID)
   740  	if err != nil {
   741  		return ContainerStats{}, err
   742  	}
   743  	defer unlock()
   744  
   745  	s, err := fetchSandbox(ctx, sandboxID)
   746  	if err != nil {
   747  		return ContainerStats{}, err
   748  	}
   749  	defer s.releaseStatelessSandbox()
   750  
   751  	return s.StatsContainer(containerID)
   752  }
   753  
   754  // StatsSandbox is the virtcontainers sandbox stats entry point.
   755  // StatsSandbox returns a detailed sandbox stats.
   756  func StatsSandbox(ctx context.Context, sandboxID string) (SandboxStats, []ContainerStats, error) {
   757  	span, ctx := trace(ctx, "StatsSandbox")
   758  	defer span.Finish()
   759  
   760  	if sandboxID == "" {
   761  		return SandboxStats{}, []ContainerStats{}, vcTypes.ErrNeedSandboxID
   762  	}
   763  
   764  	unlock, err := rLockSandbox(sandboxID)
   765  	if err != nil {
   766  		return SandboxStats{}, []ContainerStats{}, err
   767  	}
   768  	defer unlock()
   769  
   770  	s, err := fetchSandbox(ctx, sandboxID)
   771  	if err != nil {
   772  		return SandboxStats{}, []ContainerStats{}, err
   773  	}
   774  	defer s.releaseStatelessSandbox()
   775  
   776  	sandboxStats, err := s.Stats()
   777  	if err != nil {
   778  		return SandboxStats{}, []ContainerStats{}, err
   779  	}
   780  
   781  	containerStats := []ContainerStats{}
   782  	for _, c := range s.containers {
   783  		cstats, err := s.StatsContainer(c.id)
   784  		if err != nil {
   785  			return SandboxStats{}, []ContainerStats{}, err
   786  		}
   787  		containerStats = append(containerStats, cstats)
   788  	}
   789  
   790  	return sandboxStats, containerStats, nil
   791  }
   792  
   793  func togglePauseContainer(ctx context.Context, sandboxID, containerID string, pause bool) error {
   794  	if sandboxID == "" {
   795  		return vcTypes.ErrNeedSandboxID
   796  	}
   797  
   798  	if containerID == "" {
   799  		return vcTypes.ErrNeedContainerID
   800  	}
   801  
   802  	unlock, err := rwLockSandbox(sandboxID)
   803  	if err != nil {
   804  		return err
   805  	}
   806  	defer unlock()
   807  
   808  	s, err := fetchSandbox(ctx, sandboxID)
   809  	if err != nil {
   810  		return err
   811  	}
   812  	defer s.releaseStatelessSandbox()
   813  
   814  	if pause {
   815  		return s.PauseContainer(containerID)
   816  	}
   817  
   818  	return s.ResumeContainer(containerID)
   819  }
   820  
   821  // PauseContainer is the virtcontainers container pause entry point.
   822  func PauseContainer(ctx context.Context, sandboxID, containerID string) error {
   823  	span, ctx := trace(ctx, "PauseContainer")
   824  	defer span.Finish()
   825  
   826  	return togglePauseContainer(ctx, sandboxID, containerID, true)
   827  }
   828  
   829  // ResumeContainer is the virtcontainers container resume entry point.
   830  func ResumeContainer(ctx context.Context, sandboxID, containerID string) error {
   831  	span, ctx := trace(ctx, "ResumeContainer")
   832  	defer span.Finish()
   833  
   834  	return togglePauseContainer(ctx, sandboxID, containerID, false)
   835  }
   836  
   837  // AddDevice will add a device to sandbox
   838  func AddDevice(ctx context.Context, sandboxID string, info deviceConfig.DeviceInfo) (deviceApi.Device, error) {
   839  	span, ctx := trace(ctx, "AddDevice")
   840  	defer span.Finish()
   841  
   842  	if sandboxID == "" {
   843  		return nil, vcTypes.ErrNeedSandboxID
   844  	}
   845  
   846  	unlock, err := rwLockSandbox(sandboxID)
   847  	if err != nil {
   848  		return nil, err
   849  	}
   850  	defer unlock()
   851  
   852  	s, err := fetchSandbox(ctx, sandboxID)
   853  	if err != nil {
   854  		return nil, err
   855  	}
   856  	defer s.releaseStatelessSandbox()
   857  
   858  	return s.AddDevice(info)
   859  }
   860  
   861  func toggleInterface(ctx context.Context, sandboxID string, inf *vcTypes.Interface, add bool) (*vcTypes.Interface, error) {
   862  	if sandboxID == "" {
   863  		return nil, vcTypes.ErrNeedSandboxID
   864  	}
   865  
   866  	unlock, err := rwLockSandbox(sandboxID)
   867  	if err != nil {
   868  		return nil, err
   869  	}
   870  	defer unlock()
   871  
   872  	s, err := fetchSandbox(ctx, sandboxID)
   873  	if err != nil {
   874  		return nil, err
   875  	}
   876  	defer s.releaseStatelessSandbox()
   877  
   878  	if add {
   879  		return s.AddInterface(inf)
   880  	}
   881  
   882  	return s.RemoveInterface(inf)
   883  }
   884  
   885  // AddInterface is the virtcontainers add interface entry point.
   886  func AddInterface(ctx context.Context, sandboxID string, inf *vcTypes.Interface) (*vcTypes.Interface, error) {
   887  	span, ctx := trace(ctx, "AddInterface")
   888  	defer span.Finish()
   889  
   890  	return toggleInterface(ctx, sandboxID, inf, true)
   891  }
   892  
   893  // RemoveInterface is the virtcontainers remove interface entry point.
   894  func RemoveInterface(ctx context.Context, sandboxID string, inf *vcTypes.Interface) (*vcTypes.Interface, error) {
   895  	span, ctx := trace(ctx, "RemoveInterface")
   896  	defer span.Finish()
   897  
   898  	return toggleInterface(ctx, sandboxID, inf, false)
   899  }
   900  
   901  // ListInterfaces is the virtcontainers list interfaces entry point.
   902  func ListInterfaces(ctx context.Context, sandboxID string) ([]*vcTypes.Interface, error) {
   903  	span, ctx := trace(ctx, "ListInterfaces")
   904  	defer span.Finish()
   905  
   906  	if sandboxID == "" {
   907  		return nil, vcTypes.ErrNeedSandboxID
   908  	}
   909  
   910  	unlock, err := rLockSandbox(sandboxID)
   911  	if err != nil {
   912  		return nil, err
   913  	}
   914  	defer unlock()
   915  
   916  	s, err := fetchSandbox(ctx, sandboxID)
   917  	if err != nil {
   918  		return nil, err
   919  	}
   920  	defer s.releaseStatelessSandbox()
   921  
   922  	return s.ListInterfaces()
   923  }
   924  
   925  // UpdateRoutes is the virtcontainers update routes entry point.
   926  func UpdateRoutes(ctx context.Context, sandboxID string, routes []*vcTypes.Route) ([]*vcTypes.Route, error) {
   927  	span, ctx := trace(ctx, "UpdateRoutes")
   928  	defer span.Finish()
   929  
   930  	if sandboxID == "" {
   931  		return nil, vcTypes.ErrNeedSandboxID
   932  	}
   933  
   934  	unlock, err := rwLockSandbox(sandboxID)
   935  	if err != nil {
   936  		return nil, err
   937  	}
   938  	defer unlock()
   939  
   940  	s, err := fetchSandbox(ctx, sandboxID)
   941  	if err != nil {
   942  		return nil, err
   943  	}
   944  	defer s.releaseStatelessSandbox()
   945  
   946  	return s.UpdateRoutes(routes)
   947  }
   948  
   949  // ListRoutes is the virtcontainers list routes entry point.
   950  func ListRoutes(ctx context.Context, sandboxID string) ([]*vcTypes.Route, error) {
   951  	span, ctx := trace(ctx, "ListRoutes")
   952  	defer span.Finish()
   953  
   954  	if sandboxID == "" {
   955  		return nil, vcTypes.ErrNeedSandboxID
   956  	}
   957  
   958  	unlock, err := rLockSandbox(sandboxID)
   959  	if err != nil {
   960  		return nil, err
   961  	}
   962  	defer unlock()
   963  
   964  	s, err := fetchSandbox(ctx, sandboxID)
   965  	if err != nil {
   966  		return nil, err
   967  	}
   968  	defer s.releaseStatelessSandbox()
   969  
   970  	return s.ListRoutes()
   971  }
   972  
   973  // CleanupContaienr is used by shimv2 to stop and delete a container exclusively, once there is no container
   974  // in the sandbox left, do stop the sandbox and delete it. Those serial operations will be done exclusively by
   975  // locking the sandbox.
   976  func CleanupContainer(ctx context.Context, sandboxID, containerID string, force bool) error {
   977  	span, ctx := trace(ctx, "CleanupContainer")
   978  	defer span.Finish()
   979  
   980  	if sandboxID == "" {
   981  		return vcTypes.ErrNeedSandboxID
   982  	}
   983  
   984  	if containerID == "" {
   985  		return vcTypes.ErrNeedContainerID
   986  	}
   987  
   988  	unlock, err := rwLockSandbox(sandboxID)
   989  	if err != nil {
   990  		return err
   991  	}
   992  	defer unlock()
   993  
   994  	s, err := fetchSandbox(ctx, sandboxID)
   995  	if err != nil {
   996  		return err
   997  	}
   998  
   999  	defer s.Release()
  1000  
  1001  	_, err = s.StopContainer(containerID, force)
  1002  	if err != nil && !force {
  1003  		return err
  1004  	}
  1005  
  1006  	_, err = s.DeleteContainer(containerID)
  1007  	if err != nil && !force {
  1008  		return err
  1009  	}
  1010  
  1011  	if len(s.GetAllContainers()) > 0 {
  1012  		return nil
  1013  	}
  1014  
  1015  	if err = s.Stop(force); err != nil && !force {
  1016  		return err
  1017  	}
  1018  
  1019  	if err = s.Delete(); err != nil {
  1020  		return err
  1021  	}
  1022  
  1023  	return nil
  1024  }