diff options
-rw-r--r-- | cmd/podman/common/create.go | 17 | ||||
-rw-r--r-- | cmd/podman/play/kube.go | 1 | ||||
-rw-r--r-- | cmd/podman/pods/create.go | 14 | ||||
-rw-r--r-- | docs/source/markdown/podman-play-kube.1.md | 4 | ||||
-rw-r--r-- | docs/source/markdown/podman-pod-create.1.md | 6 | ||||
-rw-r--r-- | libpod/container_inspect.go | 56 | ||||
-rw-r--r-- | libpod/define/pod_inspect.go | 2 | ||||
-rw-r--r-- | libpod/pod_api.go | 54 | ||||
-rw-r--r-- | pkg/api/handlers/libpod/play.go | 2 | ||||
-rw-r--r-- | pkg/bindings/play/play.go | 3 | ||||
-rw-r--r-- | pkg/bindings/play/types.go | 2 | ||||
-rw-r--r-- | pkg/bindings/play/types_kube_options.go | 15 | ||||
-rw-r--r-- | pkg/domain/entities/play.go | 3 | ||||
-rw-r--r-- | pkg/domain/entities/pods.go | 5 | ||||
-rw-r--r-- | pkg/domain/infra/abi/play.go | 2 | ||||
-rw-r--r-- | pkg/domain/infra/tunnel/play.go | 2 | ||||
-rw-r--r-- | pkg/specgen/generate/container.go | 52 | ||||
-rw-r--r-- | pkg/specgen/generate/container_create.go | 38 | ||||
-rw-r--r-- | pkg/specgen/generate/kube/kube.go | 7 | ||||
-rw-r--r-- | pkg/specgen/podspecgen.go | 2 | ||||
-rw-r--r-- | pkg/specgen/specgen.go | 16 | ||||
-rw-r--r-- | test/e2e/play_kube_test.go | 43 | ||||
-rw-r--r-- | test/e2e/pod_create_test.go | 21 |
23 files changed, 273 insertions, 94 deletions
diff --git a/cmd/podman/common/create.go b/cmd/podman/common/create.go index e490fa121..e714b6785 100644 --- a/cmd/podman/common/create.go +++ b/cmd/podman/common/create.go @@ -164,14 +164,6 @@ func DefineCreateFlags(cmd *cobra.Command, cf *entities.ContainerCreateOptions, ) _ = cmd.RegisterFlagCompletionFunc(deviceCgroupRuleFlagName, completion.AutocompleteNone) - deviceReadBpsFlagName := "device-read-bps" - createFlags.StringSliceVar( - &cf.DeviceReadBPs, - deviceReadBpsFlagName, []string{}, - "Limit read rate (bytes per second) from a device (e.g. --device-read-bps=/dev/sda:1mb)", - ) - _ = cmd.RegisterFlagCompletionFunc(deviceReadBpsFlagName, completion.AutocompleteDefault) - deviceReadIopsFlagName := "device-read-iops" createFlags.StringSliceVar( &cf.DeviceReadIOPs, @@ -869,6 +861,7 @@ func DefineCreateFlags(cmd *cobra.Command, cf *entities.ContainerCreateOptions, volumeDesciption, ) _ = cmd.RegisterFlagCompletionFunc(volumeFlagName, AutocompleteVolumeFlag) + deviceFlagName := "device" createFlags.StringSliceVar( &cf.Devices, @@ -876,4 +869,12 @@ func DefineCreateFlags(cmd *cobra.Command, cf *entities.ContainerCreateOptions, "Add a host device to the container", ) _ = cmd.RegisterFlagCompletionFunc(deviceFlagName, completion.AutocompleteDefault) + + deviceReadBpsFlagName := "device-read-bps" + createFlags.StringSliceVar( + &cf.DeviceReadBPs, + deviceReadBpsFlagName, []string{}, + "Limit read rate (bytes per second) from a device (e.g. --device-read-bps=/dev/sda:1mb)", + ) + _ = cmd.RegisterFlagCompletionFunc(deviceReadBpsFlagName, completion.AutocompleteDefault) } diff --git a/cmd/podman/play/kube.go b/cmd/podman/play/kube.go index 9308371d2..85e0c279c 100644 --- a/cmd/podman/play/kube.go +++ b/cmd/podman/play/kube.go @@ -78,6 +78,7 @@ func init() { flags.StringVar(&kubeOptions.LogDriver, logDriverFlagName, "", "Logging driver for the container") _ = kubeCmd.RegisterFlagCompletionFunc(logDriverFlagName, common.AutocompleteLogDriver) + flags.BoolVar(&kubeOptions.NoHosts, "no-hosts", false, "Do not create /etc/hosts within the pod's containers, instead use the version from the image") flags.BoolVarP(&kubeOptions.Quiet, "quiet", "q", false, "Suppress output information when pulling images") flags.BoolVar(&kubeOptions.TLSVerifyCLI, "tls-verify", true, "Require HTTPS and verify certificates when contacting registries") flags.BoolVar(&kubeOptions.StartCLI, "start", true, "Start the pod after creating it") diff --git a/cmd/podman/pods/create.go b/cmd/podman/pods/create.go index ca73a8356..d5aaf09ce 100644 --- a/cmd/podman/pods/create.go +++ b/cmd/podman/pods/create.go @@ -101,6 +101,7 @@ func create(cmd *cobra.Command, args []string) error { podIDFD *os.File imageName string rawImageName string + podName string ) labelFile = infraOptions.LabelFile labels = infraOptions.Label @@ -158,10 +159,12 @@ func create(cmd *cobra.Command, args []string) error { return err } } + podName = createOptions.Name err = common.ContainerToPodOptions(&infraOptions, &createOptions) if err != nil { return err } + createOptions.Name = podName } if cmd.Flag("pod-id-file").Changed { @@ -264,6 +267,17 @@ func create(cmd *cobra.Command, args []string) error { podSpec.ImageVolumes = podSpec.InfraContainerSpec.ImageVolumes podSpec.OverlayVolumes = podSpec.InfraContainerSpec.OverlayVolumes podSpec.Mounts = podSpec.InfraContainerSpec.Mounts + + // Marshall and Unmarshal the spec in order to map similar entities + wrapped, err := json.Marshal(podSpec.InfraContainerSpec) + if err != nil { + return err + } + err = json.Unmarshal(wrapped, podSpec) + if err != nil { + return err + } + podSpec.Name = podName } PodSpec := entities.PodSpec{PodSpecGen: *podSpec} response, err := registry.ContainerEngine().PodCreate(context.Background(), PodSpec) diff --git a/docs/source/markdown/podman-play-kube.1.md b/docs/source/markdown/podman-play-kube.1.md index 7e3e0f431..a4b9722b8 100644 --- a/docs/source/markdown/podman-play-kube.1.md +++ b/docs/source/markdown/podman-play-kube.1.md @@ -138,6 +138,10 @@ Valid _mode_ values are: Note: Rootlesskit changes the source IP address of incoming packets to a IP address in the container network namespace, usually `10.0.2.100`. If your application requires the real source IP address, e.g. web server logs, use the slirp4netns port handler. The rootlesskit port handler is also used for rootless containers when connected to user-defined networks. - **port_handler=slirp4netns**: Use the slirp4netns port forwarding, it is slower than rootlesskit but preserves the correct source IP address. This port handler cannot be used for user-defined networks. +#### **--no-hosts** + +Do not create /etc/hosts within the pod's containers, instead use the version from the image + #### **--quiet**, **-q** Suppress output information when pulling images diff --git a/docs/source/markdown/podman-pod-create.1.md b/docs/source/markdown/podman-pod-create.1.md index fcb8ddeb9..4c36c66ca 100644 --- a/docs/source/markdown/podman-pod-create.1.md +++ b/docs/source/markdown/podman-pod-create.1.md @@ -41,7 +41,7 @@ Examples of the List Format: #### **--device**=_host-device_[**:**_container-device_][**:**_permissions_] Add a host device to the pod. Optional *permissions* parameter -can be used to specify device permissions It is a combination of +can be used to specify device permissions. It is a combination of **r** for read, **w** for write, and **m** for **mknod**(2). Example: **--device=/dev/sdc:/dev/xvdc:rwm**. @@ -55,6 +55,10 @@ Podman may load kernel modules required for using the specified device. The devices that Podman will load modules for when necessary are: /dev/fuse. +#### **--device-read-bps**=*path* + +Limit read rate (bytes per second) from a device (e.g. --device-read-bps=/dev/sda:1mb) + #### **--dns**=*ipaddr* Set custom DNS servers in the /etc/resolv.conf file that will be shared between all containers in the pod. A special option, "none" is allowed which disables creation of /etc/resolv.conf for the pod. diff --git a/libpod/container_inspect.go b/libpod/container_inspect.go index ab79d82d9..277c3b960 100644 --- a/libpod/container_inspect.go +++ b/libpod/container_inspect.go @@ -531,49 +531,25 @@ func (c *Container) generateInspectContainerHostConfig(ctrSpec *spec.Spec, named hostConfig.BlkioWeightDevice = append(hostConfig.BlkioWeightDevice, weightDev) } - handleThrottleDevice := func(devs []spec.LinuxThrottleDevice) ([]define.InspectBlkioThrottleDevice, error) { - out := []define.InspectBlkioThrottleDevice{} - for _, dev := range devs { - key := fmt.Sprintf("%d:%d", dev.Major, dev.Minor) - if deviceNodes == nil { - nodes, err := util.FindDeviceNodes() - if err != nil { - return nil, err - } - deviceNodes = nodes - } - path, ok := deviceNodes[key] - if !ok { - logrus.Infof("Could not locate throttle device %s in system devices", key) - continue - } - throttleDev := define.InspectBlkioThrottleDevice{} - throttleDev.Path = path - throttleDev.Rate = dev.Rate - out = append(out, throttleDev) - } - return out, nil - } - - readBps, err := handleThrottleDevice(ctrSpec.Linux.Resources.BlockIO.ThrottleReadBpsDevice) + readBps, err := blkioDeviceThrottle(deviceNodes, ctrSpec.Linux.Resources.BlockIO.ThrottleReadBpsDevice) if err != nil { return nil, err } hostConfig.BlkioDeviceReadBps = readBps - writeBps, err := handleThrottleDevice(ctrSpec.Linux.Resources.BlockIO.ThrottleWriteBpsDevice) + writeBps, err := blkioDeviceThrottle(deviceNodes, ctrSpec.Linux.Resources.BlockIO.ThrottleWriteBpsDevice) if err != nil { return nil, err } hostConfig.BlkioDeviceWriteBps = writeBps - readIops, err := handleThrottleDevice(ctrSpec.Linux.Resources.BlockIO.ThrottleReadIOPSDevice) + readIops, err := blkioDeviceThrottle(deviceNodes, ctrSpec.Linux.Resources.BlockIO.ThrottleReadIOPSDevice) if err != nil { return nil, err } hostConfig.BlkioDeviceReadIOps = readIops - writeIops, err := handleThrottleDevice(ctrSpec.Linux.Resources.BlockIO.ThrottleWriteIOPSDevice) + writeIops, err := blkioDeviceThrottle(deviceNodes, ctrSpec.Linux.Resources.BlockIO.ThrottleWriteIOPSDevice) if err != nil { return nil, err } @@ -894,3 +870,27 @@ func (c *Container) GetDevices(priv bool, ctrSpec spec.Spec, deviceNodes map[str } return devices, nil } + +func blkioDeviceThrottle(deviceNodes map[string]string, devs []spec.LinuxThrottleDevice) ([]define.InspectBlkioThrottleDevice, error) { + out := []define.InspectBlkioThrottleDevice{} + for _, dev := range devs { + key := fmt.Sprintf("%d:%d", dev.Major, dev.Minor) + if deviceNodes == nil { + nodes, err := util.FindDeviceNodes() + if err != nil { + return nil, err + } + deviceNodes = nodes + } + path, ok := deviceNodes[key] + if !ok { + logrus.Infof("Could not locate throttle device %s in system devices", key) + continue + } + throttleDev := define.InspectBlkioThrottleDevice{} + throttleDev.Path = path + throttleDev.Rate = dev.Rate + out = append(out, throttleDev) + } + return out, nil +} diff --git a/libpod/define/pod_inspect.go b/libpod/define/pod_inspect.go index e78d97850..bc2c1d81f 100644 --- a/libpod/define/pod_inspect.go +++ b/libpod/define/pod_inspect.go @@ -61,6 +61,8 @@ type InspectPodData struct { Mounts []InspectMount `json:"mounts,omitempty"` // Devices contains the specified host devices Devices []InspectDevice `json:"devices,omitempty"` + // BlkioDeviceReadBps contains the Read/Access limit for the pod's devices + BlkioDeviceReadBps []InspectBlkioThrottleDevice `json:"device_read_bps,omitempty"` } // InspectPodInfraConfig contains the configuration of the pod's infra diff --git a/libpod/pod_api.go b/libpod/pod_api.go index 971309f77..05349aff5 100644 --- a/libpod/pod_api.go +++ b/libpod/pod_api.go @@ -584,6 +584,7 @@ func (p *Pod) Inspect() (*define.InspectPodData, error) { var infraConfig *define.InspectPodInfraConfig var inspectMounts []define.InspectMount var devices []define.InspectDevice + var deviceLimits []define.InspectBlkioThrottleDevice if p.state.InfraContainerID != "" { infra, err := p.runtime.GetContainer(p.state.InfraContainerID) if err != nil { @@ -604,12 +605,18 @@ func (p *Pod) Inspect() (*define.InspectPodData, error) { if err != nil { return nil, err } - var nodes map[string]string devices, err = infra.GetDevices(false, *infra.config.Spec, nodes) if err != nil { return nil, err } + spec := infra.config.Spec + if spec.Linux != nil && spec.Linux.Resources != nil && spec.Linux.Resources.BlockIO != nil { + deviceLimits, err = blkioDeviceThrottle(nodes, spec.Linux.Resources.BlockIO.ThrottleReadBpsDevice) + if err != nil { + return nil, err + } + } if len(infra.config.ContainerNetworkConfig.DNSServer) > 0 { infraConfig.DNSServer = make([]string, 0, len(infra.config.ContainerNetworkConfig.DNSServer)) @@ -638,28 +645,29 @@ func (p *Pod) Inspect() (*define.InspectPodData, error) { } inspectData := define.InspectPodData{ - ID: p.ID(), - Name: p.Name(), - Namespace: p.Namespace(), - Created: p.CreatedTime(), - CreateCommand: p.config.CreateCommand, - State: podState, - Hostname: p.config.Hostname, - Labels: p.Labels(), - CreateCgroup: p.config.UsePodCgroup, - CgroupParent: p.CgroupParent(), - CgroupPath: p.state.CgroupPath, - CreateInfra: infraConfig != nil, - InfraContainerID: p.state.InfraContainerID, - InfraConfig: infraConfig, - SharedNamespaces: sharesNS, - NumContainers: uint(len(containers)), - Containers: ctrs, - CPUSetCPUs: p.ResourceLim().CPU.Cpus, - CPUPeriod: p.CPUPeriod(), - CPUQuota: p.CPUQuota(), - Mounts: inspectMounts, - Devices: devices, + ID: p.ID(), + Name: p.Name(), + Namespace: p.Namespace(), + Created: p.CreatedTime(), + CreateCommand: p.config.CreateCommand, + State: podState, + Hostname: p.config.Hostname, + Labels: p.Labels(), + CreateCgroup: p.config.UsePodCgroup, + CgroupParent: p.CgroupParent(), + CgroupPath: p.state.CgroupPath, + CreateInfra: infraConfig != nil, + InfraContainerID: p.state.InfraContainerID, + InfraConfig: infraConfig, + SharedNamespaces: sharesNS, + NumContainers: uint(len(containers)), + Containers: ctrs, + CPUSetCPUs: p.ResourceLim().CPU.Cpus, + CPUPeriod: p.CPUPeriod(), + CPUQuota: p.CPUQuota(), + Mounts: inspectMounts, + Devices: devices, + BlkioDeviceReadBps: deviceLimits, } return &inspectData, nil diff --git a/pkg/api/handlers/libpod/play.go b/pkg/api/handlers/libpod/play.go index 0def32821..851e0f6c8 100644 --- a/pkg/api/handlers/libpod/play.go +++ b/pkg/api/handlers/libpod/play.go @@ -29,6 +29,7 @@ func PlayKube(w http.ResponseWriter, r *http.Request) { Start bool `schema:"start"` StaticIPs []string `schema:"staticIPs"` StaticMACs []string `schema:"staticMACs"` + NoHosts bool `schema:"noHosts"` }{ TLSVerify: true, Start: true, @@ -102,6 +103,7 @@ func PlayKube(w http.ResponseWriter, r *http.Request) { Username: username, Password: password, Network: query.Network, + NoHosts: query.NoHosts, Quiet: true, LogDriver: query.LogDriver, StaticIPs: staticIPs, diff --git a/pkg/bindings/play/play.go b/pkg/bindings/play/play.go index 89a6f9b65..bdd13d03d 100644 --- a/pkg/bindings/play/play.go +++ b/pkg/bindings/play/play.go @@ -6,11 +6,10 @@ import ( "os" "strconv" - "github.com/sirupsen/logrus" - "github.com/containers/podman/v3/pkg/auth" "github.com/containers/podman/v3/pkg/bindings" "github.com/containers/podman/v3/pkg/domain/entities" + "github.com/sirupsen/logrus" ) func Kube(ctx context.Context, path string, options *KubeOptions) (*entities.PlayKubeReport, error) { diff --git a/pkg/bindings/play/types.go b/pkg/bindings/play/types.go index 787069169..fdfc4a6fa 100644 --- a/pkg/bindings/play/types.go +++ b/pkg/bindings/play/types.go @@ -17,6 +17,8 @@ type KubeOptions struct { Password *string // Network - name of the CNI network to connect to. Network *string + // NoHosts - do not generate /etc/hosts file in pod's containers + NoHosts *bool // Quiet - suppress output when pulling images. Quiet *bool // SignaturePolicy - path to a signature-policy file. diff --git a/pkg/bindings/play/types_kube_options.go b/pkg/bindings/play/types_kube_options.go index 65757cc5e..1a6324302 100644 --- a/pkg/bindings/play/types_kube_options.go +++ b/pkg/bindings/play/types_kube_options.go @@ -93,6 +93,21 @@ func (o *KubeOptions) GetNetwork() string { return *o.Network } +// WithNoHosts set field NoHosts to given value +func (o *KubeOptions) WithNoHosts(value bool) *KubeOptions { + o.NoHosts = &value + return o +} + +// GetNoHosts returns value of field NoHosts +func (o *KubeOptions) GetNoHosts() bool { + if o.NoHosts == nil { + var z bool + return z + } + return *o.NoHosts +} + // WithQuiet set field Quiet to given value func (o *KubeOptions) WithQuiet(value bool) *KubeOptions { o.Quiet = &value diff --git a/pkg/domain/entities/play.go b/pkg/domain/entities/play.go index f630b3f24..af4b0fc35 100644 --- a/pkg/domain/entities/play.go +++ b/pkg/domain/entities/play.go @@ -17,6 +17,9 @@ type PlayKubeOptions struct { // Down indicates whether to bring contents of a yaml file "down" // as in stop Down bool + // Do not create /etc/hosts within the pod's containers, + // instead use the version from the image + NoHosts bool // Username for authenticating against the registry. Username string // Password for authenticating against the registry. diff --git a/pkg/domain/entities/pods.go b/pkg/domain/entities/pods.go index f0c88d77e..0356383ec 100644 --- a/pkg/domain/entities/pods.go +++ b/pkg/domain/entities/pods.go @@ -119,6 +119,7 @@ type PodCreateOptions struct { CGroupParent string `json:"cgroup_parent,omitempty"` CreateCommand []string `json:"create_command,omitempty"` Devices []string `json:"devices,omitempty"` + DeviceReadBPs []string `json:"device_read_bps,omitempty"` Hostname string `json:"hostname,omitempty"` Infra bool `json:"infra,omitempty"` InfraImage string `json:"infra_image,omitempty"` @@ -167,7 +168,7 @@ type ContainerCreateOptions struct { CPUSetMems string Devices []string `json:"devices,omitempty"` DeviceCGroupRule []string - DeviceReadBPs []string + DeviceReadBPs []string `json:"device_read_bps,omitempty"` DeviceReadIOPs []string DeviceWriteBPs []string DeviceWriteIOPs []string @@ -200,7 +201,7 @@ type ContainerCreateOptions struct { MemoryReservation string MemorySwap string MemorySwappiness int64 - Name string `json:"container_name,omitempty"` + Name string `json:"container_name"` NoHealthCheck bool OOMKillDisable bool OOMScoreAdj int diff --git a/pkg/domain/infra/abi/play.go b/pkg/domain/infra/abi/play.go index cf72a6253..751d6cc05 100644 --- a/pkg/domain/infra/abi/play.go +++ b/pkg/domain/infra/abi/play.go @@ -181,7 +181,7 @@ func (ic *ContainerEngine) playKubePod(ctx context.Context, podName string, podY } } - podOpt := entities.PodCreateOptions{Infra: true, Net: &entities.NetOptions{StaticIP: &net.IP{}, StaticMAC: &net.HardwareAddr{}}} + podOpt := entities.PodCreateOptions{Infra: true, Net: &entities.NetOptions{StaticIP: &net.IP{}, StaticMAC: &net.HardwareAddr{}, NoHosts: options.NoHosts}} podOpt, err = kube.ToPodOpt(ctx, podName, podOpt, podYAML) if err != nil { return nil, err diff --git a/pkg/domain/infra/tunnel/play.go b/pkg/domain/infra/tunnel/play.go index e39751a18..0b1c3d2ca 100644 --- a/pkg/domain/infra/tunnel/play.go +++ b/pkg/domain/infra/tunnel/play.go @@ -13,7 +13,7 @@ func (ic *ContainerEngine) PlayKube(ctx context.Context, path string, opts entit options.WithCertDir(opts.CertDir).WithQuiet(opts.Quiet).WithSignaturePolicy(opts.SignaturePolicy).WithConfigMaps(opts.ConfigMaps) options.WithLogDriver(opts.LogDriver).WithNetwork(opts.Network).WithSeccompProfileRoot(opts.SeccompProfileRoot) options.WithStaticIPs(opts.StaticIPs).WithStaticMACs(opts.StaticMACs) - + options.WithNoHosts(opts.NoHosts) if s := opts.SkipTLSVerify; s != types.OptionalBoolUndefined { options.WithSkipTLSVerify(s == types.OptionalBoolTrue) } diff --git a/pkg/specgen/generate/container.go b/pkg/specgen/generate/container.go index 71b882510..f126aa018 100644 --- a/pkg/specgen/generate/container.go +++ b/pkg/specgen/generate/container.go @@ -18,19 +18,43 @@ import ( "golang.org/x/sys/unix" ) +func getImageFromSpec(ctx context.Context, r *libpod.Runtime, s *specgen.SpecGenerator) (*libimage.Image, string, *libimage.ImageData, error) { + if s.Image == "" || s.Rootfs != "" { + return nil, "", nil, nil + } + + // Image may already have been set in the generator. + image, resolvedName := s.GetImage() + if image != nil { + inspectData, err := image.Inspect(ctx, false) + if err != nil { + return nil, "", nil, err + } + return image, resolvedName, inspectData, nil + } + + // Need to look up image. + image, resolvedName, err := r.LibimageRuntime().LookupImage(s.Image, nil) + if err != nil { + return nil, "", nil, err + } + s.SetImage(image, resolvedName) + inspectData, err := image.Inspect(ctx, false) + if err != nil { + return nil, "", nil, err + } + return image, resolvedName, inspectData, err +} + // Fill any missing parts of the spec generator (e.g. from the image). // Returns a set of warnings or any fatal error that occurred. func CompleteSpec(ctx context.Context, r *libpod.Runtime, s *specgen.SpecGenerator) ([]string, error) { // Only add image configuration if we have an image - var newImage *libimage.Image - var inspectData *libimage.ImageData - var err error - if s.Image != "" { - newImage, _, err = r.LibimageRuntime().LookupImage(s.Image, nil) - if err != nil { - return nil, err - } - + newImage, _, inspectData, err := getImageFromSpec(ctx, r, s) + if err != nil { + return nil, err + } + if inspectData != nil { inspectData, err = newImage.Inspect(ctx, false) if err != nil { return nil, err @@ -191,9 +215,6 @@ func CompleteSpec(ctx context.Context, r *libpod.Runtime, s *specgen.SpecGenerat if len(s.User) == 0 && inspectData != nil { s.User = inspectData.Config.User } - if err := finishThrottleDevices(s); err != nil { - return nil, err - } // Unless already set via the CLI, check if we need to disable process // labels or set the defaults. if len(s.SelinuxOpts) == 0 { @@ -251,10 +272,10 @@ func CompleteSpec(ctx context.Context, r *libpod.Runtime, s *specgen.SpecGenerat return warnings, nil } -// finishThrottleDevices takes the temporary representation of the throttle +// FinishThrottleDevices takes the temporary representation of the throttle // devices in the specgen and looks up the major and major minors. it then // sets the throttle devices proper in the specgen -func finishThrottleDevices(s *specgen.SpecGenerator) error { +func FinishThrottleDevices(s *specgen.SpecGenerator) error { if bps := s.ThrottleReadBpsDevice; len(bps) > 0 { for k, v := range bps { statT := unix.Stat_t{} @@ -263,6 +284,9 @@ func finishThrottleDevices(s *specgen.SpecGenerator) error { } v.Major = (int64(unix.Major(uint64(statT.Rdev)))) v.Minor = (int64(unix.Minor(uint64(statT.Rdev)))) + if s.ResourceLimits.BlockIO == nil { + s.ResourceLimits.BlockIO = new(spec.LinuxBlockIO) + } s.ResourceLimits.BlockIO.ThrottleReadBpsDevice = append(s.ResourceLimits.BlockIO.ThrottleReadBpsDevice, v) } } diff --git a/pkg/specgen/generate/container_create.go b/pkg/specgen/generate/container_create.go index 6100e7a5b..92c0f22d9 100644 --- a/pkg/specgen/generate/container_create.go +++ b/pkg/specgen/generate/container_create.go @@ -2,6 +2,7 @@ package generate import ( "context" + "fmt" "os" "path/filepath" "strings" @@ -52,6 +53,24 @@ func MakeContainer(ctx context.Context, rt *libpod.Runtime, s *specgen.SpecGener if infraConfig != nil && len(infraConfig.Spec.Linux.Devices) > 0 { s.DevicesFrom = append(s.DevicesFrom, infraConfig.ID) } + if infraConfig != nil && infraConfig.Spec.Linux.Resources != nil && infraConfig.Spec.Linux.Resources.BlockIO != nil && len(infraConfig.Spec.Linux.Resources.BlockIO.ThrottleReadBpsDevice) > 0 { + tempDev := make(map[string]spec.LinuxThrottleDevice) + for _, val := range infraConfig.Spec.Linux.Resources.BlockIO.ThrottleReadBpsDevice { + nodes, err := util.FindDeviceNodes() + if err != nil { + return nil, nil, nil, err + } + key := fmt.Sprintf("%d:%d", val.Major, val.Minor) + tempDev[nodes[key]] = spec.LinuxThrottleDevice{Rate: uint64(val.Rate)} + } + for i, dev := range s.ThrottleReadBpsDevice { + tempDev[i] = dev + } + s.ThrottleReadBpsDevice = tempDev + } + if err := FinishThrottleDevices(s); err != nil { + return nil, nil, nil, err + } // Set defaults for unset namespaces if s.PidNS.IsDefault() { defaultNS, err := GetDefaultNamespaceMode("pid", rtc, pod) @@ -102,20 +121,15 @@ func MakeContainer(ctx context.Context, rt *libpod.Runtime, s *specgen.SpecGener options = append(options, libpod.WithCreateCommand(s.ContainerCreateCommand)) } - var newImage *libimage.Image - var imageData *libimage.ImageData if s.Rootfs != "" { options = append(options, libpod.WithRootFS(s.Rootfs, s.RootfsOverlay)) - } else { - var resolvedImageName string - newImage, resolvedImageName, err = rt.LibimageRuntime().LookupImage(s.Image, nil) - if err != nil { - return nil, nil, nil, err - } - imageData, err = newImage.Inspect(ctx, false) - if err != nil { - return nil, nil, nil, err - } + } + + newImage, resolvedImageName, imageData, err := getImageFromSpec(ctx, rt, s) + if err != nil { + return nil, nil, nil, err + } + if newImage != nil { // If the input name changed, we could properly resolve the // image. Otherwise, it must have been an ID where we're // defaulting to the first name or an empty one if no names are diff --git a/pkg/specgen/generate/kube/kube.go b/pkg/specgen/generate/kube/kube.go index 9389b1a20..194c8dce5 100644 --- a/pkg/specgen/generate/kube/kube.go +++ b/pkg/specgen/generate/kube/kube.go @@ -26,8 +26,8 @@ import ( ) func ToPodOpt(ctx context.Context, podName string, p entities.PodCreateOptions, podYAML *v1.PodTemplateSpec) (entities.PodCreateOptions, error) { - // p := specgen.NewPodSpecGenerator() - p.Net = &entities.NetOptions{} + p.Net = &entities.NetOptions{NoHosts: p.Net.NoHosts} + p.Name = podName p.Labels = podYAML.ObjectMeta.Labels // Kube pods must share {ipc, net, uts} by default @@ -47,6 +47,9 @@ func ToPodOpt(ctx context.Context, podName string, p entities.PodCreateOptions, p.Net.Network = specgen.Namespace{NSMode: "host"} } if podYAML.Spec.HostAliases != nil { + if p.Net.NoHosts { + return p, errors.New("HostAliases in yaml file will not work with --no-hosts") + } hosts := make([]string, 0, len(podYAML.Spec.HostAliases)) for _, hostAlias := range podYAML.Spec.HostAliases { for _, host := range hostAlias.Hostnames { diff --git a/pkg/specgen/podspecgen.go b/pkg/specgen/podspecgen.go index 83fa9426c..ee4fbc13a 100644 --- a/pkg/specgen/podspecgen.go +++ b/pkg/specgen/podspecgen.go @@ -201,6 +201,8 @@ type PodResourceConfig struct { CPUPeriod uint64 `json:"cpu_period,omitempty"` // CPU quota of the cpuset, determined by --cpus CPUQuota int64 `json:"cpu_quota,omitempty"` + // ThrottleReadBpsDevice contains the rate at which the devices in the pod can be read from/accessed + ThrottleReadBpsDevice map[string]spec.LinuxThrottleDevice `json:"throttleReadBpsDevice,omitempty"` } // NewPodSpecGenerator creates a new pod spec diff --git a/pkg/specgen/specgen.go b/pkg/specgen/specgen.go index 70b2aa1ef..dbb669291 100644 --- a/pkg/specgen/specgen.go +++ b/pkg/specgen/specgen.go @@ -5,6 +5,7 @@ import ( "strings" "syscall" + "github.com/containers/common/libimage" "github.com/containers/image/v5/manifest" nettypes "github.com/containers/podman/v3/libpod/network/types" "github.com/containers/storage/types" @@ -512,6 +513,21 @@ type SpecGenerator struct { ContainerNetworkConfig ContainerResourceConfig ContainerHealthCheckConfig + + image *libimage.Image `json:"-"` + resolvedImageName string `json:"-"` +} + +// SetImage sets the associated for the generator. +func (s *SpecGenerator) SetImage(image *libimage.Image, resolvedImageName string) { + s.image = image + s.resolvedImageName = resolvedImageName +} + +// Image returns the associated image for the generator. +// May be nil if no image has been set yet. +func (s *SpecGenerator) GetImage() (*libimage.Image, string) { + return s.image, s.resolvedImageName } type Secret struct { diff --git a/test/e2e/play_kube_test.go b/test/e2e/play_kube_test.go index 83ce751e6..a29d0ad46 100644 --- a/test/e2e/play_kube_test.go +++ b/test/e2e/play_kube_test.go @@ -1137,6 +1137,49 @@ var _ = Describe("Podman play kube", func() { Expect(infraContainerImage).To(Equal(config.DefaultInfraImage)) }) + It("podman play kube --no-host", func() { + err := writeYaml(checkInfraImagePodYaml, kubeYaml) + Expect(err).To(BeNil()) + + kube := podmanTest.Podman([]string{"play", "kube", "--no-hosts", kubeYaml}) + kube.WaitWithDefaultTimeout() + Expect(kube).Should(Exit(0)) + + podInspect := podmanTest.Podman([]string{"pod", "inspect", "check-infra-image"}) + podInspect.WaitWithDefaultTimeout() + Expect(podInspect).Should(Exit(0)) + + data := podInspect.InspectPodToJSON() + for _, ctr := range data.Containers { + if strings.HasSuffix(ctr.Name, "-infra") { + continue + } + exec := podmanTest.Podman([]string{"exec", ctr.ID, "cat", "/etc/hosts"}) + exec.WaitWithDefaultTimeout() + Expect(exec).Should(Exit(0)) + Expect(exec.OutputToString()).To(Not(ContainSubstring("check-infra-image"))) + } + }) + + It("podman play kube test HostAliases with --no-hosts", func() { + pod := getPod(withHostAliases("192.168.1.2", []string{ + "test1.podman.io", + "test2.podman.io", + }), + withHostAliases("192.168.1.3", []string{ + "test3.podman.io", + "test4.podman.io", + }), + ) + err := generateKubeYaml("pod", pod, kubeYaml) + Expect(err).To(BeNil()) + + kube := podmanTest.Podman([]string{"play", "kube", "--no-hosts", kubeYaml}) + kube.WaitWithDefaultTimeout() + Expect(kube).Should(Exit(125)) + Expect(kube.ErrorToString()).To(ContainSubstring("HostAliases in yaml file will not work with --no-hosts")) + }) + It("podman play kube should use customized infra_image", func() { conffile := filepath.Join(podmanTest.TempDir, "container.conf") diff --git a/test/e2e/pod_create_test.go b/test/e2e/pod_create_test.go index c9924be72..e8bc871da 100644 --- a/test/e2e/pod_create_test.go +++ b/test/e2e/pod_create_test.go @@ -903,4 +903,25 @@ ENTRYPOINT ["sleep","99999"] }) + It("podman pod create --device-read-bps", func() { + SkipIfRootless("Cannot create devices in /dev in rootless mode") + SkipIfRootlessCgroupsV1("Setting device-read-bps not supported on cgroupv1 for rootless users") + + podName := "testPod" + session := podmanTest.Podman([]string{"pod", "create", "--device-read-bps", "/dev/zero:1mb", "--name", podName}) + session.WaitWithDefaultTimeout() + Expect(session).Should(Exit(0)) + + if CGROUPSV2 { + session = podmanTest.Podman([]string{"run", "--rm", "--pod", podName, ALPINE, "sh", "-c", "cat /sys/fs/cgroup/$(sed -e 's|0::||' < /proc/self/cgroup)/io.max"}) + } else { + session = podmanTest.Podman([]string{"run", "--rm", "--pod", podName, ALPINE, "cat", "/sys/fs/cgroup/blkio/blkio.throttle.read_bps_device"}) + } + session.WaitWithDefaultTimeout() + Expect(session).Should(Exit(0)) + if !CGROUPSV2 { + Expect(session.OutputToString()).To(ContainSubstring("1048576")) + } + }) + }) |