Skip to content

Commit 1401505

Browse files
PreisschildUnix4ever
authored andcommitted
feat: trigger rollout on controlPlaneConfig changes
This change automatically rolls out new Machines when the controlPlaneConfig has been changed. Signed-off-by: Ströger Florian <[email protected]> Signed-off-by: Artem Chernyshev <[email protected]>
1 parent 6be6eec commit 1401505

File tree

2 files changed

+83
-0
lines changed

2 files changed

+83
-0
lines changed

controllers/controllers_test.go

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@ import (
1010
"time"
1111

1212
. "github.com/onsi/gomega"
13+
bootstrapv1alpha3 "github.com/siderolabs/cluster-api-bootstrap-provider-talos/api/v1alpha3"
1314
"github.com/siderolabs/talos/pkg/machinery/api/common"
1415
"github.com/siderolabs/talos/pkg/machinery/api/machine"
1516
"github.com/siderolabs/talos/pkg/machinery/config/types/v1alpha1/generate"
@@ -568,6 +569,31 @@ func (suite *ControllersSuite) TestRollingUpdate() {
568569
}
569570
}, time.Minute).Should(Succeed())
570571

572+
for _, machine := range getMachines() {
573+
talosconfig := &bootstrapv1alpha3.TalosConfig{}
574+
575+
fakeClient.Get(suite.ctx, client.ObjectKey{Name: machine.Spec.Bootstrap.ConfigRef.Name, Namespace: machine.Spec.Bootstrap.ConfigRef.Namespace}, talosconfig)
576+
577+
patchHelper, err := patch.NewHelper(talosconfig, fakeClient)
578+
talosconfig.Spec.TalosVersion = "v1.5.0"
579+
580+
g.Expect(err).To(BeNil())
581+
g.Expect(patchHelper.Patch(suite.ctx, talosconfig)).To(Succeed())
582+
}
583+
584+
g.Eventually(func(g Gomega) {
585+
_, err = r.Reconcile(suite.ctx, ctrl.Request{NamespacedName: util.ObjectKey(tcp)})
586+
g.Expect(err).NotTo(HaveOccurred())
587+
g.Expect(r.APIReader.Get(suite.ctx, client.ObjectKey{Name: tcp.Name, Namespace: tcp.Namespace}, tcp)).To(Succeed())
588+
g.Expect(tcp.Status.ReadyReplicas).To(BeEquivalentTo(2))
589+
590+
machines := getMachines()
591+
for _, machine := range machines {
592+
g.Expect(machine.Spec.Version).ToNot(BeNil())
593+
g.Expect(*machine.Spec.Version).To(BeEquivalentTo(tcp.Spec.Version))
594+
}
595+
}, time.Minute).Should(Succeed())
596+
571597
cancel()
572598
g.Expect(eg.Wait()).To(Succeed())
573599
}

controllers/controlplane.go

Lines changed: 57 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,9 @@ package controllers
66

77
import (
88
"context"
9+
"reflect"
10+
11+
cabptv1 "github.com/siderolabs/cluster-api-bootstrap-provider-talos/api/v1alpha3"
912

1013
"github.com/go-logr/logr"
1114
"github.com/pkg/errors"
@@ -30,6 +33,7 @@ type ControlPlane struct {
3033
Machines collections.Machines
3134

3235
infraObjects map[string]*unstructured.Unstructured
36+
talosConfigs map[string]*cabptv1.TalosConfig
3337
}
3438

3539
// newControlPlane returns an instantiated ControlPlane.
@@ -39,11 +43,17 @@ func newControlPlane(ctx context.Context, client client.Client, cluster *cluster
3943
return nil, err
4044
}
4145

46+
talosConfigs, err := getTalosConfigs(ctx, client, machines)
47+
if err != nil {
48+
return nil, err
49+
}
50+
4251
return &ControlPlane{
4352
TCP: tcp,
4453
Cluster: cluster,
4554
Machines: machines,
4655
infraObjects: infraObjects,
56+
talosConfigs: talosConfigs,
4757
}, nil
4858
}
4959

@@ -76,6 +86,7 @@ func (c *ControlPlane) MachinesNeedingRollout() collections.Machines {
7686
collections.And(
7787
collections.MatchesKubernetesVersion(c.TCP.Spec.Version),
7888
MatchesTemplateClonedFrom(c.infraObjects, c.TCP),
89+
MatchesControlPlaneConfig(c.talosConfigs, c.TCP),
7990
),
8091
),
8192
)
@@ -97,6 +108,35 @@ func getInfraResources(ctx context.Context, cl client.Client, machines collectio
97108
return result, nil
98109
}
99110

111+
// getTalosConfigs fetches the TalosConfigs for each machine in the collection and returns a map of machine.Name -> TalosConfig.
112+
func getTalosConfigs(ctx context.Context, cl client.Client, machines collections.Machines) (map[string]*cabptv1.TalosConfig, error) {
113+
result := map[string]*cabptv1.TalosConfig{}
114+
115+
for _, m := range machines {
116+
bootstrapRef := m.Spec.Bootstrap.ConfigRef
117+
if bootstrapRef == nil {
118+
continue
119+
}
120+
121+
talosconfig := &cabptv1.TalosConfig{}
122+
123+
err := cl.Get(ctx, client.ObjectKey{
124+
Namespace: m.Namespace,
125+
Name: bootstrapRef.Name,
126+
}, talosconfig)
127+
if err != nil {
128+
if apierrors.IsNotFound(errors.Cause(err)) {
129+
continue
130+
}
131+
return nil, errors.Wrapf(err, "failed to retrieve talosconfig obj for machine %q", m.Name)
132+
}
133+
134+
result[m.Name] = talosconfig
135+
}
136+
137+
return result, nil
138+
}
139+
100140
// MatchesTemplateClonedFrom returns a filter to find all machines that match a given TCP infra template.
101141
func MatchesTemplateClonedFrom(infraConfigs map[string]*unstructured.Unstructured, tcp *controlplanev1.TalosControlPlane) collections.Func {
102142
return func(machine *clusterv1.Machine) bool {
@@ -127,3 +167,20 @@ func MatchesTemplateClonedFrom(infraConfigs map[string]*unstructured.Unstructure
127167
return true
128168
}
129169
}
170+
171+
// MatchesControlPlaneConfig returns a filter to find all machines that match a given controlPaneConfig.
172+
func MatchesControlPlaneConfig(talosConfigs map[string]*cabptv1.TalosConfig, tcp *controlplanev1.TalosControlPlane) collections.Func {
173+
return func(machine *clusterv1.Machine) bool {
174+
if machine == nil {
175+
return false
176+
}
177+
178+
talosConfig, found := talosConfigs[machine.Name]
179+
if !found {
180+
// Return true here because failing to get talosconfig should not be considered as unmatching.
181+
return true
182+
}
183+
184+
return reflect.DeepEqual(tcp.Spec.ControlPlaneConfig.ControlPlaneConfig, talosConfig.Spec)
185+
}
186+
}

0 commit comments

Comments
 (0)