Skip to content

Commit

Permalink
Fix: List container with volume filter
Browse files Browse the repository at this point in the history
Modify the condition in line 149 in order to list container by mounting
point.

Closes containers#16019

Signed-off-by: SamirPS <akariohsamir@yahoo.com>
  • Loading branch information
SamirPS committed Dec 29, 2022
1 parent e000f85 commit 69941c3
Show file tree
Hide file tree
Showing 19 changed files with 133 additions and 46 deletions.
2 changes: 1 addition & 1 deletion DOWNLOADS.md
Expand Up @@ -30,7 +30,7 @@ don't take them beyond that.
WARNING: The items linked below all come from scripts in the `artifacts_task`
map of `.cirrus.yml`. When adding or updating any item below, please ensure it
matches cooresponding changes in the artifacts task.
matches corresponding changes in the artifacts task.
-->

Expand Down
6 changes: 3 additions & 3 deletions cmd/podman/common/create.go
Expand Up @@ -377,12 +377,12 @@ func DefineCreateFlags(cmd *cobra.Command, cf *entities.ContainerCreateOptions,
)
createFlags.BoolVar(
&cf.ReadOnly,
"read-only", false,
"read-only", podmanConfig.ContainersConfDefaultsRO.Containers.ReadOnly,
"Make containers root filesystem read-only",
)
createFlags.BoolVar(
&cf.ReadOnlyTmpFS,
"read-only-tmpfs", cf.ReadOnlyTmpFS,
&cf.ReadWriteTmpFS,
"read-only-tmpfs", cf.ReadWriteTmpFS,
"When running containers in read-only mode mount a read-write tmpfs on /run, /tmp and /var/tmp",
)
requiresFlagName := "requires"
Expand Down
2 changes: 1 addition & 1 deletion cmd/podman/common/create_opts.go
Expand Up @@ -83,7 +83,7 @@ func DefineCreateDefaults(opts *entities.ContainerCreateOptions) {
opts.MemorySwappiness = -1
opts.ImageVolume = podmanConfig.ContainersConfDefaultsRO.Engine.ImageVolumeMode
opts.Pull = policy()
opts.ReadOnlyTmpFS = true
opts.ReadWriteTmpFS = true
opts.SdNotifyMode = define.SdNotifyModeContainer
opts.StopTimeout = podmanConfig.ContainersConfDefaultsRO.Engine.StopTimeout
opts.Systemd = "true"
Expand Down
2 changes: 2 additions & 0 deletions cmd/podman/containers/create.go
Expand Up @@ -409,6 +409,8 @@ func createPodIfNecessary(cmd *cobra.Command, s *specgen.SpecGenerator, netOpts
infraOpts := entities.NewInfraContainerCreateOptions()
infraOpts.Net = netOpts
infraOpts.Quiet = true
infraOpts.ReadOnly = true
infraOpts.ReadWriteTmpFS = false
infraOpts.Hostname, err = cmd.Flags().GetString("hostname")
if err != nil {
return err
Expand Down
4 changes: 2 additions & 2 deletions cmd/podman/machine/init.go
Expand Up @@ -89,11 +89,11 @@ func init() {
_ = flags.MarkHidden("reexec")

UsernameFlagName := "username"
flags.StringVar(&initOpts.Username, UsernameFlagName, cfg.ContainersConfDefaultsRO.Machine.User, "Username used in qcow image")
flags.StringVar(&initOpts.Username, UsernameFlagName, cfg.ContainersConfDefaultsRO.Machine.User, "Username used in image")
_ = initCmd.RegisterFlagCompletionFunc(UsernameFlagName, completion.AutocompleteDefault)

ImagePathFlagName := "image-path"
flags.StringVar(&initOpts.ImagePath, ImagePathFlagName, cfg.ContainersConfDefaultsRO.Machine.Image, "Path to qcow image")
flags.StringVar(&initOpts.ImagePath, ImagePathFlagName, cfg.ContainersConfDefaultsRO.Machine.Image, "Path to bootable image")
_ = initCmd.RegisterFlagCompletionFunc(ImagePathFlagName, completion.AutocompleteDefault)

VolumeFlagName := "volume"
Expand Down
4 changes: 2 additions & 2 deletions docs/source/markdown/podman.1.md
Expand Up @@ -164,9 +164,9 @@ NOTE --tmpdir is not used for the temporary storage of downloaded images. Use t

#### **--transient-store**

Enables a global transient storaga mode where all container metadata is stored on non-persistant media (i.e. in the location specified by `--runroot`).
Enables a global transient storage mode where all container metadata is stored on non-persistent media (i.e. in the location specified by `--runroot`).
This mode allows starting containers faster, as well as guaranteeing a fresh state on boot in case of unclean shutdowns or other problems. However
it is not compabible with a traditional model where containers persist across reboots.
it is not compatible with a traditional model where containers persist across reboots.

Default value for this is configured in `containers-storage.conf(5)`.

Expand Down
2 changes: 1 addition & 1 deletion pkg/api/handlers/compat/containers_create.go
Expand Up @@ -413,7 +413,7 @@ func cliOpts(cc handlers.CreateContainerConfig, rtc *config.Config) (*entities.C
PublishAll: cc.HostConfig.PublishAllPorts,
Quiet: false,
ReadOnly: cc.HostConfig.ReadonlyRootfs,
ReadOnlyTmpFS: true, // podman default
ReadWriteTmpFS: true, // podman default
Rm: cc.HostConfig.AutoRemove,
SecurityOpt: cc.HostConfig.SecurityOpt,
StopSignal: cc.Config.StopSignal,
Expand Down
2 changes: 1 addition & 1 deletion pkg/domain/entities/pods.go
Expand Up @@ -249,7 +249,7 @@ type ContainerCreateOptions struct {
Pull string
Quiet bool
ReadOnly bool
ReadOnlyTmpFS bool
ReadWriteTmpFS bool
Restart string
Replace bool
Requires []string
Expand Down
2 changes: 1 addition & 1 deletion pkg/domain/filters/containers.go
Expand Up @@ -146,7 +146,7 @@ func GenerateContainerFilterFuncs(filter string, filterValues []string, r *libpo
if dest != "" && (mount.Source == source && mount.Destination == dest) {
return true
}
if dest == "" && mount.Source == source {
if dest == "" && mount.Destination == source {
return true
}
}
Expand Down
16 changes: 16 additions & 0 deletions pkg/domain/infra/abi/play.go
Expand Up @@ -68,6 +68,8 @@ func (ic *ContainerEngine) createServiceContainer(ctx context.Context, name stri
ImageVolume: "bind",
IsInfra: false,
MemorySwappiness: -1,
ReadOnly: true,
ReadWriteTmpFS: false,
// No need to spin up slirp etc.
Net: &entities.NetOptions{Network: specgen.Namespace{NSMode: specgen.NoNetwork}},
}
Expand Down Expand Up @@ -560,6 +562,8 @@ func (ic *ContainerEngine) playKubePod(ctx context.Context, podName string, podY
infraImage := util.DefaultContainerConfig().Engine.InfraImage
infraOptions := entities.NewInfraContainerCreateOptions()
infraOptions.Hostname = podSpec.PodSpecGen.PodBasicConfig.Hostname
infraOptions.ReadOnly = true
infraOptions.ReadWriteTmpFS = false
infraOptions.UserNS = options.Userns
podSpec.PodSpecGen.InfraImage = infraImage
podSpec.PodSpecGen.NoInfra = false
Expand Down Expand Up @@ -605,6 +609,16 @@ func (ic *ContainerEngine) playKubePod(ctx context.Context, podName string, podY
}
}

cfg, err := ic.Libpod.GetConfigNoCopy()
if err != nil {
return nil, nil, err
}

var readOnly types.OptionalBool
if cfg.Containers.ReadOnly {
readOnly = types.NewOptionalBool(cfg.Containers.ReadOnly)
}

ctrNames := make(map[string]string)
for _, initCtr := range podYAML.Spec.InitContainers {
// Error out if same name is used for more than one container
Expand Down Expand Up @@ -643,6 +657,7 @@ func (ic *ContainerEngine) playKubePod(ctx context.Context, podName string, podY
PodInfraID: podInfraID,
PodName: podName,
PodSecurityContext: podYAML.Spec.SecurityContext,
ReadOnly: readOnly,
RestartPolicy: define.RestartPolicyNo,
SeccompPaths: seccompPaths,
SecretsManager: secretsManager,
Expand Down Expand Up @@ -697,6 +712,7 @@ func (ic *ContainerEngine) playKubePod(ctx context.Context, podName string, podY
PodInfraID: podInfraID,
PodName: podName,
PodSecurityContext: podYAML.Spec.SecurityContext,
ReadOnly: readOnly,
RestartPolicy: ctrRestartPolicy,
SeccompPaths: seccompPaths,
SecretsManager: secretsManager,
Expand Down
2 changes: 1 addition & 1 deletion pkg/machine/e2e/config_init_test.go
Expand Up @@ -10,7 +10,7 @@ type initMachine struct {
--disk-size uint Disk size in GB (default 100)
--ignition-path string Path to ignition file
--username string Username of the remote user (default "core" for FCOS, "user" for Fedora)
--image-path string Path to qcow image (default "testing")
--image-path string Path to bootable image (default "testing")
-m, --memory uint Memory in MB (default 2048)
--now Start machine now
--rootful Whether this machine should prefer rootful container execution
Expand Down
2 changes: 2 additions & 0 deletions pkg/specgen/generate/kube/kube.go
Expand Up @@ -472,6 +472,8 @@ func ToSpecGen(ctx context.Context, opts *CtrSpecGenOptions) (*specgen.SpecGener
if ro := opts.ReadOnly; ro != itypes.OptionalBoolUndefined {
s.ReadOnlyFilesystem = (ro == itypes.OptionalBoolTrue)
}
// This should default to true for kubernetes yaml
s.ReadWriteTmpfs = true

// Make sure the container runs in a systemd unit which is
// stored as a label at container creation.
Expand Down
35 changes: 33 additions & 2 deletions pkg/specgen/generate/storage.go
Expand Up @@ -159,14 +159,19 @@ func finalizeMounts(ctx context.Context, s *specgen.SpecGenerator, rt *libpod.Ru
// Check for conflicts between named volumes and mounts
for dest := range baseMounts {
if _, ok := baseVolumes[dest]; ok {
return nil, nil, nil, fmt.Errorf("conflict at mount destination %v: %w", dest, specgen.ErrDuplicateDest)
return nil, nil, nil, fmt.Errorf("baseMounts conflict at mount destination %v: %w", dest, specgen.ErrDuplicateDest)
}
}
for dest := range baseVolumes {
if _, ok := baseMounts[dest]; ok {
return nil, nil, nil, fmt.Errorf("conflict at mount destination %v: %w", dest, specgen.ErrDuplicateDest)
return nil, nil, nil, fmt.Errorf("baseVolumes conflict at mount destination %v: %w", dest, specgen.ErrDuplicateDest)
}
}

if s.ReadWriteTmpfs {
baseMounts = addReadWriteTmpfsMounts(baseMounts, s.Volumes)
}

// Final step: maps to arrays
finalMounts := make([]spec.Mount, 0, len(baseMounts))
for _, mount := range baseMounts {
Expand Down Expand Up @@ -427,3 +432,29 @@ func InitFSMounts(mounts []spec.Mount) error {
}
return nil
}

func addReadWriteTmpfsMounts(mounts map[string]spec.Mount, volumes []*specgen.NamedVolume) map[string]spec.Mount {
readonlyTmpfs := []string{"/tmp", "/var/tmp", "/run"}
options := []string{"rw", "rprivate", "nosuid", "nodev", "tmpcopyup"}
for _, dest := range readonlyTmpfs {
if _, ok := mounts[dest]; ok {
continue
}
for _, m := range volumes {
if m.Dest == dest {
continue
}
}
mnt := spec.Mount{
Destination: dest,
Type: define.TypeTmpfs,
Source: define.TypeTmpfs,
Options: options,
}
if dest != "/run" {
mnt.Options = append(mnt.Options, "noexec")
}
mounts[dest] = mnt
}
return mounts
}
4 changes: 4 additions & 0 deletions pkg/specgen/specgen.go
Expand Up @@ -384,6 +384,10 @@ type ContainerSecurityConfig struct {
// ReadOnlyFilesystem indicates that everything will be mounted
// as read-only
ReadOnlyFilesystem bool `json:"read_only_filesystem,omitempty"`
// ReadWriteTmpfs indicates that when running with a ReadOnlyFilesystem
// mount temporary file systems
ReadWriteTmpfs bool `json:"read_write_tmpfs,omitempty"`

// Umask is the umask the init process of the container will be run with.
Umask string `json:"umask,omitempty"`
// ProcOpts are the options used for the proc mount.
Expand Down
13 changes: 5 additions & 8 deletions pkg/specgenutil/specgen.go
Expand Up @@ -592,10 +592,11 @@ func FillOutSpecGen(s *specgen.SpecGenerator, c *entities.ContainerCreateOptions
s.DependencyContainers = c.Requires
}

// TODO
// outside of specgen and oci though
// defaults to true, check spec/storage
// s.readonly = c.ReadOnlyTmpFS
// Only add ReadWrite tmpfs mounts iff the container is
// being run ReadOnly and ReadWriteTmpFS is not disabled,
// (user specifying --read-only-tmpfs=false.)
s.ReadWriteTmpfs = c.ReadOnly && c.ReadWriteTmpFS

// TODO convert to map?
// check if key=value and convert
sysmap := make(map[string]string)
Expand Down Expand Up @@ -853,10 +854,6 @@ func FillOutSpecGen(s *specgen.SpecGenerator, c *entities.ContainerCreateOptions
s.PasswdEntry = c.PasswdEntry
}

if c.ReadOnly && c.ReadOnlyTmpFS {
s.Mounts = addReadOnlyMounts(s.Mounts)
}

return nil
}

Expand Down
23 changes: 0 additions & 23 deletions pkg/specgenutil/volumes.go
Expand Up @@ -703,26 +703,3 @@ func validChownFlag(flag string) (bool, error) {
func unixPathClean(p string) string {
return path.Clean(p)
}

func addReadOnlyMounts(mounts []spec.Mount) []spec.Mount {
readonlyTmpfs := []string{"/tmp", "/var/tmp", "/run"}
options := []string{"rw", "rprivate", "nosuid", "nodev", "tmpcopyup"}
for _, dest := range readonlyTmpfs {
for _, m := range mounts {
if m.Destination == dest {
continue
}
}
mnt := spec.Mount{
Destination: dest,
Type: define.TypeTmpfs,
Source: define.TypeTmpfs,
Options: options,
}
if dest != "/run" {
mnt.Options = append(mnt.Options, "noexec")
}
mounts = append(mounts, mnt)
}
return mounts
}
13 changes: 13 additions & 0 deletions test/system/030-run.bats
Expand Up @@ -951,4 +951,17 @@ $IMAGE--c_ok" \
run_podman stop -t 0 $cid
}

@test "podman run read-only from containers.conf" {
containersconf=$PODMAN_TMPDIR/containers.conf
cat >$containersconf <<EOF
[containers]
read_only=true
EOF

CONTAINERS_CONF="$containersconf" run_podman 1 run --rm $IMAGE touch /testro
CONTAINERS_CONF="$containersconf" run_podman run --rm --read-only=false $IMAGE touch /testrw
CONTAINERS_CONF="$containersconf" run_podman run --rm $IMAGE touch /tmp/testrw
CONTAINERS_CONF="$containersconf" run_podman 1 run --rm --read-only-tmpfs=false $IMAGE touch /tmp/testro
}

# vim: filetype=sh
10 changes: 10 additions & 0 deletions test/system/160-volumes.bats
Expand Up @@ -509,4 +509,14 @@ EOF
is "$output" "" "Should print no output"
}

@test "podman ps -f" {
vol1=${PODMAN_TMPDIR}/v1_$(random_string)
mkdir $vol1
run_podman run -d --rm --volume $vol1:/$vol1 $IMAGE top
cid=$output
run_podman ps --noheading -f volume=${vol1} -q
is "$output" "$cid" "Should find container by volume"
}


# vim: filetype=sh
35 changes: 35 additions & 0 deletions test/system/700-play.bats
Expand Up @@ -238,6 +238,41 @@ EOF
run_podman 1 container exists pod1-test3
}

@test "podman kube play read-only from containers.conf" {
containersconf=$PODMAN_TMPDIR/containers.conf
cat >$containersconf <<EOF
[containers]
read_only=true
EOF

YAML=$PODMAN_TMPDIR/test.yml
CONTAINERS_CONF="$containersconf" run_podman create --pod new:pod1 --read-only=false --name test1 $IMAGE touch /testrw
CONTAINERS_CONF="$containersconf" run_podman create --pod pod1 --name test2 $IMAGE touch /testro
CONTAINERS_CONF="$containersconf" run_podman create --pod pod1 --name test3 $IMAGE touch /tmp/testtmp
CONTAINERS_CONF="$containersconf" run_podman container inspect --format '{{.HostConfig.ReadonlyRootfs}}' test1 test2 test3
is "$output" "false.*true.*true" "Rootfs should be read/only"

# Now generate and run kube.yaml on a machine without the defaults set
CONTAINERS_CONF="$containersconf" run_podman kube generate pod1 -f $YAML
cat $YAML

run_podman kube play --replace $YAML
run_podman container inspect --format '{{.HostConfig.ReadonlyRootfs}}' pod1-test1 pod1-test2 pod1-test3
is "$output" "false.*true.*true" "Rootfs should be read/only"

run_podman inspect --format "{{.State.ExitCode}}" pod1-test1
is "$output" "0" "Container / should be read/write"
run_podman inspect --format "{{.State.ExitCode}}" pod1-test2
is "$output" "1" "Container / should be read/only"
run_podman inspect --format "{{.State.ExitCode}}" pod1-test3
is "$output" "0" "/tmp in a read-only container should be read/write"

run_podman kube down - < $YAML
run_podman 1 container exists pod1-test1
run_podman 1 container exists pod1-test2
run_podman 1 container exists pod1-test3
}

@test "podman play with user from image" {
TESTDIR=$PODMAN_TMPDIR/testdir
mkdir -p $TESTDIR
Expand Down

0 comments on commit 69941c3

Please sign in to comment.