Skip to content

Commit

Permalink
Merge pull request #7910 from EduardoVega/7567-podman-configmaps
Browse files Browse the repository at this point in the history
Enable k8s configmaps as flags for play kube
  • Loading branch information
openshift-merge-robot authored Oct 9, 2020
2 parents db684f9 + 39dde9b commit 953e16f
Show file tree
Hide file tree
Showing 6 changed files with 547 additions and 47 deletions.
1 change: 1 addition & 0 deletions cmd/podman/play/kube.go
Original file line number Diff line number Diff line change
Expand Up @@ -60,6 +60,7 @@ func init() {
flags.BoolVar(&kubeOptions.TLSVerifyCLI, "tls-verify", true, "Require HTTPS and verify certificates when contacting registries")
flags.StringVar(&kubeOptions.SignaturePolicy, "signature-policy", "", "`Pathname` of signature policy file (not usually used)")
flags.StringVar(&kubeOptions.SeccompProfileRoot, "seccomp-profile-root", defaultSeccompRoot, "Directory path for seccomp profiles")
flags.StringSliceVar(&kubeOptions.ConfigMaps, "configmap", []string{}, "`Pathname` of a YAML file containing a kubernetes configmap")
}
_ = flags.MarkHidden("signature-policy")
}
Expand Down
15 changes: 15 additions & 0 deletions docs/source/markdown/podman-play-kube.1.md
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,12 @@ environment variable. `export REGISTRY_AUTH_FILE=path`
Use certificates at *path* (\*.crt, \*.cert, \*.key) to connect to the registry.
Default certificates directory is _/etc/containers/certs.d_. (Not available for remote commands)

**--configmap**=*path*

Use Kubernetes configmap YAML at path to provide a source for environment variable values within the containers of the pod.

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.

**--creds**

The [username[:password]] to use to authenticate with the registry if required.
Expand Down Expand Up @@ -66,6 +72,15 @@ $ podman play kube demo.yml
52182811df2b1e73f36476003a66ec872101ea59034ac0d4d3a7b40903b955a6
```

Provide `configmap-foo.yml` and `configmap-bar.yml` as sources for environment variables within the containers.
```
$ podman play kube demo.yml --configmap configmap-foo.yml,configmap-bar.yml
52182811df2b1e73f36476003a66ec872101ea59034ac0d4d3a7b40903b955a6
$ podman play kube demo.yml --configmap configmap-foo.yml --configmap configmap-bar.yml
52182811df2b1e73f36476003a66ec872101ea59034ac0d4d3a7b40903b955a6
```

CNI network(s) can be specified as comma-separated list using ``--network``
```
$ podman play kube demo.yml --network cni1,cni2
Expand Down
2 changes: 2 additions & 0 deletions pkg/domain/entities/play.go
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,8 @@ type PlayKubeOptions struct {
// SeccompProfileRoot - path to a directory containing seccomp
// profiles.
SeccompProfileRoot string
// ConfigMaps - slice of pathnames to kubernetes configmap YAMLs.
ConfigMaps []string
}

// PlayKubePod represents a single pod and associated containers created by play kube
Expand Down
89 changes: 85 additions & 4 deletions pkg/domain/infra/abi/play.go
Original file line number Diff line number Diff line change
Expand Up @@ -311,6 +311,22 @@ func (ic *ContainerEngine) playKubePod(ctx context.Context, podName string, podY
ctrRestartPolicy = libpod.RestartPolicyAlways
}

configMaps := []v1.ConfigMap{}
for _, p := range options.ConfigMaps {
f, err := os.Open(p)
if err != nil {
return nil, err
}
defer f.Close()

cm, err := readConfigMapFromFile(f)
if err != nil {
return nil, errors.Wrapf(err, "%q", p)
}

configMaps = append(configMaps, cm)
}

containers := make([]*libpod.Container, 0, len(podYAML.Spec.Containers))
for _, container := range podYAML.Spec.Containers {
pullPolicy := util.PullImageMissing
Expand All @@ -334,7 +350,7 @@ func (ic *ContainerEngine) playKubePod(ctx context.Context, podName string, podY
if err != nil {
return nil, err
}
conf, err := kubeContainerToCreateConfig(ctx, container, newImage, namespaces, volumes, pod.ID(), podName, podInfraID, seccompPaths)
conf, err := kubeContainerToCreateConfig(ctx, container, newImage, namespaces, volumes, pod.ID(), podName, podInfraID, configMaps, seccompPaths)
if err != nil {
return nil, err
}
Expand Down Expand Up @@ -447,7 +463,7 @@ func setupSecurityContext(securityConfig *createconfig.SecurityConfig, userConfi
}

// kubeContainerToCreateConfig takes a v1.Container and returns a createconfig describing a container
func kubeContainerToCreateConfig(ctx context.Context, containerYAML v1.Container, newImage *image.Image, namespaces map[string]string, volumes map[string]string, podID, podName, infraID string, seccompPaths *kubeSeccompPaths) (*createconfig.CreateConfig, error) {
func kubeContainerToCreateConfig(ctx context.Context, containerYAML v1.Container, newImage *image.Image, namespaces map[string]string, volumes map[string]string, podID, podName, infraID string, configMaps []v1.ConfigMap, seccompPaths *kubeSeccompPaths) (*createconfig.CreateConfig, error) {
var (
containerConfig createconfig.CreateConfig
pidConfig createconfig.PidConfig
Expand Down Expand Up @@ -572,8 +588,17 @@ func kubeContainerToCreateConfig(ctx context.Context, containerYAML v1.Container
}
envs = imageEnv
}
for _, e := range containerYAML.Env {
envs[e.Name] = e.Value
for _, env := range containerYAML.Env {
value := envVarValue(env, configMaps)

envs[env.Name] = value
}
for _, envFrom := range containerYAML.EnvFrom {
cmEnvs := envVarsFromConfigMap(envFrom, configMaps)

for k, v := range cmEnvs {
envs[k] = v
}
}
containerConfig.Env = envs

Expand All @@ -594,6 +619,62 @@ func kubeContainerToCreateConfig(ctx context.Context, containerYAML v1.Container
return &containerConfig, nil
}

// readConfigMapFromFile returns a kubernetes configMap obtained from --configmap flag
func readConfigMapFromFile(r io.Reader) (v1.ConfigMap, error) {
var cm v1.ConfigMap

content, err := ioutil.ReadAll(r)
if err != nil {
return cm, errors.Wrapf(err, "unable to read ConfigMap YAML content")
}

if err := yaml.Unmarshal(content, &cm); err != nil {
return cm, errors.Wrapf(err, "unable to read YAML as Kube ConfigMap")
}

if cm.Kind != "ConfigMap" {
return cm, errors.Errorf("invalid YAML kind: %q. [ConfigMap] is the only supported by --configmap", cm.Kind)
}

return cm, nil
}

// envVarsFromConfigMap returns all key-value pairs as env vars from a configMap that matches the envFrom setting of a container
func envVarsFromConfigMap(envFrom v1.EnvFromSource, configMaps []v1.ConfigMap) map[string]string {
envs := map[string]string{}

if envFrom.ConfigMapRef != nil {
cmName := envFrom.ConfigMapRef.Name

for _, c := range configMaps {
if cmName == c.Name {
envs = c.Data
break
}
}
}

return envs
}

// envVarValue returns the environment variable value configured within the container's env setting.
// It gets the value from a configMap if specified, otherwise returns env.Value
func envVarValue(env v1.EnvVar, configMaps []v1.ConfigMap) string {
for _, c := range configMaps {
if env.ValueFrom != nil {
if env.ValueFrom.ConfigMapKeyRef != nil {
if env.ValueFrom.ConfigMapKeyRef.Name == c.Name {
if value, ok := c.Data[env.ValueFrom.ConfigMapKeyRef.Key]; ok {
return value
}
}
}
}
}

return env.Value
}

// kubeSeccompPaths holds information about a pod YAML's seccomp configuration
// it holds both container and pod seccomp paths
type kubeSeccompPaths struct {
Expand Down
Loading

0 comments on commit 953e16f

Please sign in to comment.