From 3d00dc0745d106b5233b091426a4c7a9f64ea819 Mon Sep 17 00:00:00 2001 From: Carl Montanari Date: Thu, 13 Jun 2024 10:18:37 -0700 Subject: [PATCH] feat: add extraEnv support at topology and global config --- apis/v1alpha1/configspec.go | 5 + apis/v1alpha1/topologyspec.go | 5 + apis/v1alpha1/zz_generated.deepcopy.go | 14 ++ .../clabernetes.containerlab.dev_configs.yaml | 127 ++++++++++++++++++ ...abernetes.containerlab.dev_topologies.yaml | 127 ++++++++++++++++++ .../clabernetes.containerlab.dev_configs.yaml | 127 ++++++++++++++++++ ...abernetes.containerlab.dev_topologies.yaml | 127 ++++++++++++++++++ charts/clabernetes/templates/configmap.yaml | 4 + charts/clabernetes/values.schema.json | 6 + charts/clabernetes/values.yaml | 4 + .../simple-no-explicit-namespace/topo01.yaml | 1 + .../test-fixtures/golden/simple/topo01.yaml | 1 + config/bootstrap.go | 14 ++ config/fake.go | 4 + config/get.go | 7 + config/manager.go | 2 + controllers/topology/deployment.go | 14 ++ generated/openapi/openapi_generated.go | 42 +++++- 18 files changed, 629 insertions(+), 2 deletions(-) diff --git a/apis/v1alpha1/configspec.go b/apis/v1alpha1/configspec.go index d01a20c..2c1f1b4 100644 --- a/apis/v1alpha1/configspec.go +++ b/apis/v1alpha1/configspec.go @@ -79,6 +79,11 @@ type ConfigDeployment struct { // +kubebuilder:validation:Enum=disabled;critical;warn;info;debug // +optional LauncherLogLevel string `json:"launcherLogLevel,omitempty"` + // ExtraEnv is a list of additional environment variables to set on the launcher container. The + // values here are applied to *all* launchers since this is the global config after all! + // +optional + // +listType=atomic + ExtraEnv []k8scorev1.EnvVar `json:"extraEnv"` } // ConfigImagePull holds configurations relevant to how clabernetes launcher pods handle pulling diff --git a/apis/v1alpha1/topologyspec.go b/apis/v1alpha1/topologyspec.go index 48fef5d..848875c 100644 --- a/apis/v1alpha1/topologyspec.go +++ b/apis/v1alpha1/topologyspec.go @@ -179,6 +179,11 @@ type Deployment struct { // +kubebuilder:validation:Enum=disabled;critical;warn;info;debug // +optional LauncherLogLevel string `json:"launcherLogLevel,omitempty"` + // ExtraEnv is a list of additional environment variables to set on the launcher container. The + // values here override any configured global config extra envs! + // +optional + // +listType=atomic + ExtraEnv []k8scorev1.EnvVar `json:"extraEnv"` } // Scheduling holds information about how the launcher pod(s) should be configured with respect diff --git a/apis/v1alpha1/zz_generated.deepcopy.go b/apis/v1alpha1/zz_generated.deepcopy.go index bb533a2..c6b3b50 100644 --- a/apis/v1alpha1/zz_generated.deepcopy.go +++ b/apis/v1alpha1/zz_generated.deepcopy.go @@ -88,6 +88,13 @@ func (in *ConfigDeployment) DeepCopyInto(out *ConfigDeployment) { (*out)[key] = outVal } } + if in.ExtraEnv != nil { + in, out := &in.ExtraEnv, &out.ExtraEnv + *out = make([]v1.EnvVar, len(*in)) + for i := range *in { + (*in)[i].DeepCopyInto(&(*out)[i]) + } + } return } @@ -397,6 +404,13 @@ func (in *Deployment) DeepCopyInto(out *Deployment) { *out = new(bool) **out = **in } + if in.ExtraEnv != nil { + in, out := &in.ExtraEnv, &out.ExtraEnv + *out = make([]v1.EnvVar, len(*in)) + for i := range *in { + (*in)[i].DeepCopyInto(&(*out)[i]) + } + } return } diff --git a/assets/crd/clabernetes.containerlab.dev_configs.yaml b/assets/crd/clabernetes.containerlab.dev_configs.yaml index bef2622..3866a94 100644 --- a/assets/crd/clabernetes.containerlab.dev_configs.yaml +++ b/assets/crd/clabernetes.containerlab.dev_configs.yaml @@ -68,6 +68,133 @@ spec: some new feature (but do note that just because it exists in containerlab doesnt *necessarily* mean it will be auto-working in clabernetes! type: string + extraEnv: + description: |- + ExtraEnv is a list of additional environment variables to set on the launcher container. The + values here are applied to *all* launchers since this is the global config after all! + items: + description: EnvVar represents an environment variable present + in a Container. + properties: + name: + description: Name of the environment variable. Must be a + C_IDENTIFIER. + type: string + value: + description: |- + Variable references $(VAR_NAME) are expanded + using the previously defined environment variables in the container and + any service environment variables. If a variable cannot be resolved, + the reference in the input string will be unchanged. Double $$ are reduced + to a single $, which allows for escaping the $(VAR_NAME) syntax: i.e. + "$$(VAR_NAME)" will produce the string literal "$(VAR_NAME)". + Escaped references will never be expanded, regardless of whether the variable + exists or not. + Defaults to "". + type: string + valueFrom: + description: Source for the environment variable's value. + Cannot be used if value is not empty. + properties: + configMapKeyRef: + description: Selects a key of a ConfigMap. + properties: + key: + description: The key to select. + type: string + name: + default: "" + description: |- + Name of the referent. + This field is effectively required, but due to backwards compatibility is + allowed to be empty. Instances of this type with an empty value here are + almost certainly wrong. + TODO: Add other useful fields. apiVersion, kind, uid? + More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names + TODO: Drop `kubebuilder:default` when controller-gen doesn't need it https://github.com/kubernetes-sigs/kubebuilder/issues/3896. + type: string + optional: + description: Specify whether the ConfigMap or its + key must be defined + type: boolean + required: + - key + type: object + x-kubernetes-map-type: atomic + fieldRef: + description: |- + Selects a field of the pod: supports metadata.name, metadata.namespace, `metadata.labels['']`, `metadata.annotations['']`, + spec.nodeName, spec.serviceAccountName, status.hostIP, status.podIP, status.podIPs. + properties: + apiVersion: + description: Version of the schema the FieldPath + is written in terms of, defaults to "v1". + type: string + fieldPath: + description: Path of the field to select in the + specified API version. + type: string + required: + - fieldPath + type: object + x-kubernetes-map-type: atomic + resourceFieldRef: + description: |- + Selects a resource of the container: only resources limits and requests + (limits.cpu, limits.memory, limits.ephemeral-storage, requests.cpu, requests.memory and requests.ephemeral-storage) are currently supported. + properties: + containerName: + description: 'Container name: required for volumes, + optional for env vars' + type: string + divisor: + anyOf: + - type: integer + - type: string + description: Specifies the output format of the + exposed resources, defaults to "1" + pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ + x-kubernetes-int-or-string: true + resource: + description: 'Required: resource to select' + type: string + required: + - resource + type: object + x-kubernetes-map-type: atomic + secretKeyRef: + description: Selects a key of a secret in the pod's + namespace + properties: + key: + description: The key of the secret to select from. Must + be a valid secret key. + type: string + name: + default: "" + description: |- + Name of the referent. + This field is effectively required, but due to backwards compatibility is + allowed to be empty. Instances of this type with an empty value here are + almost certainly wrong. + TODO: Add other useful fields. apiVersion, kind, uid? + More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names + TODO: Drop `kubebuilder:default` when controller-gen doesn't need it https://github.com/kubernetes-sigs/kubebuilder/issues/3896. + type: string + optional: + description: Specify whether the Secret or its key + must be defined + type: boolean + required: + - key + type: object + x-kubernetes-map-type: atomic + type: object + required: + - name + type: object + type: array + x-kubernetes-list-type: atomic launcherImage: default: ghcr.io/srl-labs/clabernetes/clabernetes-launcher:latest description: LauncherImage sets the default launcher image to diff --git a/assets/crd/clabernetes.containerlab.dev_topologies.yaml b/assets/crd/clabernetes.containerlab.dev_topologies.yaml index a04c69d..ec512d5 100644 --- a/assets/crd/clabernetes.containerlab.dev_topologies.yaml +++ b/assets/crd/clabernetes.containerlab.dev_topologies.yaml @@ -103,6 +103,133 @@ spec: some new feature (but do note that just because it exists in containerlab doesnt *necessarily* mean it will be auto-working in clabernetes! type: string + extraEnv: + description: |- + ExtraEnv is a list of additional environment variables to set on the launcher container. The + values here override any configured global config extra envs! + items: + description: EnvVar represents an environment variable present + in a Container. + properties: + name: + description: Name of the environment variable. Must be a + C_IDENTIFIER. + type: string + value: + description: |- + Variable references $(VAR_NAME) are expanded + using the previously defined environment variables in the container and + any service environment variables. If a variable cannot be resolved, + the reference in the input string will be unchanged. Double $$ are reduced + to a single $, which allows for escaping the $(VAR_NAME) syntax: i.e. + "$$(VAR_NAME)" will produce the string literal "$(VAR_NAME)". + Escaped references will never be expanded, regardless of whether the variable + exists or not. + Defaults to "". + type: string + valueFrom: + description: Source for the environment variable's value. + Cannot be used if value is not empty. + properties: + configMapKeyRef: + description: Selects a key of a ConfigMap. + properties: + key: + description: The key to select. + type: string + name: + default: "" + description: |- + Name of the referent. + This field is effectively required, but due to backwards compatibility is + allowed to be empty. Instances of this type with an empty value here are + almost certainly wrong. + TODO: Add other useful fields. apiVersion, kind, uid? + More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names + TODO: Drop `kubebuilder:default` when controller-gen doesn't need it https://github.com/kubernetes-sigs/kubebuilder/issues/3896. + type: string + optional: + description: Specify whether the ConfigMap or its + key must be defined + type: boolean + required: + - key + type: object + x-kubernetes-map-type: atomic + fieldRef: + description: |- + Selects a field of the pod: supports metadata.name, metadata.namespace, `metadata.labels['']`, `metadata.annotations['']`, + spec.nodeName, spec.serviceAccountName, status.hostIP, status.podIP, status.podIPs. + properties: + apiVersion: + description: Version of the schema the FieldPath + is written in terms of, defaults to "v1". + type: string + fieldPath: + description: Path of the field to select in the + specified API version. + type: string + required: + - fieldPath + type: object + x-kubernetes-map-type: atomic + resourceFieldRef: + description: |- + Selects a resource of the container: only resources limits and requests + (limits.cpu, limits.memory, limits.ephemeral-storage, requests.cpu, requests.memory and requests.ephemeral-storage) are currently supported. + properties: + containerName: + description: 'Container name: required for volumes, + optional for env vars' + type: string + divisor: + anyOf: + - type: integer + - type: string + description: Specifies the output format of the + exposed resources, defaults to "1" + pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ + x-kubernetes-int-or-string: true + resource: + description: 'Required: resource to select' + type: string + required: + - resource + type: object + x-kubernetes-map-type: atomic + secretKeyRef: + description: Selects a key of a secret in the pod's + namespace + properties: + key: + description: The key of the secret to select from. Must + be a valid secret key. + type: string + name: + default: "" + description: |- + Name of the referent. + This field is effectively required, but due to backwards compatibility is + allowed to be empty. Instances of this type with an empty value here are + almost certainly wrong. + TODO: Add other useful fields. apiVersion, kind, uid? + More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names + TODO: Drop `kubebuilder:default` when controller-gen doesn't need it https://github.com/kubernetes-sigs/kubebuilder/issues/3896. + type: string + optional: + description: Specify whether the Secret or its key + must be defined + type: boolean + required: + - key + type: object + x-kubernetes-map-type: atomic + type: object + required: + - name + type: object + type: array + x-kubernetes-list-type: atomic filesFromConfigMap: additionalProperties: items: diff --git a/charts/clabernetes/crds/clabernetes.containerlab.dev_configs.yaml b/charts/clabernetes/crds/clabernetes.containerlab.dev_configs.yaml index bef2622..3866a94 100644 --- a/charts/clabernetes/crds/clabernetes.containerlab.dev_configs.yaml +++ b/charts/clabernetes/crds/clabernetes.containerlab.dev_configs.yaml @@ -68,6 +68,133 @@ spec: some new feature (but do note that just because it exists in containerlab doesnt *necessarily* mean it will be auto-working in clabernetes! type: string + extraEnv: + description: |- + ExtraEnv is a list of additional environment variables to set on the launcher container. The + values here are applied to *all* launchers since this is the global config after all! + items: + description: EnvVar represents an environment variable present + in a Container. + properties: + name: + description: Name of the environment variable. Must be a + C_IDENTIFIER. + type: string + value: + description: |- + Variable references $(VAR_NAME) are expanded + using the previously defined environment variables in the container and + any service environment variables. If a variable cannot be resolved, + the reference in the input string will be unchanged. Double $$ are reduced + to a single $, which allows for escaping the $(VAR_NAME) syntax: i.e. + "$$(VAR_NAME)" will produce the string literal "$(VAR_NAME)". + Escaped references will never be expanded, regardless of whether the variable + exists or not. + Defaults to "". + type: string + valueFrom: + description: Source for the environment variable's value. + Cannot be used if value is not empty. + properties: + configMapKeyRef: + description: Selects a key of a ConfigMap. + properties: + key: + description: The key to select. + type: string + name: + default: "" + description: |- + Name of the referent. + This field is effectively required, but due to backwards compatibility is + allowed to be empty. Instances of this type with an empty value here are + almost certainly wrong. + TODO: Add other useful fields. apiVersion, kind, uid? + More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names + TODO: Drop `kubebuilder:default` when controller-gen doesn't need it https://github.com/kubernetes-sigs/kubebuilder/issues/3896. + type: string + optional: + description: Specify whether the ConfigMap or its + key must be defined + type: boolean + required: + - key + type: object + x-kubernetes-map-type: atomic + fieldRef: + description: |- + Selects a field of the pod: supports metadata.name, metadata.namespace, `metadata.labels['']`, `metadata.annotations['']`, + spec.nodeName, spec.serviceAccountName, status.hostIP, status.podIP, status.podIPs. + properties: + apiVersion: + description: Version of the schema the FieldPath + is written in terms of, defaults to "v1". + type: string + fieldPath: + description: Path of the field to select in the + specified API version. + type: string + required: + - fieldPath + type: object + x-kubernetes-map-type: atomic + resourceFieldRef: + description: |- + Selects a resource of the container: only resources limits and requests + (limits.cpu, limits.memory, limits.ephemeral-storage, requests.cpu, requests.memory and requests.ephemeral-storage) are currently supported. + properties: + containerName: + description: 'Container name: required for volumes, + optional for env vars' + type: string + divisor: + anyOf: + - type: integer + - type: string + description: Specifies the output format of the + exposed resources, defaults to "1" + pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ + x-kubernetes-int-or-string: true + resource: + description: 'Required: resource to select' + type: string + required: + - resource + type: object + x-kubernetes-map-type: atomic + secretKeyRef: + description: Selects a key of a secret in the pod's + namespace + properties: + key: + description: The key of the secret to select from. Must + be a valid secret key. + type: string + name: + default: "" + description: |- + Name of the referent. + This field is effectively required, but due to backwards compatibility is + allowed to be empty. Instances of this type with an empty value here are + almost certainly wrong. + TODO: Add other useful fields. apiVersion, kind, uid? + More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names + TODO: Drop `kubebuilder:default` when controller-gen doesn't need it https://github.com/kubernetes-sigs/kubebuilder/issues/3896. + type: string + optional: + description: Specify whether the Secret or its key + must be defined + type: boolean + required: + - key + type: object + x-kubernetes-map-type: atomic + type: object + required: + - name + type: object + type: array + x-kubernetes-list-type: atomic launcherImage: default: ghcr.io/srl-labs/clabernetes/clabernetes-launcher:latest description: LauncherImage sets the default launcher image to diff --git a/charts/clabernetes/crds/clabernetes.containerlab.dev_topologies.yaml b/charts/clabernetes/crds/clabernetes.containerlab.dev_topologies.yaml index a04c69d..ec512d5 100644 --- a/charts/clabernetes/crds/clabernetes.containerlab.dev_topologies.yaml +++ b/charts/clabernetes/crds/clabernetes.containerlab.dev_topologies.yaml @@ -103,6 +103,133 @@ spec: some new feature (but do note that just because it exists in containerlab doesnt *necessarily* mean it will be auto-working in clabernetes! type: string + extraEnv: + description: |- + ExtraEnv is a list of additional environment variables to set on the launcher container. The + values here override any configured global config extra envs! + items: + description: EnvVar represents an environment variable present + in a Container. + properties: + name: + description: Name of the environment variable. Must be a + C_IDENTIFIER. + type: string + value: + description: |- + Variable references $(VAR_NAME) are expanded + using the previously defined environment variables in the container and + any service environment variables. If a variable cannot be resolved, + the reference in the input string will be unchanged. Double $$ are reduced + to a single $, which allows for escaping the $(VAR_NAME) syntax: i.e. + "$$(VAR_NAME)" will produce the string literal "$(VAR_NAME)". + Escaped references will never be expanded, regardless of whether the variable + exists or not. + Defaults to "". + type: string + valueFrom: + description: Source for the environment variable's value. + Cannot be used if value is not empty. + properties: + configMapKeyRef: + description: Selects a key of a ConfigMap. + properties: + key: + description: The key to select. + type: string + name: + default: "" + description: |- + Name of the referent. + This field is effectively required, but due to backwards compatibility is + allowed to be empty. Instances of this type with an empty value here are + almost certainly wrong. + TODO: Add other useful fields. apiVersion, kind, uid? + More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names + TODO: Drop `kubebuilder:default` when controller-gen doesn't need it https://github.com/kubernetes-sigs/kubebuilder/issues/3896. + type: string + optional: + description: Specify whether the ConfigMap or its + key must be defined + type: boolean + required: + - key + type: object + x-kubernetes-map-type: atomic + fieldRef: + description: |- + Selects a field of the pod: supports metadata.name, metadata.namespace, `metadata.labels['']`, `metadata.annotations['']`, + spec.nodeName, spec.serviceAccountName, status.hostIP, status.podIP, status.podIPs. + properties: + apiVersion: + description: Version of the schema the FieldPath + is written in terms of, defaults to "v1". + type: string + fieldPath: + description: Path of the field to select in the + specified API version. + type: string + required: + - fieldPath + type: object + x-kubernetes-map-type: atomic + resourceFieldRef: + description: |- + Selects a resource of the container: only resources limits and requests + (limits.cpu, limits.memory, limits.ephemeral-storage, requests.cpu, requests.memory and requests.ephemeral-storage) are currently supported. + properties: + containerName: + description: 'Container name: required for volumes, + optional for env vars' + type: string + divisor: + anyOf: + - type: integer + - type: string + description: Specifies the output format of the + exposed resources, defaults to "1" + pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ + x-kubernetes-int-or-string: true + resource: + description: 'Required: resource to select' + type: string + required: + - resource + type: object + x-kubernetes-map-type: atomic + secretKeyRef: + description: Selects a key of a secret in the pod's + namespace + properties: + key: + description: The key of the secret to select from. Must + be a valid secret key. + type: string + name: + default: "" + description: |- + Name of the referent. + This field is effectively required, but due to backwards compatibility is + allowed to be empty. Instances of this type with an empty value here are + almost certainly wrong. + TODO: Add other useful fields. apiVersion, kind, uid? + More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names + TODO: Drop `kubebuilder:default` when controller-gen doesn't need it https://github.com/kubernetes-sigs/kubebuilder/issues/3896. + type: string + optional: + description: Specify whether the Secret or its key + must be defined + type: boolean + required: + - key + type: object + x-kubernetes-map-type: atomic + type: object + required: + - name + type: object + type: array + x-kubernetes-list-type: atomic filesFromConfigMap: additionalProperties: items: diff --git a/charts/clabernetes/templates/configmap.yaml b/charts/clabernetes/templates/configmap.yaml index fecc9d3..d73c84d 100644 --- a/charts/clabernetes/templates/configmap.yaml +++ b/charts/clabernetes/templates/configmap.yaml @@ -56,4 +56,8 @@ data: criKindOverride: {{ .Values.globalConfig.imagePull.criKindOverride }} {{- end }} naming: {{ .Values.globalConfig.naming }} + {{- if .Values.globalConfig.deployment.extraEnv }} + extraEnv: |- +{{ .Values.globalConfig.deployment.extraEnv | toYaml | indent 4 }} + {{- end }} {{- end }} \ No newline at end of file diff --git a/charts/clabernetes/values.schema.json b/charts/clabernetes/values.schema.json index 2edf491..5fb0d8d 100644 --- a/charts/clabernetes/values.schema.json +++ b/charts/clabernetes/values.schema.json @@ -114,6 +114,12 @@ }, "containerlabVersion": { "type": "string" + }, + "extraEnv": { + "type": "array", + "items": { + "type": "object" + } } } }, diff --git a/charts/clabernetes/values.yaml b/charts/clabernetes/values.yaml index f24bb95..e311015 100644 --- a/charts/clabernetes/values.yaml +++ b/charts/clabernetes/values.yaml @@ -138,6 +138,10 @@ globalConfig: # version of containerlab. generally don't set this unless you need to. containerlabVersion: "" + # extraEnv is a list of k8scorev1.EnvVar that will be set on any launcher pods. Note that any + # configured global config env vars will be ignored if a Topology has an extraEnv config. + extraEnv: [] + # name is the global setting that governs a Topology's "naming" field when set to "global". # valid options are "prefixed" or "non-prefixed", see the api types for more detail. naming: prefixed diff --git a/clabverter/test-fixtures/golden/simple-no-explicit-namespace/topo01.yaml b/clabverter/test-fixtures/golden/simple-no-explicit-namespace/topo01.yaml index ce5c686..50f5db4 100755 --- a/clabverter/test-fixtures/golden/simple-no-explicit-namespace/topo01.yaml +++ b/clabverter/test-fixtures/golden/simple-no-explicit-namespace/topo01.yaml @@ -42,6 +42,7 @@ spec: containerlabDebug: null containerlabTimeout: "" containerlabVersion: 0.51.0 + extraEnv: null filesFromConfigMap: srl1: - configMapName: topo01-srl1-startup-config diff --git a/clabverter/test-fixtures/golden/simple/topo01.yaml b/clabverter/test-fixtures/golden/simple/topo01.yaml index 0c97667..8a7fdcb 100755 --- a/clabverter/test-fixtures/golden/simple/topo01.yaml +++ b/clabverter/test-fixtures/golden/simple/topo01.yaml @@ -41,6 +41,7 @@ spec: deployment: containerlabDebug: null containerlabTimeout: "" + extraEnv: null filesFromConfigMap: srl1: - configMapName: topo01-srl1-startup-config diff --git a/config/bootstrap.go b/config/bootstrap.go index 17b2459..5fe8a17 100644 --- a/config/bootstrap.go +++ b/config/bootstrap.go @@ -31,6 +31,7 @@ type bootstrapConfig struct { criKindOverride string naming string containerlabVersion string + extraEnv []k8scorev1.EnvVar } func bootstrapFromConfigMap( //nolint:gocyclo,funlen,gocognit @@ -156,6 +157,14 @@ func bootstrapFromConfigMap( //nolint:gocyclo,funlen,gocognit bc.containerlabVersion = containerlabVersion } + extraEnvData, extraEnvOk := inMap["extraEnv"] + if extraEnvOk { + err := sigsyaml.Unmarshal([]byte(extraEnvData), &bc.extraEnv) + if err != nil { + outErrors = append(outErrors, err.Error()) + } + } + var err error if len(outErrors) > 0 { @@ -275,6 +284,10 @@ func mergeFromBootstrapConfigMerge( //nolint:gocyclo if config.Spec.Deployment.ContainerlabVersion == "" { config.Spec.Deployment.ContainerlabVersion = bootstrap.containerlabVersion } + + if len(config.Spec.Deployment.ExtraEnv) == 0 { + config.Spec.Deployment.ExtraEnv = bootstrap.extraEnv + } } func mergeFromBootstrapConfigReplace( @@ -301,6 +314,7 @@ func mergeFromBootstrapConfigReplace( LauncherImagePullPolicy: bootstrap.launcherImagePullPolicy, LauncherLogLevel: bootstrap.launcherLogLevel, ContainerlabVersion: bootstrap.containerlabVersion, + ExtraEnv: bootstrap.extraEnv, }, Naming: bootstrap.naming, } diff --git a/config/fake.go b/config/fake.go index 66fe34c..af2f850 100644 --- a/config/fake.go +++ b/config/fake.go @@ -86,6 +86,10 @@ func (f fakeManager) GetLauncherLogLevel() string { return clabernetesconstants.Info } +func (f fakeManager) GetExtraEnv() []k8scorev1.EnvVar { + return nil +} + func (f fakeManager) GetRemoveTopologyPrefix() bool { return false } diff --git a/config/get.go b/config/get.go index dfbfd56..9101ed4 100644 --- a/config/get.go +++ b/config/get.go @@ -149,6 +149,13 @@ func (m *manager) GetLauncherLogLevel() string { return m.config.Deployment.LauncherLogLevel } +func (m *manager) GetExtraEnv() []k8scorev1.EnvVar { + m.lock.RLock() + defer m.lock.RUnlock() + + return m.config.Deployment.ExtraEnv +} + func (m *manager) GetRemoveTopologyPrefix() bool { m.lock.RLock() defer m.lock.RUnlock() diff --git a/config/manager.go b/config/manager.go index ed76b50..515813a 100644 --- a/config/manager.go +++ b/config/manager.go @@ -145,6 +145,8 @@ type Manager interface { GetLauncherImagePullPolicy() string // GetLauncherLogLevel returns the default launcher log level. GetLauncherLogLevel() string + // GetExtraEnv returns the default extra env vars for setting on launcher containers. + GetExtraEnv() []k8scorev1.EnvVar // GetRemoveTopologyPrefix returns true if the topology prefix should be removed from Topology // resources, otherwise false. GetRemoveTopologyPrefix() bool diff --git a/controllers/topology/deployment.go b/controllers/topology/deployment.go index 6d44b1a..0e34da2 100644 --- a/controllers/topology/deployment.go +++ b/controllers/topology/deployment.go @@ -635,6 +635,20 @@ func (r *DeploymentReconciler) renderDeploymentContainerEnv( //nolint: funlen ) } + if len(owningTopology.Spec.Deployment.ExtraEnv) > 0 { + envs = append( + envs, + owningTopology.Spec.Deployment.ExtraEnv..., + ) + } else { + globalEnvs := r.configManagerGetter().GetExtraEnv() + + envs = append( + envs, + globalEnvs..., + ) + } + deployment.Spec.Template.Spec.Containers[0].Env = envs } diff --git a/generated/openapi/openapi_generated.go b/generated/openapi/openapi_generated.go index 1eab516..53ed655 100644 --- a/generated/openapi/openapi_generated.go +++ b/generated/openapi/openapi_generated.go @@ -282,12 +282,31 @@ func schema_srl_labs_clabernetes_apis_v1alpha1_ConfigDeployment( Format: "", }, }, + "extraEnv": { + VendorExtensible: spec.VendorExtensible{ + Extensions: spec.Extensions{ + "x-kubernetes-list-type": "atomic", + }, + }, + SchemaProps: spec.SchemaProps{ + Description: "ExtraEnv is a list of additional environment variables to set on the launcher container. The values here are applied to *all* launchers since this is the global config after all!", + Type: []string{"array"}, + Items: &spec.SchemaOrArray{ + Schema: &spec.Schema{ + SchemaProps: spec.SchemaProps{ + Default: map[string]interface{}{}, + Ref: ref("k8s.io/api/core/v1.EnvVar"), + }, + }, + }, + }, + }, }, Required: []string{"launcherImage", "launcherImagePullPolicy"}, }, }, Dependencies: []string{ - "k8s.io/api/core/v1.ResourceRequirements"}, + "k8s.io/api/core/v1.EnvVar", "k8s.io/api/core/v1.ResourceRequirements"}, } } @@ -842,11 +861,30 @@ func schema_srl_labs_clabernetes_apis_v1alpha1_Deployment( Format: "", }, }, + "extraEnv": { + VendorExtensible: spec.VendorExtensible{ + Extensions: spec.Extensions{ + "x-kubernetes-list-type": "atomic", + }, + }, + SchemaProps: spec.SchemaProps{ + Description: "ExtraEnv is a list of additional environment variables to set on the launcher container. The values here override any configured global config extra envs!", + Type: []string{"array"}, + Items: &spec.SchemaOrArray{ + Schema: &spec.Schema{ + SchemaProps: spec.SchemaProps{ + Default: map[string]interface{}{}, + Ref: ref("k8s.io/api/core/v1.EnvVar"), + }, + }, + }, + }, + }, }, }, }, Dependencies: []string{ - "github.com/srl-labs/clabernetes/apis/v1alpha1.FileFromConfigMap", "github.com/srl-labs/clabernetes/apis/v1alpha1.FileFromURL", "github.com/srl-labs/clabernetes/apis/v1alpha1.Persistence", "github.com/srl-labs/clabernetes/apis/v1alpha1.Scheduling", "k8s.io/api/core/v1.ResourceRequirements"}, + "github.com/srl-labs/clabernetes/apis/v1alpha1.FileFromConfigMap", "github.com/srl-labs/clabernetes/apis/v1alpha1.FileFromURL", "github.com/srl-labs/clabernetes/apis/v1alpha1.Persistence", "github.com/srl-labs/clabernetes/apis/v1alpha1.Scheduling", "k8s.io/api/core/v1.EnvVar", "k8s.io/api/core/v1.ResourceRequirements"}, } }