github.com/kotalco/kotal@v0.3.0/controllers/ethereum2/beacon_node_controller_test.go (about)

     1  package controllers
     2  
     3  import (
     4  	"context"
     5  	"fmt"
     6  	"os"
     7  	"time"
     8  
     9  	appsv1 "k8s.io/api/apps/v1"
    10  	corev1 "k8s.io/api/core/v1"
    11  	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
    12  
    13  	"k8s.io/apimachinery/pkg/api/resource"
    14  	"k8s.io/apimachinery/pkg/types"
    15  	"k8s.io/apimachinery/pkg/util/intstr"
    16  
    17  	ethereum2v1alpha1 "github.com/kotalco/kotal/apis/ethereum2/v1alpha1"
    18  	"github.com/kotalco/kotal/controllers/shared"
    19  
    20  	. "github.com/onsi/ginkgo/v2"
    21  	. "github.com/onsi/gomega"
    22  	"github.com/onsi/gomega/gstruct"
    23  )
    24  
    25  var _ = Describe("Ethereum 2.0 beacon node", func() {
    26  
    27  	Context("Joining Mainnet", func() {
    28  		ns := &corev1.Namespace{
    29  			ObjectMeta: metav1.ObjectMeta{
    30  				Name: "beacon-node",
    31  			},
    32  		}
    33  
    34  		key := types.NamespacedName{
    35  			Name:      "my-node",
    36  			Namespace: ns.Name,
    37  		}
    38  
    39  		testImage := "kotalco/teku:controller-test"
    40  
    41  		spec := ethereum2v1alpha1.BeaconNodeSpec{
    42  			Image:   testImage,
    43  			Client:  ethereum2v1alpha1.TekuClient,
    44  			Network: "mainnet",
    45  		}
    46  
    47  		toCreate := &ethereum2v1alpha1.BeaconNode{
    48  			ObjectMeta: metav1.ObjectMeta{
    49  				Name:      key.Name,
    50  				Namespace: key.Namespace,
    51  			},
    52  			Spec: spec,
    53  		}
    54  
    55  		t := true
    56  
    57  		nodeOwnerReference := metav1.OwnerReference{
    58  			APIVersion:         "ethereum2.kotal.io/v1alpha1",
    59  			Kind:               "BeaconNode",
    60  			Name:               toCreate.Name,
    61  			Controller:         &t,
    62  			BlockOwnerDeletion: &t,
    63  		}
    64  
    65  		It(fmt.Sprintf("Should create %s namespace", ns.Name), func() {
    66  			Expect(k8sClient.Create(context.TODO(), ns))
    67  		})
    68  
    69  		It("Should create beacon node", func() {
    70  			if os.Getenv(shared.EnvUseExistingCluster) != "true" {
    71  				toCreate.Default()
    72  			}
    73  			Expect(k8sClient.Create(context.Background(), toCreate)).Should(Succeed())
    74  		})
    75  
    76  		It("should get beacon node", func() {
    77  			fetched := &ethereum2v1alpha1.BeaconNode{}
    78  			Expect(k8sClient.Get(context.Background(), key, fetched)).To(Succeed())
    79  			Expect(fetched.Spec).To(Equal(toCreate.Spec))
    80  			nodeOwnerReference.UID = fetched.GetUID()
    81  			time.Sleep(5 * time.Second)
    82  		})
    83  
    84  		It("Should create statefulset with correct arguments", func() {
    85  			nodeSts := &appsv1.StatefulSet{}
    86  
    87  			Expect(k8sClient.Get(context.Background(), key, nodeSts)).To(Succeed())
    88  			Expect(nodeSts.GetOwnerReferences()).To(ContainElement(nodeOwnerReference))
    89  			Expect(*nodeSts.Spec.Template.Spec.SecurityContext).To(gstruct.MatchFields(gstruct.IgnoreExtras, gstruct.Fields{
    90  				"RunAsUser":    gstruct.PointTo(Equal(int64(1000))),
    91  				"RunAsGroup":   gstruct.PointTo(Equal(int64(3000))),
    92  				"FSGroup":      gstruct.PointTo(Equal(int64(2000))),
    93  				"RunAsNonRoot": gstruct.PointTo(Equal(true)),
    94  			}))
    95  			Expect(nodeSts.Spec.Template.Spec.Containers[0].Image).To(Equal(testImage))
    96  		})
    97  
    98  		It("Should allocate correct resources to bootnode statefulset", func() {
    99  			nodeSts := &appsv1.StatefulSet{}
   100  			expectedResources := corev1.ResourceRequirements{
   101  				Requests: corev1.ResourceList{
   102  					corev1.ResourceCPU:    resource.MustParse(ethereum2v1alpha1.DefaultCPURequest),
   103  					corev1.ResourceMemory: resource.MustParse(ethereum2v1alpha1.DefaultMemoryRequest),
   104  				},
   105  				Limits: corev1.ResourceList{
   106  					corev1.ResourceCPU:    resource.MustParse(ethereum2v1alpha1.DefaultCPULimit),
   107  					corev1.ResourceMemory: resource.MustParse(ethereum2v1alpha1.DefaultMemoryLimit),
   108  				},
   109  			}
   110  			Expect(k8sClient.Get(context.Background(), key, nodeSts)).To(Succeed())
   111  			Expect(nodeSts.Spec.Template.Spec.Containers[0].Resources).To(Equal(expectedResources))
   112  		})
   113  
   114  		It("Should create data persistent volume with correct resources", func() {
   115  			nodePVC := &corev1.PersistentVolumeClaim{}
   116  			expectedResources := corev1.VolumeResourceRequirements{
   117  				Requests: corev1.ResourceList{
   118  					corev1.ResourceStorage: resource.MustParse(ethereum2v1alpha1.DefaultStorage),
   119  				},
   120  			}
   121  			Expect(k8sClient.Get(context.Background(), key, nodePVC)).To(Succeed())
   122  			Expect(nodePVC.GetOwnerReferences()).To(ContainElement(nodeOwnerReference))
   123  			Expect(nodePVC.Spec.Resources).To(Equal(expectedResources))
   124  		})
   125  
   126  		It("Should create node service", func() {
   127  			nodeSVC := &corev1.Service{}
   128  			Expect(k8sClient.Get(context.Background(), key, nodeSVC)).To(Succeed())
   129  			Expect(nodeSVC.GetOwnerReferences()).To(ContainElement(nodeOwnerReference))
   130  			Expect(nodeSVC.Spec.Ports).To(ContainElements([]corev1.ServicePort{
   131  				{
   132  					Name:       "discovery",
   133  					Port:       int32(ethereum2v1alpha1.DefaultP2PPort),
   134  					TargetPort: intstr.FromString("discovery"),
   135  					Protocol:   corev1.ProtocolUDP,
   136  				},
   137  				{
   138  					Name:       "p2p",
   139  					Port:       int32(ethereum2v1alpha1.DefaultP2PPort),
   140  					TargetPort: intstr.FromString("p2p"),
   141  					Protocol:   corev1.ProtocolTCP,
   142  				},
   143  			}))
   144  		})
   145  
   146  		It(fmt.Sprintf("Should delete %s namespace", ns.Name), func() {
   147  			Expect(k8sClient.Delete(context.Background(), ns)).To(Succeed())
   148  		})
   149  
   150  	})
   151  })