diff --git a/pkg/reconciler/common/proxy.go b/pkg/reconciler/common/proxy.go index 705944e473..c0cccf441d 100644 --- a/pkg/reconciler/common/proxy.go +++ b/pkg/reconciler/common/proxy.go @@ -24,10 +24,10 @@ import ( ) // ApplyProxySettings is a transformer that propagate any proxy environment variables -// set on the operator deployment to the underlying deployment. +// set on the operator deployment to the underlying deployment or statefulset. func ApplyProxySettings(u *unstructured.Unstructured) error { - if u.GetKind() != "Deployment" { - // Don't do anything on something else than Deployment + if u.GetKind() != "Deployment" && u.GetKind() != "StatefulSet" { + // Don't do anything on something else than Deployment or StatefulSet return nil } @@ -48,7 +48,7 @@ func ApplyProxySettings(u *unstructured.Unstructured) error { return err } if !found { - // No containers in the deployment, it is weird but let's not fail + // No containers in the resource, it is weird but let's not fail return nil } for _, c := range containers { diff --git a/pkg/reconciler/common/proxy_test.go b/pkg/reconciler/common/proxy_test.go index 6ab625b2b8..c9c1960b85 100644 --- a/pkg/reconciler/common/proxy_test.go +++ b/pkg/reconciler/common/proxy_test.go @@ -108,7 +108,69 @@ func TestApplyProxySettingsRemovingProxy(t *testing.T) { assert.DeepEqual(t, actual, expected) } +func TestApplyProxySettingsStatefulSetNoProxy(t *testing.T) { + actual := unstructuredStatefulSet(t) + expected := unstructuredStatefulSet(t) + + if err := ApplyProxySettings(actual); err != nil { + t.Fatal(err) + } + + assert.DeepEqual(t, actual, expected) +} + +func TestApplyProxySettingsStatefulSetWithProxy(t *testing.T) { + proxyEnv := map[string]string{ + "HTTP_PROXY": "http://1.2.3.4:30001", + "HTTPS_PROXY": "http://1.2.3.4:30002", + "NO_PROXY": "index.docker.io", + } + actual := unstructuredStatefulSet(t, withStatefulSetEnv(extraEnvVars)) + expected := unstructuredStatefulSet(t, withStatefulSetEnv(toEnvVar(proxyEnv), extraEnvVars)) + + defer env.PatchAll(t, proxyEnv)() + if err := ApplyProxySettings(actual); err != nil { + t.Fatal(err) + } + + assert.DeepEqual(t, actual, expected) +} + +func TestApplyProxySettingsOtherKindIgnored(t *testing.T) { + svc := &corev1.Service{ + ObjectMeta: metav1.ObjectMeta{ + Namespace: "foo", + Name: "registry", + }, + } + svc.SetGroupVersionKind(schema.GroupVersionKind{ + Group: corev1.SchemeGroupVersion.Group, + Version: corev1.SchemeGroupVersion.Version, + Kind: "Service", + }) + b, err := json.Marshal(svc) + if err != nil { + t.Fatal(err) + } + actual := &unstructured.Unstructured{} + if err := json.Unmarshal(b, actual); err != nil { + t.Fatal(err) + } + expected := actual.DeepCopy() + + proxyEnv := map[string]string{ + "HTTP_PROXY": "http://1.2.3.4:30001", + } + defer env.PatchAll(t, proxyEnv)() + if err := ApplyProxySettings(actual); err != nil { + t.Fatal(err) + } + + assert.DeepEqual(t, actual, expected) +} + type deploymentModifier func(*appsv1.Deployment) +type statefulSetModifier func(*appsv1.StatefulSet) func unstructuredDeployment(t *testing.T, modifiers ...deploymentModifier) *unstructured.Unstructured { deploy := &appsv1.Deployment{ @@ -158,6 +220,69 @@ func unstructuredDeployment(t *testing.T, modifiers ...deploymentModifier) *unst return ud } +func unstructuredStatefulSet(t *testing.T, modifiers ...statefulSetModifier) *unstructured.Unstructured { + ss := &appsv1.StatefulSet{ + ObjectMeta: metav1.ObjectMeta{ + Namespace: "foo", + Name: "registry", + }, + Spec: appsv1.StatefulSetSpec{ + ServiceName: "registry", + Selector: &metav1.LabelSelector{ + MatchLabels: map[string]string{ + "app": "registry", + }, + }, + Template: corev1.PodTemplateSpec{ + ObjectMeta: metav1.ObjectMeta{ + Labels: map[string]string{ + "app": "registry", + }, + }, + Spec: corev1.PodSpec{ + Containers: []corev1.Container{{ + Name: "registry", + Image: "registry", + }}, + }, + }, + }, + } + + for _, modifier := range modifiers { + modifier(ss) + } + + ss.SetGroupVersionKind(schema.GroupVersionKind{ + Group: appsv1.SchemeGroupVersion.Group, + Version: appsv1.SchemeGroupVersion.Version, + Kind: "StatefulSet", + }) + b, err := json.Marshal(ss) + if err != nil { + t.Fatal(err) + } + ud := &unstructured.Unstructured{} + if err := json.Unmarshal(b, ud); err != nil { + t.Fatal(err) + } + return ud +} + +func withStatefulSetEnv(envs ...[]corev1.EnvVar) func(*appsv1.StatefulSet) { + return func(ss *appsv1.StatefulSet) { + for i, c := range ss.Spec.Template.Spec.Containers { + for _, env := range envs { + c.Env = append(c.Env, env...) + } + sort.Slice(c.Env, func(i, j int) bool { + return c.Env[i].Name < c.Env[j].Name + }) + ss.Spec.Template.Spec.Containers[i] = c + } + } +} + func withEnv(envs ...[]corev1.EnvVar) func(*appsv1.Deployment) { return func(d *appsv1.Deployment) { for i, c := range d.Spec.Template.Spec.Containers { diff --git a/pkg/reconciler/kubernetes/tektoninstallerset/install_test.go b/pkg/reconciler/kubernetes/tektoninstallerset/install_test.go index b77483571d..85d325d2ca 100644 --- a/pkg/reconciler/kubernetes/tektoninstallerset/install_test.go +++ b/pkg/reconciler/kubernetes/tektoninstallerset/install_test.go @@ -163,6 +163,7 @@ var ( Spec: appsv1.StatefulSetSpec{ Replicas: ptr.Int32(1), ServiceName: "test", + Template: statefulsetPodTemplate, }, Status: appsv1.StatefulSetStatus{ Replicas: 1, @@ -181,12 +182,24 @@ var ( Spec: appsv1.StatefulSetSpec{ Replicas: ptr.Int32(1), ServiceName: "test", + Template: statefulsetPodTemplate, }, Status: appsv1.StatefulSetStatus{ Replicas: 1, ReadyReplicas: 1, }, } + // statefulsetPodTemplate gives the StatefulSet fixtures above a real container + // so that spec.template.spec.containers isn't a JSON null, matching what a + // real manifest looks like once ApplyProxySettings processes it. + statefulsetPodTemplate = corev1.PodTemplateSpec{ + Spec: corev1.PodSpec{ + Containers: []corev1.Container{{ + Name: "test", + Image: "test", + }}, + }, + } readyControllerDeployment = &appsv1.Deployment{ ObjectMeta: metav1.ObjectMeta{ Namespace: "test",