InfraContainer Rework

InfraContainer should go through the same creation process as regular containers. This change was from the cmd level
down, involving new container CLI opts and specgen creating functions. What now happens is that both container and pod
cli options are populated in cmd and used to create a podSpecgen and a containerSpecgen. The process then goes as follows

FillOutSpecGen (infra) -> MapSpec (podOpts -> infraOpts) -> PodCreate -> MakePod -> createPodOptions -> NewPod -> CompleteSpec (infra) -> MakeContainer -> NewContainer -> newContainer -> AddInfra (to pod state)

Signed-off-by: cdoern <cdoern@redhat.com>
This commit is contained in:
cdoern 2021-07-14 16:30:28 -04:00
parent 94c37d7d47
commit d28e85741f
51 changed files with 1988 additions and 2336 deletions

File diff suppressed because it is too large Load Diff

View File

@ -19,122 +19,6 @@ import (
"github.com/pkg/errors" "github.com/pkg/errors"
) )
type ContainerCLIOpts struct {
Annotation []string
Attach []string
Authfile string
BlkIOWeight string
BlkIOWeightDevice []string
CapAdd []string
CapDrop []string
CgroupNS string
CGroupsMode string
CGroupParent string
CIDFile string
ConmonPIDFile string
CPUPeriod uint64
CPUQuota int64
CPURTPeriod uint64
CPURTRuntime int64
CPUShares uint64
CPUS float64
CPUSetCPUs string
CPUSetMems string
Devices []string
DeviceCGroupRule []string
DeviceReadBPs []string
DeviceReadIOPs []string
DeviceWriteBPs []string
DeviceWriteIOPs []string
Entrypoint *string
Env []string
EnvHost bool
EnvFile []string
Expose []string
GIDMap []string
GroupAdd []string
HealthCmd string
HealthInterval string
HealthRetries uint
HealthStartPeriod string
HealthTimeout string
Hostname string
HTTPProxy bool
ImageVolume string
Init bool
InitContainerType string
InitPath string
Interactive bool
IPC string
KernelMemory string
Label []string
LabelFile []string
LogDriver string
LogOptions []string
Memory string
MemoryReservation string
MemorySwap string
MemorySwappiness int64
Name string
NoHealthCheck bool
OOMKillDisable bool
OOMScoreAdj int
Arch string
OS string
Variant string
Personality string
PID string
PIDsLimit *int64
Platform string
Pod string
PodIDFile string
PreserveFDs uint
Privileged bool
PublishAll bool
Pull string
Quiet bool
ReadOnly bool
ReadOnlyTmpFS bool
Restart string
Replace bool
Requires []string
Rm bool
RootFS bool
Secrets []string
SecurityOpt []string
SdNotifyMode string
ShmSize string
SignaturePolicy string
StopSignal string
StopTimeout uint
StorageOpt []string
SubUIDName string
SubGIDName string
Sysctl []string
Systemd string
Timeout uint
TLSVerify bool
TmpFS []string
TTY bool
Timezone string
Umask string
UIDMap []string
Ulimit []string
User string
UserNS string
UTS string
Mount []string
Volume []string
VolumesFrom []string
Workdir string
SeccompPolicy string
PidFile string
Net *entities.NetOptions
CgroupConf []string
}
func stringMaptoArray(m map[string]string) []string { func stringMaptoArray(m map[string]string) []string {
a := make([]string, 0, len(m)) a := make([]string, 0, len(m))
for k, v := range m { for k, v := range m {
@ -145,7 +29,7 @@ func stringMaptoArray(m map[string]string) []string {
// ContainerCreateToContainerCLIOpts converts a compat input struct to cliopts so it can be converted to // ContainerCreateToContainerCLIOpts converts a compat input struct to cliopts so it can be converted to
// a specgen spec. // a specgen spec.
func ContainerCreateToContainerCLIOpts(cc handlers.CreateContainerConfig, rtc *config.Config) (*ContainerCLIOpts, []string, error) { func ContainerCreateToContainerCLIOpts(cc handlers.CreateContainerConfig, rtc *config.Config) (*entities.ContainerCreateOptions, []string, error) {
var ( var (
capAdd []string capAdd []string
cappDrop []string cappDrop []string
@ -341,7 +225,7 @@ func ContainerCreateToContainerCLIOpts(cc handlers.CreateContainerConfig, rtc *c
// Note: several options here are marked as "don't need". this is based // Note: several options here are marked as "don't need". this is based
// on speculation by Matt and I. We think that these come into play later // on speculation by Matt and I. We think that these come into play later
// like with start. We believe this is just a difference in podman/compat // like with start. We believe this is just a difference in podman/compat
cliOpts := ContainerCLIOpts{ cliOpts := entities.ContainerCreateOptions{
// Attach: nil, // don't need? // Attach: nil, // don't need?
Authfile: "", Authfile: "",
CapAdd: append(capAdd, cc.HostConfig.CapAdd...), CapAdd: append(capAdd, cc.HostConfig.CapAdd...),

View File

@ -8,8 +8,10 @@ import (
"github.com/containers/podman/v3/libpod/define" "github.com/containers/podman/v3/libpod/define"
"github.com/containers/podman/v3/pkg/domain/entities" "github.com/containers/podman/v3/pkg/domain/entities"
"github.com/containers/podman/v3/pkg/specgen" "github.com/containers/podman/v3/pkg/specgen"
"github.com/containers/podman/v3/pkg/specgenutil"
"github.com/pkg/errors" "github.com/pkg/errors"
"github.com/spf13/cobra" "github.com/spf13/cobra"
"github.com/spf13/pflag"
) )
func DefineNetFlags(cmd *cobra.Command) { func DefineNetFlags(cmd *cobra.Command) {
@ -87,12 +89,15 @@ func DefineNetFlags(cmd *cobra.Command) {
// NetFlagsToNetOptions parses the network flags for the given cmd. // NetFlagsToNetOptions parses the network flags for the given cmd.
// The netnsFromConfig bool is used to indicate if the --network flag // The netnsFromConfig bool is used to indicate if the --network flag
// should always be parsed regardless if it was set on the cli. // should always be parsed regardless if it was set on the cli.
func NetFlagsToNetOptions(cmd *cobra.Command, netnsFromConfig bool) (*entities.NetOptions, error) { func NetFlagsToNetOptions(opts *entities.NetOptions, flags pflag.FlagSet, netnsFromConfig bool) (*entities.NetOptions, error) {
var ( var (
err error err error
) )
opts := entities.NetOptions{} if opts == nil {
opts.AddHosts, err = cmd.Flags().GetStringSlice("add-host") opts = &entities.NetOptions{}
}
opts.AddHosts, err = flags.GetStringSlice("add-host")
if err != nil { if err != nil {
return nil, err return nil, err
} }
@ -103,56 +108,50 @@ func NetFlagsToNetOptions(cmd *cobra.Command, netnsFromConfig bool) (*entities.N
} }
} }
if cmd.Flags().Changed("dns") { servers, err := flags.GetStringSlice("dns")
servers, err := cmd.Flags().GetStringSlice("dns") if err != nil {
if err != nil { return nil, err
return nil, err }
} for _, d := range servers {
for _, d := range servers { if d == "none" {
if d == "none" { opts.UseImageResolvConf = true
opts.UseImageResolvConf = true if len(servers) > 1 {
if len(servers) > 1 { return nil, errors.Errorf("%s is not allowed to be specified with other DNS ip addresses", d)
return nil, errors.Errorf("%s is not allowed to be specified with other DNS ip addresses", d)
}
break
} }
dns := net.ParseIP(d) break
if dns == nil {
return nil, errors.Errorf("%s is not an ip address", d)
}
opts.DNSServers = append(opts.DNSServers, dns)
} }
dns := net.ParseIP(d)
if dns == nil {
return nil, errors.Errorf("%s is not an ip address", d)
}
opts.DNSServers = append(opts.DNSServers, dns)
} }
if cmd.Flags().Changed("dns-opt") { options, err := flags.GetStringSlice("dns-opt")
options, err := cmd.Flags().GetStringSlice("dns-opt") if err != nil {
if err != nil { return nil, err
}
opts.DNSOptions = options
dnsSearches, err := flags.GetStringSlice("dns-search")
if err != nil {
return nil, err
}
// Validate domains are good
for _, dom := range dnsSearches {
if dom == "." {
if len(dnsSearches) > 1 {
return nil, errors.Errorf("cannot pass additional search domains when also specifying '.'")
}
continue
}
if _, err := parse.ValidateDomain(dom); err != nil {
return nil, err return nil, err
} }
opts.DNSOptions = options
} }
opts.DNSSearch = dnsSearches
if cmd.Flags().Changed("dns-search") { m, err := flags.GetString("mac-address")
dnsSearches, err := cmd.Flags().GetStringSlice("dns-search")
if err != nil {
return nil, err
}
// Validate domains are good
for _, dom := range dnsSearches {
if dom == "." {
if len(dnsSearches) > 1 {
return nil, errors.Errorf("cannot pass additional search domains when also specifying '.'")
}
continue
}
if _, err := parse.ValidateDomain(dom); err != nil {
return nil, err
}
}
opts.DNSSearch = dnsSearches
}
m, err := cmd.Flags().GetString("mac-address")
if err != nil { if err != nil {
return nil, err return nil, err
} }
@ -164,18 +163,18 @@ func NetFlagsToNetOptions(cmd *cobra.Command, netnsFromConfig bool) (*entities.N
opts.StaticMAC = &mac opts.StaticMAC = &mac
} }
inputPorts, err := cmd.Flags().GetStringSlice("publish") inputPorts, err := flags.GetStringSlice("publish")
if err != nil { if err != nil {
return nil, err return nil, err
} }
if len(inputPorts) > 0 { if len(inputPorts) > 0 {
opts.PublishPorts, err = CreatePortBindings(inputPorts) opts.PublishPorts, err = specgenutil.CreatePortBindings(inputPorts)
if err != nil { if err != nil {
return nil, err return nil, err
} }
} }
ip, err := cmd.Flags().GetString("ip") ip, err := flags.GetString("ip")
if err != nil { if err != nil {
return nil, err return nil, err
} }
@ -190,15 +189,15 @@ func NetFlagsToNetOptions(cmd *cobra.Command, netnsFromConfig bool) (*entities.N
opts.StaticIP = &staticIP opts.StaticIP = &staticIP
} }
opts.NoHosts, err = cmd.Flags().GetBool("no-hosts") opts.NoHosts, err = flags.GetBool("no-hosts")
if err != nil { if err != nil {
return nil, err return nil, err
} }
// parse the --network value only when the flag is set or we need to use // parse the --network value only when the flag is set or we need to use
// the netns config value, e.g. when --pod is not used // the netns config value, e.g. when --pod is not used
if netnsFromConfig || cmd.Flag("network").Changed { if netnsFromConfig || flags.Changed("network") {
network, err := cmd.Flags().GetString("network") network, err := flags.GetString("network")
if err != nil { if err != nil {
return nil, err return nil, err
} }
@ -215,12 +214,13 @@ func NetFlagsToNetOptions(cmd *cobra.Command, netnsFromConfig bool) (*entities.N
opts.CNINetworks = cniNets opts.CNINetworks = cniNets
} }
aliases, err := cmd.Flags().GetStringSlice("network-alias") aliases, err := flags.GetStringSlice("network-alias")
if err != nil { if err != nil {
return nil, err return nil, err
} }
if len(aliases) > 0 { if len(aliases) > 0 {
opts.Aliases = aliases opts.Aliases = aliases
} }
return &opts, err
return opts, err
} }

View File

@ -17,6 +17,7 @@ import (
"github.com/containers/podman/v3/libpod/define" "github.com/containers/podman/v3/libpod/define"
"github.com/containers/podman/v3/pkg/domain/entities" "github.com/containers/podman/v3/pkg/domain/entities"
"github.com/containers/podman/v3/pkg/specgen" "github.com/containers/podman/v3/pkg/specgen"
"github.com/containers/podman/v3/pkg/specgenutil"
"github.com/containers/podman/v3/pkg/util" "github.com/containers/podman/v3/pkg/util"
"github.com/pkg/errors" "github.com/pkg/errors"
"github.com/spf13/cobra" "github.com/spf13/cobra"
@ -52,8 +53,8 @@ var (
) )
var ( var (
cliVals common.ContainerCLIOpts
InitContainerType string InitContainerType string
cliVals entities.ContainerCreateOptions
) )
func createFlags(cmd *cobra.Command) { func createFlags(cmd *cobra.Command) {
@ -67,13 +68,18 @@ func createFlags(cmd *cobra.Command) {
) )
flags.SetInterspersed(false) flags.SetInterspersed(false)
common.DefineCreateFlags(cmd, &cliVals) common.DefineCreateFlags(cmd, &cliVals, false)
common.DefineNetFlags(cmd) common.DefineNetFlags(cmd)
flags.SetNormalizeFunc(utils.AliasFlags) flags.SetNormalizeFunc(utils.AliasFlags)
if registry.IsRemote() { if registry.IsRemote() {
_ = flags.MarkHidden("conmon-pidfile") if cliVals.IsInfra {
_ = flags.MarkHidden("infra-conmon-pidfile")
} else {
_ = flags.MarkHidden("conmon-pidfile")
}
_ = flags.MarkHidden("pidfile") _ = flags.MarkHidden("pidfile")
} }
@ -97,7 +103,8 @@ func create(cmd *cobra.Command, args []string) error {
var ( var (
err error err error
) )
cliVals.Net, err = common.NetFlagsToNetOptions(cmd, cliVals.Pod == "" && cliVals.PodIDFile == "") flags := cmd.Flags()
cliVals.Net, err = common.NetFlagsToNetOptions(nil, *flags, cliVals.Pod == "" && cliVals.PodIDFile == "")
if err != nil { if err != nil {
return err return err
} }
@ -113,22 +120,22 @@ func create(cmd *cobra.Command, args []string) error {
cliVals.InitContainerType = initctr cliVals.InitContainerType = initctr
} }
if err := createInit(cmd); err != nil { cliVals, err = CreateInit(cmd, cliVals, false)
if err != nil {
return err return err
} }
imageName := args[0] imageName := args[0]
rawImageName := "" rawImageName := ""
if !cliVals.RootFS { if !cliVals.RootFS {
rawImageName = args[0] rawImageName = args[0]
name, err := pullImage(args[0]) name, err := PullImage(args[0], cliVals)
if err != nil { if err != nil {
return err return err
} }
imageName = name imageName = name
} }
s := specgen.NewSpecGenerator(imageName, cliVals.RootFS) s := specgen.NewSpecGenerator(imageName, cliVals.RootFS)
if err := common.FillOutSpecGen(s, &cliVals, args); err != nil { if err := specgenutil.FillOutSpecGen(s, &cliVals, args); err != nil {
return err return err
} }
s.RawImageName = rawImageName s.RawImageName = rawImageName
@ -169,100 +176,101 @@ func replaceContainer(name string) error {
return removeContainers([]string{name}, rmOptions, false) return removeContainers([]string{name}, rmOptions, false)
} }
func createInit(c *cobra.Command) error { func CreateInit(c *cobra.Command, vals entities.ContainerCreateOptions, isInfra bool) (entities.ContainerCreateOptions, error) {
cliVals.StorageOpt = registry.PodmanConfig().StorageOpts vals.UserNS = c.Flag("userns").Value.String()
if c.Flag("shm-size").Changed {
cliVals.ShmSize = c.Flag("shm-size").Value.String()
}
if (c.Flag("dns").Changed || c.Flag("dns-opt").Changed || c.Flag("dns-search").Changed) && (cliVals.Net.Network.NSMode == specgen.NoNetwork || cliVals.Net.Network.IsContainer()) {
return errors.Errorf("conflicting options: dns and the network mode.")
}
if c.Flag("cpu-period").Changed && c.Flag("cpus").Changed {
return errors.Errorf("--cpu-period and --cpus cannot be set together")
}
if c.Flag("cpu-quota").Changed && c.Flag("cpus").Changed {
return errors.Errorf("--cpu-quota and --cpus cannot be set together")
}
if c.Flag("pod").Changed && !strings.HasPrefix(c.Flag("pod").Value.String(), "new:") && c.Flag("userns").Changed {
return errors.Errorf("--userns and --pod cannot be set together")
}
noHosts, err := c.Flags().GetBool("no-hosts")
if err != nil {
return err
}
if noHosts && c.Flag("add-host").Changed {
return errors.Errorf("--no-hosts and --add-host cannot be set together")
}
cliVals.UserNS = c.Flag("userns").Value.String()
// if user did not modify --userns flag and did turn on // if user did not modify --userns flag and did turn on
// uid/gid mappings, set userns flag to "private" // uid/gid mappings, set userns flag to "private"
if !c.Flag("userns").Changed && cliVals.UserNS == "host" { if !c.Flag("userns").Changed && vals.UserNS == "host" {
if len(cliVals.UIDMap) > 0 || if len(vals.UIDMap) > 0 ||
len(cliVals.GIDMap) > 0 || len(vals.GIDMap) > 0 ||
cliVals.SubUIDName != "" || vals.SubUIDName != "" ||
cliVals.SubGIDName != "" { vals.SubGIDName != "" {
cliVals.UserNS = "private" vals.UserNS = "private"
} }
} }
cliVals.IPC = c.Flag("ipc").Value.String() if !isInfra {
cliVals.UTS = c.Flag("uts").Value.String() if c.Flag("shm-size").Changed {
cliVals.PID = c.Flag("pid").Value.String() vals.ShmSize = c.Flag("shm-size").Value.String()
cliVals.CgroupNS = c.Flag("cgroupns").Value.String() }
if c.Flag("entrypoint").Changed { if c.Flag("cpu-period").Changed && c.Flag("cpus").Changed {
val := c.Flag("entrypoint").Value.String() return vals, errors.Errorf("--cpu-period and --cpus cannot be set together")
cliVals.Entrypoint = &val }
} if c.Flag("cpu-quota").Changed && c.Flag("cpus").Changed {
return vals, errors.Errorf("--cpu-quota and --cpus cannot be set together")
}
vals.IPC = c.Flag("ipc").Value.String()
vals.UTS = c.Flag("uts").Value.String()
vals.PID = c.Flag("pid").Value.String()
vals.CgroupNS = c.Flag("cgroupns").Value.String()
if c.Flags().Changed("group-add") { if c.Flags().Changed("group-add") {
groups := []string{} groups := []string{}
for _, g := range cliVals.GroupAdd { for _, g := range cliVals.GroupAdd {
if g == "keep-groups" { if g == "keep-groups" {
if len(cliVals.GroupAdd) > 1 { if len(cliVals.GroupAdd) > 1 {
return errors.New("the '--group-add keep-groups' option is not allowed with any other --group-add options") return vals, errors.New("the '--group-add keep-groups' option is not allowed with any other --group-add options")
}
if registry.IsRemote() {
return vals, errors.New("the '--group-add keep-groups' option is not supported in remote mode")
}
vals.Annotation = append(vals.Annotation, "run.oci.keep_original_groups=1")
} else {
groups = append(groups, g)
} }
if registry.IsRemote() {
return errors.New("the '--group-add keep-groups' option is not supported in remote mode")
}
cliVals.Annotation = append(cliVals.Annotation, "run.oci.keep_original_groups=1")
} else {
groups = append(groups, g)
} }
vals.GroupAdd = groups
} }
cliVals.GroupAdd = groups
if c.Flags().Changed("pids-limit") {
val := c.Flag("pids-limit").Value.String()
pidsLimit, err := strconv.ParseInt(val, 10, 32)
if err != nil {
return vals, err
}
vals.PIDsLimit = &pidsLimit
}
if c.Flags().Changed("env") {
env, err := c.Flags().GetStringArray("env")
if err != nil {
return vals, errors.Wrapf(err, "retrieve env flag")
}
vals.Env = env
}
if c.Flag("cgroups").Changed && vals.CGroupsMode == "split" && registry.IsRemote() {
return vals, errors.Errorf("the option --cgroups=%q is not supported in remote mode", vals.CGroupsMode)
}
if c.Flag("pod").Changed && !strings.HasPrefix(c.Flag("pod").Value.String(), "new:") && c.Flag("userns").Changed {
return vals, errors.Errorf("--userns and --pod cannot be set together")
}
}
if (c.Flag("dns").Changed || c.Flag("dns-opt").Changed || c.Flag("dns-search").Changed) && vals.Net != nil && (vals.Net.Network.NSMode == specgen.NoNetwork || vals.Net.Network.IsContainer()) {
return vals, errors.Errorf("conflicting options: dns and the network mode: " + string(vals.Net.Network.NSMode))
}
noHosts, err := c.Flags().GetBool("no-hosts")
if err != nil {
return vals, err
}
if noHosts && c.Flag("add-host").Changed {
return vals, errors.Errorf("--no-hosts and --add-host cannot be set together")
} }
if c.Flags().Changed("pids-limit") { if !isInfra && c.Flag("entrypoint").Changed {
val := c.Flag("pids-limit").Value.String() val := c.Flag("entrypoint").Value.String()
pidsLimit, err := strconv.ParseInt(val, 10, 32) vals.Entrypoint = &val
if err != nil { } else if isInfra && c.Flag("infra-command").Changed {
return err
}
cliVals.PIDsLimit = &pidsLimit
}
if c.Flags().Changed("env") {
env, err := c.Flags().GetStringArray("env")
if err != nil {
return errors.Wrapf(err, "retrieve env flag")
}
cliVals.Env = env
}
if c.Flag("cgroups").Changed && cliVals.CGroupsMode == "split" && registry.IsRemote() {
return errors.Errorf("the option --cgroups=%q is not supported in remote mode", cliVals.CGroupsMode)
} }
// Docker-compatibility: the "-h" flag for run/create is reserved for // Docker-compatibility: the "-h" flag for run/create is reserved for
// the hostname (see https://github.com/containers/podman/issues/1367). // the hostname (see https://github.com/containers/podman/issues/1367).
return nil return vals, nil
} }
func pullImage(imageName string) (string, error) { func PullImage(imageName string, cliVals entities.ContainerCreateOptions) (string, error) {
pullPolicy, err := config.ParsePullPolicy(cliVals.Pull) pullPolicy, err := config.ValidatePullPolicy(cliVals.Pull)
if err != nil { if err != nil {
return "", err return "", err
} }
@ -316,11 +324,14 @@ func createPodIfNecessary(s *specgen.SpecGenerator, netOpts *entities.NetOptions
return nil, errors.Errorf("new pod name must be at least one character") return nil, errors.Errorf("new pod name must be at least one character")
} }
userns, err := specgen.ParseUserNamespace(cliVals.UserNS) var err error
if err != nil { uns := specgen.Namespace{NSMode: specgen.Default}
return nil, err if cliVals.UserNS != "" {
uns, err = specgen.ParseNamespace(cliVals.UserNS)
if err != nil {
return nil, err
}
} }
createOptions := entities.PodCreateOptions{ createOptions := entities.PodCreateOptions{
Name: podName, Name: podName,
Infra: true, Infra: true,
@ -330,12 +341,36 @@ func createPodIfNecessary(s *specgen.SpecGenerator, netOpts *entities.NetOptions
Cpus: cliVals.CPUS, Cpus: cliVals.CPUS,
CpusetCpus: cliVals.CPUSetCPUs, CpusetCpus: cliVals.CPUSetCPUs,
Pid: cliVals.PID, Pid: cliVals.PID,
Userns: userns, Userns: uns,
} }
// Unset config values we passed to the pod to prevent them being used twice for the container and pod. // Unset config values we passed to the pod to prevent them being used twice for the container and pod.
s.ContainerBasicConfig.Hostname = "" s.ContainerBasicConfig.Hostname = ""
s.ContainerNetworkConfig = specgen.ContainerNetworkConfig{} s.ContainerNetworkConfig = specgen.ContainerNetworkConfig{}
s.Pod = podName s.Pod = podName
return registry.ContainerEngine().PodCreate(context.Background(), createOptions) podSpec := entities.PodSpec{}
podGen := specgen.NewPodSpecGenerator()
podSpec.PodSpecGen = *podGen
podGen, err = entities.ToPodSpecGen(*&podSpec.PodSpecGen, &createOptions)
if err != nil {
return nil, err
}
infraOpts := entities.ContainerCreateOptions{ImageVolume: "bind", Net: netOpts, Quiet: true}
rawImageName := config.DefaultInfraImage
name, err := PullImage(rawImageName, infraOpts)
if err != nil {
fmt.Println(err)
}
imageName := name
podGen.InfraImage = imageName
podGen.InfraContainerSpec = specgen.NewSpecGenerator(imageName, false)
podGen.InfraContainerSpec.RawImageName = rawImageName
podGen.InfraContainerSpec.NetworkOptions = podGen.NetworkOptions
err = specgenutil.FillOutSpecGen(podGen.InfraContainerSpec, &infraOpts, []string{})
if err != nil {
return nil, err
}
podSpec.PodSpecGen = *podGen
return registry.ContainerEngine().PodCreate(context.Background(), podSpec)
} }

View File

@ -13,6 +13,7 @@ import (
"github.com/containers/podman/v3/cmd/podman/utils" "github.com/containers/podman/v3/cmd/podman/utils"
"github.com/containers/podman/v3/cmd/podman/validate" "github.com/containers/podman/v3/cmd/podman/validate"
"github.com/containers/podman/v3/pkg/domain/entities" "github.com/containers/podman/v3/pkg/domain/entities"
"github.com/containers/podman/v3/pkg/specgenutil"
"github.com/spf13/cobra" "github.com/spf13/cobra"
) )
@ -63,7 +64,7 @@ func prune(cmd *cobra.Command, args []string) error {
} }
} }
pruneOptions.Filters, err = common.ParseFilters(filter) pruneOptions.Filters, err = specgenutil.ParseFilters(filter)
if err != nil { if err != nil {
return err return err
} }

View File

@ -11,6 +11,7 @@ import (
"github.com/containers/podman/v3/cmd/podman/validate" "github.com/containers/podman/v3/cmd/podman/validate"
"github.com/containers/podman/v3/pkg/domain/entities" "github.com/containers/podman/v3/pkg/domain/entities"
"github.com/containers/podman/v3/pkg/rootless" "github.com/containers/podman/v3/pkg/rootless"
"github.com/containers/podman/v3/pkg/specgenutil"
"github.com/pkg/errors" "github.com/pkg/errors"
"github.com/spf13/cobra" "github.com/spf13/cobra"
) )
@ -106,7 +107,7 @@ func restore(cmd *cobra.Command, args []string) error {
return err return err
} }
if len(inputPorts) > 0 { if len(inputPorts) > 0 {
restoreOptions.PublishPorts, err = common.CreatePortBindings(inputPorts) restoreOptions.PublishPorts, err = specgenutil.CreatePortBindings(inputPorts)
if err != nil { if err != nil {
return err return err
} }

View File

@ -14,6 +14,7 @@ import (
"github.com/containers/podman/v3/pkg/errorhandling" "github.com/containers/podman/v3/pkg/errorhandling"
"github.com/containers/podman/v3/pkg/rootless" "github.com/containers/podman/v3/pkg/rootless"
"github.com/containers/podman/v3/pkg/specgen" "github.com/containers/podman/v3/pkg/specgen"
"github.com/containers/podman/v3/pkg/specgenutil"
"github.com/pkg/errors" "github.com/pkg/errors"
"github.com/sirupsen/logrus" "github.com/sirupsen/logrus"
"github.com/spf13/cobra" "github.com/spf13/cobra"
@ -60,7 +61,7 @@ func runFlags(cmd *cobra.Command) {
flags := cmd.Flags() flags := cmd.Flags()
flags.SetInterspersed(false) flags.SetInterspersed(false)
common.DefineCreateFlags(cmd, &cliVals) common.DefineCreateFlags(cmd, &cliVals, false)
common.DefineNetFlags(cmd) common.DefineNetFlags(cmd)
flags.SetNormalizeFunc(utils.AliasFlags) flags.SetNormalizeFunc(utils.AliasFlags)
@ -106,10 +107,6 @@ func init() {
func run(cmd *cobra.Command, args []string) error { func run(cmd *cobra.Command, args []string) error {
var err error var err error
cliVals.Net, err = common.NetFlagsToNetOptions(cmd, cliVals.Pod == "" && cliVals.PodIDFile == "")
if err != nil {
return err
}
// TODO: Breaking change should be made fatal in next major Release // TODO: Breaking change should be made fatal in next major Release
if cliVals.TTY && cliVals.Interactive && !terminal.IsTerminal(int(os.Stdin.Fd())) { if cliVals.TTY && cliVals.Interactive && !terminal.IsTerminal(int(os.Stdin.Fd())) {
@ -122,11 +119,17 @@ func run(cmd *cobra.Command, args []string) error {
} }
} }
runOpts.CIDFile = cliVals.CIDFile flags := cmd.Flags()
runOpts.Rm = cliVals.Rm cliVals.Net, err = common.NetFlagsToNetOptions(nil, *flags, cliVals.Pod == "" && cliVals.PodIDFile == "")
if err := createInit(cmd); err != nil { if err != nil {
return err return err
} }
runOpts.CIDFile = cliVals.CIDFile
runOpts.Rm = cliVals.Rm
if cliVals, err = CreateInit(cmd, cliVals, false); err != nil {
return err
}
for fd := 3; fd < int(3+runOpts.PreserveFDs); fd++ { for fd := 3; fd < int(3+runOpts.PreserveFDs); fd++ {
if !rootless.IsFdInherited(fd) { if !rootless.IsFdInherited(fd) {
return errors.Errorf("file descriptor %d is not available - the preserve-fds option requires that file descriptors must be passed", fd) return errors.Errorf("file descriptor %d is not available - the preserve-fds option requires that file descriptors must be passed", fd)
@ -137,7 +140,7 @@ func run(cmd *cobra.Command, args []string) error {
rawImageName := "" rawImageName := ""
if !cliVals.RootFS { if !cliVals.RootFS {
rawImageName = args[0] rawImageName = args[0]
name, err := pullImage(args[0]) name, err := PullImage(args[0], cliVals)
if err != nil { if err != nil {
return err return err
} }
@ -178,7 +181,7 @@ func run(cmd *cobra.Command, args []string) error {
} }
cliVals.PreserveFDs = runOpts.PreserveFDs cliVals.PreserveFDs = runOpts.PreserveFDs
s := specgen.NewSpecGenerator(imageName, cliVals.RootFS) s := specgen.NewSpecGenerator(imageName, cliVals.RootFS)
if err := common.FillOutSpecGen(s, &cliVals, args); err != nil { if err := specgenutil.FillOutSpecGen(s, &cliVals, args); err != nil {
return err return err
} }
s.RawImageName = rawImageName s.RawImageName = rawImageName

View File

@ -12,6 +12,7 @@ import (
"github.com/containers/podman/v3/cmd/podman/utils" "github.com/containers/podman/v3/cmd/podman/utils"
"github.com/containers/podman/v3/cmd/podman/validate" "github.com/containers/podman/v3/cmd/podman/validate"
"github.com/containers/podman/v3/pkg/domain/entities" "github.com/containers/podman/v3/pkg/domain/entities"
"github.com/containers/podman/v3/pkg/specgenutil"
"github.com/spf13/cobra" "github.com/spf13/cobra"
) )
@ -59,7 +60,7 @@ func prune(cmd *cobra.Command, args []string) error {
return nil return nil
} }
} }
filterMap, err := common.ParseFilters(filter) filterMap, err := specgenutil.ParseFilters(filter)
if err != nil { if err != nil {
return err return err
} }

View File

@ -11,6 +11,7 @@ import (
"github.com/containers/podman/v3/cmd/podman/utils" "github.com/containers/podman/v3/cmd/podman/utils"
"github.com/containers/podman/v3/cmd/podman/validate" "github.com/containers/podman/v3/cmd/podman/validate"
"github.com/containers/podman/v3/pkg/domain/entities" "github.com/containers/podman/v3/pkg/domain/entities"
"github.com/containers/podman/v3/pkg/specgenutil"
"github.com/spf13/cobra" "github.com/spf13/cobra"
"github.com/spf13/pflag" "github.com/spf13/pflag"
) )
@ -67,7 +68,7 @@ func networkPrune(cmd *cobra.Command, _ []string) error {
return nil return nil
} }
} }
networkPruneOptions.Filters, err = common.ParseFilters(filter) networkPruneOptions.Filters, err = specgenutil.ParseFilters(filter)
if err != nil { if err != nil {
return err return err
} }

View File

@ -11,14 +11,17 @@ import (
"strings" "strings"
"github.com/containers/common/pkg/completion" "github.com/containers/common/pkg/completion"
"github.com/containers/common/pkg/config"
"github.com/containers/common/pkg/sysinfo" "github.com/containers/common/pkg/sysinfo"
"github.com/containers/podman/v3/cmd/podman/common" "github.com/containers/podman/v3/cmd/podman/common"
"github.com/containers/podman/v3/cmd/podman/containers"
"github.com/containers/podman/v3/cmd/podman/parse" "github.com/containers/podman/v3/cmd/podman/parse"
"github.com/containers/podman/v3/cmd/podman/registry" "github.com/containers/podman/v3/cmd/podman/registry"
"github.com/containers/podman/v3/cmd/podman/validate" "github.com/containers/podman/v3/cmd/podman/validate"
"github.com/containers/podman/v3/pkg/domain/entities" "github.com/containers/podman/v3/pkg/domain/entities"
"github.com/containers/podman/v3/pkg/errorhandling" "github.com/containers/podman/v3/pkg/errorhandling"
"github.com/containers/podman/v3/pkg/specgen" "github.com/containers/podman/v3/pkg/specgen"
"github.com/containers/podman/v3/pkg/specgenutil"
"github.com/containers/podman/v3/pkg/util" "github.com/containers/podman/v3/pkg/util"
"github.com/docker/docker/pkg/parsers" "github.com/docker/docker/pkg/parsers"
"github.com/pkg/errors" "github.com/pkg/errors"
@ -44,11 +47,11 @@ var (
var ( var (
createOptions entities.PodCreateOptions createOptions entities.PodCreateOptions
infraOptions entities.ContainerCreateOptions
labels, labelFile []string labels, labelFile []string
podIDFile string podIDFile string
replace bool replace bool
share string share string
userns string
) )
func init() { func init() {
@ -58,62 +61,19 @@ func init() {
}) })
flags := createCommand.Flags() flags := createCommand.Flags()
flags.SetInterspersed(false) flags.SetInterspersed(false)
infraOptions.IsInfra = true
common.DefineCreateFlags(createCommand, &infraOptions, true)
common.DefineNetFlags(createCommand) common.DefineNetFlags(createCommand)
cpusetflagName := "cpuset-cpus"
flags.StringVar(&createOptions.CpusetCpus, cpusetflagName, "", "CPUs in which to allow execution")
_ = createCommand.RegisterFlagCompletionFunc(cpusetflagName, completion.AutocompleteDefault)
cpusflagName := "cpus"
flags.Float64Var(&createOptions.Cpus, cpusflagName, 0.000, "set amount of CPUs for the pod")
_ = createCommand.RegisterFlagCompletionFunc(cpusflagName, completion.AutocompleteDefault)
cgroupParentflagName := "cgroup-parent"
flags.StringVar(&createOptions.CGroupParent, cgroupParentflagName, "", "Set parent cgroup for the pod")
_ = createCommand.RegisterFlagCompletionFunc(cgroupParentflagName, completion.AutocompleteDefault)
usernsFlagName := "userns"
flags.StringVar(&userns, usernsFlagName, os.Getenv("PODMAN_USERNS"), "User namespace to use")
_ = createCommand.RegisterFlagCompletionFunc(usernsFlagName, common.AutocompleteUserNamespace)
flags.BoolVar(&createOptions.Infra, "infra", true, "Create an infra container associated with the pod to share namespaces with") flags.BoolVar(&createOptions.Infra, "infra", true, "Create an infra container associated with the pod to share namespaces with")
infraConmonPidfileFlagName := "infra-conmon-pidfile"
flags.StringVar(&createOptions.InfraConmonPidFile, infraConmonPidfileFlagName, "", "Path to the file that will receive the POD of the infra container's conmon")
_ = createCommand.RegisterFlagCompletionFunc(infraConmonPidfileFlagName, completion.AutocompleteDefault)
infraImageFlagName := "infra-image"
flags.String(infraImageFlagName, containerConfig.Engine.InfraImage, "The image of the infra container to associate with the pod")
_ = createCommand.RegisterFlagCompletionFunc(infraImageFlagName, common.AutocompleteImages)
infraCommandFlagName := "infra-command"
flags.String(infraCommandFlagName, containerConfig.Engine.InfraCommand, "The command to run on the infra container when the pod is started")
_ = createCommand.RegisterFlagCompletionFunc(infraCommandFlagName, completion.AutocompleteNone)
infraNameFlagName := "infra-name"
flags.StringVarP(&createOptions.InfraName, infraNameFlagName, "", "", "The name used as infra container name")
_ = createCommand.RegisterFlagCompletionFunc(infraNameFlagName, completion.AutocompleteNone)
labelFileFlagName := "label-file"
flags.StringSliceVar(&labelFile, labelFileFlagName, []string{}, "Read in a line delimited file of labels")
_ = createCommand.RegisterFlagCompletionFunc(labelFileFlagName, completion.AutocompleteDefault)
labelFlagName := "label"
flags.StringSliceVarP(&labels, labelFlagName, "l", []string{}, "Set metadata on pod (default [])")
_ = createCommand.RegisterFlagCompletionFunc(labelFlagName, completion.AutocompleteNone)
nameFlagName := "name" nameFlagName := "name"
flags.StringVarP(&createOptions.Name, nameFlagName, "n", "", "Assign a name to the pod") flags.StringVarP(&createOptions.Name, nameFlagName, "n", "", "Assign a name to the pod")
_ = createCommand.RegisterFlagCompletionFunc(nameFlagName, completion.AutocompleteNone) _ = createCommand.RegisterFlagCompletionFunc(nameFlagName, completion.AutocompleteNone)
hostnameFlagName := "hostname" infraImageFlagName := "infra-image"
flags.StringVarP(&createOptions.Hostname, hostnameFlagName, "", "", "Set a hostname to the pod") flags.String(infraImageFlagName, containerConfig.Engine.InfraImage, "The image of the infra container to associate with the pod")
_ = createCommand.RegisterFlagCompletionFunc(hostnameFlagName, completion.AutocompleteNone) _ = createCommand.RegisterFlagCompletionFunc(infraImageFlagName, common.AutocompleteImages)
pidFlagName := "pid"
flags.StringVar(&createOptions.Pid, pidFlagName, "", "PID namespace to use")
_ = createCommand.RegisterFlagCompletionFunc(pidFlagName, common.AutocompleteNamespace)
podIDFileFlagName := "pod-id-file" podIDFileFlagName := "pod-id-file"
flags.StringVar(&podIDFile, podIDFileFlagName, "", "Write the pod ID to the file") flags.StringVar(&podIDFile, podIDFileFlagName, "", "Write the pod ID to the file")
@ -137,25 +97,30 @@ func aliasNetworkFlag(_ *pflag.FlagSet, name string) pflag.NormalizedName {
func create(cmd *cobra.Command, args []string) error { func create(cmd *cobra.Command, args []string) error {
var ( var (
err error err error
podIDFD *os.File podIDFD *os.File
imageName string
rawImageName string
) )
labelFile = infraOptions.LabelFile
labels = infraOptions.Label
createOptions.Labels, err = parse.GetAllLabels(labelFile, labels) createOptions.Labels, err = parse.GetAllLabels(labelFile, labels)
if err != nil { if err != nil {
return errors.Wrapf(err, "unable to process labels") return errors.Wrapf(err, "unable to process labels")
} }
imageName = config.DefaultInfraImage
img := imageName
if !createOptions.Infra { if !createOptions.Infra {
if cmd.Flag("no-hosts").Changed {
return fmt.Errorf("cannot specify no-hosts without an infra container")
}
flags := cmd.Flags()
createOptions.Net, err = common.NetFlagsToNetOptions(nil, *flags, false)
if err != nil {
return err
}
logrus.Debugf("Not creating an infra container") logrus.Debugf("Not creating an infra container")
if cmd.Flag("infra-conmon-pidfile").Changed {
return errors.New("cannot set infra-conmon-pid without an infra container")
}
if cmd.Flag("infra-command").Changed {
return errors.New("cannot set infra-command without an infra container")
}
if cmd.Flag("infra-image").Changed {
return errors.New("cannot set infra-image without an infra container")
}
createOptions.InfraImage = "" createOptions.InfraImage = ""
if createOptions.InfraName != "" { if createOptions.InfraName != "" {
return errors.New("cannot set infra-name without an infra container") return errors.New("cannot set infra-name without an infra container")
@ -166,28 +131,43 @@ func create(cmd *cobra.Command, args []string) error {
} }
createOptions.Share = nil createOptions.Share = nil
} else { } else {
// reassign certain optios for lbpod api, these need to be populated in spec
createOptions.InfraConmonPidFile = infraOptions.ConmonPIDFile
createOptions.InfraName = infraOptions.Name
createOptions.Hostname = infraOptions.Hostname
createOptions.Cpus = infraOptions.CPUS
createOptions.CpusetCpus = infraOptions.CPUSetCPUs
createOptions.Pid = infraOptions.PID
flags := cmd.Flags()
infraOptions.Net, err = common.NetFlagsToNetOptions(nil, *flags, false)
if err != nil {
return err
}
infraOptions, err = containers.CreateInit(cmd, infraOptions, true)
if err != nil {
return err
}
createOptions.Net = infraOptions.Net
createOptions.Share = strings.Split(share, ",") createOptions.Share = strings.Split(share, ",")
if cmd.Flag("infra-command").Changed { if cmd.Flag("infra-command").Changed {
// Only send content to server side if user changed defaults // Only send content to server side if user changed defaults
createOptions.InfraCommand, err = cmd.Flags().GetString("infra-command") cmdIn, err := cmd.Flags().GetString("infra-command")
infraOptions.Entrypoint = &cmdIn
createOptions.InfraCommand = cmdIn
if err != nil { if err != nil {
return err return err
} }
} }
if cmd.Flag("infra-image").Changed { if cmd.Flag("infra-image").Changed {
// Only send content to server side if user changed defaults // Only send content to server side if user changed defaults
createOptions.InfraImage, err = cmd.Flags().GetString("infra-image") img, err = cmd.Flags().GetString("infra-image")
imageName = img
if err != nil { if err != nil {
return err return err
} }
} }
} }
createOptions.Userns, err = specgen.ParseUserNamespace(userns)
if err != nil {
return err
}
if cmd.Flag("pod-id-file").Changed { if cmd.Flag("pod-id-file").Changed {
podIDFD, err = util.OpenExclusiveFile(podIDFile) podIDFD, err = util.OpenExclusiveFile(podIDFile)
if err != nil && os.IsExist(err) { if err != nil && os.IsExist(err) {
@ -200,13 +180,6 @@ func create(cmd *cobra.Command, args []string) error {
defer errorhandling.SyncQuiet(podIDFD) defer errorhandling.SyncQuiet(podIDFD)
} }
createOptions.Pid = cmd.Flag("pid").Value.String()
createOptions.Net, err = common.NetFlagsToNetOptions(cmd, createOptions.Infra)
if err != nil {
return err
}
if len(createOptions.Net.PublishPorts) > 0 { if len(createOptions.Net.PublishPorts) > 0 {
if !createOptions.Infra { if !createOptions.Infra {
return errors.Errorf("you must have an infra container to publish port bindings to the host") return errors.Errorf("you must have an infra container to publish port bindings to the host")
@ -261,10 +234,44 @@ func create(cmd *cobra.Command, args []string) error {
copy = "" + strconv.Itoa(core) copy = "" + strconv.Itoa(core)
} }
} }
response, err := registry.ContainerEngine().PodCreate(context.Background(), createOptions) podSpec := specgen.NewPodSpecGenerator()
podSpec, err = entities.ToPodSpecGen(*podSpec, &createOptions)
if err != nil { if err != nil {
return err return err
} }
if createOptions.Infra {
rawImageName = img
if !infraOptions.RootFS {
curr := infraOptions.Quiet
infraOptions.Quiet = true
name, err := containers.PullImage(imageName, infraOptions)
if err != nil {
fmt.Println(err)
}
imageName = name
infraOptions.Quiet = curr
}
podSpec.InfraImage = imageName
if infraOptions.Entrypoint != nil {
createOptions.InfraCommand = *infraOptions.Entrypoint
}
infraOptions.CPUS = createOptions.Cpus
infraOptions.CPUSetCPUs = createOptions.CpusetCpus
infraOptions.PID = createOptions.Pid
podSpec.InfraContainerSpec = specgen.NewSpecGenerator(imageName, false)
podSpec.InfraContainerSpec.RawImageName = rawImageName
podSpec.InfraContainerSpec.NetworkOptions = podSpec.NetworkOptions
err = specgenutil.FillOutSpecGen(podSpec.InfraContainerSpec, &infraOptions, []string{})
if err != nil {
return err
}
}
PodSpec := entities.PodSpec{PodSpecGen: *podSpec}
response, err := registry.ContainerEngine().PodCreate(context.Background(), PodSpec)
if err != nil {
return err
}
if len(podIDFile) > 0 { if len(podIDFile) > 0 {
if err = ioutil.WriteFile(podIDFile, []byte(response.Id), 0644); err != nil { if err = ioutil.WriteFile(podIDFile, []byte(response.Id), 0644); err != nil {
return errors.Wrapf(err, "failed to write pod ID to file") return errors.Wrapf(err, "failed to write pod ID to file")

View File

@ -12,6 +12,7 @@ import (
"github.com/containers/podman/v3/cmd/podman/validate" "github.com/containers/podman/v3/cmd/podman/validate"
"github.com/containers/podman/v3/libpod/define" "github.com/containers/podman/v3/libpod/define"
"github.com/containers/podman/v3/pkg/domain/entities" "github.com/containers/podman/v3/pkg/domain/entities"
"github.com/containers/podman/v3/pkg/specgenutil"
"github.com/pkg/errors" "github.com/pkg/errors"
"github.com/spf13/cobra" "github.com/spf13/cobra"
) )
@ -66,7 +67,7 @@ func init() {
} }
func rm(_ *cobra.Command, args []string) error { func rm(_ *cobra.Command, args []string) error {
ids, err := common.ReadPodIDFiles(rmOptions.PodIDFiles) ids, err := specgenutil.ReadPodIDFiles(rmOptions.PodIDFiles)
if err != nil { if err != nil {
return err return err
} }

View File

@ -10,6 +10,7 @@ import (
"github.com/containers/podman/v3/cmd/podman/utils" "github.com/containers/podman/v3/cmd/podman/utils"
"github.com/containers/podman/v3/cmd/podman/validate" "github.com/containers/podman/v3/cmd/podman/validate"
"github.com/containers/podman/v3/pkg/domain/entities" "github.com/containers/podman/v3/pkg/domain/entities"
"github.com/containers/podman/v3/pkg/specgenutil"
"github.com/spf13/cobra" "github.com/spf13/cobra"
) )
@ -64,7 +65,7 @@ func start(cmd *cobra.Command, args []string) error {
errs utils.OutputErrors errs utils.OutputErrors
) )
ids, err := common.ReadPodIDFiles(startOptions.PodIDFiles) ids, err := specgenutil.ReadPodIDFiles(startOptions.PodIDFiles)
if err != nil { if err != nil {
return err return err
} }

View File

@ -10,6 +10,7 @@ import (
"github.com/containers/podman/v3/cmd/podman/utils" "github.com/containers/podman/v3/cmd/podman/utils"
"github.com/containers/podman/v3/cmd/podman/validate" "github.com/containers/podman/v3/cmd/podman/validate"
"github.com/containers/podman/v3/pkg/domain/entities" "github.com/containers/podman/v3/pkg/domain/entities"
"github.com/containers/podman/v3/pkg/specgenutil"
"github.com/spf13/cobra" "github.com/spf13/cobra"
) )
@ -78,7 +79,7 @@ func stop(cmd *cobra.Command, args []string) error {
stopOptions.Timeout = int(stopOptions.TimeoutCLI) stopOptions.Timeout = int(stopOptions.TimeoutCLI)
} }
ids, err := common.ReadPodIDFiles(stopOptions.PodIDFiles) ids, err := specgenutil.ReadPodIDFiles(stopOptions.PodIDFiles)
if err != nil { if err != nil {
return err return err
} }

View File

@ -51,7 +51,26 @@ Set custom DNS options in the /etc/resolv.conf file that will be shared between
Set custom DNS search domains in the /etc/resolv.conf file that will be shared between all containers in the pod. Set custom DNS search domains in the /etc/resolv.conf file that will be shared between all containers in the pod.
#### **--help** #### **--gidmap**=*container_gid:host_gid:amount*
GID map for the user namespace. Using this flag will run the container with user namespace enabled. It conflicts with the `--userns` and `--subgidname` flags.
#### **--uidmap**=*container_uid*:*from_uid*:*amount*
Run the container in a new user namespace using the supplied mapping. This
option conflicts with the **--userns** and **--subuidname** options. This
option provides a way to map host UIDs to container UIDs. It can be passed
several times to map different ranges.
#### **--subgidname**=*name*
Name for GID map from the `/etc/subgid` file. Using this flag will run the container with user namespace enabled. This flag conflicts with `--userns` and `--gidmap`.
#### **--subuidname**=*name*
Name for UID map from the `/etc/subuid` file. Using this flag will run the container with user namespace enabled. This flag conflicts with `--userns` and `--uidmap`.
#### **--help**, **-h**
Print usage statement. Print usage statement.

View File

@ -972,11 +972,12 @@ func (c *Container) checkDependenciesRunning() ([]string, error) {
} }
// Check the status // Check the status
conf := depCtr.Config()
state, err := depCtr.State() state, err := depCtr.State()
if err != nil { if err != nil {
return nil, errors.Wrapf(err, "error retrieving state of dependency %s of container %s", dep, c.ID()) return nil, errors.Wrapf(err, "error retrieving state of dependency %s of container %s", dep, c.ID())
} }
if state != define.ContainerStateRunning { if state != define.ContainerStateRunning && !conf.IsInfra {
notRunning = append(notRunning, dep) notRunning = append(notRunning, dep)
} }
depCtrs[dep] = depCtr depCtrs[dep] = depCtr

View File

@ -10,6 +10,8 @@ import (
"github.com/containers/podman/v3/libpod/define" "github.com/containers/podman/v3/libpod/define"
"github.com/containers/podman/v3/pkg/lookup" "github.com/containers/podman/v3/pkg/lookup"
"github.com/containers/podman/v3/pkg/namespaces"
"github.com/containers/podman/v3/pkg/specgen"
"github.com/containers/podman/v3/pkg/util" "github.com/containers/podman/v3/pkg/util"
"github.com/cri-o/ocicni/pkg/ocicni" "github.com/cri-o/ocicni/pkg/ocicni"
"github.com/opencontainers/runtime-spec/specs-go" "github.com/opencontainers/runtime-spec/specs-go"
@ -72,7 +74,7 @@ func (p *Pod) GenerateForKube() (*v1.Pod, []v1.ServicePort, error) {
return nil, servicePorts, err return nil, servicePorts, err
} }
servicePorts = containerPortsToServicePorts(ports) servicePorts = containerPortsToServicePorts(ports)
hostNetwork = p.config.InfraContainer.HostNetwork hostNetwork = infraContainer.NetworkMode() == string(namespaces.NetworkMode(specgen.Host))
} }
pod, err := p.podWithContainers(allContainers, ports, hostNetwork) pod, err := p.podWithContainers(allContainers, ports, hostNetwork)
if err != nil { if err != nil {

View File

@ -632,7 +632,6 @@ func (r *Runtime) configureNetNS(ctr *Container, ctrNS ns.NetNS) ([]*cnitypes.Re
} }
podName := getCNIPodName(ctr) podName := getCNIPodName(ctr)
networks, _, err := ctr.networks() networks, _, err := ctr.networks()
if err != nil { if err != nil {
return nil, err return nil, err

View File

@ -14,6 +14,7 @@ import (
"github.com/containers/image/v5/types" "github.com/containers/image/v5/types"
"github.com/containers/podman/v3/libpod/define" "github.com/containers/podman/v3/libpod/define"
"github.com/containers/podman/v3/libpod/events" "github.com/containers/podman/v3/libpod/events"
netTypes "github.com/containers/podman/v3/libpod/network/types"
"github.com/containers/podman/v3/pkg/namespaces" "github.com/containers/podman/v3/pkg/namespaces"
"github.com/containers/podman/v3/pkg/rootless" "github.com/containers/podman/v3/pkg/rootless"
"github.com/containers/podman/v3/pkg/specgen" "github.com/containers/podman/v3/pkg/specgen"
@ -21,7 +22,6 @@ import (
"github.com/containers/storage" "github.com/containers/storage"
"github.com/containers/storage/pkg/idtools" "github.com/containers/storage/pkg/idtools"
"github.com/cri-o/ocicni/pkg/ocicni" "github.com/cri-o/ocicni/pkg/ocicni"
"github.com/opencontainers/runtime-spec/specs-go"
"github.com/opencontainers/runtime-tools/generate" "github.com/opencontainers/runtime-tools/generate"
"github.com/pkg/errors" "github.com/pkg/errors"
"github.com/sirupsen/logrus" "github.com/sirupsen/logrus"
@ -713,7 +713,6 @@ func (r *Runtime) WithPod(pod *Pod) CtrCreateOption {
if pod == nil { if pod == nil {
return define.ErrInvalidArg return define.ErrInvalidArg
} }
ctr.config.Pod = pod.ID() ctr.config.Pod = pod.ID()
return nil return nil
@ -1430,20 +1429,6 @@ func WithRestartRetries(tries uint) CtrCreateOption {
} }
} }
// withIsInfra sets the container to be an infra container. This means the container will be sometimes hidden
// and expected to be the first container in the pod.
func withIsInfra() CtrCreateOption {
return func(ctr *Container) error {
if ctr.valid {
return define.ErrCtrFinalized
}
ctr.config.IsInfra = true
return nil
}
}
// WithNamedVolumes adds the given named volumes to the container. // WithNamedVolumes adds the given named volumes to the container.
func WithNamedVolumes(volumes []*ContainerNamedVolume) CtrCreateOption { func WithNamedVolumes(volumes []*ContainerNamedVolume) CtrCreateOption {
return func(ctr *Container) error { return func(ctr *Container) error {
@ -1541,6 +1526,20 @@ func WithCreateCommand(cmd []string) CtrCreateOption {
} }
} }
// withIsInfra allows us to dfferentiate between infra containers and regular containers
// within the container config
func withIsInfra() CtrCreateOption {
return func(ctr *Container) error {
if ctr.valid {
return define.ErrCtrFinalized
}
ctr.config.IsInfra = true
return nil
}
}
// WithCreateWorkingDir tells Podman to create the container's working directory // WithCreateWorkingDir tells Podman to create the container's working directory
// if it does not exist. // if it does not exist.
func WithCreateWorkingDir() CtrCreateOption { func WithCreateWorkingDir() CtrCreateOption {
@ -1812,45 +1811,14 @@ func WithInitCtrType(containerType string) CtrCreateOption {
// Pod Creation Options // Pod Creation Options
// WithInfraImage sets the infra image for libpod. // WithPodCreateCommand adds the full command plus arguments of the current
// An infra image is used for inter-container kernel // process to the pod config.
// namespace sharing within a pod. Typically, an infra func WithPodCreateCommand(createCmd []string) PodCreateOption {
// container is lightweight and is there to reap
// zombie processes within its pid namespace.
func WithInfraImage(img string) PodCreateOption {
return func(pod *Pod) error { return func(pod *Pod) error {
if pod.valid { if pod.valid {
return define.ErrPodFinalized return define.ErrPodFinalized
} }
pod.config.CreateCommand = createCmd
pod.config.InfraContainer.InfraImage = img
return nil
}
}
// WithInfraCommand sets the command to
// run on pause container start up.
func WithInfraCommand(cmd []string) PodCreateOption {
return func(pod *Pod) error {
if pod.valid {
return define.ErrPodFinalized
}
pod.config.InfraContainer.InfraCommand = cmd
return nil
}
}
// WithInfraName sets the infra container name for a single pod.
func WithInfraName(name string) PodCreateOption {
return func(pod *Pod) error {
if pod.valid {
return define.ErrPodFinalized
}
pod.config.InfraContainer.InfraName = name
return nil return nil
} }
} }
@ -1891,26 +1859,14 @@ func WithPodHostname(hostname string) PodCreateOption {
} }
} }
// WithPodCreateCommand adds the full command plus arguments of the current
// process to the pod config.
func WithPodCreateCommand(createCmd []string) PodCreateOption {
return func(pod *Pod) error {
if pod.valid {
return define.ErrPodFinalized
}
pod.config.CreateCommand = createCmd
return nil
}
}
// WithInfraConmonPidFile sets the path to a custom conmon PID file for the // WithInfraConmonPidFile sets the path to a custom conmon PID file for the
// infra container. // infra container.
func WithInfraConmonPidFile(path string) PodCreateOption { func WithInfraConmonPidFile(path string, infraSpec *specgen.SpecGenerator) PodCreateOption {
return func(pod *Pod) error { return func(pod *Pod) error {
if pod.valid { if pod.valid {
return define.ErrPodFinalized return define.ErrPodFinalized
} }
pod.config.InfraContainer.ConmonPidFile = path infraSpec.ConmonPidFile = path
return nil return nil
} }
} }
@ -2099,320 +2055,25 @@ func WithInfraContainer() PodCreateOption {
if pod.valid { if pod.valid {
return define.ErrPodFinalized return define.ErrPodFinalized
} }
pod.config.HasInfra = true
pod.config.InfraContainer.HasInfraContainer = true
return nil return nil
} }
} }
// WithInfraContainerPorts tells the pod to add port bindings to the pause container // WithInfraContainerPorts tells the pod to add port bindings to the pause container
func WithInfraContainerPorts(bindings []ocicni.PortMapping) PodCreateOption { func WithInfraContainerPorts(bindings []ocicni.PortMapping, infraSpec *specgen.SpecGenerator) []netTypes.PortMapping {
return func(pod *Pod) error { bindingSpec := []netTypes.PortMapping{}
if pod.valid { for _, bind := range bindings {
return define.ErrPodFinalized currBind := netTypes.PortMapping{}
} currBind.ContainerPort = uint16(bind.ContainerPort)
if !pod.config.InfraContainer.HasInfraContainer { currBind.HostIP = bind.HostIP
return errors.Wrapf(define.ErrInvalidArg, "cannot set pod ports as no infra container is being created") currBind.HostPort = uint16(bind.HostPort)
} currBind.Protocol = bind.Protocol
pod.config.InfraContainer.PortBindings = bindings bindingSpec = append(bindingSpec, currBind)
return nil
}
}
// WithPodStaticIP sets a static IP for the pod.
func WithPodStaticIP(ip net.IP) PodCreateOption {
return func(pod *Pod) error {
if pod.valid {
return define.ErrPodFinalized
}
if !pod.config.InfraContainer.HasInfraContainer {
return errors.Wrapf(define.ErrInvalidArg, "cannot set pod static IP as no infra container is being created")
}
if pod.config.InfraContainer.HostNetwork {
return errors.Wrapf(define.ErrInvalidArg, "cannot set static IP if host network is specified")
}
if len(pod.config.InfraContainer.Networks) > 1 {
return errors.Wrapf(define.ErrInvalidArg, "cannot set a static IP if joining more than 1 CNI network")
}
pod.config.InfraContainer.StaticIP = ip
return nil
}
}
// WithPodStaticMAC sets a static MAC address for the pod.
func WithPodStaticMAC(mac net.HardwareAddr) PodCreateOption {
return func(pod *Pod) error {
if pod.valid {
return define.ErrPodFinalized
}
if !pod.config.InfraContainer.HasInfraContainer {
return errors.Wrapf(define.ErrInvalidArg, "cannot set pod static MAC as no infra container is being created")
}
if pod.config.InfraContainer.HostNetwork {
return errors.Wrapf(define.ErrInvalidArg, "cannot set static MAC if host network is specified")
}
if len(pod.config.InfraContainer.Networks) > 1 {
return errors.Wrapf(define.ErrInvalidArg, "cannot set a static MAC if joining more than 1 CNI network")
}
pod.config.InfraContainer.StaticMAC = mac
return nil
}
}
// WithPodUseImageResolvConf sets a pod to use an image's resolv.conf and not
// create its own.
func WithPodUseImageResolvConf() PodCreateOption {
return func(pod *Pod) error {
if pod.valid {
return define.ErrPodFinalized
}
if !pod.config.InfraContainer.HasInfraContainer {
return errors.Wrapf(define.ErrInvalidArg, "cannot configure pod DNS as no infra container is being created")
}
if len(pod.config.InfraContainer.DNSServer) != 0 ||
len(pod.config.InfraContainer.DNSSearch) != 0 ||
len(pod.config.InfraContainer.DNSOption) != 0 {
return errors.Wrapf(define.ErrInvalidArg, "requested use of image resolv.conf conflicts with already-configured DNS settings")
}
pod.config.InfraContainer.UseImageResolvConf = true
return nil
}
}
// WithPodDNS sets the DNS Servers for a pod.
func WithPodDNS(dnsServer []string) PodCreateOption {
return func(pod *Pod) error {
if pod.valid {
return define.ErrPodFinalized
}
if !pod.config.InfraContainer.HasInfraContainer {
return errors.Wrapf(define.ErrInvalidArg, "cannot configure pod DNS as no infra container is being created")
}
if pod.config.InfraContainer.UseImageResolvConf {
return errors.Wrapf(define.ErrInvalidArg, "cannot add DNS servers if pod will not create /etc/resolv.conf")
}
pod.config.InfraContainer.DNSServer = dnsServer
return nil
}
}
// WithPodDNSSearch sets the DNS Search domains for a pod.
func WithPodDNSSearch(dnsSearch []string) PodCreateOption {
return func(pod *Pod) error {
if pod.valid {
return define.ErrPodFinalized
}
if !pod.config.InfraContainer.HasInfraContainer {
return errors.Wrapf(define.ErrInvalidArg, "cannot configure pod DNS as no infra container is being created")
}
if pod.config.InfraContainer.UseImageResolvConf {
return errors.Wrapf(define.ErrInvalidArg, "cannot add DNS search domains if pod will not create /etc/resolv.conf")
}
pod.config.InfraContainer.DNSSearch = dnsSearch
return nil
}
}
// WithPodDNSOption sets DNS Options for a pod.
func WithPodDNSOption(dnsOption []string) PodCreateOption {
return func(pod *Pod) error {
if pod.valid {
return define.ErrPodFinalized
}
if !pod.config.InfraContainer.HasInfraContainer {
return errors.Wrapf(define.ErrInvalidArg, "cannot configure pod DNS as no infra container is being created")
}
if pod.config.InfraContainer.UseImageResolvConf {
return errors.Wrapf(define.ErrInvalidArg, "cannot add DNS options if pod will not create /etc/resolv.conf")
}
pod.config.InfraContainer.DNSOption = dnsOption
return nil
}
}
// WithPodUseImageHosts tells the pod not to create /etc/hosts and instead to
// use the one provided by the image.
func WithPodUseImageHosts() PodCreateOption {
return func(pod *Pod) error {
if pod.valid {
return define.ErrPodFinalized
}
if !pod.config.InfraContainer.HasInfraContainer {
return errors.Wrapf(define.ErrInvalidArg, "cannot configure pod hosts as no infra container is being created")
}
if len(pod.config.InfraContainer.HostAdd) != 0 {
return errors.Wrapf(define.ErrInvalidArg, "not creating /etc/hosts conflicts with adding to the hosts file")
}
pod.config.InfraContainer.UseImageHosts = true
return nil
}
}
// WithPodHosts adds additional entries to the pod's /etc/hosts
func WithPodHosts(hosts []string) PodCreateOption {
return func(pod *Pod) error {
if pod.valid {
return define.ErrPodFinalized
}
if !pod.config.InfraContainer.HasInfraContainer {
return errors.Wrapf(define.ErrInvalidArg, "cannot configure pod hosts as no infra container is being created")
}
if pod.config.InfraContainer.UseImageHosts {
return errors.Wrapf(define.ErrInvalidArg, "cannot add to /etc/hosts if container is using image hosts")
}
pod.config.InfraContainer.HostAdd = hosts
return nil
}
}
// WithPodNetworks sets additional CNI networks for the pod to join.
func WithPodNetworks(networks []string) PodCreateOption {
return func(pod *Pod) error {
if pod.valid {
return define.ErrPodFinalized
}
if !pod.config.InfraContainer.HasInfraContainer {
return errors.Wrapf(define.ErrInvalidArg, "cannot configure pod CNI networks as no infra container is being created")
}
if (pod.config.InfraContainer.StaticIP != nil || pod.config.InfraContainer.StaticMAC != nil) &&
len(networks) > 1 {
return errors.Wrapf(define.ErrInvalidArg, "cannot join more than one CNI network if setting a static IP or MAC address")
}
if pod.config.InfraContainer.HostNetwork {
return errors.Wrapf(define.ErrInvalidArg, "cannot join pod to CNI networks if host network is specified")
}
pod.config.InfraContainer.Networks = networks
return nil
}
}
// WithPodNoNetwork tells the pod to disable external networking.
func WithPodNoNetwork() PodCreateOption {
return func(pod *Pod) error {
if pod.valid {
return define.ErrPodFinalized
}
if !pod.config.InfraContainer.HasInfraContainer {
return errors.Wrapf(define.ErrInvalidArg, "cannot disable pod networking as no infra container is being created")
}
if len(pod.config.InfraContainer.PortBindings) > 0 ||
pod.config.InfraContainer.StaticIP != nil ||
pod.config.InfraContainer.StaticMAC != nil ||
len(pod.config.InfraContainer.Networks) > 0 ||
pod.config.InfraContainer.HostNetwork {
return errors.Wrapf(define.ErrInvalidArg, "cannot disable pod network if network-related configuration is specified")
}
pod.config.InfraContainer.NoNetwork = true
return nil
}
}
// WithPodHostNetwork tells the pod to use the host's network namespace.
func WithPodHostNetwork() PodCreateOption {
return func(pod *Pod) error {
if pod.valid {
return define.ErrPodFinalized
}
if !pod.config.InfraContainer.HasInfraContainer {
return errors.Wrapf(define.ErrInvalidArg, "cannot configure pod host networking as no infra container is being created")
}
if len(pod.config.InfraContainer.PortBindings) > 0 ||
pod.config.InfraContainer.StaticIP != nil ||
pod.config.InfraContainer.StaticMAC != nil ||
len(pod.config.InfraContainer.Networks) > 0 ||
pod.config.InfraContainer.NoNetwork {
return errors.Wrapf(define.ErrInvalidArg, "cannot set host network if network-related configuration is specified")
}
pod.config.InfraContainer.HostNetwork = true
return nil
}
}
// WithPodInfraExitCommand sets an exit command for the pod's infra container.
// Semantics are identical to WithExitCommand() above - the ID of the container
// will be appended to the end of the provided command (note that this will
// specifically be the ID of the infra container *and not the pod's id*.
func WithPodInfraExitCommand(exitCmd []string) PodCreateOption {
return func(pod *Pod) error {
if pod.valid {
return define.ErrPodFinalized
}
if !pod.config.InfraContainer.HasInfraContainer {
return errors.Wrapf(define.ErrInvalidArg, "cannot configure pod infra container exit command as no infra container is being created")
}
pod.config.InfraContainer.ExitCommand = exitCmd
return nil
}
}
// WithPodSlirp4netns tells the pod to use slirp4netns.
func WithPodSlirp4netns(networkOptions map[string][]string) PodCreateOption {
return func(pod *Pod) error {
if pod.valid {
return define.ErrPodFinalized
}
if !pod.config.InfraContainer.HasInfraContainer {
return errors.Wrapf(define.ErrInvalidArg, "cannot configure pod networking as no infra container is being created")
}
if pod.config.InfraContainer.HostNetwork {
return errors.Wrapf(define.ErrInvalidArg, "cannot set both HostNetwork and Slirp4netns")
}
pod.config.InfraContainer.Slirp4netns = true
pod.config.InfraContainer.NetworkOptions = networkOptions
return nil
} }
infraSpec.PortMappings = bindingSpec
return infraSpec.PortMappings
} }
// WithVolatile sets the volatile flag for the container storage. // WithVolatile sets the volatile flag for the container storage.
@ -2428,78 +2089,3 @@ func WithVolatile() CtrCreateOption {
return nil return nil
} }
} }
// WithPodUserns sets the userns for the infra container in a pod.
func WithPodUserns(userns specgen.Namespace) PodCreateOption {
return func(pod *Pod) error {
if pod.valid {
return define.ErrPodFinalized
}
if !pod.config.InfraContainer.HasInfraContainer {
return errors.Wrapf(define.ErrInvalidArg, "cannot configure pod userns as no infra container is being created")
}
pod.config.InfraContainer.Userns = userns
return nil
}
}
// WithPodCPUPAQ takes the given cpu period and quota and inserts them in the proper place.
func WithPodCPUPAQ(period uint64, quota int64) PodCreateOption {
return func(pod *Pod) error {
if pod.valid {
return define.ErrPodFinalized
}
if pod.CPUPeriod() != 0 && pod.CPUQuota() != 0 {
pod.config.InfraContainer.ResourceLimits.CPU = &specs.LinuxCPU{
Period: &period,
Quota: &quota,
}
} else {
pod.config.InfraContainer.ResourceLimits = &specs.LinuxResources{}
pod.config.InfraContainer.ResourceLimits.CPU = &specs.LinuxCPU{
Period: &period,
Quota: &quota,
}
}
return nil
}
}
// WithPodCPUSetCPUS computes and sets the Cpus linux resource string which determines the amount of cores, from those available, we are allowed to execute on
func WithPodCPUSetCPUs(inp string) PodCreateOption {
return func(pod *Pod) error {
if pod.valid {
return define.ErrPodFinalized
}
if pod.ResourceLim().CPU.Period != nil {
pod.config.InfraContainer.ResourceLimits.CPU.Cpus = inp
} else {
pod.config.InfraContainer.ResourceLimits = &specs.LinuxResources{}
pod.config.InfraContainer.ResourceLimits.CPU = &specs.LinuxCPU{}
pod.config.InfraContainer.ResourceLimits.CPU.Cpus = inp
}
return nil
}
}
func WithPodPidNS(inp specgen.Namespace) PodCreateOption {
return func(p *Pod) error {
if p.valid {
return define.ErrPodFinalized
}
if p.config.UsePodPID {
switch inp.NSMode {
case "container":
return errors.Wrap(define.ErrInvalidArg, "Cannot take container in a different NS as an argument")
case "host":
p.config.UsePodPID = false
}
p.config.InfraContainer.PidNS = inp
}
return nil
}
}

View File

@ -2,14 +2,12 @@ package libpod
import ( import (
"context" "context"
"net" "fmt"
"sort" "sort"
"time" "time"
"github.com/containers/podman/v3/libpod/define" "github.com/containers/podman/v3/libpod/define"
"github.com/containers/podman/v3/libpod/lock" "github.com/containers/podman/v3/libpod/lock"
"github.com/containers/podman/v3/pkg/specgen"
"github.com/cri-o/ocicni/pkg/ocicni"
"github.com/opencontainers/runtime-spec/specs-go" "github.com/opencontainers/runtime-spec/specs-go"
"github.com/pkg/errors" "github.com/pkg/errors"
) )
@ -63,7 +61,7 @@ type PodConfig struct {
UsePodUTS bool `json:"sharesUts,omitempty"` UsePodUTS bool `json:"sharesUts,omitempty"`
UsePodCgroupNS bool `json:"sharesCgroupNS,omitempty"` UsePodCgroupNS bool `json:"sharesCgroupNS,omitempty"`
InfraContainer *InfraContainerConfig `json:"infraConfig"` HasInfra bool `json:"hasInfra,omitempty"`
// Time pod was created // Time pod was created
CreatedTime time.Time `json:"created"` CreatedTime time.Time `json:"created"`
@ -85,41 +83,6 @@ type podState struct {
InfraContainerID string InfraContainerID string
} }
// InfraContainerConfig is the configuration for the pod's infra container.
// Generally speaking, these are equivalent to container configuration options
// you will find in container_config.go (and even named identically), save for
// HasInfraContainer (which determines if an infra container is even created -
// if it is false, no other options in this struct will be used) and HostNetwork
// (this involves the created OCI spec, and as such is not represented directly
// in container_config.go).
// Generally speaking, aside from those two exceptions, these options will set
// the equivalent field in the container's configuration.
type InfraContainerConfig struct {
ConmonPidFile string `json:"conmonPidFile"`
HasInfraContainer bool `json:"makeInfraContainer"`
NoNetwork bool `json:"noNetwork,omitempty"`
HostNetwork bool `json:"infraHostNetwork,omitempty"`
PidNS specgen.Namespace `json:"infraPid,omitempty"`
PortBindings []ocicni.PortMapping `json:"infraPortBindings"`
StaticIP net.IP `json:"staticIP,omitempty"`
StaticMAC net.HardwareAddr `json:"staticMAC,omitempty"`
UseImageResolvConf bool `json:"useImageResolvConf,omitempty"`
DNSServer []string `json:"dnsServer,omitempty"`
DNSSearch []string `json:"dnsSearch,omitempty"`
DNSOption []string `json:"dnsOption,omitempty"`
UseImageHosts bool `json:"useImageHosts,omitempty"`
HostAdd []string `json:"hostsAdd,omitempty"`
Networks []string `json:"networks,omitempty"`
ExitCommand []string `json:"exitCommand,omitempty"`
InfraImage string `json:"infraImage,omitempty"`
InfraCommand []string `json:"infraCommand,omitempty"`
InfraName string `json:"infraName,omitempty"`
Slirp4netns bool `json:"slirp4netns,omitempty"`
NetworkOptions map[string][]string `json:"network_options,omitempty"`
ResourceLimits *specs.LinuxResources `json:"resource_limits,omitempty"`
Userns specgen.Namespace `json:"userns,omitempty"`
}
// ID retrieves the pod's ID // ID retrieves the pod's ID
func (p *Pod) ID() string { func (p *Pod) ID() string {
return p.config.ID return p.config.ID
@ -139,45 +102,104 @@ func (p *Pod) Namespace() string {
// ResourceLim returns the cpuset resource limits for the pod // ResourceLim returns the cpuset resource limits for the pod
func (p *Pod) ResourceLim() *specs.LinuxResources { func (p *Pod) ResourceLim() *specs.LinuxResources {
resCopy := &specs.LinuxResources{} resCopy := &specs.LinuxResources{}
if err := JSONDeepCopy(p.config.InfraContainer.ResourceLimits, resCopy); err != nil {
return nil
}
if resCopy != nil && resCopy.CPU != nil {
return resCopy
}
empty := &specs.LinuxResources{ empty := &specs.LinuxResources{
CPU: &specs.LinuxCPU{}, CPU: &specs.LinuxCPU{},
} }
infra, err := p.runtime.GetContainer(p.state.InfraContainerID)
if err != nil {
return empty
}
conf := infra.config.Spec
if err != nil {
return empty
}
if conf.Linux == nil || conf.Linux.Resources == nil {
return empty
}
if err = JSONDeepCopy(conf.Linux.Resources, resCopy); err != nil {
return nil
}
if resCopy.CPU != nil {
return resCopy
}
return empty return empty
} }
// CPUPeriod returns the pod CPU period // CPUPeriod returns the pod CPU period
func (p *Pod) CPUPeriod() uint64 { func (p *Pod) CPUPeriod() uint64 {
resCopy := &specs.LinuxResources{} if p.state.InfraContainerID == "" {
if err := JSONDeepCopy(p.config.InfraContainer.ResourceLimits, resCopy); err != nil {
return 0 return 0
} }
if resCopy != nil && resCopy.CPU != nil && resCopy.CPU.Period != nil { infra, err := p.runtime.GetContainer(p.state.InfraContainerID)
return *resCopy.CPU.Period if err != nil {
return 0
}
conf := infra.config.Spec
if conf != nil && conf.Linux != nil && conf.Linux.Resources != nil && conf.Linux.Resources.CPU != nil && conf.Linux.Resources.CPU.Period != nil {
return *conf.Linux.Resources.CPU.Period
} }
return 0 return 0
} }
// CPUQuota returns the pod CPU quota // CPUQuota returns the pod CPU quota
func (p *Pod) CPUQuota() int64 { func (p *Pod) CPUQuota() int64 {
resCopy := &specs.LinuxResources{} if p.state.InfraContainerID == "" {
if err := JSONDeepCopy(p.config.InfraContainer.ResourceLimits, resCopy); err != nil {
return 0 return 0
} }
if resCopy != nil && resCopy.CPU != nil && resCopy.CPU.Quota != nil { infra, err := p.runtime.GetContainer(p.state.InfraContainerID)
return *resCopy.CPU.Quota if err != nil {
return 0
}
conf := infra.config.Spec
if conf != nil && conf.Linux != nil && conf.Linux.Resources != nil && conf.Linux.Resources.CPU != nil && conf.Linux.Resources.CPU.Quota != nil {
return *conf.Linux.Resources.CPU.Quota
} }
return 0 return 0
} }
// PidMode returns the PID mode given by the user ex: pod, private... // PidMode returns the PID mode given by the user ex: pod, private...
func (p *Pod) PidMode() string { func (p *Pod) PidMode() string {
return string(p.config.InfraContainer.PidNS.NSMode) infra, err := p.runtime.GetContainer(p.state.InfraContainerID)
if err != nil {
return ""
}
conf := infra.Config()
ctrSpec := conf.Spec
if ctrSpec != nil && ctrSpec.Linux != nil {
for _, ns := range ctrSpec.Linux.Namespaces {
if ns.Type == specs.PIDNamespace {
if ns.Path != "" {
return fmt.Sprintf("ns:%s", ns.Path)
}
return "private"
}
}
return "host"
}
return ""
}
// PidMode returns the PID mode given by the user ex: pod, private...
func (p *Pod) UserNSMode() string {
infra, err := p.infraContainer()
if err != nil {
return ""
}
conf := infra.Config()
ctrSpec := conf.Spec
if ctrSpec != nil && ctrSpec.Linux != nil {
for _, ns := range ctrSpec.Linux.Namespaces {
if ns.Type == specs.UserNamespace {
if ns.Path != "" {
return fmt.Sprintf("ns:%s", ns.Path)
}
return "private"
}
}
return "host"
}
return ""
} }
// Labels returns the pod's labels // Labels returns the pod's labels
@ -263,20 +285,24 @@ func (p *Pod) CgroupPath() (string, error) {
if p.state.CgroupPath != "" { if p.state.CgroupPath != "" {
return p.state.CgroupPath, nil return p.state.CgroupPath, nil
} }
if !p.HasInfraContainer() { if p.state.InfraContainerID == "" {
return "", errors.Wrap(define.ErrNoSuchCtr, "pod has no infra container") return "", errors.Wrap(define.ErrNoSuchCtr, "pod has no infra container")
} }
id := p.state.InfraContainerID id, err := p.infraContainerID()
if err != nil {
return "", err
}
if id != "" { if id != "" {
ctr, err := p.runtime.state.Container(id) ctr, err := p.infraContainer()
if err != nil { if err != nil {
return "", errors.Wrapf(err, "could not get infra") return "", errors.Wrapf(err, "could not get infra")
} }
if ctr != nil { if ctr != nil {
ctr.Start(context.Background(), false) ctr.Start(context.Background(), true)
cgroupPath, err := ctr.CGroupPath() cgroupPath, err := ctr.CGroupPath()
fmt.Println(cgroupPath)
if err != nil { if err != nil {
return "", errors.Wrapf(err, "could not get container cgroup") return "", errors.Wrapf(err, "could not get container cgroup")
} }
@ -325,7 +351,7 @@ func (p *Pod) allContainers() ([]*Container, error) {
// HasInfraContainer returns whether the pod will create an infra container // HasInfraContainer returns whether the pod will create an infra container
func (p *Pod) HasInfraContainer() bool { func (p *Pod) HasInfraContainer() bool {
return p.config.InfraContainer.HasInfraContainer return p.config.HasInfra
} }
// SharesNamespaces checks if the pod has any kernel namespaces set as shared. An infra container will not be // SharesNamespaces checks if the pod has any kernel namespaces set as shared. An infra container will not be
@ -350,19 +376,26 @@ func (p *Pod) InfraContainerID() (string, error) {
return p.infraContainerID() return p.infraContainerID()
} }
// InfraContainer returns the infra container. // infraContainer is the unlocked versio of InfraContainer which returns the infra container
func (p *Pod) InfraContainer() (*Container, error) { func (p *Pod) infraContainer() (*Container, error) {
if !p.HasInfraContainer() { id, err := p.infraContainerID()
return nil, errors.Wrap(define.ErrNoSuchCtr, "pod has no infra container")
}
id, err := p.InfraContainerID()
if err != nil { if err != nil {
return nil, err return nil, err
} }
if id == "" {
return nil, errors.Wrap(define.ErrNoSuchCtr, "pod has no infra container")
}
return p.runtime.state.Container(id) return p.runtime.state.Container(id)
} }
// InfraContainer returns the infra container.
func (p *Pod) InfraContainer() (*Container, error) {
p.lock.Lock()
defer p.lock.Unlock()
return p.infraContainer()
}
// TODO add pod batching // TODO add pod batching
// Lock pod to avoid lock contention // Lock pod to avoid lock contention
// Store and lock all containers (no RemoveContainer in batch guarantees cache will not become stale) // Store and lock all containers (no RemoveContainer in batch guarantees cache will not become stale)
@ -412,13 +445,7 @@ func (p *Pod) ProcessLabel() (string, error) {
if !p.HasInfraContainer() { if !p.HasInfraContainer() {
return "", nil return "", nil
} }
ctr, err := p.infraContainer()
id, err := p.InfraContainerID()
if err != nil {
return "", err
}
ctr, err := p.runtime.state.Container(id)
if err != nil { if err != nil {
return "", err return "", err
} }

View File

@ -582,41 +582,46 @@ func (p *Pod) Inspect() (*define.InspectPodData, error) {
// Infra config contains detailed information on the pod's infra // Infra config contains detailed information on the pod's infra
// container. // container.
var infraConfig *define.InspectPodInfraConfig var infraConfig *define.InspectPodInfraConfig
if p.config.InfraContainer != nil && p.config.InfraContainer.HasInfraContainer { if p.state.InfraContainerID != "" {
infra, err := p.runtime.GetContainer(p.state.InfraContainerID)
if err != nil {
return nil, err
}
infraConfig = new(define.InspectPodInfraConfig) infraConfig = new(define.InspectPodInfraConfig)
infraConfig.HostNetwork = p.config.InfraContainer.HostNetwork infraConfig.HostNetwork = !infra.Config().ContainerNetworkConfig.UseImageHosts
infraConfig.StaticIP = p.config.InfraContainer.StaticIP infraConfig.StaticIP = infra.Config().ContainerNetworkConfig.StaticIP
infraConfig.StaticMAC = p.config.InfraContainer.StaticMAC.String() infraConfig.NoManageResolvConf = infra.Config().UseImageResolvConf
infraConfig.NoManageResolvConf = p.config.InfraContainer.UseImageResolvConf infraConfig.NoManageHosts = infra.Config().UseImageHosts
infraConfig.NoManageHosts = p.config.InfraContainer.UseImageHosts
infraConfig.CPUPeriod = p.CPUPeriod() infraConfig.CPUPeriod = p.CPUPeriod()
infraConfig.CPUQuota = p.CPUQuota() infraConfig.CPUQuota = p.CPUQuota()
infraConfig.CPUSetCPUs = p.ResourceLim().CPU.Cpus infraConfig.CPUSetCPUs = p.ResourceLim().CPU.Cpus
infraConfig.PidNS = p.PidMode() infraConfig.PidNS = p.PidMode()
infraConfig.UserNS = p.config.InfraContainer.Userns.String() infraConfig.UserNS = p.UserNSMode()
if len(p.config.InfraContainer.DNSServer) > 0 { if len(infra.Config().ContainerNetworkConfig.DNSServer) > 0 {
infraConfig.DNSServer = make([]string, 0, len(p.config.InfraContainer.DNSServer)) infraConfig.DNSServer = make([]string, 0, len(infra.Config().ContainerNetworkConfig.DNSServer))
infraConfig.DNSServer = append(infraConfig.DNSServer, p.config.InfraContainer.DNSServer...) for _, entry := range infra.Config().ContainerNetworkConfig.DNSServer {
infraConfig.DNSServer = append(infraConfig.DNSServer, entry.String())
}
} }
if len(p.config.InfraContainer.DNSSearch) > 0 { if len(infra.Config().ContainerNetworkConfig.DNSSearch) > 0 {
infraConfig.DNSSearch = make([]string, 0, len(p.config.InfraContainer.DNSSearch)) infraConfig.DNSSearch = make([]string, 0, len(infra.Config().ContainerNetworkConfig.DNSSearch))
infraConfig.DNSSearch = append(infraConfig.DNSSearch, p.config.InfraContainer.DNSSearch...) infraConfig.DNSSearch = append(infraConfig.DNSSearch, infra.Config().ContainerNetworkConfig.DNSSearch...)
} }
if len(p.config.InfraContainer.DNSOption) > 0 { if len(infra.Config().ContainerNetworkConfig.DNSOption) > 0 {
infraConfig.DNSOption = make([]string, 0, len(p.config.InfraContainer.DNSOption)) infraConfig.DNSOption = make([]string, 0, len(infra.Config().ContainerNetworkConfig.DNSOption))
infraConfig.DNSOption = append(infraConfig.DNSOption, p.config.InfraContainer.DNSOption...) infraConfig.DNSOption = append(infraConfig.DNSOption, infra.Config().ContainerNetworkConfig.DNSOption...)
} }
if len(p.config.InfraContainer.HostAdd) > 0 { if len(infra.Config().HostAdd) > 0 {
infraConfig.HostAdd = make([]string, 0, len(p.config.InfraContainer.HostAdd)) infraConfig.HostAdd = make([]string, 0, len(infra.Config().HostAdd))
infraConfig.HostAdd = append(infraConfig.HostAdd, p.config.InfraContainer.HostAdd...) infraConfig.HostAdd = append(infraConfig.HostAdd, infra.Config().HostAdd...)
} }
if len(p.config.InfraContainer.Networks) > 0 { if len(infra.Config().ContainerNetworkConfig.Networks) > 0 {
infraConfig.Networks = make([]string, 0, len(p.config.InfraContainer.Networks)) infraConfig.Networks = make([]string, 0, len(infra.Config().ContainerNetworkConfig.Networks))
infraConfig.Networks = append(infraConfig.Networks, p.config.InfraContainer.Networks...) infraConfig.Networks = append(infraConfig.Networks, infra.Config().ContainerNetworkConfig.Networks...)
} }
infraConfig.NetworkOptions = p.config.InfraContainer.NetworkOptions infraConfig.NetworkOptions = infra.Config().ContainerNetworkConfig.NetworkOptions
infraConfig.PortBindings = makeInspectPortBindings(p.config.InfraContainer.PortBindings, nil) infraConfig.PortBindings = makeInspectPortBindings(infra.Config().ContainerNetworkConfig.PortMappings, nil)
} }
inspectData := define.InspectPodData{ inspectData := define.InspectPodData{

View File

@ -20,7 +20,7 @@ func newPod(runtime *Runtime) *Pod {
pod.config.ID = stringid.GenerateNonCryptoID() pod.config.ID = stringid.GenerateNonCryptoID()
pod.config.Labels = make(map[string]string) pod.config.Labels = make(map[string]string)
pod.config.CreatedTime = time.Now() pod.config.CreatedTime = time.Now()
pod.config.InfraContainer = new(InfraContainerConfig) // pod.config.InfraContainer = new(ContainerConfig)
pod.state = new(podState) pod.state = new(podState)
pod.runtime = runtime pod.runtime = runtime

View File

@ -17,6 +17,7 @@ import (
"github.com/containers/podman/v3/pkg/cgroups" "github.com/containers/podman/v3/pkg/cgroups"
"github.com/containers/podman/v3/pkg/domain/entities/reports" "github.com/containers/podman/v3/pkg/domain/entities/reports"
"github.com/containers/podman/v3/pkg/rootless" "github.com/containers/podman/v3/pkg/rootless"
"github.com/containers/podman/v3/pkg/specgen"
"github.com/containers/storage" "github.com/containers/storage"
"github.com/containers/storage/pkg/stringid" "github.com/containers/storage/pkg/stringid"
"github.com/docker/go-units" "github.com/docker/go-units"
@ -38,12 +39,15 @@ type CtrCreateOption func(*Container) error
type ContainerFilter func(*Container) bool type ContainerFilter func(*Container) bool
// NewContainer creates a new container from a given OCI config. // NewContainer creates a new container from a given OCI config.
func (r *Runtime) NewContainer(ctx context.Context, rSpec *spec.Spec, options ...CtrCreateOption) (*Container, error) { func (r *Runtime) NewContainer(ctx context.Context, rSpec *spec.Spec, spec *specgen.SpecGenerator, infra bool, options ...CtrCreateOption) (*Container, error) {
r.lock.Lock() r.lock.Lock()
defer r.lock.Unlock() defer r.lock.Unlock()
if !r.valid { if !r.valid {
return nil, define.ErrRuntimeStopped return nil, define.ErrRuntimeStopped
} }
if infra {
options = append(options, withIsInfra())
}
return r.newContainer(ctx, rSpec, options...) return r.newContainer(ctx, rSpec, options...)
} }
@ -172,6 +176,7 @@ func (r *Runtime) initContainerVariables(rSpec *spec.Spec, config *ContainerConf
} }
ctr.config.ShmSize = size ctr.config.ShmSize = size
ctr.config.StopSignal = 15 ctr.config.StopSignal = 15
ctr.config.StopTimeout = r.config.Engine.StopTimeout ctr.config.StopTimeout = r.config.Engine.StopTimeout
} else { } else {
// This is a restore from an imported checkpoint // This is a restore from an imported checkpoint
@ -211,7 +216,11 @@ func (r *Runtime) initContainerVariables(rSpec *spec.Spec, config *ContainerConf
} }
func (r *Runtime) newContainer(ctx context.Context, rSpec *spec.Spec, options ...CtrCreateOption) (*Container, error) { func (r *Runtime) newContainer(ctx context.Context, rSpec *spec.Spec, options ...CtrCreateOption) (*Container, error) {
ctr, err := r.initContainerVariables(rSpec, nil) var ctr *Container
var err error
ctr, err = r.initContainerVariables(rSpec, nil)
if err != nil { if err != nil {
return nil, errors.Wrapf(err, "error initializing container variables") return nil, errors.Wrapf(err, "error initializing container variables")
} }
@ -230,7 +239,9 @@ func (r *Runtime) setupContainer(ctx context.Context, ctr *Container) (_ *Contai
if err := ctr.validate(); err != nil { if err := ctr.validate(); err != nil {
return nil, err return nil, err
} }
if ctr.config.IsInfra {
ctr.config.StopTimeout = 10
}
// normalize the networks to names // normalize the networks to names
// ocicni only knows about cni names so we have to make // ocicni only knows about cni names so we have to make
// sure we do not use ids internally // sure we do not use ids internally
@ -327,7 +338,7 @@ func (r *Runtime) setupContainer(ctx context.Context, ctr *Container) (_ *Contai
switch r.config.Engine.CgroupManager { switch r.config.Engine.CgroupManager {
case config.CgroupfsCgroupsManager: case config.CgroupfsCgroupsManager:
if ctr.config.CgroupParent == "" { if ctr.config.CgroupParent == "" {
if pod != nil && pod.config.UsePodCgroup { if pod != nil && pod.config.UsePodCgroup && !ctr.IsInfra() {
podCgroup, err := pod.CgroupPath() podCgroup, err := pod.CgroupPath()
if err != nil { if err != nil {
return nil, errors.Wrapf(err, "error retrieving pod %s cgroup", pod.ID()) return nil, errors.Wrapf(err, "error retrieving pod %s cgroup", pod.ID())
@ -348,7 +359,7 @@ func (r *Runtime) setupContainer(ctx context.Context, ctr *Container) (_ *Contai
case config.SystemdCgroupsManager: case config.SystemdCgroupsManager:
if ctr.config.CgroupParent == "" { if ctr.config.CgroupParent == "" {
switch { switch {
case pod != nil && pod.config.UsePodCgroup: case pod != nil && pod.config.UsePodCgroup && !ctr.IsInfra():
podCgroup, err := pod.CgroupPath() podCgroup, err := pod.CgroupPath()
if err != nil { if err != nil {
return nil, errors.Wrapf(err, "error retrieving pod %s cgroup", pod.ID()) return nil, errors.Wrapf(err, "error retrieving pod %s cgroup", pod.ID())
@ -833,7 +844,10 @@ func (r *Runtime) evictContainer(ctx context.Context, idOrName string, removeVol
return id, err return id, err
} }
infraID := pod.state.InfraContainerID infraID, err := pod.infraContainerID()
if err != nil {
return "", err
}
if c.ID() == infraID { if c.ID() == infraID {
return id, errors.Errorf("container %s is the infra container of pod %s and cannot be removed without removing the pod", c.ID(), pod.ID()) return id, errors.Errorf("container %s is the infra container of pod %s and cannot be removed without removing the pod", c.ID(), pod.ID())
} }

View File

@ -1,284 +0,0 @@
// +build linux
package libpod
import (
"context"
"strings"
"github.com/containers/common/pkg/config"
"github.com/containers/podman/v3/libpod/define"
"github.com/containers/podman/v3/pkg/namespaces"
"github.com/containers/podman/v3/pkg/rootless"
"github.com/containers/podman/v3/pkg/specgen"
"github.com/containers/podman/v3/pkg/util"
v1 "github.com/opencontainers/image-spec/specs-go/v1"
spec "github.com/opencontainers/runtime-spec/specs-go"
"github.com/opencontainers/runtime-tools/generate"
"github.com/pkg/errors"
"github.com/sirupsen/logrus"
)
const (
// IDTruncLength is the length of the pod's id that will be used to make the
// infra container name
IDTruncLength = 12
)
func (r *Runtime) makeInfraContainer(ctx context.Context, p *Pod, imgName, rawImageName, imgID string, config *v1.ImageConfig) (*Container, error) {
// Set up generator for infra container defaults
g, err := generate.New("linux")
if err != nil {
return nil, err
}
// Set Pod hostname
g.Config.Hostname = p.config.Hostname
var options []CtrCreateOption
// Command: If user-specified, use that preferentially.
// If not set and the config file is set, fall back to that.
var infraCtrCommand []string
if p.config.InfraContainer.InfraCommand != nil {
logrus.Debugf("User-specified infra container entrypoint %v", p.config.InfraContainer.InfraCommand)
infraCtrCommand = p.config.InfraContainer.InfraCommand
} else if r.config.Engine.InfraCommand != "" {
logrus.Debugf("Config-specified infra container entrypoint %s", r.config.Engine.InfraCommand)
infraCtrCommand = []string{r.config.Engine.InfraCommand}
}
// Only if set by the user or containers.conf, we set entrypoint for the
// infra container.
// This is only used by commit, so it shouldn't matter... But someone
// may eventually want to commit an infra container?
// TODO: Should we actually do this if set by containers.conf?
if infraCtrCommand != nil {
// Need to duplicate the array - we are going to add Cmd later
// so the current array will be changed.
newArr := make([]string, 0, len(infraCtrCommand))
newArr = append(newArr, infraCtrCommand...)
options = append(options, WithEntrypoint(newArr))
}
isRootless := rootless.IsRootless()
// I've seen circumstances where config is being passed as nil.
// Let's err on the side of safety and make sure it's safe to use.
if config != nil {
if infraCtrCommand == nil {
// If we have no entrypoint and command from the image,
// we can't go on - the infra container has no command.
if len(config.Entrypoint) == 0 && len(config.Cmd) == 0 {
return nil, errors.Errorf("infra container has no command")
}
if len(config.Entrypoint) > 0 {
infraCtrCommand = config.Entrypoint
} else {
// Use the Docker default "/bin/sh -c"
// entrypoint, as we're overriding command.
// If an image doesn't want this, it can
// override entrypoint too.
infraCtrCommand = []string{"/bin/sh", "-c"}
}
}
if len(config.Cmd) > 0 {
infraCtrCommand = append(infraCtrCommand, config.Cmd...)
}
if len(config.Env) > 0 {
for _, nameValPair := range config.Env {
nameValSlice := strings.Split(nameValPair, "=")
if len(nameValSlice) < 2 {
return nil, errors.Errorf("Invalid environment variable structure in pause image")
}
g.AddProcessEnv(nameValSlice[0], nameValSlice[1])
}
}
switch {
case p.config.InfraContainer.HostNetwork:
if err := g.RemoveLinuxNamespace(string(spec.NetworkNamespace)); err != nil {
return nil, errors.Wrapf(err, "error removing network namespace from pod %s infra container", p.ID())
}
case p.config.InfraContainer.NoNetwork:
// Do nothing - we have a network namespace by default,
// but should not configure slirp.
default:
// Since user namespace sharing is not implemented, we only need to check if it's rootless
netmode := "bridge"
if p.config.InfraContainer.Slirp4netns {
netmode = "slirp4netns"
if len(p.config.InfraContainer.NetworkOptions) != 0 {
options = append(options, WithNetworkOptions(p.config.InfraContainer.NetworkOptions))
}
}
// FIXME allow pods to have exposed ports
options = append(options, WithNetNS(p.config.InfraContainer.PortBindings, nil, !p.config.InfraContainer.Userns.IsHost(), netmode, p.config.InfraContainer.Networks))
}
// For each option in InfraContainerConfig - if set, pass into
// the infra container we're creating with the appropriate
// With... option.
if p.config.InfraContainer.StaticIP != nil {
options = append(options, WithStaticIP(p.config.InfraContainer.StaticIP))
}
if p.config.InfraContainer.StaticMAC != nil {
options = append(options, WithStaticMAC(p.config.InfraContainer.StaticMAC))
}
if p.config.InfraContainer.UseImageResolvConf {
options = append(options, WithUseImageResolvConf())
}
if len(p.config.InfraContainer.DNSServer) > 0 {
options = append(options, WithDNS(p.config.InfraContainer.DNSServer))
}
if len(p.config.InfraContainer.DNSSearch) > 0 {
options = append(options, WithDNSSearch(p.config.InfraContainer.DNSSearch))
}
if len(p.config.InfraContainer.DNSOption) > 0 {
options = append(options, WithDNSOption(p.config.InfraContainer.DNSOption))
}
if p.config.InfraContainer.UseImageHosts {
options = append(options, WithUseImageHosts())
}
if len(p.config.InfraContainer.HostAdd) > 0 {
options = append(options, WithHosts(p.config.InfraContainer.HostAdd))
}
if len(p.config.InfraContainer.ExitCommand) > 0 {
options = append(options, WithExitCommand(p.config.InfraContainer.ExitCommand))
}
if p.config.UsePodPID && p.config.InfraContainer.PidNS.NSMode != "host" {
g.AddOrReplaceLinuxNamespace(string(spec.LinuxNamespaceType("pid")), p.config.InfraContainer.PidNS.Value)
} else if p.config.InfraContainer.PidNS.NSMode == "host" {
newNS := []spec.LinuxNamespace{}
for _, entry := range g.Config.Linux.Namespaces {
if entry.Type != spec.LinuxNamespaceType("pid") {
newNS = append(newNS, entry)
}
}
g.Config.Linux.Namespaces = newNS
}
}
for _, ctl := range r.config.Containers.DefaultSysctls {
sysctl := strings.SplitN(ctl, "=", 2)
if len(sysctl) < 2 {
return nil, errors.Errorf("invalid default sysctl %s", ctl)
}
// Ignore net sysctls if --net=host
if p.config.InfraContainer.HostNetwork && strings.HasPrefix(sysctl[0], "net.") {
logrus.Infof("Sysctl %s=%s ignored in containers.conf, since Network Namespace set to host", sysctl[0], sysctl[1])
continue
}
g.AddLinuxSysctl(sysctl[0], sysctl[1])
}
g.SetRootReadonly(true)
g.SetProcessArgs(infraCtrCommand)
logrus.Debugf("Using %q as infra container command", infraCtrCommand)
mapopt, err := util.ParseIDMapping(namespaces.UsernsMode(p.config.InfraContainer.Userns.String()), []string{}, []string{}, "", "")
if err != nil {
return nil, err
}
user, err := specgen.SetupUserNS(mapopt, p.config.InfraContainer.Userns, &g)
if err != nil {
return nil, err
}
if user != "" {
options = append(options, WithUser(user))
}
g.RemoveMount("/dev/shm")
if isRootless {
g.RemoveMount("/dev/pts")
devPts := spec.Mount{
Destination: "/dev/pts",
Type: "devpts",
Source: "devpts",
Options: []string{"private", "nosuid", "noexec", "newinstance", "ptmxmode=0666", "mode=0620"},
}
g.AddMount(devPts)
}
// Add default sysctls from containers.conf
defaultSysctls, err := util.ValidateSysctls(r.config.Sysctls())
if err != nil {
return nil, err
}
for sysctlKey, sysctlVal := range defaultSysctls {
// Ignore mqueue sysctls if not sharing IPC
if !p.config.UsePodIPC && strings.HasPrefix(sysctlKey, "fs.mqueue.") {
logrus.Infof("Sysctl %s=%s ignored in containers.conf, since IPC Namespace for pod is unused", sysctlKey, sysctlVal)
continue
}
// Ignore net sysctls if host network or not sharing network
if (p.config.InfraContainer.HostNetwork || !p.config.UsePodNet) && strings.HasPrefix(sysctlKey, "net.") {
logrus.Infof("Sysctl %s=%s ignored in containers.conf, since Network Namespace for pod is unused", sysctlKey, sysctlVal)
continue
}
// Ignore uts sysctls if not sharing UTS
if !p.config.UsePodUTS && (strings.HasPrefix(sysctlKey, "kernel.domainname") || strings.HasPrefix(sysctlKey, "kernel.hostname")) {
logrus.Infof("Sysctl %s=%s ignored in containers.conf, since UTS Namespace for pod is unused", sysctlKey, sysctlVal)
continue
}
g.AddLinuxSysctl(sysctlKey, sysctlVal)
}
containerName := p.config.InfraContainer.InfraName
if containerName == "" {
containerName = p.ID()[:IDTruncLength] + "-infra"
}
logrus.Infof("Infra container name %s", containerName)
options = append(options, r.WithPod(p))
options = append(options, WithRootFSFromImage(imgID, imgName, rawImageName))
options = append(options, WithName(containerName))
options = append(options, withIsInfra())
options = append(options, WithIDMappings(*mapopt))
if len(p.config.InfraContainer.ConmonPidFile) > 0 {
options = append(options, WithConmonPidFile(p.config.InfraContainer.ConmonPidFile))
}
newRes := new(spec.LinuxResources)
newRes.CPU = new(spec.LinuxCPU)
newRes.CPU = p.ResourceLim().CPU
g.Config.Linux.Resources.CPU = newRes.CPU
return r.newContainer(ctx, g.Config, options...)
}
// createInfraContainer wrap creates an infra container for a pod.
// An infra container becomes the basis for kernel namespace sharing between
// containers in the pod.
func (r *Runtime) createInfraContainer(ctx context.Context, p *Pod) (*Container, error) {
if !r.valid {
return nil, define.ErrRuntimeStopped
}
imageName := p.config.InfraContainer.InfraImage
if imageName == "" {
imageName = r.config.Engine.InfraImage
}
pulledImages, err := r.LibimageRuntime().Pull(ctx, imageName, config.PullPolicyMissing, nil)
if err != nil {
return nil, errors.Wrap(err, "error pulling infra-container image")
}
newImage := pulledImages[0]
data, err := newImage.Inspect(ctx, false)
if err != nil {
return nil, err
}
imageName = "none"
if len(newImage.Names()) > 0 {
imageName = newImage.Names()[0]
}
imageID := data.ID
return r.makeInfraContainer(ctx, p, imageName, r.config.Engine.InfraImage, imageID, data.Config)
}

View File

@ -14,13 +14,14 @@ import (
"github.com/containers/podman/v3/libpod/events" "github.com/containers/podman/v3/libpod/events"
"github.com/containers/podman/v3/pkg/cgroups" "github.com/containers/podman/v3/pkg/cgroups"
"github.com/containers/podman/v3/pkg/rootless" "github.com/containers/podman/v3/pkg/rootless"
"github.com/containers/podman/v3/pkg/specgen"
spec "github.com/opencontainers/runtime-spec/specs-go" spec "github.com/opencontainers/runtime-spec/specs-go"
"github.com/pkg/errors" "github.com/pkg/errors"
"github.com/sirupsen/logrus" "github.com/sirupsen/logrus"
) )
// NewPod makes a new, empty pod // NewPod makes a new, empty pod
func (r *Runtime) NewPod(ctx context.Context, options ...PodCreateOption) (_ *Pod, deferredErr error) { func (r *Runtime) NewPod(ctx context.Context, p specgen.PodSpecGenerator, options ...PodCreateOption) (_ *Pod, deferredErr error) {
r.lock.Lock() r.lock.Lock()
defer r.lock.Unlock() defer r.lock.Unlock()
@ -50,8 +51,8 @@ func (r *Runtime) NewPod(ctx context.Context, options ...PodCreateOption) (_ *Po
pod.config.Name = name pod.config.Name = name
} }
if pod.config.Hostname == "" { if p.InfraContainerSpec != nil && p.InfraContainerSpec.Hostname == "" {
pod.config.Hostname = pod.config.Name p.InfraContainerSpec.Hostname = pod.config.Name
} }
// Allocate a lock for the pod // Allocate a lock for the pod
@ -88,6 +89,9 @@ func (r *Runtime) NewPod(ctx context.Context, options ...PodCreateOption) (_ *Po
// launch should do it for us // launch should do it for us
if pod.config.UsePodCgroup { if pod.config.UsePodCgroup {
pod.state.CgroupPath = filepath.Join(pod.config.CgroupParent, pod.ID()) pod.state.CgroupPath = filepath.Join(pod.config.CgroupParent, pod.ID())
if p.InfraContainerSpec != nil {
p.InfraContainerSpec.CgroupParent = pod.state.CgroupPath
}
} }
} }
case config.SystemdCgroupsManager: case config.SystemdCgroupsManager:
@ -108,6 +112,9 @@ func (r *Runtime) NewPod(ctx context.Context, options ...PodCreateOption) (_ *Po
return nil, errors.Wrapf(err, "unable to create pod cgroup for pod %s", pod.ID()) return nil, errors.Wrapf(err, "unable to create pod cgroup for pod %s", pod.ID())
} }
pod.state.CgroupPath = cgroupPath pod.state.CgroupPath = cgroupPath
if p.InfraContainerSpec != nil {
p.InfraContainerSpec.CgroupParent = pod.state.CgroupPath
}
} }
default: default:
return nil, errors.Wrapf(define.ErrInvalidArg, "unsupported CGroup manager: %s - cannot validate cgroup parent", r.config.Engine.CgroupManager) return nil, errors.Wrapf(define.ErrInvalidArg, "unsupported CGroup manager: %s - cannot validate cgroup parent", r.config.Engine.CgroupManager)
@ -127,28 +134,40 @@ func (r *Runtime) NewPod(ctx context.Context, options ...PodCreateOption) (_ *Po
if err := r.state.AddPod(pod); err != nil { if err := r.state.AddPod(pod); err != nil {
return nil, errors.Wrapf(err, "error adding pod to state") return nil, errors.Wrapf(err, "error adding pod to state")
} }
defer func() { return pod, nil
if deferredErr != nil { }
if err := r.removePod(ctx, pod, true, true); err != nil {
logrus.Errorf("Error removing pod after pause container creation failure: %v", err)
}
}
}()
if pod.HasInfraContainer() { // AddInfra adds the created infra container to the pod state
ctr, err := r.createInfraContainer(ctx, pod) func (r *Runtime) AddInfra(ctx context.Context, pod *Pod, infraCtr *Container) (*Pod, error) {
if err != nil { r.lock.Lock()
return nil, errors.Wrapf(err, "error adding Infra Container") defer r.lock.Unlock()
}
pod.state.InfraContainerID = ctr.ID() if !r.valid {
if err := pod.save(); err != nil { return nil, define.ErrRuntimeStopped
return nil, err }
} pod.state.InfraContainerID = infraCtr.ID()
if err := pod.save(); err != nil {
return nil, err
} }
pod.newPodEvent(events.Create) pod.newPodEvent(events.Create)
return pod, nil return pod, nil
} }
// SavePod is a helper function to save the pod state from outside of libpod
func (r *Runtime) SavePod(pod *Pod) error {
r.lock.Lock()
defer r.lock.Unlock()
if !r.valid {
return define.ErrRuntimeStopped
}
if err := pod.save(); err != nil {
return err
}
pod.newPodEvent(events.Create)
return nil
}
func (r *Runtime) removePod(ctx context.Context, p *Pod, removeCtrs, force bool) error { func (r *Runtime) removePod(ctx context.Context, p *Pod, removeCtrs, force bool) error {
if err := p.updatePod(); err != nil { if err := p.updatePod(); err != nil {
return err return err

View File

@ -11,6 +11,7 @@ import (
"github.com/containers/podman/v3/pkg/domain/entities" "github.com/containers/podman/v3/pkg/domain/entities"
"github.com/containers/podman/v3/pkg/domain/infra/abi" "github.com/containers/podman/v3/pkg/domain/infra/abi"
"github.com/containers/podman/v3/pkg/specgen" "github.com/containers/podman/v3/pkg/specgen"
"github.com/containers/podman/v3/pkg/specgenutil"
"github.com/containers/storage" "github.com/containers/storage"
"github.com/gorilla/schema" "github.com/gorilla/schema"
"github.com/pkg/errors" "github.com/pkg/errors"
@ -80,7 +81,7 @@ func CreateContainer(w http.ResponseWriter, r *http.Request) {
} }
sg := specgen.NewSpecGenerator(imgNameOrID, cliOpts.RootFS) sg := specgen.NewSpecGenerator(imgNameOrID, cliOpts.RootFS)
if err := common.FillOutSpecGen(sg, cliOpts, args); err != nil { if err := specgenutil.FillOutSpecGen(sg, cliOpts, args); err != nil {
utils.Error(w, "Something went wrong.", http.StatusInternalServerError, errors.Wrap(err, "fill out specgen")) utils.Error(w, "Something went wrong.", http.StatusInternalServerError, errors.Wrap(err, "fill out specgen"))
return return
} }

View File

@ -28,7 +28,12 @@ func CreateContainer(w http.ResponseWriter, r *http.Request) {
utils.InternalServerError(w, err) utils.InternalServerError(w, err)
return return
} }
ctr, err := generate.MakeContainer(context.Background(), runtime, &sg) rtSpec, spec, opts, err := generate.MakeContainer(context.Background(), runtime, &sg)
if err != nil {
utils.InternalServerError(w, err)
return
}
ctr, err := generate.ExecuteCreate(context.Background(), runtime, rtSpec, spec, false, opts...)
if err != nil { if err != nil {
utils.InternalServerError(w, err) utils.InternalServerError(w, err)
return return

View File

@ -1,11 +1,15 @@
package libpod package libpod
import ( import (
"context"
"encoding/json" "encoding/json"
"fmt" "fmt"
"net/http" "net/http"
"strings" "strings"
"github.com/containers/common/libimage"
"github.com/containers/common/pkg/config"
"github.com/containers/image/v5/transports/alltransports"
"github.com/containers/podman/v3/libpod" "github.com/containers/podman/v3/libpod"
"github.com/containers/podman/v3/libpod/define" "github.com/containers/podman/v3/libpod/define"
"github.com/containers/podman/v3/pkg/api/handlers" "github.com/containers/podman/v3/pkg/api/handlers"
@ -14,6 +18,7 @@ import (
"github.com/containers/podman/v3/pkg/domain/infra/abi" "github.com/containers/podman/v3/pkg/domain/infra/abi"
"github.com/containers/podman/v3/pkg/specgen" "github.com/containers/podman/v3/pkg/specgen"
"github.com/containers/podman/v3/pkg/specgen/generate" "github.com/containers/podman/v3/pkg/specgen/generate"
"github.com/containers/podman/v3/pkg/specgenutil"
"github.com/containers/podman/v3/pkg/util" "github.com/containers/podman/v3/pkg/util"
"github.com/gorilla/schema" "github.com/gorilla/schema"
"github.com/pkg/errors" "github.com/pkg/errors"
@ -25,24 +30,70 @@ func PodCreate(w http.ResponseWriter, r *http.Request) {
runtime = r.Context().Value("runtime").(*libpod.Runtime) runtime = r.Context().Value("runtime").(*libpod.Runtime)
err error err error
) )
var psg specgen.PodSpecGenerator psg := specgen.PodSpecGenerator{InfraContainerSpec: &specgen.SpecGenerator{}}
if err := json.NewDecoder(r.Body).Decode(&psg); err != nil { if err := json.NewDecoder(r.Body).Decode(&psg); err != nil {
utils.Error(w, "failed to decode specgen", http.StatusInternalServerError, errors.Wrap(err, "failed to decode specgen")) utils.Error(w, "Something went wrong.", http.StatusInternalServerError, errors.Wrap(err, "failed to decode specgen"))
return return
} }
// parse userns so we get the valid default value of userns
psg.Userns, err = specgen.ParseUserNamespace(psg.Userns.String())
if err != nil { if err != nil {
utils.Error(w, "failed to parse userns", http.StatusInternalServerError, errors.Wrap(err, "failed to parse userns")) utils.Error(w, "Something went wrong.", http.StatusInternalServerError, errors.Wrap(err, "failed to decode specgen"))
return return
} }
pod, err := generate.MakePod(&psg, runtime) if !psg.NoInfra {
infraOptions := &entities.ContainerCreateOptions{ImageVolume: "bind", IsInfra: true, Net: &entities.NetOptions{}} // options for pulling the image and FillOutSpec
err = specgenutil.FillOutSpecGen(psg.InfraContainerSpec, infraOptions, []string{}) // necessary for default values in many cases (userns, idmappings)
if err != nil {
utils.Error(w, "Something went wrong.", http.StatusInternalServerError, errors.Wrap(err, "error filling out specgen"))
return
}
out, err := json.Marshal(psg) // marshal our spec so the matching options can be unmarshaled into infra
if err != nil {
utils.Error(w, "Something went wrong.", http.StatusInternalServerError, errors.Wrap(err, "failed to decode specgen"))
return
}
tempSpec := &specgen.SpecGenerator{} // temporary spec since infra cannot be decoded into
err = json.Unmarshal(out, tempSpec) // unmarhal matching options
if err != nil {
utils.Error(w, "Something went wrong.", http.StatusInternalServerError, errors.Wrap(err, "failed to decode specgen"))
return
}
psg.InfraContainerSpec = tempSpec // set infra spec equal to temp
// a few extra that do not have the same json tags
psg.InfraContainerSpec.Name = psg.InfraName
psg.InfraContainerSpec.ConmonPidFile = psg.InfraConmonPidFile
psg.InfraContainerSpec.ContainerCreateCommand = psg.InfraCommand
imageName := psg.InfraImage
rawImageName := psg.InfraImage
if imageName == "" {
imageName = config.DefaultInfraImage
rawImageName = config.DefaultInfraImage
}
curr := infraOptions.Quiet
infraOptions.Quiet = true
pullOptions := &libimage.PullOptions{}
pulledImages, err := runtime.LibimageRuntime().Pull(context.Background(), imageName, config.PullPolicyMissing, pullOptions)
if err != nil {
utils.Error(w, "Something went wrong.", http.StatusInternalServerError, errors.Wrap(err, "could not pull image"))
return
}
if _, err := alltransports.ParseImageName(imageName); err == nil {
if len(pulledImages) != 0 {
imageName = pulledImages[0].ID()
}
}
infraOptions.Quiet = curr
psg.InfraImage = imageName
psg.InfraContainerSpec.Image = imageName
psg.InfraContainerSpec.RawImageName = rawImageName
}
podSpecComplete := entities.PodSpec{PodSpecGen: psg}
pod, err := generate.MakePod(&podSpecComplete, runtime)
if err != nil { if err != nil {
httpCode := http.StatusInternalServerError httpCode := http.StatusInternalServerError
if errors.Cause(err) == define.ErrPodExists { if errors.Cause(err) == define.ErrPodExists {
httpCode = http.StatusConflict httpCode = http.StatusConflict
} }
utils.Error(w, "Something went wrong.", httpCode, err) utils.Error(w, "Something went wrong.", httpCode, errors.Wrap(err, "failed to make pod"))
return return
} }
utils.WriteResponse(w, http.StatusCreated, handlers.IDResponse{ID: pod.ID()}) utils.WriteResponse(w, http.StatusCreated, handlers.IDResponse{ID: pod.ID()})

View File

@ -1,8 +1,6 @@
package types package types
import ( import "github.com/containers/podman/v3/pkg/domain/entities"
"github.com/containers/podman/v3/pkg/domain/entities"
)
// LibpodImagesRemoveReport is the return type for image removal via the rest // LibpodImagesRemoveReport is the return type for image removal via the rest
// api. // api.

View File

@ -9,27 +9,25 @@ import (
"github.com/containers/podman/v3/pkg/api/handlers" "github.com/containers/podman/v3/pkg/api/handlers"
"github.com/containers/podman/v3/pkg/bindings" "github.com/containers/podman/v3/pkg/bindings"
"github.com/containers/podman/v3/pkg/domain/entities" "github.com/containers/podman/v3/pkg/domain/entities"
"github.com/containers/podman/v3/pkg/specgen"
jsoniter "github.com/json-iterator/go" jsoniter "github.com/json-iterator/go"
) )
func CreatePodFromSpec(ctx context.Context, s *specgen.PodSpecGenerator, options *CreateOptions) (*entities.PodCreateReport, error) { func CreatePodFromSpec(ctx context.Context, spec *entities.PodSpec) (*entities.PodCreateReport, error) {
var ( var (
pcr entities.PodCreateReport pcr entities.PodCreateReport
) )
if options == nil { if spec == nil {
options = new(CreateOptions) spec = new(entities.PodSpec)
} }
_ = options
conn, err := bindings.GetClient(ctx) conn, err := bindings.GetClient(ctx)
if err != nil { if err != nil {
return nil, err return nil, err
} }
specgenString, err := jsoniter.MarshalToString(s) specString, err := jsoniter.MarshalToString(spec.PodSpecGen)
if err != nil { if err != nil {
return nil, err return nil, err
} }
stringReader := strings.NewReader(specgenString) stringReader := strings.NewReader(specString)
response, err := conn.DoRequest(stringReader, http.MethodPost, "/pods/create", nil, nil) response, err := conn.DoRequest(stringReader, http.MethodPost, "/pods/create", nil, nil)
if err != nil { if err != nil {
return nil, err return nil, err

View File

@ -8,6 +8,7 @@ import (
"github.com/containers/podman/v3/libpod/define" "github.com/containers/podman/v3/libpod/define"
"github.com/containers/podman/v3/pkg/bindings" "github.com/containers/podman/v3/pkg/bindings"
"github.com/containers/podman/v3/pkg/bindings/pods" "github.com/containers/podman/v3/pkg/bindings/pods"
"github.com/containers/podman/v3/pkg/domain/entities"
"github.com/containers/podman/v3/pkg/specgen" "github.com/containers/podman/v3/pkg/specgen"
. "github.com/onsi/ginkgo" . "github.com/onsi/ginkgo"
. "github.com/onsi/gomega" . "github.com/onsi/gomega"
@ -333,9 +334,9 @@ var _ = Describe("Podman pods", func() {
}) })
It("simple create pod", func() { It("simple create pod", func() {
ps := specgen.PodSpecGenerator{} ps := entities.PodSpec{PodSpecGen: specgen.PodSpecGenerator{InfraContainerSpec: &specgen.SpecGenerator{}}}
ps.Name = "foobar" ps.PodSpecGen.Name = "foobar"
_, err := pods.CreatePodFromSpec(bt.conn, &ps, nil) _, err := pods.CreatePodFromSpec(bt.conn, &ps)
Expect(err).To(BeNil()) Expect(err).To(BeNil())
exists, err := pods.Exists(bt.conn, "foobar", nil) exists, err := pods.Exists(bt.conn, "foobar", nil)

View File

@ -68,7 +68,7 @@ type ContainerEngine interface {
NetworkRm(ctx context.Context, namesOrIds []string, options NetworkRmOptions) ([]*NetworkRmReport, error) NetworkRm(ctx context.Context, namesOrIds []string, options NetworkRmOptions) ([]*NetworkRmReport, error)
PlayKube(ctx context.Context, path string, opts PlayKubeOptions) (*PlayKubeReport, error) PlayKube(ctx context.Context, path string, opts PlayKubeOptions) (*PlayKubeReport, error)
PlayKubeDown(ctx context.Context, path string, opts PlayKubeDownOptions) (*PlayKubeReport, error) PlayKubeDown(ctx context.Context, path string, opts PlayKubeDownOptions) (*PlayKubeReport, error)
PodCreate(ctx context.Context, opts PodCreateOptions) (*PodCreateReport, error) PodCreate(ctx context.Context, specg PodSpec) (*PodCreateReport, error)
PodExists(ctx context.Context, nameOrID string) (*BoolReport, error) PodExists(ctx context.Context, nameOrID string) (*BoolReport, error)
PodInspect(ctx context.Context, options PodInspectOptions) (*PodInspectReport, error) PodInspect(ctx context.Context, options PodInspectOptions) (*PodInspectReport, error)
PodKill(ctx context.Context, namesOrIds []string, options PodKillOptions) ([]*PodKillReport, error) PodKill(ctx context.Context, namesOrIds []string, options PodKillOptions) ([]*PodKillReport, error)

View File

@ -106,6 +106,14 @@ type PodRmReport struct {
Id string //nolint Id string //nolint
} }
// PddSpec is an abstracted version of PodSpecGen designed to eventually accept options
// not meant to be in a specgen
type PodSpec struct {
PodSpecGen specgen.PodSpecGenerator
}
// PodCreateOptions provides all possible options for creating a pod and its infra container
// swagger:model PodCreateOptions
type PodCreateOptions struct { type PodCreateOptions struct {
CGroupParent string CGroupParent string
CreateCommand []string CreateCommand []string
@ -125,6 +133,123 @@ type PodCreateOptions struct {
Userns specgen.Namespace Userns specgen.Namespace
} }
type ContainerCreateOptions struct {
Annotation []string
Attach []string
Authfile string
BlkIOWeight string
BlkIOWeightDevice []string
CapAdd []string
CapDrop []string
CgroupNS string
CGroupsMode string
CGroupParent string
CIDFile string
ConmonPIDFile string
CPUPeriod uint64
CPUQuota int64
CPURTPeriod uint64
CPURTRuntime int64
CPUShares uint64
CPUS float64
CPUSetCPUs string
CPUSetMems string
Devices []string
DeviceCGroupRule []string
DeviceReadBPs []string
DeviceReadIOPs []string
DeviceWriteBPs []string
DeviceWriteIOPs []string
Entrypoint *string
Env []string
EnvHost bool
EnvFile []string
Expose []string
GIDMap []string
GroupAdd []string
HealthCmd string
HealthInterval string
HealthRetries uint
HealthStartPeriod string
HealthTimeout string
Hostname string
HTTPProxy bool
ImageVolume string
Init bool
InitContainerType string
InitPath string
Interactive bool
IPC string
KernelMemory string
Label []string
LabelFile []string
LogDriver string
LogOptions []string
Memory string
MemoryReservation string
MemorySwap string
MemorySwappiness int64
Name string
NoHealthCheck bool
OOMKillDisable bool
OOMScoreAdj int
Arch string
OS string
Variant string
PID string
PIDsLimit *int64
Platform string
Pod string
PodIDFile string
Personality string
PreserveFDs uint
Privileged bool
PublishAll bool
Pull string
Quiet bool
ReadOnly bool
ReadOnlyTmpFS bool
Restart string
Replace bool
Requires []string
Rm bool
RootFS bool
Secrets []string
SecurityOpt []string
SdNotifyMode string
ShmSize string
SignaturePolicy string
StopSignal string
StopTimeout uint
StorageOpt []string
SubUIDName string
SubGIDName string
Sysctl []string
Systemd string
Timeout uint
TLSVerify bool
TmpFS []string
TTY bool
Timezone string
Umask string
UIDMap []string
Ulimit []string
User string
UserNS string
UTS string
Mount []string
Volume []string
VolumesFrom []string
Workdir string
SeccompPolicy string
PidFile string
IsInfra bool
Net *NetOptions
CgroupConf []string
}
type PodCreateReport struct { type PodCreateReport struct {
Id string //nolint Id string //nolint
} }
@ -149,21 +274,15 @@ func (p *PodCreateOptions) CPULimits() *specs.LinuxCPU {
return cpu return cpu
} }
func setNamespaces(p *PodCreateOptions) ([4]specgen.Namespace, error) { func ToPodSpecGen(s specgen.PodSpecGenerator, p *PodCreateOptions) (*specgen.PodSpecGenerator, error) {
allNS := [4]specgen.Namespace{}
if p.Pid != "" {
pid, err := specgen.ParseNamespace(p.Pid)
if err != nil {
return [4]specgen.Namespace{}, err
}
allNS[0] = pid
}
return allNS, nil
}
func (p *PodCreateOptions) ToPodSpecGen(s *specgen.PodSpecGenerator) error {
// Basic Config // Basic Config
s.Name = p.Name s.Name = p.Name
s.InfraName = p.InfraName
out, err := specgen.ParseNamespace(p.Pid)
if err != nil {
return nil, err
}
s.Pid = out
s.Hostname = p.Hostname s.Hostname = p.Hostname
s.Labels = p.Labels s.Labels = p.Labels
s.NoInfra = !p.Infra s.NoInfra = !p.Infra
@ -174,32 +293,26 @@ func (p *PodCreateOptions) ToPodSpecGen(s *specgen.PodSpecGenerator) error {
s.InfraConmonPidFile = p.InfraConmonPidFile s.InfraConmonPidFile = p.InfraConmonPidFile
} }
s.InfraImage = p.InfraImage s.InfraImage = p.InfraImage
s.InfraName = p.InfraName
s.SharedNamespaces = p.Share s.SharedNamespaces = p.Share
s.PodCreateCommand = p.CreateCommand s.PodCreateCommand = p.CreateCommand
// Networking config // Networking config
s.NetNS = p.Net.Network
s.StaticIP = p.Net.StaticIP
s.StaticMAC = p.Net.StaticMAC
s.PortMappings = p.Net.PublishPorts
s.CNINetworks = p.Net.CNINetworks
s.NetworkOptions = p.Net.NetworkOptions
if p.Net.UseImageResolvConf {
s.NoManageResolvConf = true
}
s.DNSServer = p.Net.DNSServers
s.DNSSearch = p.Net.DNSSearch
s.DNSOption = p.Net.DNSOptions
s.NoManageHosts = p.Net.NoHosts
s.HostAdd = p.Net.AddHosts
namespaces, err := setNamespaces(p) if p.Net != nil {
if err != nil { s.NetNS = p.Net.Network
return err s.StaticIP = p.Net.StaticIP
} s.StaticMAC = p.Net.StaticMAC
if !namespaces[0].IsDefault() { s.PortMappings = p.Net.PublishPorts
s.Pid = namespaces[0] s.CNINetworks = p.Net.CNINetworks
s.NetworkOptions = p.Net.NetworkOptions
if p.Net.UseImageResolvConf {
s.NoManageResolvConf = true
}
s.DNSServer = p.Net.DNSServers
s.DNSSearch = p.Net.DNSSearch
s.DNSOption = p.Net.DNSOptions
s.NoManageHosts = p.Net.NoHosts
s.HostAdd = p.Net.AddHosts
} }
// Cgroup // Cgroup
@ -219,7 +332,7 @@ func (p *PodCreateOptions) ToPodSpecGen(s *specgen.PodSpecGenerator) error {
} }
} }
s.Userns = p.Userns s.Userns = p.Userns
return nil return &s, nil
} }
type PodPruneOptions struct { type PodPruneOptions struct {

View File

@ -31,21 +31,33 @@ type VolumeDeleteReport struct{ Report }
// NetOptions reflect the shared network options between // NetOptions reflect the shared network options between
// pods and containers // pods and containers
type NetFlags struct {
AddHosts []string `json:"add-host,omitempty"`
DNS []string `json:"dns,omitempty"`
DNSOpt []string `json:"dns-opt,omitempty"`
DNDSearch []string `json:"dns-search,omitempty"`
MacAddr string `json:"mac-address,omitempty"`
Publish []string `json:"publish,omitempty"`
IP string `json:"ip,omitempty"`
NoHosts bool `json:"no-hosts,omitempty"`
Network string `json:"network,omitempty"`
NetworkAlias []string `json:"network-alias,omitempty"`
}
type NetOptions struct { type NetOptions struct {
AddHosts []string AddHosts []string `json:"hostadd,omitempty"`
Aliases []string Aliases []string `json:"network_alias,omitempty"`
CNINetworks []string CNINetworks []string `json:"cni_networks,omitempty"`
UseImageResolvConf bool UseImageResolvConf bool `json:"no_manage_resolv_conf,omitempty"`
DNSOptions []string DNSOptions []string `json:"dns_option,omitempty"`
DNSSearch []string DNSSearch []string `json:"dns_search,omitempty"`
DNSServers []net.IP DNSServers []net.IP `json:"dns_server,omitempty"`
Network specgen.Namespace Network specgen.Namespace `json:"netns,omitempty"`
NoHosts bool NoHosts bool `json:"no_manage_hosts,omitempty"`
PublishPorts []types.PortMapping PublishPorts []types.PortMapping `json:"portmappings,omitempty"`
StaticIP *net.IP StaticIP *net.IP `json:"static_ip,omitempty"`
StaticMAC *net.HardwareAddr StaticMAC *net.HardwareAddr `json:"static_mac,omitempty"`
// NetworkOptions are additional options for each network // NetworkOptions are additional options for each network
NetworkOptions map[string][]string NetworkOptions map[string][]string `json:"network_options,omitempty"`
} }
// All CLI inspect commands and inspect sub-commands use the same options // All CLI inspect commands and inspect sub-commands use the same options

View File

@ -583,7 +583,11 @@ func (ic *ContainerEngine) ContainerCreate(ctx context.Context, s *specgen.SpecG
for _, w := range warn { for _, w := range warn {
fmt.Fprintf(os.Stderr, "%s\n", w) fmt.Fprintf(os.Stderr, "%s\n", w)
} }
ctr, err := generate.MakeContainer(ctx, ic.Libpod, s) rtSpec, spec, opts, err := generate.MakeContainer(context.Background(), ic.Libpod, s)
if err != nil {
return nil, err
}
ctr, err := generate.ExecuteCreate(ctx, ic.Libpod, rtSpec, spec, false, opts...)
if err != nil { if err != nil {
return nil, err return nil, err
} }
@ -915,7 +919,11 @@ func (ic *ContainerEngine) ContainerRun(ctx context.Context, opts entities.Conta
for _, w := range warn { for _, w := range warn {
fmt.Fprintf(os.Stderr, "%s\n", w) fmt.Fprintf(os.Stderr, "%s\n", w)
} }
ctr, err := generate.MakeContainer(ctx, ic.Libpod, opts.Spec) rtSpec, spec, optsN, err := generate.MakeContainer(ctx, ic.Libpod, opts.Spec)
if err != nil {
return nil, err
}
ctr, err := generate.ExecuteCreate(ctx, ic.Libpod, rtSpec, spec, false, optsN...)
if err != nil { if err != nil {
return nil, err return nil, err
} }

View File

@ -60,9 +60,7 @@ func (ic *ContainerEngine) GenerateKube(ctx context.Context, nameOrIDs []string,
return nil, err return nil, err
} }
} else { } else {
if len(ctr.Dependencies()) > 0 { // now that infra holds NS data, we need to support dependencies.
return nil, errors.Wrapf(define.ErrNotImplemented, "containers with dependencies")
}
// we cannot deal with ctrs already in a pod. // we cannot deal with ctrs already in a pod.
if len(ctr.PodID()) > 0 { if len(ctr.PodID()) > 0 {
return nil, errors.Errorf("container %s is associated with pod %s: use generate on the pod itself", ctr.ID(), ctr.PodID()) return nil, errors.Errorf("container %s is associated with pod %s: use generate on the pod itself", ctr.ID(), ctr.PodID())

View File

@ -6,6 +6,7 @@ import (
"fmt" "fmt"
"io" "io"
"io/ioutil" "io/ioutil"
"net"
"os" "os"
"path/filepath" "path/filepath"
"strconv" "strconv"
@ -22,6 +23,7 @@ import (
"github.com/containers/podman/v3/pkg/specgen" "github.com/containers/podman/v3/pkg/specgen"
"github.com/containers/podman/v3/pkg/specgen/generate" "github.com/containers/podman/v3/pkg/specgen/generate"
"github.com/containers/podman/v3/pkg/specgen/generate/kube" "github.com/containers/podman/v3/pkg/specgen/generate/kube"
"github.com/containers/podman/v3/pkg/specgenutil"
"github.com/containers/podman/v3/pkg/util" "github.com/containers/podman/v3/pkg/util"
"github.com/ghodss/yaml" "github.com/ghodss/yaml"
"github.com/pkg/errors" "github.com/pkg/errors"
@ -179,10 +181,12 @@ func (ic *ContainerEngine) playKubePod(ctx context.Context, podName string, podY
} }
} }
p, err := kube.ToPodGen(ctx, podName, podYAML) podOpt := entities.PodCreateOptions{Infra: true, Net: &entities.NetOptions{StaticIP: &net.IP{}, StaticMAC: &net.HardwareAddr{}}}
podOpt, err = kube.ToPodOpt(ctx, podName, podOpt, podYAML)
if err != nil { if err != nil {
return nil, err return nil, err
} }
if options.Network != "" { if options.Network != "" {
ns, cniNets, netOpts, err := specgen.ParseNetworkString(options.Network) ns, cniNets, netOpts, err := specgen.ParseNetworkString(options.Network)
if err != nil { if err != nil {
@ -193,42 +197,37 @@ func (ic *ContainerEngine) playKubePod(ctx context.Context, podName string, podY
return nil, errors.Errorf("invalid value passed to --network: bridge or host networking must be configured in YAML") return nil, errors.Errorf("invalid value passed to --network: bridge or host networking must be configured in YAML")
} }
logrus.Debugf("Pod %q joining CNI networks: %v", podName, cniNets) logrus.Debugf("Pod %q joining CNI networks: %v", podName, cniNets)
p.NetNS.NSMode = specgen.Bridge podOpt.Net.Network.NSMode = specgen.Bridge
p.CNINetworks = append(p.CNINetworks, cniNets...) podOpt.Net.CNINetworks = append(podOpt.Net.CNINetworks, cniNets...)
if len(netOpts) > 0 { if len(netOpts) > 0 {
p.NetworkOptions = netOpts podOpt.Net.NetworkOptions = netOpts
} }
} }
if len(options.StaticIPs) > *ipIndex { if len(options.StaticIPs) > *ipIndex {
p.StaticIP = &options.StaticIPs[*ipIndex] podOpt.Net.StaticIP = &options.StaticIPs[*ipIndex]
} else if len(options.StaticIPs) > 0 { } else if len(options.StaticIPs) > 0 {
// only warn if the user has set at least one ip // only warn if the user has set at least one ip
logrus.Warn("No more static ips left using a random one") logrus.Warn("No more static ips left using a random one")
} }
if len(options.StaticMACs) > *ipIndex { if len(options.StaticMACs) > *ipIndex {
p.StaticMAC = &options.StaticMACs[*ipIndex] podOpt.Net.StaticMAC = &options.StaticMACs[*ipIndex]
} else if len(options.StaticIPs) > 0 { } else if len(options.StaticIPs) > 0 {
// only warn if the user has set at least one mac // only warn if the user has set at least one mac
logrus.Warn("No more static macs left using a random one") logrus.Warn("No more static macs left using a random one")
} }
*ipIndex++ *ipIndex++
// Create the Pod p := specgen.NewPodSpecGenerator()
pod, err := generate.MakePod(p, ic.Libpod)
if err != nil { if err != nil {
return nil, err return nil, err
} }
podInfraID, err := pod.InfraContainerID() p, err = entities.ToPodSpecGen(*p, &podOpt)
if err != nil { if err != nil {
return nil, err return nil, err
} }
podSpec := entities.PodSpec{PodSpecGen: *p}
if !options.Quiet {
writer = os.Stderr
}
volumes, err := kube.InitializeVolumes(podYAML.Spec.Volumes) volumes, err := kube.InitializeVolumes(podYAML.Spec.Volumes)
if err != nil { if err != nil {
return nil, err return nil, err
@ -267,112 +266,146 @@ func (ic *ContainerEngine) playKubePod(ctx context.Context, podName string, podY
configMaps = append(configMaps, cm) configMaps = append(configMaps, cm)
} }
if podOpt.Infra {
imagePull := config.DefaultInfraImage
if podOpt.InfraImage != config.DefaultInfraImage && podOpt.InfraImage != "" {
imagePull = podOpt.InfraImage
}
pulledImages, err := pullImage(ic, writer, imagePull, options, config.PullPolicyNewer)
if err != nil {
return nil, err
}
infraOptions := entities.ContainerCreateOptions{ImageVolume: "bind"}
podSpec.PodSpecGen.InfraImage = pulledImages[0].Names()[0]
podSpec.PodSpecGen.NoInfra = false
podSpec.PodSpecGen.InfraContainerSpec = specgen.NewSpecGenerator(pulledImages[0].Names()[0], false)
podSpec.PodSpecGen.InfraContainerSpec.NetworkOptions = p.NetworkOptions
err = specgenutil.FillOutSpecGen(podSpec.PodSpecGen.InfraContainerSpec, &infraOptions, []string{})
if err != nil {
return nil, err
}
}
// Create the Pod
pod, err := generate.MakePod(&podSpec, ic.Libpod)
if err != nil {
return nil, err
}
podInfraID, err := pod.InfraContainerID()
if err != nil {
return nil, err
}
if !options.Quiet {
writer = os.Stderr
}
containers := make([]*libpod.Container, 0, len(podYAML.Spec.Containers)) containers := make([]*libpod.Container, 0, len(podYAML.Spec.Containers))
cwd, err := os.Getwd() cwd, err := os.Getwd()
if err != nil { if err != nil {
return nil, err return nil, err
} }
for _, container := range podYAML.Spec.Containers { for _, container := range podYAML.Spec.Containers {
// Contains all labels obtained from kube if !strings.Contains("infra", container.Name) {
labels := make(map[string]string) // Contains all labels obtained from kube
var pulledImage *libimage.Image labels := make(map[string]string)
buildFile, err := getBuildFile(container.Image, cwd) var pulledImage *libimage.Image
if err != nil { buildFile, err := getBuildFile(container.Image, cwd)
return nil, err
}
existsLocally, err := ic.Libpod.LibimageRuntime().Exists(container.Image)
if err != nil {
return nil, err
}
if (len(buildFile) > 0 && !existsLocally) || (len(buildFile) > 0 && options.Build) {
buildOpts := new(buildahDefine.BuildOptions)
commonOpts := new(buildahDefine.CommonBuildOptions)
buildOpts.ConfigureNetwork = buildahDefine.NetworkDefault
buildOpts.Isolation = buildahDefine.IsolationChroot
buildOpts.CommonBuildOpts = commonOpts
buildOpts.Output = container.Image
if _, _, err := ic.Libpod.Build(ctx, *buildOpts, []string{buildFile}...); err != nil {
return nil, err
}
i, _, err := ic.Libpod.LibimageRuntime().LookupImage(container.Image, new(libimage.LookupImageOptions))
if err != nil { if err != nil {
return nil, err return nil, err
} }
pulledImage = i existsLocally, err := ic.Libpod.LibimageRuntime().Exists(container.Image)
} else { if err != nil {
// NOTE: set the pull policy to "newer". This will cover cases return nil, err
// where the "latest" tag requires a pull and will also }
// transparently handle "localhost/" prefixed files which *may* if (len(buildFile) > 0 && !existsLocally) || (len(buildFile) > 0 && options.Build) {
// refer to a locally built image OR an image running a buildOpts := new(buildahDefine.BuildOptions)
// registry on localhost. commonOpts := new(buildahDefine.CommonBuildOptions)
pullPolicy := config.PullPolicyNewer buildOpts.ConfigureNetwork = buildahDefine.NetworkDefault
if len(container.ImagePullPolicy) > 0 { buildOpts.Isolation = buildahDefine.IsolationChroot
// Make sure to lower the strings since K8s pull policy buildOpts.CommonBuildOpts = commonOpts
// may be capitalized (see bugzilla.redhat.com/show_bug.cgi?id=1985905). buildOpts.Output = container.Image
rawPolicy := string(container.ImagePullPolicy) if _, _, err := ic.Libpod.Build(ctx, *buildOpts, []string{buildFile}...); err != nil {
pullPolicy, err = config.ParsePullPolicy(strings.ToLower(rawPolicy)) return nil, err
}
i, _, err := ic.Libpod.LibimageRuntime().LookupImage(container.Image, new(libimage.LookupImageOptions))
if err != nil { if err != nil {
return nil, err return nil, err
} }
pulledImage = i
} else {
// NOTE: set the pull policy to "newer". This will cover cases
// where the "latest" tag requires a pull and will also
// transparently handle "localhost/" prefixed files which *may*
// refer to a locally built image OR an image running a
// registry on localhost.
pullPolicy := config.PullPolicyNewer
if len(container.ImagePullPolicy) > 0 {
// Make sure to lower the strings since K8s pull policy
// may be capitalized (see bugzilla.redhat.com/show_bug.cgi?id=1985905).
rawPolicy := string(container.ImagePullPolicy)
pullPolicy, err = config.ParsePullPolicy(strings.ToLower(rawPolicy))
if err != nil {
return nil, err
}
}
pulledImages, err := pullImage(ic, writer, container.Image, options, pullPolicy)
if err != nil {
return nil, err
}
pulledImage = pulledImages[0]
} }
// This ensures the image is the image store
pullOptions := &libimage.PullOptions{}
pullOptions.AuthFilePath = options.Authfile
pullOptions.CertDirPath = options.CertDir
pullOptions.SignaturePolicyPath = options.SignaturePolicy
pullOptions.Writer = writer
pullOptions.Username = options.Username
pullOptions.Password = options.Password
pullOptions.InsecureSkipTLSVerify = options.SkipTLSVerify
pulledImages, err := ic.Libpod.LibimageRuntime().Pull(ctx, container.Image, pullPolicy, pullOptions) // Handle kube annotations
for k, v := range annotations {
switch k {
// Auto update annotation without container name will apply to
// all containers within the pod
case autoupdate.Label, autoupdate.AuthfileLabel:
labels[k] = v
// Auto update annotation with container name will apply only
// to the specified container
case fmt.Sprintf("%s/%s", autoupdate.Label, container.Name),
fmt.Sprintf("%s/%s", autoupdate.AuthfileLabel, container.Name):
prefixAndCtr := strings.Split(k, "/")
labels[prefixAndCtr[0]] = v
}
}
specgenOpts := kube.CtrSpecGenOptions{
Container: container,
Image: pulledImage,
Volumes: volumes,
PodID: pod.ID(),
PodName: podName,
PodInfraID: podInfraID,
ConfigMaps: configMaps,
SeccompPaths: seccompPaths,
RestartPolicy: ctrRestartPolicy,
NetNSIsHost: p.NetNS.IsHost(),
SecretsManager: secretsManager,
LogDriver: options.LogDriver,
Labels: labels,
}
specGen, err := kube.ToSpecGen(ctx, &specgenOpts)
if err != nil { if err != nil {
return nil, err return nil, err
} }
pulledImage = pulledImages[0]
}
// Handle kube annotations rtSpec, spec, opts, err := generate.MakeContainer(ctx, ic.Libpod, specGen)
for k, v := range annotations { if err != nil {
switch k { return nil, err
// Auto update annotation without container name will apply to
// all containers within the pod
case autoupdate.Label, autoupdate.AuthfileLabel:
labels[k] = v
// Auto update annotation with container name will apply only
// to the specified container
case fmt.Sprintf("%s/%s", autoupdate.Label, container.Name),
fmt.Sprintf("%s/%s", autoupdate.AuthfileLabel, container.Name):
prefixAndCtr := strings.Split(k, "/")
labels[prefixAndCtr[0]] = v
} }
ctr, err := generate.ExecuteCreate(ctx, ic.Libpod, rtSpec, spec, false, opts...)
if err != nil {
return nil, err
}
containers = append(containers, ctr)
} }
specgenOpts := kube.CtrSpecGenOptions{
Container: container,
Image: pulledImage,
Volumes: volumes,
PodID: pod.ID(),
PodName: podName,
PodInfraID: podInfraID,
ConfigMaps: configMaps,
SeccompPaths: seccompPaths,
RestartPolicy: ctrRestartPolicy,
NetNSIsHost: p.NetNS.IsHost(),
SecretsManager: secretsManager,
LogDriver: options.LogDriver,
Labels: labels,
}
specGen, err := kube.ToSpecGen(ctx, &specgenOpts)
if err != nil {
return nil, err
}
ctr, err := generate.MakeContainer(ctx, ic.Libpod, specGen)
if err != nil {
return nil, err
}
containers = append(containers, ctr)
} }
if options.Start != types.OptionalBoolFalse { if options.Start != types.OptionalBoolFalse {
@ -383,6 +416,7 @@ func (ic *ContainerEngine) playKubePod(ctx context.Context, podName string, podY
} }
for id, err := range podStartErrors { for id, err := range podStartErrors {
playKubePod.ContainerErrors = append(playKubePod.ContainerErrors, errors.Wrapf(err, "error starting container %s", id).Error()) playKubePod.ContainerErrors = append(playKubePod.ContainerErrors, errors.Wrapf(err, "error starting container %s", id).Error())
fmt.Println(playKubePod.ContainerErrors)
} }
} }
@ -656,3 +690,21 @@ func (ic *ContainerEngine) PlayKubeDown(ctx context.Context, path string, _ enti
} }
return reports, nil return reports, nil
} }
// pullImage is a helper function to set up the proper pull options and pull the image for certain containers
func pullImage(ic *ContainerEngine, writer io.Writer, imagePull string, options entities.PlayKubeOptions, pullPolicy config.PullPolicy) ([]*libimage.Image, error) {
// This ensures the image is the image store
pullOptions := &libimage.PullOptions{}
pullOptions.AuthFilePath = options.Authfile
pullOptions.CertDirPath = options.CertDir
pullOptions.SignaturePolicyPath = options.SignaturePolicy
pullOptions.Writer = writer
pullOptions.Username = options.Username
pullOptions.Password = options.Password
pullOptions.InsecureSkipTLSVerify = options.SkipTLSVerify
pulledImages, err := ic.Libpod.LibimageRuntime().Pull(context.Background(), imagePull, pullPolicy, pullOptions)
if err != nil {
return nil, err
}
return pulledImages, nil
}

View File

@ -8,7 +8,6 @@ import (
"github.com/containers/podman/v3/pkg/domain/entities" "github.com/containers/podman/v3/pkg/domain/entities"
dfilters "github.com/containers/podman/v3/pkg/domain/filters" dfilters "github.com/containers/podman/v3/pkg/domain/filters"
"github.com/containers/podman/v3/pkg/signal" "github.com/containers/podman/v3/pkg/signal"
"github.com/containers/podman/v3/pkg/specgen"
"github.com/containers/podman/v3/pkg/specgen/generate" "github.com/containers/podman/v3/pkg/specgen/generate"
"github.com/pkg/errors" "github.com/pkg/errors"
"github.com/sirupsen/logrus" "github.com/sirupsen/logrus"
@ -248,12 +247,8 @@ func (ic *ContainerEngine) prunePodHelper(ctx context.Context) ([]*entities.PodP
return reports, nil return reports, nil
} }
func (ic *ContainerEngine) PodCreate(ctx context.Context, opts entities.PodCreateOptions) (*entities.PodCreateReport, error) { func (ic *ContainerEngine) PodCreate(ctx context.Context, specg entities.PodSpec) (*entities.PodCreateReport, error) {
podSpec := specgen.NewPodSpecGenerator() pod, err := generate.MakePod(&specg, ic.Libpod)
if err := opts.ToPodSpecGen(podSpec); err != nil {
return nil, err
}
pod, err := generate.MakePod(podSpec, ic.Libpod)
if err != nil { if err != nil {
return nil, err return nil, err
} }

View File

@ -7,6 +7,7 @@ import (
"github.com/containers/podman/v3/libpod/events" "github.com/containers/podman/v3/libpod/events"
"github.com/containers/podman/v3/pkg/bindings/system" "github.com/containers/podman/v3/pkg/bindings/system"
"github.com/containers/podman/v3/pkg/domain/entities" "github.com/containers/podman/v3/pkg/domain/entities"
"github.com/pkg/errors" "github.com/pkg/errors"
) )

View File

@ -6,7 +6,6 @@ import (
"github.com/containers/podman/v3/libpod/define" "github.com/containers/podman/v3/libpod/define"
"github.com/containers/podman/v3/pkg/bindings/pods" "github.com/containers/podman/v3/pkg/bindings/pods"
"github.com/containers/podman/v3/pkg/domain/entities" "github.com/containers/podman/v3/pkg/domain/entities"
"github.com/containers/podman/v3/pkg/specgen"
"github.com/containers/podman/v3/pkg/util" "github.com/containers/podman/v3/pkg/util"
"github.com/pkg/errors" "github.com/pkg/errors"
) )
@ -179,10 +178,8 @@ func (ic *ContainerEngine) PodPrune(ctx context.Context, opts entities.PodPruneO
return pods.Prune(ic.ClientCtx, nil) return pods.Prune(ic.ClientCtx, nil)
} }
func (ic *ContainerEngine) PodCreate(ctx context.Context, opts entities.PodCreateOptions) (*entities.PodCreateReport, error) { func (ic *ContainerEngine) PodCreate(ctx context.Context, specg entities.PodSpec) (*entities.PodCreateReport, error) {
podSpec := specgen.NewPodSpecGenerator() return pods.CreatePodFromSpec(ic.ClientCtx, &specg)
opts.ToPodSpecGen(podSpec)
return pods.CreatePodFromSpec(ic.ClientCtx, podSpec, nil)
} }
func (ic *ContainerEngine) PodTop(ctx context.Context, opts entities.PodTopOptions) (*entities.StringSliceReport, error) { func (ic *ContainerEngine) PodTop(ctx context.Context, opts entities.PodTopOptions) (*entities.StringSliceReport, error) {

View File

@ -22,10 +22,10 @@ import (
// MakeContainer creates a container based on the SpecGenerator. // MakeContainer creates a container based on the SpecGenerator.
// Returns the created, container and any warnings resulting from creating the // Returns the created, container and any warnings resulting from creating the
// container, or an error. // container, or an error.
func MakeContainer(ctx context.Context, rt *libpod.Runtime, s *specgen.SpecGenerator) (*libpod.Container, error) { func MakeContainer(ctx context.Context, rt *libpod.Runtime, s *specgen.SpecGenerator) (*spec.Spec, *specgen.SpecGenerator, []libpod.CtrCreateOption, error) {
rtc, err := rt.GetConfig() rtc, err := rt.GetConfig()
if err != nil { if err != nil {
return nil, err return nil, nil, nil, err
} }
// If joining a pod, retrieve the pod for use. // If joining a pod, retrieve the pod for use.
@ -33,7 +33,7 @@ func MakeContainer(ctx context.Context, rt *libpod.Runtime, s *specgen.SpecGener
if s.Pod != "" { if s.Pod != "" {
pod, err = rt.LookupPod(s.Pod) pod, err = rt.LookupPod(s.Pod)
if err != nil { if err != nil {
return nil, errors.Wrapf(err, "error retrieving pod %s", s.Pod) return nil, nil, nil, errors.Wrapf(err, "error retrieving pod %s", s.Pod)
} }
} }
@ -41,47 +41,48 @@ func MakeContainer(ctx context.Context, rt *libpod.Runtime, s *specgen.SpecGener
if s.PidNS.IsDefault() { if s.PidNS.IsDefault() {
defaultNS, err := GetDefaultNamespaceMode("pid", rtc, pod) defaultNS, err := GetDefaultNamespaceMode("pid", rtc, pod)
if err != nil { if err != nil {
return nil, err return nil, nil, nil, err
} }
s.PidNS = defaultNS s.PidNS = defaultNS
} }
if s.IpcNS.IsDefault() { if s.IpcNS.IsDefault() {
defaultNS, err := GetDefaultNamespaceMode("ipc", rtc, pod) defaultNS, err := GetDefaultNamespaceMode("ipc", rtc, pod)
if err != nil { if err != nil {
return nil, err return nil, nil, nil, err
} }
s.IpcNS = defaultNS s.IpcNS = defaultNS
} }
if s.UtsNS.IsDefault() { if s.UtsNS.IsDefault() {
defaultNS, err := GetDefaultNamespaceMode("uts", rtc, pod) defaultNS, err := GetDefaultNamespaceMode("uts", rtc, pod)
if err != nil { if err != nil {
return nil, err return nil, nil, nil, err
} }
s.UtsNS = defaultNS s.UtsNS = defaultNS
} }
if s.UserNS.IsDefault() { if s.UserNS.IsDefault() {
defaultNS, err := GetDefaultNamespaceMode("user", rtc, pod) defaultNS, err := GetDefaultNamespaceMode("user", rtc, pod)
if err != nil { if err != nil {
return nil, err return nil, nil, nil, err
} }
s.UserNS = defaultNS s.UserNS = defaultNS
} }
if s.NetNS.IsDefault() { if s.NetNS.IsDefault() {
defaultNS, err := GetDefaultNamespaceMode("net", rtc, pod) defaultNS, err := GetDefaultNamespaceMode("net", rtc, pod)
if err != nil { if err != nil {
return nil, err return nil, nil, nil, err
} }
s.NetNS = defaultNS s.NetNS = defaultNS
} }
if s.CgroupNS.IsDefault() { if s.CgroupNS.IsDefault() {
defaultNS, err := GetDefaultNamespaceMode("cgroup", rtc, pod) defaultNS, err := GetDefaultNamespaceMode("cgroup", rtc, pod)
if err != nil { if err != nil {
return nil, err return nil, nil, nil, err
} }
s.CgroupNS = defaultNS s.CgroupNS = defaultNS
} }
options := []libpod.CtrCreateOption{} options := []libpod.CtrCreateOption{}
if s.ContainerCreateCommand != nil { if s.ContainerCreateCommand != nil {
options = append(options, libpod.WithCreateCommand(s.ContainerCreateCommand)) options = append(options, libpod.WithCreateCommand(s.ContainerCreateCommand))
} }
@ -94,12 +95,11 @@ func MakeContainer(ctx context.Context, rt *libpod.Runtime, s *specgen.SpecGener
var resolvedImageName string var resolvedImageName string
newImage, resolvedImageName, err = rt.LibimageRuntime().LookupImage(s.Image, nil) newImage, resolvedImageName, err = rt.LibimageRuntime().LookupImage(s.Image, nil)
if err != nil { if err != nil {
return nil, err return nil, nil, nil, err
} }
imageData, err = newImage.Inspect(ctx, false) imageData, err = newImage.Inspect(ctx, false)
if err != nil { if err != nil {
return nil, err return nil, nil, nil, err
} }
// If the input name changed, we could properly resolve the // If the input name changed, we could properly resolve the
// image. Otherwise, it must have been an ID where we're // image. Otherwise, it must have been an ID where we're
@ -115,29 +115,32 @@ func MakeContainer(ctx context.Context, rt *libpod.Runtime, s *specgen.SpecGener
options = append(options, libpod.WithRootFSFromImage(newImage.ID(), resolvedImageName, s.RawImageName)) options = append(options, libpod.WithRootFSFromImage(newImage.ID(), resolvedImageName, s.RawImageName))
} }
if err := s.Validate(); err != nil { if err := s.Validate(); err != nil {
return nil, errors.Wrap(err, "invalid config provided") return nil, nil, nil, errors.Wrap(err, "invalid config provided")
} }
finalMounts, finalVolumes, finalOverlays, err := finalizeMounts(ctx, s, rt, rtc, newImage) finalMounts, finalVolumes, finalOverlays, err := finalizeMounts(ctx, s, rt, rtc, newImage)
if err != nil { if err != nil {
return nil, err return nil, nil, nil, err
} }
command, err := makeCommand(ctx, s, imageData, rtc) command, err := makeCommand(ctx, s, imageData, rtc)
if err != nil { if err != nil {
return nil, err return nil, nil, nil, err
} }
opts, err := createContainerOptions(ctx, rt, s, pod, finalVolumes, finalOverlays, imageData, command) opts, err := createContainerOptions(ctx, rt, s, pod, finalVolumes, finalOverlays, imageData, command)
if err != nil { if err != nil {
return nil, err return nil, nil, nil, err
} }
options = append(options, opts...) options = append(options, opts...)
exitCommandArgs, err := CreateExitCommandArgs(rt.StorageConfig(), rtc, logrus.IsLevelEnabled(logrus.DebugLevel), s.Remove, false) var exitCommandArgs []string
exitCommandArgs, err = CreateExitCommandArgs(rt.StorageConfig(), rtc, logrus.IsLevelEnabled(logrus.DebugLevel), s.Remove, false)
if err != nil { if err != nil {
return nil, err return nil, nil, nil, err
} }
options = append(options, libpod.WithExitCommand(exitCommandArgs)) options = append(options, libpod.WithExitCommand(exitCommandArgs))
if len(s.Aliases) > 0 { if len(s.Aliases) > 0 {
@ -147,23 +150,26 @@ func MakeContainer(ctx context.Context, rt *libpod.Runtime, s *specgen.SpecGener
if containerType := s.InitContainerType; len(containerType) > 0 { if containerType := s.InitContainerType; len(containerType) > 0 {
options = append(options, libpod.WithInitCtrType(containerType)) options = append(options, libpod.WithInitCtrType(containerType))
} }
if len(s.Name) > 0 {
logrus.Debugf("setting container name %s", s.Name)
options = append(options, libpod.WithName(s.Name))
}
if len(s.Devices) > 0 { if len(s.Devices) > 0 {
opts = extractCDIDevices(s) opts = extractCDIDevices(s)
options = append(options, opts...) 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)
if err != nil { if err != nil {
return nil, err return nil, nil, nil, err
} }
return runtimeSpec, s, options, err
ctr, err := rt.NewContainer(ctx, runtimeSpec, options...) }
func ExecuteCreate(ctx context.Context, rt *libpod.Runtime, runtimeSpec *spec.Spec, s *specgen.SpecGenerator, infra bool, options ...libpod.CtrCreateOption) (*libpod.Container, error) {
ctr, err := rt.NewContainer(ctx, runtimeSpec, s, infra, options...)
if err != nil { if err != nil {
return ctr, err return ctr, err
} }
// Copy the content from the underlying image into the newly created
// volume if configured to do so.
return ctr, rt.PrepareVolumeOnCreateContainer(ctx, ctr) return ctr, rt.PrepareVolumeOnCreateContainer(ctx, ctr)
} }
@ -256,11 +262,6 @@ func createContainerOptions(ctx context.Context, rt *libpod.Runtime, s *specgen.
if len(s.SdNotifyMode) > 0 { if len(s.SdNotifyMode) > 0 {
options = append(options, libpod.WithSdNotifyMode(s.SdNotifyMode)) options = append(options, libpod.WithSdNotifyMode(s.SdNotifyMode))
} }
if len(s.Name) > 0 {
logrus.Debugf("setting container name %s", s.Name)
options = append(options, libpod.WithName(s.Name))
}
if pod != nil { if pod != nil {
logrus.Debugf("adding container to pod %s", pod.Name()) logrus.Debugf("adding container to pod %s", pod.Name())
options = append(options, rt.WithPod(pod)) options = append(options, rt.WithPod(pod))
@ -379,11 +380,11 @@ func createContainerOptions(ctx context.Context, rt *libpod.Runtime, s *specgen.
options = append(options, libpod.WithPrivileged(s.Privileged)) options = append(options, libpod.WithPrivileged(s.Privileged))
// Get namespace related options // Get namespace related options
namespaceOptions, err := namespaceOptions(ctx, s, rt, pod, imageData) namespaceOpts, err := namespaceOptions(ctx, s, rt, pod, imageData)
if err != nil { if err != nil {
return nil, err return nil, err
} }
options = append(options, namespaceOptions...) options = append(options, namespaceOpts...)
if len(s.ConmonPidFile) > 0 { if len(s.ConmonPidFile) > 0 {
options = append(options, libpod.WithConmonPidFile(s.ConmonPidFile)) options = append(options, libpod.WithConmonPidFile(s.ConmonPidFile))

View File

@ -14,6 +14,7 @@ import (
"github.com/containers/image/v5/manifest" "github.com/containers/image/v5/manifest"
"github.com/containers/podman/v3/libpod/network/types" "github.com/containers/podman/v3/libpod/network/types"
ann "github.com/containers/podman/v3/pkg/annotations" ann "github.com/containers/podman/v3/pkg/annotations"
"github.com/containers/podman/v3/pkg/domain/entities"
"github.com/containers/podman/v3/pkg/specgen" "github.com/containers/podman/v3/pkg/specgen"
"github.com/containers/podman/v3/pkg/specgen/generate" "github.com/containers/podman/v3/pkg/specgen/generate"
"github.com/containers/podman/v3/pkg/util" "github.com/containers/podman/v3/pkg/util"
@ -23,25 +24,26 @@ import (
"k8s.io/apimachinery/pkg/api/resource" "k8s.io/apimachinery/pkg/api/resource"
) )
func ToPodGen(ctx context.Context, podName string, podYAML *v1.PodTemplateSpec) (*specgen.PodSpecGenerator, error) { func ToPodOpt(ctx context.Context, podName string, p entities.PodCreateOptions, podYAML *v1.PodTemplateSpec) (entities.PodCreateOptions, error) {
p := specgen.NewPodSpecGenerator() // p := specgen.NewPodSpecGenerator()
p.Net = &entities.NetOptions{}
p.Name = podName p.Name = podName
p.Labels = podYAML.ObjectMeta.Labels p.Labels = podYAML.ObjectMeta.Labels
// Kube pods must share {ipc, net, uts} by default // Kube pods must share {ipc, net, uts} by default
p.SharedNamespaces = append(p.SharedNamespaces, "ipc") p.Share = append(p.Share, "ipc")
p.SharedNamespaces = append(p.SharedNamespaces, "net") p.Share = append(p.Share, "net")
p.SharedNamespaces = append(p.SharedNamespaces, "uts") p.Share = append(p.Share, "uts")
// TODO we only configure Process namespace. We also need to account for Host{IPC,Network,PID} // TODO we only configure Process namespace. We also need to account for Host{IPC,Network,PID}
// which is not currently possible with pod create // which is not currently possible with pod create
if podYAML.Spec.ShareProcessNamespace != nil && *podYAML.Spec.ShareProcessNamespace { if podYAML.Spec.ShareProcessNamespace != nil && *podYAML.Spec.ShareProcessNamespace {
p.SharedNamespaces = append(p.SharedNamespaces, "pid") p.Share = append(p.Share, "pid")
} }
p.Hostname = podYAML.Spec.Hostname p.Hostname = podYAML.Spec.Hostname
if p.Hostname == "" { if p.Hostname == "" {
p.Hostname = podName p.Hostname = podName
} }
if podYAML.Spec.HostNetwork { if podYAML.Spec.HostNetwork {
p.NetNS.NSMode = specgen.Host p.Net.Network = specgen.Namespace{NSMode: "host"}
} }
if podYAML.Spec.HostAliases != nil { if podYAML.Spec.HostAliases != nil {
hosts := make([]string, 0, len(podYAML.Spec.HostAliases)) hosts := make([]string, 0, len(podYAML.Spec.HostAliases))
@ -50,10 +52,10 @@ func ToPodGen(ctx context.Context, podName string, podYAML *v1.PodTemplateSpec)
hosts = append(hosts, host+":"+hostAlias.IP) hosts = append(hosts, host+":"+hostAlias.IP)
} }
} }
p.HostAdd = hosts p.Net.AddHosts = hosts
} }
podPorts := getPodPorts(podYAML.Spec.Containers) podPorts := getPodPorts(podYAML.Spec.Containers)
p.PortMappings = podPorts p.Net.PublishPorts = podPorts
if dnsConfig := podYAML.Spec.DNSConfig; dnsConfig != nil { if dnsConfig := podYAML.Spec.DNSConfig; dnsConfig != nil {
// name servers // name servers
@ -62,11 +64,11 @@ func ToPodGen(ctx context.Context, podName string, podYAML *v1.PodTemplateSpec)
for _, server := range dnsServers { for _, server := range dnsServers {
servers = append(servers, net.ParseIP(server)) servers = append(servers, net.ParseIP(server))
} }
p.DNSServer = servers p.Net.DNSServers = servers
} }
// search domains // search domains
if domains := dnsConfig.Searches; len(domains) > 0 { if domains := dnsConfig.Searches; len(domains) > 0 {
p.DNSSearch = domains p.Net.DNSSearch = domains
} }
// dns options // dns options
if options := dnsConfig.Options; len(options) > 0 { if options := dnsConfig.Options; len(options) > 0 {
@ -110,6 +112,8 @@ type CtrSpecGenOptions struct {
LogDriver string LogDriver string
// Labels define key-value pairs of metadata // Labels define key-value pairs of metadata
Labels map[string]string Labels map[string]string
//
IsInfra bool
} }
func ToSpecGen(ctx context.Context, opts *CtrSpecGenOptions) (*specgen.SpecGenerator, error) { func ToSpecGen(ctx context.Context, opts *CtrSpecGenOptions) (*specgen.SpecGenerator, error) {
@ -216,19 +220,19 @@ func ToSpecGen(ctx context.Context, opts *CtrSpecGenOptions) (*specgen.SpecGener
} }
} }
// If only the yaml.Command is specified, set it as the entrypoint and drop the image Cmd // If only the yaml.Command is specified, set it as the entrypoint and drop the image Cmd
if len(opts.Container.Command) != 0 { if !opts.IsInfra && len(opts.Container.Command) != 0 {
s.Entrypoint = opts.Container.Command s.Entrypoint = opts.Container.Command
s.Command = []string{} s.Command = []string{}
} }
// Only override the cmd field if yaml.Args is specified // Only override the cmd field if yaml.Args is specified
// Keep the image entrypoint, or the yaml.command if specified // Keep the image entrypoint, or the yaml.command if specified
if len(opts.Container.Args) != 0 { if !opts.IsInfra && len(opts.Container.Args) != 0 {
s.Command = opts.Container.Args s.Command = opts.Container.Args
} }
// FIXME, // FIXME,
// we are currently ignoring imageData.Config.ExposedPorts // we are currently ignoring imageData.Config.ExposedPorts
if opts.Container.WorkingDir != "" { if !opts.IsInfra && opts.Container.WorkingDir != "" {
s.WorkDir = opts.Container.WorkingDir s.WorkDir = opts.Container.WorkingDir
} }

View File

@ -250,7 +250,7 @@ func namespaceOptions(ctx context.Context, s *specgen.SpecGenerator, rt *libpod.
if s.NetNS.Value != "" { if s.NetNS.Value != "" {
val = fmt.Sprintf("slirp4netns:%s", s.NetNS.Value) val = fmt.Sprintf("slirp4netns:%s", s.NetNS.Value)
} }
toReturn = append(toReturn, libpod.WithNetNS(portMappings, expose, postConfigureNetNS, val, nil)) toReturn = append(toReturn, libpod.WithNetNS(portMappings, expose, postConfigureNetNS, val, s.CNINetworks))
case specgen.Private: case specgen.Private:
fallthrough fallthrough
case specgen.Bridge: case specgen.Bridge:

View File

@ -201,7 +201,8 @@ func SpecGenToOCI(ctx context.Context, s *specgen.SpecGenerator, rt *libpod.Runt
Options: []string{"rprivate", "nosuid", "noexec", "nodev", "rw"}, Options: []string{"rprivate", "nosuid", "noexec", "nodev", "rw"},
} }
g.AddMount(sysMnt) g.AddMount(sysMnt)
} else if !canMountSys { }
if !canMountSys {
addCgroup = false addCgroup = false
g.RemoveMount("/sys") g.RemoveMount("/sys")
r := "ro" r := "ro"

View File

@ -2,53 +2,82 @@ package generate
import ( import (
"context" "context"
"net"
"github.com/containers/common/pkg/config"
"github.com/containers/podman/v3/libpod" "github.com/containers/podman/v3/libpod"
"github.com/containers/podman/v3/libpod/define"
"github.com/containers/podman/v3/pkg/domain/entities"
"github.com/containers/podman/v3/pkg/rootless" "github.com/containers/podman/v3/pkg/rootless"
"github.com/containers/podman/v3/pkg/specgen" "github.com/containers/podman/v3/pkg/specgen"
"github.com/pkg/errors" "github.com/pkg/errors"
"github.com/sirupsen/logrus" "github.com/sirupsen/logrus"
) )
func MakePod(p *specgen.PodSpecGenerator, rt *libpod.Runtime) (*libpod.Pod, error) { func MakePod(p *entities.PodSpec, rt *libpod.Runtime) (*libpod.Pod, error) {
if err := p.Validate(); err != nil { if err := p.PodSpecGen.Validate(); err != nil {
return nil, err return nil, err
} }
options, err := createPodOptions(p, rt) if !p.PodSpecGen.NoInfra && p.PodSpecGen.InfraContainerSpec != nil {
var err error
p.PodSpecGen.InfraContainerSpec, err = MapSpec(&p.PodSpecGen)
if err != nil {
return nil, err
}
}
options, err := createPodOptions(&p.PodSpecGen, rt, p.PodSpecGen.InfraContainerSpec)
if err != nil { if err != nil {
return nil, err return nil, err
} }
return rt.NewPod(context.Background(), options...) pod, err := rt.NewPod(context.Background(), p.PodSpecGen, options...)
if err != nil {
return nil, err
}
if !p.PodSpecGen.NoInfra && p.PodSpecGen.InfraContainerSpec != nil {
p.PodSpecGen.InfraContainerSpec.ContainerCreateCommand = []string{} // we do NOT want os.Args as the command, will display the pod create cmd
if p.PodSpecGen.InfraContainerSpec.Name == "" {
p.PodSpecGen.InfraContainerSpec.Name = pod.ID()[:12] + "-infra"
}
_, err = CompleteSpec(context.Background(), rt, p.PodSpecGen.InfraContainerSpec)
if err != nil {
return nil, err
}
p.PodSpecGen.InfraContainerSpec.User = "" // infraSpec user will get incorrectly assigned via the container creation process, overwrite here
rtSpec, spec, opts, err := MakeContainer(context.Background(), rt, p.PodSpecGen.InfraContainerSpec)
if err != nil {
return nil, err
}
spec.Pod = pod.ID()
opts = append(opts, rt.WithPod(pod))
spec.CgroupParent = pod.CgroupParent()
infraCtr, err := ExecuteCreate(context.Background(), rt, rtSpec, spec, true, opts...)
if err != nil {
return nil, err
}
pod, err = rt.AddInfra(context.Background(), pod, infraCtr)
if err != nil {
return nil, err
}
}
return pod, nil
} }
func createPodOptions(p *specgen.PodSpecGenerator, rt *libpod.Runtime) ([]libpod.PodCreateOption, error) { func createPodOptions(p *specgen.PodSpecGenerator, rt *libpod.Runtime, infraSpec *specgen.SpecGenerator) ([]libpod.PodCreateOption, error) {
var ( var (
options []libpod.PodCreateOption options []libpod.PodCreateOption
) )
if !p.NoInfra { if !p.NoInfra { //&& infraSpec != nil {
options = append(options, libpod.WithInfraContainer()) options = append(options, libpod.WithInfraContainer())
nsOptions, err := GetNamespaceOptions(p.SharedNamespaces, p.NetNS.IsHost()) nsOptions, err := GetNamespaceOptions(p.SharedNamespaces, p.InfraContainerSpec.NetNS.IsHost())
if err != nil { if err != nil {
return nil, err return nil, err
} }
options = append(options, nsOptions...) options = append(options, nsOptions...)
// Use pod user and infra userns only when --userns is not set to host // Use pod user and infra userns only when --userns is not set to host
if !p.Userns.IsHost() { if !p.InfraContainerSpec.UserNS.IsHost() && !p.InfraContainerSpec.UserNS.IsDefault() {
options = append(options, libpod.WithPodUser()) options = append(options, libpod.WithPodUser())
options = append(options, libpod.WithPodUserns(p.Userns))
} }
// Make our exit command
storageConfig := rt.StorageConfig()
runtimeConfig, err := rt.GetConfig()
if err != nil {
return nil, err
}
exitCommand, err := CreateExitCommandArgs(storageConfig, runtimeConfig, logrus.IsLevelEnabled(logrus.DebugLevel), false, false)
if err != nil {
return nil, errors.Wrapf(err, "error creating infra container exit command")
}
options = append(options, libpod.WithPodInfraExitCommand(exitCommand))
} }
if len(p.CgroupParent) > 0 { if len(p.CgroupParent) > 0 {
options = append(options, libpod.WithPodCgroupParent(p.CgroupParent)) options = append(options, libpod.WithPodCgroupParent(p.CgroupParent))
@ -59,62 +88,27 @@ func createPodOptions(p *specgen.PodSpecGenerator, rt *libpod.Runtime) ([]libpod
if len(p.Name) > 0 { if len(p.Name) > 0 {
options = append(options, libpod.WithPodName(p.Name)) options = append(options, libpod.WithPodName(p.Name))
} }
if p.ResourceLimits != nil && p.ResourceLimits.CPU != nil && p.ResourceLimits.CPU.Period != nil && p.ResourceLimits.CPU.Quota != nil { if p.PodCreateCommand != nil {
if *p.ResourceLimits.CPU.Period != 0 || *p.ResourceLimits.CPU.Quota != 0 { options = append(options, libpod.WithPodCreateCommand(p.PodCreateCommand))
options = append(options, libpod.WithPodCPUPAQ((*p.ResourceLimits.CPU.Period), (*p.ResourceLimits.CPU.Quota)))
}
}
if p.ResourceLimits != nil && p.ResourceLimits.CPU != nil && p.ResourceLimits.CPU.Cpus != "" {
options = append(options, libpod.WithPodCPUSetCPUs(p.ResourceLimits.CPU.Cpus))
} }
if len(p.Hostname) > 0 { if len(p.Hostname) > 0 {
options = append(options, libpod.WithPodHostname(p.Hostname)) options = append(options, libpod.WithPodHostname(p.Hostname))
} }
if len(p.HostAdd) > 0 {
options = append(options, libpod.WithPodHosts(p.HostAdd)) return options, nil
} }
if len(p.DNSServer) > 0 {
var dnsServers []string // MapSpec modifies the already filled Infra specgenerator,
for _, d := range p.DNSServer { // replacing necessary values with those specified in pod creation
dnsServers = append(dnsServers, d.String()) func MapSpec(p *specgen.PodSpecGenerator) (*specgen.SpecGenerator, error) {
if len(p.PortMappings) > 0 {
ports, _, _, err := ParsePortMapping(p.PortMappings)
if err != nil {
return nil, err
} }
options = append(options, libpod.WithPodDNS(dnsServers)) p.InfraContainerSpec.PortMappings = libpod.WithInfraContainerPorts(ports, p.InfraContainerSpec)
} }
if len(p.DNSOption) > 0 {
options = append(options, libpod.WithPodDNSOption(p.DNSOption))
}
if len(p.DNSSearch) > 0 {
options = append(options, libpod.WithPodDNSSearch(p.DNSSearch))
}
if p.StaticIP != nil {
options = append(options, libpod.WithPodStaticIP(*p.StaticIP))
}
if p.StaticMAC != nil {
options = append(options, libpod.WithPodStaticMAC(*p.StaticMAC))
}
if p.NoManageResolvConf {
options = append(options, libpod.WithPodUseImageResolvConf())
}
if len(p.CNINetworks) > 0 {
options = append(options, libpod.WithPodNetworks(p.CNINetworks))
}
if len(p.InfraImage) > 0 {
options = append(options, libpod.WithInfraImage(p.InfraImage))
}
if len(p.InfraName) > 0 {
options = append(options, libpod.WithInfraName(p.InfraName))
}
if len(p.InfraCommand) > 0 {
options = append(options, libpod.WithInfraCommand(p.InfraCommand))
}
if !p.Pid.IsDefault() {
options = append(options, libpod.WithPodPidNS(p.Pid))
}
switch p.NetNS.NSMode { switch p.NetNS.NSMode {
case specgen.Default, "": case specgen.Default, "":
if p.NoInfra { if p.NoInfra {
@ -123,42 +117,88 @@ func createPodOptions(p *specgen.PodSpecGenerator, rt *libpod.Runtime) ([]libpod
} }
if rootless.IsRootless() { if rootless.IsRootless() {
logrus.Debugf("Pod will use slirp4netns") logrus.Debugf("Pod will use slirp4netns")
options = append(options, libpod.WithPodSlirp4netns(p.NetworkOptions)) if p.InfraContainerSpec.NetNS.NSMode != "host" {
p.InfraContainerSpec.NetworkOptions = p.NetworkOptions
p.InfraContainerSpec.NetNS.NSMode = specgen.NamespaceMode("slirp4netns")
}
} else { } else {
logrus.Debugf("Pod using bridge network mode") logrus.Debugf("Pod using bridge network mode")
} }
case specgen.Bridge: case specgen.Bridge:
p.InfraContainerSpec.NetNS.NSMode = specgen.Bridge
logrus.Debugf("Pod using bridge network mode") logrus.Debugf("Pod using bridge network mode")
case specgen.Host: case specgen.Host:
logrus.Debugf("Pod will use host networking") logrus.Debugf("Pod will use host networking")
options = append(options, libpod.WithPodHostNetwork()) if len(p.InfraContainerSpec.PortMappings) > 0 ||
p.InfraContainerSpec.StaticIP != nil ||
p.InfraContainerSpec.StaticMAC != nil ||
len(p.InfraContainerSpec.CNINetworks) > 0 ||
p.InfraContainerSpec.NetNS.NSMode == specgen.NoNetwork {
return nil, errors.Wrapf(define.ErrInvalidArg, "cannot set host network if network-related configuration is specified")
}
p.InfraContainerSpec.NetNS.NSMode = specgen.Host
case specgen.Slirp: case specgen.Slirp:
logrus.Debugf("Pod will use slirp4netns") logrus.Debugf("Pod will use slirp4netns")
options = append(options, libpod.WithPodSlirp4netns(p.NetworkOptions)) if p.InfraContainerSpec.NetNS.NSMode != "host" {
p.InfraContainerSpec.NetworkOptions = p.NetworkOptions
p.InfraContainerSpec.NetNS.NSMode = specgen.NamespaceMode("slirp4netns")
}
case specgen.NoNetwork: case specgen.NoNetwork:
logrus.Debugf("Pod will not use networking") logrus.Debugf("Pod will not use networking")
options = append(options, libpod.WithPodNoNetwork()) if len(p.InfraContainerSpec.PortMappings) > 0 ||
p.InfraContainerSpec.StaticIP != nil ||
p.InfraContainerSpec.StaticMAC != nil ||
len(p.InfraContainerSpec.CNINetworks) > 0 ||
p.InfraContainerSpec.NetNS.NSMode == "host" {
return nil, errors.Wrapf(define.ErrInvalidArg, "cannot disable pod network if network-related configuration is specified")
}
p.InfraContainerSpec.NetNS.NSMode = specgen.NoNetwork
default: default:
return nil, errors.Errorf("pods presently do not support network mode %s", p.NetNS.NSMode) return nil, errors.Errorf("pods presently do not support network mode %s", p.NetNS.NSMode)
} }
if p.NoManageHosts { libpod.WithPodCgroups()
options = append(options, libpod.WithPodUseImageHosts()) if len(p.InfraCommand) > 0 {
} p.InfraContainerSpec.Entrypoint = p.InfraCommand
if len(p.PortMappings) > 0 {
ports, _, _, err := ParsePortMapping(p.PortMappings)
if err != nil {
return nil, err
}
options = append(options, libpod.WithInfraContainerPorts(ports))
}
options = append(options, libpod.WithPodCgroups())
if p.PodCreateCommand != nil {
options = append(options, libpod.WithPodCreateCommand(p.PodCreateCommand))
}
if len(p.InfraConmonPidFile) > 0 {
options = append(options, libpod.WithInfraConmonPidFile(p.InfraConmonPidFile))
} }
return options, nil if len(p.HostAdd) > 0 {
p.InfraContainerSpec.HostAdd = p.HostAdd
}
if len(p.DNSServer) > 0 {
var dnsServers []net.IP
dnsServers = append(dnsServers, p.DNSServer...)
p.InfraContainerSpec.DNSServers = dnsServers
}
if len(p.DNSOption) > 0 {
p.InfraContainerSpec.DNSOptions = p.DNSOption
}
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.CNINetworks) > 0 {
p.InfraContainerSpec.CNINetworks = p.CNINetworks
}
if p.NoManageHosts {
p.InfraContainerSpec.UseImageHosts = p.NoManageHosts
}
if len(p.InfraConmonPidFile) > 0 {
p.InfraContainerSpec.ConmonPidFile = p.InfraConmonPidFile
}
if p.InfraImage != config.DefaultInfraImage {
p.InfraContainerSpec.Image = p.InfraImage
}
return p.InfraContainerSpec, nil
} }

View File

@ -67,7 +67,7 @@ type PodBasicConfig struct {
// Pid sets the process id namespace of the pod // Pid sets the process id namespace of the pod
// Optional (defaults to private if unset). This sets the PID namespace of the infra container // Optional (defaults to private if unset). This sets the PID namespace of the infra container
// This configuration will then be shared with the entire pod if PID namespace sharing is enabled via --share // This configuration will then be shared with the entire pod if PID namespace sharing is enabled via --share
Pid Namespace `json:"pid,omitempty:"` Pid Namespace `json:"pidns,omitempty"`
// Userns is used to indicate which kind of Usernamespace to enter. // Userns is used to indicate which kind of Usernamespace to enter.
// Any containers created within the pod will inherit the pod's userns settings. // Any containers created within the pod will inherit the pod's userns settings.
// Optional // Optional
@ -173,6 +173,7 @@ type PodSpecGenerator struct {
PodNetworkConfig PodNetworkConfig
PodCgroupConfig PodCgroupConfig
PodResourceConfig PodResourceConfig
InfraContainerSpec *SpecGenerator `json:"-"`
} }
type PodResourceConfig struct { type PodResourceConfig struct {

View File

@ -1,13 +1,14 @@
package common package specgenutil
import ( import (
"github.com/containers/common/pkg/config" "github.com/containers/common/pkg/config"
"github.com/containers/podman/v3/pkg/domain/entities"
"github.com/pkg/errors" "github.com/pkg/errors"
) )
// validate determines if the flags and values given by the user are valid. things checked // validate determines if the flags and values given by the user are valid. things checked
// by validate must not need any state information on the flag (i.e. changed) // by validate must not need any state information on the flag (i.e. changed)
func (c *ContainerCLIOpts) validate() error { func validate(c *entities.ContainerCreateOptions) error {
var () var ()
if c.Rm && (c.Restart != "" && c.Restart != "no" && c.Restart != "on-failure") { if c.Rm && (c.Restart != "" && c.Restart != "no" && c.Restart != "on-failure") {
return errors.Errorf(`the --rm option conflicts with --restart, when the restartPolicy is not "" and "no"`) return errors.Errorf(`the --rm option conflicts with --restart, when the restartPolicy is not "" and "no"`)
@ -23,7 +24,11 @@ func (c *ContainerCLIOpts) validate() error {
"ignore": "", "ignore": "",
} }
if _, ok := imageVolType[c.ImageVolume]; !ok { if _, ok := imageVolType[c.ImageVolume]; !ok {
return errors.Errorf("invalid image-volume type %q. Pick one of bind, tmpfs, or ignore", c.ImageVolume) if c.IsInfra {
c.ImageVolume = "bind"
} else {
return errors.Errorf("invalid image-volume type %q. Pick one of bind, tmpfs, or ignore", c.ImageVolume)
}
} }
return nil return nil
} }

View File

@ -1,4 +1,4 @@
package common package specgenutil
import ( import (
"github.com/docker/go-connections/nat" "github.com/docker/go-connections/nat"

View File

@ -1,6 +1,7 @@
package common package specgenutil
import ( import (
"encoding/json"
"fmt" "fmt"
"os" "os"
"strconv" "strconv"
@ -11,8 +12,9 @@ import (
"github.com/containers/podman/v3/cmd/podman/parse" "github.com/containers/podman/v3/cmd/podman/parse"
"github.com/containers/podman/v3/libpod/define" "github.com/containers/podman/v3/libpod/define"
ann "github.com/containers/podman/v3/pkg/annotations" ann "github.com/containers/podman/v3/pkg/annotations"
"github.com/containers/podman/v3/pkg/domain/entities"
envLib "github.com/containers/podman/v3/pkg/env" envLib "github.com/containers/podman/v3/pkg/env"
ns "github.com/containers/podman/v3/pkg/namespaces" "github.com/containers/podman/v3/pkg/namespaces"
"github.com/containers/podman/v3/pkg/specgen" "github.com/containers/podman/v3/pkg/specgen"
systemdDefine "github.com/containers/podman/v3/pkg/systemd/define" systemdDefine "github.com/containers/podman/v3/pkg/systemd/define"
"github.com/containers/podman/v3/pkg/util" "github.com/containers/podman/v3/pkg/util"
@ -21,7 +23,7 @@ import (
"github.com/pkg/errors" "github.com/pkg/errors"
) )
func getCPULimits(c *ContainerCLIOpts) *specs.LinuxCPU { func getCPULimits(c *entities.ContainerCreateOptions) *specs.LinuxCPU {
cpu := &specs.LinuxCPU{} cpu := &specs.LinuxCPU{}
hasLimits := false hasLimits := false
@ -67,7 +69,7 @@ func getCPULimits(c *ContainerCLIOpts) *specs.LinuxCPU {
return cpu return cpu
} }
func getIOLimits(s *specgen.SpecGenerator, c *ContainerCLIOpts) (*specs.LinuxBlockIO, error) { func getIOLimits(s *specgen.SpecGenerator, c *entities.ContainerCreateOptions) (*specs.LinuxBlockIO, error) {
var err error var err error
io := &specs.LinuxBlockIO{} io := &specs.LinuxBlockIO{}
hasLimits := false hasLimits := false
@ -122,7 +124,7 @@ func getIOLimits(s *specgen.SpecGenerator, c *ContainerCLIOpts) (*specs.LinuxBlo
return io, nil return io, nil
} }
func getMemoryLimits(s *specgen.SpecGenerator, c *ContainerCLIOpts) (*specs.LinuxMemory, error) { func getMemoryLimits(s *specgen.SpecGenerator, c *entities.ContainerCreateOptions) (*specs.LinuxMemory, error) {
var err error var err error
memory := &specs.LinuxMemory{} memory := &specs.LinuxMemory{}
hasLimits := false hasLimits := false
@ -167,7 +169,7 @@ func getMemoryLimits(s *specgen.SpecGenerator, c *ContainerCLIOpts) (*specs.Linu
memory.Kernel = &mk memory.Kernel = &mk
hasLimits = true hasLimits = true
} }
if c.MemorySwappiness >= 0 { if c.MemorySwappiness > 0 {
swappiness := uint64(c.MemorySwappiness) swappiness := uint64(c.MemorySwappiness)
memory.Swappiness = &swappiness memory.Swappiness = &swappiness
hasLimits = true hasLimits = true
@ -182,7 +184,7 @@ func getMemoryLimits(s *specgen.SpecGenerator, c *ContainerCLIOpts) (*specs.Linu
return memory, nil return memory, nil
} }
func setNamespaces(s *specgen.SpecGenerator, c *ContainerCLIOpts) error { func setNamespaces(s *specgen.SpecGenerator, c *entities.ContainerCreateOptions) error {
var err error var err error
if c.PID != "" { if c.PID != "" {
@ -222,18 +224,22 @@ func setNamespaces(s *specgen.SpecGenerator, c *ContainerCLIOpts) error {
return nil return nil
} }
func FillOutSpecGen(s *specgen.SpecGenerator, c *ContainerCLIOpts, args []string) error { func FillOutSpecGen(s *specgen.SpecGenerator, c *entities.ContainerCreateOptions, args []string) error {
var ( var (
err error err error
) )
// validate flags as needed // validate flags as needed
if err := c.validate(); err != nil { if err := validate(c); err != nil {
return err return err
} }
s.User = c.User s.User = c.User
inputCommand := args[1:] var inputCommand []string
if !c.IsInfra {
if len(args) > 1 {
inputCommand = args[1:]
}
}
if len(c.HealthCmd) > 0 { if len(c.HealthCmd) > 0 {
if c.NoHealthCheck { if c.NoHealthCheck {
return errors.New("Cannot specify both --no-healthcheck and --health-cmd") return errors.New("Cannot specify both --no-healthcheck and --health-cmd")
@ -247,12 +253,33 @@ func FillOutSpecGen(s *specgen.SpecGenerator, c *ContainerCLIOpts, args []string
Test: []string{"NONE"}, Test: []string{"NONE"},
} }
} }
if err := setNamespaces(s, c); err != nil {
userNS := ns.UsernsMode(c.UserNS) return err
}
userNS := namespaces.UsernsMode(s.UserNS.NSMode)
tempIDMap, err := util.ParseIDMapping(namespaces.UsernsMode(c.UserNS), []string{}, []string{}, "", "")
if err != nil {
return err
}
s.IDMappings, err = util.ParseIDMapping(userNS, c.UIDMap, c.GIDMap, c.SubUIDName, c.SubGIDName) s.IDMappings, err = util.ParseIDMapping(userNS, c.UIDMap, c.GIDMap, c.SubUIDName, c.SubGIDName)
if err != nil { if err != nil {
return err return err
} }
if len(s.IDMappings.GIDMap) == 0 {
s.IDMappings.AutoUserNsOpts.AdditionalGIDMappings = tempIDMap.AutoUserNsOpts.AdditionalGIDMappings
if s.UserNS.NSMode == specgen.NamespaceMode("auto") {
s.IDMappings.AutoUserNs = true
}
}
if len(s.IDMappings.UIDMap) == 0 {
s.IDMappings.AutoUserNsOpts.AdditionalUIDMappings = tempIDMap.AutoUserNsOpts.AdditionalUIDMappings
if s.UserNS.NSMode == specgen.NamespaceMode("auto") {
s.IDMappings.AutoUserNs = true
}
}
if tempIDMap.AutoUserNsOpts.Size != 0 {
s.IDMappings.AutoUserNsOpts.Size = tempIDMap.AutoUserNsOpts.Size
}
// If some mappings are specified, assume a private user namespace // If some mappings are specified, assume a private user namespace
if userNS.IsDefaultValue() && (!s.IDMappings.HostUIDMapping || !s.IDMappings.HostGIDMapping) { if userNS.IsDefaultValue() && (!s.IDMappings.HostUIDMapping || !s.IDMappings.HostGIDMapping) {
s.UserNS.NSMode = specgen.Private s.UserNS.NSMode = specgen.Private
@ -267,7 +294,9 @@ func FillOutSpecGen(s *specgen.SpecGenerator, c *ContainerCLIOpts, args []string
} }
// We are not handling the Expose flag yet. // We are not handling the Expose flag yet.
// s.PortsExpose = c.Expose // s.PortsExpose = c.Expose
s.PortMappings = c.Net.PublishPorts if c.Net != nil {
s.PortMappings = c.Net.PublishPorts
}
s.PublishExposedPorts = c.PublishAll s.PublishExposedPorts = c.PublishAll
s.Pod = c.Pod s.Pod = c.Pod
@ -288,10 +317,6 @@ func FillOutSpecGen(s *specgen.SpecGenerator, c *ContainerCLIOpts, args []string
} }
s.Expose = expose s.Expose = expose
if err := setNamespaces(s, c); err != nil {
return err
}
if sig := c.StopSignal; len(sig) > 0 { if sig := c.StopSignal; len(sig) > 0 {
stopSignal, err := util.ParseSignal(sig) stopSignal, err := util.ParseSignal(sig)
if err != nil { if err != nil {
@ -380,6 +405,7 @@ func FillOutSpecGen(s *specgen.SpecGenerator, c *ContainerCLIOpts, args []string
} }
// Include the command used to create the container. // Include the command used to create the container.
s.ContainerCreateCommand = os.Args s.ContainerCreateCommand = os.Args
if len(inputCommand) > 0 { if len(inputCommand) > 0 {
@ -394,28 +420,34 @@ func FillOutSpecGen(s *specgen.SpecGenerator, c *ContainerCLIOpts, args []string
} }
s.ShmSize = &shmSize s.ShmSize = &shmSize
} }
s.CNINetworks = c.Net.CNINetworks
// Network aliases if c.Net != nil {
if len(c.Net.Aliases) > 0 { s.CNINetworks = c.Net.CNINetworks
// build a map of aliases where key=cniName
aliases := make(map[string][]string, len(s.CNINetworks))
for _, cniNetwork := range s.CNINetworks {
aliases[cniNetwork] = c.Net.Aliases
}
s.Aliases = aliases
} }
s.HostAdd = c.Net.AddHosts // Network aliases
s.UseImageResolvConf = c.Net.UseImageResolvConf if c.Net != nil {
s.DNSServers = c.Net.DNSServers if len(c.Net.Aliases) > 0 {
s.DNSSearch = c.Net.DNSSearch // build a map of aliases where key=cniName
s.DNSOptions = c.Net.DNSOptions aliases := make(map[string][]string, len(s.CNINetworks))
s.StaticIP = c.Net.StaticIP for _, cniNetwork := range s.CNINetworks {
s.StaticMAC = c.Net.StaticMAC aliases[cniNetwork] = c.Net.Aliases
s.NetworkOptions = c.Net.NetworkOptions }
s.UseImageHosts = c.Net.NoHosts s.Aliases = aliases
}
}
if c.Net != nil {
s.HostAdd = c.Net.AddHosts
s.UseImageResolvConf = c.Net.UseImageResolvConf
s.DNSServers = c.Net.DNSServers
s.DNSSearch = c.Net.DNSSearch
s.DNSOptions = c.Net.DNSOptions
s.StaticIP = c.Net.StaticIP
s.StaticMAC = c.Net.StaticMAC
s.NetworkOptions = c.Net.NetworkOptions
s.UseImageHosts = c.Net.NoHosts
}
s.ImageVolumeMode = c.ImageVolume s.ImageVolumeMode = c.ImageVolume
if s.ImageVolumeMode == "bind" { if s.ImageVolumeMode == "bind" {
s.ImageVolumeMode = "anonymous" s.ImageVolumeMode = "anonymous"

View File

@ -1,4 +1,4 @@
package common package specgenutil
import ( import (
"io/ioutil" "io/ioutil"

View File

@ -1,4 +1,4 @@
package common package specgenutil
import ( import (
"fmt" "fmt"

View File

@ -559,7 +559,7 @@ ENTRYPOINT ["sleep","99999"]
It("podman pod create --cpuset-cpus", func() { It("podman pod create --cpuset-cpus", func() {
podName := "testPod" podName := "testPod"
ctrName := "testCtr" ctrName := "testCtr"
numCPU := float64(sysinfo.NumCPU()) numCPU := float64(sysinfo.NumCPU()) - 1
numCPUStr := strconv.Itoa(int(numCPU)) numCPUStr := strconv.Itoa(int(numCPU))
in := "0-" + numCPUStr in := "0-" + numCPUStr
podCreate := podmanTest.Podman([]string{"pod", "create", "--cpuset-cpus", in, "--name", podName}) podCreate := podmanTest.Podman([]string{"pod", "create", "--cpuset-cpus", in, "--name", podName})
@ -588,20 +588,14 @@ ENTRYPOINT ["sleep","99999"]
podInspect.WaitWithDefaultTimeout() podInspect.WaitWithDefaultTimeout()
Expect(podInspect).Should(Exit(0)) Expect(podInspect).Should(Exit(0))
podJSON := podInspect.InspectPodToJSON() podJSON := podInspect.InspectPodToJSON()
Expect(podJSON.InfraConfig.PidNS).To(Equal("path")) Expect(podJSON.InfraConfig.PidNS).To(Equal(ns))
podName = "pidPod2" podName = "pidPod2"
ns = "pod" ns = "pod"
podCreate = podmanTest.Podman([]string{"pod", "create", "--pid", ns, "--name", podName, "--share", "pid"}) podCreate = podmanTest.Podman([]string{"pod", "create", "--pid", ns, "--name", podName, "--share", "pid"})
podCreate.WaitWithDefaultTimeout() podCreate.WaitWithDefaultTimeout()
Expect(podCreate).Should(Exit(0)) Expect(podCreate).Should(ExitWithError())
podInspect = podmanTest.Podman([]string{"pod", "inspect", podName})
podInspect.WaitWithDefaultTimeout()
Expect(podInspect).Should(Exit(0))
podJSON = podInspect.InspectPodToJSON()
Expect(podJSON.InfraConfig.PidNS).To(Equal("pod"))
podName = "pidPod3" podName = "pidPod3"
ns = "host" ns = "host"