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