github.com/kotalco/kotal@v0.3.0/controllers/ipfs/cluster_peer_controller_test.go (about) 1 package controllers 2 3 import ( 4 "context" 5 "fmt" 6 "os" 7 "strings" 8 "time" 9 10 . "github.com/onsi/ginkgo/v2" 11 . "github.com/onsi/gomega" 12 "github.com/onsi/gomega/gstruct" 13 14 ipfsv1alpha1 "github.com/kotalco/kotal/apis/ipfs/v1alpha1" 15 ipfsClients "github.com/kotalco/kotal/clients/ipfs" 16 "github.com/kotalco/kotal/controllers/shared" 17 18 appsv1 "k8s.io/api/apps/v1" 19 corev1 "k8s.io/api/core/v1" 20 "k8s.io/apimachinery/pkg/api/resource" 21 metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" 22 "k8s.io/apimachinery/pkg/types" 23 "k8s.io/apimachinery/pkg/util/intstr" 24 ) 25 26 var _ = Describe("IPFS cluster peer controller", func() { 27 ns := &corev1.Namespace{ 28 ObjectMeta: metav1.ObjectMeta{ 29 Name: "ipfs-cluster-peer", 30 }, 31 } 32 33 key := types.NamespacedName{ 34 Name: "my-cluster-peer", 35 Namespace: ns.Name, 36 } 37 38 image := "kotalco/ipfs-cluster:test" 39 40 spec := ipfsv1alpha1.ClusterPeerSpec{ 41 Image: image, 42 ID: "12D3KooWBcEtY8GH4mNkri9kM3haeWhEXtQV7mi81ErWrqLYGuiq", 43 PrivateKeySecretName: "cluster-privatekey", 44 ClusterSecretName: "cluster-secret", 45 Consensus: ipfsv1alpha1.CRDT, 46 TrustedPeers: []string{ 47 "12D3KooWBcEtY8GH4mNkri9kM3haeWhEXtQV7mi81ErWrqLYGuiq", 48 "12D3KooWQ9yZnqowEDme3gSgS45KY9ZoEmAiGYRxusdEaqtFa9pr", 49 }, 50 PeerEndpoint: "/dns4/ipfs-peer/tcp/5001", 51 } 52 53 toCreate := &ipfsv1alpha1.ClusterPeer{ 54 ObjectMeta: metav1.ObjectMeta{ 55 Name: key.Name, 56 Namespace: key.Namespace, 57 }, 58 Spec: spec, 59 } 60 61 t := true 62 63 peerOwnerReference := metav1.OwnerReference{ 64 APIVersion: "ipfs.kotal.io/v1alpha1", 65 Kind: "ClusterPeer", 66 Name: toCreate.Name, 67 Controller: &t, 68 BlockOwnerDeletion: &t, 69 } 70 71 It(fmt.Sprintf("Should create %s namespace", ns.Name), func() { 72 Expect(k8sClient.Create(context.TODO(), ns)).To(Succeed()) 73 }) 74 75 It("should create cluster privatekey secret", func() { 76 secret := &corev1.Secret{ 77 ObjectMeta: metav1.ObjectMeta{ 78 Name: "cluster-privatekey", 79 Namespace: ns.Name, 80 }, 81 StringData: map[string]string{ 82 "key": "CAESQOH/DvUJmeJ9z6m3wAStpkrlBwJQxIyNSK0YGf0EI5ZRGpwsWxl4wmgReqmHl8LQjTC2iPM0QbYAjeY3Z63AFnI=", 83 }, 84 } 85 86 Expect(k8sClient.Create(context.TODO(), secret)).To(Succeed()) 87 }) 88 89 It("should create cluster secret", func() { 90 secret := &corev1.Secret{ 91 ObjectMeta: metav1.ObjectMeta{ 92 Name: "cluster-secret", 93 Namespace: ns.Name, 94 }, 95 StringData: map[string]string{ 96 "secret": "clu$ter$3cr3t", 97 }, 98 } 99 100 Expect(k8sClient.Create(context.TODO(), secret)).To(Succeed()) 101 }) 102 103 It("should create ipfs cluster peer", func() { 104 if os.Getenv(shared.EnvUseExistingCluster) != "true" { 105 toCreate.Default() 106 } 107 Expect(k8sClient.Create(context.Background(), toCreate)).Should(Succeed()) 108 }) 109 110 It("should get ipfs cluster peer", func() { 111 fetched := &ipfsv1alpha1.ClusterPeer{} 112 Expect(k8sClient.Get(context.TODO(), key, fetched)).To(Succeed()) 113 Expect(fetched.Spec).To(Equal(toCreate.Spec)) 114 peerOwnerReference.UID = fetched.UID 115 time.Sleep(5 * time.Second) 116 }) 117 118 It("Should create ipfs cluster peer statefulset with correct image and arguments", func() { 119 fetched := &appsv1.StatefulSet{} 120 Expect(k8sClient.Get(context.Background(), key, fetched)).To(Succeed()) 121 Expect(fetched.OwnerReferences).To(ContainElements(peerOwnerReference)) 122 Expect(*fetched.Spec.Template.Spec.SecurityContext).To(gstruct.MatchFields(gstruct.IgnoreExtras, gstruct.Fields{ 123 "RunAsUser": gstruct.PointTo(Equal(int64(1000))), 124 "RunAsGroup": gstruct.PointTo(Equal(int64(3000))), 125 "FSGroup": gstruct.PointTo(Equal(int64(2000))), 126 "RunAsNonRoot": gstruct.PointTo(Equal(true)), 127 })) 128 container := fetched.Spec.Template.Spec.Containers[0] 129 Expect(container.Image).To(Equal(image)) 130 131 }) 132 133 It("Should pass correct environment variables to ipfs cluster peer statefulset containers", func() { 134 fetched := &appsv1.StatefulSet{} 135 Expect(k8sClient.Get(context.Background(), key, fetched)).To(Succeed()) 136 137 container := fetched.Spec.Template.Spec.Containers[0] 138 Expect(container.Env).To(ContainElements([]corev1.EnvVar{ 139 { 140 Name: ipfsClients.EnvIPFSClusterPath, 141 Value: shared.PathData(ipfsClients.GoIPFSClusterHomeDir), 142 }, 143 { 144 Name: ipfsClients.EnvIPFSClusterPeerName, 145 Value: toCreate.Name, 146 }, 147 })) 148 149 initContainer := fetched.Spec.Template.Spec.InitContainers[0] 150 Expect(initContainer.Env).To(ContainElements([]corev1.EnvVar{ 151 { 152 Name: ipfsClients.EnvIPFSClusterPath, 153 Value: shared.PathData(ipfsClients.GoIPFSClusterHomeDir), 154 }, 155 { 156 Name: ipfsClients.EnvIPFSClusterConsensus, 157 Value: string(toCreate.Spec.Consensus), 158 }, 159 { 160 Name: ipfsClients.EnvIPFSClusterPeerEndpoint, 161 Value: toCreate.Spec.PeerEndpoint, 162 }, 163 { 164 Name: ipfsClients.EnvIPFSClusterSecret, 165 ValueFrom: &corev1.EnvVarSource{ 166 SecretKeyRef: &corev1.SecretKeySelector{ 167 LocalObjectReference: corev1.LocalObjectReference{ 168 Name: toCreate.Spec.ClusterSecretName, 169 }, 170 Key: "secret", 171 }, 172 }, 173 }, 174 { 175 Name: ipfsClients.EnvIPFSClusterTrustedPeers, 176 Value: strings.Join(toCreate.Spec.TrustedPeers, ","), 177 }, 178 { 179 Name: ipfsClients.EnvIPFSClusterId, 180 Value: toCreate.Spec.ID, 181 }, 182 { 183 Name: ipfsClients.EnvIPFSClusterPrivateKey, 184 ValueFrom: &corev1.EnvVarSource{ 185 SecretKeyRef: &corev1.SecretKeySelector{ 186 LocalObjectReference: corev1.LocalObjectReference{ 187 Name: toCreate.Spec.PrivateKeySecretName, 188 }, 189 Key: "key", 190 }, 191 }, 192 }, 193 })) 194 }) 195 196 It("Should create allocate correct resources to cluster peer statefulset", func() { 197 fetched := &appsv1.StatefulSet{} 198 expectedResources := corev1.ResourceRequirements{ 199 Requests: corev1.ResourceList{ 200 corev1.ResourceCPU: resource.MustParse(ipfsv1alpha1.DefaultNodeCPURequest), 201 corev1.ResourceMemory: resource.MustParse(ipfsv1alpha1.DefaultNodeMemoryRequest), 202 }, 203 Limits: corev1.ResourceList{ 204 corev1.ResourceCPU: resource.MustParse(ipfsv1alpha1.DefaultNodeCPULimit), 205 corev1.ResourceMemory: resource.MustParse(ipfsv1alpha1.DefaultNodeMemoryLimit), 206 }, 207 } 208 Expect(k8sClient.Get(context.Background(), key, fetched)).To(Succeed()) 209 Expect(fetched.Spec.Template.Spec.Containers[0].Resources).To(Equal(expectedResources)) 210 }) 211 212 It("Should create peer configmap", func() { 213 fetched := &corev1.ConfigMap{} 214 Expect(k8sClient.Get(context.Background(), key, fetched)).To(Succeed()) 215 Expect(fetched.OwnerReferences).To(ContainElements(peerOwnerReference)) 216 Expect(fetched.Data).To(HaveKey("init_ipfs_cluster_config.sh")) 217 }) 218 219 It("Should create peer data persistent volume with correct resources", func() { 220 fetched := &corev1.PersistentVolumeClaim{} 221 Expect(k8sClient.Get(context.Background(), key, fetched)).To(Succeed()) 222 Expect(fetched.OwnerReferences).To(ContainElements(peerOwnerReference)) 223 224 expectedResources := corev1.VolumeResourceRequirements{ 225 Requests: corev1.ResourceList{ 226 corev1.ResourceStorage: resource.MustParse(ipfsv1alpha1.DefaultNodeStorageRequest), 227 }, 228 } 229 Expect(fetched.Spec.Resources).To(Equal(expectedResources)) 230 }) 231 232 It("Should create peer service", func() { 233 fetched := &corev1.Service{} 234 Expect(k8sClient.Get(context.Background(), key, fetched)).To(Succeed()) 235 Expect(fetched.OwnerReferences).To(ContainElements(peerOwnerReference)) 236 Expect(fetched.Spec.Ports).To(ContainElements( 237 []corev1.ServicePort{ 238 { 239 Name: "swarm", 240 Port: 9096, 241 TargetPort: intstr.FromString("swarm"), 242 Protocol: corev1.ProtocolTCP, 243 }, 244 { 245 Name: "swarm-udp", 246 Port: 9096, 247 TargetPort: intstr.FromString("swarm-udp"), 248 Protocol: corev1.ProtocolUDP, 249 }, 250 { 251 Name: "api", 252 Port: 5001, 253 TargetPort: intstr.FromString("api"), 254 Protocol: corev1.ProtocolTCP, 255 }, 256 { 257 Name: "proxy-api", 258 Port: 9095, 259 TargetPort: intstr.FromString("proxy-api"), 260 Protocol: corev1.ProtocolTCP, 261 }, 262 { 263 Name: "rest", 264 Port: 9094, 265 TargetPort: intstr.FromString("rest"), 266 Protocol: corev1.ProtocolTCP, 267 }, 268 { 269 Name: "metrics", 270 Port: 8888, 271 TargetPort: intstr.FromString("metrics"), 272 Protocol: corev1.ProtocolTCP, 273 }, 274 { 275 Name: "tracing", 276 Port: 6831, 277 TargetPort: intstr.FromString("tracing"), 278 Protocol: corev1.ProtocolTCP, 279 }, 280 }, 281 )) 282 }) 283 284 It(fmt.Sprintf("Should delete %s namespace", ns.Name), func() { 285 Expect(k8sClient.Delete(context.Background(), ns)).To(Succeed()) 286 }) 287 288 })