Kube Play - Support multi-doc YAML files for configmap argument

Read the entire YAML file in case of a multi-doc file
Adjust the unit test
Add a system test
Add comment in the man page

Signed-off-by: Ygal Blum <ygal.blum@gmail.com>
This commit is contained in:
Ygal Blum
2023-05-11 11:13:22 +03:00
parent d7f9ef253a
commit 26f1e95ab4
4 changed files with 166 additions and 35 deletions

View File

@ -174,6 +174,7 @@ Build images even if they are found in the local storage. Use `--build=false` to
Use Kubernetes configmap YAML at path to provide a source for environment variable values within the containers of the pod. (This option is not available with the remote Podman client)
Note: The *--configmap* option can be used multiple times or a comma-separated list of paths can be used to pass multiple Kubernetes configmap YAMLs.
The YAML file may be in a multi-doc YAML format. But, it must container only configmaps
#### **--context-dir**=*path*

View File

@ -524,16 +524,18 @@ func (ic *ContainerEngine) playKubePod(ctx context.Context, podName string, podY
}
defer f.Close()
cm, err := readConfigMapFromFile(f)
cms, err := readConfigMapFromFile(f)
if err != nil {
return nil, nil, fmt.Errorf("%q: %w", p, err)
}
if _, present := configMapIndex[cm.Name]; present {
return nil, nil, fmt.Errorf("ambiguous configuration: the same config map %s is present in YAML and in --configmaps %s file", cm.Name, p)
}
for _, cm := range cms {
if _, present := configMapIndex[cm.Name]; present {
return nil, nil, fmt.Errorf("ambiguous configuration: the same config map %s is present in YAML and in --configmaps %s file", cm.Name, p)
}
configMaps = append(configMaps, cm)
configMaps = append(configMaps, cm)
}
}
mountLabel, err := getMountLabel(podYAML.Spec.SecurityContext)
@ -1152,23 +1154,38 @@ func (ic *ContainerEngine) importVolume(ctx context.Context, vol *libpod.Volume,
}
// readConfigMapFromFile returns a kubernetes configMap obtained from --configmap flag
func readConfigMapFromFile(r io.Reader) (v1.ConfigMap, error) {
var cm v1.ConfigMap
func readConfigMapFromFile(r io.Reader) ([]v1.ConfigMap, error) {
configMaps := make([]v1.ConfigMap, 0)
content, err := io.ReadAll(r)
if err != nil {
return cm, fmt.Errorf("unable to read ConfigMap YAML content: %w", err)
return nil, fmt.Errorf("unable to read ConfigMap YAML content: %w", err)
}
if err := yaml.Unmarshal(content, &cm); err != nil {
return cm, fmt.Errorf("unable to read YAML as Kube ConfigMap: %w", err)
// split yaml document
documentList, err := splitMultiDocYAML(content)
if err != nil {
return nil, fmt.Errorf("unable to read as kube YAML: %w", err)
}
if cm.Kind != "ConfigMap" {
return cm, fmt.Errorf("invalid YAML kind: %q. [ConfigMap] is the only supported by --configmap", cm.Kind)
for _, document := range documentList {
kind, err := getKubeKind(document)
if err != nil {
return nil, fmt.Errorf("unable to read as kube YAML: %w", err)
}
if kind != "ConfigMap" {
return nil, fmt.Errorf("invalid YAML kind: %q. [ConfigMap] is the only supported by --configmap", kind)
}
var configMap v1.ConfigMap
if err := yaml.Unmarshal(document, &configMap); err != nil {
return nil, fmt.Errorf("unable to read YAML as Kube ConfigMap: %w", err)
}
configMaps = append(configMaps, configMap)
}
return cm, nil
return configMaps, nil
}
// splitMultiDocYAML reads multiple documents in a YAML file and

View File

@ -15,7 +15,7 @@ func TestReadConfigMapFromFile(t *testing.T) {
configMapContent string
expectError bool
expectedErrorMsg string
expected v1.ConfigMap
expected []v1.ConfigMap
}{
{
"ValidConfigMap",
@ -29,16 +29,18 @@ data:
`,
false,
"",
v1.ConfigMap{
TypeMeta: v12.TypeMeta{
Kind: "ConfigMap",
APIVersion: "v1",
},
ObjectMeta: v12.ObjectMeta{
Name: "foo",
},
Data: map[string]string{
"myvar": "foo",
[]v1.ConfigMap{
{
TypeMeta: v12.TypeMeta{
Kind: "ConfigMap",
APIVersion: "v1",
},
ObjectMeta: v12.ObjectMeta{
Name: "foo",
},
Data: map[string]string{
"myvar": "foo",
},
},
},
},
@ -54,8 +56,8 @@ data:
myvar: foo
`,
true,
"unable to read YAML as Kube ConfigMap",
v1.ConfigMap{},
"unable to read as kube YAML",
[]v1.ConfigMap{},
},
{
"InvalidKind",
@ -69,7 +71,7 @@ data:
`,
true,
"invalid YAML kind",
v1.ConfigMap{},
[]v1.ConfigMap{},
},
{
"ValidBinaryDataConfigMap",
@ -83,15 +85,64 @@ binaryData:
`,
false,
"",
v1.ConfigMap{
TypeMeta: v12.TypeMeta{
Kind: "ConfigMap",
APIVersion: "v1",
[]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}},
},
ObjectMeta: v12.ObjectMeta{
Name: "foo",
},
},
{
"MultiDocConfigMapFile",
`
---
apiVersion: v1
kind: ConfigMap
metadata:
name: foo
data:
myvar: foo
---
apiVersion: v1
kind: ConfigMap
metadata:
name: bar
data:
myvar: bar
`,
false,
"",
[]v1.ConfigMap{
{
TypeMeta: v12.TypeMeta{
Kind: "ConfigMap",
APIVersion: "v1",
},
ObjectMeta: v12.ObjectMeta{
Name: "foo",
},
Data: map[string]string{
"myvar": "foo",
},
},
{
TypeMeta: v12.TypeMeta{
Kind: "ConfigMap",
APIVersion: "v1",
},
ObjectMeta: v12.ObjectMeta{
Name: "bar",
},
Data: map[string]string{
"myvar": "bar",
},
},
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}},
},
},
}
@ -107,7 +158,9 @@ binaryData:
assert.Contains(t, err.Error(), test.expectedErrorMsg)
} else {
assert.NoError(t, err)
assert.Equal(t, test.expected, cm)
for _, expected := range test.expected {
assert.Contains(t, cm, expected)
}
}
})
}

View File

@ -651,3 +651,63 @@ spec:
run_podman pod ps
run_podman rmi $(pause_image)
}
@test "podman kube play with configmaps" {
skip_if_remote "the configmap argument is supported only locally"
configmap_file=${PODMAN_TMPDIR}/play_kube_configmap_configmaps$(random_string 6).yaml
echo "
---
apiVersion: v1
kind: ConfigMap
metadata:
name: foo
data:
value: foo
---
apiVersion: v1
kind: ConfigMap
metadata:
name: bar
data:
value: bar
" > $configmap_file
pod_file=${PODMAN_TMPDIR}/play_kube_configmap_pod$(random_string 6).yaml
echo "
apiVersion: v1
kind: Pod
metadata:
labels:
app: test
name: test_pod
spec:
restartPolicy: Never
containers:
- name: server
image: $IMAGE
env:
- name: FOO
valueFrom:
configMapKeyRef:
name: foo
key: value
- name: BAR
valueFrom:
configMapKeyRef:
name: bar
key: value
command:
- /bin/sh
args:
- -c
- "echo \$FOO:\$BAR"
" > $pod_file
run_podman kube play --configmap=$configmap_file $pod_file
run_podman wait test_pod-server
run_podman logs test_pod-server
is $output "foo:bar"
run_podman kube down $pod_file
}