summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--cmd/podman/common/create.go17
-rw-r--r--cmd/podman/pods/create.go14
-rw-r--r--docs/source/markdown/podman-pod-create.1.md6
-rw-r--r--libpod/container_inspect.go56
-rw-r--r--libpod/define/pod_inspect.go2
-rw-r--r--libpod/pod_api.go54
-rw-r--r--pkg/bindings/images/build.go5
-rw-r--r--pkg/bindings/test/fixture/Containerfile1
-rw-r--r--pkg/bindings/test/images_test.go100
-rw-r--r--pkg/domain/entities/pods.go5
-rw-r--r--pkg/machine/qemu/machine.go16
-rw-r--r--pkg/specgen/generate/container.go10
-rw-r--r--pkg/specgen/generate/container_create.go19
-rw-r--r--pkg/specgen/podspecgen.go2
-rw-r--r--test/e2e/pod_create_test.go21
-rw-r--r--test/system/160-volumes.bats2
16 files changed, 217 insertions, 113 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/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-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/bindings/images/build.go b/pkg/bindings/images/build.go
index 8cf4532d0..403d90721 100644
--- a/pkg/bindings/images/build.go
+++ b/pkg/bindings/images/build.go
@@ -16,6 +16,7 @@ import (
"strconv"
"strings"
+ "github.com/containers/buildah/define"
"github.com/containers/podman/v3/pkg/auth"
"github.com/containers/podman/v3/pkg/bindings"
"github.com/containers/podman/v3/pkg/domain/entities"
@@ -39,6 +40,10 @@ var (
// Build creates an image using a containerfile reference
func Build(ctx context.Context, containerFiles []string, options entities.BuildOptions) (*entities.BuildReport, error) {
+ if options.CommonBuildOpts == nil {
+ options.CommonBuildOpts = new(define.CommonBuildOptions)
+ }
+
params := url.Values{}
if caps := options.AddCapabilities; len(caps) > 0 {
diff --git a/pkg/bindings/test/fixture/Containerfile b/pkg/bindings/test/fixture/Containerfile
new file mode 100644
index 000000000..3a1031f32
--- /dev/null
+++ b/pkg/bindings/test/fixture/Containerfile
@@ -0,0 +1 @@
+From quay.io/libpod/alpine_nginx
diff --git a/pkg/bindings/test/images_test.go b/pkg/bindings/test/images_test.go
index ff8f72c85..aa8ff0537 100644
--- a/pkg/bindings/test/images_test.go
+++ b/pkg/bindings/test/images_test.go
@@ -9,9 +9,11 @@ import (
"github.com/containers/podman/v3/pkg/bindings"
"github.com/containers/podman/v3/pkg/bindings/containers"
"github.com/containers/podman/v3/pkg/bindings/images"
+ "github.com/containers/podman/v3/pkg/domain/entities"
. "github.com/onsi/ginkgo"
. "github.com/onsi/gomega"
- "github.com/onsi/gomega/gexec"
+ . "github.com/onsi/gomega/gexec"
+ . "github.com/onsi/gomega/gstruct"
)
var _ = Describe("Podman images", func() {
@@ -20,7 +22,7 @@ var _ = Describe("Podman images", func() {
// err error
// podmanTest *PodmanTestIntegration
bt *bindingTest
- s *gexec.Session
+ s *Session
err error
)
@@ -37,7 +39,7 @@ var _ = Describe("Podman images", func() {
s = bt.startAPIService()
time.Sleep(1 * time.Second)
err := bt.NewConnection()
- Expect(err).To(BeNil())
+ Expect(err).ToNot(HaveOccurred())
})
AfterEach(func() {
@@ -57,19 +59,19 @@ var _ = Describe("Podman images", func() {
// Inspect by short name
data, err := images.GetImage(bt.conn, alpine.shortName, nil)
- Expect(err).To(BeNil())
+ Expect(err).ToNot(HaveOccurred())
// Inspect with full ID
_, err = images.GetImage(bt.conn, data.ID, nil)
- Expect(err).To(BeNil())
+ Expect(err).ToNot(HaveOccurred())
// Inspect with partial ID
_, err = images.GetImage(bt.conn, data.ID[0:12], nil)
- Expect(err).To(BeNil())
+ Expect(err).ToNot(HaveOccurred())
// Inspect by long name
_, err = images.GetImage(bt.conn, alpine.name, nil)
- Expect(err).To(BeNil())
+ Expect(err).ToNot(HaveOccurred())
// TODO it looks like the images API always returns size regardless
// of bool or not. What should we do ?
// Expect(data.Size).To(BeZero())
@@ -77,7 +79,7 @@ var _ = Describe("Podman images", func() {
options := new(images.GetOptions).WithSize(true)
// Enabling the size parameter should result in size being populated
data, err = images.GetImage(bt.conn, alpine.name, options)
- Expect(err).To(BeNil())
+ Expect(err).ToNot(HaveOccurred())
Expect(data.Size).To(BeNumerically(">", 0))
})
@@ -90,7 +92,7 @@ var _ = Describe("Podman images", func() {
// Remove an image by name, validate image is removed and error is nil
inspectData, err := images.GetImage(bt.conn, busybox.shortName, nil)
- Expect(err).To(BeNil())
+ Expect(err).ToNot(HaveOccurred())
response, errs = images.Remove(bt.conn, []string{busybox.shortName}, nil)
Expect(len(errs)).To(BeZero())
@@ -101,10 +103,10 @@ var _ = Describe("Podman images", func() {
// Start a container with alpine image
var top string = "top"
_, err = bt.RunTopContainer(&top, nil)
- Expect(err).To(BeNil())
+ Expect(err).ToNot(HaveOccurred())
// we should now have a container called "top" running
containerResponse, err := containers.Inspect(bt.conn, "top", nil)
- Expect(err).To(BeNil())
+ Expect(err).ToNot(HaveOccurred())
Expect(containerResponse.Name).To(Equal("top"))
// try to remove the image "alpine". This should fail since we are not force
@@ -115,7 +117,7 @@ var _ = Describe("Podman images", func() {
// Removing the image "alpine" where force = true
options := new(images.RemoveOptions).WithForce(true)
response, errs = images.Remove(bt.conn, []string{alpine.shortName}, options)
- Expect(errs).To(BeNil())
+ Expect(errs).To(Or(HaveLen(0), BeNil()))
// To be extra sure, check if the previously created container
// is gone as well.
_, err = containers.Inspect(bt.conn, "top", nil)
@@ -141,11 +143,11 @@ var _ = Describe("Podman images", func() {
// Validates if the image is tagged successfully.
err = images.Tag(bt.conn, alpine.shortName, "demo", alpine.shortName, nil)
- Expect(err).To(BeNil())
+ Expect(err).ToNot(HaveOccurred())
// Validates if name updates when the image is retagged.
_, err := images.GetImage(bt.conn, "alpine:demo", nil)
- Expect(err).To(BeNil())
+ Expect(err).ToNot(HaveOccurred())
})
@@ -154,7 +156,7 @@ var _ = Describe("Podman images", func() {
// Array to hold the list of images returned
imageSummary, err := images.List(bt.conn, nil)
// There Should be no errors in the response.
- Expect(err).To(BeNil())
+ Expect(err).ToNot(HaveOccurred())
// Since in the begin context two images are created the
// list context should have only 2 images
Expect(len(imageSummary)).To(Equal(2))
@@ -163,23 +165,23 @@ var _ = Describe("Podman images", func() {
// And the count should be three now.
bt.Pull("testimage:20200929")
imageSummary, err = images.List(bt.conn, nil)
- Expect(err).To(BeNil())
- Expect(len(imageSummary)).To(Equal(3))
+ Expect(err).ToNot(HaveOccurred())
+ Expect(len(imageSummary)).To(BeNumerically(">=", 2))
// Validate the image names.
var names []string
for _, i := range imageSummary {
names = append(names, i.RepoTags...)
}
- Expect(StringInSlice(alpine.name, names)).To(BeTrue())
- Expect(StringInSlice(busybox.name, names)).To(BeTrue())
+ Expect(names).To(ContainElement(alpine.name))
+ Expect(names).To(ContainElement(busybox.name))
// List images with a filter
filters := make(map[string][]string)
filters["reference"] = []string{alpine.name}
options := new(images.ListOptions).WithFilters(filters).WithAll(false)
filteredImages, err := images.List(bt.conn, options)
- Expect(err).To(BeNil())
+ Expect(err).ToNot(HaveOccurred())
Expect(len(filteredImages)).To(BeNumerically("==", 1))
// List images with a bad filter
@@ -194,17 +196,17 @@ var _ = Describe("Podman images", func() {
It("Image Exists", func() {
// exists on bogus image should be false, with no error
exists, err := images.Exists(bt.conn, "foobar", nil)
- Expect(err).To(BeNil())
+ Expect(err).ToNot(HaveOccurred())
Expect(exists).To(BeFalse())
// exists with shortname should be true
exists, err = images.Exists(bt.conn, alpine.shortName, nil)
- Expect(err).To(BeNil())
+ Expect(err).ToNot(HaveOccurred())
Expect(exists).To(BeTrue())
// exists with fqname should be true
exists, err = images.Exists(bt.conn, alpine.name, nil)
- Expect(err).To(BeNil())
+ Expect(err).ToNot(HaveOccurred())
Expect(exists).To(BeTrue())
})
@@ -213,37 +215,37 @@ var _ = Describe("Podman images", func() {
_, errs := images.Remove(bt.conn, []string{alpine.name}, nil)
Expect(len(errs)).To(BeZero())
exists, err := images.Exists(bt.conn, alpine.name, nil)
- Expect(err).To(BeNil())
+ Expect(err).ToNot(HaveOccurred())
Expect(exists).To(BeFalse())
f, err := os.Open(filepath.Join(ImageCacheDir, alpine.tarballName))
defer f.Close()
- Expect(err).To(BeNil())
+ Expect(err).ToNot(HaveOccurred())
names, err := images.Load(bt.conn, f)
- Expect(err).To(BeNil())
+ Expect(err).ToNot(HaveOccurred())
Expect(names.Names[0]).To(Equal(alpine.name))
exists, err = images.Exists(bt.conn, alpine.name, nil)
- Expect(err).To(BeNil())
+ Expect(err).ToNot(HaveOccurred())
Expect(exists).To(BeTrue())
// load with a repo name
f, err = os.Open(filepath.Join(ImageCacheDir, alpine.tarballName))
- Expect(err).To(BeNil())
+ Expect(err).ToNot(HaveOccurred())
_, errs = images.Remove(bt.conn, []string{alpine.name}, nil)
Expect(len(errs)).To(BeZero())
exists, err = images.Exists(bt.conn, alpine.name, nil)
- Expect(err).To(BeNil())
+ Expect(err).ToNot(HaveOccurred())
Expect(exists).To(BeFalse())
names, err = images.Load(bt.conn, f)
- Expect(err).To(BeNil())
+ Expect(err).ToNot(HaveOccurred())
Expect(names.Names[0]).To(Equal(alpine.name))
// load with a bad repo name should trigger a 500
f, err = os.Open(filepath.Join(ImageCacheDir, alpine.tarballName))
- Expect(err).To(BeNil())
+ Expect(err).ToNot(HaveOccurred())
_, errs = images.Remove(bt.conn, []string{alpine.name}, nil)
Expect(len(errs)).To(BeZero())
exists, err = images.Exists(bt.conn, alpine.name, nil)
- Expect(err).To(BeNil())
+ Expect(err).ToNot(HaveOccurred())
Expect(exists).To(BeFalse())
})
@@ -252,11 +254,11 @@ var _ = Describe("Podman images", func() {
exportPath := filepath.Join(bt.tempDirPath, alpine.tarballName)
w, err := os.Create(filepath.Join(bt.tempDirPath, alpine.tarballName))
defer w.Close()
- Expect(err).To(BeNil())
+ Expect(err).ToNot(HaveOccurred())
err = images.Export(bt.conn, []string{alpine.name}, w, nil)
- Expect(err).To(BeNil())
+ Expect(err).ToNot(HaveOccurred())
_, err = os.Stat(exportPath)
- Expect(err).To(BeNil())
+ Expect(err).ToNot(HaveOccurred())
// TODO how do we verify that a format change worked?
})
@@ -266,21 +268,21 @@ var _ = Describe("Podman images", func() {
_, errs := images.Remove(bt.conn, []string{alpine.name}, nil)
Expect(len(errs)).To(BeZero())
exists, err := images.Exists(bt.conn, alpine.name, nil)
- Expect(err).To(BeNil())
+ Expect(err).ToNot(HaveOccurred())
Expect(exists).To(BeFalse())
f, err := os.Open(filepath.Join(ImageCacheDir, alpine.tarballName))
defer f.Close()
- Expect(err).To(BeNil())
+ Expect(err).ToNot(HaveOccurred())
changes := []string{"CMD /bin/foobar"}
testMessage := "test_import"
options := new(images.ImportOptions).WithMessage(testMessage).WithChanges(changes).WithReference(alpine.name)
_, err = images.Import(bt.conn, f, options)
- Expect(err).To(BeNil())
+ Expect(err).ToNot(HaveOccurred())
exists, err = images.Exists(bt.conn, alpine.name, nil)
- Expect(err).To(BeNil())
+ Expect(err).ToNot(HaveOccurred())
Expect(exists).To(BeTrue())
data, err := images.GetImage(bt.conn, alpine.name, nil)
- Expect(err).To(BeNil())
+ Expect(err).ToNot(HaveOccurred())
Expect(data.Comment).To(Equal(testMessage))
})
@@ -294,9 +296,9 @@ var _ = Describe("Podman images", func() {
var foundID bool
data, err := images.GetImage(bt.conn, alpine.name, nil)
- Expect(err).To(BeNil())
+ Expect(err).ToNot(HaveOccurred())
history, err := images.History(bt.conn, alpine.name, nil)
- Expect(err).To(BeNil())
+ Expect(err).ToNot(HaveOccurred())
for _, i := range history {
if i.ID == data.ID {
foundID = true
@@ -308,7 +310,7 @@ var _ = Describe("Podman images", func() {
It("Search for an image", func() {
reports, err := images.Search(bt.conn, "alpine", nil)
- Expect(err).To(BeNil())
+ Expect(err).ToNot(HaveOccurred())
Expect(len(reports)).To(BeNumerically(">", 1))
var foundAlpine bool
for _, i := range reports {
@@ -322,7 +324,7 @@ var _ = Describe("Podman images", func() {
// Search for alpine with a limit of 10
options := new(images.SearchOptions).WithLimit(10)
reports, err = images.Search(bt.conn, "docker.io/alpine", options)
- Expect(err).To(BeNil())
+ Expect(err).ToNot(HaveOccurred())
Expect(len(reports)).To(BeNumerically("<=", 10))
filters := make(map[string][]string)
@@ -330,7 +332,7 @@ var _ = Describe("Podman images", func() {
// Search for alpine with stars greater than 100
options = new(images.SearchOptions).WithFilters(filters)
reports, err = images.Search(bt.conn, "docker.io/alpine", options)
- Expect(err).To(BeNil())
+ Expect(err).ToNot(HaveOccurred())
for _, i := range reports {
Expect(i.Stars).To(BeNumerically(">=", 100))
}
@@ -367,4 +369,12 @@ var _ = Describe("Podman images", func() {
_, err = images.Pull(bt.conn, "bogus-transport:bogus.com/image:reference", nil)
Expect(err).To(HaveOccurred())
})
+
+ It("Build no options", func() {
+ results, err := images.Build(bt.conn, []string{"fixture/Containerfile"}, entities.BuildOptions{})
+ Expect(err).ToNot(HaveOccurred())
+ Expect(*results).To(MatchFields(IgnoreMissing, Fields{
+ "ID": Not(BeEmpty()),
+ }))
+ })
})
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/machine/qemu/machine.go b/pkg/machine/qemu/machine.go
index c4e6aa611..727b3cda4 100644
--- a/pkg/machine/qemu/machine.go
+++ b/pkg/machine/qemu/machine.go
@@ -465,6 +465,22 @@ func (v *MachineVM) Remove(name string, opts machine.RemoveOptions) (string, fun
for _, msg := range files {
confirmationMessage += msg + "\n"
}
+
+ // Get path to socket and pidFile before we do any cleanups
+ qemuSocketFile, pidFile, errSocketFile := v.getSocketandPid()
+ //silently try to delete socket and pid file
+ //remove socket and pid file if any: warn at low priority if things fail
+ if errSocketFile == nil {
+ // Remove the pidfile
+ if err := os.Remove(pidFile); err != nil && !errors.Is(err, os.ErrNotExist) {
+ logrus.Debugf("Error while removing pidfile: %v", err)
+ }
+ // Remove socket
+ if err := os.Remove(qemuSocketFile); err != nil && !errors.Is(err, os.ErrNotExist) {
+ logrus.Debugf("Error while removing podman-machine-socket: %v", err)
+ }
+ }
+
confirmationMessage += "\n"
return confirmationMessage, func() error {
for _, f := range files {
diff --git a/pkg/specgen/generate/container.go b/pkg/specgen/generate/container.go
index f4b2eeb25..f126aa018 100644
--- a/pkg/specgen/generate/container.go
+++ b/pkg/specgen/generate/container.go
@@ -215,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 {
@@ -275,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{}
@@ -287,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 d0db9f35d..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)
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/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"))
+ }
+ })
+
})
diff --git a/test/system/160-volumes.bats b/test/system/160-volumes.bats
index b48198a18..c02525e0d 100644
--- a/test/system/160-volumes.bats
+++ b/test/system/160-volumes.bats
@@ -191,7 +191,7 @@ EOF
run_podman run --rm -v my_vol:/data $IMAGE sh -c "echo hello >> /data/test"
run_podman volume create my_vol2
- tarfile=hello$(random_string | tr A-Z a-z).tar
+ tarfile=${PODMAN_TMPDIR}/hello$(random_string | tr A-Z a-z).tar
run_podman volume export my_vol --output=$tarfile
# we want to use `run_podman volume export my_vol` but run_podman is wrapping EOF
run_podman volume import my_vol2 - < $tarfile