diff --git a/controllers/hcloudmachine_controller_test.go b/controllers/hcloudmachine_controller_test.go index 77515d053..bbbe5553a 100644 --- a/controllers/hcloudmachine_controller_test.go +++ b/controllers/hcloudmachine_controller_test.go @@ -133,118 +133,162 @@ var _ = Describe("HCloudMachineReconciler", func() { }) Context("Basic test", func() { - BeforeEach(func() { - // remove bootstrap infos - capiMachine.Spec.Bootstrap = clusterv1.Bootstrap{} - Expect(testEnv.Create(ctx, capiMachine)).To(Succeed()) - - hcloudMachine = &infrav1.HCloudMachine{ - ObjectMeta: metav1.ObjectMeta{ - Name: hcloudMachineName, - Namespace: testNs.Name, - Labels: map[string]string{ - clusterv1.ClusterNameLabel: capiCluster.Name, - clusterv1.MachineControlPlaneNameLabel: "", - }, - OwnerReferences: []metav1.OwnerReference{ - { - APIVersion: clusterv1.GroupVersion.String(), - Kind: "Machine", - Name: capiMachine.Name, - UID: capiMachine.UID, + Context("correct server", func() { + BeforeEach(func() { + // remove bootstrap infos + capiMachine.Spec.Bootstrap = clusterv1.Bootstrap{} + Expect(testEnv.Create(ctx, capiMachine)).To(Succeed()) + + hcloudMachine = &infrav1.HCloudMachine{ + ObjectMeta: metav1.ObjectMeta{ + Name: hcloudMachineName, + Namespace: testNs.Name, + Labels: map[string]string{ + clusterv1.ClusterNameLabel: capiCluster.Name, + clusterv1.MachineControlPlaneNameLabel: "", + }, + OwnerReferences: []metav1.OwnerReference{ + { + APIVersion: clusterv1.GroupVersion.String(), + Kind: "Machine", + Name: capiMachine.Name, + UID: capiMachine.UID, + }, }, }, - }, - Spec: infrav1.HCloudMachineSpec{ - ImageName: "fedora-control-plane", - Type: "cpx31", - PlacementGroupName: &defaultPlacementGroupName, - }, - } + Spec: infrav1.HCloudMachineSpec{ + ImageName: "fedora-control-plane", + Type: "cpx31", + PlacementGroupName: &defaultPlacementGroupName, + }, + } + Expect(testEnv.Create(ctx, hcloudMachine)).To(Succeed()) + Expect(testEnv.Create(ctx, hetznerCluster)).To(Succeed()) + }) - Expect(testEnv.Create(ctx, hcloudMachine)).To(Succeed()) - Expect(testEnv.Create(ctx, hetznerCluster)).To(Succeed()) - }) + AfterEach(func() { + Expect(testEnv.Cleanup(ctx, capiMachine, hcloudMachine, hetznerCluster)).To(Succeed()) + }) - AfterEach(func() { - Expect(testEnv.Cleanup(ctx, capiMachine, hcloudMachine, hetznerCluster)).To(Succeed()) - }) + It("creates the infra machine", func() { + Eventually(func() bool { + if err := testEnv.Get(ctx, key, hcloudMachine); err != nil { + return false + } + return true + }, timeout).Should(BeTrue()) + }) - It("creates the infra machine", func() { - Eventually(func() bool { - if err := testEnv.Get(ctx, key, hcloudMachine); err != nil { - return false - } - return true - }, timeout).Should(BeTrue()) - }) + It("creates the HCloud machine in Hetzner", func() { + By("checking that no servers exist") + + Eventually(func() bool { + servers, err := hcloudClient.ListServers(ctx, hcloud.ServerListOpts{ + ListOpts: hcloud.ListOpts{ + LabelSelector: utils.LabelsToLabelSelector(map[string]string{hetznerCluster.ClusterTagKey(): "owned"}), + }, + }) + if err != nil { + return false + } - It("creates the HCloud machine in Hetzner", func() { - By("checking that no servers exist") + return len(servers) == 0 + }, timeout, time.Second).Should(BeTrue()) - Eventually(func() bool { - servers, err := hcloudClient.ListServers(ctx, hcloud.ServerListOpts{ - ListOpts: hcloud.ListOpts{ - LabelSelector: utils.LabelsToLabelSelector(map[string]string{hetznerCluster.ClusterTagKey(): "owned"}), - }, - }) - if err != nil { - return false - } + By("checking that bootstrap condition is not ready") - return len(servers) == 0 - }, timeout, time.Second).Should(BeTrue()) + Eventually(func() bool { + return isPresentAndFalseWithReason(key, hcloudMachine, infrav1.BootstrapReadyCondition, infrav1.BootstrapNotReadyReason) + }, timeout, time.Second).Should(BeTrue()) - By("checking that bootstrap condition is not ready") + By("setting the bootstrap data") - Eventually(func() bool { - return isPresentAndFalseWithReason(key, hcloudMachine, infrav1.BootstrapReadyCondition, infrav1.BootstrapNotReadyReason) - }, timeout, time.Second).Should(BeTrue()) + ph, err := patch.NewHelper(capiMachine, testEnv) + Expect(err).ShouldNot(HaveOccurred()) - By("setting the bootstrap data") + capiMachine.Spec.Bootstrap = clusterv1.Bootstrap{ + DataSecretName: ptr.To("bootstrap-secret"), + } - ph, err := patch.NewHelper(capiMachine, testEnv) - Expect(err).ShouldNot(HaveOccurred()) + Eventually(func() error { + return ph.Patch(ctx, capiMachine, patch.WithStatusObservedGeneration{}) + }, timeout, time.Second).Should(BeNil()) - capiMachine.Spec.Bootstrap = clusterv1.Bootstrap{ - DataSecretName: ptr.To("bootstrap-secret"), - } + By("checking that bootstrap condition is ready") - Eventually(func() error { - return ph.Patch(ctx, capiMachine, patch.WithStatusObservedGeneration{}) - }, timeout, time.Second).Should(BeNil()) + Eventually(func() bool { + return isPresentAndTrue(key, hcloudMachine, infrav1.BootstrapReadyCondition) + }, timeout, time.Second).Should(BeTrue()) - By("checking that bootstrap condition is ready") + By("listing hcloud servers") - Eventually(func() bool { - return isPresentAndTrue(key, hcloudMachine, infrav1.BootstrapReadyCondition) - }, timeout, time.Second).Should(BeTrue()) + Eventually(func() int { + servers, err := hcloudClient.ListServers(ctx, hcloud.ServerListOpts{ + ListOpts: hcloud.ListOpts{ + LabelSelector: utils.LabelsToLabelSelector(map[string]string{hetznerCluster.ClusterTagKey(): "owned"}), + }, + }) + if err != nil { + return 0 + } + return len(servers) + }, timeout, time.Second).Should(BeNumerically(">", 0)) - By("listing hcloud servers") + By("checking if server created condition is set") + + Eventually(func() bool { + return isPresentAndTrue(key, hcloudMachine, infrav1.ServerCreateSucceededCondition) + }, timeout, time.Second).Should(BeTrue()) - Eventually(func() int { - servers, err := hcloudClient.ListServers(ctx, hcloud.ServerListOpts{ - ListOpts: hcloud.ListOpts{ - LabelSelector: utils.LabelsToLabelSelector(map[string]string{hetznerCluster.ClusterTagKey(): "owned"}), + By("checking if server available condition is set") + + Eventually(func() bool { + return isPresentAndTrue(key, hcloudMachine, infrav1.ServerAvailableCondition) + }, timeout, time.Second).Should(BeTrue()) + }) + }) + + Context("wrong server", func() { + BeforeEach(func() { + Expect(testEnv.Create(ctx, capiMachine)).To(Succeed()) + + hcloudMachine = &infrav1.HCloudMachine{ + ObjectMeta: metav1.ObjectMeta{ + Name: hcloudMachineName, + Namespace: testNs.Name, + Labels: map[string]string{ + clusterv1.ClusterNameLabel: capiCluster.Name, + clusterv1.MachineControlPlaneNameLabel: "", + }, + OwnerReferences: []metav1.OwnerReference{ + { + APIVersion: clusterv1.GroupVersion.String(), + Kind: "Machine", + Name: capiMachine.Name, + UID: capiMachine.UID, + }, + }, + }, + Spec: infrav1.HCloudMachineSpec{ + ImageName: "fedora-control-plane-2", + Type: "cpx31", + PlacementGroupName: &defaultPlacementGroupName, }, - }) - if err != nil { - return 0 } - return len(servers) - }, timeout, time.Second).Should(BeNumerically(">", 0)) - - By("checking if server created condition is set") + Expect(testEnv.Create(ctx, hcloudMachine)).To(Succeed()) - Eventually(func() bool { - return isPresentAndTrue(key, hcloudMachine, infrav1.ServerCreateSucceededCondition) - }, timeout, time.Second).Should(BeTrue()) + Expect(testEnv.Create(ctx, hetznerCluster)).To(Succeed()) + }) - By("checking if server available condition is set") + AfterEach(func() { + Expect(testEnv.Cleanup(ctx, hcloudMachine, hetznerCluster)).To(Succeed()) + }) - Eventually(func() bool { - return isPresentAndTrue(key, hcloudMachine, infrav1.ServerAvailableCondition) - }, timeout, time.Second).Should(BeTrue()) + It("checks that ImageNotFound is visible in conditions if image does not exist", func() { + Eventually(func() bool { + return isPresentAndFalseWithReason(key, hcloudMachine, infrav1.ServerCreateSucceededCondition, infrav1.ImageNotFoundReason) + }, timeout, time.Second).Should(BeTrue()) + }) }) }) diff --git a/pkg/services/hcloud/client/fake/hcloud_client.go b/pkg/services/hcloud/client/fake/hcloud_client.go index 4a0b88a7c..fc17bcfca 100644 --- a/pkg/services/hcloud/client/fake/hcloud_client.go +++ b/pkg/services/hcloud/client/fake/hcloud_client.go @@ -143,8 +143,11 @@ var defaultSSHKey = hcloud.SSHKey{ } var defaultImage = hcloud.Image{ - ID: 42, - Name: "myimage", + ID: 42, + Labels: map[string]string{ + "caph-image-name": "fedora-control-plane", + }, + Name: "fedora-control-plane", } func (c *cacheHCloudClient) CreateLoadBalancer(_ context.Context, opts hcloud.LoadBalancerCreateOpts) (*hcloud.LoadBalancer, error) { @@ -420,7 +423,24 @@ func (c *cacheHCloudClient) ListImages(_ context.Context, opts hcloud.ImageListO if opts.Name != "" { return nil, nil } - return []*hcloud.Image{&defaultImage}, nil + + labels, err := utils.LabelSelectorToLabels(opts.LabelSelector) + if err != nil { + return nil, fmt.Errorf("failed to convert label selector to labels: %w", err) + } + + allLabelsFound := true + for key, label := range labels { + if val, found := defaultImage.Labels[key]; !found || val != label { + allLabelsFound = false + break + } + } + if allLabelsFound { + return []*hcloud.Image{&defaultImage}, nil + } + + return nil, nil } func (c *cacheHCloudClient) CreateServer(_ context.Context, opts hcloud.ServerCreateOpts) (*hcloud.Server, error) { diff --git a/pkg/services/hcloud/client/fake/hcloud_client_test.go b/pkg/services/hcloud/client/fake/hcloud_client_test.go index 4c582d330..f9e13c157 100644 --- a/pkg/services/hcloud/client/fake/hcloud_client_test.go +++ b/pkg/services/hcloud/client/fake/hcloud_client_test.go @@ -426,7 +426,7 @@ var _ = Describe("Load balancer", func() { var listOpts hcloud.ImageListOpts client := factory.NewClient("") BeforeEach(func() { - listOpts.LabelSelector = labelSelector + listOpts.LabelSelector = "caph-image-name==fedora-control-plane" }) It("lists at least one image", func() { resp, err := client.ListImages(ctx, listOpts)