Skip to content
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
22 changes: 17 additions & 5 deletions pkg/controller/ingress/ingressclass_controller.go
Original file line number Diff line number Diff line change
Expand Up @@ -289,14 +289,16 @@ func (r *IngressClassReconciler) reconcileALBResources( //nolint:gocyclo,funlen

missingCertificates := tree.GetMissingCertificates(ingressClassCertificates)
for fingerprint, c := range missingCertificates {
labels := map[string]string{
spec.LabelIngressClassUID: string(ingressClass.UID),
}

createCertificatePayload := &certsdk.CreateCertificatePayload{
Name: new("k8s-ingress-" + string(ingressClass.UID)),
ProjectId: &r.ALBConfig.Global.ProjectID,
PrivateKey: new(c.PrivateKey),
PublicKey: new(c.PublicKey),
Labels: &map[string]string{
spec.LabelIngressClassUID: string(ingressClass.UID),
},
Labels: new(spec.MergeExtraLabels(labels, r.ALBConfig.ApplicationLoadBalancer.ExtraLabels)),
}
response, err := r.CertificateClient.CreateCertificate(ctx, r.ALBConfig.Global.ProjectID, r.ALBConfig.Global.Region, createCertificatePayload)
if err != nil {
Expand Down Expand Up @@ -325,14 +327,24 @@ func (r *IngressClassReconciler) reconcileALBResources( //nolint:gocyclo,funlen

alb := existingALB
if existingALB == nil {
create := tree.ToCreatePayload(certIDMap, r.ALBConfig.ApplicationLoadBalancer.NetworkID, r.ALBConfig.Global.Region)
create := tree.ToCreatePayload(
certIDMap,
r.ALBConfig.ApplicationLoadBalancer.NetworkID,
r.ALBConfig.Global.Region,
r.ALBConfig.ApplicationLoadBalancer.ExtraLabels,
)
alb, err = r.ALBClient.CreateLoadBalancer(ctx, r.ALBConfig.Global.ProjectID, r.ALBConfig.Global.Region, create)
if err != nil {
return nil, fmt.Errorf("failed to create load balancer: %w", err)
}
ctrl.LoggerFrom(ctx).Info("Created application load balancer", "name", create.Name, "version", *alb.Version)
} else {
update := tree.ToUpdatePayload(certIDMap, r.ALBConfig.ApplicationLoadBalancer.NetworkID, r.ALBConfig.Global.Region)
update := tree.ToUpdatePayload(
certIDMap,
r.ALBConfig.ApplicationLoadBalancer.NetworkID,
r.ALBConfig.Global.Region,
r.ALBConfig.ApplicationLoadBalancer.ExtraLabels,
)
if diff.UpdateNeeded(existingALB, update) {
alb, err = r.ALBClient.UpdateLoadBalancer(ctx, r.ALBConfig.Global.ProjectID, r.ALBConfig.Global.Region, *update.Name, update)
if err != nil {
Expand Down
12 changes: 12 additions & 0 deletions pkg/controller/ingress/spec/labels.go
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
package spec

import "maps"

const (

// prefixALBIngressController is the prefix for all labels associated with ingress controllers
Expand All @@ -8,3 +10,13 @@ const (
// owned by a specific IngressClass.
LabelIngressClassUID = prefixALBIngressController + "ingress-class-uid"
)

// MergeExtraLabels merges extraLabels into labels. If there are the same key is in both maps, the labels map will have priority.
func MergeExtraLabels(labels, extraLabels map[string]string) map[string]string {
l := maps.Clone(extraLabels)
if l == nil {
l = map[string]string{}
}
maps.Copy(l, labels)
return l
}
43 changes: 43 additions & 0 deletions pkg/controller/ingress/spec/labels_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
package spec

import (
. "github.com/onsi/ginkgo/v2"
. "github.com/onsi/gomega"
)

var _ = DescribeTable("test merging of labels",
func(labels, extraLabels, expected map[string]string) {
got := MergeExtraLabels(labels, extraLabels)
Expect(got).To(Equal(expected))
},
Entry("no duplicates",
map[string]string{"label1": "value1", "label2": "value2"},
map[string]string{"label3": "value3"},
map[string]string{"label1": "value1", "label2": "value2", "label3": "value3"},
),
Entry("duplicates",
map[string]string{"label1": "value1", "label2": "value2"},
map[string]string{"label1": "otherValue1"},
map[string]string{"label1": "value1", "label2": "value2"},
),
Entry("labels nil",
nil,
map[string]string{"label1": "value1"},
map[string]string{"label1": "value1"},
),
Entry("extralabels nil",
map[string]string{"label1": "value1"},
nil,
map[string]string{"label1": "value1"},
),
Entry("labels empty",
map[string]string{},
map[string]string{"label1": "value1"},
map[string]string{"label1": "value1"},
),
Entry("extralabels empty",
map[string]string{"label1": "value1"},
map[string]string{},
map[string]string{"label1": "value1"},
),
)
14 changes: 9 additions & 5 deletions pkg/controller/ingress/spec/worktree.go
Original file line number Diff line number Diff line change
Expand Up @@ -673,6 +673,7 @@ func (t *WorkTreeALB) ToCreatePayload( //nolint:gocyclo,funlen // Breaking up th
certificateIDMap map[CertificateFingerprint]string,
networkID string,
region string,
extraLabels map[string]string,
) *albsdk.CreateLoadBalancerPayload {
listeners := []albsdk.Listener{}
for port, listener := range t.listeners {
Expand Down Expand Up @@ -778,13 +779,15 @@ func (t *WorkTreeALB) ToCreatePayload( //nolint:gocyclo,funlen // Breaking up th
ephemeralAddress = new(true)
}

labels := map[string]string{
Comment thread
xoxys marked this conversation as resolved.
LabelIngressClassUID: string(t.ingressClass.UID),
}

return &albsdk.CreateLoadBalancerPayload{
DisableTargetSecurityGroupAssignment: new(true), // TODO: Make this configurable via flag.
Name: new(LoadBalancerName(t.ingressClass)),
Labels: &map[string]string{
"ingress-class-uid": string(t.ingressClass.UID),
},
Listeners: listeners,
Labels: new(MergeExtraLabels(labels, extraLabels)),
Listeners: listeners,
Networks: []albsdk.Network{
{
NetworkId: new(networkID),
Expand Down Expand Up @@ -813,8 +816,9 @@ func (t *WorkTreeALB) ToUpdatePayload(
certificateIDMap map[CertificateFingerprint]string,
networkID string,
region string,
extraLabels map[string]string,
) *albsdk.UpdateLoadBalancerPayload {
create := t.ToCreatePayload(certificateIDMap, networkID, region)
create := t.ToCreatePayload(certificateIDMap, networkID, region, extraLabels)
update := new(albsdk.UpdateLoadBalancerPayload{
DisableTargetSecurityGroupAssignment: create.DisableTargetSecurityGroupAssignment,
ExternalAddress: create.ExternalAddress,
Expand Down
80 changes: 63 additions & 17 deletions pkg/controller/ingress/spec/worktree_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import (
"fmt"
"time"

"github.com/google/uuid"
. "github.com/onsi/ginkgo/v2"
. "github.com/onsi/gomega"
. "github.com/onsi/gomega/gstruct"
Expand All @@ -17,6 +18,7 @@ import (
corev1 "k8s.io/api/core/v1"
networkingv1 "k8s.io/api/networking/v1"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
k8stypes "k8s.io/apimachinery/pkg/types"
"k8s.io/apimachinery/pkg/util/validation/field"
)

Expand Down Expand Up @@ -58,7 +60,7 @@ var _ = Describe("WorkTreeALB", func() {
}, nil, nil)
Expect(err).NotTo(HaveOccurred())
Expect(errs).To(BeEmpty())
createPayload := tree.ToCreatePayload(nil, "", "")
createPayload := tree.ToCreatePayload(nil, "", "", nil)
Expect(createPayload.Listeners[0].Http.Hosts[0].Host).To(HaveValue(Equal("my-host.local")))
Expect(createPayload.Listeners[0].Http.Hosts[0].Rules).To(HaveLen(7))
Expect(createPayload.Listeners[0].Http.Hosts[0].Rules[0].Path.ExactMatch).To(HaveValue(Equal("/exact/a/a")))
Expand Down Expand Up @@ -108,7 +110,7 @@ var _ = Describe("WorkTreeALB", func() {
Expect(err).NotTo(HaveOccurred())
Expect(errs).To(BeEmpty())

createPayload := tree.ToCreatePayload(nil, "", "")
createPayload := tree.ToCreatePayload(nil, "", "", nil)

Expect(createPayload.Listeners[0].Http.Hosts[0].Host).To(HaveValue(Equal(host)))

Expand Down Expand Up @@ -194,7 +196,7 @@ var _ = Describe("WorkTreeALB", func() {
"FieldPath": Equal(field.NewPath("spec", "tls").Index(0).Child("secretName")),
}),
))
create := tree.ToCreatePayload(nil, "network-id", "eu01")
create := tree.ToCreatePayload(nil, "network-id", "eu01", nil)
// HTTP rules should still work.
Expect(create.Listeners).To(HaveLen(1))
Expect(create.Listeners[0].Port).To(HaveValue(BeEquivalentTo(80)))
Expand Down Expand Up @@ -384,7 +386,7 @@ var _ = Describe("WorkTreeALB", func() {
testdata.FixtureTLS1FingerprintSHA256: "id-cert-1",
testdata.FixtureTLS2FingerprintSHA256: "id-cert-2",
testdata.FixtureTLS3FingerprintSHA256: "id-cert-3",
}, "my-network", "region")
}, "my-network", "region", nil)
Expect(create.Listeners).To(HaveLen(2))
Expect(create.Listeners[0].Port).To(HaveValue(BeEquivalentTo(443)))
Expect(create.Listeners[0].Https.CertificateConfig.CertificateIds).To(ConsistOf(
Expand Down Expand Up @@ -424,7 +426,7 @@ var _ = Describe("WorkTreeALB", func() {
Expect(err).NotTo(HaveOccurred())

Expect(errs).To(BeEmpty())
create := tree.ToCreatePayload(nil, "network-id", "region")
create := tree.ToCreatePayload(nil, "network-id", "region", nil)
Expect(create.Listeners).To(HaveLen(1))
Expect(create.Listeners[0].Http.Hosts).To(HaveLen(1))
Expect(create.Listeners[0].Http.Hosts[0].Rules).To(HaveLen(2))
Expand Down Expand Up @@ -459,7 +461,7 @@ var _ = Describe("WorkTreeALB", func() {
Expect(err).NotTo(HaveOccurred())

Expect(errs).To(BeEmpty())
create := tree.ToCreatePayload(nil, "network-id", "region")
create := tree.ToCreatePayload(nil, "network-id", "region", nil)
Expect(create.Listeners).To(HaveLen(1))
Expect(create.Listeners[0].Http.Hosts).To(HaveLen(1))
Expect(create.Listeners[0].Http.Hosts[0].Rules).To(HaveLen(2))
Expand Down Expand Up @@ -495,7 +497,7 @@ var _ = Describe("WorkTreeALB", func() {
Expect(err).NotTo(HaveOccurred())

Expect(errs).To(BeEmpty())
create := tree.ToCreatePayload(nil, "network-id", "region")
create := tree.ToCreatePayload(nil, "network-id", "region", nil)
Expect(create.Listeners).To(HaveLen(2))
Expect(create.Listeners[0].WafConfigName).To(HaveValue(Equal("my-waf")))
Expect(create.Listeners[1].WafConfigName).To(HaveValue(Equal("my-waf")))
Expand All @@ -515,7 +517,7 @@ var _ = Describe("WorkTreeALB", func() {
Expect(err).NotTo(HaveOccurred())

Expect(errs).To(BeEmpty())
create := tree.ToCreatePayload(nil, "network-id", "region")
create := tree.ToCreatePayload(nil, "network-id", "region", nil)
Expect(create.Options.AccessControl.AllowedSourceRanges).To(HaveExactElements("10.0.0.0/24", "1.2.3.4/32"))
})

Expand All @@ -533,7 +535,7 @@ var _ = Describe("WorkTreeALB", func() {
Expect(err).NotTo(HaveOccurred())

Expect(errs).To(BeEmpty())
create := tree.ToCreatePayload(nil, "network-id", "region")
create := tree.ToCreatePayload(nil, "network-id", "region", nil)
Expect(create.Options.PrivateNetworkOnly).To(HaveValue(BeTrue()))
Expect(create.Options.EphemeralAddress).To(HaveValue(BeFalse()))
})
Expand All @@ -552,7 +554,7 @@ var _ = Describe("WorkTreeALB", func() {
Expect(err).NotTo(HaveOccurred())

Expect(errs).To(BeEmpty())
create := tree.ToCreatePayload(nil, "network-id", "region")
create := tree.ToCreatePayload(nil, "network-id", "region", nil)
Expect(create.ExternalAddress).To(HaveValue(Equal("1.2.3.4")))
Expect(create.Options.EphemeralAddress).To(HaveValue(BeFalse()))
})
Expand Down Expand Up @@ -655,7 +657,7 @@ var _ = Describe("WorkTreeALB", func() {
Expect(err).NotTo(HaveOccurred())

Expect(errs).To(BeEmpty())
create := tree.ToCreatePayload(nil, "network-id", "region")
create := tree.ToCreatePayload(nil, "network-id", "region", nil)
Expect(create.TargetPools).To(HaveLen(5))
Expect(create.TargetPools[0].TlsConfig.Enabled).To(HaveValue(BeTrue()))
Expect(create.TargetPools[1].TlsConfig.Enabled).To(HaveValue(BeFalse()))
Expand Down Expand Up @@ -686,7 +688,7 @@ var _ = Describe("WorkTreeALB", func() {
Expect(err).NotTo(HaveOccurred())

Expect(errs).To(BeEmpty())
update := tree.ToUpdatePayload(nil, "network-id", "region")
update := tree.ToUpdatePayload(nil, "network-id", "region", nil)
Expect(update.Options.Observability.Logs.CredentialsRef).To(HaveValue(Equal("my-creds")))
Expect(update.Options.Observability.Logs.PushUrl).To(HaveValue(Equal("my-push-url")))
})
Expand All @@ -706,7 +708,7 @@ var _ = Describe("WorkTreeALB", func() {
Expect(err).NotTo(HaveOccurred())

Expect(errs).To(BeEmpty())
update := tree.ToUpdatePayload(nil, "network-id", "region")
update := tree.ToUpdatePayload(nil, "network-id", "region", nil)
Expect(update.Version).To(HaveValue(Equal("current-version")))
})

Expand All @@ -732,7 +734,7 @@ var _ = Describe("WorkTreeALB", func() {
Expect(err).NotTo(HaveOccurred())

Expect(errs).To(BeEmpty())
create := tree.ToCreatePayload(nil, "network-id", "region")
create := tree.ToCreatePayload(nil, "network-id", "region", nil)
Expect(create.Listeners[0].Http.Hosts[0].Rules[0].Path.ExactMatch).To(HaveValue(Equal("/a")))
})

Expand Down Expand Up @@ -880,7 +882,7 @@ var _ = Describe("WorkTreeALB", func() {
Expect(err).NotTo(HaveOccurred())

Expect(errs).To(BeEmpty())
create := tree.ToCreatePayload(nil, "network-id", "region")
create := tree.ToCreatePayload(nil, "network-id", "region", nil)
Expect(create.TargetPools).To(HaveLen(1))
Expect(create.TargetPools[0].Targets).To(ConsistOf(
v2api.Target{
Expand Down Expand Up @@ -954,7 +956,7 @@ var _ = Describe("WorkTreeALB", func() {
Expect(err).NotTo(HaveOccurred())
Expect(errs).To(BeEmpty())

create := tree.ToCreatePayload(nil, "network-id", "region")
create := tree.ToCreatePayload(nil, "network-id", "region", nil)
Expect(create.TargetPools).To(HaveLen(1))
Expect(create.TargetPools[0].Targets).To(HaveLen(250))
Expect(create.TargetPools[0].Targets).To(HaveEach(MatchFields(IgnoreExtras, Fields{
Expand Down Expand Up @@ -1018,7 +1020,7 @@ var _ = Describe("WorkTreeALB", func() {
Expect(err).NotTo(HaveOccurred())

Expect(errs).To(BeEmpty())
create := tree.ToCreatePayload(nil, "network-id", "region")
create := tree.ToCreatePayload(nil, "network-id", "region", nil)
// Sorting of path is done in a separate test.
Expect(create.Listeners).To(HaveExactElements(
MatchFields(IgnoreExtras, Fields{
Expand Down Expand Up @@ -1182,6 +1184,50 @@ var _ = Describe("WorkTreeALB", func() {
Expect(tree.targetPools).To(BeEmpty())
})

It("should contain extraLabels", func() {
ingressClass := &networkingv1.IngressClass{
ObjectMeta: metav1.ObjectMeta{
UID: k8stypes.UID(uuid.NewString()),
Annotations: map[string]string{
AnnotationNetworkMode: NetworkModeNodePort,
},
},
}

tree, errs, err := BuildTree(
ingressClass, nil, nil, nil, nil, nil,
)
Expect(err).NotTo(HaveOccurred())

Expect(errs).To(BeEmpty())
create := tree.ToCreatePayload(nil, "network-id", "region", map[string]string{"foo": "bar", "bar": "foo"})
Expect(create.Labels).To(Not(BeNil()))
Expect(*create.Labels).To(HaveKeyWithValue("foo", "bar"))
Expect(*create.Labels).To(HaveKeyWithValue("bar", "foo"))
Expect(*create.Labels).To(HaveKeyWithValue(LabelIngressClassUID, string(ingressClass.UID)))
})

It("should not overwrite needed labels with extraLabels", func() {
ingressClass := &networkingv1.IngressClass{
ObjectMeta: metav1.ObjectMeta{
UID: k8stypes.UID(uuid.NewString()),
Annotations: map[string]string{
AnnotationNetworkMode: NetworkModeNodePort,
},
},
}

tree, errs, err := BuildTree(
ingressClass, nil, nil, nil, nil, nil,
)
Expect(err).NotTo(HaveOccurred())

Expect(errs).To(BeEmpty())
create := tree.ToCreatePayload(nil, "network-id", "region", map[string]string{LabelIngressClassUID: "foobar"})
Expect(create.Labels).To(Not(BeNil()))
Expect(*create.Labels).To(HaveKeyWithValue(LabelIngressClassUID, string(ingressClass.UID)))
})

DescribeTable("parsing ingress class annotation", func(key, value, expectErr string) {
_, _, err := BuildTree(
&networkingv1.IngressClass{
Expand Down
3 changes: 2 additions & 1 deletion pkg/stackit/config/config.go
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,8 @@ type ALBConfig struct {
ApplicationLoadBalancer ApplicationLoadBalancerOpts `yaml:"applicationLoadBalancer"`
}
type ApplicationLoadBalancerOpts struct {
NetworkID string `yaml:"networkId"`
NetworkID string `yaml:"networkId"`
ExtraLabels map[string]string `yaml:"extraLabels"`
}

func readFile(path string) ([]byte, error) {
Expand Down