github.com/containers/libpod@v1.9.4-0.20220419124438-4284fd425507/pkg/spec/createconfig.go (about) 1 package createconfig 2 3 import ( 4 "os" 5 "strconv" 6 "strings" 7 "syscall" 8 9 "github.com/containers/image/v5/manifest" 10 "github.com/containers/libpod/libpod" 11 "github.com/containers/libpod/libpod/define" 12 "github.com/containers/libpod/pkg/namespaces" 13 "github.com/containers/libpod/pkg/seccomp" 14 "github.com/containers/storage" 15 "github.com/docker/go-connections/nat" 16 spec "github.com/opencontainers/runtime-spec/specs-go" 17 "github.com/opencontainers/runtime-tools/generate" 18 "github.com/pkg/errors" 19 "github.com/sirupsen/logrus" 20 ) 21 22 // Type constants 23 const ( 24 bps = iota 25 iops 26 ) 27 28 // CreateResourceConfig represents resource elements in CreateConfig 29 // structures 30 type CreateResourceConfig struct { 31 BlkioWeight uint16 // blkio-weight 32 BlkioWeightDevice []string // blkio-weight-device 33 CPUPeriod uint64 // cpu-period 34 CPUQuota int64 // cpu-quota 35 CPURtPeriod uint64 // cpu-rt-period 36 CPURtRuntime int64 // cpu-rt-runtime 37 CPUShares uint64 // cpu-shares 38 CPUs float64 // cpus 39 CPUsetCPUs string 40 CPUsetMems string // cpuset-mems 41 DeviceCgroupRules []string //device-cgroup-rule 42 DeviceReadBps []string // device-read-bps 43 DeviceReadIOps []string // device-read-iops 44 DeviceWriteBps []string // device-write-bps 45 DeviceWriteIOps []string // device-write-iops 46 DisableOomKiller bool // oom-kill-disable 47 KernelMemory int64 // kernel-memory 48 Memory int64 //memory 49 MemoryReservation int64 // memory-reservation 50 MemorySwap int64 //memory-swap 51 MemorySwappiness int // memory-swappiness 52 OomScoreAdj int //oom-score-adj 53 PidsLimit int64 // pids-limit 54 ShmSize int64 55 Ulimit []string //ulimit 56 } 57 58 // PidConfig configures the pid namespace for the container 59 type PidConfig struct { 60 PidMode namespaces.PidMode //pid 61 } 62 63 // IpcConfig configures the ipc namespace for the container 64 type IpcConfig struct { 65 IpcMode namespaces.IpcMode //ipc 66 } 67 68 // CgroupConfig configures the cgroup namespace for the container 69 type CgroupConfig struct { 70 Cgroups string 71 Cgroupns string 72 CgroupParent string // cgroup-parent 73 CgroupMode namespaces.CgroupMode //cgroup 74 } 75 76 // UserConfig configures the user namespace for the container 77 type UserConfig struct { 78 GroupAdd []string // group-add 79 IDMappings *storage.IDMappingOptions 80 UsernsMode namespaces.UsernsMode //userns 81 User string //user 82 } 83 84 // UtsConfig configures the uts namespace for the container 85 type UtsConfig struct { 86 UtsMode namespaces.UTSMode //uts 87 NoHosts bool 88 HostAdd []string //add-host 89 Hostname string 90 } 91 92 // NetworkConfig configures the network namespace for the container 93 type NetworkConfig struct { 94 DNSOpt []string //dns-opt 95 DNSSearch []string //dns-search 96 DNSServers []string //dns 97 ExposedPorts map[nat.Port]struct{} 98 HTTPProxy bool 99 IP6Address string //ipv6 100 IPAddress string //ip 101 LinkLocalIP []string // link-local-ip 102 MacAddress string //mac-address 103 NetMode namespaces.NetworkMode //net 104 Network string //network 105 NetworkAlias []string //network-alias 106 PortBindings nat.PortMap 107 Publish []string //publish 108 PublishAll bool //publish-all 109 } 110 111 // SecurityConfig configures the security features for the container 112 type SecurityConfig struct { 113 CapAdd []string // cap-add 114 CapDrop []string // cap-drop 115 CapRequired []string // cap-required 116 LabelOpts []string //SecurityOpts 117 NoNewPrivs bool //SecurityOpts 118 ApparmorProfile string //SecurityOpts 119 SeccompProfilePath string //SecurityOpts 120 SeccompProfileFromImage string // seccomp profile from the container image 121 SeccompPolicy seccomp.Policy 122 SecurityOpts []string 123 Privileged bool //privileged 124 ReadOnlyRootfs bool //read-only 125 ReadOnlyTmpfs bool //read-only-tmpfs 126 Sysctl map[string]string //sysctl 127 } 128 129 // CreateConfig is a pre OCI spec structure. It represents user input from varlink or the CLI 130 // swagger:model CreateConfig 131 type CreateConfig struct { 132 Annotations map[string]string 133 Args []string 134 CidFile string 135 ConmonPidFile string 136 Command []string // Full command that will be used 137 UserCommand []string // User-entered command (or image CMD) 138 Detach bool // detach 139 Devices []string // device 140 Entrypoint []string //entrypoint 141 Env map[string]string //env 142 HealthCheck *manifest.Schema2HealthConfig 143 Init bool // init 144 InitPath string //init-path 145 Image string 146 ImageID string 147 RawImageName string 148 BuiltinImgVolumes map[string]struct{} // volumes defined in the image config 149 ImageVolumeType string // how to handle the image volume, either bind, tmpfs, or ignore 150 Interactive bool //interactive 151 Labels map[string]string //label 152 LogDriver string // log-driver 153 LogDriverOpt []string // log-opt 154 Name string //name 155 PodmanPath string 156 Pod string //pod 157 Quiet bool //quiet 158 Resources CreateResourceConfig 159 RestartPolicy string 160 Rm bool //rm 161 Rmi bool //rmi 162 StopSignal syscall.Signal // stop-signal 163 StopTimeout uint // stop-timeout 164 Systemd bool 165 Tmpfs []string // tmpfs 166 Tty bool //tty 167 Mounts []spec.Mount 168 MountsFlag []string // mounts 169 NamedVolumes []*libpod.ContainerNamedVolume 170 Volumes []string //volume 171 VolumesFrom []string 172 WorkDir string //workdir 173 Rootfs string 174 Security SecurityConfig 175 Syslog bool // Whether to enable syslog on exit commands 176 177 // Namespaces 178 Pid PidConfig 179 Ipc IpcConfig 180 Cgroup CgroupConfig 181 User UserConfig 182 Uts UtsConfig 183 Network NetworkConfig 184 } 185 186 func u32Ptr(i int64) *uint32 { u := uint32(i); return &u } 187 func fmPtr(i int64) *os.FileMode { fm := os.FileMode(i); return &fm } 188 189 // CreateBlockIO returns a LinuxBlockIO struct from a CreateConfig 190 func (c *CreateConfig) CreateBlockIO() (*spec.LinuxBlockIO, error) { 191 return c.createBlockIO() 192 } 193 194 func (c *CreateConfig) createExitCommand(runtime *libpod.Runtime) ([]string, error) { 195 config, err := runtime.GetConfig() 196 if err != nil { 197 return nil, err 198 } 199 storageConfig := runtime.StorageConfig() 200 201 // We need a cleanup process for containers in the current model. 202 // But we can't assume that the caller is Podman - it could be another 203 // user of the API. 204 // As such, provide a way to specify a path to Podman, so we can 205 // still invoke a cleanup process. 206 cmd := c.PodmanPath 207 if cmd == "" { 208 cmd, _ = os.Executable() 209 } 210 211 command := []string{cmd, 212 "--root", storageConfig.GraphRoot, 213 "--runroot", storageConfig.RunRoot, 214 "--log-level", logrus.GetLevel().String(), 215 "--cgroup-manager", config.Engine.CgroupManager, 216 "--tmpdir", config.Engine.TmpDir, 217 } 218 if config.Engine.OCIRuntime != "" { 219 command = append(command, []string{"--runtime", config.Engine.OCIRuntime}...) 220 } 221 if storageConfig.GraphDriverName != "" { 222 command = append(command, []string{"--storage-driver", storageConfig.GraphDriverName}...) 223 } 224 for _, opt := range storageConfig.GraphDriverOptions { 225 command = append(command, []string{"--storage-opt", opt}...) 226 } 227 if config.Engine.EventsLogger != "" { 228 command = append(command, []string{"--events-backend", config.Engine.EventsLogger}...) 229 } 230 231 if c.Syslog { 232 command = append(command, "--syslog", "true") 233 } 234 command = append(command, []string{"container", "cleanup"}...) 235 236 if c.Rm { 237 command = append(command, "--rm") 238 } 239 240 if c.Rmi { 241 command = append(command, "--rmi") 242 } 243 244 return command, nil 245 } 246 247 // GetContainerCreateOptions takes a CreateConfig and returns a slice of CtrCreateOptions 248 func (c *CreateConfig) getContainerCreateOptions(runtime *libpod.Runtime, pod *libpod.Pod, mounts []spec.Mount, namedVolumes []*libpod.ContainerNamedVolume) ([]libpod.CtrCreateOption, error) { 249 var options []libpod.CtrCreateOption 250 var err error 251 252 if c.Interactive { 253 options = append(options, libpod.WithStdin()) 254 } 255 if c.Systemd { 256 options = append(options, libpod.WithSystemd()) 257 } 258 if c.Name != "" { 259 logrus.Debugf("setting container name %s", c.Name) 260 options = append(options, libpod.WithName(c.Name)) 261 } 262 if c.Pod != "" { 263 logrus.Debugf("adding container to pod %s", c.Pod) 264 options = append(options, runtime.WithPod(pod)) 265 } 266 267 if len(mounts) != 0 || len(namedVolumes) != 0 { 268 destinations := []string{} 269 270 // Take all mount and named volume destinations. 271 for _, mount := range mounts { 272 destinations = append(destinations, mount.Destination) 273 } 274 for _, volume := range namedVolumes { 275 destinations = append(destinations, volume.Dest) 276 } 277 278 options = append(options, libpod.WithUserVolumes(destinations)) 279 } 280 281 if len(namedVolumes) != 0 { 282 options = append(options, libpod.WithNamedVolumes(namedVolumes)) 283 } 284 285 if len(c.UserCommand) != 0 { 286 options = append(options, libpod.WithCommand(c.UserCommand)) 287 } 288 289 // Add entrypoint unconditionally 290 // If it's empty it's because it was explicitly set to "" or the image 291 // does not have one 292 options = append(options, libpod.WithEntrypoint(c.Entrypoint)) 293 294 // TODO: MNT, USER, CGROUP 295 options = append(options, libpod.WithStopSignal(c.StopSignal)) 296 options = append(options, libpod.WithStopTimeout(c.StopTimeout)) 297 298 logPath, logTag := getLoggingOpts(c.LogDriverOpt) 299 if logPath != "" { 300 options = append(options, libpod.WithLogPath(logPath)) 301 } 302 if logTag != "" { 303 options = append(options, libpod.WithLogTag(logTag)) 304 } 305 306 if c.LogDriver != "" { 307 options = append(options, libpod.WithLogDriver(c.LogDriver)) 308 } 309 310 secOpts, err := c.Security.ToCreateOptions() 311 if err != nil { 312 return nil, err 313 } 314 options = append(options, secOpts...) 315 316 nsOpts, err := c.Cgroup.ToCreateOptions(runtime) 317 if err != nil { 318 return nil, err 319 } 320 options = append(options, nsOpts...) 321 322 nsOpts, err = c.Ipc.ToCreateOptions(runtime) 323 if err != nil { 324 return nil, err 325 } 326 options = append(options, nsOpts...) 327 328 nsOpts, err = c.Pid.ToCreateOptions(runtime) 329 if err != nil { 330 return nil, err 331 } 332 options = append(options, nsOpts...) 333 334 nsOpts, err = c.Network.ToCreateOptions(runtime, &c.User) 335 if err != nil { 336 return nil, err 337 } 338 options = append(options, nsOpts...) 339 340 nsOpts, err = c.Uts.ToCreateOptions(runtime, pod) 341 if err != nil { 342 return nil, err 343 } 344 options = append(options, nsOpts...) 345 346 nsOpts, err = c.User.ToCreateOptions(runtime) 347 if err != nil { 348 return nil, err 349 } 350 options = append(options, nsOpts...) 351 352 // Gather up the options for NewContainer which consist of With... funcs 353 options = append(options, libpod.WithRootFSFromImage(c.ImageID, c.Image, c.RawImageName)) 354 options = append(options, libpod.WithConmonPidFile(c.ConmonPidFile)) 355 options = append(options, libpod.WithLabels(c.Labels)) 356 options = append(options, libpod.WithShmSize(c.Resources.ShmSize)) 357 if c.Rootfs != "" { 358 options = append(options, libpod.WithRootFS(c.Rootfs)) 359 } 360 // Default used if not overridden on command line 361 362 if c.RestartPolicy != "" { 363 if c.RestartPolicy == "unless-stopped" { 364 return nil, errors.Wrapf(define.ErrInvalidArg, "the unless-stopped restart policy is not supported") 365 } 366 367 split := strings.Split(c.RestartPolicy, ":") 368 if len(split) > 1 { 369 numTries, err := strconv.Atoi(split[1]) 370 if err != nil { 371 return nil, errors.Wrapf(err, "%s is not a valid number of retries for restart policy", split[1]) 372 } 373 if numTries < 0 { 374 return nil, errors.Wrapf(define.ErrInvalidArg, "restart policy requires a positive number of retries") 375 } 376 options = append(options, libpod.WithRestartRetries(uint(numTries))) 377 } 378 options = append(options, libpod.WithRestartPolicy(split[0])) 379 } 380 381 // Always use a cleanup process to clean up Podman after termination 382 exitCmd, err := c.createExitCommand(runtime) 383 if err != nil { 384 return nil, err 385 } 386 options = append(options, libpod.WithExitCommand(exitCmd)) 387 388 if c.HealthCheck != nil { 389 options = append(options, libpod.WithHealthCheck(c.HealthCheck)) 390 logrus.Debugf("New container has a health check") 391 } 392 return options, nil 393 } 394 395 // AddPrivilegedDevices iterates through host devices and adds all 396 // host devices to the spec 397 func AddPrivilegedDevices(g *generate.Generator) error { 398 return addPrivilegedDevices(g) 399 }