Merge pull request #11793 from baude/playgenkubeselinux

Support selinux options with bind mounts play/gen
This commit is contained in:
OpenShift Merge Robot
2021-09-30 13:31:53 -04:00
committed by GitHub
5 changed files with 58 additions and 20 deletions

View File

@ -90,3 +90,6 @@ const (
// DefaultRlimitValue is the value set by default for nofile and nproc // DefaultRlimitValue is the value set by default for nofile and nproc
const RLimitDefaultValue = uint64(1048576) const RLimitDefaultValue = uint64(1048576)
// BindMountPrefix distinguishes its annotations from others
const BindMountPrefix = "bind-mount-options:"

View File

@ -241,11 +241,13 @@ func (p *Pod) podWithContainers(ctx context.Context, containers []*Container, po
isInit := ctr.IsInitCtr() isInit := ctr.IsInitCtr()
ctr, volumes, _, err := containerToV1Container(ctx, ctr) ctr, volumes, _, annotations, err := containerToV1Container(ctx, ctr)
if err != nil { if err != nil {
return nil, err return nil, err
} }
for k, v := range annotations {
podAnnotations[define.BindMountPrefix+k] = v
}
// Since port bindings for the pod are handled by the // Since port bindings for the pod are handled by the
// infra container, wipe them here. // infra container, wipe them here.
ctr.Ports = nil ctr.Ports = nil
@ -271,7 +273,7 @@ func (p *Pod) podWithContainers(ctx context.Context, containers []*Container, po
deDupPodVolumes[vol.Name] = &vol deDupPodVolumes[vol.Name] = &vol
} }
} else { } else {
_, _, infraDNS, err := containerToV1Container(ctx, ctr) _, _, infraDNS, _, err := containerToV1Container(ctx, ctr)
if err != nil { if err != nil {
return nil, err return nil, err
} }
@ -359,17 +361,19 @@ func simplePodWithV1Containers(ctx context.Context, ctrs []*Container) (*v1.Pod,
if !ctr.HostNetwork() { if !ctr.HostNetwork() {
hostNetwork = false hostNetwork = false
} }
kubeCtr, kubeVols, ctrDNS, err := containerToV1Container(ctx, ctr) kubeCtr, kubeVols, ctrDNS, annotations, err := containerToV1Container(ctx, ctr)
if err != nil { if err != nil {
return nil, err return nil, err
} }
for k, v := range annotations {
kubeAnnotations[define.BindMountPrefix+k] = v
}
if isInit { if isInit {
kubeInitCtrs = append(kubeInitCtrs, kubeCtr) kubeInitCtrs = append(kubeInitCtrs, kubeCtr)
} else { } else {
kubeCtrs = append(kubeCtrs, kubeCtr) kubeCtrs = append(kubeCtrs, kubeCtr)
} }
kubeVolumes = append(kubeVolumes, kubeVols...) kubeVolumes = append(kubeVolumes, kubeVols...)
// Combine DNS information in sum'd structure // Combine DNS information in sum'd structure
if ctrDNS != nil { if ctrDNS != nil {
// nameservers // nameservers
@ -415,42 +419,44 @@ func simplePodWithV1Containers(ctx context.Context, ctrs []*Container) (*v1.Pod,
// containerToV1Container converts information we know about a libpod container // containerToV1Container converts information we know about a libpod container
// to a V1.Container specification. // to a V1.Container specification.
func containerToV1Container(ctx context.Context, c *Container) (v1.Container, []v1.Volume, *v1.PodDNSConfig, error) { func containerToV1Container(ctx context.Context, c *Container) (v1.Container, []v1.Volume, *v1.PodDNSConfig, map[string]string, error) {
kubeContainer := v1.Container{} kubeContainer := v1.Container{}
kubeVolumes := []v1.Volume{} kubeVolumes := []v1.Volume{}
annotations := make(map[string]string)
kubeSec, err := generateKubeSecurityContext(c) kubeSec, err := generateKubeSecurityContext(c)
if err != nil { if err != nil {
return kubeContainer, kubeVolumes, nil, err return kubeContainer, kubeVolumes, nil, annotations, err
} }
// NOTE: a privileged container mounts all of /dev/*. // NOTE: a privileged container mounts all of /dev/*.
if !c.Privileged() && len(c.config.Spec.Linux.Devices) > 0 { if !c.Privileged() && len(c.config.Spec.Linux.Devices) > 0 {
// TODO Enable when we can support devices and their names // TODO Enable when we can support devices and their names
kubeContainer.VolumeDevices = generateKubeVolumeDeviceFromLinuxDevice(c.config.Spec.Linux.Devices) kubeContainer.VolumeDevices = generateKubeVolumeDeviceFromLinuxDevice(c.config.Spec.Linux.Devices)
return kubeContainer, kubeVolumes, nil, errors.Wrapf(define.ErrNotImplemented, "linux devices") return kubeContainer, kubeVolumes, nil, annotations, errors.Wrapf(define.ErrNotImplemented, "linux devices")
} }
if len(c.config.UserVolumes) > 0 { if len(c.config.UserVolumes) > 0 {
volumeMounts, volumes, err := libpodMountsToKubeVolumeMounts(c) volumeMounts, volumes, localAnnotations, err := libpodMountsToKubeVolumeMounts(c)
if err != nil { if err != nil {
return kubeContainer, kubeVolumes, nil, err return kubeContainer, kubeVolumes, nil, nil, err
} }
annotations = localAnnotations
kubeContainer.VolumeMounts = volumeMounts kubeContainer.VolumeMounts = volumeMounts
kubeVolumes = append(kubeVolumes, volumes...) kubeVolumes = append(kubeVolumes, volumes...)
} }
envVariables, err := libpodEnvVarsToKubeEnvVars(c.config.Spec.Process.Env) envVariables, err := libpodEnvVarsToKubeEnvVars(c.config.Spec.Process.Env)
if err != nil { if err != nil {
return kubeContainer, kubeVolumes, nil, err return kubeContainer, kubeVolumes, nil, annotations, err
} }
portmappings, err := c.PortMappings() portmappings, err := c.PortMappings()
if err != nil { if err != nil {
return kubeContainer, kubeVolumes, nil, err return kubeContainer, kubeVolumes, nil, annotations, err
} }
ports, err := ocicniPortMappingToContainerPort(portmappings) ports, err := ocicniPortMappingToContainerPort(portmappings)
if err != nil { if err != nil {
return kubeContainer, kubeVolumes, nil, err return kubeContainer, kubeVolumes, nil, annotations, err
} }
// Handle command and arguments. // Handle command and arguments.
@ -469,11 +475,11 @@ func containerToV1Container(ctx context.Context, c *Container) (v1.Container, []
kubeContainer.Stdin = c.Stdin() kubeContainer.Stdin = c.Stdin()
img, _, err := c.runtime.libimageRuntime.LookupImage(image, nil) img, _, err := c.runtime.libimageRuntime.LookupImage(image, nil)
if err != nil { if err != nil {
return kubeContainer, kubeVolumes, nil, err return kubeContainer, kubeVolumes, nil, annotations, err
} }
imgData, err := img.Inspect(ctx, false) imgData, err := img.Inspect(ctx, false)
if err != nil { if err != nil {
return kubeContainer, kubeVolumes, nil, err return kubeContainer, kubeVolumes, nil, annotations, err
} }
if reflect.DeepEqual(imgData.Config.Cmd, kubeContainer.Command) { if reflect.DeepEqual(imgData.Config.Cmd, kubeContainer.Command) {
kubeContainer.Command = nil kubeContainer.Command = nil
@ -555,7 +561,7 @@ func containerToV1Container(ctx context.Context, c *Container) (v1.Container, []
} }
dns.Options = dnsOptions dns.Options = dnsOptions
} }
return kubeContainer, kubeVolumes, &dns, nil return kubeContainer, kubeVolumes, &dns, annotations, nil
} }
// ocicniPortMappingToContainerPort takes an ocicni portmapping and converts // ocicniPortMappingToContainerPort takes an ocicni portmapping and converts
@ -606,16 +612,23 @@ func libpodEnvVarsToKubeEnvVars(envs []string) ([]v1.EnvVar, error) {
} }
// libpodMountsToKubeVolumeMounts converts the containers mounts to a struct kube understands // libpodMountsToKubeVolumeMounts converts the containers mounts to a struct kube understands
func libpodMountsToKubeVolumeMounts(c *Container) ([]v1.VolumeMount, []v1.Volume, error) { func libpodMountsToKubeVolumeMounts(c *Container) ([]v1.VolumeMount, []v1.Volume, map[string]string, error) {
namedVolumes, mounts := c.sortUserVolumes(c.config.Spec) namedVolumes, mounts := c.sortUserVolumes(c.config.Spec)
vms := make([]v1.VolumeMount, 0, len(mounts)) vms := make([]v1.VolumeMount, 0, len(mounts))
vos := make([]v1.Volume, 0, len(mounts)) vos := make([]v1.Volume, 0, len(mounts))
annotations := make(map[string]string)
var suffix string var suffix string
for index, m := range mounts { for index, m := range mounts {
for _, opt := range m.Options {
if opt == "Z" || opt == "z" {
annotations[m.Source] = opt
break
}
}
vm, vo, err := generateKubeVolumeMount(m) vm, vo, err := generateKubeVolumeMount(m)
if err != nil { if err != nil {
return vms, vos, err return vms, vos, annotations, err
} }
// Name will be the same, so use the index as suffix // Name will be the same, so use the index as suffix
suffix = fmt.Sprintf("-%d", index) suffix = fmt.Sprintf("-%d", index)
@ -629,7 +642,7 @@ func libpodMountsToKubeVolumeMounts(c *Container) ([]v1.VolumeMount, []v1.Volume
vms = append(vms, vm) vms = append(vms, vm)
vos = append(vos, vo) vos = append(vos, vo)
} }
return vms, vos, nil return vms, vos, annotations, nil
} }
// generateKubePersistentVolumeClaim converts a ContainerNamedVolume to a Kubernetes PersistentVolumeClaim // generateKubePersistentVolumeClaim converts a ContainerNamedVolume to a Kubernetes PersistentVolumeClaim

View File

@ -319,8 +319,8 @@ func (ic *ContainerEngine) playKubePod(ctx context.Context, podName string, podY
if err != nil { if err != nil {
return nil, err return nil, err
} }
specgenOpts := kube.CtrSpecGenOptions{ specgenOpts := kube.CtrSpecGenOptions{
Annotations: annotations,
Container: initCtr, Container: initCtr,
Image: pulledImage, Image: pulledImage,
Volumes: volumes, Volumes: volumes,

View File

@ -12,6 +12,7 @@ import (
"github.com/containers/common/pkg/parse" "github.com/containers/common/pkg/parse"
"github.com/containers/common/pkg/secrets" "github.com/containers/common/pkg/secrets"
"github.com/containers/image/v5/manifest" "github.com/containers/image/v5/manifest"
"github.com/containers/podman/v3/libpod/define"
"github.com/containers/podman/v3/libpod/network/types" "github.com/containers/podman/v3/libpod/network/types"
ann "github.com/containers/podman/v3/pkg/annotations" ann "github.com/containers/podman/v3/pkg/annotations"
"github.com/containers/podman/v3/pkg/domain/entities" "github.com/containers/podman/v3/pkg/domain/entities"
@ -86,6 +87,8 @@ func ToPodOpt(ctx context.Context, podName string, p entities.PodCreateOptions,
} }
type CtrSpecGenOptions struct { type CtrSpecGenOptions struct {
// Annotations from the Pod
Annotations map[string]string
// Container as read from the pod yaml // Container as read from the pod yaml
Container v1.Container Container v1.Container
// Image available to use (pulled or found local) // Image available to use (pulled or found local)
@ -289,6 +292,14 @@ func ToSpecGen(ctx context.Context, opts *CtrSpecGenOptions) (*specgen.SpecGener
volume.MountPath = dest volume.MountPath = dest
switch volumeSource.Type { switch volumeSource.Type {
case KubeVolumeTypeBindMount: case KubeVolumeTypeBindMount:
// If the container has bind mounts, we need to check if
// a selinux mount option exists for it
for k, v := range opts.Annotations {
// Make sure the z/Z option is not already there (from editing the YAML)
if strings.Replace(k, define.BindMountPrefix, "", 1) == volumeSource.Source && !util.StringInSlice("z", options) && !util.StringInSlice("Z", options) {
options = append(options, v)
}
}
mount := spec.Mount{ mount := spec.Mount{
Destination: volume.MountPath, Destination: volume.MountPath,
Source: volumeSource.Source, Source: volumeSource.Source,

View File

@ -6,6 +6,8 @@ import (
"path/filepath" "path/filepath"
"strconv" "strconv"
"github.com/containers/podman/v3/libpod/define"
"github.com/containers/podman/v3/pkg/util" "github.com/containers/podman/v3/pkg/util"
. "github.com/containers/podman/v3/test/utils" . "github.com/containers/podman/v3/test/utils"
"github.com/ghodss/yaml" "github.com/ghodss/yaml"
@ -555,6 +557,15 @@ var _ = Describe("Podman generate kube", func() {
kube.WaitWithDefaultTimeout() kube.WaitWithDefaultTimeout()
Expect(kube).Should(Exit(0)) Expect(kube).Should(Exit(0))
b, err := ioutil.ReadFile(outputFile)
Expect(err).ShouldNot(HaveOccurred())
pod := new(v1.Pod)
err = yaml.Unmarshal(b, pod)
Expect(err).To(BeNil())
val, found := pod.Annotations[define.BindMountPrefix+vol1]
Expect(found).To(BeTrue())
Expect(val).To(HaveSuffix("z"))
rm := podmanTest.Podman([]string{"pod", "rm", "-f", "test1"}) rm := podmanTest.Podman([]string{"pod", "rm", "-f", "test1"})
rm.WaitWithDefaultTimeout() rm.WaitWithDefaultTimeout()
Expect(rm).Should(Exit(0)) Expect(rm).Should(Exit(0))