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 }