mirror of
https://github.com/containers/podman.git
synced 2025-06-05 22:31:06 +08:00
Merge pull request #20194 from umohnani8/kube-mode
Add DefaultMode to kube play
This commit is contained in:
@ -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
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -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")
|
||||
}
|
||||
|
@ -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())
|
||||
|
Reference in New Issue
Block a user