Skip to content

Commit

Permalink
Make latest check optional behind followLatest field
Browse files Browse the repository at this point in the history
Signed-off-by: Danil-Grigorev <danil.grigorev@suse.com>
  • Loading branch information
Danil-Grigorev committed Aug 26, 2024
1 parent 4e377f9 commit 5da5166
Show file tree
Hide file tree
Showing 8 changed files with 70 additions and 32 deletions.
6 changes: 6 additions & 0 deletions api/v1alpha1/capiprovider_types.go
Original file line number Diff line number Diff line change
Expand Up @@ -60,6 +60,12 @@ type CAPIProviderSpec struct {
// +kubebuilder:example={CLUSTER_TOPOLOGY:"true",EXP_CLUSTER_RESOURCE_SET:"true",EXP_MACHINE_POOL: "true"}
Variables map[string]string `json:"variables,omitempty"`

// FollowLatest allows to track current latest version, and update provider accordingly to keep
// manifests in sync with new releases. Maximum version of the released components is limited by the provider
// override in the clusterctl.yaml data within clusterctl-config `ConfigMap`, or the fetchConfig.url.
// +optional
FollowLatest bool `json:"followLatest,omitempty"`

// ProviderSpec is the spec of the underlying CAPI Provider resource.
operatorv1.ProviderSpec `json:",inline"`
}
Expand Down
1 change: 1 addition & 0 deletions charts/rancher-turtles/templates/addon-provider-fleet.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ metadata:
"helm.sh/hook-weight": "2"
spec:
type: addon
followLatest: true
additionalManifests:
name: fleet-addon-config
namespace: '{{ .Values.rancherTurtles.namespace }}'
Expand Down
1 change: 1 addition & 0 deletions charts/rancher-turtles/templates/core-provider.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ metadata:
"helm.sh/hook-weight": "2"
spec:
name: cluster-api
followLatest: true
type: core
version: {{ index .Values "cluster-api-operator" "cluster-api" "version" }}
additionalManifests:
Expand Down
1 change: 1 addition & 0 deletions charts/rancher-turtles/templates/rke2-bootstrap.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ metadata:
spec:
name: rke2
type: bootstrap
followLatest: true
{{- if index .Values "cluster-api-operator" "cluster-api" "rke2" "version" }}
version: {{ index .Values "cluster-api-operator" "cluster-api" "rke2" "version" }}
{{- end }}
Expand Down
1 change: 1 addition & 0 deletions charts/rancher-turtles/templates/rke2-controlplane.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ metadata:
spec:
name: rke2
type: controlPlane
followLatest: true
{{- if index .Values "cluster-api-operator" "cluster-api" "rke2" "version" }}
version: {{ index .Values "cluster-api-operator" "cluster-api" "rke2" "version" }}
{{- end }}
Expand Down
6 changes: 6 additions & 0 deletions config/crd/bases/turtles-capi.cattle.io_capiproviders.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -2769,6 +2769,12 @@ spec:
desired version of the release from GitHub.
type: string
type: object
followLatest:
description: |-
FollowLatest allows to track current latest version, and update provider accordingly to keep
manifests in sync with new releases. Maximum version of the released components is limited by the provider
override in the clusterctl.yaml data within clusterctl-config `ConfigMap`, or the fetchConfig.url.
type: boolean
manager:
description: Manager defines the properties that can be enabled on
the controller manager for the provider.
Expand Down
2 changes: 1 addition & 1 deletion internal/sync/provider_sync.go
Original file line number Diff line number Diff line change
Expand Up @@ -153,7 +153,7 @@ func (s *ProviderSync) rolloutInfrastructure() {

func (s *ProviderSync) updateLatestVersion(ctx context.Context) error {
// Skip for user specified versions
if s.Source.Spec.Version != "" {
if s.Source.Spec.Version != "" || !s.Source.Spec.FollowLatest {
return nil
}

Expand Down
84 changes: 53 additions & 31 deletions internal/sync/provider_sync_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -40,9 +40,11 @@ var _ = Describe("Provider sync", func() {
ns *corev1.Namespace
otherNs *corev1.Namespace
capiProvider *turtlesv1.CAPIProvider
capiProviderFollowLatest *turtlesv1.CAPIProvider
capiProviderAzure *turtlesv1.CAPIProvider
capiProviderDuplicate *turtlesv1.CAPIProvider
infrastructure *operatorv1.InfrastructureProvider
infrastructureFollowLatest *operatorv1.InfrastructureProvider
infrastructureStatusOutdated operatorv1.ProviderStatus
infrastructureDuplicate *operatorv1.InfrastructureProvider
infrastructureAzure *operatorv1.InfrastructureProvider
Expand Down Expand Up @@ -73,6 +75,10 @@ var _ = Describe("Provider sync", func() {
capiProviderDuplicate = capiProvider.DeepCopy()
capiProviderDuplicate.Namespace = otherNs.Name

capiProviderFollowLatest = capiProvider.DeepCopy()
capiProviderFollowLatest.Name = "latest"
capiProviderFollowLatest.Spec.FollowLatest = true

infrastructure = &operatorv1.InfrastructureProvider{ObjectMeta: metav1.ObjectMeta{
Name: string(capiProvider.Spec.Name),
Namespace: ns.Name,
Expand All @@ -88,6 +94,11 @@ var _ = Describe("Provider sync", func() {
Namespace: otherNs.Name,
}}

infrastructureFollowLatest = &operatorv1.InfrastructureProvider{ObjectMeta: metav1.ObjectMeta{
Name: string(capiProviderFollowLatest.Spec.Name),
Namespace: otherNs.Name,
}}

infrastructureStatusOutdated = operatorv1.ProviderStatus{
Conditions: clusterv1.Conditions{
{
Expand All @@ -103,6 +114,7 @@ var _ = Describe("Provider sync", func() {
},
}

Expect(testEnv.Client.Create(ctx, capiProviderFollowLatest)).To(Succeed())
Expect(testEnv.Client.Create(ctx, capiProvider)).To(Succeed())
Expect(testEnv.Client.Create(ctx, capiProviderDuplicate)).To(Succeed())
Expect(testEnv.Client.Create(ctx, capiProviderAzure)).To(Succeed())
Expand Down Expand Up @@ -169,26 +181,25 @@ var _ = Describe("Provider sync", func() {
g.Expect(s.Sync(ctx)).To(Succeed())
s.Apply(ctx, &err)
g.Expect(conditions.IsTrue(capiProvider, turtlesv1.LastAppliedConfigurationTime)).To(BeTrue())
g.Expect(conditions.IsTrue(capiProvider, turtlesv1.CheckLatestVersionTime)).To(BeTrue())
g.Expect(capiProvider.Status.Conditions).To(HaveLen(2))
g.Expect(capiProvider.Status.Conditions).To(HaveLen(1))
g.Expect(capiProvider).To(HaveField("Status.Phase", Equal(turtlesv1.Provisioning)))
}).Should(Succeed())
})

It("Should update outdated condition, maintain last applied time and empty the hash annotation", func() {
capiProvider.Status.ProviderStatus = infrastructureStatusOutdated
capiProviderFollowLatest.Status.ProviderStatus = infrastructureStatusOutdated

appliedCondition := conditions.Get(capiProvider, turtlesv1.LastAppliedConfigurationTime)
lastVersionCheckCondition := conditions.Get(capiProvider, turtlesv1.CheckLatestVersionTime)
appliedCondition := conditions.Get(capiProviderFollowLatest, turtlesv1.LastAppliedConfigurationTime)
lastVersionCheckCondition := conditions.Get(capiProviderFollowLatest, turtlesv1.CheckLatestVersionTime)

Eventually(testEnv.Status().Update(ctx, capiProvider)).Should(Succeed())
Eventually(testEnv.Status().Update(ctx, capiProviderFollowLatest)).Should(Succeed())
Eventually(func(g Gomega) {
g.Expect(testEnv.Get(ctx, client.ObjectKeyFromObject(capiProvider), capiProvider)).To(Succeed())
g.Expect(conditions.Get(capiProvider, turtlesv1.LastAppliedConfigurationTime)).ToNot(BeNil())
g.Expect(conditions.Get(capiProvider, turtlesv1.LastAppliedConfigurationTime).LastTransitionTime.Second()).To(Equal(appliedCondition.LastTransitionTime.Second()))
g.Expect(testEnv.Get(ctx, client.ObjectKeyFromObject(capiProviderFollowLatest), capiProviderFollowLatest)).To(Succeed())
g.Expect(conditions.Get(capiProviderFollowLatest, turtlesv1.LastAppliedConfigurationTime)).ToNot(BeNil())
g.Expect(conditions.Get(capiProviderFollowLatest, turtlesv1.LastAppliedConfigurationTime).LastTransitionTime.Second()).To(Equal(appliedCondition.LastTransitionTime.Second()))
}).Should(Succeed())

s := sync.NewProviderSync(testEnv, capiProvider)
s := sync.NewProviderSync(testEnv, capiProviderFollowLatest)

dest := &operatorv1.InfrastructureProvider{}
Eventually(func(g Gomega) {
Expand All @@ -200,48 +211,61 @@ var _ = Describe("Provider sync", func() {
g.Expect(testEnv.Get(ctx, client.ObjectKeyFromObject(infrastructure), dest)).To(Succeed())
g.Expect(dest.GetAnnotations()).To(HaveKeyWithValue(sync.AppliedSpecHashAnnotation, ""))
g.Expect(testEnv.Get(ctx, client.ObjectKeyFromObject(infrastructure), dest)).To(Succeed())
g.Expect(capiProvider.Status.Conditions).To(HaveLen(2))
g.Expect(conditions.IsTrue(capiProvider, turtlesv1.LastAppliedConfigurationTime)).To(BeTrue())
g.Expect(conditions.IsTrue(capiProvider, turtlesv1.CheckLatestVersionTime)).To(BeTrue())
g.Expect(conditions.Get(capiProvider, turtlesv1.CheckLatestVersionTime).LastTransitionTime.Equal(
g.Expect(capiProviderFollowLatest.Status.Conditions).To(HaveLen(2))
g.Expect(conditions.IsTrue(capiProviderFollowLatest, turtlesv1.LastAppliedConfigurationTime)).To(BeTrue())
g.Expect(conditions.IsTrue(capiProviderFollowLatest, turtlesv1.CheckLatestVersionTime)).To(BeTrue())
g.Expect(conditions.Get(capiProviderFollowLatest, turtlesv1.CheckLatestVersionTime).LastTransitionTime.Equal(
&lastVersionCheckCondition.LastTransitionTime)).To(BeTrue())
g.Expect(conditions.Get(capiProvider, turtlesv1.LastAppliedConfigurationTime).LastTransitionTime.After(
g.Expect(conditions.Get(capiProviderFollowLatest, turtlesv1.LastAppliedConfigurationTime).LastTransitionTime.After(
appliedCondition.LastTransitionTime.Time)).To(BeTrue())
}).Should(Succeed())

Expect(testEnv.Get(ctx, client.ObjectKeyFromObject(capiProvider), capiProvider)).To(Succeed())
condition := conditions.Get(capiProvider, turtlesv1.LastAppliedConfigurationTime)
lastVersionCheckCondition = conditions.Get(capiProvider, turtlesv1.CheckLatestVersionTime)
Expect(testEnv.Get(ctx, client.ObjectKeyFromObject(capiProviderFollowLatest), capiProviderFollowLatest)).To(Succeed())
condition := conditions.Get(capiProviderFollowLatest, turtlesv1.LastAppliedConfigurationTime)
lastVersionCheckCondition = conditions.Get(capiProviderFollowLatest, turtlesv1.CheckLatestVersionTime)

Consistently(func(g Gomega) {
err = nil
g.Expect(s.Get(ctx)).To(Succeed())
g.Expect(s.Sync(ctx)).To(Succeed())
s.Apply(ctx, &err)
g.Expect(testEnv.Get(ctx, client.ObjectKeyFromObject(capiProvider), capiProvider)).To(Succeed())
g.Expect(conditions.Get(capiProvider, turtlesv1.LastAppliedConfigurationTime)).To(Equal(condition))
g.Expect(conditions.Get(capiProvider, turtlesv1.CheckLatestVersionTime)).To(Equal(lastVersionCheckCondition))
g.Expect(testEnv.Get(ctx, client.ObjectKeyFromObject(capiProviderFollowLatest), capiProviderFollowLatest)).To(Succeed())
g.Expect(conditions.Get(capiProviderFollowLatest, turtlesv1.LastAppliedConfigurationTime)).To(Equal(condition))
g.Expect(conditions.Get(capiProviderFollowLatest, turtlesv1.CheckLatestVersionTime)).To(Equal(lastVersionCheckCondition))
}, 5*time.Second).Should(Succeed())
})

It("Should set the last applied version check condition and empty the version field", func() {
s := sync.NewProviderSync(testEnv, capiProvider)
s := sync.NewProviderSync(testEnv, capiProviderFollowLatest)

infrastructure.Spec.Version = "v1.2.3"
infrastructureFollowLatest.Spec.Version = "v1.2.3"

Expect(testEnv.Create(ctx, infrastructure)).To(Succeed())
Expect(testEnv.Create(ctx, infrastructureFollowLatest)).To(Succeed())

Eventually(func(g Gomega) {
err = nil
g.Expect(s.Get(ctx)).To(Succeed())
g.Expect(s.Sync(ctx)).To(Succeed())
s.Apply(ctx, &err)
g.Expect(conditions.IsTrue(capiProvider, turtlesv1.LastAppliedConfigurationTime)).To(BeTrue())
g.Expect(conditions.IsTrue(capiProvider, turtlesv1.CheckLatestVersionTime)).To(BeTrue())
g.Expect(capiProvider.Status.Conditions).To(HaveLen(2))
g.Expect(conditions.IsTrue(capiProviderFollowLatest, turtlesv1.LastAppliedConfigurationTime)).To(BeTrue())
g.Expect(conditions.IsTrue(capiProviderFollowLatest, turtlesv1.CheckLatestVersionTime)).To(BeTrue())
g.Expect(capiProviderFollowLatest.Status.Conditions).To(HaveLen(2))
}, 5*time.Second).Should(Succeed())
})

It("Should not set the last applied version check, if the FollowLatest is not set", func() {
s := sync.NewProviderSync(testEnv, capiProvider)

Consistently(func(g Gomega) {
err = nil
g.Expect(s.Get(ctx)).To(Succeed())
g.Expect(s.Sync(ctx)).To(Succeed())
s.Apply(ctx, &err)
g.Expect(conditions.IsTrue(capiProvider, turtlesv1.LastAppliedConfigurationTime)).To(BeTrue())
g.Expect(capiProvider.Status.Conditions).To(HaveLen(1))
}).Should(Succeed())
})

It("Should individually sync every provider", func() {
Expect(testEnv.Client.Create(ctx, infrastructure.DeepCopy())).To(Succeed())
Eventually(UpdateStatus(infrastructure, func() {
Expand All @@ -261,9 +285,8 @@ var _ = Describe("Provider sync", func() {
g.Expect(s.Sync(ctx)).To(Succeed())
s.Apply(ctx, &err)
g.Expect(err).ToNot(HaveOccurred())
g.Expect(capiProvider.Status.Conditions).To(HaveLen(2))
g.Expect(capiProvider.Status.Conditions).To(HaveLen(1))
g.Expect(conditions.IsTrue(capiProvider, turtlesv1.LastAppliedConfigurationTime)).To(BeTrue())
g.Expect(conditions.IsTrue(capiProvider, turtlesv1.CheckLatestVersionTime)).To(BeTrue())
g.Expect(testEnv.Get(ctx, client.ObjectKeyFromObject(infrastructure), dest)).To(Succeed())
}).Should(Succeed())

Expand All @@ -278,9 +301,8 @@ var _ = Describe("Provider sync", func() {

g.Expect(testEnv.Get(ctx, client.ObjectKeyFromObject(infrastructureDuplicate), dest)).To(Succeed())
g.Expect(dest.GetAnnotations()).To(HaveKeyWithValue(sync.AppliedSpecHashAnnotation, ""))
g.Expect(capiProviderDuplicate.Status.Conditions).To(HaveLen(2))
g.Expect(capiProviderDuplicate.Status.Conditions).To(HaveLen(1))
g.Expect(conditions.IsTrue(capiProviderDuplicate, turtlesv1.LastAppliedConfigurationTime)).To(BeTrue())
g.Expect(conditions.IsTrue(capiProviderDuplicate, turtlesv1.CheckLatestVersionTime)).To(BeTrue())
g.Expect(conditions.Get(capiProviderDuplicate, turtlesv1.LastAppliedConfigurationTime).LastTransitionTime.Minute()).To(Equal(time.Now().UTC().Minute()))
}).Should(Succeed())

Expand Down

0 comments on commit 5da5166

Please sign in to comment.