Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[v0.36.x] Update env priority #571

Merged
merged 3 commits into from
Jun 28, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
13 changes: 13 additions & 0 deletions changelog/v0.36.7/env-template-sources.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
changelog:
- type: FIX
issueLink: https://github.com/solo-io/skv2/issues/565
description: >
Add support for other sources in templated env vars field.
skipCI: "false"
- type: NON_USER_FACING
description: >
Reorder the priority of the environment variables to be loaded in the following order:
1. Templated environment variables
2. Environment variables
3. Extra environment variables
skipCI: "false"
2 changes: 1 addition & 1 deletion ci/oss_compliance/osa_provided.md
Original file line number Diff line number Diff line change
Expand Up @@ -51,7 +51,7 @@ Name|Version|License
[config/v1alpha1](https://k8s.io/component-base/config/v1alpha1)|v0.28.3|Apache License 2.0
[v2/internal](https://k8s.io/klog/v2/internal)|v2.100.1|Apache License 2.0
[kube-openapi/pkg](https://k8s.io/kube-openapi/pkg)|v0.0.0-20230717233707-2695361300d9|Apache License 2.0
[k8s.io/utils](https://k8s.io/utils)|v0.0.0-20230406110748-d93618cff8a2|Apache License 2.0
[k8s.io/utils](https://k8s.io/utils)|v0.0.0-20240502163921-fe8a2dddb1d0|Apache License 2.0
[controller-runtime/pkg](https://sigs.k8s.io/controller-runtime/pkg)|v0.16.3|Apache License 2.0
[encoding/json](https://sigs.k8s.io/json/internal/golang/encoding/json)|v0.0.0-20221116044647-bc3834ca7abd|Apache License 2.0
[structured-merge-diff/v4](https://sigs.k8s.io/structured-merge-diff/v4)|v4.2.3|Apache License 2.0
Expand Down
160 changes: 124 additions & 36 deletions codegen/cmd_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -10,27 +10,26 @@ import (
"reflect"
"strings"

goyaml "gopkg.in/yaml.v3"
rbacv1 "k8s.io/api/rbac/v1"
v12 "k8s.io/apiextensions-apiserver/pkg/apis/apiextensions/v1"
"k8s.io/utils/pointer"

. "github.com/onsi/ginkgo/v2"
. "github.com/onsi/gomega"
. "github.com/solo-io/skv2/codegen"
"github.com/solo-io/skv2/codegen/model"
. "github.com/solo-io/skv2/codegen/model"
"github.com/solo-io/skv2/codegen/skv2_anyvendor"
"github.com/solo-io/skv2/codegen/util"
"github.com/solo-io/skv2/contrib"
goyaml "gopkg.in/yaml.v3"
appsv1 "k8s.io/api/apps/v1"
v1 "k8s.io/api/core/v1"
rbacv1 "k8s.io/api/rbac/v1"
v12 "k8s.io/apiextensions-apiserver/pkg/apis/apiextensions/v1"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/apimachinery/pkg/apis/meta/v1/unstructured"
"k8s.io/apimachinery/pkg/runtime/schema"
"k8s.io/apimachinery/pkg/util/intstr"
kubeyaml "k8s.io/apimachinery/pkg/util/yaml"
"k8s.io/utils/ptr"
"sigs.k8s.io/yaml"

. "github.com/solo-io/skv2/codegen"
. "github.com/solo-io/skv2/codegen/model"
"github.com/solo-io/skv2/codegen/skv2_anyvendor"
"github.com/solo-io/skv2/codegen/util"
"github.com/solo-io/skv2/contrib"
)

var _ = Describe("Cmd", func() {
Expand All @@ -42,6 +41,66 @@ var _ = Describe("Cmd", func() {
skv2Imports.External["github.com/solo-io/cue"] = []string{
"encoding/protobuf/cue/cue.proto",
}
It("env variable priority", func() {
cmd := &Command{
Chart: &Chart{
Data: Data{
ApiVersion: "v1",
Description: "",
Name: "Painting Operator",
Version: "v0.0.1",
Home: "https://docs.solo.io/skv2/latest",
Sources: []string{
"https://github.com/solo-io/skv2",
},
},
Operators: []Operator{{
Name: "painter",
Deployment: Deployment{
Container: Container{
Image: Image{Repository: "painter", Tag: "v0.0.1"},
Env: []v1.EnvVar{{Name: "ENV_VAR", Value: "default"}},
TemplateEnvVars: []TemplateEnvVar{
{
Condition: "$.Values.secret",
Name: "ENV_VAR",
Value: "templated",
},
},
},
},
}},
},
ManifestRoot: "codegen/test/chart/env-priority",
}
Expect(cmd.Execute()).NotTo(HaveOccurred(), "failed to execute command")

manifests := helmTemplate("./test/chart/env-priority", map[string]any{"painter": map[string]any{"enabled": true}, "secret": true})
var renderedDeployment *appsv1.Deployment
decoder := kubeyaml.NewYAMLOrJSONDecoder(bytes.NewBuffer(manifests), 4096)
for {
obj := &unstructured.Unstructured{}
err := decoder.Decode(obj)
if err != nil {
break
}
if obj.GetName() != "painter" || obj.GetKind() != "Deployment" {
continue
}

bytes, err := obj.MarshalJSON()
Expect(err).NotTo(HaveOccurred())
renderedDeployment = &appsv1.Deployment{}
err = json.Unmarshal(bytes, renderedDeployment)
Expect(err).NotTo(HaveOccurred())
}
Expect(renderedDeployment).NotTo(BeNil())

Expect(renderedDeployment.Spec.Template.Spec.Containers[0].Env).To(HaveLen(2))
Expect(renderedDeployment.Spec.Template.Spec.Containers[0].Env[0]).To(Equal(v1.EnvVar{Name: "ENV_VAR", Value: "templated"}))
Expect(renderedDeployment.Spec.Template.Spec.Containers[0].Env[1]).To(Equal(v1.EnvVar{Name: "ENV_VAR", Value: "default"}))
})

It("install conditional sidecars", func() {
agentConditional := "and ($.Values.glooAgent.enabled) ($.Values.glooAgent.runAsSidecar)"

Expand Down Expand Up @@ -111,6 +170,30 @@ var _ = Describe("Cmd", func() {
Repository: "gloo-mesh-mgmt-server",
Tag: "0.0.1",
},
TemplateEnvVars: []TemplateEnvVar{
{
Name: "USERNAME",
ValueFrom: v1.EnvVarSource{
SecretKeyRef: &v1.SecretKeySelector{
LocalObjectReference: v1.LocalObjectReference{
Name: "{{ $.Values.someSecret }}",
},
Key: "{{ $.Values.usernameKey }}",
},
},
},
{
Name: "PASSWORD",
ValueFrom: v1.EnvVarSource{
ConfigMapKeyRef: &v1.ConfigMapKeySelector{
LocalObjectReference: v1.LocalObjectReference{
Name: "{{ $.Values.someConfigMap }}",
},
Key: "{{ $.Values.passwordKey }}",
},
},
},
},
ContainerPorts: []ContainerPort{{
Name: "stats",
Port: "{{ $Values.glooMgmtServer.statsPort }}",
Expand Down Expand Up @@ -155,6 +238,11 @@ var _ = Describe("Cmd", func() {
Expect(deployment).To(ContainSubstring("name: agent-volume"))
Expect(deployment).To(ContainSubstring(`{{ index $glooAgent "ports" "grpc" }}`))
Expect(deployment).To(ContainSubstring("{{ $Values.glooMgmtServer.statsPort }}"))

Expect(deployment).To(ContainSubstring("{{ $.Values.usernameKey }}"))
Expect(deployment).To(ContainSubstring("{{ $.Values.passwordKey }}"))
Expect(deployment).To(ContainSubstring("{{ $.Values.someSecret }}"))
Expect(deployment).To(ContainSubstring("{{ $.Values.someConfigMap }}"))
})
It("generates conditional crds", func() {
cmd := &Command{
Expand Down Expand Up @@ -772,13 +860,11 @@ var _ = Describe("Cmd", func() {
}
Expect(renderedDeployment).NotTo(BeNil())

pointerBool := func(b bool) *bool { return &b }
pointerInt64 := func(i int64) *int64 { return &i }
defaultSecurityContext := v1.SecurityContext{
RunAsNonRoot: pointerBool(true),
RunAsUser: pointerInt64(10101),
ReadOnlyRootFilesystem: pointerBool(true),
AllowPrivilegeEscalation: pointerBool(false),
RunAsNonRoot: ptr.To(true),
RunAsUser: ptr.To[int64](10101),
ReadOnlyRootFilesystem: ptr.To(true),
AllowPrivilegeEscalation: ptr.To(false),
Capabilities: &v1.Capabilities{
Drop: []v1.Capability{"ALL"},
},
Expand All @@ -798,8 +884,8 @@ var _ = Describe("Cmd", func() {
Entry("renders empty map for container security context when set as false via helm cli", nil, true),
Entry("overrides container security context with empty map", &v1.SecurityContext{}, false),
Entry("overrides container security context", &v1.SecurityContext{
RunAsNonRoot: func(b bool) *bool { return &b }(true),
RunAsUser: func(i int64) *int64 { return &i }(20202),
RunAsNonRoot: ptr.To(true),
RunAsUser: ptr.To[int64](20202),
}, false),
)

Expand Down Expand Up @@ -1928,7 +2014,7 @@ roleRef:
)

DescribeTable("rendering conditional deployment strategy",
func(values map[string]any, conditionalStrategy []model.ConditionalStrategy, expectedStrategy appsv1.DeploymentStrategy) {
func(values map[string]any, conditionalStrategy []ConditionalStrategy, expectedStrategy appsv1.DeploymentStrategy) {
cmd := &Command{
Chart: &Chart{
Operators: []Operator{
Expand Down Expand Up @@ -1999,7 +2085,7 @@ roleRef:
),
Entry("when the condition is true",
map[string]any{"enabled": true, "condition": true},
[]model.ConditionalStrategy{
[]ConditionalStrategy{
{
Condition: "$.Values.painter.condition",
Strategy: appsv1.DeploymentStrategy{
Expand All @@ -2019,7 +2105,7 @@ roleRef:
),
Entry("when the condition is false",
map[string]any{"enabled": true, "condition": false},
[]model.ConditionalStrategy{
[]ConditionalStrategy{
{
Condition: "$.Values.painter.condition",
Strategy: appsv1.DeploymentStrategy{
Expand Down Expand Up @@ -2114,23 +2200,23 @@ roleRef:
map[string]interface{}{"fsGroup": 1000},
nil,
&v1.PodSecurityContext{
FSGroup: pointer.Int64(1000),
FSGroup: ptr.To[int64](1000),
}),
Entry("when PodSecurityContext is defined only in the operator",
nil,
&v1.PodSecurityContext{
FSGroup: pointer.Int64(1000),
FSGroup: ptr.To[int64](1000),
},
&v1.PodSecurityContext{
FSGroup: pointer.Int64(1000),
FSGroup: ptr.To[int64](1000),
}),
Entry("when PodSecurityContext is defined in both values and the operator",
map[string]interface{}{"fsGroup": 1024},
&v1.PodSecurityContext{
FSGroup: pointer.Int64(1000),
FSGroup: ptr.To[int64](1000),
},
&v1.PodSecurityContext{
FSGroup: pointer.Int64(1024), // should override the value defined in the operator
FSGroup: ptr.To[int64](1024), // should override the value defined in the operator
}),
)

Expand Down Expand Up @@ -2229,7 +2315,9 @@ roleRef:
Value: "{{ $.Values.featureGates.Foo | quote }}",
},
},
nil),
[]v1.EnvVar{
{Name: "FEATURE_ENABLE_FOO", Value: "true"},
}),
Entry("when Env and TemplateEnvVar are specified, true value",
map[string]string{"Foo": "true"},
[]v1.EnvVar{
Expand Down Expand Up @@ -2318,7 +2406,7 @@ roleRef:
})

DescribeTable("validation",
func(values map[string]any, defaultVolumes []v1.Volume, conditionalVolumes []model.ConditionalVolume, expected []v1.Volume) {
func(values map[string]any, defaultVolumes []v1.Volume, conditionalVolumes []ConditionalVolume, expected []v1.Volume) {
cmd := &Command{
Chart: &Chart{
Operators: []Operator{
Expand Down Expand Up @@ -2412,7 +2500,7 @@ roleRef:
"condition": "true",
},
nil,
[]model.ConditionalVolume{
[]ConditionalVolume{
{
Condition: "$.Values.painter.condition",
Volume: v1.Volume{
Expand All @@ -2432,7 +2520,7 @@ roleRef:
"condition": "true",
},
nil,
[]model.ConditionalVolume{
[]ConditionalVolume{
{
Condition: "$.Values.painter.invalidCondition",
Volume: v1.Volume{
Expand All @@ -2452,7 +2540,7 @@ roleRef:
Name: "vol-1",
},
},
[]model.ConditionalVolume{
[]ConditionalVolume{
{
Condition: "$.Values.painter.condition",
Volume: v1.Volume{
Expand Down Expand Up @@ -2484,7 +2572,7 @@ roleRef:
})

DescribeTable("validation",
func(values map[string]any, defaultMounts []v1.VolumeMount, conditionalMounts []model.ConditionalVolumeMount, expected []v1.VolumeMount) {
func(values map[string]any, defaultMounts []v1.VolumeMount, conditionalMounts []ConditionalVolumeMount, expected []v1.VolumeMount) {
cmd := &Command{
Chart: &Chart{
Operators: []Operator{
Expand Down Expand Up @@ -2580,7 +2668,7 @@ roleRef:
"condition": "true",
},
nil,
[]model.ConditionalVolumeMount{
[]ConditionalVolumeMount{
{
Condition: "$.Values.painter.condition",
VolumeMount: v1.VolumeMount{
Expand All @@ -2600,7 +2688,7 @@ roleRef:
"condition": "true",
},
nil,
[]model.ConditionalVolumeMount{
[]ConditionalVolumeMount{
{
Condition: "$.Values.painter.invalidCondition",
VolumeMount: v1.VolumeMount{
Expand All @@ -2620,7 +2708,7 @@ roleRef:
Name: "vol-1",
},
},
[]model.ConditionalVolumeMount{
[]ConditionalVolumeMount{
{
Condition: "$.Values.painter.condition",
VolumeMount: v1.VolumeMount{
Expand Down
3 changes: 3 additions & 0 deletions codegen/model/chart.go
Original file line number Diff line number Diff line change
Expand Up @@ -173,6 +173,9 @@ type TemplateEnvVar struct {
// Helm value
// E.g. {{ .Values.foo.bar }}
Value string

//
ValueFrom corev1.EnvVarSource
}

type ContainerPort struct {
Expand Down
31 changes: 20 additions & 11 deletions codegen/templates/chart/operator-deployment.yamltmpl
Original file line number Diff line number Diff line change
Expand Up @@ -140,25 +140,34 @@ spec:
containerPort: [[ $port.Port ]]
[[- end ]]
[[- end ]]
{{- if [[ $containerVar ]].env }}
[[- if or $container.Env $container.TemplateEnvVars ]]
env:
[[- else ]]
{{- if or [[ $containerVar ]].env [[ $containerVar ]].extraEnvs }}
env:
{{ toYaml [[ $containerVar ]].env | indent 10 }}
{{- end }}
[[- end ]]
[[- range $f := $container.TemplateEnvVars ]]
[[- if $f.Condition ]]
{{- if [[ $f.Condition ]] }}
[[- end]]
[[- if $f.Condition ]]
{{- if [[ $f.Condition ]] }}
[[- end ]]
[[- if $f.Value ]]
- name: [[ $f.Name ]]
value: [[ $f.Value ]]
[[- if $f.Condition ]]
{{- end }}
[[- end]]
[[- else if $f.ValueFrom ]]
- name: [[ $f.Name ]]
valueFrom: [[ $f.ValueFrom | toYaml | nindent 14 ]]
[[- end ]]
[[- if $f.Condition ]]
{{- end }}
[[- end ]]
[[- end ]]
{{- else if [[ $containerVar ]].extraEnvs }}
env:
{{- if [[ $containerVar ]].env }}
{{- toYaml [[ $containerVar ]].env | nindent 10 }}
{{- end }}
{{- range $name, $item := [[ $containerVar ]].extraEnvs }}
- name: {{ $name }}
{{- $item | toYaml | nindent 12 }}
{{- $item | toYaml | nindent 12 }}
{{- end }}
[[- if $container.VolumeMounts ]]
volumeMounts:
Expand Down
Loading
Loading