@@ -18,13 +18,15 @@ package controller
1818
1919import (
2020 "context"
21+ "net/http"
2122
2223 . "github.com/onsi/ginkgo/v2"
2324 . "github.com/onsi/gomega"
2425 . "github.com/onsi/gomega/gstruct"
2526 "github.com/stretchr/testify/mock"
2627 "k8s.io/apimachinery/pkg/types"
2728 "k8s.io/utils/ptr"
29+ "sigs.k8s.io/controller-runtime/pkg/client"
2830 "sigs.k8s.io/controller-runtime/pkg/reconcile"
2931
3032 corev1 "k8s.io/api/core/v1"
@@ -36,6 +38,7 @@ import (
3638 metalnetwork "github.com/metal-stack/metal-go/api/client/network"
3739 "github.com/metal-stack/metal-go/api/models"
3840 metalgoclient "github.com/metal-stack/metal-go/test/client"
41+ "github.com/metal-stack/metal-lib/httperrors"
3942 "github.com/metal-stack/metal-lib/pkg/pointer"
4043 "github.com/metal-stack/metal-lib/pkg/testcommon"
4144
@@ -270,6 +273,17 @@ var _ = Describe("MetalStackCluster Controller", func() {
270273 "Type" : Equal (v1alpha1 .ClusterControlPlaneEndpointEnsured ),
271274 "Status" : Equal (corev1 .ConditionTrue ),
272275 })))
276+
277+ By ("ssh keypair generation" )
278+ sshSecret := & corev1.Secret {
279+ ObjectMeta : metav1.ObjectMeta {
280+ Name : owner .Name + "-ssh-keypair" ,
281+ Namespace : resource .Namespace ,
282+ },
283+ }
284+ Expect (k8sClient .Get (ctx , client .ObjectKeyFromObject (sshSecret ), sshSecret )).NotTo (HaveOccurred ())
285+ Expect (sshSecret .Data ).To (HaveKey ("id_rsa" ))
286+ Expect (sshSecret .Data ).To (HaveKey ("id_rsa.pub" ))
273287 })
274288 })
275289 Context ("reconciliation when external resources are provided" , func () {
@@ -377,111 +391,76 @@ var _ = Describe("MetalStackCluster Controller", func() {
377391
378392 When ("referenced resources do not exist" , func () {
379393 It ("should fail reconciling" , func () {
394+ Expect (k8sClient .Create (ctx , resource )).To (Succeed ())
380395
381- })
382- })
383- })
384-
385- Context ("When reconciling a MetalStackCluster resource" , func () {
386- // const resourceName = "test-resource"
387-
388- // var (
389- // ctx = context.Background()
390-
391- // resource *infrastructurev1alpha1.MetalStackCluster
392- // typeNamespacedName = types.NamespacedName{
393- // Name: resourceName,
394- // Namespace: "default",
395- // }
396- // metalstackcluster = &infrastructurev1alpha1.MetalStackCluster{}
397- // )
398-
399- // BeforeEach(func() {
400- // resource = &infrastructurev1alpha1.MetalStackCluster{
401- // ObjectMeta: metav1.ObjectMeta{
402- // Name: resourceName,
403- // Namespace: "default",
404- // },
405- // Spec: infrastructurev1alpha1.MetalStackClusterSpec{
406- // ControlPlaneEndpoint: infrastructurev1alpha1.APIEndpoint{},
407- // ProjectID: "test-project",
408- // NodeNetworkID: nil,
409- // ControlPlaneIP: nil,
410- // Partition: "test-partition",
411- // Firewall: &infrastructurev1alpha1.Firewall{},
412- // },
413- // }
414-
415- // By("creating the custom resource for the Kind MetalStackCluster")
416- // err := k8sClient.Get(ctx, typeNamespacedName, metalstackcluster)
417- // if err != nil && errors.IsNotFound(err) {
418- // Expect(k8sClient.Create(ctx, resource)).To(Succeed())
419- // }
420- // })
421-
422- // AfterEach(func() {
423- // resource := &infrastructurev1alpha1.MetalStackCluster{}
424- // err := k8sClient.Get(ctx, typeNamespacedName, resource)
425- // Expect(err).NotTo(HaveOccurred())
426-
427- // By("Cleanup the specific resource instance MetalStackCluster")
428- // Expect(k8sClient.Delete(ctx, resource)).To(Succeed())
429- // })
430-
431- // it should not do anything when the resource has no ownership yet
432-
433- // it should reconcile successfully when the resource gets an ownership
434-
435- // it automatically allocates dependent resources
436-
437- // it should generate an SSH secret
438- // it should allocate a node network
439- // it should allocate a control plane ip
440- // it should ensure a firewall deployment
441-
442- // it is idempotent!
443- // status conditions should be properly evaluated
444-
445- // it is possible to optionally provide control plane ip, node network id and firewall
446-
447- // it should delete the resource
448-
449- // it should delete all managed resources
450-
451- // it should not delete optionally provided resources
452-
453- // Context("should successfully reconcile the resource", Ordered, func() {
454- // It("should not do anything when the resource has no ownership yet", func() {
455-
456- // })
457-
458- // By("setting an ownership ownership yet")
459-
460- // It("it should reconcile successfully", func() {
396+ By ("creating the cluster resource and setting the owner reference" )
397+ owner := & clusterv1beta1.Cluster {
398+ ObjectMeta : metav1.ObjectMeta {
399+ GenerateName : "owner-" ,
400+ Namespace : "default" ,
401+ },
402+ }
403+ Expect (k8sClient .Create (ctx , owner )).To (Succeed ())
461404
462- // })
405+ resource .OwnerReferences = []metav1.OwnerReference {
406+ * metav1 .NewControllerRef (owner , clusterv1beta1 .GroupVersion .WithKind ("Cluster" )),
407+ }
408+ Expect (k8sClient .Update (ctx , resource )).To (Succeed ())
463409
464- // It("it should automatically allocate dependent resources", func() {
465- // // it should generate an SSH secret
466- // // it should allocate a node network
467- // // it should allocate a control plane ip
468- // // it should ensure a firewall deployment
469- // })
470- // })
471- // controllerReconciler := &MetalStackClusterReconciler{
472- // Client: k8sClient,
473- // Scheme: k8sClient.Scheme(),
474- // }
410+ By ("reconciling the resource" )
475411
476- // _, err := controllerReconciler.Reconcile(ctx, reconcile.Request {
477- // NamespacedName: typeNamespacedName ,
478- // })
479- // Expect(err).NotTo(HaveOccurred())
412+ typeNamespacedName := types. NamespacedName {
413+ Name : resource . Name ,
414+ Namespace : "default" ,
415+ }
480416
481- // resource := &infrastructurev1alpha1.MetalStackCluster{}
482- // err = k8sClient.Get(ctx, typeNamespacedName, resource)
483- // Expect(err).NotTo(HaveOccurred())
417+ controllerReconciler .MetalClient , _ = metalgoclient .NewMetalMockClient (testingT , & metalgoclient.MetalMockFns {
418+ IP : func (m * mock.Mock ) {
419+ m .On ("FindIP" , testcommon .MatchIgnoreContext (testingT , metalip .NewFindIPParams ().WithID (controlPlaneIP )), nil ).
420+ Return (nil , & metalip.FindIPDefault {
421+ Payload : & httperrors.HTTPErrorResponse {
422+ StatusCode : http .StatusNotFound ,
423+ Message : "ip not found" ,
424+ },
425+ })
426+ },
427+ Network : func (m * mock.Mock ) {
428+ m .On ("FindNetwork" , testcommon .MatchIgnoreContext (testingT , metalnetwork .NewFindNetworkParams ().WithID (nodeNetworkID )), nil ).
429+ Return (nil , & metalnetwork.FindNetworkDefault {
430+ Payload : & httperrors.HTTPErrorResponse {
431+ StatusCode : http .StatusNotFound ,
432+ Message : "network not found" ,
433+ },
434+ })
435+ },
436+ })
484437
485- // Expect(resource.Status.Conditions).To(ContainElement("bla"))
438+ Eventually (func () error {
439+ _ , err := controllerReconciler .Reconcile (ctx , reconcile.Request {
440+ NamespacedName : typeNamespacedName ,
441+ })
442+ return err
443+ }).Should (MatchError (ContainSubstring ("not found" )))
444+
445+ Expect (k8sClient .Get (ctx , typeNamespacedName , resource )).ToNot (HaveOccurred ())
446+
447+ Expect (resource .Status .Conditions ).To (ContainElement (MatchFields (IgnoreExtras , Fields {
448+ "Type" : Equal (v1alpha1 .ClusterNodeNetworkEnsured ),
449+ "Status" : Equal (corev1 .ConditionFalse ),
450+ "Reason" : Equal ("InternalError" ),
451+ "Message" : ContainSubstring ("network not found" ),
452+ })))
453+ Expect (resource .Status .Conditions ).To (ContainElement (MatchFields (IgnoreExtras , Fields {
454+ "Type" : Equal (v1alpha1 .ClusterFirewallDeploymentReady ),
455+ "Status" : Equal (corev1 .ConditionTrue ),
456+ })))
457+ Expect (resource .Status .Conditions ).To (ContainElement (MatchFields (IgnoreExtras , Fields {
458+ "Type" : Equal (v1alpha1 .ClusterControlPlaneEndpointEnsured ),
459+ "Status" : Equal (corev1 .ConditionFalse ),
460+ "Reason" : Equal ("InternalError" ),
461+ "Message" : ContainSubstring ("ip not found" ),
462+ })))
463+ })
464+ })
486465 })
487466})
0 commit comments