diff options
author | Brent Baude <bbaude@redhat.com> | 2020-04-16 12:25:26 -0500 |
---|---|---|
committer | Brent Baude <bbaude@redhat.com> | 2020-04-16 15:53:58 -0500 |
commit | 241326a9a8c20ad7f2bcf651416b836e7778e090 (patch) | |
tree | 4001e8e47a022bb1b9bfbf2332c42e1aeb802f9e /cmd/podmanV2/common/specgen.go | |
parent | 88c6fd06cd54fb9a8826306dfdf1a77e400de5de (diff) | |
download | podman-241326a9a8c20ad7f2bcf651416b836e7778e090.tar.gz podman-241326a9a8c20ad7f2bcf651416b836e7778e090.tar.bz2 podman-241326a9a8c20ad7f2bcf651416b836e7778e090.zip |
Podman V2 birth
remote podman v1 and replace with podman v2.
Signed-off-by: Brent Baude <bbaude@redhat.com>
Diffstat (limited to 'cmd/podmanV2/common/specgen.go')
-rw-r--r-- | cmd/podmanV2/common/specgen.go | 647 |
1 files changed, 0 insertions, 647 deletions
diff --git a/cmd/podmanV2/common/specgen.go b/cmd/podmanV2/common/specgen.go deleted file mode 100644 index 2232fb4ba..000000000 --- a/cmd/podmanV2/common/specgen.go +++ /dev/null @@ -1,647 +0,0 @@ -package common - -import ( - "encoding/json" - "fmt" - "os" - "path/filepath" - "strconv" - "strings" - "time" - - "github.com/containers/image/v5/manifest" - "github.com/containers/libpod/cmd/podmanV2/parse" - "github.com/containers/libpod/libpod/define" - ann "github.com/containers/libpod/pkg/annotations" - envLib "github.com/containers/libpod/pkg/env" - ns "github.com/containers/libpod/pkg/namespaces" - "github.com/containers/libpod/pkg/specgen" - systemdGen "github.com/containers/libpod/pkg/systemd/generate" - "github.com/containers/libpod/pkg/util" - "github.com/docker/go-units" - "github.com/opencontainers/runtime-spec/specs-go" - "github.com/pkg/errors" -) - -func FillOutSpecGen(s *specgen.SpecGenerator, c *ContainerCLIOpts, args []string) error { - var ( - err error - //namespaces map[string]string - ) - - // validate flags as needed - if err := c.validate(); err != nil { - return nil - } - - inputCommand := args[1:] - if len(c.HealthCmd) > 0 { - s.HealthConfig, err = makeHealthCheckFromCli(c.HealthCmd, c.HealthInterval, c.HealthRetries, c.HealthTimeout, c.HealthStartPeriod) - if err != nil { - return err - } - } - - s.IDMappings, err = util.ParseIDMapping(ns.UsernsMode(c.UserNS), c.UIDMap, c.GIDMap, c.SubUIDName, c.SubGIDName) - if err != nil { - return err - } - if m := c.Memory; len(m) > 0 { - ml, err := units.RAMInBytes(m) - if err != nil { - return errors.Wrapf(err, "invalid value for memory") - } - s.ResourceLimits.Memory.Limit = &ml - } - if m := c.MemoryReservation; len(m) > 0 { - mr, err := units.RAMInBytes(m) - if err != nil { - return errors.Wrapf(err, "invalid value for memory") - } - s.ResourceLimits.Memory.Reservation = &mr - } - if m := c.MemorySwap; len(m) > 0 { - var ms int64 - if m == "-1" { - ms = int64(-1) - s.ResourceLimits.Memory.Swap = &ms - } else { - ms, err = units.RAMInBytes(m) - if err != nil { - return errors.Wrapf(err, "invalid value for memory") - } - } - s.ResourceLimits.Memory.Swap = &ms - } - if m := c.KernelMemory; len(m) > 0 { - mk, err := units.RAMInBytes(m) - if err != nil { - return errors.Wrapf(err, "invalid value for kernel-memory") - } - s.ResourceLimits.Memory.Kernel = &mk - } - if b := c.BlkIOWeight; len(b) > 0 { - u, err := strconv.ParseUint(b, 10, 16) - if err != nil { - return errors.Wrapf(err, "invalid value for blkio-weight") - } - nu := uint16(u) - s.ResourceLimits.BlockIO.Weight = &nu - } - - s.Terminal = c.TTY - ep, err := ExposedPorts(c.Expose, c.Net.PublishPorts, c.PublishAll, nil) - if err != nil { - return err - } - s.PortMappings = ep - s.Pod = c.Pod - - //s.CgroupNS = specgen.Namespace{ - // NSMode: , - // Value: "", - //} - - //s.UserNS = specgen.Namespace{} - - // Kernel Namespaces - // TODO Fix handling of namespace from pod - // Instead of integrating here, should be done in libpod - // However, that also involves setting up security opts - // when the pod's namespace is integrated - //namespaces = map[string]string{ - // "cgroup": c.CGroupsNS, - // "pid": c.PID, - // //"net": c.Net.Network.Value, // TODO need help here - // "ipc": c.IPC, - // "user": c.User, - // "uts": c.UTS, - //} - // - //if len(c.PID) > 0 { - // split := strings.SplitN(c.PID, ":", 2) - // // need a way to do thsi - // specgen.Namespace{ - // NSMode: split[0], - // } - // //Value: split1 if len allows - //} - // TODO this is going to have be done after things like pod creation are done because - // pod creation changes these values. - //pidMode := ns.PidMode(namespaces["pid"]) - //usernsMode := ns.UsernsMode(namespaces["user"]) - //utsMode := ns.UTSMode(namespaces["uts"]) - //cgroupMode := ns.CgroupMode(namespaces["cgroup"]) - //ipcMode := ns.IpcMode(namespaces["ipc"]) - //// Make sure if network is set to container namespace, port binding is not also being asked for - //netMode := ns.NetworkMode(namespaces["net"]) - //if netMode.IsContainer() { - // if len(portBindings) > 0 { - // return nil, errors.Errorf("cannot set port bindings on an existing container network namespace") - // } - //} - - // TODO Remove when done with namespaces for realz - // Setting a default for IPC to get this working - s.IpcNS = specgen.Namespace{ - NSMode: specgen.Private, - Value: "", - } - - // TODO this is going to have to be done the libpod/server end of things - // USER - //user := c.String("user") - //if user == "" { - // switch { - // case usernsMode.IsKeepID(): - // user = fmt.Sprintf("%d:%d", rootless.GetRootlessUID(), rootless.GetRootlessGID()) - // case data == nil: - // user = "0" - // default: - // user = data.Config.User - // } - //} - - // STOP SIGNAL - signalString := "TERM" - if sig := c.StopSignal; len(sig) > 0 { - signalString = sig - } - stopSignal, err := util.ParseSignal(signalString) - if err != nil { - return err - } - s.StopSignal = &stopSignal - - // ENVIRONMENT VARIABLES - // - // Precedence order (higher index wins): - // 1) env-host, 2) image data, 3) env-file, 4) env - env := map[string]string{ - "container": "podman", - } - - // First transform the os env into a map. We need it for the labels later in - // any case. - osEnv, err := envLib.ParseSlice(os.Environ()) - if err != nil { - return errors.Wrap(err, "error parsing host environment variables") - } - - if c.EnvHost { - env = envLib.Join(env, osEnv) - } - // env-file overrides any previous variables - for _, f := range c.EnvFile { - fileEnv, err := envLib.ParseFile(f) - if err != nil { - return err - } - // File env is overridden by env. - env = envLib.Join(env, fileEnv) - } - - // env overrides any previous variables - if cmdLineEnv := c.env; len(cmdLineEnv) > 0 { - parsedEnv, err := envLib.ParseSlice(cmdLineEnv) - if err != nil { - return err - } - env = envLib.Join(env, parsedEnv) - } - s.Env = env - - // LABEL VARIABLES - labels, err := parse.GetAllLabels(c.LabelFile, c.Label) - if err != nil { - return errors.Wrapf(err, "unable to process labels") - } - - if systemdUnit, exists := osEnv[systemdGen.EnvVariable]; exists { - labels[systemdGen.EnvVariable] = systemdUnit - } - - s.Labels = labels - - // ANNOTATIONS - annotations := make(map[string]string) - - // First, add our default annotations - annotations[ann.TTY] = "false" - if c.TTY { - annotations[ann.TTY] = "true" - } - - // Last, add user annotations - for _, annotation := range c.Annotation { - splitAnnotation := strings.SplitN(annotation, "=", 2) - if len(splitAnnotation) < 2 { - return errors.Errorf("Annotations must be formatted KEY=VALUE") - } - annotations[splitAnnotation[0]] = splitAnnotation[1] - } - s.Annotations = annotations - - workDir := "/" - if wd := c.Workdir; len(wd) > 0 { - workDir = wd - } - s.WorkDir = workDir - entrypoint := []string{} - userCommand := []string{} - if ep := c.Entrypoint; len(ep) > 0 { - // Check if entrypoint specified is json - if err := json.Unmarshal([]byte(c.Entrypoint), &entrypoint); err != nil { - entrypoint = append(entrypoint, ep) - } - } - - var command []string - - // Build the command - // If we have an entry point, it goes first - if len(entrypoint) > 0 { - command = entrypoint - } - if len(inputCommand) > 0 { - // User command overrides data CMD - command = append(command, inputCommand...) - userCommand = append(userCommand, inputCommand...) - } - - if len(inputCommand) > 0 { - s.Command = userCommand - } else { - s.Command = command - } - - // SHM Size - shmSize, err := units.FromHumanSize(c.ShmSize) - if err != nil { - return errors.Wrapf(err, "unable to translate --shm-size") - } - s.ShmSize = &shmSize - s.HostAdd = c.Net.AddHosts - s.DNSServer = c.Net.DNSServers - s.DNSSearch = c.Net.DNSSearch - s.DNSOption = c.Net.DNSOptions - - // deferred, must be added on libpod side - //var ImageVolumes map[string]struct{} - //if data != nil && c.String("image-volume") != "ignore" { - // ImageVolumes = data.Config.Volumes - //} - - s.ImageVolumeMode = c.ImageVolume - systemd := c.SystemdD == "always" - if !systemd && command != nil { - x, err := strconv.ParseBool(c.SystemdD) - if err != nil { - return errors.Wrapf(err, "cannot parse bool %s", c.SystemdD) - } - if x && (command[0] == "/usr/sbin/init" || command[0] == "/sbin/init" || (filepath.Base(command[0]) == "systemd")) { - systemd = true - } - } - if systemd { - if s.StopSignal == nil { - stopSignal, err = util.ParseSignal("RTMIN+3") - if err != nil { - return errors.Wrapf(err, "error parsing systemd signal") - } - s.StopSignal = &stopSignal - } - } - swappiness := uint64(c.MemorySwappiness) - if s.ResourceLimits == nil { - s.ResourceLimits = &specs.LinuxResources{} - } - if s.ResourceLimits.Memory == nil { - s.ResourceLimits.Memory = &specs.LinuxMemory{} - } - s.ResourceLimits.Memory.Swappiness = &swappiness - - if s.LogConfiguration == nil { - s.LogConfiguration = &specgen.LogConfig{} - } - s.LogConfiguration.Driver = define.KubernetesLogging - if ld := c.LogDriver; len(ld) > 0 { - s.LogConfiguration.Driver = ld - } - if s.ResourceLimits.Pids == nil { - s.ResourceLimits.Pids = &specs.LinuxPids{} - } - s.ResourceLimits.Pids.Limit = c.PIDsLimit - if c.CGroups == "disabled" && c.PIDsLimit > 0 { - s.ResourceLimits.Pids.Limit = -1 - } - // TODO WTF - //cgroup := &cc.CgroupConfig{ - // Cgroups: c.String("cgroups"), - // Cgroupns: c.String("cgroupns"), - // CgroupParent: c.String("cgroup-parent"), - // CgroupMode: cgroupMode, - //} - // - //userns := &cc.UserConfig{ - // GroupAdd: c.StringSlice("group-add"), - // IDMappings: idmappings, - // UsernsMode: usernsMode, - // User: user, - //} - // - //uts := &cc.UtsConfig{ - // UtsMode: utsMode, - // NoHosts: c.Bool("no-hosts"), - // HostAdd: c.StringSlice("add-host"), - // Hostname: c.String("hostname"), - //} - - sysctl := map[string]string{} - if ctl := c.Sysctl; len(ctl) > 0 { - sysctl, err = util.ValidateSysctls(ctl) - if err != nil { - return err - } - } - s.Sysctl = sysctl - - s.CapAdd = c.CapAdd - s.CapDrop = c.CapDrop - s.Privileged = c.Privileged - s.ReadOnlyFilesystem = c.ReadOnly - - // TODO - // ouitside of specgen and oci though - // defaults to true, check spec/storage - //s.readon = c.ReadOnlyTmpFS - // TODO convert to map? - // check if key=value and convert - sysmap := make(map[string]string) - for _, ctl := range c.Sysctl { - splitCtl := strings.SplitN(ctl, "=", 2) - if len(splitCtl) < 2 { - return errors.Errorf("invalid sysctl value %q", ctl) - } - sysmap[splitCtl[0]] = splitCtl[1] - } - s.Sysctl = sysmap - - for _, opt := range c.SecurityOpt { - if opt == "no-new-privileges" { - s.ContainerSecurityConfig.NoNewPrivileges = true - } else { - con := strings.SplitN(opt, "=", 2) - if len(con) != 2 { - return fmt.Errorf("invalid --security-opt 1: %q", opt) - } - - switch con[0] { - case "label": - // TODO selinux opts and label opts are the same thing - s.ContainerSecurityConfig.SelinuxOpts = append(s.ContainerSecurityConfig.SelinuxOpts, con[1]) - case "apparmor": - s.ContainerSecurityConfig.ApparmorProfile = con[1] - case "seccomp": - s.SeccompProfilePath = con[1] - default: - return fmt.Errorf("invalid --security-opt 2: %q", opt) - } - } - } - - // TODO any idea why this was done - // storage.go from spec/ - // grab it - //volumes := rtc.Containers.Volumes - // TODO conflict on populate? - //if v := c.Volume; len(v)> 0 { - // s.Volumes = append(volumes, c.StringSlice("volume")...) - //} - //s.volu - - //s.Mounts = c.Mount - s.VolumesFrom = c.VolumesFrom - - // TODO any idea why this was done - //devices := rtc.Containers.Devices - // TODO conflict on populate? - // - //if c.Changed("device") { - // devices = append(devices, c.StringSlice("device")...) - //} - - // TODO things i cannot find in spec - // we dont think these are in the spec - // init - initbinary - // initpath - s.Stdin = c.Interactive - // quiet - //DeviceCgroupRules: c.StringSlice("device-cgroup-rule"), - - if bps := c.DeviceReadBPs; len(bps) > 0 { - if s.ThrottleReadBpsDevice, err = parseThrottleBPSDevices(bps); err != nil { - return err - } - } - - if bps := c.DeviceWriteBPs; len(bps) > 0 { - if s.ThrottleWriteBpsDevice, err = parseThrottleBPSDevices(bps); err != nil { - return err - } - } - - if iops := c.DeviceReadIOPs; len(iops) > 0 { - if s.ThrottleReadIOPSDevice, err = parseThrottleIOPsDevices(iops); err != nil { - return err - } - } - - if iops := c.DeviceWriteIOPs; len(iops) > 0 { - if s.ThrottleWriteIOPSDevice, err = parseThrottleIOPsDevices(iops); err != nil { - return err - } - } - - s.ResourceLimits.Memory.DisableOOMKiller = &c.OOMKillDisable - - // Rlimits/Ulimits - for _, u := range c.Ulimit { - if u == "host" { - s.Rlimits = nil - break - } - ul, err := units.ParseUlimit(u) - if err != nil { - return errors.Wrapf(err, "ulimit option %q requires name=SOFT:HARD, failed to be parsed", u) - } - rl := specs.POSIXRlimit{ - Type: ul.Name, - Hard: uint64(ul.Hard), - Soft: uint64(ul.Soft), - } - s.Rlimits = append(s.Rlimits, rl) - } - - //Tmpfs: c.StringArray("tmpfs"), - - // TODO how to handle this? - //Syslog: c.Bool("syslog"), - - logOpts := make(map[string]string) - for _, o := range c.LogOptions { - split := strings.SplitN(o, "=", 2) - if len(split) < 2 { - return errors.Errorf("invalid log option %q", o) - } - logOpts[split[0]] = split[1] - } - s.LogConfiguration.Options = logOpts - s.Name = c.Name - - if err := parseWeightDevices(c.BlkIOWeightDevice, s); err != nil { - return err - } - - if s.ResourceLimits.CPU == nil { - s.ResourceLimits.CPU = &specs.LinuxCPU{} - } - s.ResourceLimits.CPU.Shares = &c.CPUShares - s.ResourceLimits.CPU.Period = &c.CPUPeriod - - // TODO research these - //s.ResourceLimits.CPU.Cpus = c.CPUS - //s.ResourceLimits.CPU.Cpus = c.CPUSetCPUs - - //s.ResourceLimits.CPU. = c.CPUSetCPUs - s.ResourceLimits.CPU.Mems = c.CPUSetMems - s.ResourceLimits.CPU.Quota = &c.CPUQuota - s.ResourceLimits.CPU.RealtimePeriod = &c.CPURTPeriod - s.ResourceLimits.CPU.RealtimeRuntime = &c.CPURTRuntime - s.OOMScoreAdj = &c.OOMScoreAdj - s.RestartPolicy = c.Restart - s.Remove = c.Rm - s.StopTimeout = &c.StopTimeout - - // TODO where should we do this? - //func verifyContainerResources(config *cc.CreateConfig, update bool) ([]string, error) { - return nil -} - -func makeHealthCheckFromCli(inCmd, interval string, retries uint, timeout, startPeriod string) (*manifest.Schema2HealthConfig, error) { - // Every healthcheck requires a command - if len(inCmd) == 0 { - return nil, errors.New("Must define a healthcheck command for all healthchecks") - } - - // first try to parse option value as JSON array of strings... - cmd := []string{} - err := json.Unmarshal([]byte(inCmd), &cmd) - if err != nil { - // ...otherwise pass it to "/bin/sh -c" inside the container - cmd = []string{"CMD-SHELL", inCmd} - } - hc := manifest.Schema2HealthConfig{ - Test: cmd, - } - - if interval == "disable" { - interval = "0" - } - intervalDuration, err := time.ParseDuration(interval) - if err != nil { - return nil, errors.Wrapf(err, "invalid healthcheck-interval %s ", interval) - } - - hc.Interval = intervalDuration - - if retries < 1 { - return nil, errors.New("healthcheck-retries must be greater than 0.") - } - hc.Retries = int(retries) - timeoutDuration, err := time.ParseDuration(timeout) - if err != nil { - return nil, errors.Wrapf(err, "invalid healthcheck-timeout %s", timeout) - } - if timeoutDuration < time.Duration(1) { - return nil, errors.New("healthcheck-timeout must be at least 1 second") - } - hc.Timeout = timeoutDuration - - startPeriodDuration, err := time.ParseDuration(startPeriod) - if err != nil { - return nil, errors.Wrapf(err, "invalid healthcheck-start-period %s", startPeriod) - } - if startPeriodDuration < time.Duration(0) { - return nil, errors.New("healthcheck-start-period must be 0 seconds or greater") - } - hc.StartPeriod = startPeriodDuration - - return &hc, nil -} - -func parseWeightDevices(weightDevs []string, s *specgen.SpecGenerator) error { - for _, val := range weightDevs { - split := strings.SplitN(val, ":", 2) - if len(split) != 2 { - return fmt.Errorf("bad format: %s", val) - } - if !strings.HasPrefix(split[0], "/dev/") { - return fmt.Errorf("bad format for device path: %s", val) - } - weight, err := strconv.ParseUint(split[1], 10, 0) - if err != nil { - return fmt.Errorf("invalid weight for device: %s", val) - } - if weight > 0 && (weight < 10 || weight > 1000) { - return fmt.Errorf("invalid weight for device: %s", val) - } - w := uint16(weight) - s.WeightDevice[split[0]] = specs.LinuxWeightDevice{ - Weight: &w, - LeafWeight: nil, - } - } - return nil -} - -func parseThrottleBPSDevices(bpsDevices []string) (map[string]specs.LinuxThrottleDevice, error) { - td := make(map[string]specs.LinuxThrottleDevice) - for _, val := range bpsDevices { - split := strings.SplitN(val, ":", 2) - if len(split) != 2 { - return nil, fmt.Errorf("bad format: %s", val) - } - if !strings.HasPrefix(split[0], "/dev/") { - return nil, fmt.Errorf("bad format for device path: %s", val) - } - rate, err := units.RAMInBytes(split[1]) - if err != nil { - return nil, fmt.Errorf("invalid rate for device: %s. The correct format is <device-path>:<number>[<unit>]. Number must be a positive integer. Unit is optional and can be kb, mb, or gb", val) - } - if rate < 0 { - return nil, fmt.Errorf("invalid rate for device: %s. The correct format is <device-path>:<number>[<unit>]. Number must be a positive integer. Unit is optional and can be kb, mb, or gb", val) - } - td[split[0]] = specs.LinuxThrottleDevice{Rate: uint64(rate)} - } - return td, nil -} - -func parseThrottleIOPsDevices(iopsDevices []string) (map[string]specs.LinuxThrottleDevice, error) { - td := make(map[string]specs.LinuxThrottleDevice) - for _, val := range iopsDevices { - split := strings.SplitN(val, ":", 2) - if len(split) != 2 { - return nil, fmt.Errorf("bad format: %s", val) - } - if !strings.HasPrefix(split[0], "/dev/") { - return nil, fmt.Errorf("bad format for device path: %s", val) - } - rate, err := strconv.ParseUint(split[1], 10, 64) - if err != nil { - return nil, fmt.Errorf("invalid rate for device: %s. The correct format is <device-path>:<number>. Number must be a positive integer", val) - } - td[split[0]] = specs.LinuxThrottleDevice{Rate: rate} - } - return td, nil -} |