summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--cmd/podman/common/create.go27
-rw-r--r--cmd/podman/common/create_test.go53
-rw-r--r--cmd/podman/containers/ps.go8
-rw-r--r--cmd/podman/images/inspect.go6
-rw-r--r--cmd/podman/machine/init.go21
-rw-r--r--cmd/podman/networks/inspect.go2
-rw-r--r--cmd/podman/pods/create.go32
-rw-r--r--cmd/podman/system/service.go3
-rw-r--r--docs/source/markdown/links/podman-container-inspect.11
-rw-r--r--docs/source/markdown/links/podman-image-inspect.11
-rw-r--r--docs/source/markdown/podman-container-inspect.1.md318
-rw-r--r--docs/source/markdown/podman-container.1.md2
-rw-r--r--docs/source/markdown/podman-image-inspect.1.md105
-rw-r--r--docs/source/markdown/podman-image.1.md48
-rw-r--r--docs/source/markdown/podman-inspect.1.md4
-rw-r--r--docs/source/markdown/podman-machine-init.1.md4
-rw-r--r--docs/source/markdown/podman-pod-create.1.md16
-rw-r--r--docs/source/markdown/podman-pod-inspect.1.md2
-rw-r--r--docs/source/markdown/podman-system-service.1.md5
-rw-r--r--docs/source/markdown/podman-volume-inspect.1.md2
-rw-r--r--libpod/container.go5
-rw-r--r--libpod/container_config.go2
-rw-r--r--libpod/container_inspect.go51
-rw-r--r--libpod/container_internal_linux.go97
-rw-r--r--libpod/define/pod_inspect.go2
-rw-r--r--libpod/kube.go5
-rw-r--r--libpod/options.go12
-rw-r--r--libpod/pod_api.go8
-rw-r--r--pkg/api/handlers/libpod/pods.go4
-rw-r--r--pkg/domain/entities/pods.go67
-rw-r--r--pkg/env/env.go5
-rw-r--r--pkg/specgen/generate/config_linux.go1
-rw-r--r--pkg/specgen/generate/container_create.go28
-rw-r--r--pkg/specgen/generate/oci.go7
-rw-r--r--pkg/specgen/podspecgen.go2
-rw-r--r--pkg/specgen/specgen.go4
-rw-r--r--test/e2e/config/containers.conf1
-rw-r--r--test/e2e/containers_conf_test.go8
-rw-r--r--test/e2e/play_kube_test.go24
-rw-r--r--test/e2e/pod_create_test.go19
-rw-r--r--test/e2e/ps_test.go57
-rw-r--r--test/e2e/run_volume_test.go33
-rw-r--r--test/utils/utils.go15
43 files changed, 904 insertions, 213 deletions
diff --git a/cmd/podman/common/create.go b/cmd/podman/common/create.go
index 6200592b4..a969e17e9 100644
--- a/cmd/podman/common/create.go
+++ b/cmd/podman/common/create.go
@@ -15,6 +15,18 @@ const sizeWithUnitFormat = "(format: `<number>[<unit>]`, where unit = b (bytes),
var containerConfig = registry.PodmanConfig()
+// ContainerToPodOptions takes the Container and Pod Create options, assigning the matching values back to podCreate for the purpose of the libpod API
+// For this function to succeed, the JSON tags in PodCreateOptions and ContainerCreateOptions need to match due to the Marshaling and Unmarshaling done.
+// The types of the options also need to match or else the unmarshaling will fail even if the tags match
+func ContainerToPodOptions(containerCreate *entities.ContainerCreateOptions, podCreate *entities.PodCreateOptions) error {
+ contMarshal, err := json.Marshal(containerCreate)
+ if err != nil {
+ return err
+ }
+ return json.Unmarshal(contMarshal, podCreate)
+}
+
+// DefineCreateFlags declares and instantiates the container create flags
func DefineCreateFlags(cmd *cobra.Command, cf *entities.ContainerCreateOptions, isInfra bool) {
createFlags := cmd.Flags()
@@ -144,14 +156,6 @@ func DefineCreateFlags(cmd *cobra.Command, cf *entities.ContainerCreateOptions,
)
_ = cmd.RegisterFlagCompletionFunc(cpusetMemsFlagName, completion.AutocompleteNone)
- deviceFlagName := "device"
- createFlags.StringSliceVar(
- &cf.Devices,
- deviceFlagName, devices(),
- "Add a host device to the container",
- )
- _ = cmd.RegisterFlagCompletionFunc(deviceFlagName, completion.AutocompleteDefault)
-
deviceCgroupRuleFlagName := "device-cgroup-rule"
createFlags.StringSliceVar(
&cf.DeviceCGroupRule,
@@ -865,4 +869,11 @@ func DefineCreateFlags(cmd *cobra.Command, cf *entities.ContainerCreateOptions,
volumeDesciption,
)
_ = cmd.RegisterFlagCompletionFunc(volumeFlagName, AutocompleteVolumeFlag)
+ deviceFlagName := "device"
+ createFlags.StringSliceVar(
+ &cf.Devices,
+ deviceFlagName, devices(),
+ "Add a host device to the container",
+ )
+ _ = cmd.RegisterFlagCompletionFunc(deviceFlagName, completion.AutocompleteDefault)
}
diff --git a/cmd/podman/common/create_test.go b/cmd/podman/common/create_test.go
new file mode 100644
index 000000000..17b47dd16
--- /dev/null
+++ b/cmd/podman/common/create_test.go
@@ -0,0 +1,53 @@
+package common_test
+
+import (
+ "reflect"
+ "strings"
+ "testing"
+
+ "github.com/containers/podman/v3/cmd/podman/common"
+ "github.com/containers/podman/v3/pkg/domain/entities"
+ "github.com/stretchr/testify/assert"
+)
+
+func TestPodOptions(t *testing.T) {
+ entry := "/test1"
+ exampleOptions := entities.ContainerCreateOptions{CPUS: 5.5, CPUSetCPUs: "0-4", Entrypoint: &entry, Hostname: "foo", Name: "testing123", Volume: []string{"/fakeVol1", "/fakeVol2"}, Net: &entities.NetOptions{CNINetworks: []string{"FakeNetwork"}}, PID: "ns:/proc/self/ns"}
+
+ podOptions := entities.PodCreateOptions{}
+ err := common.ContainerToPodOptions(&exampleOptions, &podOptions)
+ assert.Nil(t, err)
+
+ cc := reflect.ValueOf(&exampleOptions).Elem()
+ pc := reflect.ValueOf(&podOptions).Elem()
+
+ pcType := reflect.TypeOf(podOptions)
+ for i := 0; i < pc.NumField(); i++ {
+ podField := pc.FieldByIndex([]int{i})
+ podType := pcType.Field(i)
+ for j := 0; j < cc.NumField(); j++ {
+ containerField := cc.FieldByIndex([]int{j})
+ containerType := reflect.TypeOf(exampleOptions).Field(j)
+ tagPod := strings.Split(string(podType.Tag.Get("json")), ",")[0]
+ tagContainer := strings.Split(string(containerType.Tag.Get("json")), ",")[0]
+ if tagPod == tagContainer && (tagPod != "" && tagContainer != "") {
+ areEqual := true
+ if containerField.Kind() == podField.Kind() {
+ switch containerField.Kind() {
+ case reflect.Slice:
+ for i, w := range containerField.Interface().([]string) {
+ areEqual = podField.Interface().([]string)[i] == w
+ }
+ case reflect.String:
+ areEqual = (podField.String() == containerField.String())
+ case reflect.Bool:
+ areEqual = (podField.Bool() == containerField.Bool())
+ case reflect.Ptr:
+ areEqual = (reflect.DeepEqual(podField.Elem().Interface(), containerField.Elem().Interface()))
+ }
+ }
+ assert.True(t, areEqual)
+ }
+ }
+ }
+}
diff --git a/cmd/podman/containers/ps.go b/cmd/podman/containers/ps.go
index ff792b78b..afb8edd91 100644
--- a/cmd/podman/containers/ps.go
+++ b/cmd/podman/containers/ps.go
@@ -221,7 +221,10 @@ func ps(cmd *cobra.Command, _ []string) error {
}
hdrs, format := createPsOut()
+
+ noHeading, _ := cmd.Flags().GetBool("noheading")
if cmd.Flags().Changed("format") {
+ noHeading = noHeading || !report.HasTable(listOpts.Format)
format = report.NormalizeFormat(listOpts.Format)
format = report.EnforceRange(format)
}
@@ -240,8 +243,7 @@ func ps(cmd *cobra.Command, _ []string) error {
defer w.Flush()
headers := func() error { return nil }
- noHeading, _ := cmd.Flags().GetBool("noheading")
- if !(noHeading || listOpts.Quiet || cmd.Flags().Changed("format")) {
+ if !noHeading {
headers = func() error {
return tmpl.Execute(w, hdrs)
}
@@ -298,9 +300,11 @@ func createPsOut() ([]map[string]string, string) {
"IPC": "ipc",
"MNT": "mnt",
"NET": "net",
+ "Networks": "networks",
"PIDNS": "pidns",
"Pod": "pod id",
"PodName": "podname", // undo camelcase space break
+ "RunningFor": "running for",
"UTS": "uts",
"User": "userns",
})
diff --git a/cmd/podman/images/inspect.go b/cmd/podman/images/inspect.go
index 35c173a60..dd8cf8056 100644
--- a/cmd/podman/images/inspect.go
+++ b/cmd/podman/images/inspect.go
@@ -17,9 +17,9 @@ var (
Long: `Displays the low-level information of an image identified by name or ID.`,
RunE: inspectExec,
ValidArgsFunction: common.AutocompleteImages,
- Example: `podman inspect alpine
- podman inspect --format "imageId: {{.Id}} size: {{.Size}}" alpine
- podman inspect --format "image: {{.ImageName}} driver: {{.Driver}}" myctr`,
+ Example: `podman image inspect alpine
+ podman image inspect --format "imageId: {{.Id}} size: {{.Size}}" alpine
+ podman image inspect --format "image: {{.ImageName}} driver: {{.Driver}}" myctr`,
}
inspectOpts *entities.InspectOptions
)
diff --git a/cmd/podman/machine/init.go b/cmd/podman/machine/init.go
index ec44a707d..19f31d1a6 100644
--- a/cmd/podman/machine/init.go
+++ b/cmd/podman/machine/init.go
@@ -3,6 +3,8 @@
package machine
import (
+ "fmt"
+
"github.com/containers/common/pkg/completion"
"github.com/containers/podman/v3/cmd/podman/registry"
"github.com/containers/podman/v3/pkg/machine"
@@ -26,6 +28,7 @@ var (
var (
initOpts = machine.InitOptions{}
defaultMachineName = "podman-machine-default"
+ now bool
)
func init() {
@@ -61,6 +64,12 @@ func init() {
)
_ = initCmd.RegisterFlagCompletionFunc(memoryFlagName, completion.AutocompleteNone)
+ flags.BoolVar(
+ &now,
+ "now", false,
+ "Start machine now",
+ )
+
ImagePathFlagName := "image-path"
flags.StringVar(&initOpts.ImagePath, ImagePathFlagName, cfg.Engine.MachineImage, "Path to qcow image")
_ = initCmd.RegisterFlagCompletionFunc(ImagePathFlagName, completion.AutocompleteDefault)
@@ -91,5 +100,15 @@ func initMachine(cmd *cobra.Command, args []string) error {
if err != nil {
return err
}
- return vm.Init(initOpts)
+ err = vm.Init(initOpts)
+ if err != nil {
+ return err
+ }
+ if now {
+ err = vm.Start(initOpts.Name, machine.StartOptions{})
+ if err == nil {
+ fmt.Printf("Machine %q started successfully\n", initOpts.Name)
+ }
+ }
+ return err
}
diff --git a/cmd/podman/networks/inspect.go b/cmd/podman/networks/inspect.go
index c0e5b9720..4f3e86fc9 100644
--- a/cmd/podman/networks/inspect.go
+++ b/cmd/podman/networks/inspect.go
@@ -12,7 +12,7 @@ var (
networkinspectDescription = `Inspect network`
networkinspectCommand = &cobra.Command{
Use: "inspect [options] NETWORK [NETWORK...]",
- Short: "network inspect",
+ Short: "Displays the raw CNI network configuration for one or more networks.",
Long: networkinspectDescription,
RunE: networkInspect,
Example: `podman network inspect podman`,
diff --git a/cmd/podman/pods/create.go b/cmd/podman/pods/create.go
index 7000c92c8..ca73a8356 100644
--- a/cmd/podman/pods/create.go
+++ b/cmd/podman/pods/create.go
@@ -132,7 +132,6 @@ 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
- MapOptions()
flags := cmd.Flags()
infraOptions.Net, err = common.NetFlagsToNetOptions(nil, *flags, false)
if err != nil {
@@ -142,13 +141,11 @@ func create(cmd *cobra.Command, args []string) error {
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
cmdIn, err := cmd.Flags().GetString("infra-command")
infraOptions.Entrypoint = &cmdIn
- createOptions.InfraCommand = cmdIn
if err != nil {
return err
}
@@ -161,6 +158,10 @@ func create(cmd *cobra.Command, args []string) error {
return err
}
}
+ err = common.ContainerToPodOptions(&infraOptions, &createOptions)
+ if err != nil {
+ return err
+ }
}
if cmd.Flag("pod-id-file").Changed {
@@ -196,8 +197,8 @@ func create(cmd *cobra.Command, args []string) error {
if createOptions.Cpus > float64(numCPU) {
createOptions.Cpus = float64(numCPU)
}
- copy := createOptions.CpusetCpus
- cpuSet := createOptions.Cpus
+ copy := infraOptions.CPUSetCPUs
+ cpuSet := infraOptions.CPUS
if cpuSet == 0 {
cpuSet = float64(sysinfo.NumCPU())
}
@@ -217,10 +218,10 @@ func create(cmd *cobra.Command, args []string) error {
if core > int(cpuSet) {
if copy == "" {
copy = "0-" + strconv.Itoa(int(cpuSet))
- createOptions.CpusetCpus = copy
+ infraOptions.CPUSetCPUs = copy
break
} else {
- createOptions.CpusetCpus = copy
+ infraOptions.CPUSetCPUs = copy
break
}
} else if ind != 0 {
@@ -229,6 +230,8 @@ func create(cmd *cobra.Command, args []string) error {
copy = "" + strconv.Itoa(core)
}
}
+ createOptions.Cpus = infraOptions.CPUS
+ createOptions.CpusetCpus = infraOptions.CPUSetCPUs
podSpec := specgen.NewPodSpecGenerator()
podSpec, err = entities.ToPodSpecGen(*podSpec, &createOptions)
if err != nil {
@@ -248,11 +251,8 @@ func create(cmd *cobra.Command, args []string) error {
}
podSpec.InfraImage = imageName
if infraOptions.Entrypoint != nil {
- createOptions.InfraCommand = *infraOptions.Entrypoint
+ 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
@@ -290,13 +290,3 @@ func replacePod(name string) error {
}
return removePods([]string{name}, rmOptions, false)
}
-
-func MapOptions() {
- createOptions.Cpus = infraOptions.CPUS
- createOptions.CpusetCpus = infraOptions.CPUSetCPUs
- createOptions.Hostname = infraOptions.Hostname
- createOptions.InfraConmonPidFile = infraOptions.ConmonPIDFile
- createOptions.InfraName = infraOptions.Name
- createOptions.Pid = infraOptions.PID
- createOptions.Volume = infraOptions.Volume
-}
diff --git a/cmd/podman/system/service.go b/cmd/podman/system/service.go
index a30f43839..d6fe8837b 100644
--- a/cmd/podman/system/service.go
+++ b/cmd/podman/system/service.go
@@ -52,8 +52,9 @@ func init() {
flags := srvCmd.Flags()
+ cfg := registry.PodmanConfig()
timeFlagName := "time"
- flags.Int64VarP(&srvArgs.Timeout, timeFlagName, "t", 5, "Time until the service session expires in seconds. Use 0 to disable the timeout")
+ flags.Int64VarP(&srvArgs.Timeout, timeFlagName, "t", int64(cfg.Engine.ServiceTimeout), "Time until the service session expires in seconds. Use 0 to disable the timeout")
_ = srvCmd.RegisterFlagCompletionFunc(timeFlagName, completion.AutocompleteNone)
flags.StringVarP(&srvArgs.CorsHeaders, "cors", "", "", "Set CORS Headers")
_ = srvCmd.RegisterFlagCompletionFunc("cors", completion.AutocompleteNone)
diff --git a/docs/source/markdown/links/podman-container-inspect.1 b/docs/source/markdown/links/podman-container-inspect.1
deleted file mode 100644
index 261043845..000000000
--- a/docs/source/markdown/links/podman-container-inspect.1
+++ /dev/null
@@ -1 +0,0 @@
-.so man1/podman-inspect.1
diff --git a/docs/source/markdown/links/podman-image-inspect.1 b/docs/source/markdown/links/podman-image-inspect.1
deleted file mode 100644
index 261043845..000000000
--- a/docs/source/markdown/links/podman-image-inspect.1
+++ /dev/null
@@ -1 +0,0 @@
-.so man1/podman-inspect.1
diff --git a/docs/source/markdown/podman-container-inspect.1.md b/docs/source/markdown/podman-container-inspect.1.md
new file mode 100644
index 000000000..72b7cef3b
--- /dev/null
+++ b/docs/source/markdown/podman-container-inspect.1.md
@@ -0,0 +1,318 @@
+% podman-container-inspect(1)
+
+## NAME
+podman\-container\-inspect - Display a container's configuration
+
+## SYNOPSIS
+**podman container inspect** [*options*] *container* [*container* ...]
+
+## DESCRIPTION
+
+This displays the low-level information on containers identified by name or ID. By default, this will render
+all results in a JSON array. If a format is specified, the given template will be executed for each result.
+
+## OPTIONS
+
+#### **--format**, **-f**=*format*
+
+Format the output using the given Go template.
+The keys of the returned JSON can be used as the values for the --format flag (see examples below).
+
+#### **--latest**, **-l**
+
+Instead of providing the container name or ID, use the last created container. If you use methods other than Podman
+to run containers such as CRI-O, the last started container could be from either of those methods.
+
+(This option is not available with the remote Podman client.)
+
+#### **--size**, **-s**
+
+In addition to normal output, display the total file size if the type is a container.
+
+
+## EXAMPLE
+
+```
+$ podman container inspect foobar
+[
+ {
+ "Id": "99f66530fe9c7249f7cf29f78e8661669d5831cbe4ee80ea757d5e922dd6a8a6",
+ "Created": "2021-09-16T06:09:08.936623325-04:00",
+ "Path": "echo",
+ "Args": [
+ "hi"
+ ],
+ "State": {
+ "OciVersion": "1.0.2-dev",
+ "Status": "exited",
+ "Running": false,
+ "Paused": false,
+ "Restarting": false,
+ "OOMKilled": false,
+ "Dead": false,
+ "Pid": 0,
+ "ExitCode": 0,
+ "Error": "",
+ "StartedAt": "2021-09-16T06:09:09.033564436-04:00",
+ "FinishedAt": "2021-09-16T06:09:09.036184314-04:00",
+ "Healthcheck": {
+ "Status": "",
+ "FailingStreak": 0,
+ "Log": null
+ }
+ },
+ "Image": "14119a10abf4669e8cdbdff324a9f9605d99697215a0d21c360fe8dfa8471bab",
+ "ImageName": "docker.io/library/alpine:latest",
+ "Rootfs": "",
+ "Pod": "",
+ "ResolvConfPath": "/run/user/3267/containers/overlay-containers/99f66530fe9c7249f7cf29f78e8661669d5831cbe4ee80ea757d5e922dd6a8a6/userdata/resolv.conf",
+ "HostnamePath": "/run/user/3267/containers/overlay-containers/99f66530fe9c7249f7cf29f78e8661669d5831cbe4ee80ea757d5e922dd6a8a6/userdata/hostname",
+ "HostsPath": "/run/user/3267/containers/overlay-containers/99f66530fe9c7249f7cf29f78e8661669d5831cbe4ee80ea757d5e922dd6a8a6/userdata/hosts",
+ "StaticDir": "/home/dwalsh/.local/share/containers/storage/overlay-containers/99f66530fe9c7249f7cf29f78e8661669d5831cbe4ee80ea757d5e922dd6a8a6/userdata",
+ "OCIConfigPath": "/home/dwalsh/.local/share/containers/storage/overlay-containers/99f66530fe9c7249f7cf29f78e8661669d5831cbe4ee80ea757d5e922dd6a8a6/userdata/config.json",
+ "OCIRuntime": "crun",
+ "ConmonPidFile": "/run/user/3267/containers/overlay-containers/99f66530fe9c7249f7cf29f78e8661669d5831cbe4ee80ea757d5e922dd6a8a6/userdata/conmon.pid",
+ "PidFile": "/run/user/3267/containers/overlay-containers/99f66530fe9c7249f7cf29f78e8661669d5831cbe4ee80ea757d5e922dd6a8a6/userdata/pidfile",
+ "Name": "foobar",
+ "RestartCount": 0,
+ "Driver": "overlay",
+ "MountLabel": "system_u:object_r:container_file_t:s0:c25,c695",
+ "ProcessLabel": "system_u:system_r:container_t:s0:c25,c695",
+ "AppArmorProfile": "",
+ "EffectiveCaps": [
+ "CAP_CHOWN",
+ "CAP_DAC_OVERRIDE",
+ "CAP_FOWNER",
+ "CAP_FSETID",
+ "CAP_KILL",
+ "CAP_NET_BIND_SERVICE",
+ "CAP_SETFCAP",
+ "CAP_SETGID",
+ "CAP_SETPCAP",
+ "CAP_SETUID",
+ "CAP_SYS_CHROOT"
+ ],
+ "BoundingCaps": [
+ "CAP_CHOWN",
+ "CAP_DAC_OVERRIDE",
+ "CAP_FOWNER",
+ "CAP_FSETID",
+ "CAP_KILL",
+ "CAP_NET_BIND_SERVICE",
+ "CAP_SETFCAP",
+ "CAP_SETGID",
+ "CAP_SETPCAP",
+ "CAP_SETUID",
+ "CAP_SYS_CHROOT"
+ ],
+ "ExecIDs": [],
+ "GraphDriver": {
+ "Name": "overlay",
+ "Data": {
+ "LowerDir": "/home/dwalsh/.local/share/containers/storage/overlay/e2eb06d8af8218cfec8210147357a68b7e13f7c485b991c288c2d01dc228bb68/diff",
+ "UpperDir": "/home/dwalsh/.local/share/containers/storage/overlay/8f3d70434a3db17410ec4710caf4f251f3e4ed0a96a08124e4b3d4af0a0ea300/diff",
+ "WorkDir": "/home/dwalsh/.local/share/containers/storage/overlay/8f3d70434a3db17410ec4710caf4f251f3e4ed0a96a08124e4b3d4af0a0ea300/work"
+ }
+ },
+ "Mounts": [],
+ "Dependencies": [],
+ "NetworkSettings": {
+ "EndpointID": "",
+ "Gateway": "",
+ "IPAddress": "",
+ "IPPrefixLen": 0,
+ "IPv6Gateway": "",
+ "GlobalIPv6Address": "",
+ "GlobalIPv6PrefixLen": 0,
+ "MacAddress": "",
+ "Bridge": "",
+ "SandboxID": "",
+ "HairpinMode": false,
+ "LinkLocalIPv6Address": "",
+ "LinkLocalIPv6PrefixLen": 0,
+ "Ports": {},
+ "SandboxKey": ""
+ },
+ "ExitCommand": [
+ "/usr/bin/podman",
+ "--root",
+ "/home/dwalsh/.local/share/containers/storage",
+ "--runroot",
+ "/run/user/3267/containers",
+ "--log-level",
+ "warning",
+ "--cgroup-manager",
+ "systemd",
+ "--tmpdir",
+ "/run/user/3267/libpod/tmp",
+ "--runtime",
+ "crun",
+ "--storage-driver",
+ "overlay",
+ "--events-backend",
+ "journald",
+ "container",
+ "cleanup",
+ "99f66530fe9c7249f7cf29f78e8661669d5831cbe4ee80ea757d5e922dd6a8a6"
+ ],
+ "Namespace": "",
+ "IsInfra": false,
+ "Config": {
+ "Hostname": "99f66530fe9c",
+ "Domainname": "",
+ "User": "",
+ "AttachStdin": false,
+ "AttachStdout": false,
+ "AttachStderr": false,
+ "Tty": false,
+ "OpenStdin": false,
+ "StdinOnce": false,
+ "Env": [
+ "PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin",
+ "TERM=xterm",
+ "container=podman",
+ "HOME=/root",
+ "HOSTNAME=99f66530fe9c"
+ ],
+ "Cmd": [
+ "echo",
+ "hi"
+ ],
+ "Image": "docker.io/library/alpine:latest",
+ "Volumes": null,
+ "WorkingDir": "/",
+ "Entrypoint": "",
+ "OnBuild": null,
+ "Labels": null,
+ "Annotations": {
+ "io.container.manager": "libpod",
+ "io.kubernetes.cri-o.Created": "2021-09-16T06:09:08.936623325-04:00",
+ "io.kubernetes.cri-o.TTY": "false",
+ "io.podman.annotations.autoremove": "FALSE",
+ "io.podman.annotations.init": "FALSE",
+ "io.podman.annotations.privileged": "FALSE",
+ "io.podman.annotations.publish-all": "FALSE",
+ "org.opencontainers.image.stopSignal": "15"
+ },
+ "StopSignal": 15,
+ "CreateCommand": [
+ "podman",
+ "run",
+ "--name",
+ "foobar",
+ "alpine",
+ "echo",
+ "hi"
+ ],
+ "Timezone": "local",
+ "Umask": "0022",
+ "Timeout": 0,
+ "StopTimeout": 10
+ },
+ "HostConfig": {
+ "Binds": [],
+ "CgroupManager": "systemd",
+ "CgroupMode": "private",
+ "ContainerIDFile": "",
+ "LogConfig": {
+ "Type": "journald",
+ "Config": null,
+ "Path": "",
+ "Tag": "",
+ "Size": "0B"
+ },
+ "NetworkMode": "slirp4netns",
+ "PortBindings": {},
+ "RestartPolicy": {
+ "Name": "",
+ "MaximumRetryCount": 0
+ },
+ "AutoRemove": false,
+ "VolumeDriver": "",
+ "VolumesFrom": null,
+ "CapAdd": [],
+ "CapDrop": [
+ "CAP_AUDIT_WRITE",
+ "CAP_MKNOD",
+ "CAP_NET_RAW"
+ ],
+ "Dns": [],
+ "DnsOptions": [],
+ "DnsSearch": [],
+ "ExtraHosts": [],
+ "GroupAdd": [],
+ "IpcMode": "private",
+ "Cgroup": "",
+ "Cgroups": "default",
+ "Links": null,
+ "OomScoreAdj": 0,
+ "PidMode": "private",
+ "Privileged": false,
+ "PublishAllPorts": false,
+ "ReadonlyRootfs": false,
+ "SecurityOpt": [],
+ "Tmpfs": {},
+ "UTSMode": "private",
+ "UsernsMode": "",
+ "ShmSize": 65536000,
+ "Runtime": "oci",
+ "ConsoleSize": [
+ 0,
+ 0
+ ],
+ "Isolation": "",
+ "CpuShares": 0,
+ "Memory": 0,
+ "NanoCpus": 0,
+ "CgroupParent": "user.slice",
+ "BlkioWeight": 0,
+ "BlkioWeightDevice": null,
+ "BlkioDeviceReadBps": null,
+ "BlkioDeviceWriteBps": null,
+ "BlkioDeviceReadIOps": null,
+ "BlkioDeviceWriteIOps": null,
+ "CpuPeriod": 0,
+ "CpuQuota": 0,
+ "CpuRealtimePeriod": 0,
+ "CpuRealtimeRuntime": 0,
+ "CpusetCpus": "",
+ "CpusetMems": "",
+ "Devices": [],
+ "DiskQuota": 0,
+ "KernelMemory": 0,
+ "MemoryReservation": 0,
+ "MemorySwap": 0,
+ "MemorySwappiness": 0,
+ "OomKillDisable": false,
+ "PidsLimit": 2048,
+ "Ulimits": [],
+ "CpuCount": 0,
+ "CpuPercent": 0,
+ "IOMaximumIOps": 0,
+ "IOMaximumBandwidth": 0,
+ "CgroupConf": null
+ }
+ }
+]
+```
+
+```
+$ podman container inspect nervous_fermi --format "{{.ImageName}}"
+registry.access.redhat.com/ubi8:latest
+```
+
+```
+$ podman container inspect foobar --format "{{.GraphDriver.Name}}"
+overlay
+```
+
+```
+$ podman container inspect --latest --format {{.EffectiveCaps}}
+[CAP_CHOWN CAP_DAC_OVERRIDE CAP_FOWNER CAP_FSETID CAP_KILL CAP_NET_BIND_SERVICE CAP_SETFCAP CAP_SETGID CAP_SETPCAP CAP_SETUID CAP_SYS_CHROOT]
+```
+
+## SEE ALSO
+**[podman(1)](podman.1.md)**,**[podman-container(1)](podman-container.1.md)**, **[podman-inspect(1)](podman-inspect.1.md)**
+
+## HISTORY
+Sep 2021, Originally compiled by Dan Walsh <dwalsh@redhat.com>
diff --git a/docs/source/markdown/podman-container.1.md b/docs/source/markdown/podman-container.1.md
index 3cc90d9ec..c950347a9 100644
--- a/docs/source/markdown/podman-container.1.md
+++ b/docs/source/markdown/podman-container.1.md
@@ -24,7 +24,7 @@ The container command allows you to manage containers
| exists | [podman-container-exists(1)](podman-container-exists.1.md) | Check if a container exists in local storage |
| export | [podman-export(1)](podman-export.1.md) | Export a container's filesystem contents as a tar archive. |
| init | [podman-init(1)](podman-init.1.md) | Initialize a container |
-| inspect | [podman-inspect(1)](podman-inspect.1.md) | Display a container or image's configuration. |
+| inspect | [podman-container-inspect(1)](podman-container-inspect.1.md)| Display a container's configuration. |
| kill | [podman-kill(1)](podman-kill.1.md) | Kill the main process in one or more containers. |
| list | [podman-ps(1)](podman-ps.1.md) | List the containers on the system.(alias ls) |
| logs | [podman-logs(1)](podman-logs.1.md) | Display the logs of a container. |
diff --git a/docs/source/markdown/podman-image-inspect.1.md b/docs/source/markdown/podman-image-inspect.1.md
new file mode 100644
index 000000000..a4f81dfc0
--- /dev/null
+++ b/docs/source/markdown/podman-image-inspect.1.md
@@ -0,0 +1,105 @@
+% podman-image-inspect(1)
+
+## NAME
+podman\-image\-inspect - Display an image's configuration
+
+## SYNOPSIS
+**podman image inspect** [*options*] *image* [*image* ...]
+
+## DESCRIPTION
+
+This displays the low-level information on images identified by name or ID. By default, this will render
+all results in a JSON array. If a format is specified, the given template will be executed for each result.
+
+## OPTIONS
+
+#### **--format**, **-f**=*format*
+
+Format the output using the given Go template.
+The keys of the returned JSON can be used as the values for the --format flag (see examples below).
+
+## EXAMPLE
+
+```
+$ podman image inspect fedora
+[
+ {
+ "Id": "37e5619f4a8ca9dbc4d6c0ae7890625674a10dbcfb76201399e2aaddb40da17d",
+ "Digest": "sha256:1b0d4ddd99b1a8c8a80e885aafe6034c95f266da44ead992aab388e6aa91611a",
+ "RepoTags": [
+ "registry.fedoraproject.org/fedora:latest"
+ ],
+ "RepoDigests": [
+ "registry.fedoraproject.org/fedora@sha256:1b0d4ddd99b1a8c8a80e885aafe6034c95f266da44ead992aab388e6aa91611a",
+ "registry.fedoraproject.org/fedora@sha256:b5290db40008aae9272ad3a6bd8070ef7ecd547c3bef014b894c327960acc582"
+ ],
+ "Parent": "",
+ "Comment": "Created by Image Factory",
+ "Created": "2021-08-09T05:48:47Z",
+ "Config": {
+ "Env": [
+ "DISTTAG=f34container",
+ "FGC=f34",
+ "container=oci"
+ ],
+ "Cmd": [
+ "/bin/bash"
+ ],
+ "Labels": {
+ "license": "MIT",
+ "name": "fedora",
+ "vendor": "Fedora Project",
+ "version": "34"
+ }
+ },
+ "Version": "1.10.1",
+ "Author": "",
+ "Architecture": "amd64",
+ "Os": "linux",
+ "Size": 183852302,
+ "VirtualSize": 183852302,
+ "GraphDriver": {
+ "Name": "overlay",
+ "Data": {
+ "UpperDir": "/home/dwalsh/.local/share/containers/storage/overlay/0203e243f1ca4b6bb49371ecd21363212467ec6d7d3fa9f324cd4e78cc6b5fa2/diff",
+ "WorkDir": "/home/dwalsh/.local/share/containers/storage/overlay/0203e243f1ca4b6bb49371ecd21363212467ec6d7d3fa9f324cd4e78cc6b5fa2/work"
+ }
+ },
+ "RootFS": {
+ "Type": "layers",
+ "Layers": [
+ "sha256:0203e243f1ca4b6bb49371ecd21363212467ec6d7d3fa9f324cd4e78cc6b5fa2"
+ ]
+ },
+ "Labels": {
+ "license": "MIT",
+ "name": "fedora",
+ "vendor": "Fedora Project",
+ "version": "34"
+ },
+ "Annotations": {},
+ "ManifestType": "application/vnd.docker.distribution.manifest.v2+json",
+ "User": "",
+ "History": [
+ {
+ "created": "2021-08-09T05:48:47Z",
+ "comment": "Created by Image Factory"
+ }
+ ],
+ "NamesHistory": [
+ "registry.fedoraproject.org/fedora:latest"
+ ]
+ }
+]
+```
+
+```
+$ podman image inspect --format '{{ .Id }}' fedora
+37e5619f4a8ca9dbc4d6c0ae7890625674a10dbcfb76201399e2aaddb40da17d
+```
+
+## SEE ALSO
+**[podman(1)](podman.1.md)**,**[podman-image(1)](podman-image.1.md)**, **[podman-inspect(1)](podman-inspect.1.md)**
+
+## HISTORY
+Sep 2021, Originally compiled by Dan Walsh <dwalsh@redhat.com>
diff --git a/docs/source/markdown/podman-image.1.md b/docs/source/markdown/podman-image.1.md
index 3e6050d99..01024519f 100644
--- a/docs/source/markdown/podman-image.1.md
+++ b/docs/source/markdown/podman-image.1.md
@@ -11,30 +11,30 @@ The image command allows you to manage images
## COMMANDS
-| Command | Man Page | Description |
-| -------- | ----------------------------------------------- | --------------------------------------------------------------------------- |
-| build | [podman-build(1)](podman-build.1.md) | Build a container using a Dockerfile. |
-| diff | [podman-image-diff(1)](podman-image-diff.1.md) | Inspect changes on an image's filesystem. |
-| exists | [podman-image-exists(1)](podman-image-exists.1.md) | Check if an image exists in local storage. |
-| history | [podman-history(1)](podman-history.1.md) | Show the history of an image. |
-| import | [podman-import(1)](podman-import.1.md) | Import a tarball and save it as a filesystem image. |
-| inspect | [podman-inspect(1)](podman-inspect.1.md) | Display an image or image's configuration. |
-| list | [podman-images(1)](podman-images.1.md) | List the container images on the system.(alias ls) |
-| load | [podman-load(1)](podman-load.1.md) | Load an image from the docker archive. |
-| mount | [podman-image-mount(1)](podman-image-mount.1.md) | Mount an image's root filesystem. |
-| prune | [podman-image-prune(1)](podman-image-prune.1.md) | Remove all unused images from the local store. |
-| pull | [podman-pull(1)](podman-pull.1.md) | Pull an image from a registry. |
-| push | [podman-push(1)](podman-push.1.md) | Push an image from local storage to elsewhere. |
-| rm | [podman-rmi(1)](podman-rmi.1.md) | Removes one or more locally stored images. |
-| save | [podman-save(1)](podman-save.1.md) | Save an image to docker-archive or oci. |
-| scp | [podman-image-scp(1)](podman-image-scp.1.md) | Securely copy an image from one host to another. |
-| search | [podman-search(1)](podman-search.1.md) | Search a registry for an image. |
-| sign | [podman-image-sign(1)](podman-image-sign.1.md) | Create a signature for an image. |
-| tag | [podman-tag(1)](podman-tag.1.md) | Add an additional name to a local image. |
-| tree | [podman-image-tree(1)](podman-image-tree.1.md) | Prints layer hierarchy of an image in a tree format. |
-| trust | [podman-image-trust(1)](podman-image-trust.1.md) | Manage container registry image trust policy. |
-| unmount | [podman-image-unmount(1)](podman-image-unmount.1.md) | Unmount an image's root filesystem. |
-| untag | [podman-untag(1)](podman-untag.1.md) | Removes one or more names from a locally-stored image. |
+| Command | Man Page | Description |
+| -------- | --------------------------------------------------- | ----------------------------------------------------------------------- |
+| build | [podman-build(1)](podman-build.1.md) | Build a container using a Dockerfile. |
+| diff | [podman-image-diff(1)](podman-image-diff.1.md) | Inspect changes on an image's filesystem. |
+| exists | [podman-image-exists(1)](podman-image-exists.1.md) | Check if an image exists in local storage. |
+| history | [podman-history(1)](podman-history.1.md) | Show the history of an image. |
+| import | [podman-import(1)](podman-import.1.md) | Import a tarball and save it as a filesystem image. |
+| inspect | [podman-image-inspect(1)](podman-image-inspect.1.md)| Display an image's configuration. |
+| list | [podman-images(1)](podman-images.1.md) | List the container images on the system.(alias ls) |
+| load | [podman-load(1)](podman-load.1.md) | Load an image from the docker archive. |
+| mount | [podman-image-mount(1)](podman-image-mount.1.md) | Mount an image's root filesystem. |
+| prune | [podman-image-prune(1)](podman-image-prune.1.md) | Remove all unused images from the local store. |
+| pull | [podman-pull(1)](podman-pull.1.md) | Pull an image from a registry. |
+| push | [podman-push(1)](podman-push.1.md) | Push an image from local storage to elsewhere. |
+| rm | [podman-rmi(1)](podman-rmi.1.md) | Removes one or more locally stored images. |
+| save | [podman-save(1)](podman-save.1.md) | Save an image to docker-archive or oci. |
+| scp | [podman-image-scp(1)](podman-image-scp.1.md) | Securely copy an image from one host to another. |
+| search | [podman-search(1)](podman-search.1.md) | Search a registry for an image. |
+| sign | [podman-image-sign(1)](podman-image-sign.1.md) | Create a signature for an image. |
+| tag | [podman-tag(1)](podman-tag.1.md) | Add an additional name to a local image. |
+| tree | [podman-image-tree(1)](podman-image-tree.1.md) | Prints layer hierarchy of an image in a tree format. |
+| trust | [podman-image-trust(1)](podman-image-trust.1.md) | Manage container registry image trust policy. |
+| unmount | [podman-image-unmount(1)](podman-image-unmount.1.md) | Unmount an image's root filesystem. |
+| untag | [podman-untag(1)](podman-untag.1.md) | Removes one or more names from a locally-stored image. |
## SEE ALSO
podman
diff --git a/docs/source/markdown/podman-inspect.1.md b/docs/source/markdown/podman-inspect.1.md
index ae26c1bbb..83dc5cbbe 100644
--- a/docs/source/markdown/podman-inspect.1.md
+++ b/docs/source/markdown/podman-inspect.1.md
@@ -14,6 +14,8 @@ all results in a JSON array. If the inspect type is all, the order of inspection
If a format is specified, the given template will be executed for each result.
For more inspection options, see also
+[podman-container-inspect(1)](podman-container-inspect.1.md),
+[podman-image-inspect(1)](podman-image-inspect.1.md),
[podman-network-inspect(1)](podman-network-inspect.1.md),
[podman-pod-inspect(1)](podman-pod-inspect.1.md), and
[podman-volume-inspect(1)](podman-volume-inspect.1.md).
@@ -160,7 +162,7 @@ myNetwork
```
## SEE ALSO
-podman(1)
+**[podman(1)](podman.1.md)**,**[podman-container-inspect(1)](podman-container-inspect.1.md)**,**[podman-image-inspect(1)](podman-image-inspect.1.md)**,**[podman-network-inspect(1)](podman-network-inspect.1.md)**,**[podman-pod-inspect(1)](podman-pod-inspect.1.md)**,**[podman-volume-inspect(1)](podman-volume-inspect.1.md)**.
## HISTORY
July 2017, Originally compiled by Dan Walsh <dwalsh@redhat.com>
diff --git a/docs/source/markdown/podman-machine-init.1.md b/docs/source/markdown/podman-machine-init.1.md
index c864a87ef..1236db602 100644
--- a/docs/source/markdown/podman-machine-init.1.md
+++ b/docs/source/markdown/podman-machine-init.1.md
@@ -47,6 +47,10 @@ Defaults to `testing`.
Memory (in MB).
+#### **--now**
+
+Start the virtual machine immediately after it has been initialized.
+
#### **--help**
Print usage statement.
diff --git a/docs/source/markdown/podman-pod-create.1.md b/docs/source/markdown/podman-pod-create.1.md
index b4c3fc2eb..a1540672c 100644
--- a/docs/source/markdown/podman-pod-create.1.md
+++ b/docs/source/markdown/podman-pod-create.1.md
@@ -38,6 +38,22 @@ Examples of the List Format:
0-4,9 # bits 0, 1, 2, 3, 4, and 9 set
0-2,7,12-14 # bits 0, 1, 2, 7, 12, 13, and 14 set
+#### **--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
+**r** for read, **w** for write, and **m** for **mknod**(2).
+
+Example: **--device=/dev/sdc:/dev/xvdc:rwm**.
+
+Note: if _host_device_ is a symbolic link then it will be resolved first.
+The pod will only store the major and minor numbers of the host device.
+
+Note: the pod implements devices by storing the initial configuration passed by the user and recreating the device on each container added to the pod.
+
+Podman may load kernel modules required for using the specified
+device. The devices that Podman will load modules for when necessary are:
+/dev/fuse.
#### **--dns**=*ipaddr*
diff --git a/docs/source/markdown/podman-pod-inspect.1.md b/docs/source/markdown/podman-pod-inspect.1.md
index 1f4e6cb06..0c58b099e 100644
--- a/docs/source/markdown/podman-pod-inspect.1.md
+++ b/docs/source/markdown/podman-pod-inspect.1.md
@@ -70,7 +70,7 @@ Valid placeholders for the Go template are listed below:
```
## SEE ALSO
-podman-pod(1), podman-pod-ps(1)
+**[podman(1)](podman.1.md)**,**[podman-pod(1)](podman-pod.1.md)**, **[podman-inspect(1)](podman-inspect.1.md)**
## HISTORY
August 2018, Originally compiled by Brent Baude <bbaude@redhat.com>
diff --git a/docs/source/markdown/podman-system-service.1.md b/docs/source/markdown/podman-system-service.1.md
index dfb026de1..3bc4fc7f1 100644
--- a/docs/source/markdown/podman-system-service.1.md
+++ b/docs/source/markdown/podman-system-service.1.md
@@ -30,6 +30,9 @@ Note: The default systemd unit files (system and user) change the log-level opti
The time until the session expires in _seconds_. The default is 5
seconds. A value of `0` means no timeout, therefore the session will not expire.
+The default timeout can be changed via the `service_timeout=VALUE` field in containers.conf.
+See **[containers.conf(5)](https://github.com/containers/common/blob/master/docs/containers.conf.5.md)** for more information.
+
#### **--cors**
CORS headers to inject to the HTTP response. The default value is empty string which disables CORS headers.
@@ -46,7 +49,7 @@ podman system service --time 5
```
## SEE ALSO
-podman(1), podman-system-service(1), podman-system-connection(1)
+**[podman(1)](podman.1.md)**, **[podman-system-connection(1)](podman-system-connection.1.md)**, **[containers.conf(5)](https://github.com/containers/common/blob/master/docs/containers.conf.5.md)**
## HISTORY
January 2020, Originally compiled by Brent Baude `<bbaude@redhat.com>`
diff --git a/docs/source/markdown/podman-volume-inspect.1.md b/docs/source/markdown/podman-volume-inspect.1.md
index ea0ee91b4..4595ccda6 100644
--- a/docs/source/markdown/podman-volume-inspect.1.md
+++ b/docs/source/markdown/podman-volume-inspect.1.md
@@ -40,7 +40,7 @@ $ podman volume inspect --format "{{.Driver}} {{.Scope}}" myvol
```
## SEE ALSO
-podman-volume(1)
+**[podman(1)](podman.1.md)**,**[podman-volume(1)](podman-volume.1.md)**, **[podman-inspect(1)](podman-inspect.1.md)**
## HISTORY
November 2018, Originally compiled by Urvashi Mohnani <umohnani@redhat.com>
diff --git a/libpod/container.go b/libpod/container.go
index cf727926c..7d602326e 100644
--- a/libpod/container.go
+++ b/libpod/container.go
@@ -278,6 +278,11 @@ func (c *Container) Config() *ContainerConfig {
return returnConfig
}
+// DeviceHostSrc returns the user supplied device to be passed down in the pod
+func (c *Container) DeviceHostSrc() []spec.LinuxDevice {
+ return c.config.DeviceHostSrc
+}
+
// Runtime returns the container's Runtime.
func (c *Container) Runtime() *Runtime {
return c.runtime
diff --git a/libpod/container_config.go b/libpod/container_config.go
index 0374c25fe..54d102a71 100644
--- a/libpod/container_config.go
+++ b/libpod/container_config.go
@@ -381,6 +381,8 @@ type ContainerMiscConfig struct {
PidFile string `json:"pid_file,omitempty"`
// CDIDevices contains devices that use the CDI
CDIDevices []string `json:"cdiDevices,omitempty"`
+ // DeviceHostSrc contains the original source on the host
+ DeviceHostSrc []spec.LinuxDevice `json:"device_host_src,omitempty"`
// EnvSecrets are secrets that are set as environment variables
EnvSecrets map[string]*secrets.Secret `json:"secret_env,omitempty"`
// InitContainerType specifies if the container is an initcontainer
diff --git a/libpod/container_inspect.go b/libpod/container_inspect.go
index 530160b2d..e65c86cef 100644
--- a/libpod/container_inspect.go
+++ b/libpod/container_inspect.go
@@ -819,27 +819,10 @@ func (c *Container) generateInspectContainerHostConfig(ctrSpec *spec.Spec, named
// Devices
// Do not include if privileged - assumed that all devices will be
// included.
- hostConfig.Devices = []define.InspectDevice{}
- if ctrSpec.Linux != nil && !hostConfig.Privileged {
- for _, dev := range ctrSpec.Linux.Devices {
- 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.Warnf("Could not locate device %s on host", key)
- continue
- }
- newDev := define.InspectDevice{}
- newDev.PathOnHost = path
- newDev.PathInContainer = dev.Path
- hostConfig.Devices = append(hostConfig.Devices, newDev)
- }
+ var err error
+ hostConfig.Devices, err = c.GetDevices(*&hostConfig.Privileged, *ctrSpec, deviceNodes)
+ if err != nil {
+ return nil, err
}
// Ulimits
@@ -885,3 +868,29 @@ func (c *Container) inHostPidNS() (bool, error) {
}
return true, nil
}
+
+func (c *Container) GetDevices(priv bool, ctrSpec spec.Spec, deviceNodes map[string]string) ([]define.InspectDevice, error) {
+ devices := []define.InspectDevice{}
+ if ctrSpec.Linux != nil && !priv {
+ for _, dev := range ctrSpec.Linux.Devices {
+ 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.Warnf("Could not locate device %s on host", key)
+ continue
+ }
+ newDev := define.InspectDevice{}
+ newDev.PathOnHost = path
+ newDev.PathInContainer = dev.Path
+ devices = append(devices, newDev)
+ }
+ }
+ return devices, nil
+}
diff --git a/libpod/container_internal_linux.go b/libpod/container_internal_linux.go
index 6ebbfd1f3..0a663200a 100644
--- a/libpod/container_internal_linux.go
+++ b/libpod/container_internal_linux.go
@@ -369,13 +369,46 @@ func (c *Container) generateSpec(ctx context.Context) (*spec.Spec, error) {
if err != nil {
return nil, err
}
- volMount := spec.Mount{
- Type: "bind",
- Source: mountPoint,
- Destination: namedVol.Dest,
- Options: namedVol.Options,
+
+ overlayFlag := false
+ for _, o := range namedVol.Options {
+ if o == "O" {
+ overlayFlag = true
+ }
+ }
+
+ if overlayFlag {
+ contentDir, err := overlay.TempDir(c.config.StaticDir, c.RootUID(), c.RootGID())
+ if err != nil {
+ return nil, err
+ }
+ overlayMount, err := overlay.Mount(contentDir, mountPoint, namedVol.Dest, c.RootUID(), c.RootGID(), c.runtime.store.GraphOptions())
+ if err != nil {
+ return nil, errors.Wrapf(err, "mounting overlay failed %q", mountPoint)
+ }
+
+ for _, o := range namedVol.Options {
+ switch o {
+ case "U":
+ if err := chown.ChangeHostPathOwnership(mountPoint, true, int(hostUID), int(hostGID)); err != nil {
+ return nil, err
+ }
+
+ if err := chown.ChangeHostPathOwnership(contentDir, true, int(hostUID), int(hostGID)); err != nil {
+ return nil, err
+ }
+ }
+ }
+ g.AddMount(overlayMount)
+ } else {
+ volMount := spec.Mount{
+ Type: "bind",
+ Source: mountPoint,
+ Destination: namedVol.Dest,
+ Options: namedVol.Options,
+ }
+ g.AddMount(volMount)
}
- g.AddMount(volMount)
}
// Check if the spec file mounts contain the options z, Z or U.
@@ -2050,35 +2083,39 @@ func (c *Container) getHosts() string {
}
}
- // Add gateway entry
- var depCtr *Container
- netStatus := c.getNetworkStatus()
- if c.config.NetNsCtr != "" {
- // ignoring the error because there isn't anything to do
- depCtr, _ = c.getRootNetNsDepCtr()
- } else if len(netStatus) != 0 {
- depCtr = c
- }
-
- if depCtr != nil {
- for _, status := range depCtr.getNetworkStatus() {
- for _, netInt := range status.Interfaces {
- for _, netAddress := range netInt.Networks {
- if netAddress.Gateway != nil {
- hosts += fmt.Sprintf("%s host.containers.internal\n", netAddress.Gateway.String())
+ // Add gateway entry if we are not in a machine. If we use podman machine
+ // the gvproxy dns server will take care of host.containers.internal.
+ // https://github.com/containers/gvisor-tap-vsock/commit/1108ea45162281046d239047a6db9bc187e64b08
+ if !c.runtime.config.Engine.MachineEnabled {
+ var depCtr *Container
+ netStatus := c.getNetworkStatus()
+ if c.config.NetNsCtr != "" {
+ // ignoring the error because there isn't anything to do
+ depCtr, _ = c.getRootNetNsDepCtr()
+ } else if len(netStatus) != 0 {
+ depCtr = c
+ }
+
+ if depCtr != nil {
+ for _, status := range depCtr.getNetworkStatus() {
+ for _, netInt := range status.Interfaces {
+ for _, netAddress := range netInt.Networks {
+ if netAddress.Gateway != nil {
+ hosts += fmt.Sprintf("%s host.containers.internal\n", netAddress.Gateway.String())
+ }
}
}
}
- }
- } else if c.config.NetMode.IsSlirp4netns() {
- gatewayIP, err := GetSlirp4netnsGateway(c.slirp4netnsSubnet)
- if err != nil {
- logrus.Warn("failed to determine gatewayIP: ", err.Error())
+ } else if c.config.NetMode.IsSlirp4netns() {
+ gatewayIP, err := GetSlirp4netnsGateway(c.slirp4netnsSubnet)
+ if err != nil {
+ logrus.Warn("failed to determine gatewayIP: ", err.Error())
+ } else {
+ hosts += fmt.Sprintf("%s host.containers.internal\n", gatewayIP.String())
+ }
} else {
- hosts += fmt.Sprintf("%s host.containers.internal\n", gatewayIP.String())
+ logrus.Debug("network configuration does not support host.containers.internal address")
}
- } else {
- logrus.Debug("network configuration does not support host.containers.internal address")
}
return hosts
diff --git a/libpod/define/pod_inspect.go b/libpod/define/pod_inspect.go
index b7a6e76b5..e78d97850 100644
--- a/libpod/define/pod_inspect.go
+++ b/libpod/define/pod_inspect.go
@@ -59,6 +59,8 @@ type InspectPodData struct {
CPUSetCPUs string `json:"cpuset_cpus,omitempty"`
// Mounts contains volume related information for the pod
Mounts []InspectMount `json:"mounts,omitempty"`
+ // Devices contains the specified host devices
+ Devices []InspectDevice `json:"devices,omitempty"`
}
// InspectPodInfraConfig contains the configuration of the pod's infra
diff --git a/libpod/kube.go b/libpod/kube.go
index 54e8a7c50..9b96dd99d 100644
--- a/libpod/kube.go
+++ b/libpod/kube.go
@@ -11,6 +11,7 @@ import (
"github.com/containers/podman/v3/libpod/define"
"github.com/containers/podman/v3/libpod/network/types"
+ "github.com/containers/podman/v3/pkg/env"
"github.com/containers/podman/v3/pkg/lookup"
"github.com/containers/podman/v3/pkg/namespaces"
"github.com/containers/podman/v3/pkg/specgen"
@@ -570,12 +571,16 @@ func ocicniPortMappingToContainerPort(portMappings []types.OCICNIPortMapping) ([
// libpodEnvVarsToKubeEnvVars converts a key=value string slice to []v1.EnvVar
func libpodEnvVarsToKubeEnvVars(envs []string) ([]v1.EnvVar, error) {
+ defaultEnv := env.DefaultEnvVariables()
envVars := make([]v1.EnvVar, 0, len(envs))
for _, e := range envs {
split := strings.SplitN(e, "=", 2)
if len(split) != 2 {
return envVars, errors.Errorf("environment variable %s is malformed; should be key=value", e)
}
+ if defaultEnv[split[0]] == split[1] {
+ continue
+ }
ev := v1.EnvVar{
Name: split[0],
Value: split[1],
diff --git a/libpod/options.go b/libpod/options.go
index 3f6ccf1cb..a80f51c6a 100644
--- a/libpod/options.go
+++ b/libpod/options.go
@@ -21,6 +21,7 @@ import (
"github.com/containers/podman/v3/pkg/util"
"github.com/containers/storage"
"github.com/containers/storage/pkg/idtools"
+ "github.com/opencontainers/runtime-spec/specs-go"
"github.com/opencontainers/runtime-tools/generate"
"github.com/pkg/errors"
"github.com/sirupsen/logrus"
@@ -1809,6 +1810,17 @@ func WithInitCtrType(containerType string) CtrCreateOption {
}
}
+// WithHostDevice adds the original host src to the config
+func WithHostDevice(dev []specs.LinuxDevice) CtrCreateOption {
+ return func(ctr *Container) error {
+ if ctr.valid {
+ return define.ErrCtrFinalized
+ }
+ ctr.config.DeviceHostSrc = dev
+ return nil
+ }
+}
+
// Pod Creation Options
// WithPodCreateCommand adds the full command plus arguments of the current
diff --git a/libpod/pod_api.go b/libpod/pod_api.go
index 4e0acf950..ff818edc2 100644
--- a/libpod/pod_api.go
+++ b/libpod/pod_api.go
@@ -583,6 +583,7 @@ func (p *Pod) Inspect() (*define.InspectPodData, error) {
// container.
var infraConfig *define.InspectPodInfraConfig
var inspectMounts []define.InspectMount
+ var devices []define.InspectDevice
if p.state.InfraContainerID != "" {
infra, err := p.runtime.GetContainer(p.state.InfraContainerID)
if err != nil {
@@ -604,6 +605,12 @@ func (p *Pod) Inspect() (*define.InspectPodData, error) {
return nil, err
}
+ var nodes map[string]string
+ devices, err = infra.GetDevices(false, *infra.config.Spec, nodes)
+ if err != nil {
+ return nil, err
+ }
+
if len(infra.Config().ContainerNetworkConfig.DNSServer) > 0 {
infraConfig.DNSServer = make([]string, 0, len(infra.Config().ContainerNetworkConfig.DNSServer))
for _, entry := range infra.Config().ContainerNetworkConfig.DNSServer {
@@ -652,6 +659,7 @@ func (p *Pod) Inspect() (*define.InspectPodData, error) {
CPUPeriod: p.CPUPeriod(),
CPUQuota: p.CPUQuota(),
Mounts: inspectMounts,
+ Devices: devices,
}
return &inspectData, nil
diff --git a/pkg/api/handlers/libpod/pods.go b/pkg/api/handlers/libpod/pods.go
index 1f03e121e..9f46ecc52 100644
--- a/pkg/api/handlers/libpod/pods.go
+++ b/pkg/api/handlers/libpod/pods.go
@@ -41,8 +41,8 @@ func PodCreate(w http.ResponseWriter, r *http.Request) {
return
}
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)
+ infraOptions := &entities.ContainerCreateOptions{ImageVolume: "bind", IsInfra: true, Net: &entities.NetOptions{}, Devices: psg.Devices} // 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
diff --git a/pkg/domain/entities/pods.go b/pkg/domain/entities/pods.go
index a74725c63..f0c88d77e 100644
--- a/pkg/domain/entities/pods.go
+++ b/pkg/domain/entities/pods.go
@@ -112,26 +112,28 @@ type PodSpec struct {
PodSpecGen specgen.PodSpecGenerator
}
-// PodCreateOptions provides all possible options for creating a pod and its infra container
+// PodCreateOptions provides all possible options for creating a pod and its infra container.
+// The JSON tags below are made to match the respective field in ContainerCreateOptions for the purpose of mapping.
// swagger:model PodCreateOptions
type PodCreateOptions struct {
- CGroupParent string
- CreateCommand []string
- Hostname string
- Infra bool
- InfraImage string
- InfraName string
- InfraCommand string
- InfraConmonPidFile string
- Labels map[string]string
- Name string
- Net *NetOptions
- Share []string
- Pid string
- Cpus float64
- CpusetCpus string
- Userns specgen.Namespace
- Volume []string
+ CGroupParent string `json:"cgroup_parent,omitempty"`
+ CreateCommand []string `json:"create_command,omitempty"`
+ Devices []string `json:"devices,omitempty"`
+ Hostname string `json:"hostname,omitempty"`
+ Infra bool `json:"infra,omitempty"`
+ InfraImage string `json:"infra_image,omitempty"`
+ InfraName string `json:"container_name,omitempty"`
+ InfraCommand *string `json:"container_command,omitempty"`
+ InfraConmonPidFile string `json:"container_conmon_pidfile,omitempty"`
+ Labels map[string]string `json:"labels,omitempty"`
+ Name string `json:"name,omitempty"`
+ Net *NetOptions `json:"net,omitempty"`
+ Share []string `json:"share,omitempty"`
+ Pid string `json:"pid,omitempty"`
+ Cpus float64 `json:"cpus,omitempty"`
+ CpusetCpus string `json:"cpuset_cpus,omitempty"`
+ Userns specgen.Namespace `json:"-"`
+ Volume []string `json:"volume,omitempty"`
}
// PodLogsOptions describes the options to extract pod logs.
@@ -152,24 +154,24 @@ type ContainerCreateOptions struct {
CapDrop []string
CgroupNS string
CGroupsMode string
- CGroupParent string
+ CGroupParent string `json:"cgroup_parent,omitempty"`
CIDFile string
- ConmonPIDFile string
+ ConmonPIDFile string `json:"container_conmon_pidfile,omitempty"`
CPUPeriod uint64
CPUQuota int64
CPURTPeriod uint64
CPURTRuntime int64
CPUShares uint64
- CPUS float64
- CPUSetCPUs string
+ CPUS float64 `json:"cpus,omitempty"`
+ CPUSetCPUs string `json:"cpuset_cpus,omitempty"`
CPUSetMems string
- Devices []string
+ Devices []string `json:"devices,omitempty"`
DeviceCGroupRule []string
DeviceReadBPs []string
DeviceReadIOPs []string
DeviceWriteBPs []string
DeviceWriteIOPs []string
- Entrypoint *string
+ Entrypoint *string `json:"container_command,omitempty"`
Env []string
EnvHost bool
EnvFile []string
@@ -181,7 +183,7 @@ type ContainerCreateOptions struct {
HealthRetries uint
HealthStartPeriod string
HealthTimeout string
- Hostname string
+ Hostname string `json:"hostname,omitempty"`
HTTPProxy bool
ImageVolume string
Init bool
@@ -198,14 +200,14 @@ type ContainerCreateOptions struct {
MemoryReservation string
MemorySwap string
MemorySwappiness int64
- Name string
+ Name string `json:"container_name,omitempty"`
NoHealthCheck bool
OOMKillDisable bool
OOMScoreAdj int
Arch string
OS string
Variant string
- PID string
+ PID string `json:"pid,omitempty"`
PIDsLimit *int64
Platform string
Pod string
@@ -244,17 +246,17 @@ type ContainerCreateOptions struct {
UIDMap []string
Ulimit []string
User string
- UserNS string
+ UserNS string `json:"-"`
UTS string
Mount []string
- Volume []string
+ Volume []string `json:"volume,omitempty"`
VolumesFrom []string
Workdir string
SeccompPolicy string
PidFile string
IsInfra bool
- Net *NetOptions
+ Net *NetOptions `json:"net,omitempty"`
CgroupConf []string
}
@@ -294,9 +296,10 @@ func ToPodSpecGen(s specgen.PodSpecGenerator, p *PodCreateOptions) (*specgen.Pod
s.Pid = out
s.Hostname = p.Hostname
s.Labels = p.Labels
+ s.Devices = p.Devices
s.NoInfra = !p.Infra
- if len(p.InfraCommand) > 0 {
- s.InfraCommand = strings.Split(p.InfraCommand, " ")
+ if p.InfraCommand != nil && len(*p.InfraCommand) > 0 {
+ s.InfraCommand = strings.Split(*p.InfraCommand, " ")
}
if len(p.InfraConmonPidFile) > 0 {
s.InfraConmonPidFile = p.InfraConmonPidFile
diff --git a/pkg/env/env.go b/pkg/env/env.go
index 0d55e5560..ecd2d62a5 100644
--- a/pkg/env/env.go
+++ b/pkg/env/env.go
@@ -17,8 +17,9 @@ const whiteSpaces = " \t"
// DefaultEnvVariables returns a default environment, with $PATH and $TERM set.
func DefaultEnvVariables() map[string]string {
return map[string]string{
- "PATH": "/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin",
- "TERM": "xterm",
+ "PATH": "/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin",
+ "TERM": "xterm",
+ "container": "podman",
}
}
diff --git a/pkg/specgen/generate/config_linux.go b/pkg/specgen/generate/config_linux.go
index 6b9e9c4bf..2d1e2b288 100644
--- a/pkg/specgen/generate/config_linux.go
+++ b/pkg/specgen/generate/config_linux.go
@@ -132,7 +132,6 @@ func DevicesFromPath(g *generate.Generator, devicePath string) error {
}
return nil
}
-
return addDevice(g, strings.Join(append([]string{resolvedDevicePath}, devs[1:]...), ":"))
}
diff --git a/pkg/specgen/generate/container_create.go b/pkg/specgen/generate/container_create.go
index 91230338e..fefa9b4a9 100644
--- a/pkg/specgen/generate/container_create.go
+++ b/pkg/specgen/generate/container_create.go
@@ -30,24 +30,27 @@ func MakeContainer(ctx context.Context, rt *libpod.Runtime, s *specgen.SpecGener
// If joining a pod, retrieve the pod for use, and its infra container
var pod *libpod.Pod
- var cont *libpod.Container
- var config *libpod.ContainerConfig
+ var infraConfig *libpod.ContainerConfig
if s.Pod != "" {
pod, err = rt.LookupPod(s.Pod)
if err != nil {
return nil, nil, nil, errors.Wrapf(err, "error retrieving pod %s", s.Pod)
}
if pod.HasInfraContainer() {
- cont, err = pod.InfraContainer()
+ infra, err := pod.InfraContainer()
if err != nil {
return nil, nil, nil, err
}
- config = cont.Config()
+ infraConfig = infra.Config()
}
}
- if config != nil && (len(config.NamedVolumes) > 0 || len(config.UserVolumes) > 0 || len(config.ImageVolumes) > 0 || len(config.OverlayVolumes) > 0) {
- s.VolumesFrom = append(s.VolumesFrom, config.ID)
+ if infraConfig != nil && (len(infraConfig.NamedVolumes) > 0 || len(infraConfig.UserVolumes) > 0 || len(infraConfig.ImageVolumes) > 0 || len(infraConfig.OverlayVolumes) > 0) {
+ s.VolumesFrom = append(s.VolumesFrom, infraConfig.ID)
+ }
+
+ if infraConfig != nil && len(infraConfig.Spec.Linux.Devices) > 0 {
+ s.DevicesFrom = append(s.DevicesFrom, infraConfig.ID)
}
// Set defaults for unset namespaces
if s.PidNS.IsDefault() {
@@ -166,6 +169,16 @@ func MakeContainer(ctx context.Context, rt *libpod.Runtime, s *specgen.SpecGener
logrus.Debugf("setting container name %s", s.Name)
options = append(options, libpod.WithName(s.Name))
}
+ if len(s.DevicesFrom) > 0 {
+ for _, dev := range s.DevicesFrom {
+ ctr, err := rt.GetContainer(dev)
+ if err != nil {
+ return nil, nil, nil, err
+ }
+ devices := ctr.DeviceHostSrc()
+ s.Devices = append(s.Devices, devices...)
+ }
+ }
if len(s.Devices) > 0 {
opts = extractCDIDevices(s)
options = append(options, opts...)
@@ -174,6 +187,9 @@ func MakeContainer(ctx context.Context, rt *libpod.Runtime, s *specgen.SpecGener
if err != nil {
return nil, nil, nil, err
}
+ if len(s.HostDeviceList) > 0 {
+ options = append(options, libpod.WithHostDevice(s.HostDeviceList))
+ }
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) {
diff --git a/pkg/specgen/generate/oci.go b/pkg/specgen/generate/oci.go
index 80c7f112f..55010f716 100644
--- a/pkg/specgen/generate/oci.go
+++ b/pkg/specgen/generate/oci.go
@@ -301,8 +301,8 @@ func SpecGenToOCI(ctx context.Context, s *specgen.SpecGenerator, rt *libpod.Runt
g.AddProcessEnv("container", "podman")
g.Config.Linux.Resources = s.ResourceLimits
-
// Devices
+
if s.Privileged {
// If privileged, we need to add all the host devices to the
// spec. We do not add the user provided ones because we are
@@ -313,17 +313,18 @@ func SpecGenToOCI(ctx context.Context, s *specgen.SpecGenerator, rt *libpod.Runt
} else {
// add default devices from containers.conf
for _, device := range rtc.Containers.Devices {
- if err := DevicesFromPath(&g, device); err != nil {
+ if err = DevicesFromPath(&g, device); err != nil {
return nil, err
}
}
// add default devices specified by caller
for _, device := range s.Devices {
- if err := DevicesFromPath(&g, device.Path); err != nil {
+ if err = DevicesFromPath(&g, device.Path); err != nil {
return nil, err
}
}
}
+ s.HostDeviceList = s.Devices
for _, dev := range s.DeviceCGroupRule {
g.AddLinuxResourcesDevice(true, dev.Type, dev.Major, dev.Minor, dev.Access)
diff --git a/pkg/specgen/podspecgen.go b/pkg/specgen/podspecgen.go
index 5f72fc47d..83fa9426c 100644
--- a/pkg/specgen/podspecgen.go
+++ b/pkg/specgen/podspecgen.go
@@ -88,6 +88,8 @@ type PodBasicConfig struct {
// Image volumes bind-mount a container-image mount into the pod's infra container.
// Optional.
ImageVolumes []*ImageVolume `json:"image_volumes,omitempty"`
+ // Devices contains user specified Devices to be added to the Pod
+ Devices []string `json:"pod_devices,omitempty"`
}
// PodNetworkConfig contains networking configuration for a pod.
diff --git a/pkg/specgen/specgen.go b/pkg/specgen/specgen.go
index e0609c5bc..7aa27487a 100644
--- a/pkg/specgen/specgen.go
+++ b/pkg/specgen/specgen.go
@@ -254,6 +254,10 @@ type ContainerStorageConfig struct {
// DeviceCGroupRule are device cgroup rules that allow containers
// to use additional types of devices.
DeviceCGroupRule []spec.LinuxDeviceCgroup `json:"device_cgroup_rule,omitempty"`
+ // DevicesFrom is a way to ensure your container inherits device specific information from another container
+ DevicesFrom []string `json:"devices_from,omitempty"`
+ // HostDeviceList is used to recreate the mounted device on inherited containers
+ HostDeviceList []spec.LinuxDevice `json:"host_device_list,omitempty"`
// IpcNS is the container's IPC namespace.
// Default is private.
// Conflicts with ShmSize if not set to private.
diff --git a/test/e2e/config/containers.conf b/test/e2e/config/containers.conf
index bbd712254..c33f32ab4 100644
--- a/test/e2e/config/containers.conf
+++ b/test/e2e/config/containers.conf
@@ -59,6 +59,7 @@ no_hosts=true
[engine]
network_cmd_options=["allow_host_loopback=true"]
+service_timeout=1234
# We need to ensure each test runs on a separate plugin instance...
# For now, let's just make a bunch of plugin paths and have each test use one.
diff --git a/test/e2e/containers_conf_test.go b/test/e2e/containers_conf_test.go
index f5e85e723..fac200c3c 100644
--- a/test/e2e/containers_conf_test.go
+++ b/test/e2e/containers_conf_test.go
@@ -444,4 +444,12 @@ var _ = Describe("Podman run", func() {
Expect(session).Should(Exit(0))
Expect(session.ErrorToString()).To(ContainSubstring("invalid image_copy_tmp_dir"))
})
+
+ It("podman system sevice --help shows (default 20)", func() {
+ SkipIfRemote("this test is only for local")
+ result := podmanTest.Podman([]string{"system", "service", "--help"})
+ result.WaitWithDefaultTimeout()
+ Expect(result).Should(Exit(0))
+ Expect(result.OutputToString()).To(ContainSubstring("(default 1234)"))
+ })
})
diff --git a/test/e2e/play_kube_test.go b/test/e2e/play_kube_test.go
index fcda89fbc..0d5b9d52c 100644
--- a/test/e2e/play_kube_test.go
+++ b/test/e2e/play_kube_test.go
@@ -63,12 +63,6 @@ spec:
- -d
- "1.5"
env:
- - name: PATH
- value: /usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin
- - name: TERM
- value: xterm
- - name: container
- value: podman
- name: HOSTNAME
value: label-pod
image: quay.io/libpod/alpine:latest
@@ -171,12 +165,6 @@ spec:
- -d
- "1.5"
env:
- - name: PATH
- value: /usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin
- - name: TERM
- value: xterm
- - name: container
- value: podman
- name: HOSTNAME
value: label-pod
image: quay.io/libpod/alpine:latest
@@ -287,13 +275,7 @@ spec:
- {{.}}
{{ end }}
env:
- - name: PATH
- value: /usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin
- - name: TERM
- value: xterm
- name: HOSTNAME
- - name: container
- value: podman
{{ range .Env }}
- name: {{ .Name }}
{{ if (eq .ValueFrom "configmap") }}
@@ -453,13 +435,7 @@ spec:
- {{.}}
{{ end }}
env:
- - name: PATH
- value: /usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin
- - name: TERM
- value: xterm
- name: HOSTNAME
- - name: container
- value: podman
image: {{ .Image }}
name: {{ .Name }}
imagePullPolicy: {{ .PullPolicy }}
diff --git a/test/e2e/pod_create_test.go b/test/e2e/pod_create_test.go
index 7d40d36dd..76a05fa0f 100644
--- a/test/e2e/pod_create_test.go
+++ b/test/e2e/pod_create_test.go
@@ -881,6 +881,25 @@ ENTRYPOINT ["sleep","99999"]
ctr3 := podmanTest.Podman([]string{"run", "--pod", podName, ALPINE, "cat", "/tmp1/test"})
ctr3.WaitWithDefaultTimeout()
Expect(ctr3.OutputToString()).To(ContainSubstring("hello"))
+ })
+
+ It("podman pod create --device", func() {
+ SkipIfRootless("Cannot create devices in /dev in rootless mode")
+ Expect(os.MkdirAll("/dev/foodevdir", os.ModePerm)).To(BeNil())
+ defer os.RemoveAll("/dev/foodevdir")
+
+ mknod := SystemExec("mknod", []string{"/dev/foodevdir/null", "c", "1", "3"})
+ mknod.WaitWithDefaultTimeout()
+ Expect(mknod).Should(Exit(0))
+
+ podName := "testPod"
+ session := podmanTest.Podman([]string{"pod", "create", "--device", "/dev/foodevdir:/dev/bar", "--name", podName})
+ session.WaitWithDefaultTimeout()
+ Expect(session).Should(Exit(0))
+ session = podmanTest.Podman([]string{"run", "-q", "--pod", podName, ALPINE, "stat", "-c%t:%T", "/dev/bar/null"})
+ session.WaitWithDefaultTimeout()
+ Expect(session).Should(Exit(0))
+ Expect(session.OutputToString()).To(Equal("1:3"))
})
diff --git a/test/e2e/ps_test.go b/test/e2e/ps_test.go
index aeb88e481..010885dd5 100644
--- a/test/e2e/ps_test.go
+++ b/test/e2e/ps_test.go
@@ -6,7 +6,6 @@ import (
"regexp"
"sort"
"strconv"
- "strings"
. "github.com/containers/podman/v3/test/utils"
"github.com/containers/storage/pkg/stringid"
@@ -187,7 +186,10 @@ var _ = Describe("Podman ps", func() {
result.WaitWithDefaultTimeout()
result.WaitWithDefaultTimeout()
Expect(result).Should(Exit(0))
- Expect(result.OutputToString()).To(ContainSubstring("bravo"))
+
+ actual := result.OutputToString()
+ Expect(actual).To(ContainSubstring("bravo"))
+ Expect(actual).To(ContainSubstring("NAMES"))
})
It("podman ps --filter network=container:<id>", func() {
@@ -206,7 +208,9 @@ var _ = Describe("Podman ps", func() {
result.WaitWithDefaultTimeout()
result.WaitWithDefaultTimeout()
Expect(result).Should(Exit(0))
- Expect(result.OutputToString()).To(ContainSubstring("second"))
+ actual := result.OutputToString()
+ Expect(actual).To(ContainSubstring("second"))
+ Expect(actual).ToNot(ContainSubstring("table"))
})
It("podman ps namespace flag", func() {
@@ -228,7 +232,7 @@ var _ = Describe("Podman ps", func() {
result.WaitWithDefaultTimeout()
Expect(result).Should(Exit(0))
// it must contains `::` when some ns is null. If it works normally, it should be "$num1:$num2:$num3"
- Expect(result.OutputToString()).To(Not(ContainSubstring(`::`)))
+ Expect(result.OutputToString()).ToNot(ContainSubstring(`::`))
})
It("podman ps with no containers is valid json format", func() {
@@ -285,11 +289,14 @@ var _ = Describe("Podman ps", func() {
result := podmanTest.Podman([]string{"ps", "-a", "--format", "table {{.ID}} {{.Image}} {{.ImageID}} {{.Labels}}"})
result.WaitWithDefaultTimeout()
-
- Expect(result.OutputToStringArray()[0]).ToNot(ContainSubstring("table"))
- Expect(result.OutputToStringArray()[0]).ToNot(ContainSubstring("ImageID"))
- Expect(result.OutputToStringArray()[0]).To(ContainSubstring("alpine:latest"))
Expect(result).Should(Exit(0))
+
+ Expect(result.OutputToString()).ToNot(ContainSubstring("table"))
+
+ actual := result.OutputToStringArray()
+ Expect(actual[0]).To(ContainSubstring("CONTAINER ID"))
+ Expect(actual[0]).ToNot(ContainSubstring("ImageID"))
+ Expect(actual[1]).To(ContainSubstring("alpine:latest"))
})
It("podman ps ancestor filter flag", func() {
@@ -380,7 +387,9 @@ var _ = Describe("Podman ps", func() {
psFilter.WaitWithDefaultTimeout()
Expect(psFilter).Should(Exit(0))
- Expect(strings.Contains(psFilter.OutputToString(), ctrName)).To(BeFalse())
+ actual := psFilter.OutputToString()
+ Expect(actual).ToNot(ContainSubstring(ctrName))
+ Expect(actual).ToNot(ContainSubstring("NAMES"))
})
It("podman ps mutually exclusive flags", func() {
@@ -453,14 +462,13 @@ var _ = Describe("Podman ps", func() {
Expect(session).Should(Exit(0))
session = podmanTest.Podman([]string{"ps", "-a", "--sort=command", "--format", "{{.Command}}"})
-
session.WaitWithDefaultTimeout()
Expect(session).Should(Exit(0))
- sortedArr := session.OutputToStringArray()
+ Expect(session.OutputToString()).ToNot(ContainSubstring("COMMAND"))
+ sortedArr := session.OutputToStringArray()
Expect(sort.SliceIsSorted(sortedArr, func(i, j int) bool { return sortedArr[i] < sortedArr[j] })).To(BeTrue())
-
})
It("podman --pod", func() {
@@ -474,7 +482,7 @@ var _ = Describe("Podman ps", func() {
session = podmanTest.Podman([]string{"ps", "--no-trunc"})
session.WaitWithDefaultTimeout()
Expect(session).Should(Exit(0))
- Expect(session.OutputToString()).To(Not(ContainSubstring(podid)))
+ Expect(session.OutputToString()).ToNot(ContainSubstring(podid))
session = podmanTest.Podman([]string{"ps", "--pod", "--no-trunc"})
session.WaitWithDefaultTimeout()
@@ -510,7 +518,11 @@ var _ = Describe("Podman ps", func() {
session = podmanTest.Podman([]string{"ps", "--format", "{{.Ports}}"})
session.WaitWithDefaultTimeout()
- Expect(session.OutputToString()).To(ContainSubstring("0.0.0.0:2000-2006"))
+ Expect(session).To(Exit(0))
+
+ actual := session.OutputToString()
+ Expect(actual).To(ContainSubstring("0.0.0.0:2000-2006"))
+ Expect(actual).ToNot(ContainSubstring("PORT"))
})
It("podman ps test with invalid port range", func() {
@@ -628,7 +640,10 @@ var _ = Describe("Podman ps", func() {
result := podmanTest.Podman([]string{"ps", "-a", "--format", "{{.RunningFor}}"})
result.WaitWithDefaultTimeout()
Expect(result).Should(Exit(0))
- Expect(result.OutputToString()).To(ContainSubstring("ago"))
+
+ actual := result.OutputToString()
+ Expect(actual).To(ContainSubstring("ago"))
+ Expect(actual).ToNot(ContainSubstring("RUNNING FOR"))
})
It("podman ps filter test", func() {
@@ -823,8 +838,9 @@ var _ = Describe("Podman ps", func() {
session = podmanTest.Podman([]string{"ps", "--all", "--no-trunc", "--filter", "network=" + net})
session.WaitWithDefaultTimeout()
Expect(session).Should(Exit(0))
- Expect(session.OutputToString()).To(ContainSubstring(ctrWithNet))
- Expect(session.OutputToString()).To(Not(ContainSubstring(ctrWithoutNet)))
+ actual := session.OutputToString()
+ Expect(actual).To(ContainSubstring(ctrWithNet))
+ Expect(actual).ToNot(ContainSubstring(ctrWithoutNet))
})
It("podman ps --format networks", func() {
@@ -835,12 +851,15 @@ var _ = Describe("Podman ps", func() {
session = podmanTest.Podman([]string{"ps", "--all", "--format", "{{ .Networks }}"})
session.WaitWithDefaultTimeout()
Expect(session).Should(Exit(0))
+
+ actual := session.OutputToString()
+ Expect(actual).ToNot(ContainSubstring("NETWORKS"))
if isRootless() {
// rootless container don't have a network by default
- Expect(session.OutputToString()).To(Equal(""))
+ Expect(actual).To(BeEmpty())
} else {
// default network name is podman
- Expect(session.OutputToString()).To(Equal("podman"))
+ Expect(actual).To(Equal("podman"))
}
net1 := stringid.GenerateNonCryptoID()
diff --git a/test/e2e/run_volume_test.go b/test/e2e/run_volume_test.go
index 59937b6c0..4264e1efe 100644
--- a/test/e2e/run_volume_test.go
+++ b/test/e2e/run_volume_test.go
@@ -242,6 +242,39 @@ var _ = Describe("Podman run with volumes", func() {
Expect(session).Should(Exit(0))
})
+ It("podman support overlay on named volume", func() {
+ SkipIfRemote("Overlay volumes only work locally")
+ if os.Getenv("container") != "" {
+ Skip("Overlay mounts not supported when running in a container")
+ }
+ if rootless.IsRootless() {
+ if _, err := exec.LookPath("fuse-overlayfs"); err != nil {
+ Skip("Fuse-Overlayfs required for rootless overlay mount test")
+ }
+ }
+ session := podmanTest.Podman([]string{"volume", "create", "myvolume"})
+ session.WaitWithDefaultTimeout()
+ volName := session.OutputToString()
+ Expect(session).Should(Exit(0))
+
+ // create file on actual volume
+ session = podmanTest.Podman([]string{"run", "--volume", volName + ":/data", ALPINE, "sh", "-c", "echo hello >> " + "/data/test"})
+ session.WaitWithDefaultTimeout()
+ Expect(session).Should(Exit(0))
+
+ // create file on overlayed volume
+ session = podmanTest.Podman([]string{"run", "--volume", volName + ":/data:O", ALPINE, "sh", "-c", "echo hello >> " + "/data/overlayed"})
+ session.WaitWithDefaultTimeout()
+ Expect(session).Should(Exit(0))
+
+ // volume should contain only `test` not `overlayed`
+ session = podmanTest.Podman([]string{"run", "--volume", volName + ":/data", ALPINE, "sh", "-c", "ls /data"})
+ session.WaitWithDefaultTimeout()
+ Expect(session.OutputToString()).To(Not(ContainSubstring("overlayed")))
+ Expect(session.OutputToString()).To(ContainSubstring("test"))
+
+ })
+
It("podman run with noexec can't exec", func() {
session := podmanTest.Podman([]string{"run", "--rm", "-v", "/bin:/hostbin:noexec", ALPINE, "/hostbin/ls", "/"})
session.WaitWithDefaultTimeout()
diff --git a/test/utils/utils.go b/test/utils/utils.go
index 80af7fb7c..bfefc58ec 100644
--- a/test/utils/utils.go
+++ b/test/utils/utils.go
@@ -19,7 +19,7 @@ import (
)
var (
- defaultWaitTimeout = 90
+ DefaultWaitTimeout = 90
OSReleasePath = "/etc/os-release"
ProcessOneCgroupPath = "/proc/1/cgroup"
)
@@ -317,15 +317,20 @@ func (s *PodmanSession) IsJSONOutputValid() bool {
return true
}
-// WaitWithDefaultTimeout waits for process finished with defaultWaitTimeout
+// WaitWithDefaultTimeout waits for process finished with DefaultWaitTimeout
func (s *PodmanSession) WaitWithDefaultTimeout() {
- Eventually(s, defaultWaitTimeout).Should(Exit())
+ s.WaitWithTimeout(DefaultWaitTimeout)
+}
+
+// WaitWithTimeout waits for process finished with DefaultWaitTimeout
+func (s *PodmanSession) WaitWithTimeout(timeout int) {
+ Eventually(s, timeout).Should(Exit())
os.Stdout.Sync()
os.Stderr.Sync()
fmt.Println("output:", s.OutputToString())
}
-// CreateTempDirinTempDir create a temp dir with prefix podman_test
+// CreateTempDirInTempDir create a temp dir with prefix podman_test
func CreateTempDirInTempDir() (string, error) {
return ioutil.TempDir("", "podman_test")
}
@@ -337,7 +342,7 @@ func SystemExec(command string, args []string) *PodmanSession {
if err != nil {
Fail(fmt.Sprintf("unable to run command: %s %s", command, strings.Join(args, " ")))
}
- session.Wait(defaultWaitTimeout)
+ session.Wait(DefaultWaitTimeout)
return &PodmanSession{session}
}