mirror of
https://github.com/containers/podman.git
synced 2025-09-21 19:55:08 +08:00
Must use mountlabel when creating builtin volumes
Signed-off-by: Daniel J Walsh <dwalsh@redhat.com>
This commit is contained in:
@ -1665,6 +1665,18 @@ func WithVolumeLabels(labels map[string]string) VolumeCreateOption {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// WithVolumeMountLabel sets the MountLabel of the volume.
|
||||||
|
func WithVolumeMountLabel(mountLabel string) VolumeCreateOption {
|
||||||
|
return func(volume *Volume) error {
|
||||||
|
if volume.valid {
|
||||||
|
return define.ErrVolumeFinalized
|
||||||
|
}
|
||||||
|
|
||||||
|
volume.config.MountLabel = mountLabel
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// WithVolumeOptions sets the options of the volume.
|
// WithVolumeOptions sets the options of the volume.
|
||||||
func WithVolumeOptions(options map[string]string) VolumeCreateOption {
|
func WithVolumeOptions(options map[string]string) VolumeCreateOption {
|
||||||
return func(volume *Volume) error {
|
return func(volume *Volume) error {
|
||||||
|
@ -107,6 +107,18 @@ func (p *Pod) Name() string {
|
|||||||
return p.config.Name
|
return p.config.Name
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// MountLabel returns the SELinux label associated with the pod
|
||||||
|
func (p *Pod) MountLabel() (string, error) {
|
||||||
|
if !p.HasInfraContainer() {
|
||||||
|
return "", nil
|
||||||
|
}
|
||||||
|
ctr, err := p.infraContainer()
|
||||||
|
if err != nil {
|
||||||
|
return "", err
|
||||||
|
}
|
||||||
|
return ctr.MountLabel(), nil
|
||||||
|
}
|
||||||
|
|
||||||
// Namespace returns the pod's libpod namespace.
|
// Namespace returns the pod's libpod namespace.
|
||||||
// Namespaces are used to logically separate containers and pods in the state.
|
// Namespaces are used to logically separate containers and pods in the state.
|
||||||
func (p *Pod) Namespace() string {
|
func (p *Pod) Namespace() string {
|
||||||
|
@ -495,7 +495,10 @@ func (r *Runtime) setupContainer(ctx context.Context, ctr *Container) (_ *Contai
|
|||||||
logrus.Debugf("Creating new volume %s for container", vol.Name)
|
logrus.Debugf("Creating new volume %s for container", vol.Name)
|
||||||
|
|
||||||
// The volume does not exist, so we need to create it.
|
// The volume does not exist, so we need to create it.
|
||||||
volOptions := []VolumeCreateOption{WithVolumeName(vol.Name)}
|
volOptions := []VolumeCreateOption{
|
||||||
|
WithVolumeName(vol.Name),
|
||||||
|
WithVolumeMountLabel(ctr.MountLabel()),
|
||||||
|
}
|
||||||
if isAnonymous {
|
if isAnonymous {
|
||||||
volOptions = append(volOptions, withSetAnon())
|
volOptions = append(volOptions, withSetAnon())
|
||||||
}
|
}
|
||||||
|
@ -20,6 +20,7 @@ import (
|
|||||||
"github.com/containers/storage/pkg/idtools"
|
"github.com/containers/storage/pkg/idtools"
|
||||||
"github.com/containers/storage/pkg/stringid"
|
"github.com/containers/storage/pkg/stringid"
|
||||||
pluginapi "github.com/docker/go-plugins-helpers/volume"
|
pluginapi "github.com/docker/go-plugins-helpers/volume"
|
||||||
|
"github.com/opencontainers/selinux/go-selinux"
|
||||||
"github.com/sirupsen/logrus"
|
"github.com/sirupsen/logrus"
|
||||||
)
|
)
|
||||||
|
|
||||||
@ -122,6 +123,13 @@ func (r *Runtime) newVolume(ctx context.Context, noCreatePluginVolume bool, opti
|
|||||||
storageConfig := storage.ContainerOptions{
|
storageConfig := storage.ContainerOptions{
|
||||||
LabelOpts: []string{"filetype:container_file_t:s0"},
|
LabelOpts: []string{"filetype:container_file_t:s0"},
|
||||||
}
|
}
|
||||||
|
if len(volume.config.MountLabel) > 0 {
|
||||||
|
context, err := selinux.NewContext(volume.config.MountLabel)
|
||||||
|
if err != nil {
|
||||||
|
return nil, fmt.Errorf("failed to get SELinux context from %s: %w", volume.config.MountLabel, err)
|
||||||
|
}
|
||||||
|
storageConfig.LabelOpts = []string{fmt.Sprintf("filetype:%s:s0", context["type"])}
|
||||||
|
}
|
||||||
if _, err := r.storageService.CreateContainerStorage(ctx, r.imageContext, imgString, image.ID(), volume.config.StorageName, volume.config.StorageID, storageConfig); err != nil {
|
if _, err := r.storageService.CreateContainerStorage(ctx, r.imageContext, imgString, image.ID(), volume.config.StorageName, volume.config.StorageID, storageConfig); err != nil {
|
||||||
return nil, fmt.Errorf("creating backing storage for image driver: %w", err)
|
return nil, fmt.Errorf("creating backing storage for image driver: %w", err)
|
||||||
}
|
}
|
||||||
@ -161,7 +169,7 @@ func (r *Runtime) newVolume(ctx context.Context, noCreatePluginVolume bool, opti
|
|||||||
if err := idtools.SafeChown(fullVolPath, volume.config.UID, volume.config.GID); err != nil {
|
if err := idtools.SafeChown(fullVolPath, volume.config.UID, volume.config.GID); err != nil {
|
||||||
return nil, fmt.Errorf("chowning volume directory %q to %d:%d: %w", fullVolPath, volume.config.UID, volume.config.GID, err)
|
return nil, fmt.Errorf("chowning volume directory %q to %d:%d: %w", fullVolPath, volume.config.UID, volume.config.GID, err)
|
||||||
}
|
}
|
||||||
if err := LabelVolumePath(fullVolPath); err != nil {
|
if err := LabelVolumePath(fullVolPath, volume.config.MountLabel); err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
if volume.config.DisableQuota {
|
if volume.config.DisableQuota {
|
||||||
|
@ -25,7 +25,7 @@ func deleteSystemdCgroup(path string, resources *spec.LinuxResources) error {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// No equivalent on FreeBSD?
|
// No equivalent on FreeBSD?
|
||||||
func LabelVolumePath(path string) error {
|
func LabelVolumePath(path, mountLabel string) error {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -109,13 +109,16 @@ var lvpReleaseLabel = label.ReleaseLabel
|
|||||||
|
|
||||||
// LabelVolumePath takes a mount path for a volume and gives it an
|
// LabelVolumePath takes a mount path for a volume and gives it an
|
||||||
// selinux label of either shared or not
|
// selinux label of either shared or not
|
||||||
func LabelVolumePath(path string) error {
|
func LabelVolumePath(path, mountLabel string) error {
|
||||||
_, mountLabel, err := lvpInitLabels([]string{})
|
if mountLabel == "" {
|
||||||
if err != nil {
|
var err error
|
||||||
return fmt.Errorf("getting default mountlabels: %w", err)
|
_, mountLabel, err = lvpInitLabels([]string{})
|
||||||
}
|
if err != nil {
|
||||||
if err := lvpReleaseLabel(mountLabel); err != nil {
|
return fmt.Errorf("getting default mountlabels: %w", err)
|
||||||
return fmt.Errorf("releasing label %q: %w", mountLabel, err)
|
}
|
||||||
|
if err := lvpReleaseLabel(mountLabel); err != nil {
|
||||||
|
return fmt.Errorf("releasing label %q: %w", mountLabel, err)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if err := lvpRelabel(path, mountLabel, true); err != nil {
|
if err := lvpRelabel(path, mountLabel, true); err != nil {
|
||||||
|
@ -34,6 +34,6 @@ func TestLabelVolumePath(t *testing.T) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// LabelVolumePath should not return an error if the operation is unsupported.
|
// LabelVolumePath should not return an error if the operation is unsupported.
|
||||||
err := LabelVolumePath("/foo/bar")
|
err := LabelVolumePath("/foo/bar", "")
|
||||||
assert.NoError(t, err)
|
assert.NoError(t, err)
|
||||||
}
|
}
|
||||||
|
@ -22,6 +22,6 @@ func Unmount(mount string) {
|
|||||||
|
|
||||||
// LabelVolumePath takes a mount path for a volume and gives it an
|
// LabelVolumePath takes a mount path for a volume and gives it an
|
||||||
// selinux label of either shared or not
|
// selinux label of either shared or not
|
||||||
func LabelVolumePath(path string) error {
|
func LabelVolumePath(path, mountLabel string) error {
|
||||||
return errors.New("not implemented LabelVolumePath")
|
return errors.New("not implemented LabelVolumePath")
|
||||||
}
|
}
|
||||||
|
@ -67,6 +67,8 @@ type VolumeConfig struct {
|
|||||||
// StorageImageID is the ID of the image the volume was based off of.
|
// StorageImageID is the ID of the image the volume was based off of.
|
||||||
// Only used for image volumes.
|
// Only used for image volumes.
|
||||||
StorageImageID string `json:"storageImageID,omitempty"`
|
StorageImageID string `json:"storageImageID,omitempty"`
|
||||||
|
// MountLabel is the SELinux label to assign to mount points
|
||||||
|
MountLabel string `json:"mountlabel,omitempty"`
|
||||||
}
|
}
|
||||||
|
|
||||||
// VolumeState holds the volume's mutable state.
|
// VolumeState holds the volume's mutable state.
|
||||||
|
@ -34,6 +34,7 @@ import (
|
|||||||
"github.com/coreos/go-systemd/v22/daemon"
|
"github.com/coreos/go-systemd/v22/daemon"
|
||||||
"github.com/ghodss/yaml"
|
"github.com/ghodss/yaml"
|
||||||
"github.com/opencontainers/go-digest"
|
"github.com/opencontainers/go-digest"
|
||||||
|
"github.com/opencontainers/selinux/go-selinux"
|
||||||
"github.com/sirupsen/logrus"
|
"github.com/sirupsen/logrus"
|
||||||
yamlv3 "gopkg.in/yaml.v3"
|
yamlv3 "gopkg.in/yaml.v3"
|
||||||
)
|
)
|
||||||
@ -279,7 +280,7 @@ func (ic *ContainerEngine) PlayKube(ctx context.Context, body io.Reader, options
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
r, err := ic.playKubePVC(ctx, &pvcYAML)
|
r, err := ic.playKubePVC(ctx, "", &pvcYAML)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
@ -535,7 +536,12 @@ func (ic *ContainerEngine) playKubePod(ctx context.Context, podName string, podY
|
|||||||
configMaps = append(configMaps, cm)
|
configMaps = append(configMaps, cm)
|
||||||
}
|
}
|
||||||
|
|
||||||
volumes, err := kube.InitializeVolumes(podYAML.Spec.Volumes, configMaps, secretsManager)
|
mountLabel, err := getMountLabel(podYAML.Spec.SecurityContext)
|
||||||
|
if err != nil {
|
||||||
|
return nil, nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
volumes, err := kube.InitializeVolumes(podYAML.Spec.Volumes, configMaps, secretsManager, mountLabel)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, nil, err
|
return nil, nil, err
|
||||||
}
|
}
|
||||||
@ -544,7 +550,11 @@ func (ic *ContainerEngine) playKubePod(ctx context.Context, podName string, podY
|
|||||||
// defined by a configmap or secret
|
// defined by a configmap or secret
|
||||||
for _, v := range volumes {
|
for _, v := range volumes {
|
||||||
if (v.Type == kube.KubeVolumeTypeConfigMap || v.Type == kube.KubeVolumeTypeSecret) && !v.Optional {
|
if (v.Type == kube.KubeVolumeTypeConfigMap || v.Type == kube.KubeVolumeTypeSecret) && !v.Optional {
|
||||||
vol, err := ic.Libpod.NewVolume(ctx, libpod.WithVolumeName(v.Source))
|
volumeOptions := []libpod.VolumeCreateOption{
|
||||||
|
libpod.WithVolumeName(v.Source),
|
||||||
|
libpod.WithVolumeMountLabel(mountLabel),
|
||||||
|
}
|
||||||
|
vol, err := ic.Libpod.NewVolume(ctx, volumeOptions...)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
if errors.Is(err, define.ErrVolumeExists) {
|
if errors.Is(err, define.ErrVolumeExists) {
|
||||||
// Volume for this configmap already exists do not
|
// Volume for this configmap already exists do not
|
||||||
@ -971,7 +981,7 @@ func (ic *ContainerEngine) getImageAndLabelInfo(ctx context.Context, cwd string,
|
|||||||
}
|
}
|
||||||
|
|
||||||
// playKubePVC creates a podman volume from a kube persistent volume claim.
|
// playKubePVC creates a podman volume from a kube persistent volume claim.
|
||||||
func (ic *ContainerEngine) playKubePVC(ctx context.Context, pvcYAML *v1.PersistentVolumeClaim) (*entities.PlayKubeReport, error) {
|
func (ic *ContainerEngine) playKubePVC(ctx context.Context, mountLabel string, pvcYAML *v1.PersistentVolumeClaim) (*entities.PlayKubeReport, error) {
|
||||||
var report entities.PlayKubeReport
|
var report entities.PlayKubeReport
|
||||||
opts := make(map[string]string)
|
opts := make(map[string]string)
|
||||||
|
|
||||||
@ -987,6 +997,7 @@ func (ic *ContainerEngine) playKubePVC(ctx context.Context, pvcYAML *v1.Persiste
|
|||||||
libpod.WithVolumeName(name),
|
libpod.WithVolumeName(name),
|
||||||
libpod.WithVolumeLabels(pvcYAML.Labels),
|
libpod.WithVolumeLabels(pvcYAML.Labels),
|
||||||
libpod.WithVolumeIgnoreIfExist(),
|
libpod.WithVolumeIgnoreIfExist(),
|
||||||
|
libpod.WithVolumeMountLabel(mountLabel),
|
||||||
}
|
}
|
||||||
|
|
||||||
// Get pvc annotations and create remaining podman volume options if available.
|
// Get pvc annotations and create remaining podman volume options if available.
|
||||||
@ -1415,3 +1426,31 @@ func (ic *ContainerEngine) playKubeSecret(secret *v1.Secret) (*entities.SecretCr
|
|||||||
|
|
||||||
return r, nil
|
return r, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func getMountLabel(securityContext *v1.PodSecurityContext) (string, error) {
|
||||||
|
var mountLabel string
|
||||||
|
if securityContext == nil {
|
||||||
|
return "", nil
|
||||||
|
}
|
||||||
|
seopt := securityContext.SELinuxOptions
|
||||||
|
if seopt == nil {
|
||||||
|
return mountLabel, nil
|
||||||
|
}
|
||||||
|
if seopt.Level == "" && seopt.FileType == "" {
|
||||||
|
return mountLabel, nil
|
||||||
|
}
|
||||||
|
privLabel := selinux.PrivContainerMountLabel()
|
||||||
|
con, err := selinux.NewContext(privLabel)
|
||||||
|
if err != nil {
|
||||||
|
return mountLabel, err
|
||||||
|
}
|
||||||
|
|
||||||
|
con["level"] = "s0"
|
||||||
|
if seopt.Level != "" {
|
||||||
|
con["level"] = seopt.Level
|
||||||
|
}
|
||||||
|
if seopt.FileType != "" {
|
||||||
|
con["type"] = seopt.FileType
|
||||||
|
}
|
||||||
|
return con.Get(), nil
|
||||||
|
}
|
||||||
|
@ -51,7 +51,7 @@ type KubeVolume struct {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Create a KubeVolume from an HostPathVolumeSource
|
// Create a KubeVolume from an HostPathVolumeSource
|
||||||
func VolumeFromHostPath(hostPath *v1.HostPathVolumeSource) (*KubeVolume, error) {
|
func VolumeFromHostPath(hostPath *v1.HostPathVolumeSource, mountLabel string) (*KubeVolume, error) {
|
||||||
if hostPath.Type != nil {
|
if hostPath.Type != nil {
|
||||||
switch *hostPath.Type {
|
switch *hostPath.Type {
|
||||||
case v1.HostPathDirectoryOrCreate:
|
case v1.HostPathDirectoryOrCreate:
|
||||||
@ -59,7 +59,7 @@ func VolumeFromHostPath(hostPath *v1.HostPathVolumeSource) (*KubeVolume, error)
|
|||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
// Label a newly created volume
|
// Label a newly created volume
|
||||||
if err := libpod.LabelVolumePath(hostPath.Path); err != nil {
|
if err := libpod.LabelVolumePath(hostPath.Path, mountLabel); err != nil {
|
||||||
return nil, fmt.Errorf("giving %s a label: %w", hostPath.Path, err)
|
return nil, fmt.Errorf("giving %s a label: %w", hostPath.Path, err)
|
||||||
}
|
}
|
||||||
case v1.HostPathFileOrCreate:
|
case v1.HostPathFileOrCreate:
|
||||||
@ -73,7 +73,8 @@ func VolumeFromHostPath(hostPath *v1.HostPathVolumeSource) (*KubeVolume, error)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
// unconditionally label a newly created volume
|
// unconditionally label a newly created volume
|
||||||
if err := libpod.LabelVolumePath(hostPath.Path); err != nil {
|
|
||||||
|
if err := libpod.LabelVolumePath(hostPath.Path, mountLabel); err != nil {
|
||||||
return nil, fmt.Errorf("giving %s a label: %w", hostPath.Path, err)
|
return nil, fmt.Errorf("giving %s a label: %w", hostPath.Path, err)
|
||||||
}
|
}
|
||||||
case v1.HostPathSocket:
|
case v1.HostPathSocket:
|
||||||
@ -232,10 +233,10 @@ func VolumeFromEmptyDir(emptyDirVolumeSource *v1.EmptyDirVolumeSource, name stri
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Create a KubeVolume from one of the supported VolumeSource
|
// Create a KubeVolume from one of the supported VolumeSource
|
||||||
func VolumeFromSource(volumeSource v1.VolumeSource, configMaps []v1.ConfigMap, secretsManager *secrets.SecretsManager, volName string) (*KubeVolume, error) {
|
func VolumeFromSource(volumeSource v1.VolumeSource, configMaps []v1.ConfigMap, secretsManager *secrets.SecretsManager, volName, mountLabel string) (*KubeVolume, error) {
|
||||||
switch {
|
switch {
|
||||||
case volumeSource.HostPath != nil:
|
case volumeSource.HostPath != nil:
|
||||||
return VolumeFromHostPath(volumeSource.HostPath)
|
return VolumeFromHostPath(volumeSource.HostPath, mountLabel)
|
||||||
case volumeSource.PersistentVolumeClaim != nil:
|
case volumeSource.PersistentVolumeClaim != nil:
|
||||||
return VolumeFromPersistentVolumeClaim(volumeSource.PersistentVolumeClaim)
|
return VolumeFromPersistentVolumeClaim(volumeSource.PersistentVolumeClaim)
|
||||||
case volumeSource.ConfigMap != nil:
|
case volumeSource.ConfigMap != nil:
|
||||||
@ -250,11 +251,11 @@ func VolumeFromSource(volumeSource v1.VolumeSource, configMaps []v1.ConfigMap, s
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Create a map of volume name to KubeVolume
|
// Create a map of volume name to KubeVolume
|
||||||
func InitializeVolumes(specVolumes []v1.Volume, configMaps []v1.ConfigMap, secretsManager *secrets.SecretsManager) (map[string]*KubeVolume, error) {
|
func InitializeVolumes(specVolumes []v1.Volume, configMaps []v1.ConfigMap, secretsManager *secrets.SecretsManager, mountLabel string) (map[string]*KubeVolume, error) {
|
||||||
volumes := make(map[string]*KubeVolume)
|
volumes := make(map[string]*KubeVolume)
|
||||||
|
|
||||||
for _, specVolume := range specVolumes {
|
for _, specVolume := range specVolumes {
|
||||||
volume, err := VolumeFromSource(specVolume.VolumeSource, configMaps, secretsManager, specVolume.Name)
|
volume, err := VolumeFromSource(specVolume.VolumeSource, configMaps, secretsManager, specVolume.Name, mountLabel)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, fmt.Errorf("failed to create volume %q: %w", specVolume.Name, err)
|
return nil, fmt.Errorf("failed to create volume %q: %w", specVolume.Name, err)
|
||||||
}
|
}
|
||||||
|
@ -519,5 +519,15 @@ EOF
|
|||||||
run_podman rm -f -t 0 -a
|
run_podman rm -f -t 0 -a
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@test "podman run with building volume and selinux file label" {
|
||||||
|
skip_if_no_selinux
|
||||||
|
run_podman create --security-opt label=filetype:usr_t --volume myvol:/myvol $IMAGE top
|
||||||
|
run_podman volume inspect myvol --format '{{ .Mountpoint }}'
|
||||||
|
path=${output}
|
||||||
|
run ls -Zd $path
|
||||||
|
is "$output" "system_u:object_r:usr_t:s0 $path" "volume should be labeled with usr_t type"
|
||||||
|
run_podman volume rm myvol --force
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
# vim: filetype=sh
|
# vim: filetype=sh
|
||||||
|
@ -559,18 +559,24 @@ EOF
|
|||||||
|
|
||||||
@test "podman kube generate filetype" {
|
@test "podman kube generate filetype" {
|
||||||
YAML=$PODMAN_TMPDIR/test.yml
|
YAML=$PODMAN_TMPDIR/test.yml
|
||||||
run_podman create --pod new:pod1 --security-opt label=level:s0:c1,c2 --security-opt label=filetype:usr_t --name test1 $IMAGE true
|
run_podman create --pod new:pod1 --security-opt label=level:s0:c1,c2 --security-opt label=filetype:usr_t -v myvol:/myvol --name test1 $IMAGE true
|
||||||
run_podman kube generate pod1 -f $YAML
|
run_podman kube generate pod1 -f $YAML
|
||||||
run cat $YAML
|
run cat $YAML
|
||||||
is "$output" ".*filetype: usr_t" "Generated YAML file should contain filetype usr_t"
|
is "$output" ".*filetype: usr_t" "Generated YAML file should contain filetype usr_t"
|
||||||
run_podman pod rm --force pod1
|
run_podman pod rm --force pod1
|
||||||
|
run_podman volume rm myvol --force
|
||||||
|
|
||||||
run_podman kube play $YAML
|
run_podman kube play $YAML
|
||||||
if selinux_enabled; then
|
if selinux_enabled; then
|
||||||
run_podman inspect pod1-test1 --format "{{ .MountLabel }}"
|
run_podman inspect pod1-test1 --format "{{ .MountLabel }}"
|
||||||
is "$output" "system_u:object_r:usr_t:s0:c1,c2" "Generated container should use filetype usr_t"
|
is "$output" "system_u:object_r:usr_t:s0:c1,c2" "Generated container should use filetype usr_t"
|
||||||
|
run_podman volume inspect myvol --format '{{ .Mountpoint }}'
|
||||||
|
path=${output}
|
||||||
|
run ls -Zd $path
|
||||||
|
is "$output" "system_u:object_r:usr_t:s0 $path" "volume should be labeled with usr_t type"
|
||||||
fi
|
fi
|
||||||
run_podman kube down $YAML
|
run_podman kube down $YAML
|
||||||
|
run_podman volume rm myvol --force
|
||||||
}
|
}
|
||||||
|
|
||||||
# kube play --wait=true, where we clear up the created containers, pods, and volumes when a kill or sigterm is triggered
|
# kube play --wait=true, where we clear up the created containers, pods, and volumes when a kill or sigterm is triggered
|
||||||
|
Reference in New Issue
Block a user