diff --git a/go.mod b/go.mod index 206a96d3..76e91984 100644 --- a/go.mod +++ b/go.mod @@ -19,7 +19,7 @@ require ( github.com/metal-stack/firewall-controller-manager v0.4.0 github.com/metal-stack/firewall-controller/v2 v2.3.3 github.com/metal-stack/metal-go v0.31.1 - github.com/metal-stack/metal-lib v0.16.2 + github.com/metal-stack/metal-lib v0.17.2 github.com/onsi/ginkgo v1.16.5 github.com/onsi/gomega v1.33.1 github.com/spf13/cobra v1.8.0 diff --git a/go.sum b/go.sum index 56ffd871..d6c62740 100644 --- a/go.sum +++ b/go.sum @@ -1035,8 +1035,8 @@ github.com/metal-stack/firewall-controller/v2 v2.3.3 h1:4NrSFGl9NdUHQpKZK867ti6z github.com/metal-stack/firewall-controller/v2 v2.3.3/go.mod h1:Zo3HIlqqzWyvPGIpfWzsxkQjrIkmZHYtKgld71q24FE= github.com/metal-stack/metal-go v0.31.1 h1:1U31FuqhUveKxlIYrlrzjIhQLEqrlsm7ohZnZGMZz/E= github.com/metal-stack/metal-go v0.31.1/go.mod h1:3MJTYCS4YJz8D8oteTKhjpaAKNMMjMKYDrIy9awHGtQ= -github.com/metal-stack/metal-lib v0.16.2 h1:RJls/Spai4h5xr3BEmQt9UdWNN4RB9+SOINoZcjYaA8= -github.com/metal-stack/metal-lib v0.16.2/go.mod h1:nyNGI4DZFOcWbSoq2Y6V3SHpFxuXBIqYBZHTb6cy//s= +github.com/metal-stack/metal-lib v0.17.2 h1:T1rxCPgagHW/M0wWSrOj4hWsPZMSt1pYw90Z3vBm88Q= +github.com/metal-stack/metal-lib v0.17.2/go.mod h1:nyNGI4DZFOcWbSoq2Y6V3SHpFxuXBIqYBZHTb6cy//s= github.com/metal-stack/security v0.8.0 h1:tVaSDB9m5clwYrnLyaXfPy7mQlJTnmeoHscG+RUy/xo= github.com/metal-stack/security v0.8.0/go.mod h1:7GAcQb+pOgflW30ohJygxpqc3i0dQ2ahGJK1CU5tqa0= github.com/miekg/dns v1.1.58 h1:ca2Hdkz+cDg/7eNF6V56jjzuZ4aCAE+DbVkILdQWG/4= diff --git a/pkg/controller/infrastructure/actuator_reconcile.go b/pkg/controller/infrastructure/actuator_reconcile.go index a10d6702..2d01e4af 100644 --- a/pkg/controller/infrastructure/actuator_reconcile.go +++ b/pkg/controller/infrastructure/actuator_reconcile.go @@ -121,7 +121,7 @@ func (a *actuator) maintainFirewallDeployment(ctx context.Context, logger logr.L // so it cannot be put to the worker controller. if !gardener.EffectiveShootMaintenanceTimeWindow(cluster.Shoot).Contains(time.Now()) { - // note that this prevents updating the firewall image even when annotating the shoot explicitly with the maintainenance annotation + // note that this prevents updating the firewall image even when annotating the shoot explicitly with the maintenance annotation // if a user wants to update the firewall immediately he needs to specify the new firewall image in the spec logger.Info("not maintaining firewall deployment as shoot not in effective maintenance time window") return nil diff --git a/pkg/controller/worker/firewall_reconcile.go b/pkg/controller/worker/firewall_reconcile.go index 4d05412a..ed6eaeba 100644 --- a/pkg/controller/worker/firewall_reconcile.go +++ b/pkg/controller/worker/firewall_reconcile.go @@ -14,6 +14,7 @@ import ( "github.com/metal-stack/gardener-extension-provider-metal/pkg/apis/metal/helper" "github.com/metal-stack/gardener-extension-provider-metal/pkg/apis/metal/validation" "github.com/metal-stack/gardener-extension-provider-metal/pkg/metal" + metalcommon "github.com/metal-stack/metal-lib/pkg/metal" "github.com/metal-stack/metal-lib/pkg/tag" admissionregistrationv1 "k8s.io/api/admissionregistration/v1" apierrors "k8s.io/apimachinery/pkg/api/errors" @@ -132,7 +133,17 @@ func (a *actuator) ensureFirewallDeployment(ctx context.Context, log logr.Logger deploy.Spec.Template.Labels[tag.ClusterID] = clusterID deploy.Spec.Template.Spec.Size = d.infrastructureConfig.Firewall.Size - deploy.Spec.Template.Spec.Image = d.infrastructureConfig.Firewall.Image + if deploy.Spec.AutoUpdate.MachineImage && d.infrastructureConfig.Firewall.Image != "" { + isPatch, err := patchUpdate(deploy.Spec.Template.Spec.Image, d.infrastructureConfig.Firewall.Image) + if err != nil { + return err + } + if !isPatch { + deploy.Spec.Template.Spec.Image = d.infrastructureConfig.Firewall.Image + } + } else { + deploy.Spec.Template.Spec.Image = d.infrastructureConfig.Firewall.Image + } deploy.Spec.Template.Spec.Networks = append(d.infrastructureConfig.Firewall.Networks, d.privateNetworkID) deploy.Spec.Template.Spec.RateLimits = mapRateLimits(d.infrastructureConfig.Firewall.RateLimits) deploy.Spec.Template.Spec.InternalPrefixes = a.controllerConfig.FirewallInternalPrefixes @@ -206,3 +217,21 @@ func mapEgressRules(egress []apismetal.EgressRule) []fcmv2.EgressRuleSNAT { } return result } + +func patchUpdate(old, new string) (bool, error) { + oldKind, o, err := metalcommon.GetOsAndSemverFromImage(old) + if err != nil { + return false, fmt.Errorf("unable to parse firewall image: %w", err) + } + + newKind, n, err := metalcommon.GetOsAndSemverFromImage(new) + if err != nil { + return false, fmt.Errorf("unable to parse firewall image: %w", err) + } + + if oldKind == newKind && o.Major() == n.Major() && o.Minor() == n.Minor() && o.Patch() != n.Patch() { + return true, nil + } + + return false, nil +} diff --git a/pkg/controller/worker/firewall_reconcile_test.go b/pkg/controller/worker/firewall_reconcile_test.go new file mode 100644 index 00000000..ec66dc2a --- /dev/null +++ b/pkg/controller/worker/firewall_reconcile_test.go @@ -0,0 +1,80 @@ +package worker + +import ( + "github.com/google/go-cmp/cmp" + "github.com/metal-stack/metal-lib/pkg/testcommon" + + "testing" +) + +func Test_patchUpdate(t *testing.T) { + tests := []struct { + name string + old string + new string + want bool + wantErr error + }{ + { + name: "no update", + old: "firewall-ubuntu-3.0", + new: "firewall-ubuntu-3.0", + want: false, + wantErr: nil, + }, + { + name: "no update fully qualified", + old: "firewall-ubuntu-3.0.20240101", + new: "firewall-ubuntu-3.0.20240101", + want: false, + wantErr: nil, + }, + { + name: "patch update", + old: "firewall-ubuntu-3.0.20240101", + new: "firewall-ubuntu-3.0.20240201", + want: true, + wantErr: nil, + }, + { + name: "minor update", + old: "firewall-ubuntu-3.0.20240101", + new: "firewall-ubuntu-3.1.20240101", + want: false, + wantErr: nil, + }, + { + name: "major update", + old: "firewall-ubuntu-3.0.20240101", + new: "firewall-ubuntu-4.0.20240101", + want: false, + wantErr: nil, + }, + { + name: "os update", + old: "firewall-ubuntu-3.0.20240101", + new: "firewall-debian-3.0.20240101", + want: false, + wantErr: nil, + }, + { + name: "update to fully qualified", + old: "firewall-ubuntu-3.0", + new: "firewall-ubuntu-3.0.20240101", + want: true, + wantErr: nil, + }, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + got, err := patchUpdate(tt.old, tt.new) + if diff := cmp.Diff(tt.wantErr, err, testcommon.ErrorStringComparer()); diff != "" { + t.Errorf("error diff (+got -want):\n %s", diff) + } + + if diff := cmp.Diff(got, tt.want, testcommon.StrFmtDateComparer()); diff != "" { + t.Errorf("diff (+got -want):\n %s", diff) + } + }) + } +}