From 800d6404b519199ad548a686cc4fa31654a5ac2f Mon Sep 17 00:00:00 2001 From: Alexander Dammeier Date: Fri, 19 Jul 2024 11:33:57 +0200 Subject: [PATCH] #95 make loadbalancer name configurable it is a cluster-wide resource, therefore names will collide --- app/context/config.go | 2 ++ app/context/config_test.go | 14 ++++++++-- app/setup/data/createLoadBalancerStep.go | 17 +++++++----- app/setup/data/createLoadBalancerStep_test.go | 10 +++---- app/setup/data/fqdnRetrieverStep.go | 27 ++++++++++--------- app/setup/data/fqdnRetrieverStep_test.go | 15 ++++++----- app/setup/executor.go | 5 ++-- 7 files changed, 55 insertions(+), 35 deletions(-) diff --git a/app/context/config.go b/app/context/config.go index 289d2d5c..3a8162ee 100644 --- a/app/context/config.go +++ b/app/context/config.go @@ -35,6 +35,8 @@ type Config struct { LogLevel *logrus.Level `json:"log_level" yaml:"log_level"` // TargetNamespace represents the namespace that is created for the ecosystem TargetNamespace string `json:"target_namespace" yaml:"target_namespace"` + // LoadbalancerName represents the name of the loadbalancer for this ecosystem + LoadbalancerName string `json:"loadbalancer_name" yaml:"loadbalancer_name"` // ComponentOperatorCrdChart sets the Helm-Chart which controls the installation of the component-operator CRD into the current cluster. ComponentOperatorCrdChart string `json:"component_operator_crd_chart" yaml:"component_operator_crd_chart"` // ComponentOperatorChart sets the Helm-Chart which controls the installation of the component-operator into the current cluster. diff --git a/app/context/config_test.go b/app/context/config_test.go index 9f567a0a..c2e3f48b 100644 --- a/app/context/config_test.go +++ b/app/context/config_test.go @@ -2,6 +2,7 @@ package context import ( "context" + "fmt" "github.com/stretchr/testify/require" corev1 "k8s.io/api/core/v1" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" @@ -57,9 +58,14 @@ func TestReadConfig(t *testing.T) { func TestReadConfigFromCluster(t *testing.T) { const testNamespace = "test-namespace" + const testLoadbalancer = "test-loadbalancer" t.Run("should return marshalled config", func(t *testing.T) { // given - myFileMap := map[string]string{"k8s-ces-setup.yaml": "component_operator_crd_chart: https://crd.chart\ncomponent_operator_chart: https://url.com"} + myFileMap := map[string]string{"k8s-ces-setup.yaml": fmt.Sprintf(` +component_operator_crd_chart: https://crd.chart +component_operator_chart: https://url.com +loadbalancer_name: %s +`, testLoadbalancer)} mockedConfig := &corev1.ConfigMap{ ObjectMeta: metav1.ObjectMeta{ Name: SetupConfigConfigmap, @@ -74,7 +80,11 @@ func TestReadConfigFromCluster(t *testing.T) { // then require.NoError(t, err) - extected := &Config{ComponentOperatorCrdChart: "https://crd.chart", ComponentOperatorChart: "https://url.com"} + extected := &Config{ + ComponentOperatorCrdChart: "https://crd.chart", + ComponentOperatorChart: "https://url.com", + LoadbalancerName: testLoadbalancer, + } assert.Equal(t, extected, actual) }) t.Run("should fail during marshalling config", func(t *testing.T) { diff --git a/app/setup/data/createLoadBalancerStep.go b/app/setup/data/createLoadBalancerStep.go index c4dc8470..484980f4 100644 --- a/app/setup/data/createLoadBalancerStep.go +++ b/app/setup/data/createLoadBalancerStep.go @@ -23,14 +23,19 @@ const ( ) type createLoadBalancerStep struct { - config *appcontext.SetupJsonConfiguration - clientSet kubernetes.Interface - namespace string + config *appcontext.SetupJsonConfiguration + clientSet kubernetes.Interface + namespace string + loadbalancerName string } // NewCreateLoadBalancerStep creates the external loadbalancer service for the Cloudogu EcoSystem -func NewCreateLoadBalancerStep(config *appcontext.SetupJsonConfiguration, clientSet kubernetes.Interface, namespace string) *createLoadBalancerStep { - return &createLoadBalancerStep{config: config, clientSet: clientSet, namespace: namespace} +func NewCreateLoadBalancerStep( + config *appcontext.SetupJsonConfiguration, + clientSet kubernetes.Interface, + namespace, loadbalancerName string, +) *createLoadBalancerStep { + return &createLoadBalancerStep{config: config, clientSet: clientSet, namespace: namespace, loadbalancerName: loadbalancerName} } // GetStepDescription return the human-readable description of the step @@ -61,7 +66,7 @@ func (fcs *createLoadBalancerStep) createServiceResource(ctx context.Context) er ipSingleStackPolicy := corev1.IPFamilyPolicySingleStack serviceResource := &corev1.Service{ ObjectMeta: metav1.ObjectMeta{ - Name: cesLoadbalancerName, + Name: fcs.loadbalancerName, Namespace: fcs.namespace, Labels: map[string]string{"app": "ces"}, }, diff --git a/app/setup/data/createLoadBalancerStep_test.go b/app/setup/data/createLoadBalancerStep_test.go index b18af26b..d1e73019 100644 --- a/app/setup/data/createLoadBalancerStep_test.go +++ b/app/setup/data/createLoadBalancerStep_test.go @@ -18,14 +18,14 @@ func Test_createLoadBalancerStep_PerformSetupStep(t *testing.T) { // given fakeClient := fake.NewSimpleClientset() config := &appctx.SetupJsonConfiguration{Naming: appctx.Naming{Fqdn: ""}, Dogus: appctx.Dogus{Install: []string{nginxIngressName}}} - sut := NewCreateLoadBalancerStep(config, fakeClient, testNamespace) + sut := NewCreateLoadBalancerStep(config, fakeClient, testNamespace, testLoadbalancerName) // when err := sut.PerformSetupStep(testCtx) // then require.NoError(t, err) - actual, err := fakeClient.CoreV1().Services(testNamespace).Get(testCtx, "ces-loadbalancer", metav1.GetOptions{}) + actual, err := fakeClient.CoreV1().Services(testNamespace).Get(testCtx, testLoadbalancerName, metav1.GetOptions{}) require.NoError(t, err) assert.NotNil(t, actual) expected := map[string]string{"app": "ces"} @@ -36,21 +36,21 @@ func Test_createLoadBalancerStep_PerformSetupStep(t *testing.T) { serviceResource := &corev1.Service{ ObjectMeta: metav1.ObjectMeta{ - Name: cesLoadbalancerName, + Name: testLoadbalancerName, Labels: map[string]string{"delete": "me"}, }, Spec: corev1.ServiceSpec{Type: corev1.ServiceTypeClusterIP}, } fakeClient := fake.NewSimpleClientset(serviceResource) config := &appctx.SetupJsonConfiguration{Naming: appctx.Naming{Fqdn: ""}, Dogus: appctx.Dogus{Install: []string{nginxIngressName}}} - sut := NewCreateLoadBalancerStep(config, fakeClient, testNamespace) + sut := NewCreateLoadBalancerStep(config, fakeClient, testNamespace, testLoadbalancerName) // when err := sut.PerformSetupStep(testCtx) // then require.NoError(t, err) - actual, err := fakeClient.CoreV1().Services(testNamespace).Get(testCtx, "ces-loadbalancer", metav1.GetOptions{}) + actual, err := fakeClient.CoreV1().Services(testNamespace).Get(testCtx, testLoadbalancerName, metav1.GetOptions{}) require.NoError(t, err) assert.NotNil(t, actual) expected := map[string]string{"app": "ces"} diff --git a/app/setup/data/fqdnRetrieverStep.go b/app/setup/data/fqdnRetrieverStep.go index 63a35241..07acfd07 100644 --- a/app/setup/data/fqdnRetrieverStep.go +++ b/app/setup/data/fqdnRetrieverStep.go @@ -24,41 +24,42 @@ var backoff = wait.Backoff{ } type fqdnRetrieverStep struct { - config *appcontext.SetupJsonConfiguration - clientSet kubernetes.Interface - namespace string + config *appcontext.SetupJsonConfiguration + clientSet kubernetes.Interface + namespace string + loadbalancerName string } // NewFQDNRetrieverStep creates a new setup step sets the FQDN -func NewFQDNRetrieverStep(config *appcontext.SetupJsonConfiguration, clientSet kubernetes.Interface, namespace string) *fqdnRetrieverStep { - return &fqdnRetrieverStep{config: config, clientSet: clientSet, namespace: namespace} +func NewFQDNRetrieverStep(config *appcontext.SetupJsonConfiguration, clientSet kubernetes.Interface, namespace, loadbalancerName string) *fqdnRetrieverStep { + return &fqdnRetrieverStep{config: config, clientSet: clientSet, namespace: namespace, loadbalancerName: loadbalancerName} } // GetStepDescription return the human-readable description of the step -func (fcs *fqdnRetrieverStep) GetStepDescription() string { +func (frs *fqdnRetrieverStep) GetStepDescription() string { return "Retrieving a new FQDN from the IP of a loadbalancer service" } // PerformSetupStep creates a loadbalancer service and sets the loadbalancer IP as the new FQDN. -func (fcs *fqdnRetrieverStep) PerformSetupStep(ctx context.Context) error { - return fcs.setFQDNFromLoadbalancerIP(ctx) +func (frs *fqdnRetrieverStep) PerformSetupStep(ctx context.Context) error { + return frs.setFQDNFromLoadbalancerIP(ctx) } -func (fcs *fqdnRetrieverStep) setFQDNFromLoadbalancerIP(ctx context.Context) error { +func (frs *fqdnRetrieverStep) setFQDNFromLoadbalancerIP(ctx context.Context) error { return retry.OnError(backoff, serviceRetry, func() error { logrus.Debug("Try retrieving service...") - service, err := fcs.clientSet.CoreV1().Services(fcs.namespace).Get(ctx, cesLoadbalancerName, metav1.GetOptions{}) + service, err := frs.clientSet.CoreV1().Services(frs.namespace).Get(ctx, frs.loadbalancerName, metav1.GetOptions{}) if errors.IsNotFound(err) || len(service.Status.LoadBalancer.Ingress) <= 0 { - logrus.Debugf("wait for service %s to be instantiated", cesLoadbalancerName) - return fmt.Errorf("service not yet ready %s: %w", cesLoadbalancerName, err) + logrus.Debugf("wait for service %s to be instantiated", frs.loadbalancerName) + return fmt.Errorf("service not yet ready %s: %w", frs.loadbalancerName, err) } if err != nil { return err } loadbalancerIP := service.Status.LoadBalancer.Ingress[0].IP - fcs.config.Naming.Fqdn = loadbalancerIP + frs.config.Naming.Fqdn = loadbalancerIP logrus.Infof("Loadbalancer IP succesfully retrieved and set as new FQDN") return nil }) diff --git a/app/setup/data/fqdnRetrieverStep_test.go b/app/setup/data/fqdnRetrieverStep_test.go index 28fdaa1e..3d648448 100644 --- a/app/setup/data/fqdnRetrieverStep_test.go +++ b/app/setup/data/fqdnRetrieverStep_test.go @@ -14,7 +14,8 @@ import ( ) const ( - testNamespace = "ecosystem" + testNamespace = "ecosystem" + testLoadbalancerName = "ces-test-loadbalancer" ) func Test_fqdnRetrieverStep_PerformSetupStep(t *testing.T) { @@ -22,7 +23,7 @@ func Test_fqdnRetrieverStep_PerformSetupStep(t *testing.T) { // given mockedLoadBalancerResource := &corev1.Service{ ObjectMeta: metav1.ObjectMeta{ - Name: cesLoadbalancerName, + Name: testLoadbalancerName, Namespace: testNamespace, }, Spec: corev1.ServiceSpec{ @@ -32,7 +33,7 @@ func Test_fqdnRetrieverStep_PerformSetupStep(t *testing.T) { fakeClient := fake.NewSimpleClientset(mockedLoadBalancerResource) config := &appctx.SetupJsonConfiguration{Naming: appctx.Naming{Fqdn: ""}, Dogus: appctx.Dogus{Install: []string{nginxIngressName}}} - sut := NewFQDNRetrieverStep(config, fakeClient, testNamespace) + sut := NewFQDNRetrieverStep(config, fakeClient, testNamespace, testLoadbalancerName) // simulate asynchronous IP setting by cluster provider timer := time.NewTimer(time.Second * 2) @@ -41,7 +42,7 @@ func Test_fqdnRetrieverStep_PerformSetupStep(t *testing.T) { patch := []byte(`{"status":{"loadBalancer":{"ingress":[{"ip": "111.222.111.222"}]}}}`) service, err := fakeClient.CoreV1().Services(testNamespace).Patch( context.Background(), - cesLoadbalancerName, + testLoadbalancerName, types.MergePatchType, patch, metav1.PatchOptions{}, @@ -63,7 +64,7 @@ func TestCreateLoadBalancerStep_PerformSetupStep(t *testing.T) { // given config := &appctx.SetupJsonConfiguration{Naming: appctx.Naming{Fqdn: ""}} - step := NewCreateLoadBalancerStep(config, nil, testNamespace) + step := NewCreateLoadBalancerStep(config, nil, testNamespace, testLoadbalancerName) // when err := step.PerformSetupStep(testCtx) @@ -76,7 +77,7 @@ func TestCreateLoadBalancerStep_PerformSetupStep(t *testing.T) { func TestNewFQDNRetrieverStep(t *testing.T) { // when - step := NewFQDNRetrieverStep(nil, nil, "") + step := NewFQDNRetrieverStep(nil, nil, "", "") // then require.NotNil(t, step) @@ -84,7 +85,7 @@ func TestNewFQDNRetrieverStep(t *testing.T) { func Test_fqdnRetrieverStep_GetStepDescription(t *testing.T) { // given - step := NewFQDNRetrieverStep(nil, nil, "") + step := NewFQDNRetrieverStep(nil, nil, "", "") // when description := step.GetStepDescription() diff --git a/app/setup/executor.go b/app/setup/executor.go index 2a53387f..eb35d7f4 100644 --- a/app/setup/executor.go +++ b/app/setup/executor.go @@ -332,8 +332,9 @@ func (e *Executor) RegisterDoguInstallationSteps() error { // RegisterLoadBalancerFQDNRetrieverSteps registers the steps for creating a loadbalancer retrieving the fqdn func (e *Executor) RegisterLoadBalancerFQDNRetrieverSteps() error { namespace := e.SetupContext.AppConfig.TargetNamespace + loadbalancerName := e.SetupContext.AppConfig.LoadbalancerName config := e.SetupContext.SetupJsonConfiguration - e.RegisterSetupSteps(data.NewCreateLoadBalancerStep(config, e.ClientSet, namespace)) + e.RegisterSetupSteps(data.NewCreateLoadBalancerStep(config, e.ClientSet, namespace, loadbalancerName)) loadbalancerResourcePatchStep, err := createResourcePatchStep( patch.LoadbalancerPhase, @@ -352,7 +353,7 @@ func (e *Executor) RegisterLoadBalancerFQDNRetrieverSteps() error { if wantsLoadbalancerIpAddressAsFqdn { // Here we wait for an external IP address automagically or (after introducing the above patch) an internal IP address. // We ignore the case where the public IP address was already assigned but the patch should lead to another. - e.RegisterSetupSteps(data.NewFQDNRetrieverStep(config, e.ClientSet, namespace)) + e.RegisterSetupSteps(data.NewFQDNRetrieverStep(config, e.ClientSet, namespace, loadbalancerName)) } return nil