summaryrefslogtreecommitdiff
path: root/cmd/podman/common
diff options
context:
space:
mode:
authorbaude <bbaude@redhat.com>2020-10-14 13:53:12 -0500
committerbaude <bbaude@redhat.com>2020-10-20 12:06:59 -0500
commiteb91d66c4aa0d2d75a5787ab7013cef88d8c9f4f (patch)
tree1dc9988ebc7470e05bd80622982ab9a5926d0d5b /cmd/podman/common
parent35b4cb196545eee3b072083e716ad4588e0bb486 (diff)
downloadpodman-eb91d66c4aa0d2d75a5787ab7013cef88d8c9f4f.tar.gz
podman-eb91d66c4aa0d2d75a5787ab7013cef88d8c9f4f.tar.bz2
podman-eb91d66c4aa0d2d75a5787ab7013cef88d8c9f4f.zip
refactor api compatibility container creation to specgen
when using the compatibility layer to create containers, it used code paths to the pkg/spec which is the old implementation of containers. it is error prone and no longer being maintained. rather that fixing things in spec, migrating to specgen usage seems to make the most sense. furthermore, any fixes to the compat create will not need to be ported later. Signed-off-by: baude <bbaude@redhat.com>
Diffstat (limited to 'cmd/podman/common')
-rw-r--r--cmd/podman/common/create_opts.go291
1 files changed, 290 insertions, 1 deletions
diff --git a/cmd/podman/common/create_opts.go b/cmd/podman/common/create_opts.go
index 83a25f4ab..f4fecf4b7 100644
--- a/cmd/podman/common/create_opts.go
+++ b/cmd/podman/common/create_opts.go
@@ -1,6 +1,15 @@
package common
-import "github.com/containers/podman/v2/pkg/domain/entities"
+import (
+ "fmt"
+ "net"
+ "strconv"
+ "strings"
+
+ "github.com/containers/podman/v2/pkg/api/handlers"
+ "github.com/containers/podman/v2/pkg/domain/entities"
+ "github.com/containers/podman/v2/pkg/specgen"
+)
type ContainerCLIOpts struct {
Annotation []string
@@ -111,3 +120,283 @@ type ContainerCLIOpts struct {
CgroupConf []string
}
+
+func stringMaptoArray(m map[string]string) []string {
+ a := make([]string, 0, len(m))
+ for k, v := range m {
+ a = append(a, fmt.Sprintf("%s=%s", k, v))
+ }
+ return a
+}
+
+// ContainerCreateToContainerCLIOpts converts a compat input struct to cliopts so it can be converted to
+// a specgen spec.
+func ContainerCreateToContainerCLIOpts(cc handlers.CreateContainerConfig) (*ContainerCLIOpts, []string, error) {
+ var (
+ capAdd []string
+ cappDrop []string
+ entrypoint string
+ init bool
+ specPorts []specgen.PortMapping
+ )
+
+ if cc.HostConfig.Init != nil {
+ init = *cc.HostConfig.Init
+ }
+
+ // Iterate devices and convert back to string
+ devices := make([]string, 0, len(cc.HostConfig.Devices))
+ for _, dev := range cc.HostConfig.Devices {
+ devices = append(devices, fmt.Sprintf("%s:%s:%s", dev.PathOnHost, dev.PathInContainer, dev.CgroupPermissions))
+ }
+
+ // iterate blkreaddevicebps
+ readBps := make([]string, 0, len(cc.HostConfig.BlkioDeviceReadBps))
+ for _, dev := range cc.HostConfig.BlkioDeviceReadBps {
+ readBps = append(readBps, dev.String())
+ }
+
+ // iterate blkreaddeviceiops
+ readIops := make([]string, 0, len(cc.HostConfig.BlkioDeviceReadIOps))
+ for _, dev := range cc.HostConfig.BlkioDeviceReadIOps {
+ readIops = append(readIops, dev.String())
+ }
+
+ // iterate blkwritedevicebps
+ writeBps := make([]string, 0, len(cc.HostConfig.BlkioDeviceWriteBps))
+ for _, dev := range cc.HostConfig.BlkioDeviceWriteBps {
+ writeBps = append(writeBps, dev.String())
+ }
+
+ // iterate blkwritedeviceiops
+ writeIops := make([]string, 0, len(cc.HostConfig.BlkioDeviceWriteIOps))
+ for _, dev := range cc.HostConfig.BlkioDeviceWriteIOps {
+ writeIops = append(writeIops, dev.String())
+ }
+
+ // entrypoint
+ // can be a string or slice. if it is a slice, we need to
+ // marshall it to json; otherwise it should just be the string
+ // value
+ if len(cc.Config.Entrypoint) > 0 {
+ entrypoint = cc.Config.Entrypoint[0]
+ if len(cc.Config.Entrypoint) > 1 {
+ b, err := json.Marshal(cc.Config.Entrypoint)
+ if err != nil {
+ return nil, nil, err
+ }
+ entrypoint = string(b)
+ }
+ }
+
+ // expose ports
+ expose := make([]string, 0, len(cc.Config.ExposedPorts))
+ for p := range cc.Config.ExposedPorts {
+ expose = append(expose, fmt.Sprintf("%s/%s", p.Port(), p.Proto()))
+ }
+
+ // mounts type=tmpfs/bind,source=,dest=,opt=val
+ // TODO options
+ mounts := make([]string, 0, len(cc.HostConfig.Mounts))
+ for _, m := range cc.HostConfig.Mounts {
+ mount := fmt.Sprintf("type=%s", m.Type)
+ if len(m.Source) > 0 {
+ mount += fmt.Sprintf("source=%s", m.Source)
+ }
+ if len(m.Target) > 0 {
+ mount += fmt.Sprintf("dest=%s", m.Target)
+ }
+ mounts = append(mounts, mount)
+ }
+
+ //volumes
+ volumes := make([]string, 0, len(cc.Config.Volumes))
+ for v := range cc.Config.Volumes {
+ volumes = append(volumes, v)
+ }
+
+ // dns
+ dns := make([]net.IP, 0, len(cc.HostConfig.DNS))
+ for _, d := range cc.HostConfig.DNS {
+ dns = append(dns, net.ParseIP(d))
+ }
+
+ // publish
+ for port, pbs := range cc.HostConfig.PortBindings {
+ for _, pb := range pbs {
+ hostport, err := strconv.Atoi(pb.HostPort)
+ if err != nil {
+ return nil, nil, err
+ }
+ tmpPort := specgen.PortMapping{
+ HostIP: pb.HostIP,
+ ContainerPort: uint16(port.Int()),
+ HostPort: uint16(hostport),
+ Range: 0,
+ Protocol: port.Proto(),
+ }
+ specPorts = append(specPorts, tmpPort)
+ }
+ }
+
+ // network names
+ endpointsConfig := cc.NetworkingConfig.EndpointsConfig
+ cniNetworks := make([]string, 0, len(endpointsConfig))
+ for netName := range endpointsConfig {
+ cniNetworks = append(cniNetworks, netName)
+ }
+
+ // netMode
+ nsmode, _, err := specgen.ParseNetworkNamespace(cc.HostConfig.NetworkMode.NetworkName())
+ if err != nil {
+ return nil, nil, err
+ }
+
+ netNS := specgen.Namespace{
+ NSMode: nsmode.NSMode,
+ Value: nsmode.Value,
+ }
+
+ // network
+ // Note: we cannot emulate compat exactly here. we only allow specifics of networks to be
+ // defined when there is only one network.
+ netInfo := entities.NetOptions{
+ AddHosts: cc.HostConfig.ExtraHosts,
+ CNINetworks: cniNetworks,
+ DNSOptions: cc.HostConfig.DNSOptions,
+ DNSSearch: cc.HostConfig.DNSSearch,
+ DNSServers: dns,
+ Network: netNS,
+ PublishPorts: specPorts,
+ }
+
+ // static IP and MAC
+ if len(endpointsConfig) == 1 {
+ for _, ep := range endpointsConfig {
+ // if IP address is provided
+ if len(ep.IPAddress) > 0 {
+ staticIP := net.ParseIP(ep.IPAddress)
+ netInfo.StaticIP = &staticIP
+ }
+ // If MAC address is provided
+ if len(ep.MacAddress) > 0 {
+ staticMac, err := net.ParseMAC(ep.MacAddress)
+ if err != nil {
+ return nil, nil, err
+ }
+ netInfo.StaticMAC = &staticMac
+ }
+ break
+ }
+ }
+
+ // Note: several options here are marked as "don't need". this is based
+ // on speculation by Matt and I. We think that these come into play later
+ // like with start. We believe this is just a difference in podman/compat
+ cliOpts := ContainerCLIOpts{
+ //Attach: nil, // dont need?
+ Authfile: "",
+ BlkIOWeight: strconv.Itoa(int(cc.HostConfig.BlkioWeight)),
+ BlkIOWeightDevice: nil, // TODO
+ CapAdd: append(capAdd, cc.HostConfig.CapAdd...),
+ CapDrop: append(cappDrop, cc.HostConfig.CapDrop...),
+ CGroupParent: cc.HostConfig.CgroupParent,
+ CIDFile: cc.HostConfig.ContainerIDFile,
+ CPUPeriod: uint64(cc.HostConfig.CPUPeriod),
+ CPUQuota: cc.HostConfig.CPUQuota,
+ CPURTPeriod: uint64(cc.HostConfig.CPURealtimePeriod),
+ CPURTRuntime: cc.HostConfig.CPURealtimeRuntime,
+ CPUShares: uint64(cc.HostConfig.CPUShares),
+ //CPUS: 0, // dont need?
+ CPUSetCPUs: cc.HostConfig.CpusetCpus,
+ CPUSetMems: cc.HostConfig.CpusetMems,
+ //Detach: false, // dont need
+ //DetachKeys: "", // dont need
+ Devices: devices,
+ DeviceCGroupRule: nil,
+ DeviceReadBPs: readBps,
+ DeviceReadIOPs: readIops,
+ DeviceWriteBPs: writeBps,
+ DeviceWriteIOPs: writeIops,
+ Entrypoint: &entrypoint,
+ Env: cc.Config.Env,
+ Expose: expose,
+ GroupAdd: cc.HostConfig.GroupAdd,
+ Hostname: cc.Config.Hostname,
+ ImageVolume: "bind",
+ Init: init,
+ Interactive: cc.Config.OpenStdin,
+ IPC: string(cc.HostConfig.IpcMode),
+ Label: stringMaptoArray(cc.Config.Labels),
+ LogDriver: cc.HostConfig.LogConfig.Type,
+ LogOptions: stringMaptoArray(cc.HostConfig.LogConfig.Config),
+ Memory: strconv.Itoa(int(cc.HostConfig.Memory)),
+ MemoryReservation: strconv.Itoa(int(cc.HostConfig.MemoryReservation)),
+ MemorySwap: strconv.Itoa(int(cc.HostConfig.MemorySwap)),
+ Name: cc.Name,
+ OOMScoreAdj: cc.HostConfig.OomScoreAdj,
+ OverrideArch: "",
+ OverrideOS: "",
+ OverrideVariant: "",
+ PID: string(cc.HostConfig.PidMode),
+ PIDsLimit: cc.HostConfig.PidsLimit,
+ Privileged: cc.HostConfig.Privileged,
+ PublishAll: cc.HostConfig.PublishAllPorts,
+ Quiet: false,
+ ReadOnly: cc.HostConfig.ReadonlyRootfs,
+ ReadOnlyTmpFS: true, // podman default
+ Rm: cc.HostConfig.AutoRemove,
+ SecurityOpt: cc.HostConfig.SecurityOpt,
+ ShmSize: strconv.Itoa(int(cc.HostConfig.ShmSize)),
+ StopSignal: cc.Config.StopSignal,
+ StoreageOpt: stringMaptoArray(cc.HostConfig.StorageOpt),
+ Sysctl: stringMaptoArray(cc.HostConfig.Sysctls),
+ Systemd: "true", // podman default
+ TmpFS: stringMaptoArray(cc.HostConfig.Tmpfs),
+ TTY: cc.Config.Tty,
+ //Ulimit: cc.HostConfig.Ulimits, // ask dan, no documented format
+ User: cc.Config.User,
+ UserNS: string(cc.HostConfig.UsernsMode),
+ UTS: string(cc.HostConfig.UTSMode),
+ Mount: mounts,
+ Volume: volumes,
+ VolumesFrom: cc.HostConfig.VolumesFrom,
+ Workdir: cc.Config.WorkingDir,
+ Net: &netInfo,
+ }
+
+ if cc.Config.StopTimeout != nil {
+ cliOpts.StopTimeout = uint(*cc.Config.StopTimeout)
+ }
+
+ if cc.HostConfig.KernelMemory > 0 {
+ cliOpts.KernelMemory = strconv.Itoa(int(cc.HostConfig.KernelMemory))
+ }
+ if len(cc.HostConfig.RestartPolicy.Name) > 0 {
+ policy := cc.HostConfig.RestartPolicy.Name
+ // only add restart count on failure
+ if cc.HostConfig.RestartPolicy.IsOnFailure() {
+ policy += fmt.Sprintf(":%d", cc.HostConfig.RestartPolicy.MaximumRetryCount)
+ }
+ cliOpts.Restart = policy
+ }
+
+ if cc.HostConfig.MemorySwappiness != nil {
+ cliOpts.MemorySwappiness = *cc.HostConfig.MemorySwappiness
+ }
+ if cc.HostConfig.OomKillDisable != nil {
+ cliOpts.OOMKillDisable = *cc.HostConfig.OomKillDisable
+ }
+ if cc.Config.Healthcheck != nil {
+ cliOpts.HealthCmd = strings.Join(cc.Config.Healthcheck.Test, " ")
+ cliOpts.HealthInterval = cc.Config.Healthcheck.Interval.String()
+ cliOpts.HealthRetries = uint(cc.Config.Healthcheck.Retries)
+ cliOpts.HealthStartPeriod = cc.Config.Healthcheck.StartPeriod.String()
+ cliOpts.HealthTimeout = cc.Config.Healthcheck.Timeout.String()
+ }
+
+ // specgen assumes the image name is arg[0]
+ cmd := []string{cc.Image}
+ cmd = append(cmd, cc.Config.Cmd...)
+ return &cliOpts, cmd, nil
+}