summaryrefslogtreecommitdiff
path: root/pkg/specgen
diff options
context:
space:
mode:
Diffstat (limited to 'pkg/specgen')
-rw-r--r--pkg/specgen/container_validate.go22
-rw-r--r--pkg/specgen/generate/container.go4
-rw-r--r--pkg/specgen/generate/container_create.go129
-rw-r--r--pkg/specgen/generate/namespaces.go40
-rw-r--r--pkg/specgen/generate/oci.go45
-rw-r--r--pkg/specgen/generate/pod_create.go18
-rw-r--r--pkg/specgen/generate/validate.go4
-rw-r--r--pkg/specgen/namespaces.go177
-rw-r--r--pkg/specgen/namespaces_test.go265
-rw-r--r--pkg/specgen/pod_validate.go23
-rw-r--r--pkg/specgen/podspecgen.go40
-rw-r--r--pkg/specgen/specgen.go29
12 files changed, 629 insertions, 167 deletions
diff --git a/pkg/specgen/container_validate.go b/pkg/specgen/container_validate.go
index caea51ea8..d06a047c1 100644
--- a/pkg/specgen/container_validate.go
+++ b/pkg/specgen/container_validate.go
@@ -29,25 +29,10 @@ func exclusiveOptions(opt1, opt2 string) error {
// Validate verifies that the given SpecGenerator is valid and satisfies required
// input for creating a container.
func (s *SpecGenerator) Validate() error {
- if rootless.IsRootless() && len(s.CNINetworks) == 0 {
- if s.StaticIP != nil || s.StaticIPv6 != nil {
- return ErrNoStaticIPRootless
- }
- if s.StaticMAC != nil {
- return ErrNoStaticMACRootless
- }
- }
-
// Containers being added to a pod cannot have certain network attributes
// associated with them because those should be on the infra container.
if len(s.Pod) > 0 && s.NetNS.NSMode == FromPod {
- if s.StaticIP != nil || s.StaticIPv6 != nil {
- return errors.Wrap(define.ErrNetworkOnPodContainer, "static ip addresses must be defined when the pod is created")
- }
- if s.StaticMAC != nil {
- return errors.Wrap(define.ErrNetworkOnPodContainer, "MAC addresses must be defined when the pod is created")
- }
- if len(s.CNINetworks) > 0 {
+ if len(s.Networks) > 0 {
return errors.Wrap(define.ErrNetworkOnPodContainer, "networks must be defined when the pod is created")
}
if len(s.PortMappings) > 0 || s.PublishExposedPorts {
@@ -204,5 +189,10 @@ func (s *SpecGenerator) Validate() error {
if err := validateNetNS(&s.NetNS); err != nil {
return err
}
+ if s.NetNS.NSMode != Bridge && len(s.Networks) > 0 {
+ // Note that we also get the ip and mac in the networks map
+ return errors.New("Networks and static ip/mac address can only be used with Bridge mode networking")
+ }
+
return nil
}
diff --git a/pkg/specgen/generate/container.go b/pkg/specgen/generate/container.go
index 40a18a6ac..57676db10 100644
--- a/pkg/specgen/generate/container.go
+++ b/pkg/specgen/generate/container.go
@@ -156,7 +156,9 @@ func CompleteSpec(ctx context.Context, r *libpod.Runtime, s *specgen.SpecGenerat
// Add annotations from the image
for k, v := range inspectData.Annotations {
- annotations[k] = v
+ if !define.IsReservedAnnotation(k) {
+ annotations[k] = v
+ }
}
}
diff --git a/pkg/specgen/generate/container_create.go b/pkg/specgen/generate/container_create.go
index df5d2e8ff..7d792b3b1 100644
--- a/pkg/specgen/generate/container_create.go
+++ b/pkg/specgen/generate/container_create.go
@@ -2,13 +2,15 @@ package generate
import (
"context"
- "fmt"
+ "encoding/json"
"path/filepath"
"strings"
cdi "github.com/container-orchestrated-devices/container-device-interface/pkg"
"github.com/containers/common/libimage"
"github.com/containers/podman/v3/libpod"
+ "github.com/containers/podman/v3/libpod/define"
+ "github.com/containers/podman/v3/pkg/namespaces"
"github.com/containers/podman/v3/pkg/specgen"
"github.com/containers/podman/v3/pkg/util"
spec "github.com/opencontainers/runtime-spec/specs-go"
@@ -28,43 +30,30 @@ func MakeContainer(ctx context.Context, rt *libpod.Runtime, s *specgen.SpecGener
// If joining a pod, retrieve the pod for use, and its infra container
var pod *libpod.Pod
- var infraConfig *libpod.ContainerConfig
+ var infra *libpod.Container
if s.Pod != "" {
pod, err = rt.LookupPod(s.Pod)
if err != nil {
return nil, nil, nil, errors.Wrapf(err, "error retrieving pod %s", s.Pod)
}
if pod.HasInfraContainer() {
- infra, err := pod.InfraContainer()
+ infra, err = pod.InfraContainer()
if err != nil {
return nil, nil, nil, err
}
- infraConfig = infra.Config()
}
}
- if infraConfig != nil && (len(infraConfig.NamedVolumes) > 0 || len(infraConfig.UserVolumes) > 0 || len(infraConfig.ImageVolumes) > 0 || len(infraConfig.OverlayVolumes) > 0) {
- s.VolumesFrom = append(s.VolumesFrom, infraConfig.ID)
- }
-
- if infraConfig != nil && len(infraConfig.Spec.Linux.Devices) > 0 {
- s.DevicesFrom = append(s.DevicesFrom, infraConfig.ID)
- }
- if infraConfig != nil && infraConfig.Spec.Linux.Resources != nil && infraConfig.Spec.Linux.Resources.BlockIO != nil && len(infraConfig.Spec.Linux.Resources.BlockIO.ThrottleReadBpsDevice) > 0 {
- tempDev := make(map[string]spec.LinuxThrottleDevice)
- for _, val := range infraConfig.Spec.Linux.Resources.BlockIO.ThrottleReadBpsDevice {
- nodes, err := util.FindDeviceNodes()
- if err != nil {
- return nil, nil, nil, err
- }
- key := fmt.Sprintf("%d:%d", val.Major, val.Minor)
- tempDev[nodes[key]] = spec.LinuxThrottleDevice{Rate: uint64(val.Rate)}
- }
- for i, dev := range s.ThrottleReadBpsDevice {
- tempDev[i] = dev
+ options := []libpod.CtrCreateOption{}
+ compatibleOptions := &libpod.InfraInherit{}
+ var infraSpec *spec.Spec
+ if infra != nil {
+ options, infraSpec, compatibleOptions, err = Inherit(*infra)
+ if err != nil {
+ return nil, nil, nil, err
}
- s.ThrottleReadBpsDevice = tempDev
}
+
if err := FinishThrottleDevices(s); err != nil {
return nil, nil, nil, err
}
@@ -96,6 +85,12 @@ func MakeContainer(ctx context.Context, rt *libpod.Runtime, s *specgen.SpecGener
return nil, nil, nil, err
}
s.UserNS = defaultNS
+
+ mappings, err := util.ParseIDMapping(namespaces.UsernsMode(s.UserNS.NSMode), nil, nil, "", "")
+ if err != nil {
+ return nil, nil, nil, err
+ }
+ s.IDMappings = mappings
}
if s.NetNS.IsDefault() {
defaultNS, err := GetDefaultNamespaceMode("net", rtc, pod)
@@ -112,8 +107,6 @@ func MakeContainer(ctx context.Context, rt *libpod.Runtime, s *specgen.SpecGener
s.CgroupNS = defaultNS
}
- options := []libpod.CtrCreateOption{}
-
if s.ContainerCreateCommand != nil {
options = append(options, libpod.WithCreateCommand(s.ContainerCreateCommand))
}
@@ -149,21 +142,22 @@ func MakeContainer(ctx context.Context, rt *libpod.Runtime, s *specgen.SpecGener
return nil, nil, nil, err
}
+ if len(s.HostUsers) > 0 {
+ options = append(options, libpod.WithHostUsers(s.HostUsers))
+ }
+
command, err := makeCommand(ctx, s, imageData, rtc)
if err != nil {
return nil, nil, nil, err
}
- opts, err := createContainerOptions(ctx, rt, s, pod, finalVolumes, finalOverlays, imageData, command)
+ infraVolumes := (len(compatibleOptions.InfraVolumes) > 0 || len(compatibleOptions.InfraUserVolumes) > 0 || len(compatibleOptions.InfraImageVolumes) > 0)
+ opts, err := createContainerOptions(ctx, rt, s, pod, finalVolumes, finalOverlays, imageData, command, infraVolumes, *compatibleOptions)
if err != nil {
return nil, nil, nil, err
}
options = append(options, opts...)
- if len(s.Aliases) > 0 {
- options = append(options, libpod.WithNetworkAliases(s.Aliases))
- }
-
if containerType := s.InitContainerType; len(containerType) > 0 {
options = append(options, libpod.WithInitCtrType(containerType))
}
@@ -171,27 +165,29 @@ func MakeContainer(ctx context.Context, rt *libpod.Runtime, s *specgen.SpecGener
logrus.Debugf("setting container name %s", s.Name)
options = append(options, libpod.WithName(s.Name))
}
- if len(s.DevicesFrom) > 0 {
- for _, dev := range s.DevicesFrom {
- ctr, err := rt.GetContainer(dev)
- if err != nil {
- return nil, nil, nil, err
- }
- devices := ctr.DeviceHostSrc()
- s.Devices = append(s.Devices, devices...)
- }
- }
if len(s.Devices) > 0 {
- opts = extractCDIDevices(s)
+ opts = ExtractCDIDevices(s)
options = append(options, opts...)
}
- runtimeSpec, err := SpecGenToOCI(ctx, s, rt, rtc, newImage, finalMounts, pod, command)
+ runtimeSpec, err := SpecGenToOCI(ctx, s, rt, rtc, newImage, finalMounts, pod, command, compatibleOptions)
if err != nil {
return nil, nil, nil, err
}
if len(s.HostDeviceList) > 0 {
options = append(options, libpod.WithHostDevice(s.HostDeviceList))
}
+ if infraSpec != nil && infraSpec.Linux != nil { // if we are inheriting Linux info from a pod...
+ // Pass Security annotations
+ if len(infraSpec.Annotations[define.InspectAnnotationLabel]) > 0 && len(runtimeSpec.Annotations[define.InspectAnnotationLabel]) == 0 {
+ runtimeSpec.Annotations[define.InspectAnnotationLabel] = infraSpec.Annotations[define.InspectAnnotationLabel]
+ }
+ if len(infraSpec.Annotations[define.InspectAnnotationSeccomp]) > 0 && len(runtimeSpec.Annotations[define.InspectAnnotationSeccomp]) == 0 {
+ runtimeSpec.Annotations[define.InspectAnnotationSeccomp] = infraSpec.Annotations[define.InspectAnnotationSeccomp]
+ }
+ if len(infraSpec.Annotations[define.InspectAnnotationApparmor]) > 0 && len(runtimeSpec.Annotations[define.InspectAnnotationApparmor]) == 0 {
+ runtimeSpec.Annotations[define.InspectAnnotationApparmor] = infraSpec.Annotations[define.InspectAnnotationApparmor]
+ }
+ }
return runtimeSpec, s, options, err
}
func ExecuteCreate(ctx context.Context, rt *libpod.Runtime, runtimeSpec *spec.Spec, s *specgen.SpecGenerator, infra bool, options ...libpod.CtrCreateOption) (*libpod.Container, error) {
@@ -203,7 +199,7 @@ func ExecuteCreate(ctx context.Context, rt *libpod.Runtime, runtimeSpec *spec.Sp
return ctr, rt.PrepareVolumeOnCreateContainer(ctx, ctr)
}
-func extractCDIDevices(s *specgen.SpecGenerator) []libpod.CtrCreateOption {
+func ExtractCDIDevices(s *specgen.SpecGenerator) []libpod.CtrCreateOption {
devs := make([]spec.LinuxDevice, 0, len(s.Devices))
var cdiDevs []string
var options []libpod.CtrCreateOption
@@ -217,19 +213,16 @@ func extractCDIDevices(s *specgen.SpecGenerator) []libpod.CtrCreateOption {
cdiDevs = append(cdiDevs, device.Path)
continue
}
-
devs = append(devs, device)
}
-
s.Devices = devs
if len(cdiDevs) > 0 {
options = append(options, libpod.WithCDI(cdiDevs))
}
-
return options
}
-func createContainerOptions(ctx context.Context, rt *libpod.Runtime, s *specgen.SpecGenerator, pod *libpod.Pod, volumes []*specgen.NamedVolume, overlays []*specgen.OverlayVolume, imageData *libimage.ImageData, command []string) ([]libpod.CtrCreateOption, error) {
+func createContainerOptions(ctx context.Context, rt *libpod.Runtime, s *specgen.SpecGenerator, pod *libpod.Pod, volumes []*specgen.NamedVolume, overlays []*specgen.OverlayVolume, imageData *libimage.ImageData, command []string, infraVolumes bool, compatibleOptions libpod.InfraInherit) ([]libpod.CtrCreateOption, error) {
var options []libpod.CtrCreateOption
var err error
@@ -310,7 +303,10 @@ func createContainerOptions(ctx context.Context, rt *libpod.Runtime, s *specgen.
for _, imageVolume := range s.ImageVolumes {
destinations = append(destinations, imageVolume.Destination)
}
- options = append(options, libpod.WithUserVolumes(destinations))
+
+ if len(destinations) > 0 || !infraVolumes {
+ options = append(options, libpod.WithUserVolumes(destinations))
+ }
if len(volumes) != 0 {
var vols []*libpod.ContainerNamedVolume
@@ -398,7 +394,7 @@ func createContainerOptions(ctx context.Context, rt *libpod.Runtime, s *specgen.
if len(s.SelinuxOpts) > 0 {
options = append(options, libpod.WithSecLabels(s.SelinuxOpts))
} else {
- if pod != nil {
+ if pod != nil && len(compatibleOptions.InfraLabels) == 0 {
// duplicate the security options from the pod
processLabel, err := pod.ProcessLabel()
if err != nil {
@@ -486,5 +482,38 @@ func createContainerOptions(ctx context.Context, rt *libpod.Runtime, s *specgen.
if s.PidFile != "" {
options = append(options, libpod.WithPidFile(s.PidFile))
}
+
+ options = append(options, libpod.WithSelectedPasswordManagement(s.Passwd))
+
return options, nil
}
+
+func Inherit(infra libpod.Container) (opts []libpod.CtrCreateOption, infraS *spec.Spec, compat *libpod.InfraInherit, err error) {
+ options := []libpod.CtrCreateOption{}
+ compatibleOptions := &libpod.InfraInherit{}
+ infraConf := infra.Config()
+ infraSpec := infraConf.Spec
+
+ config, err := json.Marshal(infraConf)
+ if err != nil {
+ return nil, nil, nil, err
+ }
+ err = json.Unmarshal(config, compatibleOptions)
+ if err != nil {
+ return nil, nil, nil, err
+ }
+ if infraSpec.Linux != nil && infraSpec.Linux.Resources != nil {
+ resources, err := json.Marshal(infraSpec.Linux.Resources)
+ if err != nil {
+ return nil, nil, nil, err
+ }
+ err = json.Unmarshal(resources, &compatibleOptions.InfraResources)
+ if err != nil {
+ return nil, nil, nil, err
+ }
+ }
+ if compatibleOptions != nil {
+ options = append(options, libpod.WithInfraConfig(*compatibleOptions))
+ }
+ return options, infraSpec, compatibleOptions, nil
+}
diff --git a/pkg/specgen/generate/namespaces.go b/pkg/specgen/generate/namespaces.go
index 7d63fc10f..a2bc37e34 100644
--- a/pkg/specgen/generate/namespaces.go
+++ b/pkg/specgen/generate/namespaces.go
@@ -10,6 +10,7 @@ import (
"github.com/containers/common/pkg/config"
"github.com/containers/podman/v3/libpod"
"github.com/containers/podman/v3/libpod/define"
+ "github.com/containers/podman/v3/libpod/network/types"
"github.com/containers/podman/v3/pkg/rootless"
"github.com/containers/podman/v3/pkg/specgen"
"github.com/containers/podman/v3/pkg/util"
@@ -66,7 +67,7 @@ func GetDefaultNamespaceMode(nsType string, cfg *config.Config, pod *libpod.Pod)
case "cgroup":
return specgen.ParseCgroupNamespace(cfg.Containers.CgroupNS)
case "net":
- ns, _, err := specgen.ParseNetworkNamespace(cfg.Containers.NetNS, cfg.Containers.RootlessNetworking == "cni")
+ ns, _, _, err := specgen.ParseNetworkFlag(nil)
return ns, err
}
@@ -250,7 +251,7 @@ func namespaceOptions(ctx context.Context, s *specgen.SpecGenerator, rt *libpod.
if s.NetNS.Value != "" {
val = fmt.Sprintf("slirp4netns:%s", s.NetNS.Value)
}
- toReturn = append(toReturn, libpod.WithNetNS(portMappings, expose, postConfigureNetNS, val, s.CNINetworks))
+ toReturn = append(toReturn, libpod.WithNetNS(portMappings, expose, postConfigureNetNS, val, nil))
case specgen.Private:
fallthrough
case specgen.Bridge:
@@ -258,7 +259,34 @@ func namespaceOptions(ctx context.Context, s *specgen.SpecGenerator, rt *libpod.
if err != nil {
return nil, err
}
- toReturn = append(toReturn, libpod.WithNetNS(portMappings, expose, postConfigureNetNS, "bridge", s.CNINetworks))
+
+ rtConfig, err := rt.GetConfigNoCopy()
+ if err != nil {
+ return nil, err
+ }
+ // if no network was specified use add the default
+ if len(s.Networks) == 0 {
+ // backwards config still allow the old cni networks list and convert to new format
+ if len(s.CNINetworks) > 0 {
+ logrus.Warn(`specgen "cni_networks" option is deprecated use the "networks" map instead`)
+ networks := make(map[string]types.PerNetworkOptions, len(s.CNINetworks))
+ for _, net := range s.CNINetworks {
+ networks[net] = types.PerNetworkOptions{}
+ }
+ s.Networks = networks
+ } else {
+ // no networks given but bridge is set so use default network
+ s.Networks = map[string]types.PerNetworkOptions{
+ rtConfig.Network.DefaultNetwork: {},
+ }
+ }
+ }
+ // rename the "default" network to the correct default name
+ if opts, ok := s.Networks["default"]; ok {
+ s.Networks[rtConfig.Network.DefaultNetwork] = opts
+ delete(s.Networks, "default")
+ }
+ toReturn = append(toReturn, libpod.WithNetNS(portMappings, expose, postConfigureNetNS, "bridge", s.Networks))
}
if s.UseImageHosts {
@@ -281,12 +309,6 @@ func namespaceOptions(ctx context.Context, s *specgen.SpecGenerator, rt *libpod.
if len(s.DNSOptions) > 0 {
toReturn = append(toReturn, libpod.WithDNSOption(s.DNSOptions))
}
- if s.StaticIP != nil {
- toReturn = append(toReturn, libpod.WithStaticIP(*s.StaticIP))
- }
- if s.StaticMAC != nil {
- toReturn = append(toReturn, libpod.WithStaticMAC(*s.StaticMAC))
- }
if s.NetworkOptions != nil {
toReturn = append(toReturn, libpod.WithNetworkOptions(s.NetworkOptions))
}
diff --git a/pkg/specgen/generate/oci.go b/pkg/specgen/generate/oci.go
index 9f8807915..ee3a990fc 100644
--- a/pkg/specgen/generate/oci.go
+++ b/pkg/specgen/generate/oci.go
@@ -2,6 +2,7 @@ package generate
import (
"context"
+ "encoding/json"
"path"
"strings"
@@ -174,7 +175,7 @@ func getCGroupPermissons(unmask []string) string {
}
// SpecGenToOCI returns the base configuration for the container.
-func SpecGenToOCI(ctx context.Context, s *specgen.SpecGenerator, rt *libpod.Runtime, rtc *config.Config, newImage *libimage.Image, mounts []spec.Mount, pod *libpod.Pod, finalCmd []string) (*spec.Spec, error) {
+func SpecGenToOCI(ctx context.Context, s *specgen.SpecGenerator, rt *libpod.Runtime, rtc *config.Config, newImage *libimage.Image, mounts []spec.Mount, pod *libpod.Pod, finalCmd []string, compatibleOptions *libpod.InfraInherit) (*spec.Spec, error) {
cgroupPerm := getCGroupPermissons(s.Unmask)
g, err := generate.New("linux")
@@ -299,9 +300,32 @@ func SpecGenToOCI(ctx context.Context, s *specgen.SpecGenerator, rt *libpod.Runt
g.AddAnnotation(key, val)
}
- g.Config.Linux.Resources = s.ResourceLimits
+ if compatibleOptions.InfraResources == nil && s.ResourceLimits != nil {
+ g.Config.Linux.Resources = s.ResourceLimits
+ } else if s.ResourceLimits != nil { // if we have predefined resource limits we need to make sure we keep the infra and container limits
+ originalResources, err := json.Marshal(s.ResourceLimits)
+ if err != nil {
+ return nil, err
+ }
+ infraResources, err := json.Marshal(compatibleOptions.InfraResources)
+ if err != nil {
+ return nil, err
+ }
+ err = json.Unmarshal(infraResources, s.ResourceLimits) // put infra's resource limits in the container
+ if err != nil {
+ return nil, err
+ }
+ err = json.Unmarshal(originalResources, s.ResourceLimits) // make sure we did not override anything
+ if err != nil {
+ return nil, err
+ }
+ g.Config.Linux.Resources = s.ResourceLimits
+ } else {
+ g.Config.Linux.Resources = compatibleOptions.InfraResources
+ }
// Devices
+ var userDevices []spec.LinuxDevice
if s.Privileged {
// If privileged, we need to add all the host devices to the
// spec. We do not add the user provided ones because we are
@@ -316,17 +340,26 @@ func SpecGenToOCI(ctx context.Context, s *specgen.SpecGenerator, rt *libpod.Runt
return nil, err
}
}
+ if len(compatibleOptions.InfraDevices) > 0 && len(s.Devices) == 0 {
+ userDevices = compatibleOptions.InfraDevices
+ } else {
+ userDevices = s.Devices
+ }
// add default devices specified by caller
- for _, device := range s.Devices {
+ for _, device := range userDevices {
if err = DevicesFromPath(&g, device.Path); err != nil {
return nil, err
}
}
}
- s.HostDeviceList = s.Devices
+ s.HostDeviceList = userDevices
- for _, dev := range s.DeviceCGroupRule {
- g.AddLinuxResourcesDevice(true, dev.Type, dev.Major, dev.Minor, dev.Access)
+ // set the devices cgroup when not running in a user namespace
+ if !inUserNS && !s.Privileged {
+ g.AddLinuxResourcesDevice(false, "", nil, nil, "rwm")
+ for _, dev := range s.DeviceCGroupRule {
+ g.AddLinuxResourcesDevice(true, dev.Type, dev.Major, dev.Minor, dev.Access)
+ }
}
for k, v := range s.WeightDevice {
diff --git a/pkg/specgen/generate/pod_create.go b/pkg/specgen/generate/pod_create.go
index 72dd249e7..0a797c571 100644
--- a/pkg/specgen/generate/pod_create.go
+++ b/pkg/specgen/generate/pod_create.go
@@ -218,9 +218,7 @@ func MapSpec(p *specgen.PodSpecGenerator) (*specgen.SpecGenerator, error) {
case specgen.Host:
logrus.Debugf("Pod will use host networking")
if len(p.InfraContainerSpec.PortMappings) > 0 ||
- p.InfraContainerSpec.StaticIP != nil ||
- p.InfraContainerSpec.StaticMAC != nil ||
- len(p.InfraContainerSpec.CNINetworks) > 0 ||
+ len(p.InfraContainerSpec.Networks) > 0 ||
p.InfraContainerSpec.NetNS.NSMode == specgen.NoNetwork {
return nil, errors.Wrapf(define.ErrInvalidArg, "cannot set host network if network-related configuration is specified")
}
@@ -234,9 +232,7 @@ func MapSpec(p *specgen.PodSpecGenerator) (*specgen.SpecGenerator, error) {
case specgen.NoNetwork:
logrus.Debugf("Pod will not use networking")
if len(p.InfraContainerSpec.PortMappings) > 0 ||
- p.InfraContainerSpec.StaticIP != nil ||
- p.InfraContainerSpec.StaticMAC != nil ||
- len(p.InfraContainerSpec.CNINetworks) > 0 ||
+ len(p.InfraContainerSpec.Networks) > 0 ||
p.InfraContainerSpec.NetNS.NSMode == "host" {
return nil, errors.Wrapf(define.ErrInvalidArg, "cannot disable pod network if network-related configuration is specified")
}
@@ -264,15 +260,13 @@ func MapSpec(p *specgen.PodSpecGenerator) (*specgen.SpecGenerator, error) {
if len(p.DNSSearch) > 0 {
p.InfraContainerSpec.DNSSearch = p.DNSSearch
}
- if p.StaticIP != nil {
- p.InfraContainerSpec.StaticIP = p.StaticIP
- }
- if p.StaticMAC != nil {
- p.InfraContainerSpec.StaticMAC = p.StaticMAC
- }
if p.NoManageResolvConf {
p.InfraContainerSpec.UseImageResolvConf = true
}
+ if len(p.Networks) > 0 {
+ p.InfraContainerSpec.Networks = p.Networks
+ }
+ // deprecated cni networks for api users
if len(p.CNINetworks) > 0 {
p.InfraContainerSpec.CNINetworks = p.CNINetworks
}
diff --git a/pkg/specgen/generate/validate.go b/pkg/specgen/generate/validate.go
index a44bf9979..c74db7325 100644
--- a/pkg/specgen/generate/validate.go
+++ b/pkg/specgen/generate/validate.go
@@ -60,10 +60,6 @@ func verifyContainerResourcesCgroupV1(s *specgen.SpecGenerator) ([]string, error
if memory.Limit != nil && memory.Reservation != nil && *memory.Limit < *memory.Reservation {
return warnings, errors.New("minimum memory limit cannot be less than memory reservation limit, see usage")
}
- if memory.Kernel != nil && !sysInfo.KernelMemory {
- warnings = append(warnings, "Your kernel does not support kernel memory limit capabilities or the cgroup is not mounted. Limitation discarded.")
- memory.Kernel = nil
- }
if memory.DisableOOMKiller != nil && *memory.DisableOOMKiller && !sysInfo.OomKillDisable {
warnings = append(warnings, "Your kernel does not support OomKillDisable. OomKillDisable discarded.")
memory.DisableOOMKiller = nil
diff --git a/pkg/specgen/namespaces.go b/pkg/specgen/namespaces.go
index bb5385ef1..15a8ece17 100644
--- a/pkg/specgen/namespaces.go
+++ b/pkg/specgen/namespaces.go
@@ -2,10 +2,13 @@ package specgen
import (
"fmt"
+ "net"
"os"
"strings"
"github.com/containers/common/pkg/cgroups"
+ "github.com/containers/podman/v3/libpod/define"
+ "github.com/containers/podman/v3/libpod/network/types"
"github.com/containers/podman/v3/pkg/rootless"
"github.com/containers/podman/v3/pkg/util"
"github.com/containers/storage"
@@ -271,9 +274,9 @@ func ParseUserNamespace(ns string) (Namespace, error) {
// ParseNetworkNamespace parses a network namespace specification in string
// form.
// Returns a namespace and (optionally) a list of CNI networks to join.
-func ParseNetworkNamespace(ns string, rootlessDefaultCNI bool) (Namespace, []string, error) {
+func ParseNetworkNamespace(ns string, rootlessDefaultCNI bool) (Namespace, map[string]types.PerNetworkOptions, error) {
toReturn := Namespace{}
- var cniNetworks []string
+ networks := make(map[string]types.PerNetworkOptions)
// Net defaults to Slirp on rootless
switch {
case ns == string(Slirp), strings.HasPrefix(ns, string(Slirp)+":"):
@@ -313,28 +316,174 @@ func ParseNetworkNamespace(ns string, rootlessDefaultCNI bool) (Namespace, []str
default:
// Assume we have been given a list of CNI networks.
// Which only works in bridge mode, so set that.
- cniNetworks = strings.Split(ns, ",")
+ networkList := strings.Split(ns, ",")
+ for _, net := range networkList {
+ networks[net] = types.PerNetworkOptions{}
+ }
+
toReturn.NSMode = Bridge
}
- return toReturn, cniNetworks, nil
+ return toReturn, networks, nil
}
-func ParseNetworkString(network string) (Namespace, []string, map[string][]string, error) {
+// ParseNetworkFlag parses a network string slice into the network options
+// If the input is nil or empty it will use the default setting from containers.conf
+func ParseNetworkFlag(networks []string) (Namespace, map[string]types.PerNetworkOptions, map[string][]string, error) {
var networkOptions map[string][]string
- parts := strings.SplitN(network, ":", 2)
+ // by default we try to use the containers.conf setting
+ // if we get at least one value use this instead
+ ns := containerConfig.Containers.NetNS
+ if len(networks) > 0 {
+ ns = networks[0]
+ }
- ns, cniNets, err := ParseNetworkNamespace(network, containerConfig.Containers.RootlessNetworking == "cni")
- if err != nil {
- return Namespace{}, nil, nil, err
+ toReturn := Namespace{}
+ podmanNetworks := make(map[string]types.PerNetworkOptions)
+
+ switch {
+ case ns == string(Slirp), strings.HasPrefix(ns, string(Slirp)+":"):
+ parts := strings.SplitN(ns, ":", 2)
+ if len(parts) > 1 {
+ networkOptions = make(map[string][]string)
+ networkOptions[parts[0]] = strings.Split(parts[1], ",")
+ }
+ toReturn.NSMode = Slirp
+ case ns == string(FromPod):
+ toReturn.NSMode = FromPod
+ case ns == "" || ns == string(Default) || ns == string(Private):
+ // Net defaults to Slirp on rootless
+ if rootless.IsRootless() && containerConfig.Containers.RootlessNetworking != "cni" {
+ toReturn.NSMode = Slirp
+ break
+ }
+ // if not slirp we use bridge
+ fallthrough
+ case ns == string(Bridge), strings.HasPrefix(ns, string(Bridge)+":"):
+ toReturn.NSMode = Bridge
+ parts := strings.SplitN(ns, ":", 2)
+ netOpts := types.PerNetworkOptions{}
+ if len(parts) > 1 {
+ var err error
+ netOpts, err = parseBridgeNetworkOptions(parts[1])
+ if err != nil {
+ return toReturn, nil, nil, err
+ }
+ }
+ // we have to set the special default network name here
+ podmanNetworks["default"] = netOpts
+
+ case ns == string(NoNetwork):
+ toReturn.NSMode = NoNetwork
+ case ns == string(Host):
+ toReturn.NSMode = Host
+ case strings.HasPrefix(ns, "ns:"):
+ split := strings.SplitN(ns, ":", 2)
+ if len(split) != 2 {
+ return toReturn, nil, nil, errors.Errorf("must provide a path to a namespace when specifying ns:")
+ }
+ toReturn.NSMode = Path
+ toReturn.Value = split[1]
+ case strings.HasPrefix(ns, string(FromContainer)+":"):
+ split := strings.SplitN(ns, ":", 2)
+ if len(split) != 2 {
+ return toReturn, nil, nil, errors.Errorf("must provide name or ID or a container when specifying container:")
+ }
+ toReturn.NSMode = FromContainer
+ toReturn.Value = split[1]
+ default:
+ // we should have a normal network
+ parts := strings.SplitN(ns, ":", 2)
+ if len(parts) == 1 {
+ // Assume we have been given a comma separated list of networks for backwards compat.
+ networkList := strings.Split(ns, ",")
+ for _, net := range networkList {
+ podmanNetworks[net] = types.PerNetworkOptions{}
+ }
+ } else {
+ if parts[0] == "" {
+ return toReturn, nil, nil, errors.New("network name cannot be empty")
+ }
+ netOpts, err := parseBridgeNetworkOptions(parts[1])
+ if err != nil {
+ return toReturn, nil, nil, errors.Wrapf(err, "invalid option for network %s", parts[0])
+ }
+ podmanNetworks[parts[0]] = netOpts
+ }
+
+ // networks need bridge mode
+ toReturn.NSMode = Bridge
+ }
+
+ if len(networks) > 1 {
+ if !toReturn.IsBridge() {
+ return toReturn, nil, nil, errors.Wrapf(define.ErrInvalidArg, "cannot set multiple networks without bridge network mode, selected mode %s", toReturn.NSMode)
+ }
+
+ for _, network := range networks[1:] {
+ parts := strings.SplitN(network, ":", 2)
+ if parts[0] == "" {
+ return toReturn, nil, nil, errors.Wrapf(define.ErrInvalidArg, "network name cannot be empty")
+ }
+ if util.StringInSlice(parts[0], []string{string(Bridge), string(Slirp), string(FromPod), string(NoNetwork),
+ string(Default), string(Private), string(Path), string(FromContainer), string(Host)}) {
+ return toReturn, nil, nil, errors.Wrapf(define.ErrInvalidArg, "can only set extra network names, selected mode %s conflicts with bridge", parts[0])
+ }
+ netOpts := types.PerNetworkOptions{}
+ if len(parts) > 1 {
+ var err error
+ netOpts, err = parseBridgeNetworkOptions(parts[1])
+ if err != nil {
+ return toReturn, nil, nil, errors.Wrapf(err, "invalid option for network %s", parts[0])
+ }
+ }
+ podmanNetworks[parts[0]] = netOpts
+ }
+ }
+
+ return toReturn, podmanNetworks, networkOptions, nil
+}
+
+func parseBridgeNetworkOptions(opts string) (types.PerNetworkOptions, error) {
+ netOpts := types.PerNetworkOptions{}
+ if len(opts) == 0 {
+ return netOpts, nil
}
+ allopts := strings.Split(opts, ",")
+ for _, opt := range allopts {
+ split := strings.SplitN(opt, "=", 2)
+ switch split[0] {
+ case "ip", "ip6":
+ ip := net.ParseIP(split[1])
+ if ip == nil {
+ return netOpts, errors.Errorf("invalid ip address %q", split[1])
+ }
+ netOpts.StaticIPs = append(netOpts.StaticIPs, ip)
- if len(parts) > 1 {
- networkOptions = make(map[string][]string)
- networkOptions[parts[0]] = strings.Split(parts[1], ",")
- cniNets = nil
+ case "mac":
+ mac, err := net.ParseMAC(split[1])
+ if err != nil {
+ return netOpts, err
+ }
+ netOpts.StaticMAC = types.HardwareAddr(mac)
+
+ case "alias":
+ if split[1] == "" {
+ return netOpts, errors.New("alias cannot be empty")
+ }
+ netOpts.Aliases = append(netOpts.Aliases, split[1])
+
+ case "interface_name":
+ if split[1] == "" {
+ return netOpts, errors.New("interface_name cannot be empty")
+ }
+ netOpts.InterfaceName = split[1]
+
+ default:
+ return netOpts, errors.Errorf("unknown bridge network option: %s", split[0])
+ }
}
- return ns, cniNets, networkOptions, nil
+ return netOpts, nil
}
func SetupUserNS(idmappings *storage.IDMappingOptions, userns Namespace, g *generate.Generator) (string, error) {
diff --git a/pkg/specgen/namespaces_test.go b/pkg/specgen/namespaces_test.go
new file mode 100644
index 000000000..4f69e6b98
--- /dev/null
+++ b/pkg/specgen/namespaces_test.go
@@ -0,0 +1,265 @@
+package specgen
+
+import (
+ "net"
+ "testing"
+
+ "github.com/containers/podman/v3/libpod/network/types"
+ "github.com/containers/podman/v3/pkg/rootless"
+ "github.com/stretchr/testify/assert"
+)
+
+func parsMacNoErr(mac string) types.HardwareAddr {
+ m, _ := net.ParseMAC(mac)
+ return types.HardwareAddr(m)
+}
+
+func TestParseNetworkFlag(t *testing.T) {
+ // root and rootless have different defaults
+ defaultNetName := "default"
+ defaultNetworks := map[string]types.PerNetworkOptions{
+ defaultNetName: {},
+ }
+ defaultNsMode := Namespace{NSMode: Bridge}
+ if rootless.IsRootless() {
+ defaultNsMode = Namespace{NSMode: Slirp}
+ defaultNetworks = map[string]types.PerNetworkOptions{}
+ }
+
+ tests := []struct {
+ name string
+ args []string
+ nsmode Namespace
+ networks map[string]types.PerNetworkOptions
+ options map[string][]string
+ err string
+ }{
+ {
+ name: "empty input",
+ args: nil,
+ nsmode: defaultNsMode,
+ networks: defaultNetworks,
+ },
+ {
+ name: "empty string as input",
+ args: []string{},
+ nsmode: defaultNsMode,
+ networks: defaultNetworks,
+ },
+ {
+ name: "default mode",
+ args: []string{"default"},
+ nsmode: defaultNsMode,
+ networks: defaultNetworks,
+ },
+ {
+ name: "private mode",
+ args: []string{"private"},
+ nsmode: defaultNsMode,
+ networks: defaultNetworks,
+ },
+ {
+ name: "bridge mode",
+ args: []string{"bridge"},
+ nsmode: Namespace{NSMode: Bridge},
+ networks: map[string]types.PerNetworkOptions{
+ defaultNetName: {},
+ },
+ },
+ {
+ name: "slirp4netns mode",
+ args: []string{"slirp4netns"},
+ nsmode: Namespace{NSMode: Slirp},
+ networks: map[string]types.PerNetworkOptions{},
+ },
+ {
+ name: "from pod mode",
+ args: []string{"pod"},
+ nsmode: Namespace{NSMode: FromPod},
+ networks: map[string]types.PerNetworkOptions{},
+ },
+ {
+ name: "no network mode",
+ args: []string{"none"},
+ nsmode: Namespace{NSMode: NoNetwork},
+ networks: map[string]types.PerNetworkOptions{},
+ },
+ {
+ name: "container mode",
+ args: []string{"container:abc"},
+ nsmode: Namespace{NSMode: FromContainer, Value: "abc"},
+ networks: map[string]types.PerNetworkOptions{},
+ },
+ {
+ name: "ns path mode",
+ args: []string{"ns:/path"},
+ nsmode: Namespace{NSMode: Path, Value: "/path"},
+ networks: map[string]types.PerNetworkOptions{},
+ },
+ {
+ name: "slirp4netns mode with options",
+ args: []string{"slirp4netns:cidr=10.0.0.0/24"},
+ nsmode: Namespace{NSMode: Slirp},
+ networks: map[string]types.PerNetworkOptions{},
+ options: map[string][]string{
+ "slirp4netns": {"cidr=10.0.0.0/24"},
+ },
+ },
+ {
+ name: "bridge mode with options 1",
+ args: []string{"bridge:ip=10.0.0.1,mac=11:22:33:44:55:66"},
+ nsmode: Namespace{NSMode: Bridge},
+ networks: map[string]types.PerNetworkOptions{
+ defaultNetName: {
+ StaticIPs: []net.IP{net.ParseIP("10.0.0.1")},
+ StaticMAC: parsMacNoErr("11:22:33:44:55:66"),
+ },
+ },
+ },
+ {
+ name: "bridge mode with options 2",
+ args: []string{"bridge:ip=10.0.0.1,ip=10.0.0.5"},
+ nsmode: Namespace{NSMode: Bridge},
+ networks: map[string]types.PerNetworkOptions{
+ defaultNetName: {
+ StaticIPs: []net.IP{net.ParseIP("10.0.0.1"), net.ParseIP("10.0.0.5")},
+ },
+ },
+ },
+ {
+ name: "bridge mode with ip6 option",
+ args: []string{"bridge:ip6=fd10::"},
+ nsmode: Namespace{NSMode: Bridge},
+ networks: map[string]types.PerNetworkOptions{
+ defaultNetName: {
+ StaticIPs: []net.IP{net.ParseIP("fd10::")},
+ },
+ },
+ },
+ {
+ name: "bridge mode with alias option",
+ args: []string{"bridge:alias=myname,alias=myname2"},
+ nsmode: Namespace{NSMode: Bridge},
+ networks: map[string]types.PerNetworkOptions{
+ defaultNetName: {
+ Aliases: []string{"myname", "myname2"},
+ },
+ },
+ },
+ {
+ name: "bridge mode with alias option",
+ args: []string{"bridge:alias=myname,alias=myname2"},
+ nsmode: Namespace{NSMode: Bridge},
+ networks: map[string]types.PerNetworkOptions{
+ defaultNetName: {
+ Aliases: []string{"myname", "myname2"},
+ },
+ },
+ },
+ {
+ name: "bridge mode with interface option",
+ args: []string{"bridge:interface_name=eth123"},
+ nsmode: Namespace{NSMode: Bridge},
+ networks: map[string]types.PerNetworkOptions{
+ defaultNetName: {
+ InterfaceName: "eth123",
+ },
+ },
+ },
+ {
+ name: "bridge mode with invalid option",
+ args: []string{"bridge:abc=123"},
+ nsmode: Namespace{NSMode: Bridge},
+ err: "unknown bridge network option: abc",
+ },
+ {
+ name: "bridge mode with invalid ip",
+ args: []string{"bridge:ip=10..1"},
+ nsmode: Namespace{NSMode: Bridge},
+ err: "invalid ip address \"10..1\"",
+ },
+ {
+ name: "bridge mode with invalid mac",
+ args: []string{"bridge:mac=123"},
+ nsmode: Namespace{NSMode: Bridge},
+ err: "address 123: invalid MAC address",
+ },
+ {
+ name: "network name",
+ args: []string{"someName"},
+ nsmode: Namespace{NSMode: Bridge},
+ networks: map[string]types.PerNetworkOptions{
+ "someName": {},
+ },
+ },
+ {
+ name: "network name with options",
+ args: []string{"someName:ip=10.0.0.1"},
+ nsmode: Namespace{NSMode: Bridge},
+ networks: map[string]types.PerNetworkOptions{
+ "someName": {StaticIPs: []net.IP{net.ParseIP("10.0.0.1")}},
+ },
+ },
+ {
+ name: "multiple networks",
+ args: []string{"someName", "net2"},
+ nsmode: Namespace{NSMode: Bridge},
+ networks: map[string]types.PerNetworkOptions{
+ "someName": {},
+ "net2": {},
+ },
+ },
+ {
+ name: "multiple networks with options",
+ args: []string{"someName:ip=10.0.0.1", "net2:ip=10.10.0.1"},
+ nsmode: Namespace{NSMode: Bridge},
+ networks: map[string]types.PerNetworkOptions{
+ "someName": {StaticIPs: []net.IP{net.ParseIP("10.0.0.1")}},
+ "net2": {StaticIPs: []net.IP{net.ParseIP("10.10.0.1")}},
+ },
+ },
+ {
+ name: "multiple networks with bridge mode first should map to default net",
+ args: []string{"bridge", "net2"},
+ nsmode: Namespace{NSMode: Bridge},
+ networks: map[string]types.PerNetworkOptions{
+ defaultNetName: {},
+ "net2": {},
+ },
+ },
+ {
+ name: "conflicting network modes should error",
+ args: []string{"bridge", "host"},
+ nsmode: Namespace{NSMode: Bridge},
+ err: "can only set extra network names, selected mode host conflicts with bridge: invalid argument",
+ },
+ {
+ name: "multiple networks empty name should error",
+ args: []string{"someName", ""},
+ nsmode: Namespace{NSMode: Bridge},
+ err: "network name cannot be empty: invalid argument",
+ },
+ {
+ name: "multiple networks on invalid mode should error",
+ args: []string{"host", "net2"},
+ nsmode: Namespace{NSMode: Host},
+ err: "cannot set multiple networks without bridge network mode, selected mode host: invalid argument",
+ },
+ }
+
+ for _, tt := range tests {
+ tt := tt
+ t.Run(tt.name, func(t *testing.T) {
+ got, got1, got2, err := ParseNetworkFlag(tt.args)
+ if tt.err != "" {
+ assert.EqualError(t, err, tt.err, tt.name)
+ } else {
+ assert.NoError(t, err, tt.name)
+ }
+
+ assert.Equal(t, tt.nsmode, got, tt.name)
+ assert.Equal(t, tt.networks, got1, tt.name)
+ assert.Equal(t, tt.options, got2, tt.name)
+ })
+ }
+}
diff --git a/pkg/specgen/pod_validate.go b/pkg/specgen/pod_validate.go
index bca7b6dbe..c5a66189c 100644
--- a/pkg/specgen/pod_validate.go
+++ b/pkg/specgen/pod_validate.go
@@ -1,7 +1,6 @@
package specgen
import (
- "github.com/containers/podman/v3/pkg/rootless"
"github.com/containers/podman/v3/pkg/util"
"github.com/pkg/errors"
)
@@ -19,15 +18,6 @@ func exclusivePodOptions(opt1, opt2 string) error {
// Validate verifies the input is valid
func (p *PodSpecGenerator) Validate() error {
- if rootless.IsRootless() && len(p.CNINetworks) == 0 {
- if p.StaticIP != nil {
- return ErrNoStaticIPRootless
- }
- if p.StaticMAC != nil {
- return ErrNoStaticMACRootless
- }
- }
-
// PodBasicConfig
if p.NoInfra {
if len(p.InfraCommand) > 0 {
@@ -52,11 +42,10 @@ func (p *PodSpecGenerator) Validate() error {
if p.NetNS.NSMode != Default && p.NetNS.NSMode != "" {
return errors.New("NoInfra and network modes cannot be used together")
}
- if p.StaticIP != nil {
- return exclusivePodOptions("NoInfra", "StaticIP")
- }
- if p.StaticMAC != nil {
- return exclusivePodOptions("NoInfra", "StaticMAC")
+ // Note that networks might be set when --ip or --mac was set
+ // so we need to check that no networks are set without the infra
+ if len(p.Networks) > 0 {
+ return errors.New("cannot set networks options without infra container")
}
if len(p.DNSOption) > 0 {
return exclusivePodOptions("NoInfra", "DNSOption")
@@ -78,10 +67,8 @@ func (p *PodSpecGenerator) Validate() error {
if len(p.PortMappings) > 0 {
return errors.New("PortMappings can only be used with Bridge or slirp4netns networking")
}
- if len(p.CNINetworks) > 0 {
- return errors.New("CNINetworks can only be used with Bridge mode networking")
- }
}
+
if p.NoManageResolvConf {
if len(p.DNSServer) > 0 {
return exclusivePodOptions("NoManageResolvConf", "DNSServer")
diff --git a/pkg/specgen/podspecgen.go b/pkg/specgen/podspecgen.go
index 948fb990c..33e8422fd 100644
--- a/pkg/specgen/podspecgen.go
+++ b/pkg/specgen/podspecgen.go
@@ -86,33 +86,26 @@ type PodNetworkConfig struct {
// Defaults to Bridge as root and Slirp as rootless.
// Mandatory.
NetNS Namespace `json:"netns,omitempty"`
- // StaticIP sets a static IP for the infra container. As the infra
- // container's network is used for the entire pod by default, this will
- // thus be a static IP for the whole pod.
- // Only available if NetNS is set to Bridge (the default for root).
- // As such, conflicts with NoInfra=true by proxy.
- // Optional.
- StaticIP *net.IP `json:"static_ip,omitempty"`
- // StaticMAC sets a static MAC for the infra container. As the infra
- // container's network is used for the entire pod by default, this will
- // thus be a static MAC for the entire pod.
- // Only available if NetNS is set to Bridge (the default for root).
- // As such, conflicts with NoInfra=true by proxy.
- // Optional.
- // swagger:strfmt string
- StaticMAC *types.HardwareAddr `json:"static_mac,omitempty"`
// PortMappings is a set of ports to map into the infra container.
// As, by default, containers share their network with the infra
// container, this will forward the ports to the entire pod.
// Only available if NetNS is set to Bridge or Slirp.
// Optional.
PortMappings []types.PortMapping `json:"portmappings,omitempty"`
- // CNINetworks is a list of CNI networks that the infra container will
- // join. As, by default, containers share their network with the infra
- // container, these networks will effectively be joined by the
- // entire pod.
- // Only available when NetNS is set to Bridge, the default for root.
- // Optional.
+ // Map of networks names ot ids the container should join to.
+ // You can request additional settings for each network, you can
+ // set network aliases, static ips, static mac address and the
+ // network interface name for this container on the specifc network.
+ // If the map is empty and the bridge network mode is set the container
+ // will be joined to the default network.
+ Networks map[string]types.PerNetworkOptions
+ // CNINetworks is a list of CNI networks to join the container to.
+ // If this list is empty, the default CNI network will be joined
+ // instead. If at least one entry is present, we will not join the
+ // default network (unless it is part of this list).
+ // Only available if NetNS is set to bridge.
+ // Optional.
+ // Deprecated: as of podman 4.0 use "Networks" instead.
CNINetworks []string `json:"cni_networks,omitempty"`
// NoManageResolvConf indicates that /etc/resolv.conf should not be
// managed by the pod. Instead, each container will create and manage a
@@ -203,6 +196,7 @@ type PodSpecGenerator struct {
PodCgroupConfig
PodResourceConfig
PodStorageConfig
+ PodSecurityConfig
InfraContainerSpec *SpecGenerator `json:"-"`
}
@@ -217,6 +211,10 @@ type PodResourceConfig struct {
ThrottleReadBpsDevice map[string]spec.LinuxThrottleDevice `json:"throttleReadBpsDevice,omitempty"`
}
+type PodSecurityConfig struct {
+ SecurityOpt []string `json:"security_opt,omitempty"`
+}
+
// NewPodSpecGenerator creates a new pod spec
func NewPodSpecGenerator() *PodSpecGenerator {
return &PodSpecGenerator{}
diff --git a/pkg/specgen/specgen.go b/pkg/specgen/specgen.go
index 0e257ad4c..5989456c9 100644
--- a/pkg/specgen/specgen.go
+++ b/pkg/specgen/specgen.go
@@ -152,6 +152,9 @@ type ContainerBasicConfig struct {
// Conflicts with UtsNS if UtsNS is not set to private.
// Optional.
Hostname string `json:"hostname,omitempty"`
+ // HostUses is a list of host usernames or UIDs to add to the container
+ // /etc/passwd file
+ HostUsers []string `json:"hostusers,omitempty"`
// Sysctl sets kernel parameters for the container
Sysctl map[string]string `json:"sysctl,omitempty"`
// Remove indicates if the container should be removed once it has been started
@@ -201,6 +204,8 @@ type ContainerBasicConfig struct {
// UnsetEnvAll unsets all default environment variables from the image or from buildin
// Optional.
UnsetEnvAll bool `json:"unsetenvall,omitempty"`
+ // Passwd is a container run option that determines if we are validating users/groups before running the container
+ Passwd *bool `json:"manage_password,omitempty"`
}
// ContainerStorageConfig contains information on the storage configuration of a
@@ -394,26 +399,10 @@ type ContainerCgroupConfig struct {
// ContainerNetworkConfig contains information on a container's network
// configuration.
type ContainerNetworkConfig struct {
- // Aliases are a list of network-scoped aliases for container
- // Optional
- Aliases map[string][]string `json:"aliases"`
// NetNS is the configuration to use for the container's network
// namespace.
// Mandatory.
NetNS Namespace `json:"netns,omitempty"`
- // StaticIP is the a IPv4 address of the container.
- // Only available if NetNS is set to Bridge.
- // Optional.
- StaticIP *net.IP `json:"static_ip,omitempty"`
- // StaticIPv6 is a static IPv6 address to set in the container.
- // Only available if NetNS is set to Bridge.
- // Optional.
- StaticIPv6 *net.IP `json:"static_ipv6,omitempty"`
- // StaticMAC is a static MAC address to set in the container.
- // Only available if NetNS is set to bridge.
- // Optional.
- // swagger:strfmt string
- StaticMAC *nettypes.HardwareAddr `json:"static_mac,omitempty"`
// PortBindings is a set of ports to map into the container.
// Only available if NetNS is set to bridge or slirp.
// Optional.
@@ -434,12 +423,20 @@ type ContainerNetworkConfig struct {
// PublishExposedPorts is set.
// Optional.
Expose map[uint16]string `json:"expose,omitempty"`
+ // Map of networks names ot ids the container should join to.
+ // You can request additional settings for each network, you can
+ // set network aliases, static ips, static mac address and the
+ // network interface name for this container on the specifc network.
+ // If the map is empty and the bridge network mode is set the container
+ // will be joined to the default network.
+ Networks map[string]nettypes.PerNetworkOptions
// CNINetworks is a list of CNI networks to join the container to.
// If this list is empty, the default CNI network will be joined
// instead. If at least one entry is present, we will not join the
// default network (unless it is part of this list).
// Only available if NetNS is set to bridge.
// Optional.
+ // Deprecated: as of podman 4.0 use "Networks" instead.
CNINetworks []string `json:"cni_networks,omitempty"`
// UseImageResolvConf indicates that resolv.conf should not be managed
// by Podman, but instead sourced from the image.