Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

🐛 Provider re apply tests #422

Merged
merged 1 commit into from
Mar 12, 2024
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
4 changes: 1 addition & 3 deletions internal/controllers/capiprovider_controller_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -17,8 +17,6 @@ limitations under the License.
package controllers

import (
"time"

. "github.com/onsi/ginkgo/v2"
. "github.com/onsi/gomega"

Expand Down Expand Up @@ -147,7 +145,7 @@ var _ = Describe("Reconcile CAPIProvider", func() {
}
})).Should(Succeed())

Eventually(Object(doSecret), 10*time.Second).Should(HaveField("Data", Equal(map[string][]byte{
Eventually(Object(doSecret)).Should(HaveField("Data", Equal(map[string][]byte{
"EXP_MACHINE_POOL": []byte("true"),
"CLUSTER_TOPOLOGY": []byte("false"),
"EXP_CLUSTER_RESOURCE_SET": []byte("false"),
Expand Down
34 changes: 18 additions & 16 deletions internal/controllers/patch_kcfg_controller_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -150,27 +150,29 @@ var _ = Describe("Patch Rancher v2Prov Kubeconfig secrets", func() {
}
Expect(cl.Create(ctx, kubeconfigSecret)).To(Succeed())

_, err := r.Reconcile(ctx, reconcile.Request{
NamespacedName: types.NamespacedName{
Namespace: kubeconfigSecret.Namespace,
Name: kubeconfigSecret.Name,
},
})
Expect(err).NotTo(HaveOccurred())
Eventually(func(g Gomega) {
_, err := r.Reconcile(ctx, reconcile.Request{
NamespacedName: types.NamespacedName{
Namespace: kubeconfigSecret.Namespace,
Name: kubeconfigSecret.Name,
},
})
g.Expect(err).NotTo(HaveOccurred())

updatedSecret := &corev1.Secret{}

updatedSecret := &corev1.Secret{}
Eventually(ctx, func(g Gomega) {
g.Expect(cl.Get(ctx, client.ObjectKeyFromObject(kubeconfigSecret), updatedSecret)).ToNot(HaveOccurred())
g.Expect(updatedSecret.GetLabels()).To(HaveLen(2))
}).Should(Succeed())

labvelVal, labelFound := updatedSecret.Labels["cluster.x-k8s.io/cluster-name"]
Expect(labelFound).To(BeTrue(), "Failed to find expected CAPI label")
Expect(labvelVal).To(Equal(clusterName))
labvelVal, labelFound := updatedSecret.Labels["cluster.x-k8s.io/cluster-name"]
g.Expect(labelFound).To(BeTrue(), "Failed to find expected CAPI label")
g.Expect(labvelVal).To(Equal(clusterName))

labvelVal, labelFound = updatedSecret.Labels["existing"]
g.Expect(labelFound).To(BeTrue(), "Failed to find existing label")
g.Expect(labvelVal).To(Equal("myvalue"))
}).Should(Succeed())

labvelVal, labelFound = updatedSecret.Labels["existing"]
Expect(labelFound).To(BeTrue(), "Failed to find existing label")
Expect(labvelVal).To(Equal("myvalue"))
})

It("should not add a label to a non-v2prov secret", func() {
Expand Down
17 changes: 14 additions & 3 deletions internal/sync/provider_sync.go
Original file line number Diff line number Diff line change
Expand Up @@ -101,8 +101,17 @@ func (s *ProviderSync) Sync(_ context.Context) error {
// CAPIProvider <- Status.
func (s *ProviderSync) SyncObjects() {
s.Destination.SetSpec(s.Source.GetSpec())
s.rolloutInfrastructure()

oldConditions := s.Source.Status.Conditions.DeepCopy()
newConditions := s.Destination.GetConditions().DeepCopy()
s.Source.SetStatus(s.Destination.GetStatus())
s.Source.Status.Conditions = oldConditions

for _, condition := range newConditions {
condition := condition
conditions.Set(s.Source, &condition)
}

s.syncStatus()
}

Expand All @@ -116,11 +125,11 @@ func (s *ProviderSync) syncStatus() {
s.Source.SetPhase(turtlesv1.Provisioning)
}

conditions.MarkTrue(s.Source, turtlesv1.LastAppliedConfigurationTime)
s.rolloutInfrastructure()
}

func (s *ProviderSync) rolloutInfrastructure() {
now := time.Now()
now := time.Now().UTC()
lastApplied := conditions.Get(s.Source, turtlesv1.LastAppliedConfigurationTime)

if lastApplied != nil && lastApplied.LastTransitionTime.Add(time.Minute).After(now) {
Expand All @@ -137,4 +146,6 @@ func (s *ProviderSync) rolloutInfrastructure() {

annotations[AppliedSpecHashAnnotation] = ""
s.Destination.SetAnnotations(annotations)

conditions.MarkTrue(s.Source, turtlesv1.LastAppliedConfigurationTime)
}
71 changes: 44 additions & 27 deletions internal/sync/provider_sync_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -107,7 +107,7 @@ var _ = Describe("Provider sync", func() {
HaveField("Spec.ProviderSpec", Equal(capiProvider.Spec.ProviderSpec)))
})

It("Should sync status up", func() {
It("Should sync status up and set provisioning state", func() {
Expect(testEnv.Client.Create(ctx, infrastructure.DeepCopy())).To(Succeed())
Eventually(UpdateStatus(infrastructure, func() {
infrastructure.Status = operatorv1.InfrastructureProviderStatus{
Expand All @@ -119,49 +119,58 @@ var _ = Describe("Provider sync", func() {

s := sync.NewProviderSync(testEnv, capiProvider)

Eventually(func(g Gomega) (err error) {
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(capiProvider.Status.Conditions).To(HaveLen(1))
g.Expect(capiProvider).To(HaveField("Status.Phase", Equal(turtlesv1.Provisioning)))
return
}).Should(Succeed())
})

It("Should update outdated condition and empty the hash annotation", func() {
It("Should update outdated condition, maintain last applied time and empty the hash annotation", func() {
capiProvider.Status.ProviderStatus = infrastructureStatusOutdated
appliedCondition := conditions.Get(capiProvider, turtlesv1.LastAppliedConfigurationTime)
Eventually(testEnv.Status().Update(ctx, capiProvider)).Should(Succeed())
Eventually(testEnv.Get(ctx, client.ObjectKeyFromObject(capiProvider), capiProvider)).Should(Succeed())
Expect(conditions.Get(capiProvider, turtlesv1.LastAppliedConfigurationTime)).ToNot(BeNil())
Expect(conditions.Get(capiProvider, turtlesv1.LastAppliedConfigurationTime).LastTransitionTime.Second()).To(Equal(appliedCondition.LastTransitionTime.Second()))
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()))
})

s := sync.NewProviderSync(testEnv, capiProvider)

dest := &operatorv1.InfrastructureProvider{}
Eventually(func(g Gomega) (err error) {
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(err).ToNot(HaveOccurred())

return testEnv.Get(ctx, client.ObjectKeyFromObject(infrastructure), dest)
}).Should(Succeed())

Eventually(testEnv.GetAs(infrastructure, dest)).Should(HaveField("Annotations", HaveKeyWithValue(sync.AppliedSpecHashAnnotation, "")))
Eventually(func(g Gomega) {
g.Expect(testEnv.GetAs(infrastructure, dest)).ToNot(BeNil())
g.Expect(conditions.IsTrue(capiProvider, turtlesv1.LastAppliedConfigurationTime)).To(BeTrue())
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(1))
g.Expect(capiProvider).To(HaveField("Status.Phase", Equal(turtlesv1.Provisioning)))
g.Expect(conditions.IsTrue(capiProvider, turtlesv1.LastAppliedConfigurationTime)).To(BeTrue())
g.Expect(conditions.Get(capiProvider, turtlesv1.LastAppliedConfigurationTime).LastTransitionTime.After(
appliedCondition.LastTransitionTime.Time)).To(BeTrue())
}).Should(Succeed())

condition := conditions.Get(capiProvider, turtlesv1.LastAppliedConfigurationTime)

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))
}, 5*time.Second)
})

PIt("Should individually sync every provider", func() {
It("Should individually sync every provider", func() {
Expect(testEnv.Client.Create(ctx, infrastructure.DeepCopy())).To(Succeed())
Eventually(UpdateStatus(infrastructure, func() {
infrastructure.Status = operatorv1.InfrastructureProviderStatus{
Expand All @@ -174,35 +183,43 @@ var _ = Describe("Provider sync", func() {
s := sync.NewProviderSync(testEnv, capiProvider)

dest := &operatorv1.InfrastructureProvider{}
Eventually(func(g Gomega) (err error) {
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(err).ToNot(HaveOccurred())
g.Expect(conditions.IsTrue(capiProvider, turtlesv1.LastAppliedConfigurationTime)).To(BeTrue())
g.Expect(capiProvider.Status.Conditions).To(HaveLen(1))
g.Expect(capiProvider).To(HaveField("Status.Phase", Equal(turtlesv1.Provisioning)))

return
g.Expect(testEnv.Get(ctx, client.ObjectKeyFromObject(infrastructure), dest)).To(Succeed())
}).Should(Succeed())

Eventually(testEnv.GetAs(infrastructure, &operatorv1.InfrastructureProvider{}), 10*time.Second).Should(HaveField("Annotations", HaveKeyWithValue(sync.AppliedSpecHashAnnotation, "")))

s = sync.NewProviderSync(testEnv, capiProviderDuplicate)

Eventually(func(g Gomega) (err error) {
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(err).ToNot(HaveOccurred())

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

// Provider manifest should be created and phase set to provisioning
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(err).ToNot(HaveOccurred())

g.Expect(capiProviderDuplicate).To(HaveField("Status.Phase", Equal(turtlesv1.Provisioning)))
g.Expect(capiProviderDuplicate).To(HaveField("Status.ProviderStatus.InstalledVersion", BeNil()))
return
}).Should(Succeed())
})
})
22 changes: 12 additions & 10 deletions internal/sync/secret_mapper_sync_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -186,10 +186,11 @@ var _ = Describe("SecretMapperSync get", func() {
RancherSecret: sync.SecretMapperSync{}.GetSecret(capiProviderWithRancherRef),
}

err := syncer.Get(context.Background())
Expect(err).NotTo(HaveOccurred())
Expect(syncer.RancherSecret.Name).To(Equal(customRancherSecret.Name))
Expect(syncer.RancherSecret.Namespace).To(Equal(customRancherSecret.Namespace))
Eventually(func(g Gomega) {
g.Expect(syncer.Get(context.Background())).NotTo(HaveOccurred())
g.Expect(syncer.RancherSecret.Name).To(Equal(customRancherSecret.Name))
g.Expect(syncer.RancherSecret.Namespace).To(Equal(customRancherSecret.Namespace))
})
})

It("should handle unexisting secret pointer by ref", func() {
Expand All @@ -204,12 +205,13 @@ var _ = Describe("SecretMapperSync get", func() {
RancherSecret: sync.SecretMapperSync{}.GetSecret(capiProviderWithRancherRef),
}

err := syncer.Get(context.Background())
Expect(err).To(HaveOccurred())
Expect(err.Error()).To(ContainSubstring("unable to locate rancher secret with name"))
Expect(conditions.Get(syncer.Source, turtlesv1.RancherCredentialsSecretCondition)).ToNot(BeNil())
Expect(conditions.IsFalse(syncer.Source, turtlesv1.RancherCredentialsSecretCondition)).To(BeTrue())
Expect(conditions.GetMessage(syncer.Source, turtlesv1.RancherCredentialsSecretCondition)).To(Equal(fmt.Sprintf("Rancher Credentials secret named %s:secret-name was not located", ns.Name)))
Eventually(func(g Gomega) {
g.Expect(syncer.Get(context.Background())).NotTo(HaveOccurred())
g.Expect(err.Error()).To(ContainSubstring("unable to locate rancher secret with name"))
g.Expect(conditions.Get(syncer.Source, turtlesv1.RancherCredentialsSecretCondition)).ToNot(BeNil())
g.Expect(conditions.IsFalse(syncer.Source, turtlesv1.RancherCredentialsSecretCondition)).To(BeTrue())
g.Expect(conditions.GetMessage(syncer.Source, turtlesv1.RancherCredentialsSecretCondition)).To(Equal(fmt.Sprintf("Rancher Credentials secret named %s:secret-name was not located", ns.Name)))
})
})

It("should handle when the source Rancher secret is not found", func() {
Expand Down
2 changes: 1 addition & 1 deletion main.go
Original file line number Diff line number Diff line change
Expand Up @@ -108,7 +108,7 @@ func initFlags(fs *pflag.FlagSet) {
fs.StringVar(&profilerAddress, "profiler-address", "",
"Bind address to expose the pprof profiler (e.g. localhost:6060)")

fs.DurationVar(&syncPeriod, "sync-period", 10*time.Minute,
fs.DurationVar(&syncPeriod, "sync-period", 2*time.Minute,
"The minimum interval at which watched resources are reconciled (e.g. 15m)")

fs.StringVar(&healthAddr, "health-addr", ":9440",
Expand Down
Loading