mirror of
https://github.com/containers/podman.git
synced 2025-08-24 18:12:25 +08:00
play kube: add support for configmap binaryData
Signed-off-by: Jakob Ahrer <jakob@ahrer.dev>
This commit is contained in:

committed by
SoMuchForSubtlety

parent
bb0b1849d7
commit
2bee2216ce
@ -155,7 +155,7 @@ Note: **N/A** means that the option cannot be supported in a single-node Podman
|
|||||||
|
|
||||||
| Field | Support |
|
| Field | Support |
|
||||||
|------------|---------|
|
|------------|---------|
|
||||||
| binaryData | |
|
| binaryData | ✅ |
|
||||||
| data | ✅ |
|
| data | ✅ |
|
||||||
| immutable | |
|
| immutable | |
|
||||||
|
|
||||||
|
@ -486,7 +486,7 @@ func (ic *ContainerEngine) playKubePod(ctx context.Context, podName string, podY
|
|||||||
return nil, fmt.Errorf("cannot create file %q at volume mountpoint %q: %w", k, mountPoint, err)
|
return nil, fmt.Errorf("cannot create file %q at volume mountpoint %q: %w", k, mountPoint, err)
|
||||||
}
|
}
|
||||||
defer f.Close()
|
defer f.Close()
|
||||||
_, err = f.WriteString(v)
|
_, err = f.Write(v)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
@ -71,6 +71,29 @@ data:
|
|||||||
"invalid YAML kind",
|
"invalid YAML kind",
|
||||||
v1.ConfigMap{},
|
v1.ConfigMap{},
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
"ValidBinaryDataConfigMap",
|
||||||
|
`
|
||||||
|
apiVersion: v1
|
||||||
|
kind: ConfigMap
|
||||||
|
metadata:
|
||||||
|
name: foo
|
||||||
|
binaryData:
|
||||||
|
data.zip: UEsDBBQACAAIAMm7SlUAAAAAAAAAAAwAAAAIACAAZGF0YS50eHRVVA0AB+qORGM7j0Rj6o5EY3V4CwABBOgDAAAE6AMAAEvKzEssqlRISSxJ5AIAUEsHCN0J2aAOAAAADAAAAFBLAQIUAxQACAAIAMm7SlXdCdmgDgAAAAwAAAAIACAAAAAAAAAAAACkgQAAAABkYXRhLnR4dFVUDQAH6o5EYzuPRGPqjkRjdXgLAAEE6AMAAAToAwAAUEsFBgAAAAABAAEAVgAAAGQAAAAAAA==
|
||||||
|
`,
|
||||||
|
false,
|
||||||
|
"",
|
||||||
|
v1.ConfigMap{
|
||||||
|
TypeMeta: v12.TypeMeta{
|
||||||
|
Kind: "ConfigMap",
|
||||||
|
APIVersion: "v1",
|
||||||
|
},
|
||||||
|
ObjectMeta: v12.ObjectMeta{
|
||||||
|
Name: "foo",
|
||||||
|
},
|
||||||
|
BinaryData: map[string][]byte{"data.zip": {0x50, 0x4b, 0x03, 0x04, 0x14, 0x00, 0x08, 0x00, 0x08, 0x00, 0xc9, 0xbb, 0x4a, 0x55, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0c, 0x00, 0x00, 0x00, 0x08, 0x00, 0x20, 0x00, 0x64, 0x61, 0x74, 0x61, 0x2e, 0x74, 0x78, 0x74, 0x55, 0x54, 0x0d, 0x00, 0x07, 0xea, 0x8e, 0x44, 0x63, 0x3b, 0x8f, 0x44, 0x63, 0xea, 0x8e, 0x44, 0x63, 0x75, 0x78, 0x0b, 0x00, 0x01, 0x04, 0xe8, 0x03, 0x00, 0x00, 0x04, 0xe8, 0x03, 0x00, 0x00, 0x4b, 0xca, 0xcc, 0x4b, 0x2c, 0xaa, 0x54, 0x48, 0x49, 0x2c, 0x49, 0xe4, 0x02, 0x00, 0x50, 0x4b, 0x07, 0x08, 0xdd, 0x09, 0xd9, 0xa0, 0x0e, 0x00, 0x00, 0x00, 0x0c, 0x00, 0x00, 0x00, 0x50, 0x4b, 0x01, 0x02, 0x14, 0x03, 0x14, 0x00, 0x08, 0x00, 0x08, 0x00, 0xc9, 0xbb, 0x4a, 0x55, 0xdd, 0x09, 0xd9, 0xa0, 0x0e, 0x00, 0x00, 0x00, 0x0c, 0x00, 0x00, 0x00, 0x08, 0x00, 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xa4, 0x81, 0x00, 0x00, 0x00, 0x00, 0x64, 0x61, 0x74, 0x61, 0x2e, 0x74, 0x78, 0x74, 0x55, 0x54, 0x0d, 0x00, 0x07, 0xea, 0x8e, 0x44, 0x63, 0x3b, 0x8f, 0x44, 0x63, 0xea, 0x8e, 0x44, 0x63, 0x75, 0x78, 0x0b, 0x00, 0x01, 0x04, 0xe8, 0x03, 0x00, 0x00, 0x04, 0xe8, 0x03, 0x00, 0x00, 0x50, 0x4b, 0x05, 0x06, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x01, 0x00, 0x56, 0x00, 0x00, 0x00, 0x64, 0x00, 0x00, 0x00, 0x00, 0x00}},
|
||||||
|
},
|
||||||
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
for _, test := range tests {
|
for _, test := range tests {
|
||||||
|
@ -41,6 +41,200 @@ func createSecrets(t *testing.T, d string) *secrets.SecretsManager {
|
|||||||
return secretsManager
|
return secretsManager
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestConfigMapVolumes(t *testing.T) {
|
||||||
|
yes := true
|
||||||
|
tests := []struct {
|
||||||
|
name string
|
||||||
|
volume v1.Volume
|
||||||
|
configmaps []v1.ConfigMap
|
||||||
|
errorMessage string
|
||||||
|
expectedItems map[string][]byte
|
||||||
|
}{
|
||||||
|
{
|
||||||
|
"VolumeFromConfigmap",
|
||||||
|
v1.Volume{
|
||||||
|
Name: "test-volume",
|
||||||
|
VolumeSource: v1.VolumeSource{
|
||||||
|
ConfigMap: &v1.ConfigMapVolumeSource{
|
||||||
|
LocalObjectReference: v1.LocalObjectReference{
|
||||||
|
Name: "bar",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
configMapList,
|
||||||
|
"",
|
||||||
|
map[string][]byte{"myvar": []byte("bar")},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"VolumeFromBinaryConfigmap",
|
||||||
|
v1.Volume{
|
||||||
|
Name: "test-volume",
|
||||||
|
VolumeSource: v1.VolumeSource{
|
||||||
|
ConfigMap: &v1.ConfigMapVolumeSource{
|
||||||
|
LocalObjectReference: v1.LocalObjectReference{
|
||||||
|
Name: "binary-bar",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
configMapList,
|
||||||
|
"",
|
||||||
|
map[string][]byte{"myvar": []byte("bin-bar")},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"ConfigmapMissing",
|
||||||
|
v1.Volume{
|
||||||
|
Name: "test-volume",
|
||||||
|
VolumeSource: v1.VolumeSource{
|
||||||
|
ConfigMap: &v1.ConfigMapVolumeSource{
|
||||||
|
LocalObjectReference: v1.LocalObjectReference{
|
||||||
|
Name: "fizz",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
configMapList,
|
||||||
|
`no such ConfigMap "fizz"`,
|
||||||
|
map[string][]byte{},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"ConfigmapMissingOptional",
|
||||||
|
v1.Volume{
|
||||||
|
Name: "test-volume",
|
||||||
|
VolumeSource: v1.VolumeSource{
|
||||||
|
ConfigMap: &v1.ConfigMapVolumeSource{
|
||||||
|
LocalObjectReference: v1.LocalObjectReference{
|
||||||
|
Name: "fizz",
|
||||||
|
},
|
||||||
|
Optional: &yes,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
configMapList,
|
||||||
|
"",
|
||||||
|
map[string][]byte{},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"MultiValue",
|
||||||
|
v1.Volume{
|
||||||
|
Name: "test-volume",
|
||||||
|
VolumeSource: v1.VolumeSource{
|
||||||
|
ConfigMap: &v1.ConfigMapVolumeSource{
|
||||||
|
LocalObjectReference: v1.LocalObjectReference{
|
||||||
|
Name: "multi-item",
|
||||||
|
},
|
||||||
|
Optional: &yes,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
configMapList,
|
||||||
|
"",
|
||||||
|
map[string][]byte{"foo": []byte("bar"), "fizz": []byte("buzz")},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"SpecificValue",
|
||||||
|
v1.Volume{
|
||||||
|
Name: "test-volume",
|
||||||
|
VolumeSource: v1.VolumeSource{
|
||||||
|
ConfigMap: &v1.ConfigMapVolumeSource{
|
||||||
|
LocalObjectReference: v1.LocalObjectReference{
|
||||||
|
Name: "multi-item",
|
||||||
|
},
|
||||||
|
Optional: &yes,
|
||||||
|
Items: []v1.KeyToPath{{Key: "fizz", Path: "/custom/path"}},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
configMapList,
|
||||||
|
"",
|
||||||
|
map[string][]byte{"/custom/path": []byte("buzz")},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"MultiValueBinary",
|
||||||
|
v1.Volume{
|
||||||
|
Name: "test-volume",
|
||||||
|
VolumeSource: v1.VolumeSource{
|
||||||
|
ConfigMap: &v1.ConfigMapVolumeSource{
|
||||||
|
LocalObjectReference: v1.LocalObjectReference{
|
||||||
|
Name: "multi-binary-item",
|
||||||
|
},
|
||||||
|
Optional: &yes,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
configMapList,
|
||||||
|
"",
|
||||||
|
map[string][]byte{"foo": []byte("bin-bar"), "fizz": []byte("bin-buzz")},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"SpecificValueBinary",
|
||||||
|
v1.Volume{
|
||||||
|
Name: "test-volume",
|
||||||
|
VolumeSource: v1.VolumeSource{
|
||||||
|
ConfigMap: &v1.ConfigMapVolumeSource{
|
||||||
|
LocalObjectReference: v1.LocalObjectReference{
|
||||||
|
Name: "multi-binary-item",
|
||||||
|
},
|
||||||
|
Optional: &yes,
|
||||||
|
Items: []v1.KeyToPath{{Key: "fizz", Path: "/custom/path"}},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
configMapList,
|
||||||
|
"",
|
||||||
|
map[string][]byte{"/custom/path": []byte("bin-buzz")},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"DuplicateValues",
|
||||||
|
v1.Volume{
|
||||||
|
Name: "test-volume",
|
||||||
|
VolumeSource: v1.VolumeSource{
|
||||||
|
ConfigMap: &v1.ConfigMapVolumeSource{
|
||||||
|
LocalObjectReference: v1.LocalObjectReference{
|
||||||
|
Name: "dupe",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
configMapList,
|
||||||
|
`the ConfigMap "dupe" is invalid: duplicate key "foo" present in data and binaryData`,
|
||||||
|
map[string][]byte{},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"DuplicateValuesSpecific",
|
||||||
|
v1.Volume{
|
||||||
|
Name: "test-volume",
|
||||||
|
VolumeSource: v1.VolumeSource{
|
||||||
|
ConfigMap: &v1.ConfigMapVolumeSource{
|
||||||
|
LocalObjectReference: v1.LocalObjectReference{
|
||||||
|
Name: "dupe",
|
||||||
|
},
|
||||||
|
Items: []v1.KeyToPath{{Key: "fizz", Path: "/custom/path"}},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
configMapList,
|
||||||
|
`the ConfigMap "dupe" is invalid: duplicate key "foo" present in data and binaryData`,
|
||||||
|
map[string][]byte{},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, test := range tests {
|
||||||
|
test := test
|
||||||
|
t.Run(test.name, func(t *testing.T) {
|
||||||
|
result, err := VolumeFromConfigMap(test.volume.ConfigMap, test.configmaps)
|
||||||
|
if test.errorMessage == "" {
|
||||||
|
assert.NoError(t, err)
|
||||||
|
assert.Equal(t, test.expectedItems, result.Items)
|
||||||
|
} else {
|
||||||
|
assert.Error(t, err)
|
||||||
|
assert.Equal(t, test.errorMessage, err.Error())
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
func TestEnvVarsFrom(t *testing.T) {
|
func TestEnvVarsFrom(t *testing.T) {
|
||||||
d := t.TempDir()
|
d := t.TempDir()
|
||||||
secretsManager := createSecrets(t, d)
|
secretsManager := createSecrets(t, d)
|
||||||
@ -813,6 +1007,56 @@ var (
|
|||||||
"myvar": "foo",
|
"myvar": "foo",
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
TypeMeta: v12.TypeMeta{
|
||||||
|
Kind: "ConfigMap",
|
||||||
|
},
|
||||||
|
ObjectMeta: v12.ObjectMeta{
|
||||||
|
Name: "binary-bar",
|
||||||
|
},
|
||||||
|
BinaryData: map[string][]byte{
|
||||||
|
"myvar": []byte("bin-bar"),
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
TypeMeta: v12.TypeMeta{
|
||||||
|
Kind: "ConfigMap",
|
||||||
|
},
|
||||||
|
ObjectMeta: v12.ObjectMeta{
|
||||||
|
Name: "multi-item",
|
||||||
|
},
|
||||||
|
Data: map[string]string{
|
||||||
|
"foo": "bar",
|
||||||
|
"fizz": "buzz",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
TypeMeta: v12.TypeMeta{
|
||||||
|
Kind: "ConfigMap",
|
||||||
|
},
|
||||||
|
ObjectMeta: v12.ObjectMeta{
|
||||||
|
Name: "multi-binary-item",
|
||||||
|
},
|
||||||
|
BinaryData: map[string][]byte{
|
||||||
|
"foo": []byte("bin-bar"),
|
||||||
|
"fizz": []byte("bin-buzz"),
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
TypeMeta: v12.TypeMeta{
|
||||||
|
Kind: "ConfigMap",
|
||||||
|
},
|
||||||
|
ObjectMeta: v12.ObjectMeta{
|
||||||
|
Name: "dupe",
|
||||||
|
},
|
||||||
|
BinaryData: map[string][]byte{
|
||||||
|
"fiz": []byte("bin-buzz"),
|
||||||
|
"foo": []byte("bin-bar"),
|
||||||
|
},
|
||||||
|
Data: map[string]string{
|
||||||
|
"foo": "bar",
|
||||||
|
},
|
||||||
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
optional = true
|
optional = true
|
||||||
|
@ -45,7 +45,7 @@ type KubeVolume struct {
|
|||||||
// This is only used when there are volumes in the yaml that refer to a configmap
|
// This is only used when there are volumes in the yaml that refer to a configmap
|
||||||
// Example: if configmap has data "SPECIAL_LEVEL: very" then the file name is "SPECIAL_LEVEL" and the
|
// Example: if configmap has data "SPECIAL_LEVEL: very" then the file name is "SPECIAL_LEVEL" and the
|
||||||
// data in that file is "very".
|
// data in that file is "very".
|
||||||
Items map[string]string
|
Items map[string][]byte
|
||||||
// If the volume is optional, we can move on if it is not found
|
// 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
|
// Only used when there are volumes in a yaml that refer to a configmap
|
||||||
Optional bool
|
Optional bool
|
||||||
@ -163,11 +163,11 @@ func VolumeFromSecret(secretSource *v1.SecretVolumeSource, secretsManager *secre
|
|||||||
kv.Type = KubeVolumeTypeSecret
|
kv.Type = KubeVolumeTypeSecret
|
||||||
kv.Source = secretSource.SecretName
|
kv.Source = secretSource.SecretName
|
||||||
kv.Optional = *secretSource.Optional
|
kv.Optional = *secretSource.Optional
|
||||||
kv.Items = make(map[string]string)
|
kv.Items = make(map[string][]byte)
|
||||||
|
|
||||||
// add key: value pairs to the items array
|
// add key: value pairs to the items array
|
||||||
for key, entry := range data.Data {
|
for key, entry := range data.Data {
|
||||||
kv.Items[key] = entry
|
kv.Items[key] = []byte(entry)
|
||||||
}
|
}
|
||||||
return kv, nil
|
return kv, nil
|
||||||
}
|
}
|
||||||
@ -182,7 +182,10 @@ func VolumeFromPersistentVolumeClaim(claim *v1.PersistentVolumeClaimVolumeSource
|
|||||||
|
|
||||||
func VolumeFromConfigMap(configMapVolumeSource *v1.ConfigMapVolumeSource, configMaps []v1.ConfigMap) (*KubeVolume, error) {
|
func VolumeFromConfigMap(configMapVolumeSource *v1.ConfigMapVolumeSource, configMaps []v1.ConfigMap) (*KubeVolume, error) {
|
||||||
var configMap *v1.ConfigMap
|
var configMap *v1.ConfigMap
|
||||||
kv := &KubeVolume{Type: KubeVolumeTypeConfigMap, Items: map[string]string{}}
|
kv := &KubeVolume{
|
||||||
|
Type: KubeVolumeTypeConfigMap,
|
||||||
|
Items: map[string][]byte{},
|
||||||
|
}
|
||||||
for _, cm := range configMaps {
|
for _, cm := range configMaps {
|
||||||
if cm.Name == configMapVolumeSource.Name {
|
if cm.Name == configMapVolumeSource.Name {
|
||||||
matchedCM := cm
|
matchedCM := cm
|
||||||
@ -203,15 +206,27 @@ func VolumeFromConfigMap(configMapVolumeSource *v1.ConfigMapVolumeSource, config
|
|||||||
return nil, fmt.Errorf("no such ConfigMap %q", configMapVolumeSource.Name)
|
return nil, fmt.Errorf("no such ConfigMap %q", configMapVolumeSource.Name)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// don't allow keys from "data" and "binaryData" to overlap
|
||||||
|
for k := range configMap.Data {
|
||||||
|
if _, ok := configMap.BinaryData[k]; ok {
|
||||||
|
return nil, fmt.Errorf("the ConfigMap %q is invalid: duplicate key %q present in data and binaryData", configMap.Name, k)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// If there are Items specified in the volumeSource, that overwrites the Data from the configmap
|
// If there are Items specified in the volumeSource, that overwrites the Data from the configmap
|
||||||
if len(configMapVolumeSource.Items) > 0 {
|
if len(configMapVolumeSource.Items) > 0 {
|
||||||
for _, item := range configMapVolumeSource.Items {
|
for _, item := range configMapVolumeSource.Items {
|
||||||
if val, ok := configMap.Data[item.Key]; ok {
|
if val, ok := configMap.Data[item.Key]; ok {
|
||||||
|
kv.Items[item.Path] = []byte(val)
|
||||||
|
} else if val, ok := configMap.BinaryData[item.Key]; ok {
|
||||||
kv.Items[item.Path] = val
|
kv.Items[item.Path] = val
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
for k, v := range configMap.Data {
|
for k, v := range configMap.Data {
|
||||||
|
kv.Items[k] = []byte(v)
|
||||||
|
}
|
||||||
|
for k, v := range configMap.BinaryData {
|
||||||
kv.Items[k] = v
|
kv.Items[k] = v
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
Reference in New Issue
Block a user