summaryrefslogtreecommitdiff
path: root/cmd/podman/spec.go
diff options
context:
space:
mode:
Diffstat (limited to 'cmd/podman/spec.go')
-rw-r--r--cmd/podman/spec.go211
1 files changed, 143 insertions, 68 deletions
diff --git a/cmd/podman/spec.go b/cmd/podman/spec.go
index d630b2f50..cb9efdcb2 100644
--- a/cmd/podman/spec.go
+++ b/cmd/podman/spec.go
@@ -1,14 +1,14 @@
package main
import (
- "encoding/json"
- "fmt"
"io/ioutil"
+ "strconv"
"strings"
"github.com/cri-o/ocicni/pkg/ocicni"
"github.com/docker/docker/daemon/caps"
"github.com/docker/docker/pkg/mount"
+ "github.com/docker/docker/profiles/seccomp"
"github.com/docker/go-units"
"github.com/opencontainers/runc/libcontainer/devices"
spec "github.com/opencontainers/runtime-spec/specs-go"
@@ -21,6 +21,8 @@ import (
"golang.org/x/sys/unix"
)
+const cpuPeriod = 100000
+
func blockAccessToKernelFilesystems(config *createConfig, g *generate.Generator) {
if !config.Privileged {
for _, mp := range []string{
@@ -51,21 +53,10 @@ func blockAccessToKernelFilesystems(config *createConfig, g *generate.Generator)
func addPidNS(config *createConfig, g *generate.Generator) error {
pidMode := config.PidMode
if pidMode.IsHost() {
- return g.RemoveLinuxNamespace(libpod.PIDNamespace)
+ return g.RemoveLinuxNamespace(string(spec.PIDNamespace))
}
if pidMode.IsContainer() {
- ctr, err := config.Runtime.LookupContainer(pidMode.Container())
- if err != nil {
- return errors.Wrapf(err, "container %q not found", pidMode.Container())
- }
- pid, err := ctr.PID()
- if err != nil {
- return errors.Wrapf(err, "Failed to get pid of container %q", pidMode.Container())
- }
- pidNsPath := fmt.Sprintf("/proc/%d/ns/pid", pid)
- if err := g.AddOrReplaceLinuxNamespace(libpod.PIDNamespace, pidNsPath); err != nil {
- return err
- }
+ logrus.Debug("using container pidmode")
}
return nil
}
@@ -74,7 +65,7 @@ func addNetNS(config *createConfig, g *generate.Generator) error {
netMode := config.NetMode
if netMode.IsHost() {
logrus.Debug("Using host netmode")
- return g.RemoveLinuxNamespace(libpod.NetNamespace)
+ return g.RemoveLinuxNamespace(spec.NetworkNamespace)
} else if netMode.IsNone() {
logrus.Debug("Using none netmode")
return nil
@@ -83,18 +74,6 @@ func addNetNS(config *createConfig, g *generate.Generator) error {
return nil
} else if netMode.IsContainer() {
logrus.Debug("Using container netmode")
- ctr, err := config.Runtime.LookupContainer(netMode.ConnectedContainer())
- if err != nil {
- return errors.Wrapf(err, "container %q not found", netMode.ConnectedContainer())
- }
- pid, err := ctr.PID()
- if err != nil {
- return errors.Wrapf(err, "Failed to get pid of container %q", netMode.ConnectedContainer())
- }
- nsPath := fmt.Sprintf("/proc/%d/ns/net", pid)
- if err := g.AddOrReplaceLinuxNamespace(libpod.NetNamespace, nsPath); err != nil {
- return err
- }
} else {
return errors.Errorf("unknown network mode")
}
@@ -104,7 +83,7 @@ func addNetNS(config *createConfig, g *generate.Generator) error {
func addUTSNS(config *createConfig, g *generate.Generator) error {
utsMode := config.UtsMode
if utsMode.IsHost() {
- return g.RemoveLinuxNamespace(libpod.UTSNamespace)
+ return g.RemoveLinuxNamespace(spec.UTSNamespace)
}
return nil
}
@@ -112,21 +91,10 @@ func addUTSNS(config *createConfig, g *generate.Generator) error {
func addIpcNS(config *createConfig, g *generate.Generator) error {
ipcMode := config.IpcMode
if ipcMode.IsHost() {
- return g.RemoveLinuxNamespace(libpod.IPCNamespace)
+ return g.RemoveLinuxNamespace(spec.IPCNamespace)
}
if ipcMode.IsContainer() {
- ctr, err := config.Runtime.LookupContainer(ipcMode.Container())
- if err != nil {
- return errors.Wrapf(err, "container %q not found", ipcMode.Container())
- }
- pid, err := ctr.PID()
- if err != nil {
- return errors.Wrapf(err, "Failed to get pid of container %q", ipcMode.Container())
- }
- nsPath := fmt.Sprintf("/proc/%d/ns/ipc", pid)
- if err := g.AddOrReplaceLinuxNamespace(libpod.IPCNamespace, nsPath); err != nil {
- return err
- }
+ logrus.Debug("Using container ipcmode")
}
return nil
@@ -143,7 +111,7 @@ func addRlimits(config *createConfig, g *generate.Generator) error {
return errors.Wrapf(err, "ulimit option %q requires name=SOFT:HARD, failed to be parsed", u)
}
- g.AddProcessRlimits("RLIMIT_"+strings.ToUpper(ul.Name), uint64(ul.Soft), uint64(ul.Hard))
+ g.AddProcessRlimits("RLIMIT_"+strings.ToUpper(ul.Name), uint64(ul.Hard), uint64(ul.Soft))
}
return nil
}
@@ -210,10 +178,8 @@ func createConfigToOCISpec(config *createConfig) (*spec.Spec, error) {
if config.Hostname != "" {
g.AddProcessEnv("HOSTNAME", config.Hostname)
}
-
- for _, sysctl := range config.Sysctl {
- s := strings.SplitN(sysctl, "=", 2)
- g.AddLinuxSysctl(s[0], s[1])
+ for sysctlKey, sysctlVal := range config.Sysctl {
+ g.AddLinuxSysctl(sysctlKey, sysctlVal)
}
// RESOURCES - MEMORY
@@ -236,7 +202,6 @@ func createConfigToOCISpec(config *createConfig) (*spec.Spec, error) {
g.SetProcessOOMScoreAdj(config.Resources.OomScoreAdj)
// RESOURCES - CPU
-
if config.Resources.CPUShares != 0 {
g.SetLinuxResourcesCPUShares(config.Resources.CPUShares)
}
@@ -246,14 +211,18 @@ func createConfigToOCISpec(config *createConfig) (*spec.Spec, error) {
if config.Resources.CPUPeriod != 0 {
g.SetLinuxResourcesCPUPeriod(config.Resources.CPUPeriod)
}
+ if config.Resources.CPUs != 0 {
+ g.SetLinuxResourcesCPUPeriod(cpuPeriod)
+ g.SetLinuxResourcesCPUQuota(int64(config.Resources.CPUs * cpuPeriod))
+ }
if config.Resources.CPURtRuntime != 0 {
g.SetLinuxResourcesCPURealtimeRuntime(config.Resources.CPURtRuntime)
}
if config.Resources.CPURtPeriod != 0 {
g.SetLinuxResourcesCPURealtimePeriod(config.Resources.CPURtPeriod)
}
- if config.Resources.CPUs != "" {
- g.SetLinuxResourcesCPUCpus(config.Resources.CPUs)
+ if config.Resources.CPUsetCPUs != "" {
+ g.SetLinuxResourcesCPUCpus(config.Resources.CPUsetCPUs)
}
if config.Resources.CPUsetMems != "" {
g.SetLinuxResourcesCPUMems(config.Resources.CPUsetMems)
@@ -322,16 +291,31 @@ func createConfigToOCISpec(config *createConfig) (*spec.Spec, error) {
}
configSpec := g.Spec()
- if config.SeccompProfilePath != "" && config.SeccompProfilePath != "unconfined" {
- seccompProfile, err := ioutil.ReadFile(config.SeccompProfilePath)
- if err != nil {
- return nil, errors.Wrapf(err, "opening seccomp profile (%s) failed", config.SeccompProfilePath)
- }
- var seccompConfig spec.LinuxSeccomp
- if err := json.Unmarshal(seccompProfile, &seccompConfig); err != nil {
- return nil, errors.Wrapf(err, "decoding seccomp profile (%s) failed", config.SeccompProfilePath)
+ // HANDLE CAPABILITIES
+ // NOTE: Must happen before SECCOMP
+ if err := setupCapabilities(config, configSpec); err != nil {
+ return nil, err
+ }
+
+ // HANDLE SECCOMP
+ if config.SeccompProfilePath != "unconfined" {
+ if config.SeccompProfilePath != "" {
+ seccompProfile, err := ioutil.ReadFile(config.SeccompProfilePath)
+ if err != nil {
+ return nil, errors.Wrapf(err, "opening seccomp profile (%s) failed", config.SeccompProfilePath)
+ }
+ seccompConfig, err := seccomp.LoadProfile(string(seccompProfile), configSpec)
+ if err != nil {
+ return nil, errors.Wrapf(err, "loading seccomp profile (%s) failed", config.SeccompProfilePath)
+ }
+ configSpec.Linux.Seccomp = seccompConfig
+ } else {
+ seccompConfig, err := seccomp.GetDefaultProfile(configSpec)
+ if err != nil {
+ return nil, errors.Wrapf(err, "loading seccomp profile (%s) failed", config.SeccompProfilePath)
+ }
+ configSpec.Linux.Seccomp = seccompConfig
}
- configSpec.Linux.Seccomp = &seccompConfig
}
// BIND MOUNTS
@@ -351,9 +335,13 @@ func createConfigToOCISpec(config *createConfig) (*spec.Spec, error) {
}
}
- // HANDLE CAPABILITIES
- if err := setupCapabilities(config, configSpec); err != nil {
- return nil, err
+ // BLOCK IO
+ blkio, err := config.CreateBlockIO()
+ if err != nil {
+ return nil, errors.Wrapf(err, "error creating block io")
+ }
+ if blkio != nil {
+ configSpec.Linux.Resources.BlockIO = blkio
}
/*
@@ -383,8 +371,8 @@ func createConfigToOCISpec(config *createConfig) (*spec.Spec, error) {
return configSpec, nil
}
-func (c *createConfig) CreateBlockIO() (spec.LinuxBlockIO, error) {
- bio := spec.LinuxBlockIO{}
+func (c *createConfig) CreateBlockIO() (*spec.LinuxBlockIO, error) {
+ bio := &spec.LinuxBlockIO{}
bio.Weight = &c.Resources.BlkioWeight
if len(c.Resources.BlkioWeightDevice) > 0 {
var lwds []spec.LinuxWeightDevice
@@ -401,6 +389,7 @@ func (c *createConfig) CreateBlockIO() (spec.LinuxBlockIO, error) {
lwd.Minor = int64(unix.Minor(wdStat.Rdev))
lwds = append(lwds, lwd)
}
+ bio.WeightDevice = lwds
}
if len(c.Resources.DeviceReadBps) > 0 {
readBps, err := makeThrottleArray(c.Resources.DeviceReadBps)
@@ -430,7 +419,6 @@ func (c *createConfig) CreateBlockIO() (spec.LinuxBlockIO, error) {
}
bio.ThrottleWriteIOPSDevice = writeIOps
}
-
return bio, nil
}
@@ -556,6 +544,8 @@ func (c *createConfig) GetTmpfsMounts() []spec.Mount {
func (c *createConfig) GetContainerCreateOptions() ([]libpod.CtrCreateOption, error) {
var options []libpod.CtrCreateOption
+ var portBindings []ocicni.PortMapping
+ var err error
// Uncomment after talking to mheon about unimplemented funcs
// options = append(options, libpod.WithLabels(c.labels))
@@ -567,12 +557,57 @@ func (c *createConfig) GetContainerCreateOptions() ([]libpod.CtrCreateOption, er
logrus.Debugf("appending name %s", c.Name)
options = append(options, libpod.WithName(c.Name))
}
- // TODO parse ports into libpod format and include
- if !c.NetMode.IsHost() {
- options = append(options, libpod.WithNetNS([]ocicni.PortMapping{}))
+
+ // TODO deal with ports defined in image metadata
+ if len(c.PortBindings) > 0 || len(c.ExposedPorts) > 0 {
+ portBindings, err = c.CreatePortBindings()
+ if err != nil {
+ return nil, errors.Wrapf(err, "unable to create port bindings")
+ }
+ }
+
+ if c.NetMode.IsContainer() {
+ connectedCtr, err := c.Runtime.LookupContainer(c.NetMode.ConnectedContainer())
+ if err != nil {
+ return nil, errors.Wrapf(err, "container %q not found", c.NetMode.ConnectedContainer())
+ }
+ options = append(options, libpod.WithNetNSFrom(connectedCtr))
+ } else if !c.NetMode.IsHost() {
+ options = append(options, libpod.WithNetNS(portBindings))
+ }
+
+ if c.PidMode.IsContainer() {
+ connectedCtr, err := c.Runtime.LookupContainer(c.PidMode.Container())
+ if err != nil {
+ return nil, errors.Wrapf(err, "container %q not found", c.PidMode.Container())
+ }
+
+ options = append(options, libpod.WithPIDNSFrom(connectedCtr))
+ }
+ if c.IpcMode.IsContainer() {
+ connectedCtr, err := c.Runtime.LookupContainer(c.IpcMode.Container())
+ if err != nil {
+ return nil, errors.Wrapf(err, "container %q not found", c.IpcMode.Container())
+ }
+
+ options = append(options, libpod.WithIPCNSFrom(connectedCtr))
}
+
options = append(options, libpod.WithStopSignal(c.StopSignal))
options = append(options, libpod.WithStopTimeout(c.StopTimeout))
+ if len(c.DNSSearch) > 0 {
+ options = append(options, libpod.WithDNSSearch(c.DNSSearch))
+ }
+ if len(c.DNSServers) > 0 {
+ options = append(options, libpod.WithDNS(c.DNSServers))
+ }
+ if len(c.DNSOpt) > 0 {
+ options = append(options, libpod.WithDNSOption(c.DNSOpt))
+ }
+ if len(c.HostAdd) > 0 {
+ options = append(options, libpod.WithHosts(c.HostAdd))
+ }
+
return options, nil
}
@@ -598,3 +633,43 @@ func makeThrottleArray(throttleInput []string) ([]spec.LinuxThrottleDevice, erro
}
return ltds, nil
}
+
+// CreatePortBindings iterates ports mappings and exposed ports into a format CNI understands
+func (c *createConfig) CreatePortBindings() ([]ocicni.PortMapping, error) {
+ var portBindings []ocicni.PortMapping
+ for containerPb, hostPb := range c.PortBindings {
+ var pm ocicni.PortMapping
+ pm.ContainerPort = int32(containerPb.Int())
+ for _, i := range hostPb {
+ var hostPort int
+ var err error
+ pm.HostIP = i.HostIP
+ if i.HostPort == "" {
+ hostPort = containerPb.Int()
+ } else {
+ hostPort, err = strconv.Atoi(i.HostPort)
+ if err != nil {
+ return nil, errors.Wrapf(err, "unable to convert host port to integer")
+ }
+ }
+
+ pm.HostPort = int32(hostPort)
+ // CNI requires us to make both udp and tcp structs
+ pm.Protocol = "udp"
+ portBindings = append(portBindings, pm)
+ pm.Protocol = "tcp"
+ portBindings = append(portBindings, pm)
+ }
+ }
+ for j := range c.ExposedPorts {
+ var expose ocicni.PortMapping
+ expose.HostPort = int32(j.Int())
+ expose.ContainerPort = int32(j.Int())
+ // CNI requires us to make both udp and tcp structs
+ expose.Protocol = "udp"
+ portBindings = append(portBindings, expose)
+ expose.Protocol = "tcp"
+ portBindings = append(portBindings, expose)
+ }
+ return portBindings, nil
+}