Modify namespace generation code for specgen
Namespaces have now been changed to properly handle all cases. Spec handling code for namespaces was consolidated in a single function. Still missing: - Image ports - Pod namespaces likely still broken in Podmanv2 Signed-off-by: Matthew Heon <matthew.heon@pm.me>
This commit is contained in:
parent
2ed4a0e35f
commit
1cd2b746d0
|
|
@ -5,6 +5,7 @@ import (
|
|||
|
||||
"github.com/containers/libpod/cmd/podman/parse"
|
||||
"github.com/containers/libpod/pkg/domain/entities"
|
||||
"github.com/containers/libpod/pkg/specgen"
|
||||
"github.com/pkg/errors"
|
||||
"github.com/spf13/cobra"
|
||||
"github.com/spf13/pflag"
|
||||
|
|
@ -159,9 +160,13 @@ func NetFlagsToNetOptions(cmd *cobra.Command) (*entities.NetOptions, error) {
|
|||
return nil, err
|
||||
}
|
||||
|
||||
return nil, errors.Errorf("network %s is not yet supported", network)
|
||||
// TODO How do I convert a string network to a Specgen.Namespace?
|
||||
// opts.Network = specgen.Namespace{NSMode: network}
|
||||
ns, cniNets, err := specgen.ParseNetworkNamespace(network)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
opts.Network = ns
|
||||
opts.CNINetworks = cniNets
|
||||
}
|
||||
|
||||
return &opts, err
|
||||
|
|
|
|||
|
|
@ -86,9 +86,6 @@ func (s *SpecGenerator) Validate() error {
|
|||
//
|
||||
// ContainerNetworkConfig
|
||||
//
|
||||
if !s.NetNS.IsPrivate() && s.ConfigureNetNS {
|
||||
return errors.New("can only configure network namespace when creating a network a network namespace")
|
||||
}
|
||||
// useimageresolveconf conflicts with dnsserver, dnssearch, dnsoption
|
||||
if s.UseImageResolvConf {
|
||||
if len(s.DNSServers) > 0 {
|
||||
|
|
|
|||
|
|
@ -15,6 +15,7 @@ import (
|
|||
func CompleteSpec(ctx context.Context, r *libpod.Runtime, s *specgen.SpecGenerator) error {
|
||||
var appendEntryPoint bool
|
||||
|
||||
// TODO add support for raw rootfs
|
||||
newImage, err := r.ImageRuntime().NewFromLocal(s.Image)
|
||||
if err != nil {
|
||||
return err
|
||||
|
|
|
|||
|
|
@ -23,7 +23,61 @@ func MakeContainer(rt *libpod.Runtime, s *specgen.SpecGenerator) (*libpod.Contai
|
|||
return nil, err
|
||||
}
|
||||
|
||||
options, err := createContainerOptions(rt, s)
|
||||
// If joining a pod, retrieve the pod for use.
|
||||
var pod *libpod.Pod
|
||||
if s.Pod != "" {
|
||||
foundPod, err := rt.LookupPod(s.Pod)
|
||||
if err != nil {
|
||||
return nil, errors.Wrapf(err, "error retrieving pod %s", s.Pod)
|
||||
}
|
||||
pod = foundPod
|
||||
}
|
||||
|
||||
// Set defaults for unset namespaces
|
||||
if s.PidNS.IsDefault() {
|
||||
defaultNS, err := GetDefaultNamespaceMode("pid", rtc, pod)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
s.PidNS = defaultNS
|
||||
}
|
||||
if s.IpcNS.IsDefault() {
|
||||
defaultNS, err := GetDefaultNamespaceMode("ipc", rtc, pod)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
s.IpcNS = defaultNS
|
||||
}
|
||||
if s.UtsNS.IsDefault() {
|
||||
defaultNS, err := GetDefaultNamespaceMode("uts", rtc, pod)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
s.UtsNS = defaultNS
|
||||
}
|
||||
if s.UserNS.IsDefault() {
|
||||
defaultNS, err := GetDefaultNamespaceMode("user", rtc, pod)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
s.UserNS = defaultNS
|
||||
}
|
||||
if s.NetNS.IsDefault() {
|
||||
defaultNS, err := GetDefaultNamespaceMode("net", rtc, pod)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
s.NetNS = defaultNS
|
||||
}
|
||||
if s.CgroupNS.IsDefault() {
|
||||
defaultNS, err := GetDefaultNamespaceMode("cgroup", rtc, pod)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
s.CgroupNS = defaultNS
|
||||
}
|
||||
|
||||
options, err := createContainerOptions(rt, s, pod)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
|
@ -47,7 +101,7 @@ func MakeContainer(rt *libpod.Runtime, s *specgen.SpecGenerator) (*libpod.Contai
|
|||
return rt.NewContainer(context.Background(), runtimeSpec, options...)
|
||||
}
|
||||
|
||||
func createContainerOptions(rt *libpod.Runtime, s *specgen.SpecGenerator) ([]libpod.CtrCreateOption, error) {
|
||||
func createContainerOptions(rt *libpod.Runtime, s *specgen.SpecGenerator, pod *libpod.Pod) ([]libpod.CtrCreateOption, error) {
|
||||
var options []libpod.CtrCreateOption
|
||||
var err error
|
||||
|
||||
|
|
@ -123,7 +177,7 @@ func createContainerOptions(rt *libpod.Runtime, s *specgen.SpecGenerator) ([]lib
|
|||
options = append(options, libpod.WithPrivileged(s.Privileged))
|
||||
|
||||
// Get namespace related options
|
||||
namespaceOptions, err := GenerateNamespaceContainerOpts(s, rt)
|
||||
namespaceOptions, err := GenerateNamespaceOptions(s, rt, pod)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
|
|
|||
|
|
@ -2,314 +2,389 @@ package generate
|
|||
|
||||
import (
|
||||
"os"
|
||||
"strings"
|
||||
|
||||
"github.com/containers/common/pkg/config"
|
||||
"github.com/containers/libpod/libpod"
|
||||
"github.com/containers/libpod/libpod/define"
|
||||
"github.com/containers/libpod/pkg/cgroups"
|
||||
"github.com/containers/libpod/pkg/rootless"
|
||||
"github.com/containers/libpod/pkg/specgen"
|
||||
"github.com/cri-o/ocicni/pkg/ocicni"
|
||||
spec "github.com/opencontainers/runtime-spec/specs-go"
|
||||
"github.com/opencontainers/runtime-tools/generate"
|
||||
"github.com/pkg/errors"
|
||||
"github.com/sirupsen/logrus"
|
||||
)
|
||||
|
||||
func GenerateNamespaceContainerOpts(s *specgen.SpecGenerator, rt *libpod.Runtime) ([]libpod.CtrCreateOption, error) {
|
||||
var portBindings []ocicni.PortMapping
|
||||
options := make([]libpod.CtrCreateOption, 0)
|
||||
// Get the default namespace mode for any given namespace type.
|
||||
func GetDefaultNamespaceMode(nsType string, cfg *config.Config, pod *libpod.Pod) (specgen.Namespace, error) {
|
||||
// The default for most is private
|
||||
toReturn := specgen.Namespace{}
|
||||
toReturn.NSMode = specgen.Private
|
||||
|
||||
// Cgroups
|
||||
switch {
|
||||
case s.CgroupNS.IsPrivate():
|
||||
ns := s.CgroupNS.Value
|
||||
if _, err := os.Stat(ns); err != nil {
|
||||
return nil, err
|
||||
// Ensure case insensitivity
|
||||
nsType = strings.ToLower(nsType)
|
||||
|
||||
// If the pod is not nil - check shared namespaces
|
||||
if pod != nil {
|
||||
podMode := false
|
||||
switch {
|
||||
case nsType == "pid" && pod.SharesPID():
|
||||
podMode = true
|
||||
case nsType == "ipc" && pod.SharesIPC():
|
||||
podMode = true
|
||||
case nsType == "uts" && pod.SharesUTS():
|
||||
podMode = true
|
||||
case nsType == "user" && pod.SharesUser():
|
||||
podMode = true
|
||||
case nsType == "net" && pod.SharesNet():
|
||||
podMode = true
|
||||
case nsType == "cgroup" && pod.SharesCgroup():
|
||||
podMode = true
|
||||
}
|
||||
case s.CgroupNS.IsContainer():
|
||||
connectedCtr, err := rt.LookupContainer(s.CgroupNS.Value)
|
||||
if podMode {
|
||||
toReturn.NSMode = specgen.FromPod
|
||||
return toReturn, nil
|
||||
}
|
||||
}
|
||||
|
||||
// If we have containers.conf and are not using cgroupns, use that.
|
||||
if cfg != nil && nsType != "cgroup" {
|
||||
switch nsType {
|
||||
case "pid":
|
||||
return specgen.ParseNamespace(cfg.Containers.PidNS)
|
||||
case "ipc":
|
||||
return specgen.ParseNamespace(cfg.Containers.IPCNS)
|
||||
case "uts":
|
||||
return specgen.ParseNamespace(cfg.Containers.UTSNS)
|
||||
case "user":
|
||||
// TODO: This may not work for --userns=auto
|
||||
return specgen.ParseNamespace(cfg.Containers.UserNS)
|
||||
case "net":
|
||||
ns, _, err := specgen.ParseNetworkNamespace(cfg.Containers.NetNS)
|
||||
return ns, err
|
||||
}
|
||||
}
|
||||
|
||||
switch nsType {
|
||||
case "pid", "ipc", "uts":
|
||||
// PID, IPC, UTS both default to private, do nothing
|
||||
case "user":
|
||||
// User namespace always defaults to host
|
||||
toReturn.NSMode = specgen.Host
|
||||
case "net":
|
||||
// Net defaults to Slirp on rootless, Bridge otherwise.
|
||||
if rootless.IsRootless() {
|
||||
toReturn.NSMode = specgen.Slirp
|
||||
} else {
|
||||
toReturn.NSMode = specgen.Bridge
|
||||
}
|
||||
case "cgroup":
|
||||
// Cgroup is host for v1, private for v2.
|
||||
// We can't trust c/common for this, as it only assumes private.
|
||||
cgroupsv2, err := cgroups.IsCgroup2UnifiedMode()
|
||||
if err != nil {
|
||||
return nil, errors.Wrapf(err, "container %q not found", s.CgroupNS.Value)
|
||||
return toReturn, err
|
||||
}
|
||||
options = append(options, libpod.WithCgroupNSFrom(connectedCtr))
|
||||
// TODO
|
||||
//default:
|
||||
// return nil, errors.New("cgroup name only supports private and container")
|
||||
if !cgroupsv2 {
|
||||
toReturn.NSMode = specgen.Host
|
||||
}
|
||||
default:
|
||||
return toReturn, errors.Wrapf(define.ErrInvalidArg, "invalid namespace type %s passed", nsType)
|
||||
}
|
||||
|
||||
if s.CgroupParent != "" {
|
||||
options = append(options, libpod.WithCgroupParent(s.CgroupParent))
|
||||
}
|
||||
return toReturn, nil
|
||||
}
|
||||
|
||||
if s.CgroupsMode != "" {
|
||||
options = append(options, libpod.WithCgroupsMode(s.CgroupsMode))
|
||||
}
|
||||
// GenerateNamespaceOptions generates container creation options for all
|
||||
// namespaces in a SpecGenerator.
|
||||
// Pod is the pod the container will join. May be nil is the container is not
|
||||
// joining a pod.
|
||||
// TODO: Consider grouping options that are not directly attached to a namespace
|
||||
// elsewhere.
|
||||
func GenerateNamespaceOptions(s *specgen.SpecGenerator, rt *libpod.Runtime, pod *libpod.Pod) ([]libpod.CtrCreateOption, error) {
|
||||
toReturn := []libpod.CtrCreateOption{}
|
||||
|
||||
// ipc
|
||||
switch {
|
||||
case s.IpcNS.IsHost():
|
||||
options = append(options, libpod.WithShmDir("/dev/shm"))
|
||||
case s.IpcNS.IsContainer():
|
||||
connectedCtr, err := rt.LookupContainer(s.IpcNS.Value)
|
||||
// If pod is not nil, get infra container.
|
||||
var infraCtr *libpod.Container
|
||||
if pod != nil {
|
||||
infraID, err := pod.InfraContainerID()
|
||||
if err != nil {
|
||||
return nil, errors.Wrapf(err, "container %q not found", s.IpcNS.Value)
|
||||
// This is likely to be of the fatal kind (pod was
|
||||
// removed) so hard fail
|
||||
return nil, errors.Wrapf(err, "error looking up pod %s infra container", pod.ID())
|
||||
}
|
||||
if infraID != "" {
|
||||
ctr, err := rt.GetContainer(infraID)
|
||||
if err != nil {
|
||||
return nil, errors.Wrapf(err, "error retrieving pod %s infra container %s", pod.ID(), infraID)
|
||||
}
|
||||
infraCtr = ctr
|
||||
}
|
||||
options = append(options, libpod.WithIPCNSFrom(connectedCtr))
|
||||
options = append(options, libpod.WithShmDir(connectedCtr.ShmDir()))
|
||||
}
|
||||
|
||||
// pid
|
||||
if s.PidNS.IsContainer() {
|
||||
connectedCtr, err := rt.LookupContainer(s.PidNS.Value)
|
||||
if err != nil {
|
||||
return nil, errors.Wrapf(err, "container %q not found", s.PidNS.Value)
|
||||
errNoInfra := errors.Wrapf(define.ErrInvalidArg, "cannot use pod namespace as container is not joining a pod or pod has no infra container")
|
||||
|
||||
// PID
|
||||
switch s.PidNS.NSMode {
|
||||
case specgen.FromPod:
|
||||
if pod == nil || infraCtr == nil {
|
||||
return nil, errNoInfra
|
||||
}
|
||||
options = append(options, libpod.WithPIDNSFrom(connectedCtr))
|
||||
toReturn = append(toReturn, libpod.WithPIDNSFrom(infraCtr))
|
||||
case specgen.FromContainer:
|
||||
pidCtr, err := rt.LookupContainer(s.PidNS.Value)
|
||||
if err != nil {
|
||||
return nil, errors.Wrapf(err, "error looking up container to share pid namespace with")
|
||||
}
|
||||
toReturn = append(toReturn, libpod.WithPIDNSFrom(pidCtr))
|
||||
}
|
||||
|
||||
// uts
|
||||
switch {
|
||||
case s.UtsNS.IsPod():
|
||||
connectedPod, err := rt.LookupPod(s.UtsNS.Value)
|
||||
if err != nil {
|
||||
return nil, errors.Wrapf(err, "pod %q not found", s.UtsNS.Value)
|
||||
// IPC
|
||||
switch s.IpcNS.NSMode {
|
||||
case specgen.Host:
|
||||
// Force use of host /dev/shm for host namespace
|
||||
toReturn = append(toReturn, libpod.WithShmDir("/dev/shm"))
|
||||
case specgen.FromPod:
|
||||
if pod == nil || infraCtr == nil {
|
||||
return nil, errNoInfra
|
||||
}
|
||||
options = append(options, libpod.WithUTSNSFromPod(connectedPod))
|
||||
case s.UtsNS.IsContainer():
|
||||
connectedCtr, err := rt.LookupContainer(s.UtsNS.Value)
|
||||
toReturn = append(toReturn, libpod.WithIPCNSFrom(infraCtr))
|
||||
case specgen.FromContainer:
|
||||
ipcCtr, err := rt.LookupContainer(s.IpcNS.Value)
|
||||
if err != nil {
|
||||
return nil, errors.Wrapf(err, "container %q not found", s.UtsNS.Value)
|
||||
return nil, errors.Wrapf(err, "error looking up container to share ipc namespace with")
|
||||
}
|
||||
|
||||
options = append(options, libpod.WithUTSNSFrom(connectedCtr))
|
||||
toReturn = append(toReturn, libpod.WithIPCNSFrom(ipcCtr))
|
||||
toReturn = append(toReturn, libpod.WithShmDir(ipcCtr.ShmDir()))
|
||||
}
|
||||
|
||||
if s.UseImageHosts {
|
||||
options = append(options, libpod.WithUseImageHosts())
|
||||
} else if len(s.HostAdd) > 0 {
|
||||
options = append(options, libpod.WithHosts(s.HostAdd))
|
||||
// UTS
|
||||
switch s.UtsNS.NSMode {
|
||||
case specgen.FromPod:
|
||||
if pod == nil || infraCtr == nil {
|
||||
return nil, errNoInfra
|
||||
}
|
||||
toReturn = append(toReturn, libpod.WithUTSNSFrom(infraCtr))
|
||||
case specgen.FromContainer:
|
||||
utsCtr, err := rt.LookupContainer(s.UtsNS.Value)
|
||||
if err != nil {
|
||||
return nil, errors.Wrapf(err, "error looking up container to share uts namespace with")
|
||||
}
|
||||
toReturn = append(toReturn, libpod.WithUTSNSFrom(utsCtr))
|
||||
}
|
||||
|
||||
// User
|
||||
|
||||
switch {
|
||||
case s.UserNS.IsPath():
|
||||
ns := s.UserNS.Value
|
||||
if ns == "" {
|
||||
return nil, errors.Errorf("invalid empty user-defined user namespace")
|
||||
switch s.UserNS.NSMode {
|
||||
case specgen.FromPod:
|
||||
if pod == nil || infraCtr == nil {
|
||||
return nil, errNoInfra
|
||||
}
|
||||
_, err := os.Stat(ns)
|
||||
toReturn = append(toReturn, libpod.WithUserNSFrom(infraCtr))
|
||||
case specgen.FromContainer:
|
||||
userCtr, err := rt.LookupContainer(s.UserNS.Value)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if s.IDMappings != nil {
|
||||
options = append(options, libpod.WithIDMappings(*s.IDMappings))
|
||||
}
|
||||
case s.UserNS.IsContainer():
|
||||
connectedCtr, err := rt.LookupContainer(s.UserNS.Value)
|
||||
if err != nil {
|
||||
return nil, errors.Wrapf(err, "container %q not found", s.UserNS.Value)
|
||||
}
|
||||
options = append(options, libpod.WithUserNSFrom(connectedCtr))
|
||||
default:
|
||||
if s.IDMappings != nil {
|
||||
options = append(options, libpod.WithIDMappings(*s.IDMappings))
|
||||
return nil, errors.Wrapf(err, "error looking up container to share user namespace with")
|
||||
}
|
||||
toReturn = append(toReturn, libpod.WithUserNSFrom(userCtr))
|
||||
}
|
||||
|
||||
options = append(options, libpod.WithUser(s.User))
|
||||
options = append(options, libpod.WithGroups(s.Groups))
|
||||
|
||||
if len(s.PortMappings) > 0 {
|
||||
portBindings = s.PortMappings
|
||||
if s.IDMappings != nil {
|
||||
toReturn = append(toReturn, libpod.WithIDMappings(*s.IDMappings))
|
||||
}
|
||||
if s.User != "" {
|
||||
toReturn = append(toReturn, libpod.WithUser(s.User))
|
||||
}
|
||||
if len(s.Groups) > 0 {
|
||||
toReturn = append(toReturn, libpod.WithGroups(s.Groups))
|
||||
}
|
||||
|
||||
switch {
|
||||
case s.NetNS.IsPath():
|
||||
ns := s.NetNS.Value
|
||||
if ns == "" {
|
||||
return nil, errors.Errorf("invalid empty user-defined network namespace")
|
||||
// Cgroup
|
||||
switch s.CgroupNS.NSMode {
|
||||
case specgen.FromPod:
|
||||
if pod == nil || infraCtr == nil {
|
||||
return nil, errNoInfra
|
||||
}
|
||||
_, err := os.Stat(ns)
|
||||
toReturn = append(toReturn, libpod.WithCgroupNSFrom(infraCtr))
|
||||
case specgen.FromContainer:
|
||||
cgroupCtr, err := rt.LookupContainer(s.CgroupNS.Value)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
return nil, errors.Wrapf(err, "error looking up container to share cgroup namespace with")
|
||||
}
|
||||
case s.NetNS.IsContainer():
|
||||
connectedCtr, err := rt.LookupContainer(s.NetNS.Value)
|
||||
if err != nil {
|
||||
return nil, errors.Wrapf(err, "container %q not found", s.NetNS.Value)
|
||||
}
|
||||
options = append(options, libpod.WithNetNSFrom(connectedCtr))
|
||||
case !s.NetNS.IsHost() && s.NetNS.NSMode != specgen.NoNetwork:
|
||||
postConfigureNetNS := !s.UserNS.IsHost()
|
||||
options = append(options, libpod.WithNetNS(portBindings, postConfigureNetNS, string(s.NetNS.NSMode), s.CNINetworks))
|
||||
toReturn = append(toReturn, libpod.WithCgroupNSFrom(cgroupCtr))
|
||||
}
|
||||
|
||||
if s.CgroupParent != "" {
|
||||
toReturn = append(toReturn, libpod.WithCgroupParent(s.CgroupParent))
|
||||
}
|
||||
|
||||
if s.CgroupsMode != "" {
|
||||
toReturn = append(toReturn, libpod.WithCgroupsMode(s.CgroupsMode))
|
||||
}
|
||||
|
||||
// Net
|
||||
// TODO image ports
|
||||
// TODO validate CNINetworks, StaticIP, StaticIPv6 are only set if we
|
||||
// are in bridge mode.
|
||||
postConfigureNetNS := !s.UserNS.IsHost()
|
||||
switch s.NetNS.NSMode {
|
||||
case specgen.FromPod:
|
||||
if pod == nil || infraCtr == nil {
|
||||
return nil, errNoInfra
|
||||
}
|
||||
toReturn = append(toReturn, libpod.WithNetNSFrom(infraCtr))
|
||||
case specgen.FromContainer:
|
||||
netCtr, err := rt.LookupContainer(s.NetNS.Value)
|
||||
if err != nil {
|
||||
return nil, errors.Wrapf(err, "error looking up container to share net namespace with")
|
||||
}
|
||||
toReturn = append(toReturn, libpod.WithNetNSFrom(netCtr))
|
||||
case specgen.Slirp:
|
||||
toReturn = append(toReturn, libpod.WithNetNS(s.PortMappings, postConfigureNetNS, "slirp4netns", nil))
|
||||
case specgen.Bridge:
|
||||
toReturn = append(toReturn, libpod.WithNetNS(s.PortMappings, postConfigureNetNS, "bridge", s.CNINetworks))
|
||||
}
|
||||
|
||||
if s.UseImageHosts {
|
||||
toReturn = append(toReturn, libpod.WithUseImageHosts())
|
||||
} else if len(s.HostAdd) > 0 {
|
||||
toReturn = append(toReturn, libpod.WithHosts(s.HostAdd))
|
||||
}
|
||||
if len(s.DNSSearch) > 0 {
|
||||
options = append(options, libpod.WithDNSSearch(s.DNSSearch))
|
||||
toReturn = append(toReturn, libpod.WithDNSSearch(s.DNSSearch))
|
||||
}
|
||||
|
||||
if s.UseImageResolvConf {
|
||||
options = append(options, libpod.WithUseImageResolvConf())
|
||||
} else {
|
||||
toReturn = append(toReturn, libpod.WithUseImageResolvConf())
|
||||
} else if len(s.DNSServers) > 0 {
|
||||
var dnsServers []string
|
||||
for _, d := range s.DNSServers {
|
||||
dnsServers = append(dnsServers, d.String())
|
||||
}
|
||||
options = append(options, libpod.WithDNS(dnsServers))
|
||||
toReturn = append(toReturn, libpod.WithDNS(dnsServers))
|
||||
}
|
||||
|
||||
if len(s.DNSOptions) > 0 {
|
||||
options = append(options, libpod.WithDNSOption(s.DNSOptions))
|
||||
toReturn = append(toReturn, libpod.WithDNSOption(s.DNSOptions))
|
||||
}
|
||||
if s.StaticIP != nil {
|
||||
options = append(options, libpod.WithStaticIP(*s.StaticIP))
|
||||
toReturn = append(toReturn, libpod.WithStaticIP(*s.StaticIP))
|
||||
}
|
||||
|
||||
if s.StaticMAC != nil {
|
||||
options = append(options, libpod.WithStaticMAC(*s.StaticMAC))
|
||||
toReturn = append(toReturn, libpod.WithStaticMAC(*s.StaticMAC))
|
||||
}
|
||||
return options, nil
|
||||
|
||||
return toReturn, nil
|
||||
}
|
||||
|
||||
func pidConfigureGenerator(s *specgen.SpecGenerator, g *generate.Generator) error {
|
||||
if s.PidNS.IsPath() {
|
||||
return g.AddOrReplaceLinuxNamespace(string(spec.PIDNamespace), s.PidNS.Value)
|
||||
func specConfigureNamespaces(s *specgen.SpecGenerator, g *generate.Generator, rt *libpod.Runtime) error {
|
||||
// PID
|
||||
switch s.PidNS.NSMode {
|
||||
case specgen.Path:
|
||||
if _, err := os.Stat(s.PidNS.Value); err != nil {
|
||||
return errors.Wrapf(err, "cannot find specified PID namespace path %q", s.PidNS.Value)
|
||||
}
|
||||
if err := g.AddOrReplaceLinuxNamespace(string(spec.PIDNamespace), s.PidNS.Value); err != nil {
|
||||
return err
|
||||
}
|
||||
case specgen.Host:
|
||||
if err := g.RemoveLinuxNamespace(string(spec.PIDNamespace)); err != nil {
|
||||
return err
|
||||
}
|
||||
case specgen.Private:
|
||||
if err := g.AddOrReplaceLinuxNamespace(string(spec.PIDNamespace), ""); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
// IPC
|
||||
switch s.IpcNS.NSMode {
|
||||
case specgen.Path:
|
||||
if _, err := os.Stat(s.IpcNS.Value); err != nil {
|
||||
return errors.Wrapf(err, "cannot find specified IPC namespace path %q", s.IpcNS.Value)
|
||||
}
|
||||
if err := g.AddOrReplaceLinuxNamespace(string(spec.IPCNamespace), s.IpcNS.Value); err != nil {
|
||||
return err
|
||||
}
|
||||
case specgen.Host:
|
||||
if err := g.RemoveLinuxNamespace(string(spec.IPCNamespace)); err != nil {
|
||||
return err
|
||||
}
|
||||
case specgen.Private:
|
||||
if err := g.AddOrReplaceLinuxNamespace(string(spec.IPCNamespace), ""); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
// UTS
|
||||
switch s.UtsNS.NSMode {
|
||||
case specgen.Path:
|
||||
if _, err := os.Stat(s.UtsNS.Value); err != nil {
|
||||
return errors.Wrapf(err, "cannot find specified UTS namespace path %q", s.UtsNS.Value)
|
||||
}
|
||||
if err := g.AddOrReplaceLinuxNamespace(string(spec.UTSNamespace), s.UtsNS.Value); err != nil {
|
||||
return err
|
||||
}
|
||||
case specgen.Host:
|
||||
if err := g.RemoveLinuxNamespace(string(spec.UTSNamespace)); err != nil {
|
||||
return err
|
||||
}
|
||||
case specgen.Private:
|
||||
if err := g.AddOrReplaceLinuxNamespace(string(spec.UTSNamespace), ""); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
if s.PidNS.IsHost() {
|
||||
return g.RemoveLinuxNamespace(string(spec.PIDNamespace))
|
||||
}
|
||||
if s.PidNS.IsContainer() {
|
||||
logrus.Debugf("using container %s pidmode", s.PidNS.Value)
|
||||
}
|
||||
if s.PidNS.IsPod() {
|
||||
logrus.Debug("using pod pidmode")
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func utsConfigureGenerator(s *specgen.SpecGenerator, g *generate.Generator, runtime *libpod.Runtime) error {
|
||||
hostname := s.Hostname
|
||||
var err error
|
||||
if hostname == "" {
|
||||
switch {
|
||||
case s.UtsNS.IsContainer():
|
||||
utsCtr, err := runtime.LookupContainer(s.UtsNS.Value)
|
||||
case s.UtsNS.NSMode == specgen.FromContainer:
|
||||
utsCtr, err := rt.LookupContainer(s.UtsNS.Value)
|
||||
if err != nil {
|
||||
return errors.Wrapf(err, "unable to retrieve hostname from dependency container %s", s.UtsNS.Value)
|
||||
return errors.Wrapf(err, "error looking up container to share uts namespace with")
|
||||
}
|
||||
hostname = utsCtr.Hostname()
|
||||
case s.NetNS.IsHost() || s.UtsNS.IsHost():
|
||||
hostname, err = os.Hostname()
|
||||
case s.NetNS.NSMode == specgen.Host || s.UtsNS.NSMode == specgen.Host:
|
||||
tmpHostname, err := os.Hostname()
|
||||
if err != nil {
|
||||
return errors.Wrap(err, "unable to retrieve hostname of the host")
|
||||
}
|
||||
hostname = tmpHostname
|
||||
default:
|
||||
logrus.Debug("No hostname set; container's hostname will default to runtime default")
|
||||
}
|
||||
}
|
||||
|
||||
g.RemoveHostname()
|
||||
if s.Hostname != "" || !s.UtsNS.IsHost() {
|
||||
// Set the hostname in the OCI configuration only
|
||||
// if specified by the user or if we are creating
|
||||
// a new UTS namespace.
|
||||
if s.Hostname != "" || s.UtsNS.NSMode != specgen.Host {
|
||||
// Set the hostname in the OCI configuration only if specified by
|
||||
// the user or if we are creating a new UTS namespace.
|
||||
// TODO: Should we be doing this for pod or container shared
|
||||
// namespaces?
|
||||
g.SetHostname(hostname)
|
||||
}
|
||||
g.AddProcessEnv("HOSTNAME", hostname)
|
||||
|
||||
if s.UtsNS.IsPath() {
|
||||
return g.AddOrReplaceLinuxNamespace(string(spec.UTSNamespace), s.UtsNS.Value)
|
||||
}
|
||||
if s.UtsNS.IsHost() {
|
||||
return g.RemoveLinuxNamespace(string(spec.UTSNamespace))
|
||||
}
|
||||
if s.UtsNS.IsContainer() {
|
||||
logrus.Debugf("using container %s utsmode", s.UtsNS.Value)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func ipcConfigureGenerator(s *specgen.SpecGenerator, g *generate.Generator) error {
|
||||
if s.IpcNS.IsPath() {
|
||||
return g.AddOrReplaceLinuxNamespace(string(spec.IPCNamespace), s.IpcNS.Value)
|
||||
}
|
||||
if s.IpcNS.IsHost() {
|
||||
return g.RemoveLinuxNamespace(s.IpcNS.Value)
|
||||
}
|
||||
if s.IpcNS.IsContainer() {
|
||||
logrus.Debugf("Using container %s ipcmode", s.IpcNS.Value)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func cgroupConfigureGenerator(s *specgen.SpecGenerator, g *generate.Generator) error {
|
||||
if s.CgroupNS.IsPath() {
|
||||
return g.AddOrReplaceLinuxNamespace(string(spec.CgroupNamespace), s.CgroupNS.Value)
|
||||
}
|
||||
if s.CgroupNS.IsHost() {
|
||||
return g.RemoveLinuxNamespace(s.CgroupNS.Value)
|
||||
}
|
||||
if s.CgroupNS.IsPrivate() {
|
||||
return g.AddOrReplaceLinuxNamespace(string(spec.CgroupNamespace), "")
|
||||
}
|
||||
if s.CgroupNS.IsContainer() {
|
||||
logrus.Debugf("Using container %s cgroup mode", s.CgroupNS.Value)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func networkConfigureGenerator(s *specgen.SpecGenerator, g *generate.Generator) error {
|
||||
switch {
|
||||
case s.NetNS.IsHost():
|
||||
logrus.Debug("Using host netmode")
|
||||
if err := g.RemoveLinuxNamespace(string(spec.NetworkNamespace)); err != nil {
|
||||
return err
|
||||
// User
|
||||
switch s.UserNS.NSMode {
|
||||
case specgen.Path:
|
||||
if _, err := os.Stat(s.UserNS.Value); err != nil {
|
||||
return errors.Wrapf(err, "cannot find specified user namespace path %s", s.UserNS.Value)
|
||||
}
|
||||
|
||||
case s.NetNS.NSMode == specgen.NoNetwork:
|
||||
logrus.Debug("Using none netmode")
|
||||
case s.NetNS.NSMode == specgen.Bridge:
|
||||
logrus.Debug("Using bridge netmode")
|
||||
case s.NetNS.IsContainer():
|
||||
logrus.Debugf("using container %s netmode", s.NetNS.Value)
|
||||
case s.NetNS.IsPath():
|
||||
logrus.Debug("Using ns netmode")
|
||||
if err := g.AddOrReplaceLinuxNamespace(string(spec.NetworkNamespace), s.NetNS.Value); err != nil {
|
||||
return err
|
||||
}
|
||||
case s.NetNS.IsPod():
|
||||
logrus.Debug("Using pod netmode, unless pod is not sharing")
|
||||
case s.NetNS.NSMode == specgen.Slirp:
|
||||
logrus.Debug("Using slirp4netns netmode")
|
||||
default:
|
||||
return errors.Errorf("unknown network mode")
|
||||
}
|
||||
|
||||
if g.Config.Annotations == nil {
|
||||
g.Config.Annotations = make(map[string]string)
|
||||
}
|
||||
|
||||
if s.PublishImagePorts {
|
||||
g.Config.Annotations[libpod.InspectAnnotationPublishAll] = libpod.InspectResponseTrue
|
||||
} else {
|
||||
g.Config.Annotations[libpod.InspectAnnotationPublishAll] = libpod.InspectResponseFalse
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func userConfigureGenerator(s *specgen.SpecGenerator, g *generate.Generator) error {
|
||||
if s.UserNS.IsPath() {
|
||||
if err := g.AddOrReplaceLinuxNamespace(string(spec.UserNamespace), s.UserNS.Value); err != nil {
|
||||
return err
|
||||
}
|
||||
// runc complains if no mapping is specified, even if we join another ns. So provide a dummy mapping
|
||||
g.AddLinuxUIDMapping(uint32(0), uint32(0), uint32(1))
|
||||
g.AddLinuxGIDMapping(uint32(0), uint32(0), uint32(1))
|
||||
}
|
||||
|
||||
if s.IDMappings != nil {
|
||||
if (len(s.IDMappings.UIDMap) > 0 || len(s.IDMappings.GIDMap) > 0) && !s.UserNS.IsHost() {
|
||||
if err := g.AddOrReplaceLinuxNamespace(string(spec.UserNamespace), ""); err != nil {
|
||||
return err
|
||||
}
|
||||
case specgen.Host:
|
||||
if err := g.RemoveLinuxNamespace(string(spec.UserNamespace)); err != nil {
|
||||
return err
|
||||
}
|
||||
case specgen.Private:
|
||||
if err := g.AddOrReplaceLinuxNamespace(string(spec.UserNamespace), ""); err != nil {
|
||||
return err
|
||||
}
|
||||
if s.IDMappings == nil || (len(s.IDMappings.UIDMap) == 0 && len(s.IDMappings.GIDMap) == 0) {
|
||||
return errors.Errorf("must provide at least one UID or GID mapping to configure a user namespace")
|
||||
}
|
||||
for _, uidmap := range s.IDMappings.UIDMap {
|
||||
g.AddLinuxUIDMapping(uint32(uidmap.HostID), uint32(uidmap.ContainerID), uint32(uidmap.Size))
|
||||
|
|
@ -318,6 +393,54 @@ func userConfigureGenerator(s *specgen.SpecGenerator, g *generate.Generator) err
|
|||
g.AddLinuxGIDMapping(uint32(gidmap.HostID), uint32(gidmap.ContainerID), uint32(gidmap.Size))
|
||||
}
|
||||
}
|
||||
|
||||
// Cgroup
|
||||
switch s.CgroupNS.NSMode {
|
||||
case specgen.Path:
|
||||
if _, err := os.Stat(s.CgroupNS.Value); err != nil {
|
||||
return errors.Wrapf(err, "cannot find specified cgroup namespace path %s", s.CgroupNS.Value)
|
||||
}
|
||||
if err := g.AddOrReplaceLinuxNamespace(string(spec.CgroupNamespace), s.CgroupNS.Value); err != nil {
|
||||
return err
|
||||
}
|
||||
case specgen.Host:
|
||||
if err := g.RemoveLinuxNamespace(string(spec.CgroupNamespace)); err != nil {
|
||||
return err
|
||||
}
|
||||
case specgen.Private:
|
||||
if err := g.AddOrReplaceLinuxNamespace(string(spec.CgroupNamespace), ""); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
// Net
|
||||
switch s.NetNS.NSMode {
|
||||
case specgen.Path:
|
||||
if _, err := os.Stat(s.NetNS.Value); err != nil {
|
||||
return errors.Wrapf(err, "cannot find specified network namespace path %s", s.NetNS.Value)
|
||||
}
|
||||
if err := g.AddOrReplaceLinuxNamespace(string(spec.NetworkNamespace), s.NetNS.Value); err != nil {
|
||||
return err
|
||||
}
|
||||
case specgen.Host:
|
||||
if err := g.RemoveLinuxNamespace(string(spec.NetworkNamespace)); err != nil {
|
||||
return err
|
||||
}
|
||||
case specgen.Private, specgen.NoNetwork:
|
||||
if err := g.AddOrReplaceLinuxNamespace(string(spec.NetworkNamespace), ""); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
if g.Config.Annotations == nil {
|
||||
g.Config.Annotations = make(map[string]string)
|
||||
}
|
||||
if s.PublishImagePorts {
|
||||
g.Config.Annotations[libpod.InspectAnnotationPublishAll] = libpod.InspectResponseTrue
|
||||
} else {
|
||||
g.Config.Annotations[libpod.InspectAnnotationPublishAll] = libpod.InspectResponseFalse
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -217,28 +217,7 @@ func SpecGenToOCI(s *specgen.SpecGenerator, rt *libpod.Runtime, newImage *image.
|
|||
}
|
||||
|
||||
// NAMESPACES
|
||||
|
||||
if err := pidConfigureGenerator(s, &g); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if err := userConfigureGenerator(s, &g); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if err := networkConfigureGenerator(s, &g); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if err := utsConfigureGenerator(s, &g, rt); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if err := ipcConfigureGenerator(s, &g); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if err := cgroupConfigureGenerator(s, &g); err != nil {
|
||||
if err := specConfigureNamespaces(s, &g, rt); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
configSpec := g.Config
|
||||
|
|
|
|||
|
|
@ -1,6 +1,8 @@
|
|||
package specgen
|
||||
|
||||
import (
|
||||
"strings"
|
||||
|
||||
"github.com/pkg/errors"
|
||||
)
|
||||
|
||||
|
|
@ -39,6 +41,12 @@ type Namespace struct {
|
|||
Value string `json:"string,omitempty"`
|
||||
}
|
||||
|
||||
// IsDefault returns whether the namespace is set to the default setting (which
|
||||
// also includes the empty string).
|
||||
func (n *Namespace) IsDefault() bool {
|
||||
return n.NSMode == Default || n.NSMode == ""
|
||||
}
|
||||
|
||||
// IsHost returns a bool if the namespace is host based
|
||||
func (n *Namespace) IsHost() bool {
|
||||
return n.NSMode == Host
|
||||
|
|
@ -69,11 +77,24 @@ func validateNetNS(n *Namespace) error {
|
|||
return nil
|
||||
}
|
||||
switch n.NSMode {
|
||||
case Host, Path, FromContainer, FromPod, Private, NoNetwork, Bridge, Slirp:
|
||||
case "", Default, Host, Path, FromContainer, FromPod, Private, NoNetwork, Bridge, Slirp:
|
||||
break
|
||||
default:
|
||||
return errors.Errorf("invalid network %q", n.NSMode)
|
||||
}
|
||||
|
||||
// Path and From Container MUST have a string value set
|
||||
if n.NSMode == Path || n.NSMode == FromContainer {
|
||||
if len(n.Value) < 1 {
|
||||
return errors.Errorf("namespace mode %s requires a value", n.NSMode)
|
||||
}
|
||||
} else {
|
||||
// All others must NOT set a string value
|
||||
if len(n.Value) > 0 {
|
||||
return errors.Errorf("namespace value %s cannot be provided with namespace mode %s", n.Value, n.NSMode)
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
|
|
@ -83,6 +104,15 @@ func (n *Namespace) validate() error {
|
|||
if n == nil {
|
||||
return nil
|
||||
}
|
||||
switch n.NSMode {
|
||||
case "", Default, Host, Path, FromContainer, FromPod, Private:
|
||||
// Valid, do nothing
|
||||
case NoNetwork, Bridge, Slirp:
|
||||
return errors.Errorf("cannot use network modes with non-network namespace")
|
||||
default:
|
||||
return errors.Errorf("invalid namespace type %s specified", n.NSMode)
|
||||
}
|
||||
|
||||
// Path and From Container MUST have a string value set
|
||||
if n.NSMode == Path || n.NSMode == FromContainer {
|
||||
if len(n.Value) < 1 {
|
||||
|
|
@ -96,3 +126,73 @@ func (n *Namespace) validate() error {
|
|||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// ParseNamespace parses a namespace in string form.
|
||||
// This is not intended for the network namespace, which has a separate
|
||||
// function.
|
||||
func ParseNamespace(ns string) (Namespace, error) {
|
||||
toReturn := Namespace{}
|
||||
switch {
|
||||
case ns == "host":
|
||||
toReturn.NSMode = Host
|
||||
case ns == "private":
|
||||
toReturn.NSMode = Private
|
||||
case strings.HasPrefix(ns, "ns:"):
|
||||
split := strings.SplitN(ns, ":", 2)
|
||||
if len(split) != 2 {
|
||||
return toReturn, errors.Errorf("must provide a path to a namespace when specifying ns:")
|
||||
}
|
||||
toReturn.NSMode = Path
|
||||
toReturn.Value = split[1]
|
||||
case strings.HasPrefix(ns, "container:"):
|
||||
split := strings.SplitN(ns, ":", 2)
|
||||
if len(split) != 2 {
|
||||
return toReturn, errors.Errorf("must provide name or ID or a container when specifying container:")
|
||||
}
|
||||
toReturn.NSMode = FromContainer
|
||||
toReturn.Value = split[1]
|
||||
default:
|
||||
return toReturn, errors.Errorf("unrecognized namespace mode %s passed", ns)
|
||||
}
|
||||
|
||||
return toReturn, nil
|
||||
}
|
||||
|
||||
// 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) (Namespace, []string, error) {
|
||||
toReturn := Namespace{}
|
||||
var cniNetworks []string
|
||||
switch {
|
||||
case ns == "bridge":
|
||||
toReturn.NSMode = Bridge
|
||||
case ns == "none":
|
||||
toReturn.NSMode = NoNetwork
|
||||
case ns == "host":
|
||||
toReturn.NSMode = Host
|
||||
case ns == "private":
|
||||
toReturn.NSMode = Private
|
||||
case strings.HasPrefix(ns, "ns:"):
|
||||
split := strings.SplitN(ns, ":", 2)
|
||||
if len(split) != 2 {
|
||||
return toReturn, nil, errors.Errorf("must provide a path to a namespace when specifying ns:")
|
||||
}
|
||||
toReturn.NSMode = Path
|
||||
toReturn.Value = split[1]
|
||||
case strings.HasPrefix(ns, "container:"):
|
||||
split := strings.SplitN(ns, ":", 2)
|
||||
if len(split) != 2 {
|
||||
return toReturn, nil, errors.Errorf("must provide name or ID or a container when specifying container:")
|
||||
}
|
||||
toReturn.NSMode = FromContainer
|
||||
toReturn.Value = split[1]
|
||||
default:
|
||||
// Assume we have been given a list of CNI networks.
|
||||
// Which only works in bridge mode, so set that.
|
||||
cniNetworks = strings.Split(ns, ",")
|
||||
toReturn.NSMode = Bridge
|
||||
}
|
||||
|
||||
return toReturn, cniNetworks, nil
|
||||
}
|
||||
|
|
|
|||
|
|
@ -5,7 +5,6 @@ import (
|
|||
"syscall"
|
||||
|
||||
"github.com/containers/image/v5/manifest"
|
||||
"github.com/containers/libpod/pkg/rootless"
|
||||
"github.com/containers/storage"
|
||||
"github.com/cri-o/ocicni/pkg/ocicni"
|
||||
spec "github.com/opencontainers/runtime-spec/specs-go"
|
||||
|
|
@ -283,25 +282,20 @@ type ContainerNetworkConfig struct {
|
|||
// namespace.
|
||||
// Mandatory.
|
||||
NetNS Namespace `json:"netns,omitempty"`
|
||||
// ConfigureNetNS is whether Libpod will configure the container's
|
||||
// network namespace to send and receive traffic.
|
||||
// Only available is NetNS is private - conflicts with other NetNS
|
||||
// modes.
|
||||
ConfigureNetNS bool `json:"configure_netns,omitempty"`
|
||||
// StaticIP is the a IPv4 address of the container.
|
||||
// Only available if ConfigureNetNS is true.
|
||||
// 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 ConfigureNetNS is true.
|
||||
// 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 ConfigureNetNS is true.
|
||||
// Only available if NetNS is set to bridge.
|
||||
// Optional.
|
||||
StaticMAC *net.HardwareAddr `json:"static_mac,omitempty"`
|
||||
// PortBindings is a set of ports to map into the container.
|
||||
// Only available if ConfigureNetNS is true.
|
||||
// Only available if NetNS is set to bridge or slirp.
|
||||
// Optional.
|
||||
PortMappings []ocicni.PortMapping `json:"portmappings,omitempty"`
|
||||
// PublishImagePorts will publish ports specified in the image to random
|
||||
|
|
@ -312,7 +306,7 @@ type ContainerNetworkConfig struct {
|
|||
// 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 ConfigureNetNS is true.
|
||||
// Only available if NetNS is set to bridge.
|
||||
// Optional.
|
||||
CNINetworks []string `json:"cni_networks,omitempty"`
|
||||
// UseImageResolvConf indicates that resolv.conf should not be managed
|
||||
|
|
@ -402,18 +396,9 @@ type Volumes struct {
|
|||
|
||||
// NewSpecGenerator returns a SpecGenerator struct given one of two mandatory inputs
|
||||
func NewSpecGenerator(image string) *SpecGenerator {
|
||||
networkConfig := ContainerNetworkConfig{
|
||||
NetNS: Namespace{
|
||||
NSMode: Bridge,
|
||||
},
|
||||
}
|
||||
csc := ContainerStorageConfig{Image: image}
|
||||
if rootless.IsRootless() {
|
||||
networkConfig.NetNS.NSMode = Slirp
|
||||
}
|
||||
return &SpecGenerator{
|
||||
ContainerStorageConfig: csc,
|
||||
ContainerNetworkConfig: networkConfig,
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
Loading…
Reference in New Issue