github.com/containers/libpod@v1.9.4-0.20220419124438-4284fd425507/pkg/specgen/generate/container.go (about)

     1  package generate
     2  
     3  import (
     4  	"context"
     5  
     6  	"github.com/containers/libpod/libpod"
     7  	ann "github.com/containers/libpod/pkg/annotations"
     8  	envLib "github.com/containers/libpod/pkg/env"
     9  	"github.com/containers/libpod/pkg/signal"
    10  	"github.com/containers/libpod/pkg/specgen"
    11  	"github.com/pkg/errors"
    12  	"golang.org/x/sys/unix"
    13  )
    14  
    15  func CompleteSpec(ctx context.Context, r *libpod.Runtime, s *specgen.SpecGenerator) error {
    16  
    17  	newImage, err := r.ImageRuntime().NewFromLocal(s.Image)
    18  	if err != nil {
    19  		return err
    20  	}
    21  
    22  	// Image stop signal
    23  	if s.StopSignal == nil && newImage.Config != nil {
    24  		sig, err := signal.ParseSignalNameOrNumber(newImage.Config.StopSignal)
    25  		if err != nil {
    26  			return err
    27  		}
    28  		s.StopSignal = &sig
    29  	}
    30  	// Image envs from the image if they don't exist
    31  	// already
    32  	if newImage.Config != nil && len(newImage.Config.Env) > 0 {
    33  		envs, err := envLib.ParseSlice(newImage.Config.Env)
    34  		if err != nil {
    35  			return err
    36  		}
    37  		for k, v := range envs {
    38  			if _, exists := s.Env[k]; !exists {
    39  				s.Env[v] = k
    40  			}
    41  		}
    42  	}
    43  
    44  	// labels from the image that dont exist already
    45  	if config := newImage.Config; config != nil {
    46  		for k, v := range config.Labels {
    47  			if _, exists := s.Labels[k]; !exists {
    48  				s.Labels[k] = v
    49  			}
    50  		}
    51  	}
    52  
    53  	// annotations
    54  	// in the event this container is in a pod, and the pod has an infra container
    55  	// we will want to configure it as a type "container" instead defaulting to
    56  	// the behavior of a "sandbox" container
    57  	// In Kata containers:
    58  	// - "sandbox" is the annotation that denotes the container should use its own
    59  	//   VM, which is the default behavior
    60  	// - "container" denotes the container should join the VM of the SandboxID
    61  	//   (the infra container)
    62  	s.Annotations = make(map[string]string)
    63  	if len(s.Pod) > 0 {
    64  		s.Annotations[ann.SandboxID] = s.Pod
    65  		s.Annotations[ann.ContainerType] = ann.ContainerTypeContainer
    66  	}
    67  	//
    68  	// Next, add annotations from the image
    69  	annotations, err := newImage.Annotations(ctx)
    70  	if err != nil {
    71  		return err
    72  	}
    73  	for k, v := range annotations {
    74  		annotations[k] = v
    75  	}
    76  
    77  	// entrypoint
    78  	if config := newImage.Config; config != nil {
    79  		if len(s.Entrypoint) < 1 && len(config.Entrypoint) > 0 {
    80  			s.Entrypoint = config.Entrypoint
    81  		}
    82  		if len(s.Command) < 1 && len(config.Cmd) > 0 {
    83  			s.Command = config.Cmd
    84  		}
    85  		if len(s.Command) < 1 && len(s.Entrypoint) < 1 {
    86  			return errors.Errorf("No command provided or as CMD or ENTRYPOINT in this image")
    87  		}
    88  		// workdir
    89  		if len(s.WorkDir) < 1 && len(config.WorkingDir) > 1 {
    90  			s.WorkDir = config.WorkingDir
    91  		}
    92  	}
    93  
    94  	if len(s.SeccompProfilePath) < 1 {
    95  		p, err := libpod.DefaultSeccompPath()
    96  		if err != nil {
    97  			return err
    98  		}
    99  		s.SeccompProfilePath = p
   100  	}
   101  
   102  	if user := s.User; len(user) == 0 {
   103  		switch {
   104  		// TODO This should be enabled when namespaces actually work
   105  		//case usernsMode.IsKeepID():
   106  		//	user = fmt.Sprintf("%d:%d", rootless.GetRootlessUID(), rootless.GetRootlessGID())
   107  		case newImage.Config == nil || (newImage.Config != nil && len(newImage.Config.User) == 0):
   108  			s.User = "0"
   109  		default:
   110  			s.User = newImage.Config.User
   111  		}
   112  	}
   113  	if err := finishThrottleDevices(s); err != nil {
   114  		return err
   115  	}
   116  	return nil
   117  }
   118  
   119  // finishThrottleDevices takes the temporary representation of the throttle
   120  // devices in the specgen and looks up the major and major minors. it then
   121  // sets the throttle devices proper in the specgen
   122  func finishThrottleDevices(s *specgen.SpecGenerator) error {
   123  	if bps := s.ThrottleReadBpsDevice; len(bps) > 0 {
   124  		for k, v := range bps {
   125  			statT := unix.Stat_t{}
   126  			if err := unix.Stat(k, &statT); err != nil {
   127  				return err
   128  			}
   129  			v.Major = (int64(unix.Major(statT.Rdev)))
   130  			v.Minor = (int64(unix.Minor(statT.Rdev)))
   131  			s.ResourceLimits.BlockIO.ThrottleReadBpsDevice = append(s.ResourceLimits.BlockIO.ThrottleReadBpsDevice, v)
   132  		}
   133  	}
   134  	if bps := s.ThrottleWriteBpsDevice; len(bps) > 0 {
   135  		for k, v := range bps {
   136  			statT := unix.Stat_t{}
   137  			if err := unix.Stat(k, &statT); err != nil {
   138  				return err
   139  			}
   140  			v.Major = (int64(unix.Major(statT.Rdev)))
   141  			v.Minor = (int64(unix.Minor(statT.Rdev)))
   142  			s.ResourceLimits.BlockIO.ThrottleWriteBpsDevice = append(s.ResourceLimits.BlockIO.ThrottleWriteBpsDevice, v)
   143  		}
   144  	}
   145  	if iops := s.ThrottleReadIOPSDevice; len(iops) > 0 {
   146  		for k, v := range iops {
   147  			statT := unix.Stat_t{}
   148  			if err := unix.Stat(k, &statT); err != nil {
   149  				return err
   150  			}
   151  			v.Major = (int64(unix.Major(statT.Rdev)))
   152  			v.Minor = (int64(unix.Minor(statT.Rdev)))
   153  			s.ResourceLimits.BlockIO.ThrottleReadIOPSDevice = append(s.ResourceLimits.BlockIO.ThrottleReadIOPSDevice, v)
   154  		}
   155  	}
   156  	if iops := s.ThrottleWriteBpsDevice; len(iops) > 0 {
   157  		for k, v := range iops {
   158  			statT := unix.Stat_t{}
   159  			if err := unix.Stat(k, &statT); err != nil {
   160  				return err
   161  			}
   162  			v.Major = (int64(unix.Major(statT.Rdev)))
   163  			v.Minor = (int64(unix.Minor(statT.Rdev)))
   164  			s.ResourceLimits.BlockIO.ThrottleWriteIOPSDevice = append(s.ResourceLimits.BlockIO.ThrottleWriteIOPSDevice, v)
   165  		}
   166  	}
   167  	return nil
   168  }