mirror of https://github.com/grafana/loki
operator: Refactor proxy env variables (#7682)
parent
3e90d5f972
commit
f6dabc81c0
@ -0,0 +1,36 @@ |
||||
package openshift |
||||
|
||||
import ( |
||||
"context" |
||||
|
||||
lokiv1 "github.com/grafana/loki/operator/apis/loki/v1" |
||||
"github.com/grafana/loki/operator/internal/external/k8s" |
||||
configv1 "github.com/openshift/api/config/v1" |
||||
"k8s.io/apimachinery/pkg/api/errors" |
||||
"sigs.k8s.io/controller-runtime/pkg/client" |
||||
) |
||||
|
||||
const proxyName = "cluster" |
||||
|
||||
// GetProxy returns the cluster-wide proxy configuration of OpenShift, if one is set.
|
||||
// It can also return an error.
|
||||
func GetProxy(ctx context.Context, k k8s.Client) (*lokiv1.ClusterProxy, error) { |
||||
key := client.ObjectKey{Name: proxyName} |
||||
p := &configv1.Proxy{} |
||||
if err := k.Get(ctx, key, p); err != nil { |
||||
if errors.IsNotFound(err) { |
||||
return nil, nil |
||||
} |
||||
return nil, err |
||||
} |
||||
|
||||
if p.Status.HTTPProxy == "" && p.Status.HTTPSProxy == "" && p.Status.NoProxy == "" { |
||||
return nil, nil |
||||
} |
||||
|
||||
return &lokiv1.ClusterProxy{ |
||||
HTTPProxy: p.Status.HTTPProxy, |
||||
HTTPSProxy: p.Status.HTTPSProxy, |
||||
NoProxy: p.Status.NoProxy, |
||||
}, nil |
||||
} |
||||
@ -0,0 +1,62 @@ |
||||
package openshift |
||||
|
||||
import ( |
||||
"context" |
||||
"testing" |
||||
|
||||
"github.com/grafana/loki/operator/internal/external/k8s/k8sfakes" |
||||
configv1 "github.com/openshift/api/config/v1" |
||||
"github.com/stretchr/testify/require" |
||||
apierrors "k8s.io/apimachinery/pkg/api/errors" |
||||
"k8s.io/apimachinery/pkg/runtime/schema" |
||||
"k8s.io/apimachinery/pkg/types" |
||||
"sigs.k8s.io/controller-runtime/pkg/client" |
||||
) |
||||
|
||||
func TestGetProxy_ReturnError_WhenOtherThanNotFound(t *testing.T) { |
||||
k := &k8sfakes.FakeClient{} |
||||
|
||||
k.GetStub = func(_ context.Context, name types.NamespacedName, object client.Object, _ ...client.GetOption) error { |
||||
return apierrors.NewBadRequest("bad request") |
||||
} |
||||
|
||||
_, err := GetProxy(context.TODO(), k) |
||||
require.Error(t, err) |
||||
} |
||||
|
||||
func TestGetProxy_ReturnEmpty_WhenNotFound(t *testing.T) { |
||||
k := &k8sfakes.FakeClient{} |
||||
|
||||
k.GetStub = func(_ context.Context, name types.NamespacedName, object client.Object, _ ...client.GetOption) error { |
||||
return apierrors.NewNotFound(schema.GroupResource{}, "something wasn't found") |
||||
} |
||||
|
||||
proxy, err := GetProxy(context.TODO(), k) |
||||
require.NoError(t, err) |
||||
require.Nil(t, proxy) |
||||
} |
||||
|
||||
func TestGetProxy_ReturnEnvVars_WhenProxyExists(t *testing.T) { |
||||
k := &k8sfakes.FakeClient{} |
||||
|
||||
k.GetStub = func(_ context.Context, name types.NamespacedName, out client.Object, _ ...client.GetOption) error { |
||||
if name.Name == proxyName { |
||||
k.SetClientObject(out, &configv1.Proxy{ |
||||
Status: configv1.ProxyStatus{ |
||||
HTTPProxy: "http-test", |
||||
HTTPSProxy: "https-test", |
||||
NoProxy: "noproxy-test", |
||||
}, |
||||
}) |
||||
return nil |
||||
} |
||||
return apierrors.NewNotFound(schema.GroupResource{}, "something wasn't found") |
||||
} |
||||
|
||||
proxy, err := GetProxy(context.TODO(), k) |
||||
require.NoError(t, err) |
||||
require.NotNil(t, proxy) |
||||
require.Equal(t, "http-test", proxy.HTTPProxy) |
||||
require.Equal(t, "https-test", proxy.HTTPSProxy) |
||||
require.Equal(t, "noproxy-test", proxy.NoProxy) |
||||
} |
||||
@ -0,0 +1,110 @@ |
||||
package manifests |
||||
|
||||
import ( |
||||
"strings" |
||||
|
||||
lokiv1 "github.com/grafana/loki/operator/apis/loki/v1" |
||||
"github.com/imdario/mergo" |
||||
corev1 "k8s.io/api/core/v1" |
||||
) |
||||
|
||||
const ( |
||||
httpProxyKey = "HTTP_PROXY" |
||||
httpsProxyKey = "HTTPS_PROXY" |
||||
noProxyKey = "NO_PROXY" |
||||
) |
||||
|
||||
var proxyEnvNames = []string{ |
||||
httpProxyKey, |
||||
strings.ToLower(httpProxyKey), |
||||
httpsProxyKey, |
||||
strings.ToLower(httpsProxyKey), |
||||
noProxyKey, |
||||
strings.ToLower(noProxyKey), |
||||
} |
||||
|
||||
func configureProxyEnv(pod *corev1.PodSpec, opts Options) error { |
||||
for _, envVar := range proxyEnvNames { |
||||
resetProxyVar(pod, envVar) |
||||
} |
||||
|
||||
proxySpec := opts.Stack.Proxy |
||||
if proxySpec == nil { |
||||
return nil |
||||
} |
||||
|
||||
src := corev1.Container{ |
||||
Env: toEnvVars(proxySpec), |
||||
} |
||||
|
||||
for i, dst := range pod.Containers { |
||||
if err := mergo.Merge(&dst, src, mergo.WithAppendSlice); err != nil { |
||||
return err |
||||
} |
||||
pod.Containers[i] = dst |
||||
} |
||||
|
||||
return nil |
||||
} |
||||
|
||||
func resetProxyVar(podSpec *corev1.PodSpec, name string) { |
||||
for i, container := range podSpec.Containers { |
||||
found, index := findEnvVar(name, container.Env) |
||||
if found { |
||||
podSpec.Containers[i].Env = append(podSpec.Containers[i].Env[:index], podSpec.Containers[i].Env[index+1:]...) |
||||
} |
||||
} |
||||
} |
||||
|
||||
func findEnvVar(name string, envVars []corev1.EnvVar) (bool, int) { |
||||
for i, env := range envVars { |
||||
if env.Name == name || env.Name == strings.ToLower(name) { |
||||
return true, i |
||||
} |
||||
} |
||||
return false, 0 |
||||
} |
||||
|
||||
func toEnvVars(proxySpec *lokiv1.ClusterProxy) []corev1.EnvVar { |
||||
var envVars []corev1.EnvVar |
||||
if proxySpec.HTTPProxy != "" { |
||||
envVars = append(envVars, |
||||
corev1.EnvVar{ |
||||
Name: httpProxyKey, |
||||
Value: proxySpec.HTTPProxy, |
||||
}, |
||||
corev1.EnvVar{ |
||||
Name: strings.ToLower(httpProxyKey), |
||||
Value: proxySpec.HTTPProxy, |
||||
}, |
||||
) |
||||
} |
||||
|
||||
if proxySpec.HTTPSProxy != "" { |
||||
envVars = append(envVars, |
||||
corev1.EnvVar{ |
||||
Name: httpsProxyKey, |
||||
Value: proxySpec.HTTPSProxy, |
||||
}, |
||||
corev1.EnvVar{ |
||||
Name: strings.ToLower(httpsProxyKey), |
||||
Value: proxySpec.HTTPSProxy, |
||||
}, |
||||
) |
||||
} |
||||
|
||||
if proxySpec.NoProxy != "" { |
||||
envVars = append(envVars, |
||||
corev1.EnvVar{ |
||||
Name: noProxyKey, |
||||
Value: proxySpec.NoProxy, |
||||
}, |
||||
corev1.EnvVar{ |
||||
Name: strings.ToLower(noProxyKey), |
||||
Value: proxySpec.NoProxy, |
||||
}, |
||||
) |
||||
} |
||||
|
||||
return envVars |
||||
} |
||||
@ -0,0 +1,97 @@ |
||||
package manifests |
||||
|
||||
import ( |
||||
"strings" |
||||
"testing" |
||||
|
||||
lokiv1 "github.com/grafana/loki/operator/apis/loki/v1" |
||||
"github.com/stretchr/testify/require" |
||||
appsv1 "k8s.io/api/apps/v1" |
||||
corev1 "k8s.io/api/core/v1" |
||||
) |
||||
|
||||
func TestContainerEnvVars_ReadVarsFromCustomResource(t *testing.T) { |
||||
opt := Options{ |
||||
Name: "test", |
||||
Namespace: "test", |
||||
Image: "test", |
||||
Stack: lokiv1.LokiStackSpec{ |
||||
Size: lokiv1.SizeOneXExtraSmall, |
||||
Proxy: &lokiv1.ClusterProxy{ |
||||
HTTPProxy: "http-test", |
||||
HTTPSProxy: "https-test", |
||||
NoProxy: "noproxy-test", |
||||
}, |
||||
Template: &lokiv1.LokiTemplateSpec{ |
||||
Compactor: &lokiv1.LokiComponentSpec{ |
||||
Replicas: 1, |
||||
}, |
||||
Distributor: &lokiv1.LokiComponentSpec{ |
||||
Replicas: 1, |
||||
}, |
||||
Ingester: &lokiv1.LokiComponentSpec{ |
||||
Replicas: 1, |
||||
}, |
||||
Querier: &lokiv1.LokiComponentSpec{ |
||||
Replicas: 1, |
||||
}, |
||||
QueryFrontend: &lokiv1.LokiComponentSpec{ |
||||
Replicas: 1, |
||||
}, |
||||
Gateway: &lokiv1.LokiComponentSpec{ |
||||
Replicas: 1, |
||||
}, |
||||
IndexGateway: &lokiv1.LokiComponentSpec{ |
||||
Replicas: 1, |
||||
}, |
||||
Ruler: &lokiv1.LokiComponentSpec{ |
||||
Replicas: 1, |
||||
}, |
||||
}, |
||||
}, |
||||
} |
||||
|
||||
for _, cs := range lokiContainers(t, opt) { |
||||
for _, c := range cs { |
||||
require.Contains(t, c.Env, corev1.EnvVar{Name: httpProxyKey, Value: "http-test"}, |
||||
"missing envVar HTTP_PROXY for: %s", c.Name) |
||||
require.Contains(t, c.Env, corev1.EnvVar{Name: strings.ToLower(httpProxyKey), Value: "http-test"}, |
||||
"missing envVar http_proxy for: %s", c.Name) |
||||
require.Contains(t, c.Env, corev1.EnvVar{Name: httpsProxyKey, Value: "https-test"}, |
||||
"missing envVar HTTPS_PROXY for: %s", c.Name) |
||||
require.Contains(t, c.Env, corev1.EnvVar{Name: strings.ToLower(httpsProxyKey), Value: "https-test"}, |
||||
"missing envVar https_proxy for: %s", c.Name) |
||||
require.Contains(t, c.Env, corev1.EnvVar{Name: noProxyKey, Value: "noproxy-test"}, |
||||
"missing envVar NO_PROXY for: %s", c.Name) |
||||
require.Contains(t, c.Env, corev1.EnvVar{Name: strings.ToLower(noProxyKey), Value: "noproxy-test"}, |
||||
"missing envVar no_proxy for: %s", c.Name) |
||||
} |
||||
} |
||||
} |
||||
|
||||
func lokiContainers(t *testing.T, opt Options) [][]corev1.Container { |
||||
db, err := BuildDistributor(opt) |
||||
require.NoError(t, err) |
||||
in, err := BuildIngester(opt) |
||||
require.NoError(t, err) |
||||
qr, err := BuildQuerier(opt) |
||||
require.NoError(t, err) |
||||
qf, err := BuildQueryFrontend(opt) |
||||
require.NoError(t, err) |
||||
cm, err := BuildCompactor(opt) |
||||
require.NoError(t, err) |
||||
ig, err := BuildIndexGateway(opt) |
||||
require.NoError(t, err) |
||||
rl, err := BuildRuler(opt) |
||||
require.NoError(t, err) |
||||
|
||||
return [][]corev1.Container{ |
||||
db[0].(*appsv1.Deployment).Spec.Template.Spec.Containers, |
||||
in[0].(*appsv1.StatefulSet).Spec.Template.Spec.Containers, |
||||
qr[0].(*appsv1.Deployment).Spec.Template.Spec.Containers, |
||||
qf[0].(*appsv1.Deployment).Spec.Template.Spec.Containers, |
||||
cm[0].(*appsv1.StatefulSet).Spec.Template.Spec.Containers, |
||||
ig[0].(*appsv1.StatefulSet).Spec.Template.Spec.Containers, |
||||
rl[0].(*appsv1.StatefulSet).Spec.Template.Spec.Containers, |
||||
} |
||||
} |
||||
Loading…
Reference in new issue