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

Support EnvFrom #3193

Merged
merged 5 commits into from
Mar 27, 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
3 changes: 2 additions & 1 deletion pkg/controller/operators/olm/overrides/config.go
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ type operatorConfig struct {
logger *logrus.Logger
}

func (o *operatorConfig) GetConfigOverrides(ownerCSV ownerutil.Owner) (envVarOverrides []corev1.EnvVar, volumeOverrides []corev1.Volume, volumeMountOverrides []corev1.VolumeMount, tolerationOverrides []corev1.Toleration, resourcesOverride *corev1.ResourceRequirements, nodeSelectorOverride map[string]string, affinity *corev1.Affinity, annotations map[string]string, err error) {
func (o *operatorConfig) GetConfigOverrides(ownerCSV ownerutil.Owner) (envVarOverrides []corev1.EnvVar, envFromOverrides []corev1.EnvFromSource, volumeOverrides []corev1.Volume, volumeMountOverrides []corev1.VolumeMount, tolerationOverrides []corev1.Toleration, resourcesOverride *corev1.ResourceRequirements, nodeSelectorOverride map[string]string, affinity *corev1.Affinity, annotations map[string]string, err error) {
list, listErr := o.lister.OperatorsV1alpha1().SubscriptionLister().Subscriptions(ownerCSV.GetNamespace()).List(labels.Everything())
if listErr != nil {
err = fmt.Errorf("failed to list subscription namespace=%s - %v", ownerCSV.GetNamespace(), listErr)
Expand All @@ -35,6 +35,7 @@ func (o *operatorConfig) GetConfigOverrides(ownerCSV ownerutil.Owner) (envVarOve
}

envVarOverrides = owner.Spec.Config.Env
envFromOverrides = owner.Spec.Config.EnvFrom
volumeOverrides = owner.Spec.Config.Volumes
volumeMountOverrides = owner.Spec.Config.VolumeMounts
tolerationOverrides = owner.Spec.Config.Tolerations
Expand Down
6 changes: 5 additions & 1 deletion pkg/controller/operators/olm/overrides/initializer.go
Original file line number Diff line number Diff line change
Expand Up @@ -45,7 +45,7 @@ func (d *DeploymentInitializer) initialize(ownerCSV ownerutil.Owner, deployment
var envVarOverrides, proxyEnvVar, merged []corev1.EnvVar
var err error

envVarOverrides, volumeOverrides, volumeMountOverrides, tolerationOverrides, resourcesOverride, nodeSelectorOverride, affinity, annotations, err := d.config.GetConfigOverrides(ownerCSV)
envVarOverrides, envFromOverrides, volumeOverrides, volumeMountOverrides, tolerationOverrides, resourcesOverride, nodeSelectorOverride, affinity, annotations, err := d.config.GetConfigOverrides(ownerCSV)
if err != nil {
err = fmt.Errorf("failed to get subscription pod configuration - %v", err)
return err
Expand All @@ -72,6 +72,10 @@ func (d *DeploymentInitializer) initialize(ownerCSV ownerutil.Owner, deployment
return fmt.Errorf("failed to inject proxy env variable(s) into deployment spec name=%s - %v", deployment.Name, err)
}

if err := inject.InjectEnvFromIntoDeployment(podSpec, envFromOverrides); err != nil {
return fmt.Errorf("failed to inject envFrom variable(s) into deployment spec name=%s - %v", deployment.Name, err)
}

if err = inject.InjectVolumesIntoDeployment(podSpec, volumeOverrides); err != nil {
return fmt.Errorf("failed to inject volume(s) into deployment spec name=%s - %v", deployment.Name, err)
}
Expand Down
39 changes: 39 additions & 0 deletions pkg/controller/operators/olm/overrides/inject/inject.go
Original file line number Diff line number Diff line change
Expand Up @@ -62,6 +62,45 @@ func mergeEnvVars(containerEnvVars []corev1.EnvVar, newEnvVars []corev1.EnvVar)
return merged
}

// InjectEnvFromIntoDeployment injects the envFrom variables
// into the container(s) of the given PodSpec.
//
// If any Container in PodSpec already defines an envFrom variable
// as any of the provided envFrom then it will be overwritten.
func InjectEnvFromIntoDeployment(podSpec *corev1.PodSpec, envFromVars []corev1.EnvFromSource) error {
if podSpec == nil {
return errors.New("no pod spec provided")
}

for i := range podSpec.Containers {
container := &podSpec.Containers[i]
container.EnvFrom = mergeEnvFromVars(container.EnvFrom, envFromVars)
}

return nil
}

func mergeEnvFromVars(containerEnvFromVars []corev1.EnvFromSource, newEnvFromVars []corev1.EnvFromSource) []corev1.EnvFromSource {
merged := containerEnvFromVars

for _, newEnvFromVar := range newEnvFromVars {
if !findEnvFromVar(containerEnvFromVars, newEnvFromVar) {
merged = append(merged, newEnvFromVar)
}
}

return merged
}

func findEnvFromVar(envFromVar []corev1.EnvFromSource, newEnvFromVar corev1.EnvFromSource) bool {
for i := range envFromVar {
if reflect.DeepEqual(envFromVar[i], newEnvFromVar) {
return true
}
}
return false
}

// InjectVolumesIntoDeployment injects the provided Volumes
// into the container(s) of the given PodSpec.
//
Expand Down
185 changes: 185 additions & 0 deletions pkg/controller/operators/olm/overrides/inject/inject_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,26 @@ var (
},
}

defaultEnvFromVars = []corev1.EnvFromSource{
{
Prefix: "test",
},
{
ConfigMapRef: &corev1.ConfigMapEnvSource{
LocalObjectReference: corev1.LocalObjectReference{
Name: "configmapForTest",
},
},
},
{
SecretRef: &corev1.SecretEnvSource{
LocalObjectReference: corev1.LocalObjectReference{
Name: "secretForTest",
},
},
},
}

defaultVolumeMounts = []corev1.VolumeMount{
{
Name: "foo",
Expand Down Expand Up @@ -526,6 +546,171 @@ func TestInjectEnvIntoDeployment(t *testing.T) {
}
}

func TestInjectEnvFromIntoDeployment(t *testing.T) {
tests := []struct {
name string
podSpec *corev1.PodSpec
envFromVar []corev1.EnvFromSource
expected *corev1.PodSpec
}{
{
// PodSpec has one container and `EnvFrom` is empty.
// Expected: All env variable(s) specified are injected.
name: "WithContainerHasNoEnvFromVar",
podSpec: &corev1.PodSpec{
Containers: []corev1.Container{
{},
},
},
envFromVar: defaultEnvFromVars,
expected: &corev1.PodSpec{
Containers: []corev1.Container{
{
EnvFrom: defaultEnvFromVars,
},
},
},
},
{
// PodSpec has one container and it has overlapping envFrom var(s).
// Expected: existing duplicate env vars won't be appended in the envFrom.
name: "WithContainerHasOverlappingEnvFromVar",
podSpec: &corev1.PodSpec{
Containers: []corev1.Container{
{
EnvFrom: []corev1.EnvFromSource{
{
Prefix: "test",
},
{
ConfigMapRef: &corev1.ConfigMapEnvSource{
LocalObjectReference: corev1.LocalObjectReference{
Name: "configmapForTest",
},
},
},
{
SecretRef: &corev1.SecretEnvSource{
LocalObjectReference: corev1.LocalObjectReference{
Name: "secretForTest",
},
},
},
},
},
},
},
envFromVar: defaultEnvFromVars,
expected: &corev1.PodSpec{
Containers: []corev1.Container{
{
EnvFrom: []corev1.EnvFromSource{
{
Prefix: "test",
},
{
ConfigMapRef: &corev1.ConfigMapEnvSource{
LocalObjectReference: corev1.LocalObjectReference{
Name: "configmapForTest",
},
},
},
{
SecretRef: &corev1.SecretEnvSource{
LocalObjectReference: corev1.LocalObjectReference{
Name: "secretForTest",
},
},
},
},
},
},
},
},
{
// PodSpec has one container and it has non overlapping envFrom var(s).
// Expected: existing non overlapping env vars are intact.
name: "WithContainerHasNonOverlappingEnvFromVar",
podSpec: &corev1.PodSpec{
Containers: []corev1.Container{
{
EnvFrom: []corev1.EnvFromSource{
{
Prefix: "foo",
},
},
},
},
},
envFromVar: defaultEnvFromVars,
expected: &corev1.PodSpec{
Containers: []corev1.Container{
{
EnvFrom: append([]corev1.EnvFromSource{
{
Prefix: "foo",
},
}, defaultEnvFromVars...),
},
},
},
},
{
// PodSpec has more than one container(s)
// Expected: All container(s) should be updated as expected.
name: "WithMultipleContainers",
podSpec: &corev1.PodSpec{
Containers: []corev1.Container{
{},
{
EnvFrom: []corev1.EnvFromSource{
{
Prefix: "foo",
},
},
},
{
EnvFrom: []corev1.EnvFromSource{
{
Prefix: "bar",
},
},
},
},
},
envFromVar: defaultEnvFromVars,
expected: &corev1.PodSpec{
Containers: []corev1.Container{
{
EnvFrom: defaultEnvFromVars,
},
{
EnvFrom: append([]corev1.EnvFromSource{
{
Prefix: "foo",
},
}, defaultEnvFromVars...),
},
{
EnvFrom: append([]corev1.EnvFromSource{
{
Prefix: "bar",
},
}, defaultEnvFromVars...),
},
},
},
},
}

for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
inject.InjectEnvFromIntoDeployment(tt.podSpec, tt.envFromVar)
assert.Equal(t, tt.expected, tt.podSpec)
})
}
}

func TestInjectTolerationsIntoDeployment(t *testing.T) {
tests := []struct {
name string
Expand Down
Loading