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"
)
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 {
a := make([]string, 0, len(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
// 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 (
capAdd []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
// on speculation by Matt and I. We think that these come into play later
// like with start. We believe this is just a difference in podman/compat
cliOpts := ContainerCLIOpts{
cliOpts := entities.ContainerCreateOptions{
// Attach: nil, // don't need?
Authfile: "",
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/pkg/domain/entities"
"github.com/containers/podman/v3/pkg/specgen"
"github.com/containers/podman/v3/pkg/specgenutil"
"github.com/pkg/errors"
"github.com/spf13/cobra"
"github.com/spf13/pflag"
)
func DefineNetFlags(cmd *cobra.Command) {
@ -87,12 +89,15 @@ func DefineNetFlags(cmd *cobra.Command) {
// NetFlagsToNetOptions parses the network flags for the given cmd.
// The netnsFromConfig bool is used to indicate if the --network flag
// 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 (
err error
)
opts := entities.NetOptions{}
opts.AddHosts, err = cmd.Flags().GetStringSlice("add-host")
if opts == nil {
opts = &entities.NetOptions{}
}
opts.AddHosts, err = flags.GetStringSlice("add-host")
if err != nil {
return nil, err
}
@ -103,56 +108,50 @@ func NetFlagsToNetOptions(cmd *cobra.Command, netnsFromConfig bool) (*entities.N
}
}
if cmd.Flags().Changed("dns") {
servers, err := cmd.Flags().GetStringSlice("dns")
if err != nil {
return nil, err
}
for _, d := range servers {
if d == "none" {
opts.UseImageResolvConf = true
if len(servers) > 1 {
return nil, errors.Errorf("%s is not allowed to be specified with other DNS ip addresses", d)
}
break
servers, err := flags.GetStringSlice("dns")
if err != nil {
return nil, err
}
for _, d := range servers {
if d == "none" {
opts.UseImageResolvConf = true
if len(servers) > 1 {
return nil, errors.Errorf("%s is not allowed to be specified with other DNS ip addresses", d)
}
dns := net.ParseIP(d)
if dns == nil {
return nil, errors.Errorf("%s is not an ip address", d)
}
opts.DNSServers = append(opts.DNSServers, dns)
break
}
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 := cmd.Flags().GetStringSlice("dns-opt")
if err != nil {
options, err := flags.GetStringSlice("dns-opt")
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
}
opts.DNSOptions = options
}
opts.DNSSearch = dnsSearches
if cmd.Flags().Changed("dns-search") {
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")
m, err := flags.GetString("mac-address")
if err != nil {
return nil, err
}
@ -164,18 +163,18 @@ func NetFlagsToNetOptions(cmd *cobra.Command, netnsFromConfig bool) (*entities.N
opts.StaticMAC = &mac
}
inputPorts, err := cmd.Flags().GetStringSlice("publish")
inputPorts, err := flags.GetStringSlice("publish")
if err != nil {
return nil, err
}
if len(inputPorts) > 0 {
opts.PublishPorts, err = CreatePortBindings(inputPorts)
opts.PublishPorts, err = specgenutil.CreatePortBindings(inputPorts)
if err != nil {
return nil, err
}
}
ip, err := cmd.Flags().GetString("ip")
ip, err := flags.GetString("ip")
if err != nil {
return nil, err
}
@ -190,15 +189,15 @@ func NetFlagsToNetOptions(cmd *cobra.Command, netnsFromConfig bool) (*entities.N
opts.StaticIP = &staticIP
}
opts.NoHosts, err = cmd.Flags().GetBool("no-hosts")
opts.NoHosts, err = flags.GetBool("no-hosts")
if err != nil {
return nil, err
}
// 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
if netnsFromConfig || cmd.Flag("network").Changed {
network, err := cmd.Flags().GetString("network")
if netnsFromConfig || flags.Changed("network") {
network, err := flags.GetString("network")
if err != nil {
return nil, err
}
@ -215,12 +214,13 @@ func NetFlagsToNetOptions(cmd *cobra.Command, netnsFromConfig bool) (*entities.N
opts.CNINetworks = cniNets
}
aliases, err := cmd.Flags().GetStringSlice("network-alias")
aliases, err := flags.GetStringSlice("network-alias")
if err != nil {
return nil, err
}
if len(aliases) > 0 {
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/pkg/domain/entities"
"github.com/containers/podman/v3/pkg/specgen"
"github.com/containers/podman/v3/pkg/specgenutil"
"github.com/containers/podman/v3/pkg/util"
"github.com/pkg/errors"
"github.com/spf13/cobra"
@ -52,8 +53,8 @@ var (
)
var (
cliVals common.ContainerCLIOpts
InitContainerType string
cliVals entities.ContainerCreateOptions
)
func createFlags(cmd *cobra.Command) {
@ -67,13 +68,18 @@ func createFlags(cmd *cobra.Command) {
)
flags.SetInterspersed(false)
common.DefineCreateFlags(cmd, &cliVals)
common.DefineCreateFlags(cmd, &cliVals, false)
common.DefineNetFlags(cmd)
flags.SetNormalizeFunc(utils.AliasFlags)
if registry.IsRemote() {
_ = flags.MarkHidden("conmon-pidfile")
if cliVals.IsInfra {
_ = flags.MarkHidden("infra-conmon-pidfile")
} else {
_ = flags.MarkHidden("conmon-pidfile")
}
_ = flags.MarkHidden("pidfile")
}
@ -97,7 +103,8 @@ func create(cmd *cobra.Command, args []string) error {
var (
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 {
return err
}
@ -113,22 +120,22 @@ func create(cmd *cobra.Command, args []string) error {
cliVals.InitContainerType = initctr
}
if err := createInit(cmd); err != nil {
cliVals, err = CreateInit(cmd, cliVals, false)
if err != nil {
return err
}
imageName := args[0]
rawImageName := ""
if !cliVals.RootFS {
rawImageName = args[0]
name, err := pullImage(args[0])
name, err := PullImage(args[0], cliVals)
if err != nil {
return err
}
imageName = name
}
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
}
s.RawImageName = rawImageName
@ -169,100 +176,101 @@ func replaceContainer(name string) error {
return removeContainers([]string{name}, rmOptions, false)
}
func createInit(c *cobra.Command) error {
cliVals.StorageOpt = registry.PodmanConfig().StorageOpts
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()
func CreateInit(c *cobra.Command, vals entities.ContainerCreateOptions, isInfra bool) (entities.ContainerCreateOptions, error) {
vals.UserNS = c.Flag("userns").Value.String()
// if user did not modify --userns flag and did turn on
// uid/gid mappings, set userns flag to "private"
if !c.Flag("userns").Changed && cliVals.UserNS == "host" {
if len(cliVals.UIDMap) > 0 ||
len(cliVals.GIDMap) > 0 ||
cliVals.SubUIDName != "" ||
cliVals.SubGIDName != "" {
cliVals.UserNS = "private"
if !c.Flag("userns").Changed && vals.UserNS == "host" {
if len(vals.UIDMap) > 0 ||
len(vals.GIDMap) > 0 ||
vals.SubUIDName != "" ||
vals.SubGIDName != "" {
vals.UserNS = "private"
}
}
cliVals.IPC = c.Flag("ipc").Value.String()
cliVals.UTS = c.Flag("uts").Value.String()
cliVals.PID = c.Flag("pid").Value.String()
cliVals.CgroupNS = c.Flag("cgroupns").Value.String()
if c.Flag("entrypoint").Changed {
val := c.Flag("entrypoint").Value.String()
cliVals.Entrypoint = &val
}
if !isInfra {
if c.Flag("shm-size").Changed {
vals.ShmSize = c.Flag("shm-size").Value.String()
}
if c.Flag("cpu-period").Changed && c.Flag("cpus").Changed {
return vals, errors.Errorf("--cpu-period and --cpus cannot be set together")
}
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") {
groups := []string{}
for _, g := range cliVals.GroupAdd {
if g == "keep-groups" {
if len(cliVals.GroupAdd) > 1 {
return errors.New("the '--group-add keep-groups' option is not allowed with any other --group-add options")
if c.Flags().Changed("group-add") {
groups := []string{}
for _, g := range cliVals.GroupAdd {
if g == "keep-groups" {
if len(cliVals.GroupAdd) > 1 {
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") {
val := c.Flag("pids-limit").Value.String()
pidsLimit, err := strconv.ParseInt(val, 10, 32)
if err != nil {
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)
if !isInfra && c.Flag("entrypoint").Changed {
val := c.Flag("entrypoint").Value.String()
vals.Entrypoint = &val
} else if isInfra && c.Flag("infra-command").Changed {
}
// Docker-compatibility: the "-h" flag for run/create is reserved for
// the hostname (see https://github.com/containers/podman/issues/1367).
return nil
return vals, nil
}
func pullImage(imageName string) (string, error) {
pullPolicy, err := config.ParsePullPolicy(cliVals.Pull)
func PullImage(imageName string, cliVals entities.ContainerCreateOptions) (string, error) {
pullPolicy, err := config.ValidatePullPolicy(cliVals.Pull)
if err != nil {
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")
}
userns, err := specgen.ParseUserNamespace(cliVals.UserNS)
if err != nil {
return nil, err
var err error
uns := specgen.Namespace{NSMode: specgen.Default}
if cliVals.UserNS != "" {
uns, err = specgen.ParseNamespace(cliVals.UserNS)
if err != nil {
return nil, err
}
}
createOptions := entities.PodCreateOptions{
Name: podName,
Infra: true,
@ -330,12 +341,36 @@ func createPodIfNecessary(s *specgen.SpecGenerator, netOpts *entities.NetOptions
Cpus: cliVals.CPUS,
CpusetCpus: cliVals.CPUSetCPUs,
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.
s.ContainerBasicConfig.Hostname = ""
s.ContainerNetworkConfig = specgen.ContainerNetworkConfig{}
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/validate"
"github.com/containers/podman/v3/pkg/domain/entities"
"github.com/containers/podman/v3/pkg/specgenutil"
"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 {
return err
}

View File

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

View File

@ -14,6 +14,7 @@ import (
"github.com/containers/podman/v3/pkg/errorhandling"
"github.com/containers/podman/v3/pkg/rootless"
"github.com/containers/podman/v3/pkg/specgen"
"github.com/containers/podman/v3/pkg/specgenutil"
"github.com/pkg/errors"
"github.com/sirupsen/logrus"
"github.com/spf13/cobra"
@ -60,7 +61,7 @@ func runFlags(cmd *cobra.Command) {
flags := cmd.Flags()
flags.SetInterspersed(false)
common.DefineCreateFlags(cmd, &cliVals)
common.DefineCreateFlags(cmd, &cliVals, false)
common.DefineNetFlags(cmd)
flags.SetNormalizeFunc(utils.AliasFlags)
@ -106,10 +107,6 @@ func init() {
func run(cmd *cobra.Command, args []string) 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
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
runOpts.Rm = cliVals.Rm
if err := createInit(cmd); err != nil {
flags := cmd.Flags()
cliVals.Net, err = common.NetFlagsToNetOptions(nil, *flags, cliVals.Pod == "" && cliVals.PodIDFile == "")
if err != nil {
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++ {
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)
@ -137,7 +140,7 @@ func run(cmd *cobra.Command, args []string) error {
rawImageName := ""
if !cliVals.RootFS {
rawImageName = args[0]
name, err := pullImage(args[0])
name, err := PullImage(args[0], cliVals)
if err != nil {
return err
}
@ -178,7 +181,7 @@ func run(cmd *cobra.Command, args []string) error {
}
cliVals.PreserveFDs = runOpts.PreserveFDs
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
}
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/validate"
"github.com/containers/podman/v3/pkg/domain/entities"
"github.com/containers/podman/v3/pkg/specgenutil"
"github.com/spf13/cobra"
)
@ -59,7 +60,7 @@ func prune(cmd *cobra.Command, args []string) error {
return nil
}
}
filterMap, err := common.ParseFilters(filter)
filterMap, err := specgenutil.ParseFilters(filter)
if err != nil {
return err
}

View File

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

View File

@ -11,14 +11,17 @@ import (
"strings"
"github.com/containers/common/pkg/completion"
"github.com/containers/common/pkg/config"
"github.com/containers/common/pkg/sysinfo"
"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/registry"
"github.com/containers/podman/v3/cmd/podman/validate"
"github.com/containers/podman/v3/pkg/domain/entities"
"github.com/containers/podman/v3/pkg/errorhandling"
"github.com/containers/podman/v3/pkg/specgen"
"github.com/containers/podman/v3/pkg/specgenutil"
"github.com/containers/podman/v3/pkg/util"
"github.com/docker/docker/pkg/parsers"
"github.com/pkg/errors"
@ -44,11 +47,11 @@ var (
var (
createOptions entities.PodCreateOptions
infraOptions entities.ContainerCreateOptions
labels, labelFile []string
podIDFile string
replace bool
share string
userns string
)
func init() {
@ -58,62 +61,19 @@ func init() {
})
flags := createCommand.Flags()
flags.SetInterspersed(false)
infraOptions.IsInfra = true
common.DefineCreateFlags(createCommand, &infraOptions, true)
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")
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"
flags.StringVarP(&createOptions.Name, nameFlagName, "n", "", "Assign a name to the pod")
_ = createCommand.RegisterFlagCompletionFunc(nameFlagName, completion.AutocompleteNone)
hostnameFlagName := "hostname"
flags.StringVarP(&createOptions.Hostname, hostnameFlagName, "", "", "Set a hostname to the pod")
_ = createCommand.RegisterFlagCompletionFunc(hostnameFlagName, completion.AutocompleteNone)
pidFlagName := "pid"
flags.StringVar(&createOptions.Pid, pidFlagName, "", "PID namespace to use")
_ = createCommand.RegisterFlagCompletionFunc(pidFlagName, common.AutocompleteNamespace)
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)
podIDFileFlagName := "pod-id-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 {
var (
err error
podIDFD *os.File
err error
podIDFD *os.File
imageName string
rawImageName string
)
labelFile = infraOptions.LabelFile
labels = infraOptions.Label
createOptions.Labels, err = parse.GetAllLabels(labelFile, labels)
if err != nil {
return errors.Wrapf(err, "unable to process labels")
}
imageName = config.DefaultInfraImage
img := imageName
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")
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 = ""
if createOptions.InfraName != "" {
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
} 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, ",")
if cmd.Flag("infra-command").Changed {
// 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 {
return err
}
}
if cmd.Flag("infra-image").Changed {
// 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 {
return err
}
}
}
createOptions.Userns, err = specgen.ParseUserNamespace(userns)
if err != nil {
return err
}
if cmd.Flag("pod-id-file").Changed {
podIDFD, err = util.OpenExclusiveFile(podIDFile)
if err != nil && os.IsExist(err) {
@ -200,13 +180,6 @@ func create(cmd *cobra.Command, args []string) error {
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 !createOptions.Infra {
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)
}
}
response, err := registry.ContainerEngine().PodCreate(context.Background(), createOptions)
podSpec := specgen.NewPodSpecGenerator()
podSpec, err = entities.ToPodSpecGen(*podSpec, &createOptions)
if err != nil {
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 err = ioutil.WriteFile(podIDFile, []byte(response.Id), 0644); err != nil {
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/libpod/define"
"github.com/containers/podman/v3/pkg/domain/entities"
"github.com/containers/podman/v3/pkg/specgenutil"
"github.com/pkg/errors"
"github.com/spf13/cobra"
)
@ -66,7 +67,7 @@ func init() {
}
func rm(_ *cobra.Command, args []string) error {
ids, err := common.ReadPodIDFiles(rmOptions.PodIDFiles)
ids, err := specgenutil.ReadPodIDFiles(rmOptions.PodIDFiles)
if err != nil {
return err
}

View File

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

View File

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

View File

@ -972,11 +972,12 @@ func (c *Container) checkDependenciesRunning() ([]string, error) {
}
// Check the status
conf := depCtr.Config()
state, err := depCtr.State()
if err != nil {
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)
}
depCtrs[dep] = depCtr

View File

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

View File

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

View File

@ -14,6 +14,7 @@ import (
"github.com/containers/image/v5/types"
"github.com/containers/podman/v3/libpod/define"
"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/rootless"
"github.com/containers/podman/v3/pkg/specgen"
@ -21,7 +22,6 @@ import (
"github.com/containers/storage"
"github.com/containers/storage/pkg/idtools"
"github.com/cri-o/ocicni/pkg/ocicni"
"github.com/opencontainers/runtime-spec/specs-go"
"github.com/opencontainers/runtime-tools/generate"
"github.com/pkg/errors"
"github.com/sirupsen/logrus"
@ -713,7 +713,6 @@ func (r *Runtime) WithPod(pod *Pod) CtrCreateOption {
if pod == nil {
return define.ErrInvalidArg
}
ctr.config.Pod = pod.ID()
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.
func WithNamedVolumes(volumes []*ContainerNamedVolume) CtrCreateOption {
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
// if it does not exist.
func WithCreateWorkingDir() CtrCreateOption {
@ -1812,45 +1811,14 @@ func WithInitCtrType(containerType string) CtrCreateOption {
// Pod Creation Options
// WithInfraImage sets the infra image for libpod.
// An infra image is used for inter-container kernel
// namespace sharing within a pod. Typically, an infra
// container is lightweight and is there to reap
// zombie processes within its pid namespace.
func WithInfraImage(img 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.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
pod.config.CreateCommand = createCmd
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
// infra container.
func WithInfraConmonPidFile(path string) PodCreateOption {
func WithInfraConmonPidFile(path string, infraSpec *specgen.SpecGenerator) PodCreateOption {
return func(pod *Pod) error {
if pod.valid {
return define.ErrPodFinalized
}
pod.config.InfraContainer.ConmonPidFile = path
infraSpec.ConmonPidFile = path
return nil
}
}
@ -2099,320 +2055,25 @@ func WithInfraContainer() PodCreateOption {
if pod.valid {
return define.ErrPodFinalized
}
pod.config.InfraContainer.HasInfraContainer = true
pod.config.HasInfra = true
return nil
}
}
// WithInfraContainerPorts tells the pod to add port bindings to the pause container
func WithInfraContainerPorts(bindings []ocicni.PortMapping) 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 ports as no infra container is being created")
}
pod.config.InfraContainer.PortBindings = bindings
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
func WithInfraContainerPorts(bindings []ocicni.PortMapping, infraSpec *specgen.SpecGenerator) []netTypes.PortMapping {
bindingSpec := []netTypes.PortMapping{}
for _, bind := range bindings {
currBind := netTypes.PortMapping{}
currBind.ContainerPort = uint16(bind.ContainerPort)
currBind.HostIP = bind.HostIP
currBind.HostPort = uint16(bind.HostPort)
currBind.Protocol = bind.Protocol
bindingSpec = append(bindingSpec, currBind)
}
infraSpec.PortMappings = bindingSpec
return infraSpec.PortMappings
}
// WithVolatile sets the volatile flag for the container storage.
@ -2428,78 +2089,3 @@ func WithVolatile() CtrCreateOption {
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 (
"context"
"net"
"fmt"
"sort"
"time"
"github.com/containers/podman/v3/libpod/define"
"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/pkg/errors"
)
@ -63,7 +61,7 @@ type PodConfig struct {
UsePodUTS bool `json:"sharesUts,omitempty"`
UsePodCgroupNS bool `json:"sharesCgroupNS,omitempty"`
InfraContainer *InfraContainerConfig `json:"infraConfig"`
HasInfra bool `json:"hasInfra,omitempty"`
// Time pod was created
CreatedTime time.Time `json:"created"`
@ -85,41 +83,6 @@ type podState struct {
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
func (p *Pod) ID() string {
return p.config.ID
@ -139,45 +102,104 @@ func (p *Pod) Namespace() string {
// ResourceLim returns the cpuset resource limits for the pod
func (p *Pod) ResourceLim() *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{
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
}
// CPUPeriod returns the pod CPU period
func (p *Pod) CPUPeriod() uint64 {
resCopy := &specs.LinuxResources{}
if err := JSONDeepCopy(p.config.InfraContainer.ResourceLimits, resCopy); err != nil {
if p.state.InfraContainerID == "" {
return 0
}
if resCopy != nil && resCopy.CPU != nil && resCopy.CPU.Period != nil {
return *resCopy.CPU.Period
infra, err := p.runtime.GetContainer(p.state.InfraContainerID)
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
}
// CPUQuota returns the pod CPU quota
func (p *Pod) CPUQuota() int64 {
resCopy := &specs.LinuxResources{}
if err := JSONDeepCopy(p.config.InfraContainer.ResourceLimits, resCopy); err != nil {
if p.state.InfraContainerID == "" {
return 0
}
if resCopy != nil && resCopy.CPU != nil && resCopy.CPU.Quota != nil {
return *resCopy.CPU.Quota
infra, err := p.runtime.GetContainer(p.state.InfraContainerID)
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
}
// PidMode returns the PID mode given by the user ex: pod, private...
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
@ -263,20 +285,24 @@ func (p *Pod) CgroupPath() (string, error) {
if p.state.CgroupPath != "" {
return p.state.CgroupPath, nil
}
if !p.HasInfraContainer() {
if p.state.InfraContainerID == "" {
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 != "" {
ctr, err := p.runtime.state.Container(id)
ctr, err := p.infraContainer()
if err != nil {
return "", errors.Wrapf(err, "could not get infra")
}
if ctr != nil {
ctr.Start(context.Background(), false)
ctr.Start(context.Background(), true)
cgroupPath, err := ctr.CGroupPath()
fmt.Println(cgroupPath)
if err != nil {
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
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
@ -350,19 +376,26 @@ func (p *Pod) InfraContainerID() (string, error) {
return p.infraContainerID()
}
// InfraContainer returns the infra container.
func (p *Pod) InfraContainer() (*Container, error) {
if !p.HasInfraContainer() {
return nil, errors.Wrap(define.ErrNoSuchCtr, "pod has no infra container")
}
id, err := p.InfraContainerID()
// infraContainer is the unlocked versio of InfraContainer which returns the infra container
func (p *Pod) infraContainer() (*Container, error) {
id, err := p.infraContainerID()
if err != nil {
return nil, err
}
if id == "" {
return nil, errors.Wrap(define.ErrNoSuchCtr, "pod has no infra container")
}
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
// Lock pod to avoid lock contention
// 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() {
return "", nil
}
id, err := p.InfraContainerID()
if err != nil {
return "", err
}
ctr, err := p.runtime.state.Container(id)
ctr, err := p.infraContainer()
if err != nil {
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
// container.
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.HostNetwork = p.config.InfraContainer.HostNetwork
infraConfig.StaticIP = p.config.InfraContainer.StaticIP
infraConfig.StaticMAC = p.config.InfraContainer.StaticMAC.String()
infraConfig.NoManageResolvConf = p.config.InfraContainer.UseImageResolvConf
infraConfig.NoManageHosts = p.config.InfraContainer.UseImageHosts
infraConfig.HostNetwork = !infra.Config().ContainerNetworkConfig.UseImageHosts
infraConfig.StaticIP = infra.Config().ContainerNetworkConfig.StaticIP
infraConfig.NoManageResolvConf = infra.Config().UseImageResolvConf
infraConfig.NoManageHosts = infra.Config().UseImageHosts
infraConfig.CPUPeriod = p.CPUPeriod()
infraConfig.CPUQuota = p.CPUQuota()
infraConfig.CPUSetCPUs = p.ResourceLim().CPU.Cpus
infraConfig.PidNS = p.PidMode()
infraConfig.UserNS = p.config.InfraContainer.Userns.String()
infraConfig.UserNS = p.UserNSMode()
if len(p.config.InfraContainer.DNSServer) > 0 {
infraConfig.DNSServer = make([]string, 0, len(p.config.InfraContainer.DNSServer))
infraConfig.DNSServer = append(infraConfig.DNSServer, p.config.InfraContainer.DNSServer...)
if len(infra.Config().ContainerNetworkConfig.DNSServer) > 0 {
infraConfig.DNSServer = make([]string, 0, len(infra.Config().ContainerNetworkConfig.DNSServer))
for _, entry := range infra.Config().ContainerNetworkConfig.DNSServer {
infraConfig.DNSServer = append(infraConfig.DNSServer, entry.String())
}
}
if len(p.config.InfraContainer.DNSSearch) > 0 {
infraConfig.DNSSearch = make([]string, 0, len(p.config.InfraContainer.DNSSearch))
infraConfig.DNSSearch = append(infraConfig.DNSSearch, p.config.InfraContainer.DNSSearch...)
if len(infra.Config().ContainerNetworkConfig.DNSSearch) > 0 {
infraConfig.DNSSearch = make([]string, 0, len(infra.Config().ContainerNetworkConfig.DNSSearch))
infraConfig.DNSSearch = append(infraConfig.DNSSearch, infra.Config().ContainerNetworkConfig.DNSSearch...)
}
if len(p.config.InfraContainer.DNSOption) > 0 {
infraConfig.DNSOption = make([]string, 0, len(p.config.InfraContainer.DNSOption))
infraConfig.DNSOption = append(infraConfig.DNSOption, p.config.InfraContainer.DNSOption...)
if len(infra.Config().ContainerNetworkConfig.DNSOption) > 0 {
infraConfig.DNSOption = make([]string, 0, len(infra.Config().ContainerNetworkConfig.DNSOption))
infraConfig.DNSOption = append(infraConfig.DNSOption, infra.Config().ContainerNetworkConfig.DNSOption...)
}
if len(p.config.InfraContainer.HostAdd) > 0 {
infraConfig.HostAdd = make([]string, 0, len(p.config.InfraContainer.HostAdd))
infraConfig.HostAdd = append(infraConfig.HostAdd, p.config.InfraContainer.HostAdd...)
if len(infra.Config().HostAdd) > 0 {
infraConfig.HostAdd = make([]string, 0, len(infra.Config().HostAdd))
infraConfig.HostAdd = append(infraConfig.HostAdd, infra.Config().HostAdd...)
}
if len(p.config.InfraContainer.Networks) > 0 {
infraConfig.Networks = make([]string, 0, len(p.config.InfraContainer.Networks))
infraConfig.Networks = append(infraConfig.Networks, p.config.InfraContainer.Networks...)
if len(infra.Config().ContainerNetworkConfig.Networks) > 0 {
infraConfig.Networks = make([]string, 0, len(infra.Config().ContainerNetworkConfig.Networks))
infraConfig.Networks = append(infraConfig.Networks, infra.Config().ContainerNetworkConfig.Networks...)
}
infraConfig.NetworkOptions = p.config.InfraContainer.NetworkOptions
infraConfig.PortBindings = makeInspectPortBindings(p.config.InfraContainer.PortBindings, nil)
infraConfig.NetworkOptions = infra.Config().ContainerNetworkConfig.NetworkOptions
infraConfig.PortBindings = makeInspectPortBindings(infra.Config().ContainerNetworkConfig.PortMappings, nil)
}
inspectData := define.InspectPodData{

View File

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

View File

@ -17,6 +17,7 @@ import (
"github.com/containers/podman/v3/pkg/cgroups"
"github.com/containers/podman/v3/pkg/domain/entities/reports"
"github.com/containers/podman/v3/pkg/rootless"
"github.com/containers/podman/v3/pkg/specgen"
"github.com/containers/storage"
"github.com/containers/storage/pkg/stringid"
"github.com/docker/go-units"
@ -38,12 +39,15 @@ type CtrCreateOption func(*Container) error
type ContainerFilter func(*Container) bool
// 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()
defer r.lock.Unlock()
if !r.valid {
return nil, define.ErrRuntimeStopped
}
if infra {
options = append(options, withIsInfra())
}
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.StopSignal = 15
ctr.config.StopTimeout = r.config.Engine.StopTimeout
} else {
// 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) {
ctr, err := r.initContainerVariables(rSpec, nil)
var ctr *Container
var err error
ctr, err = r.initContainerVariables(rSpec, nil)
if err != nil {
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 {
return nil, err
}
if ctr.config.IsInfra {
ctr.config.StopTimeout = 10
}
// normalize the networks to names
// ocicni only knows about cni names so we have to make
// 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 {
case config.CgroupfsCgroupsManager:
if ctr.config.CgroupParent == "" {
if pod != nil && pod.config.UsePodCgroup {
if pod != nil && pod.config.UsePodCgroup && !ctr.IsInfra() {
podCgroup, err := pod.CgroupPath()
if err != nil {
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:
if ctr.config.CgroupParent == "" {
switch {
case pod != nil && pod.config.UsePodCgroup:
case pod != nil && pod.config.UsePodCgroup && !ctr.IsInfra():
podCgroup, err := pod.CgroupPath()
if err != nil {
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
}
infraID := pod.state.InfraContainerID
infraID, err := pod.infraContainerID()
if err != nil {
return "", err
}
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())
}

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/pkg/cgroups"
"github.com/containers/podman/v3/pkg/rootless"
"github.com/containers/podman/v3/pkg/specgen"
spec "github.com/opencontainers/runtime-spec/specs-go"
"github.com/pkg/errors"
"github.com/sirupsen/logrus"
)
// 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()
defer r.lock.Unlock()
@ -50,8 +51,8 @@ func (r *Runtime) NewPod(ctx context.Context, options ...PodCreateOption) (_ *Po
pod.config.Name = name
}
if pod.config.Hostname == "" {
pod.config.Hostname = pod.config.Name
if p.InfraContainerSpec != nil && p.InfraContainerSpec.Hostname == "" {
p.InfraContainerSpec.Hostname = pod.config.Name
}
// 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
if pod.config.UsePodCgroup {
pod.state.CgroupPath = filepath.Join(pod.config.CgroupParent, pod.ID())
if p.InfraContainerSpec != nil {
p.InfraContainerSpec.CgroupParent = pod.state.CgroupPath
}
}
}
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())
}
pod.state.CgroupPath = cgroupPath
if p.InfraContainerSpec != nil {
p.InfraContainerSpec.CgroupParent = pod.state.CgroupPath
}
}
default:
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 {
return nil, errors.Wrapf(err, "error adding pod to state")
}
defer func() {
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)
}
}
}()
return pod, nil
}
if pod.HasInfraContainer() {
ctr, err := r.createInfraContainer(ctx, pod)
if err != nil {
return nil, errors.Wrapf(err, "error adding Infra Container")
}
pod.state.InfraContainerID = ctr.ID()
if err := pod.save(); err != nil {
return nil, err
}
// AddInfra adds the created infra container to the pod state
func (r *Runtime) AddInfra(ctx context.Context, pod *Pod, infraCtr *Container) (*Pod, error) {
r.lock.Lock()
defer r.lock.Unlock()
if !r.valid {
return nil, define.ErrRuntimeStopped
}
pod.state.InfraContainerID = infraCtr.ID()
if err := pod.save(); err != nil {
return nil, err
}
pod.newPodEvent(events.Create)
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 {
if err := p.updatePod(); err != nil {
return err

View File

@ -11,6 +11,7 @@ import (
"github.com/containers/podman/v3/pkg/domain/entities"
"github.com/containers/podman/v3/pkg/domain/infra/abi"
"github.com/containers/podman/v3/pkg/specgen"
"github.com/containers/podman/v3/pkg/specgenutil"
"github.com/containers/storage"
"github.com/gorilla/schema"
"github.com/pkg/errors"
@ -80,7 +81,7 @@ func CreateContainer(w http.ResponseWriter, r *http.Request) {
}
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"))
return
}

View File

@ -28,7 +28,12 @@ func CreateContainer(w http.ResponseWriter, r *http.Request) {
utils.InternalServerError(w, err)
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 {
utils.InternalServerError(w, err)
return

View File

@ -1,11 +1,15 @@
package libpod
import (
"context"
"encoding/json"
"fmt"
"net/http"
"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/define"
"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/specgen"
"github.com/containers/podman/v3/pkg/specgen/generate"
"github.com/containers/podman/v3/pkg/specgenutil"
"github.com/containers/podman/v3/pkg/util"
"github.com/gorilla/schema"
"github.com/pkg/errors"
@ -25,24 +30,70 @@ func PodCreate(w http.ResponseWriter, r *http.Request) {
runtime = r.Context().Value("runtime").(*libpod.Runtime)
err error
)
var psg specgen.PodSpecGenerator
psg := specgen.PodSpecGenerator{InfraContainerSpec: &specgen.SpecGenerator{}}
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
}
// parse userns so we get the valid default value of userns
psg.Userns, err = specgen.ParseUserNamespace(psg.Userns.String())
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
}
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 {
httpCode := http.StatusInternalServerError
if errors.Cause(err) == define.ErrPodExists {
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
}
utils.WriteResponse(w, http.StatusCreated, handlers.IDResponse{ID: pod.ID()})

View File

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

View File

@ -9,27 +9,25 @@ import (
"github.com/containers/podman/v3/pkg/api/handlers"
"github.com/containers/podman/v3/pkg/bindings"
"github.com/containers/podman/v3/pkg/domain/entities"
"github.com/containers/podman/v3/pkg/specgen"
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 (
pcr entities.PodCreateReport
)
if options == nil {
options = new(CreateOptions)
if spec == nil {
spec = new(entities.PodSpec)
}
_ = options
conn, err := bindings.GetClient(ctx)
if err != nil {
return nil, err
}
specgenString, err := jsoniter.MarshalToString(s)
specString, err := jsoniter.MarshalToString(spec.PodSpecGen)
if err != nil {
return nil, err
}
stringReader := strings.NewReader(specgenString)
stringReader := strings.NewReader(specString)
response, err := conn.DoRequest(stringReader, http.MethodPost, "/pods/create", nil, nil)
if err != nil {
return nil, err

View File

@ -8,6 +8,7 @@ import (
"github.com/containers/podman/v3/libpod/define"
"github.com/containers/podman/v3/pkg/bindings"
"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/onsi/ginkgo"
. "github.com/onsi/gomega"
@ -333,9 +334,9 @@ var _ = Describe("Podman pods", func() {
})
It("simple create pod", func() {
ps := specgen.PodSpecGenerator{}
ps.Name = "foobar"
_, err := pods.CreatePodFromSpec(bt.conn, &ps, nil)
ps := entities.PodSpec{PodSpecGen: specgen.PodSpecGenerator{InfraContainerSpec: &specgen.SpecGenerator{}}}
ps.PodSpecGen.Name = "foobar"
_, err := pods.CreatePodFromSpec(bt.conn, &ps)
Expect(err).To(BeNil())
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)
PlayKube(ctx context.Context, path string, opts PlayKubeOptions) (*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)
PodInspect(ctx context.Context, options PodInspectOptions) (*PodInspectReport, error)
PodKill(ctx context.Context, namesOrIds []string, options PodKillOptions) ([]*PodKillReport, error)

View File

@ -106,6 +106,14 @@ type PodRmReport struct {
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 {
CGroupParent string
CreateCommand []string
@ -125,6 +133,123 @@ type PodCreateOptions struct {
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 {
Id string //nolint
}
@ -149,21 +274,15 @@ func (p *PodCreateOptions) CPULimits() *specs.LinuxCPU {
return cpu
}
func setNamespaces(p *PodCreateOptions) ([4]specgen.Namespace, 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 {
func ToPodSpecGen(s specgen.PodSpecGenerator, p *PodCreateOptions) (*specgen.PodSpecGenerator, error) {
// Basic Config
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.Labels = p.Labels
s.NoInfra = !p.Infra
@ -174,32 +293,26 @@ func (p *PodCreateOptions) ToPodSpecGen(s *specgen.PodSpecGenerator) error {
s.InfraConmonPidFile = p.InfraConmonPidFile
}
s.InfraImage = p.InfraImage
s.InfraName = p.InfraName
s.SharedNamespaces = p.Share
s.PodCreateCommand = p.CreateCommand
// 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 err != nil {
return err
}
if !namespaces[0].IsDefault() {
s.Pid = namespaces[0]
if p.Net != nil {
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
}
// Cgroup
@ -219,7 +332,7 @@ func (p *PodCreateOptions) ToPodSpecGen(s *specgen.PodSpecGenerator) error {
}
}
s.Userns = p.Userns
return nil
return &s, nil
}
type PodPruneOptions struct {

View File

@ -31,21 +31,33 @@ type VolumeDeleteReport struct{ Report }
// NetOptions reflect the shared network options between
// 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 {
AddHosts []string
Aliases []string
CNINetworks []string
UseImageResolvConf bool
DNSOptions []string
DNSSearch []string
DNSServers []net.IP
Network specgen.Namespace
NoHosts bool
PublishPorts []types.PortMapping
StaticIP *net.IP
StaticMAC *net.HardwareAddr
AddHosts []string `json:"hostadd,omitempty"`
Aliases []string `json:"network_alias,omitempty"`
CNINetworks []string `json:"cni_networks,omitempty"`
UseImageResolvConf bool `json:"no_manage_resolv_conf,omitempty"`
DNSOptions []string `json:"dns_option,omitempty"`
DNSSearch []string `json:"dns_search,omitempty"`
DNSServers []net.IP `json:"dns_server,omitempty"`
Network specgen.Namespace `json:"netns,omitempty"`
NoHosts bool `json:"no_manage_hosts,omitempty"`
PublishPorts []types.PortMapping `json:"portmappings,omitempty"`
StaticIP *net.IP `json:"static_ip,omitempty"`
StaticMAC *net.HardwareAddr `json:"static_mac,omitempty"`
// 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

View File

@ -583,7 +583,11 @@ func (ic *ContainerEngine) ContainerCreate(ctx context.Context, s *specgen.SpecG
for _, w := range warn {
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 {
return nil, err
}
@ -915,7 +919,11 @@ func (ic *ContainerEngine) ContainerRun(ctx context.Context, opts entities.Conta
for _, w := range warn {
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 {
return nil, err
}

View File

@ -60,9 +60,7 @@ func (ic *ContainerEngine) GenerateKube(ctx context.Context, nameOrIDs []string,
return nil, err
}
} else {
if len(ctr.Dependencies()) > 0 {
return nil, errors.Wrapf(define.ErrNotImplemented, "containers with dependencies")
}
// now that infra holds NS data, we need to support dependencies.
// we cannot deal with ctrs already in a pod.
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())

View File

@ -6,6 +6,7 @@ import (
"fmt"
"io"
"io/ioutil"
"net"
"os"
"path/filepath"
"strconv"
@ -22,6 +23,7 @@ import (
"github.com/containers/podman/v3/pkg/specgen"
"github.com/containers/podman/v3/pkg/specgen/generate"
"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/ghodss/yaml"
"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 {
return nil, err
}
if options.Network != "" {
ns, cniNets, netOpts, err := specgen.ParseNetworkString(options.Network)
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")
}
logrus.Debugf("Pod %q joining CNI networks: %v", podName, cniNets)
p.NetNS.NSMode = specgen.Bridge
p.CNINetworks = append(p.CNINetworks, cniNets...)
podOpt.Net.Network.NSMode = specgen.Bridge
podOpt.Net.CNINetworks = append(podOpt.Net.CNINetworks, cniNets...)
if len(netOpts) > 0 {
p.NetworkOptions = netOpts
podOpt.Net.NetworkOptions = netOpts
}
}
if len(options.StaticIPs) > *ipIndex {
p.StaticIP = &options.StaticIPs[*ipIndex]
podOpt.Net.StaticIP = &options.StaticIPs[*ipIndex]
} else if len(options.StaticIPs) > 0 {
// only warn if the user has set at least one ip
logrus.Warn("No more static ips left using a random one")
}
if len(options.StaticMACs) > *ipIndex {
p.StaticMAC = &options.StaticMACs[*ipIndex]
podOpt.Net.StaticMAC = &options.StaticMACs[*ipIndex]
} else if len(options.StaticIPs) > 0 {
// only warn if the user has set at least one mac
logrus.Warn("No more static macs left using a random one")
}
*ipIndex++
// Create the Pod
pod, err := generate.MakePod(p, ic.Libpod)
p := specgen.NewPodSpecGenerator()
if err != nil {
return nil, err
}
podInfraID, err := pod.InfraContainerID()
p, err = entities.ToPodSpecGen(*p, &podOpt)
if err != nil {
return nil, err
}
if !options.Quiet {
writer = os.Stderr
}
podSpec := entities.PodSpec{PodSpecGen: *p}
volumes, err := kube.InitializeVolumes(podYAML.Spec.Volumes)
if err != nil {
return nil, err
@ -267,112 +266,146 @@ func (ic *ContainerEngine) playKubePod(ctx context.Context, podName string, podY
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))
cwd, err := os.Getwd()
if err != nil {
return nil, err
}
for _, container := range podYAML.Spec.Containers {
// Contains all labels obtained from kube
labels := make(map[string]string)
var pulledImage *libimage.Image
buildFile, err := getBuildFile(container.Image, cwd)
if err != nil {
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 !strings.Contains("infra", container.Name) {
// Contains all labels obtained from kube
labels := make(map[string]string)
var pulledImage *libimage.Image
buildFile, err := getBuildFile(container.Image, cwd)
if err != nil {
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))
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 {
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 {
return nil, err
}
pulledImage = pulledImages[0]
}
// 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
rtSpec, spec, opts, err := generate.MakeContainer(ctx, ic.Libpod, specGen)
if err != nil {
return nil, err
}
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 {
@ -383,6 +416,7 @@ func (ic *ContainerEngine) playKubePod(ctx context.Context, podName string, podY
}
for id, err := range podStartErrors {
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
}
// 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"
dfilters "github.com/containers/podman/v3/pkg/domain/filters"
"github.com/containers/podman/v3/pkg/signal"
"github.com/containers/podman/v3/pkg/specgen"
"github.com/containers/podman/v3/pkg/specgen/generate"
"github.com/pkg/errors"
"github.com/sirupsen/logrus"
@ -248,12 +247,8 @@ func (ic *ContainerEngine) prunePodHelper(ctx context.Context) ([]*entities.PodP
return reports, nil
}
func (ic *ContainerEngine) PodCreate(ctx context.Context, opts entities.PodCreateOptions) (*entities.PodCreateReport, error) {
podSpec := specgen.NewPodSpecGenerator()
if err := opts.ToPodSpecGen(podSpec); err != nil {
return nil, err
}
pod, err := generate.MakePod(podSpec, ic.Libpod)
func (ic *ContainerEngine) PodCreate(ctx context.Context, specg entities.PodSpec) (*entities.PodCreateReport, error) {
pod, err := generate.MakePod(&specg, ic.Libpod)
if err != nil {
return nil, err
}

View File

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

View File

@ -6,7 +6,6 @@ import (
"github.com/containers/podman/v3/libpod/define"
"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/util"
"github.com/pkg/errors"
)
@ -179,10 +178,8 @@ func (ic *ContainerEngine) PodPrune(ctx context.Context, opts entities.PodPruneO
return pods.Prune(ic.ClientCtx, nil)
}
func (ic *ContainerEngine) PodCreate(ctx context.Context, opts entities.PodCreateOptions) (*entities.PodCreateReport, error) {
podSpec := specgen.NewPodSpecGenerator()
opts.ToPodSpecGen(podSpec)
return pods.CreatePodFromSpec(ic.ClientCtx, podSpec, nil)
func (ic *ContainerEngine) PodCreate(ctx context.Context, specg entities.PodSpec) (*entities.PodCreateReport, error) {
return pods.CreatePodFromSpec(ic.ClientCtx, &specg)
}
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.
// Returns the created, container and any warnings resulting from creating the
// 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()
if err != nil {
return nil, err
return nil, nil, nil, err
}
// 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 != "" {
pod, err = rt.LookupPod(s.Pod)
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() {
defaultNS, err := GetDefaultNamespaceMode("pid", rtc, pod)
if err != nil {
return nil, err
return nil, nil, nil, err
}
s.PidNS = defaultNS
}
if s.IpcNS.IsDefault() {
defaultNS, err := GetDefaultNamespaceMode("ipc", rtc, pod)
if err != nil {
return nil, err
return nil, nil, nil, err
}
s.IpcNS = defaultNS
}
if s.UtsNS.IsDefault() {
defaultNS, err := GetDefaultNamespaceMode("uts", rtc, pod)
if err != nil {
return nil, err
return nil, nil, nil, err
}
s.UtsNS = defaultNS
}
if s.UserNS.IsDefault() {
defaultNS, err := GetDefaultNamespaceMode("user", rtc, pod)
if err != nil {
return nil, err
return nil, nil, nil, err
}
s.UserNS = defaultNS
}
if s.NetNS.IsDefault() {
defaultNS, err := GetDefaultNamespaceMode("net", rtc, pod)
if err != nil {
return nil, err
return nil, nil, nil, err
}
s.NetNS = defaultNS
}
if s.CgroupNS.IsDefault() {
defaultNS, err := GetDefaultNamespaceMode("cgroup", rtc, pod)
if err != nil {
return nil, err
return nil, nil, nil, err
}
s.CgroupNS = defaultNS
}
options := []libpod.CtrCreateOption{}
if s.ContainerCreateCommand != nil {
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
newImage, resolvedImageName, err = rt.LibimageRuntime().LookupImage(s.Image, nil)
if err != nil {
return nil, err
return nil, nil, nil, err
}
imageData, err = newImage.Inspect(ctx, false)
if err != nil {
return nil, err
return nil, nil, nil, err
}
// If the input name changed, we could properly resolve the
// 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))
}
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)
if err != nil {
return nil, err
return nil, nil, nil, err
}
command, err := makeCommand(ctx, s, imageData, rtc)
if err != nil {
return nil, err
return nil, nil, nil, err
}
opts, err := createContainerOptions(ctx, rt, s, pod, finalVolumes, finalOverlays, imageData, command)
if err != nil {
return nil, err
return nil, nil, nil, err
}
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 {
return nil, err
return nil, nil, nil, err
}
options = append(options, libpod.WithExitCommand(exitCommandArgs))
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 {
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 {
opts = extractCDIDevices(s)
options = append(options, opts...)
}
runtimeSpec, err := SpecGenToOCI(ctx, s, rt, rtc, newImage, finalMounts, pod, command)
if err != nil {
return nil, err
return nil, nil, nil, err
}
ctr, err := rt.NewContainer(ctx, runtimeSpec, options...)
return runtimeSpec, s, options, err
}
func ExecuteCreate(ctx context.Context, rt *libpod.Runtime, runtimeSpec *spec.Spec, s *specgen.SpecGenerator, infra bool, options ...libpod.CtrCreateOption) (*libpod.Container, error) {
ctr, err := rt.NewContainer(ctx, runtimeSpec, s, infra, options...)
if err != nil {
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)
}
@ -256,11 +262,6 @@ func createContainerOptions(ctx context.Context, rt *libpod.Runtime, s *specgen.
if len(s.SdNotifyMode) > 0 {
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 {
logrus.Debugf("adding container to pod %s", pod.Name())
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))
// Get namespace related options
namespaceOptions, err := namespaceOptions(ctx, s, rt, pod, imageData)
namespaceOpts, err := namespaceOptions(ctx, s, rt, pod, imageData)
if err != nil {
return nil, err
}
options = append(options, namespaceOptions...)
options = append(options, namespaceOpts...)
if len(s.ConmonPidFile) > 0 {
options = append(options, libpod.WithConmonPidFile(s.ConmonPidFile))

View File

@ -14,6 +14,7 @@ import (
"github.com/containers/image/v5/manifest"
"github.com/containers/podman/v3/libpod/network/types"
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/generate"
"github.com/containers/podman/v3/pkg/util"
@ -23,25 +24,26 @@ import (
"k8s.io/apimachinery/pkg/api/resource"
)
func ToPodGen(ctx context.Context, podName string, podYAML *v1.PodTemplateSpec) (*specgen.PodSpecGenerator, error) {
p := specgen.NewPodSpecGenerator()
func ToPodOpt(ctx context.Context, podName string, p entities.PodCreateOptions, podYAML *v1.PodTemplateSpec) (entities.PodCreateOptions, error) {
// p := specgen.NewPodSpecGenerator()
p.Net = &entities.NetOptions{}
p.Name = podName
p.Labels = podYAML.ObjectMeta.Labels
// Kube pods must share {ipc, net, uts} by default
p.SharedNamespaces = append(p.SharedNamespaces, "ipc")
p.SharedNamespaces = append(p.SharedNamespaces, "net")
p.SharedNamespaces = append(p.SharedNamespaces, "uts")
p.Share = append(p.Share, "ipc")
p.Share = append(p.Share, "net")
p.Share = append(p.Share, "uts")
// TODO we only configure Process namespace. We also need to account for Host{IPC,Network,PID}
// which is not currently possible with pod create
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
if p.Hostname == "" {
p.Hostname = podName
}
if podYAML.Spec.HostNetwork {
p.NetNS.NSMode = specgen.Host
p.Net.Network = specgen.Namespace{NSMode: "host"}
}
if podYAML.Spec.HostAliases != nil {
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)
}
}
p.HostAdd = hosts
p.Net.AddHosts = hosts
}
podPorts := getPodPorts(podYAML.Spec.Containers)
p.PortMappings = podPorts
p.Net.PublishPorts = podPorts
if dnsConfig := podYAML.Spec.DNSConfig; dnsConfig != nil {
// name servers
@ -62,11 +64,11 @@ func ToPodGen(ctx context.Context, podName string, podYAML *v1.PodTemplateSpec)
for _, server := range dnsServers {
servers = append(servers, net.ParseIP(server))
}
p.DNSServer = servers
p.Net.DNSServers = servers
}
// search domains
if domains := dnsConfig.Searches; len(domains) > 0 {
p.DNSSearch = domains
p.Net.DNSSearch = domains
}
// dns options
if options := dnsConfig.Options; len(options) > 0 {
@ -110,6 +112,8 @@ type CtrSpecGenOptions struct {
LogDriver string
// Labels define key-value pairs of metadata
Labels map[string]string
//
IsInfra bool
}
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 len(opts.Container.Command) != 0 {
if !opts.IsInfra && len(opts.Container.Command) != 0 {
s.Entrypoint = opts.Container.Command
s.Command = []string{}
}
// Only override the cmd field if yaml.Args is 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
}
// FIXME,
// we are currently ignoring imageData.Config.ExposedPorts
if opts.Container.WorkingDir != "" {
if !opts.IsInfra && 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 != "" {
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:
fallthrough
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"},
}
g.AddMount(sysMnt)
} else if !canMountSys {
}
if !canMountSys {
addCgroup = false
g.RemoveMount("/sys")
r := "ro"

View File

@ -2,53 +2,82 @@ package generate
import (
"context"
"net"
"github.com/containers/common/pkg/config"
"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/specgen"
"github.com/pkg/errors"
"github.com/sirupsen/logrus"
)
func MakePod(p *specgen.PodSpecGenerator, rt *libpod.Runtime) (*libpod.Pod, error) {
if err := p.Validate(); err != nil {
func MakePod(p *entities.PodSpec, rt *libpod.Runtime) (*libpod.Pod, error) {
if err := p.PodSpecGen.Validate(); err != nil {
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 {
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 (
options []libpod.PodCreateOption
)
if !p.NoInfra {
if !p.NoInfra { //&& infraSpec != nil {
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 {
return nil, err
}
options = append(options, nsOptions...)
// 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.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 {
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 {
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.ResourceLimits.CPU.Period != 0 || *p.ResourceLimits.CPU.Quota != 0 {
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 p.PodCreateCommand != nil {
options = append(options, libpod.WithPodCreateCommand(p.PodCreateCommand))
}
if len(p.Hostname) > 0 {
options = append(options, libpod.WithPodHostname(p.Hostname))
}
if len(p.HostAdd) > 0 {
options = append(options, libpod.WithPodHosts(p.HostAdd))
}
if len(p.DNSServer) > 0 {
var dnsServers []string
for _, d := range p.DNSServer {
dnsServers = append(dnsServers, d.String())
return options, nil
}
// MapSpec modifies the already filled Infra specgenerator,
// replacing necessary values with those specified in pod creation
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 {
case specgen.Default, "":
if p.NoInfra {
@ -123,42 +117,88 @@ func createPodOptions(p *specgen.PodSpecGenerator, rt *libpod.Runtime) ([]libpod
}
if rootless.IsRootless() {
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 {
logrus.Debugf("Pod using bridge network mode")
}
case specgen.Bridge:
p.InfraContainerSpec.NetNS.NSMode = specgen.Bridge
logrus.Debugf("Pod using bridge network mode")
case specgen.Host:
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:
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:
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:
return nil, errors.Errorf("pods presently do not support network mode %s", p.NetNS.NSMode)
}
if p.NoManageHosts {
options = append(options, libpod.WithPodUseImageHosts())
}
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))
libpod.WithPodCgroups()
if len(p.InfraCommand) > 0 {
p.InfraContainerSpec.Entrypoint = p.InfraCommand
}
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
// 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
Pid Namespace `json:"pid,omitempty:"`
Pid Namespace `json:"pidns,omitempty"`
// Userns is used to indicate which kind of Usernamespace to enter.
// Any containers created within the pod will inherit the pod's userns settings.
// Optional
@ -173,6 +173,7 @@ type PodSpecGenerator struct {
PodNetworkConfig
PodCgroupConfig
PodResourceConfig
InfraContainerSpec *SpecGenerator `json:"-"`
}
type PodResourceConfig struct {

View File

@ -1,13 +1,14 @@
package common
package specgenutil
import (
"github.com/containers/common/pkg/config"
"github.com/containers/podman/v3/pkg/domain/entities"
"github.com/pkg/errors"
)
// 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)
func (c *ContainerCLIOpts) validate() error {
func validate(c *entities.ContainerCreateOptions) error {
var ()
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"`)
@ -23,7 +24,11 @@ func (c *ContainerCLIOpts) validate() error {
"ignore": "",
}
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
}

View File

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

View File

@ -1,6 +1,7 @@
package common
package specgenutil
import (
"encoding/json"
"fmt"
"os"
"strconv"
@ -11,8 +12,9 @@ import (
"github.com/containers/podman/v3/cmd/podman/parse"
"github.com/containers/podman/v3/libpod/define"
ann "github.com/containers/podman/v3/pkg/annotations"
"github.com/containers/podman/v3/pkg/domain/entities"
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"
systemdDefine "github.com/containers/podman/v3/pkg/systemd/define"
"github.com/containers/podman/v3/pkg/util"
@ -21,7 +23,7 @@ import (
"github.com/pkg/errors"
)
func getCPULimits(c *ContainerCLIOpts) *specs.LinuxCPU {
func getCPULimits(c *entities.ContainerCreateOptions) *specs.LinuxCPU {
cpu := &specs.LinuxCPU{}
hasLimits := false
@ -67,7 +69,7 @@ func getCPULimits(c *ContainerCLIOpts) *specs.LinuxCPU {
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
io := &specs.LinuxBlockIO{}
hasLimits := false
@ -122,7 +124,7 @@ func getIOLimits(s *specgen.SpecGenerator, c *ContainerCLIOpts) (*specs.LinuxBlo
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
memory := &specs.LinuxMemory{}
hasLimits := false
@ -167,7 +169,7 @@ func getMemoryLimits(s *specgen.SpecGenerator, c *ContainerCLIOpts) (*specs.Linu
memory.Kernel = &mk
hasLimits = true
}
if c.MemorySwappiness >= 0 {
if c.MemorySwappiness > 0 {
swappiness := uint64(c.MemorySwappiness)
memory.Swappiness = &swappiness
hasLimits = true
@ -182,7 +184,7 @@ func getMemoryLimits(s *specgen.SpecGenerator, c *ContainerCLIOpts) (*specs.Linu
return memory, nil
}
func setNamespaces(s *specgen.SpecGenerator, c *ContainerCLIOpts) error {
func setNamespaces(s *specgen.SpecGenerator, c *entities.ContainerCreateOptions) error {
var err error
if c.PID != "" {
@ -222,18 +224,22 @@ func setNamespaces(s *specgen.SpecGenerator, c *ContainerCLIOpts) error {
return nil
}
func FillOutSpecGen(s *specgen.SpecGenerator, c *ContainerCLIOpts, args []string) error {
func FillOutSpecGen(s *specgen.SpecGenerator, c *entities.ContainerCreateOptions, args []string) error {
var (
err error
)
// validate flags as needed
if err := c.validate(); err != nil {
if err := validate(c); err != nil {
return err
}
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 c.NoHealthCheck {
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"},
}
}
userNS := ns.UsernsMode(c.UserNS)
if err := setNamespaces(s, c); err != nil {
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)
if err != nil {
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 userNS.IsDefaultValue() && (!s.IDMappings.HostUIDMapping || !s.IDMappings.HostGIDMapping) {
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.
// s.PortsExpose = c.Expose
s.PortMappings = c.Net.PublishPorts
if c.Net != nil {
s.PortMappings = c.Net.PublishPorts
}
s.PublishExposedPorts = c.PublishAll
s.Pod = c.Pod
@ -288,10 +317,6 @@ func FillOutSpecGen(s *specgen.SpecGenerator, c *ContainerCLIOpts, args []string
}
s.Expose = expose
if err := setNamespaces(s, c); err != nil {
return err
}
if sig := c.StopSignal; len(sig) > 0 {
stopSignal, err := util.ParseSignal(sig)
if err != nil {
@ -380,6 +405,7 @@ func FillOutSpecGen(s *specgen.SpecGenerator, c *ContainerCLIOpts, args []string
}
// Include the command used to create the container.
s.ContainerCreateCommand = os.Args
if len(inputCommand) > 0 {
@ -394,28 +420,34 @@ func FillOutSpecGen(s *specgen.SpecGenerator, c *ContainerCLIOpts, args []string
}
s.ShmSize = &shmSize
}
s.CNINetworks = c.Net.CNINetworks
// Network aliases
if len(c.Net.Aliases) > 0 {
// 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
if c.Net != nil {
s.CNINetworks = c.Net.CNINetworks
}
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
// Network aliases
if c.Net != nil {
if len(c.Net.Aliases) > 0 {
// 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
}
}
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
if s.ImageVolumeMode == "bind" {
s.ImageVolumeMode = "anonymous"

View File

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

View File

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

View File

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