diff --git a/go/api/config/crd/bases/kagent.dev_agents.yaml b/go/api/config/crd/bases/kagent.dev_agents.yaml index 15b08f0ca..35c2067b8 100644 --- a/go/api/config/crd/bases/kagent.dev_agents.yaml +++ b/go/api/config/crd/bases/kagent.dev_agents.yaml @@ -3574,6 +3574,57 @@ spec: - name type: object type: array + envFrom: + description: |- + EnvFrom are sources (ConfigMaps/Secrets) used to populate environment variables + on the agent container. Values defined in Env with a duplicate key take precedence. + items: + description: EnvFromSource represents the source of a set + of ConfigMaps or Secrets + properties: + configMapRef: + description: The ConfigMap to select from + properties: + 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. + More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names + type: string + optional: + description: Specify whether the ConfigMap must + be defined + type: boolean + type: object + x-kubernetes-map-type: atomic + prefix: + description: |- + Optional text to prepend to the name of each environment variable. + May consist of any printable ASCII characters except '='. + type: string + secretRef: + description: The Secret to select from + properties: + 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. + More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names + type: string + optional: + description: Specify whether the Secret must be + defined + type: boolean + type: object + x-kubernetes-map-type: atomic + type: object + type: array extraContainers: description: |- ExtraContainers is a list of additional containers to run alongside the main agent container. @@ -8919,6 +8970,57 @@ spec: - name type: object type: array + envFrom: + description: |- + EnvFrom are sources (ConfigMaps/Secrets) used to populate environment variables + on the agent container. Values defined in Env with a duplicate key take precedence. + items: + description: EnvFromSource represents the source of a set + of ConfigMaps or Secrets + properties: + configMapRef: + description: The ConfigMap to select from + properties: + 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. + More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names + type: string + optional: + description: Specify whether the ConfigMap must + be defined + type: boolean + type: object + x-kubernetes-map-type: atomic + prefix: + description: |- + Optional text to prepend to the name of each environment variable. + May consist of any printable ASCII characters except '='. + type: string + secretRef: + description: The Secret to select from + properties: + 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. + More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names + type: string + optional: + description: Specify whether the Secret must be + defined + type: boolean + type: object + x-kubernetes-map-type: atomic + type: object + type: array extraContainers: description: |- ExtraContainers is a list of additional containers to run alongside the main agent container. diff --git a/go/api/config/crd/bases/kagent.dev_sandboxagents.yaml b/go/api/config/crd/bases/kagent.dev_sandboxagents.yaml index 8dd8560b8..93a46d5ba 100644 --- a/go/api/config/crd/bases/kagent.dev_sandboxagents.yaml +++ b/go/api/config/crd/bases/kagent.dev_sandboxagents.yaml @@ -1231,6 +1231,57 @@ spec: - name type: object type: array + envFrom: + description: |- + EnvFrom are sources (ConfigMaps/Secrets) used to populate environment variables + on the agent container. Values defined in Env with a duplicate key take precedence. + items: + description: EnvFromSource represents the source of a set + of ConfigMaps or Secrets + properties: + configMapRef: + description: The ConfigMap to select from + properties: + 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. + More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names + type: string + optional: + description: Specify whether the ConfigMap must + be defined + type: boolean + type: object + x-kubernetes-map-type: atomic + prefix: + description: |- + Optional text to prepend to the name of each environment variable. + May consist of any printable ASCII characters except '='. + type: string + secretRef: + description: The Secret to select from + properties: + 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. + More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names + type: string + optional: + description: Specify whether the Secret must be + defined + type: boolean + type: object + x-kubernetes-map-type: atomic + type: object + type: array extraContainers: description: |- ExtraContainers is a list of additional containers to run alongside the main agent container. @@ -6576,6 +6627,57 @@ spec: - name type: object type: array + envFrom: + description: |- + EnvFrom are sources (ConfigMaps/Secrets) used to populate environment variables + on the agent container. Values defined in Env with a duplicate key take precedence. + items: + description: EnvFromSource represents the source of a set + of ConfigMaps or Secrets + properties: + configMapRef: + description: The ConfigMap to select from + properties: + 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. + More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names + type: string + optional: + description: Specify whether the ConfigMap must + be defined + type: boolean + type: object + x-kubernetes-map-type: atomic + prefix: + description: |- + Optional text to prepend to the name of each environment variable. + May consist of any printable ASCII characters except '='. + type: string + secretRef: + description: The Secret to select from + properties: + 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. + More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names + type: string + optional: + description: Specify whether the Secret must be + defined + type: boolean + type: object + x-kubernetes-map-type: atomic + type: object + type: array extraContainers: description: |- ExtraContainers is a list of additional containers to run alongside the main agent container. diff --git a/go/api/v1alpha2/agent_types.go b/go/api/v1alpha2/agent_types.go index 230368759..e7ca4ef73 100644 --- a/go/api/v1alpha2/agent_types.go +++ b/go/api/v1alpha2/agent_types.go @@ -453,6 +453,10 @@ type SharedDeploymentSpec struct { // Env are additional environment variables set on the agent container. // +optional Env []corev1.EnvVar `json:"env,omitempty"` + // EnvFrom are sources (ConfigMaps/Secrets) used to populate environment variables + // on the agent container. Values defined in Env with a duplicate key take precedence. + // +optional + EnvFrom []corev1.EnvFromSource `json:"envFrom,omitempty"` // +optional ImagePullPolicy corev1.PullPolicy `json:"imagePullPolicy,omitempty"` // +optional diff --git a/go/api/v1alpha2/zz_generated.deepcopy.go b/go/api/v1alpha2/zz_generated.deepcopy.go index 98d89ec39..829f6560c 100644 --- a/go/api/v1alpha2/zz_generated.deepcopy.go +++ b/go/api/v1alpha2/zz_generated.deepcopy.go @@ -1771,6 +1771,13 @@ func (in *SharedDeploymentSpec) DeepCopyInto(out *SharedDeploymentSpec) { (*in)[i].DeepCopyInto(&(*out)[i]) } } + if in.EnvFrom != nil { + in, out := &in.EnvFrom, &out.EnvFrom + *out = make([]v1.EnvFromSource, len(*in)) + for i := range *in { + (*in)[i].DeepCopyInto(&(*out)[i]) + } + } if in.Resources != nil { in, out := &in.Resources, &out.Resources *out = new(v1.ResourceRequirements) diff --git a/go/core/internal/controller/translator/agent/deployments.go b/go/core/internal/controller/translator/agent/deployments.go index 757a1bd0d..4d0cee9c8 100644 --- a/go/core/internal/controller/translator/agent/deployments.go +++ b/go/core/internal/controller/translator/agent/deployments.go @@ -38,6 +38,7 @@ type resolvedDeployment struct { Labels map[string]string Annotations map[string]string Env []corev1.EnvVar + EnvFrom []corev1.EnvFromSource Resources corev1.ResourceRequirements Tolerations []corev1.Toleration Affinity *corev1.Affinity @@ -254,6 +255,7 @@ func resolveInlineDeployment(agent v1alpha2.AgentObject, mdd *modelDeploymentDat Labels: getDefaultLabels(agent.GetName(), spec.Labels), Annotations: maps.Clone(spec.Annotations), Env: append(slices.Clone(spec.Env), mdd.EnvVars...), + EnvFrom: slices.Clone(spec.EnvFrom), Resources: getDefaultResources(spec.Resources), // Set default resources if not specified Tolerations: slices.Clone(spec.Tolerations), Affinity: spec.Affinity, @@ -338,6 +340,7 @@ func resolveByoDeployment(agent v1alpha2.AgentObject) (*resolvedDeployment, erro Labels: getDefaultLabels(agent.GetName(), spec.Labels), Annotations: maps.Clone(spec.Annotations), Env: slices.Clone(spec.Env), + EnvFrom: slices.Clone(spec.EnvFrom), Resources: getDefaultResources(spec.Resources), // Set default resources if not specified Tolerations: slices.Clone(spec.Tolerations), Affinity: spec.Affinity, diff --git a/go/core/internal/controller/translator/agent/deployments_test.go b/go/core/internal/controller/translator/agent/deployments_test.go index e937a20a0..0055d9a3e 100644 --- a/go/core/internal/controller/translator/agent/deployments_test.go +++ b/go/core/internal/controller/translator/agent/deployments_test.go @@ -1,6 +1,7 @@ package agent import ( + "reflect" "testing" "github.com/kagent-dev/kagent/go/api/v1alpha2" @@ -29,6 +30,60 @@ func TestResolveByoDeployment_NilReplicasPreserved(t *testing.T) { } } +func TestResolveByoDeployment_EnvFromPropagated(t *testing.T) { + envFrom := []corev1.EnvFromSource{ + {SecretRef: &corev1.SecretEnvSource{LocalObjectReference: corev1.LocalObjectReference{Name: "my-secret"}}}, + {ConfigMapRef: &corev1.ConfigMapEnvSource{LocalObjectReference: corev1.LocalObjectReference{Name: "my-config"}}}, + } + agent := &v1alpha2.Agent{ + ObjectMeta: metav1.ObjectMeta{Name: "test", Namespace: "default"}, + Spec: v1alpha2.AgentSpec{ + Type: v1alpha2.AgentType_BYO, + BYO: &v1alpha2.BYOAgentSpec{ + Deployment: &v1alpha2.ByoDeploymentSpec{ + Image: "my-image:latest", + SharedDeploymentSpec: v1alpha2.SharedDeploymentSpec{ + EnvFrom: envFrom, + }, + }, + }, + }, + } + dep, err := resolveByoDeployment(agent) + if err != nil { + t.Fatalf("resolveByoDeployment() error = %v", err) + } + if !reflect.DeepEqual(dep.EnvFrom, envFrom) { + t.Errorf("EnvFrom = %v, want %v", dep.EnvFrom, envFrom) + } +} + +func TestResolveInlineDeployment_EnvFromPropagated(t *testing.T) { + envFrom := []corev1.EnvFromSource{ + {SecretRef: &corev1.SecretEnvSource{LocalObjectReference: corev1.LocalObjectReference{Name: "my-secret"}}}, + } + agent := &v1alpha2.Agent{ + ObjectMeta: metav1.ObjectMeta{Name: "test", Namespace: "default"}, + Spec: v1alpha2.AgentSpec{ + Type: v1alpha2.AgentType_Declarative, + Declarative: &v1alpha2.DeclarativeAgentSpec{ + Deployment: &v1alpha2.DeclarativeDeploymentSpec{ + SharedDeploymentSpec: v1alpha2.SharedDeploymentSpec{ + EnvFrom: envFrom, + }, + }, + }, + }, + } + dep, err := resolveInlineDeployment(agent, &modelDeploymentData{}) + if err != nil { + t.Fatalf("resolveInlineDeployment() error = %v", err) + } + if !reflect.DeepEqual(dep.EnvFrom, envFrom) { + t.Errorf("EnvFrom = %v, want %v", dep.EnvFrom, envFrom) + } +} + func TestValidateExtraContainers(t *testing.T) { t.Parallel() diff --git a/go/core/internal/controller/translator/agent/manifest_builder.go b/go/core/internal/controller/translator/agent/manifest_builder.go index a342cc3c6..8f812cbc9 100644 --- a/go/core/internal/controller/translator/agent/manifest_builder.go +++ b/go/core/internal/controller/translator/agent/manifest_builder.go @@ -58,6 +58,7 @@ type configHashInput struct { type podRuntimeInputs struct { initContainers []corev1.Container envVars []corev1.EnvVar + envFrom []corev1.EnvFromSource volumes []corev1.Volume volumeMounts []corev1.VolumeMount securityContext *corev1.SecurityContext @@ -327,6 +328,7 @@ func buildPodRuntime( return &podRuntimeInputs{ initContainers: initContainers, envVars: envVars, + envFrom: manifestCtx.deployment.EnvFrom, volumes: volumes, volumeMounts: volumeMounts, securityContext: buildContainerSecurityContext(manifestCtx.deployment.SecurityContext, needCodeExecIsolation), @@ -538,6 +540,7 @@ func buildPodTemplate( Ports: []corev1.ContainerPort{{Name: "http", ContainerPort: dep.Port}}, Resources: dep.Resources, Env: runtimeInputs.envVars, + EnvFrom: runtimeInputs.envFrom, ReadinessProbe: &corev1.Probe{ ProbeHandler: corev1.ProbeHandler{ HTTPGet: &corev1.HTTPGetAction{ diff --git a/helm/kagent-crds/templates/kagent.dev_agents.yaml b/helm/kagent-crds/templates/kagent.dev_agents.yaml index 15b08f0ca..35c2067b8 100644 --- a/helm/kagent-crds/templates/kagent.dev_agents.yaml +++ b/helm/kagent-crds/templates/kagent.dev_agents.yaml @@ -3574,6 +3574,57 @@ spec: - name type: object type: array + envFrom: + description: |- + EnvFrom are sources (ConfigMaps/Secrets) used to populate environment variables + on the agent container. Values defined in Env with a duplicate key take precedence. + items: + description: EnvFromSource represents the source of a set + of ConfigMaps or Secrets + properties: + configMapRef: + description: The ConfigMap to select from + properties: + 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. + More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names + type: string + optional: + description: Specify whether the ConfigMap must + be defined + type: boolean + type: object + x-kubernetes-map-type: atomic + prefix: + description: |- + Optional text to prepend to the name of each environment variable. + May consist of any printable ASCII characters except '='. + type: string + secretRef: + description: The Secret to select from + properties: + 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. + More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names + type: string + optional: + description: Specify whether the Secret must be + defined + type: boolean + type: object + x-kubernetes-map-type: atomic + type: object + type: array extraContainers: description: |- ExtraContainers is a list of additional containers to run alongside the main agent container. @@ -8919,6 +8970,57 @@ spec: - name type: object type: array + envFrom: + description: |- + EnvFrom are sources (ConfigMaps/Secrets) used to populate environment variables + on the agent container. Values defined in Env with a duplicate key take precedence. + items: + description: EnvFromSource represents the source of a set + of ConfigMaps or Secrets + properties: + configMapRef: + description: The ConfigMap to select from + properties: + 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. + More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names + type: string + optional: + description: Specify whether the ConfigMap must + be defined + type: boolean + type: object + x-kubernetes-map-type: atomic + prefix: + description: |- + Optional text to prepend to the name of each environment variable. + May consist of any printable ASCII characters except '='. + type: string + secretRef: + description: The Secret to select from + properties: + 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. + More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names + type: string + optional: + description: Specify whether the Secret must be + defined + type: boolean + type: object + x-kubernetes-map-type: atomic + type: object + type: array extraContainers: description: |- ExtraContainers is a list of additional containers to run alongside the main agent container. diff --git a/helm/kagent-crds/templates/kagent.dev_sandboxagents.yaml b/helm/kagent-crds/templates/kagent.dev_sandboxagents.yaml index 8dd8560b8..93a46d5ba 100644 --- a/helm/kagent-crds/templates/kagent.dev_sandboxagents.yaml +++ b/helm/kagent-crds/templates/kagent.dev_sandboxagents.yaml @@ -1231,6 +1231,57 @@ spec: - name type: object type: array + envFrom: + description: |- + EnvFrom are sources (ConfigMaps/Secrets) used to populate environment variables + on the agent container. Values defined in Env with a duplicate key take precedence. + items: + description: EnvFromSource represents the source of a set + of ConfigMaps or Secrets + properties: + configMapRef: + description: The ConfigMap to select from + properties: + 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. + More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names + type: string + optional: + description: Specify whether the ConfigMap must + be defined + type: boolean + type: object + x-kubernetes-map-type: atomic + prefix: + description: |- + Optional text to prepend to the name of each environment variable. + May consist of any printable ASCII characters except '='. + type: string + secretRef: + description: The Secret to select from + properties: + 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. + More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names + type: string + optional: + description: Specify whether the Secret must be + defined + type: boolean + type: object + x-kubernetes-map-type: atomic + type: object + type: array extraContainers: description: |- ExtraContainers is a list of additional containers to run alongside the main agent container. @@ -6576,6 +6627,57 @@ spec: - name type: object type: array + envFrom: + description: |- + EnvFrom are sources (ConfigMaps/Secrets) used to populate environment variables + on the agent container. Values defined in Env with a duplicate key take precedence. + items: + description: EnvFromSource represents the source of a set + of ConfigMaps or Secrets + properties: + configMapRef: + description: The ConfigMap to select from + properties: + 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. + More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names + type: string + optional: + description: Specify whether the ConfigMap must + be defined + type: boolean + type: object + x-kubernetes-map-type: atomic + prefix: + description: |- + Optional text to prepend to the name of each environment variable. + May consist of any printable ASCII characters except '='. + type: string + secretRef: + description: The Secret to select from + properties: + 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. + More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names + type: string + optional: + description: Specify whether the Secret must be + defined + type: boolean + type: object + x-kubernetes-map-type: atomic + type: object + type: array extraContainers: description: |- ExtraContainers is a list of additional containers to run alongside the main agent container. diff --git a/ui/src/types/index.ts b/ui/src/types/index.ts index 502454d51..878b95e40 100644 --- a/ui/src/types/index.ts +++ b/ui/src/types/index.ts @@ -420,6 +420,7 @@ export interface BYODeploymentSpec { labels?: Record; annotations?: Record; env?: EnvVar[]; + envFrom?: EnvFromSource[]; imagePullPolicy?: string; serviceAccountName?: string; } @@ -556,6 +557,16 @@ export interface EnvVar { valueFrom?: EnvVarSource; } +export interface LocalObjectReference { + name?: string; +} + +export interface EnvFromSource { + prefix?: string; + configMapRef?: LocalObjectReference & { optional?: boolean }; + secretRef?: LocalObjectReference & { optional?: boolean }; +} + export interface ValueSource { type: string; name: string;