Skip to content

Commit

Permalink
#95 make loadbalancer name configurable
Browse files Browse the repository at this point in the history
it is a cluster-wide resource, therefore names will collide
  • Loading branch information
alexander-dammeier committed Jul 19, 2024
1 parent 0c6a56c commit 800d640
Show file tree
Hide file tree
Showing 7 changed files with 55 additions and 35 deletions.
2 changes: 2 additions & 0 deletions app/context/config.go
Original file line number Diff line number Diff line change
Expand Up @@ -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.
Expand Down
14 changes: 12 additions & 2 deletions app/context/config_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -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"
Expand Down Expand Up @@ -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,
Expand All @@ -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) {
Expand Down
17 changes: 11 additions & 6 deletions app/setup/data/createLoadBalancerStep.go
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -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"},
},
Expand Down
10 changes: 5 additions & 5 deletions app/setup/data/createLoadBalancerStep_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -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"}
Expand All @@ -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"}
Expand Down
27 changes: 14 additions & 13 deletions app/setup/data/fqdnRetrieverStep.go
Original file line number Diff line number Diff line change
Expand Up @@ -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
})
Expand Down
15 changes: 8 additions & 7 deletions app/setup/data/fqdnRetrieverStep_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -14,15 +14,16 @@ import (
)

const (
testNamespace = "ecosystem"
testNamespace = "ecosystem"
testLoadbalancerName = "ces-test-loadbalancer"
)

func Test_fqdnRetrieverStep_PerformSetupStep(t *testing.T) {
t.Run("should successfully set FQDN to IP when the load-balancer receives an external IP address", func(t *testing.T) {
// given
mockedLoadBalancerResource := &corev1.Service{
ObjectMeta: metav1.ObjectMeta{
Name: cesLoadbalancerName,
Name: testLoadbalancerName,
Namespace: testNamespace,
},
Spec: corev1.ServiceSpec{
Expand All @@ -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)
Expand All @@ -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{},
Expand All @@ -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)
Expand All @@ -76,15 +77,15 @@ 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)
}

func Test_fqdnRetrieverStep_GetStepDescription(t *testing.T) {
// given
step := NewFQDNRetrieverStep(nil, nil, "")
step := NewFQDNRetrieverStep(nil, nil, "", "")

// when
description := step.GetStepDescription()
Expand Down
5 changes: 3 additions & 2 deletions app/setup/executor.go
Original file line number Diff line number Diff line change
Expand Up @@ -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,
Expand All @@ -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
Expand Down

0 comments on commit 800d640

Please sign in to comment.