Merge pull request #20194 from umohnani8/kube-mode

Add DefaultMode to kube play
This commit is contained in:
OpenShift Merge Robot
2023-10-02 03:52:34 -04:00
committed by GitHub
3 changed files with 252 additions and 27 deletions

View File

@ -628,6 +628,7 @@ func (ic *ContainerEngine) playKubePod(ctx context.Context, podName string, podY
if err != nil || mountPoint == "" {
return nil, nil, fmt.Errorf("unable to get mountpoint of volume %q: %w", vol.Name(), err)
}
defaultMode := v.DefaultMode
// Create files and add data to the volume mountpoint based on the Items in the volume
for k, v := range v.Items {
dataPath := filepath.Join(mountPoint, k)
@ -640,6 +641,10 @@ func (ic *ContainerEngine) playKubePod(ctx context.Context, podName string, podY
if err != nil {
return nil, nil, err
}
// Set file permissions
if err := os.Chmod(f.Name(), os.FileMode(defaultMode)); err != nil {
return nil, nil, err
}
}
}
}

View File

@ -51,6 +51,9 @@ type KubeVolume struct {
// If the volume is optional, we can move on if it is not found
// Only used when there are volumes in a yaml that refer to a configmap
Optional bool
// DefaultMode sets the permissions on files created for the volume
// This is optional and defaults to 0644
DefaultMode int32
}
// Create a KubeVolume from an HostPathVolumeSource
@ -135,9 +138,18 @@ func VolumeFromHostPath(hostPath *v1.HostPathVolumeSource, mountLabel string) (*
// VolumeFromSecret creates a new kube volume from a kube secret.
func VolumeFromSecret(secretSource *v1.SecretVolumeSource, secretsManager *secrets.SecretsManager) (*KubeVolume, error) {
kv := &KubeVolume{
Type: KubeVolumeTypeSecret,
Source: secretSource.SecretName,
Items: map[string][]byte{},
Type: KubeVolumeTypeSecret,
Source: secretSource.SecretName,
Items: map[string][]byte{},
DefaultMode: v1.SecretVolumeSourceDefaultMode,
}
// Set the defaultMode if set in the kube yaml
validMode, err := isValidDefaultMode(secretSource.DefaultMode)
if err != nil {
return nil, fmt.Errorf("invalid DefaultMode for secret %q: %w", secretSource.SecretName, err)
}
if validMode {
kv.DefaultMode = *secretSource.DefaultMode
}
// returns a byte array of a kube secret data, meaning this needs to go into a string map
@ -191,8 +203,9 @@ func VolumeFromPersistentVolumeClaim(claim *v1.PersistentVolumeClaimVolumeSource
func VolumeFromConfigMap(configMapVolumeSource *v1.ConfigMapVolumeSource, configMaps []v1.ConfigMap) (*KubeVolume, error) {
var configMap *v1.ConfigMap
kv := &KubeVolume{
Type: KubeVolumeTypeConfigMap,
Items: map[string][]byte{},
Type: KubeVolumeTypeConfigMap,
Items: map[string][]byte{},
DefaultMode: v1.ConfigMapVolumeSourceDefaultMode,
}
for _, cm := range configMaps {
if cm.Name == configMapVolumeSource.Name {
@ -203,6 +216,14 @@ func VolumeFromConfigMap(configMapVolumeSource *v1.ConfigMapVolumeSource, config
break
}
}
// Set the defaultMode if set in the kube yaml
validMode, err := isValidDefaultMode(configMapVolumeSource.DefaultMode)
if err != nil {
return nil, fmt.Errorf("invalid DefaultMode for configMap %q: %w", configMapVolumeSource.Name, err)
}
if validMode {
kv.DefaultMode = *configMapVolumeSource.DefaultMode
}
if configMap == nil {
// If the volumeSource was optional, move on even if a matching configmap wasn't found
@ -279,3 +300,14 @@ func InitializeVolumes(specVolumes []v1.Volume, configMaps []v1.ConfigMap, secre
return volumes, nil
}
// isValidDefaultMode returns true if mode is between 0 and 0777
func isValidDefaultMode(mode *int32) (bool, error) {
if mode == nil {
return false, nil
}
if *mode >= 0 && *mode <= int32(os.ModePerm) {
return true, nil
}
return false, errors.New("must be between 0000 and 0777")
}

View File

@ -22,6 +22,7 @@ import (
"github.com/containers/podman/v4/libpod/define"
"github.com/containers/podman/v4/pkg/bindings"
"github.com/containers/podman/v4/pkg/bindings/play"
v1 "github.com/containers/podman/v4/pkg/k8s.io/api/core/v1"
"github.com/containers/podman/v4/pkg/util"
. "github.com/containers/podman/v4/test/utils"
"github.com/containers/podman/v4/utils"
@ -710,6 +711,7 @@ spec:
configMap:
name: {{ .ConfigMap.Name }}
optional: {{ .ConfigMap.Optional }}
defaultMode: {{ .ConfigMap.DefaultMode }}
{{- with .ConfigMap.Items }}
items:
{{- range . }}
@ -722,6 +724,7 @@ spec:
secret:
secretName: {{ .SecretVol.SecretName }}
optional: {{ .SecretVol.Optional }}
defaultMode: {{ .SecretVol.DefaultMode }}
{{- with .SecretVol.Items }}
items:
{{- range . }}
@ -1858,15 +1861,17 @@ type PersistentVolumeClaim struct {
}
type ConfigMap struct {
Name string
Items []map[string]string
Optional bool
Name string
Items []map[string]string
Optional bool
DefaultMode int32
}
type SecretVol struct {
SecretName string
Items []map[string]string
Optional bool
SecretName string
Items []map[string]string
Optional bool
DefaultMode int32
}
type EmptyDir struct{}
@ -1908,28 +1913,38 @@ func getPersistentVolumeClaimVolume(vName string) *Volume {
// getConfigMap returns a new ConfigMap Volume given the name and items
// of the ConfigMap.
func getConfigMapVolume(vName string, items []map[string]string, optional bool) *Volume { //nolint:unparam
return &Volume{
func getConfigMapVolume(vName string, items []map[string]string, optional bool, defaultMode *int32) *Volume { //nolint:unparam
vol := &Volume{
VolumeType: "ConfigMap",
Name: defaultVolName,
ConfigMap: ConfigMap{
Name: vName,
Items: items,
Optional: optional,
Name: vName,
Items: items,
Optional: optional,
DefaultMode: v1.ConfigMapVolumeSourceDefaultMode,
},
}
if defaultMode != nil {
vol.ConfigMap.DefaultMode = *defaultMode
}
return vol
}
func getSecretVolume(vName string, items []map[string]string, optional bool) *Volume {
return &Volume{
func getSecretVolume(vName string, items []map[string]string, optional bool, defaultMode *int32) *Volume {
vol := &Volume{
VolumeType: "Secret",
Name: defaultVolName,
SecretVol: SecretVol{
SecretName: vName,
Items: items,
Optional: optional,
SecretName: vName,
Items: items,
Optional: optional,
DefaultMode: v1.SecretVolumeSourceDefaultMode,
},
}
if defaultMode != nil {
vol.SecretVol.DefaultMode = *defaultMode
}
return vol
}
func getEmptyDirVolume() *Volume {
@ -3584,7 +3599,7 @@ VOLUME %s`, CITEST_IMAGE, hostPathDir+"/")
Expect(err).ToNot(HaveOccurred())
ctr := getCtr(withVolumeMount("/test", "", false), withImage(CITEST_IMAGE))
pod := getPod(withVolume(getConfigMapVolume(volumeName, []map[string]string{}, false)), withCtr(ctr))
pod := getPod(withVolume(getConfigMapVolume(volumeName, []map[string]string{}, false, nil)), withCtr(ctr))
podYaml, err := getKubeYaml("pod", pod)
Expect(err).ToNot(HaveOccurred())
yamls := []string{cmYaml, podYaml}
@ -3612,7 +3627,7 @@ VOLUME %s`, CITEST_IMAGE, hostPathDir+"/")
}}
ctr := getCtr(withVolumeMount("/test", "", false), withImage(CITEST_IMAGE))
pod := getPod(withVolume(getConfigMapVolume(volumeName, volumeContents, false)), withCtr(ctr))
pod := getPod(withVolume(getConfigMapVolume(volumeName, volumeContents, false, nil)), withCtr(ctr))
podYaml, err := getKubeYaml("pod", pod)
Expect(err).ToNot(HaveOccurred())
yamls := []string{cmYaml, podYaml}
@ -3637,7 +3652,7 @@ VOLUME %s`, CITEST_IMAGE, hostPathDir+"/")
volumeName := "cmVol"
ctr := getCtr(withVolumeMount("/test", "", false), withImage(CITEST_IMAGE))
pod := getPod(withVolume(getConfigMapVolume(volumeName, []map[string]string{}, true)), withCtr(ctr))
pod := getPod(withVolume(getConfigMapVolume(volumeName, []map[string]string{}, true, nil)), withCtr(ctr))
err = generateKubeYaml("pod", pod, kubeYaml)
Expect(err).ToNot(HaveOccurred())
@ -3646,6 +3661,94 @@ VOLUME %s`, CITEST_IMAGE, hostPathDir+"/")
Expect(kube).Should(ExitCleanly())
})
It("ConfigMap volume with defaultMode set", func() {
volumeName := "cmVol"
cm := getConfigMap(withConfigMapName(volumeName), withConfigMapData("FOO", "foobar"))
cmYaml, err := getKubeYaml("configmap", cm)
Expect(err).ToNot(HaveOccurred())
ctr := getCtr(withVolumeMount("/test", "", false), withImage(CITEST_IMAGE))
defaultMode := int32(0777)
pod := getPod(withVolume(getConfigMapVolume(volumeName, []map[string]string{}, false, &defaultMode)), withCtr(ctr))
podYaml, err := getKubeYaml("pod", pod)
Expect(err).ToNot(HaveOccurred())
yamls := []string{cmYaml, podYaml}
err = generateMultiDocKubeYaml(yamls, kubeYaml)
Expect(err).ToNot(HaveOccurred())
kube := podmanTest.Podman([]string{"kube", "play", kubeYaml})
kube.WaitWithDefaultTimeout()
Expect(kube).Should(ExitCleanly())
cmData := podmanTest.Podman([]string{"exec", getCtrNameInPod(pod), "cat", "/test/FOO"})
cmData.WaitWithDefaultTimeout()
Expect(cmData).Should(ExitCleanly())
Expect(cmData.OutputToString()).To(Equal("foobar"))
inspect := podmanTest.Podman([]string{"volume", "inspect", volumeName, "--format", "{{.Mountpoint}}"})
inspect.WaitWithDefaultTimeout()
Expect(inspect).Should(ExitCleanly())
Expect(inspect.OutputToStringArray()).To(HaveLen(1))
path := inspect.OutputToString()
permData := SystemExec("stat", []string{"-c", "%a", path + "/FOO"})
permData.WaitWithDefaultTimeout()
Expect(permData).Should(ExitCleanly())
Expect(permData.OutputToString()).To(Equal("777"))
})
It("configMap as volume with no defaultMode set", func() {
cmYaml := `
kind: ConfigMap
apiVersion: v1
metadata:
name: example-configmap
data:
foo: bar
---
apiVersion: v1
kind: Pod
metadata:
name: youthfulshaw-pod
spec:
containers:
- command:
- sleep
- "1000"
image: alpine
name: youthfulshaw
volumeMounts:
- name: cm-volume
mountPath: /test
volumes:
- name: cm-volume
configMap:
name: example-configmap
`
err := writeYaml(cmYaml, kubeYaml)
Expect(err).ToNot(HaveOccurred())
kube := podmanTest.Podman([]string{"kube", "play", kubeYaml})
kube.WaitWithDefaultTimeout()
Expect(kube).Should(ExitCleanly())
cmData := podmanTest.Podman([]string{"exec", "youthfulshaw-pod-youthfulshaw", "cat", "/test/foo"})
cmData.WaitWithDefaultTimeout()
Expect(cmData).Should(ExitCleanly())
Expect(cmData.OutputToString()).To(Equal("bar"))
inspect := podmanTest.Podman([]string{"volume", "inspect", "example-configmap", "--format", "{{.Mountpoint}}"})
inspect.WaitWithDefaultTimeout()
Expect(inspect).Should(ExitCleanly())
Expect(inspect.OutputToStringArray()).To(HaveLen(1))
path := inspect.OutputToString()
permData := SystemExec("stat", []string{"-c", "%a", path + "/foo"})
permData.WaitWithDefaultTimeout()
Expect(permData).Should(ExitCleanly())
Expect(permData.OutputToString()).To(Equal("644"))
})
It("with emptyDir volume", func() {
podName := "test-pod"
ctrName1 := "vol-test-ctr"
@ -5101,7 +5204,7 @@ ENV OPENJ9_JAVA_OPTIONS=%q
Expect(err).ToNot(HaveOccurred())
ctr := getCtr(withVolumeMount("/test", "", false), withImage(CITEST_IMAGE))
pod := getPod(withVolume(getSecretVolume(volumeName, []map[string]string{}, false)), withCtr(ctr))
pod := getPod(withVolume(getSecretVolume(volumeName, []map[string]string{}, false, nil)), withCtr(ctr))
podYaml, err := getKubeYaml("pod", pod)
Expect(err).ToNot(HaveOccurred())
yamls := []string{secretYaml, podYaml}
@ -5129,7 +5232,7 @@ ENV OPENJ9_JAVA_OPTIONS=%q
}}
ctr := getCtr(withVolumeMount("/test", "", false), withImage(CITEST_IMAGE))
pod := getPod(withVolume(getSecretVolume(volumeName, volumeContents, false)), withCtr(ctr))
pod := getPod(withVolume(getSecretVolume(volumeName, volumeContents, false, nil)), withCtr(ctr))
podYaml, err := getKubeYaml("pod", pod)
Expect(err).ToNot(HaveOccurred())
yamls := []string{secretYaml, podYaml}
@ -5148,6 +5251,91 @@ ENV OPENJ9_JAVA_OPTIONS=%q
secretData = podmanTest.Podman([]string{"exec", getCtrNameInPod(pod), "cat", "/test/FOO"})
secretData.WaitWithDefaultTimeout()
Expect(secretData).Should(Not(ExitCleanly()))
})
It("secret as volume with defaultMode set", func() {
volumeName := "secretVol"
secret := getSecret(withSecretName(volumeName), withSecretData("FOO", "testuser"))
secretYaml, err := getKubeYaml("secret", secret)
Expect(err).ToNot(HaveOccurred())
ctr := getCtr(withVolumeMount("/test", "", false), withImage(CITEST_IMAGE))
defaultMode := int32(0777)
pod := getPod(withVolume(getSecretVolume(volumeName, []map[string]string{}, false, &defaultMode)), withCtr(ctr))
podYaml, err := getKubeYaml("pod", pod)
Expect(err).ToNot(HaveOccurred())
yamls := []string{secretYaml, podYaml}
err = generateMultiDocKubeYaml(yamls, kubeYaml)
Expect(err).ToNot(HaveOccurred())
kube := podmanTest.Podman([]string{"kube", "play", kubeYaml})
kube.WaitWithDefaultTimeout()
Expect(kube).Should(ExitCleanly())
secretData := podmanTest.Podman([]string{"exec", getCtrNameInPod(pod), "cat", "/test/FOO"})
secretData.WaitWithDefaultTimeout()
Expect(secretData).Should(ExitCleanly())
Expect(secretData.OutputToString()).To(Equal("testuser"))
inspect := podmanTest.Podman([]string{"volume", "inspect", volumeName, "--format", "{{.Mountpoint}}"})
inspect.WaitWithDefaultTimeout()
Expect(inspect).Should(ExitCleanly())
Expect(inspect.OutputToStringArray()).To(HaveLen(1))
path := inspect.OutputToString()
permData := SystemExec("stat", []string{"-c", "%a", path + "/FOO"})
permData.WaitWithDefaultTimeout()
Expect(permData).Should(ExitCleanly())
Expect(permData.OutputToString()).To(Equal("777"))
})
It("secret as volume with no defaultMode set", func() {
secretYaml := `
apiVersion: v1
kind: Secret
metadata:
name: newsecret
type: Opaque
data:
foo: dXNlcg==
---
apiVersion: v1
kind: Pod
metadata:
name: test-pod
spec:
containers:
- command:
- sleep
- "1000"
image: alpine
name: test
volumeMounts:
- name: secret-volume
mountPath: /test
volumes:
- name: secret-volume
secret:
secretName: newsecret
`
err := writeYaml(secretYaml, kubeYaml)
Expect(err).ToNot(HaveOccurred())
kube := podmanTest.Podman([]string{"kube", "play", kubeYaml})
kube.WaitWithDefaultTimeout()
Expect(kube).Should(ExitCleanly())
inspect := podmanTest.Podman([]string{"volume", "inspect", "newsecret", "--format", "{{.Mountpoint}}"})
inspect.WaitWithDefaultTimeout()
Expect(inspect).Should(ExitCleanly())
Expect(inspect.OutputToStringArray()).To(HaveLen(1))
path := inspect.OutputToString()
permData := SystemExec("stat", []string{"-c", "%a", path + "/foo"})
permData.WaitWithDefaultTimeout()
Expect(permData).Should(ExitCleanly())
Expect(permData.OutputToString()).To(Equal("644"))
})
It("with disabled cgroup", func() {
@ -5374,7 +5562,7 @@ spec:
}}
ctr := getCtr(withPullPolicy("always"), withName("testctr"), withCmd([]string{"top"}), withVolumeMount("/etc/BAR", "BAR", false), withImage(CITEST_IMAGE))
pod := getPod(withPodName("testpod"), withVolume(getConfigMapVolume(volumeName, volumeContents, false)), withCtr(ctr))
pod := getPod(withPodName("testpod"), withVolume(getConfigMapVolume(volumeName, volumeContents, false, nil)), withCtr(ctr))
podYaml, err := getKubeYaml("pod", pod)
Expect(err).ToNot(HaveOccurred())