Skip to content
Open
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
38 changes: 36 additions & 2 deletions pkg/alb/ingress/alb_spec.go
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,15 @@ import (
certsdk "github.com/stackitcloud/stackit-sdk-go/services/certificates/v2api"
)

const (
// prefixCustomerLabel is the api prefix for all custom labels
prefixCustomerLabel = "lb.customer.label/"

// LabelIngressClassUID is the unique key that identifies resources
// owned by a specific IngressClass.
LabelIngressClassUID = prefixCustomerLabel + "ingress-class-uid"
)

func (r *IngressClassReconciler) getAlbSpecForIngressClass(ctx context.Context, class *networkingv1.IngressClass) (*albsdk.CreateLoadBalancerPayload, []errorEvents, error) {
ingresses, err := r.getIngressesForIngressClass(ctx, class)
if err != nil {
Expand Down Expand Up @@ -45,7 +54,7 @@ func (r *IngressClassReconciler) getAlbSpecForIngresses(ctx context.Context, cla
errorList = append(errorList, listenerMergeError...)
}

certNameToId, certificateErrorEvents := r.applyCertificates(ctx, certificates)
certNameToId, certificateErrorEvents := r.applyCertificates(ctx, class, certificates)
errorList = append(errorList, certificateErrorEvents...)

alb, albSpecErrorList, err := r.getAlbSpecForResources(ctx, class, listeners, targetPools, certNameToId)
Expand Down Expand Up @@ -83,6 +92,28 @@ func (r *IngressClassReconciler) getAlbSpecForResources(ctx context.Context, cla
alb.PlanId = &plan
}

mergedLabels := make(map[string]string)

// Add user labels, mind the limit
for k, v := range class.Labels {
if len(mergedLabels) < 64 {
mergedLabels[k] = v
}
}

// Merge with existing global config labels
if r.ALBConfig.ApplicationLoadBalancer.ExtraLabels != nil {
for k, v := range r.ALBConfig.ApplicationLoadBalancer.ExtraLabels {
if len(mergedLabels) < 64 {
mergedLabels[k] = v
}
}
}

// Add ownership label
mergedLabels[LabelIngressClassUID] = string(class.UID)
alb.Labels = &mergedLabels

for port, listener := range listeners {
albsdkListener := albsdk.Listener{
Http: nil,
Expand Down Expand Up @@ -379,7 +410,7 @@ func (r *IngressClassReconciler) getCertificateForSecretName(ctx context.Context
}, nil
}

func (r *IngressClassReconciler) applyCertificates(ctx context.Context, certificates albCertificates) (map[string]string, []errorEvents) {
func (r *IngressClassReconciler) applyCertificates(ctx context.Context, class *networkingv1.IngressClass, certificates albCertificates) (map[string]string, []errorEvents) {
errorList := []errorEvents{}
nameToID := map[string]string{}
for name, certificate := range certificates {
Expand All @@ -388,6 +419,9 @@ func (r *IngressClassReconciler) applyCertificates(ctx context.Context, certific
ProjectId: &r.ALBConfig.Global.ProjectID,
PrivateKey: new(string(certificate.privateKey)),
PublicKey: new(string(certificate.publicKey)),
Labels: &map[string]string{
LabelIngressClassUID: string(class.UID),
},
}
response, err := r.CertificateClient.CreateCertificate(ctx, r.ALBConfig.Global.ProjectID, r.ALBConfig.Global.Region, createCertificatePayload)
if err != nil {
Expand Down
13 changes: 13 additions & 0 deletions pkg/alb/ingress/alb_spec_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -142,6 +142,19 @@ var _ = Describe("Node Controller", func() {
Expect(*spec).To(BeEquivalentTo(albSpec))
})

It("should work with labels", func() {

reconciler.ALBConfig.ApplicationLoadBalancer.ExtraLabels = map[string]string{"managed-by": "alb-ingressClass"}
spec, errorEventList, err := reconciler.getAlbSpecForIngressClass(context.Background(), &ingressClass)
Expect(err).To(Succeed())
Expect(errorEventList).To(BeEmpty())

albSpec.Labels = new(map[string]string{"managed-by": "alb-ingressClass"})

Expect(spec).ToNot(BeNil())
Expect(*spec).To(BeEquivalentTo(albSpec))
})

It("should work with 2 ingresses different path", func() {
ingress2 := testIngress(&ingressClass, &service)
ingress2.Name = "ingress2"
Expand Down
10 changes: 9 additions & 1 deletion pkg/alb/ingress/certificate.go
Original file line number Diff line number Diff line change
Expand Up @@ -19,8 +19,16 @@ func (r *IngressClassReconciler) deleteAllCertsForClass(ctx context.Context, cla
return nil // No certificates to clean up
}

// using labels for certificates
targetUID := string(class.UID)

for _, cert := range certificatesList.Items {
if strings.HasPrefix(*cert.Name, shortUUID(string(class.UID))) {
if cert.Labels == nil {
// This part will go away when Labels are supported by Cert API
// do I need to check if nil
}

if val, ok := (*cert.Labels)[LabelIngressClassUID]; ok && val == targetUID {
err := r.CertificateClient.DeleteCertificate(ctx, r.ALBConfig.Global.ProjectID, r.ALBConfig.Global.Region, *cert.Id)
if err != nil {
return fmt.Errorf("failed to delete orphaned certificate %s: %v", *cert.Name, err)
Expand Down
10 changes: 10 additions & 0 deletions pkg/alb/ingress/update.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import (
"context"
"errors"
"fmt"
"reflect"

"github.com/stackitcloud/cloud-provider-stackit/pkg/stackit"
albsdk "github.com/stackitcloud/stackit-sdk-go/services/alb/v2api"
Expand Down Expand Up @@ -161,5 +162,14 @@ func updateNeeded(alb *albsdk.LoadBalancer, albPayload *albsdk.CreateLoadBalance
}
}

// Label comparison
// normalize pointers to prevent nil vs empty map issue
currentLabels := ptr.Deref(alb.Labels, map[string]string{})
desiredLabels := ptr.Deref(albPayload.Labels, map[string]string{})

if !reflect.DeepEqual(currentLabels, desiredLabels) {
return true
}

return false
}
3 changes: 2 additions & 1 deletion pkg/stackit/config/config.go
Original file line number Diff line number Diff line change
Expand Up @@ -49,7 +49,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,omitempty"`
}

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