github.com/IBM-Blockchain/fabric-operator@v1.0.4/pkg/initializer/peer/initializer_test.go (about) 1 /* 2 * Copyright contributors to the Hyperledger Fabric Operator project 3 * 4 * SPDX-License-Identifier: Apache-2.0 5 * 6 * Licensed under the Apache License, Version 2.0 (the "License"); 7 * you may not use this file except in compliance with the License. 8 * You may obtain a copy of the License at: 9 * 10 * http://www.apache.org/licenses/LICENSE-2.0 11 * 12 * Unless required by applicable law or agreed to in writing, software 13 * distributed under the License is distributed on an "AS IS" BASIS, 14 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 15 * See the License for the specific language governing permissions and 16 * limitations under the License. 17 */ 18 19 package initializer_test 20 21 import ( 22 "context" 23 "encoding/base64" 24 "encoding/pem" 25 "net/url" 26 27 . "github.com/onsi/ginkgo/v2" 28 . "github.com/onsi/gomega" 29 "github.com/pkg/errors" 30 corev1 "k8s.io/api/core/v1" 31 metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" 32 "k8s.io/apimachinery/pkg/runtime" 33 "k8s.io/apimachinery/pkg/types" 34 "sigs.k8s.io/controller-runtime/pkg/client" 35 36 current "github.com/IBM-Blockchain/fabric-operator/api/v1beta1" 37 controllermocks "github.com/IBM-Blockchain/fabric-operator/controllers/mocks" 38 commonconfig "github.com/IBM-Blockchain/fabric-operator/pkg/initializer/common/config" 39 "github.com/IBM-Blockchain/fabric-operator/pkg/initializer/common/enroller" 40 commonmocks "github.com/IBM-Blockchain/fabric-operator/pkg/initializer/common/mocks" 41 peer "github.com/IBM-Blockchain/fabric-operator/pkg/initializer/peer" 42 config "github.com/IBM-Blockchain/fabric-operator/pkg/initializer/peer/config/v1" 43 "github.com/IBM-Blockchain/fabric-operator/pkg/initializer/peer/mocks" 44 "github.com/IBM-Blockchain/fabric-operator/pkg/util" 45 ) 46 47 const ( 48 testcert = "LS0tLS1CRUdJTiBDRVJUSUZJQ0FURS0tLS0tCk1JSUNpVENDQWkrZ0F3SUJBZ0lVRkd3N0RjK0QvZUoyY08wOHd6d2tialIzK1M4d0NnWUlLb1pJemowRUF3SXcKYURFTE1Ba0dBMVVFQmhNQ1ZWTXhGekFWQmdOVkJBZ1REazV2Y25Sb0lFTmhjbTlzYVc1aE1SUXdFZ1lEVlFRSwpFd3RJZVhCbGNteGxaR2RsY2pFUE1BMEdBMVVFQ3hNR1JtRmljbWxqTVJrd0Z3WURWUVFERXhCbVlXSnlhV010ClkyRXRjMlZ5ZG1WeU1CNFhEVEU1TVRBd09URTBNakF3TUZvWERUSXdNVEF3T0RFME1qQXdNRm93YnpFTE1Ba0cKQTFVRUJoTUNWVk14RnpBVkJnTlZCQWdURGs1dmNuUm9JRU5oY205c2FXNWhNUlF3RWdZRFZRUUtFd3RJZVhCbApjbXhsWkdkbGNqRVBNQTBHQTFVRUN4TUdSbUZpY21sak1TQXdIZ1lEVlFRREV4ZFRZV0ZrY3kxTllXTkNiMjlyCkxWQnlieTVzYjJOaGJEQlpNQk1HQnlxR1NNNDlBZ0VHQ0NxR1NNNDlBd0VIQTBJQUJBK0JBRzhZakJvTllabGgKRjFrVHNUbHd6VERDQTJocDhZTXI5Ky8vbEd0NURoSGZVT1c3bkhuSW1USHlPRjJQVjFPcVRuUWhUbWpLYTdaQwpqeU9BUWxLamdhOHdnYXd3RGdZRFZSMFBBUUgvQkFRREFnT29NQjBHQTFVZEpRUVdNQlFHQ0NzR0FRVUZCd01CCkJnZ3JCZ0VGQlFjREFqQU1CZ05WSFJNQkFmOEVBakFBTUIwR0ExVWREZ1FXQkJTbHJjL0lNQkxvMzR0UktvWnEKNTQreDIyYWEyREFmQmdOVkhTTUVHREFXZ0JSWmpxT3RQZWJzSFI2UjBNQUhrNnd4ei85UFZqQXRCZ05WSFJFRQpKakFrZ2hkVFlXRmtjeTFOWVdOQ2IyOXJMVkJ5Ynk1c2IyTmhiSUlKYkc5allXeG9iM04wTUFvR0NDcUdTTTQ5CkJBTUNBMGdBTUVVQ0lRRGR0Y1QwUE9FQXJZKzgwdEhmWUwvcXBiWWoxMGU2eWlPWlpUQ29wY25mUVFJZ1FNQUQKaFc3T0NSUERNd3lqKzNhb015d2hFenFHYy9jRDJSU2V5ekRiRjFFPQotLS0tLUVORCBDRVJUSUZJQ0FURS0tLS0tCg==" 49 testkey = "LS0tLS1CRUdJTiBQUklWQVRFIEtFWS0tLS0tCk1JR0hBZ0VBTUJNR0J5cUdTTTQ5QWdFR0NDcUdTTTQ5QXdFSEJHMHdhd0lCQVFRZ3hRUXdSVFFpVUcwREo1UHoKQTJSclhIUEtCelkxMkxRa0MvbVlveWo1bEhDaFJBTkNBQVN5bE1YLzFqdDlmUGt1RTZ0anpvSTlQbGt4LzZuVQpCMHIvMU56TTdrYnBjUk8zQ3RIeXQ2TXlQR21FOUZUN29pYXphU3J1TW9JTDM0VGdBdUpIOU9ZWQotLS0tLUVORCBQUklWQVRFIEtFWS0tLS0tCg==" 50 ) 51 52 var _ = Describe("Initializing the Peer", func() { 53 var ( 54 peerinitializer *peer.Initializer 55 instance *current.IBPPeer 56 mockClient *controllermocks.Client 57 mockValidator *commonmocks.CryptoValidator 58 serverURL string 59 serverCert string 60 serverUrlObj *url.URL 61 ) 62 63 BeforeEach(func() { 64 serverURL = server.URL 65 rawCert := server.Certificate().Raw 66 pemCert := pem.EncodeToMemory(&pem.Block{Type: "CERTIFICATE", Bytes: rawCert}) 67 serverCert = string(util.BytesToBase64(pemCert)) 68 69 urlObj, err := url.Parse(serverURL) 70 Expect(err).NotTo(HaveOccurred()) 71 serverUrlObj = urlObj 72 73 mockClient = &controllermocks.Client{} 74 mockValidator = &commonmocks.CryptoValidator{} 75 getLabels := func(instance metav1.Object) map[string]string { 76 return map[string]string{} 77 } 78 peerinitializer = peer.New(nil, &runtime.Scheme{}, mockClient, getLabels, mockValidator, enroller.HSMEnrollJobTimeouts{}) 79 80 instance = ¤t.IBPPeer{ 81 Spec: current.IBPPeerSpec{ 82 Secret: ¤t.SecretSpec{ 83 Enrollment: ¤t.EnrollmentSpec{ 84 Component: ¤t.Enrollment{ 85 CAHost: serverUrlObj.Hostname(), 86 CAPort: serverUrlObj.Port(), 87 EnrollID: "admin", 88 EnrollSecret: "adminpw", 89 CATLS: ¤t.CATLS{ 90 CACert: serverCert, 91 }, 92 AdminCerts: []string{testcert}, 93 }, 94 TLS: ¤t.Enrollment{ 95 CAHost: serverUrlObj.Hostname(), 96 CAPort: serverUrlObj.Port(), 97 EnrollID: "admin", 98 EnrollSecret: "adminpw", 99 CATLS: ¤t.CATLS{ 100 CACert: serverCert, 101 }, 102 }, 103 ClientAuth: ¤t.Enrollment{ 104 CAHost: serverUrlObj.Hostname(), 105 CAPort: serverUrlObj.Port(), 106 EnrollID: "admin", 107 EnrollSecret: "adminpw", 108 CATLS: ¤t.CATLS{ 109 CACert: serverCert, 110 }, 111 }, 112 }, 113 MSP: ¤t.MSPSpec{ 114 Component: ¤t.MSP{ 115 KeyStore: "key", 116 SignCerts: "cert", 117 CACerts: []string{"certs"}, 118 AdminCerts: []string{testcert}, 119 }, 120 TLS: ¤t.MSP{ 121 KeyStore: "key", 122 SignCerts: "cert", 123 CACerts: []string{"certs"}, 124 }, 125 ClientAuth: ¤t.MSP{ 126 KeyStore: "key", 127 SignCerts: "cert", 128 CACerts: []string{"certs"}, 129 }, 130 }, 131 }, 132 }, 133 } 134 }) 135 136 Context("create", func() { 137 var peer *mocks.IBPPeer 138 139 BeforeEach(func() { 140 peer = &mocks.IBPPeer{} 141 }) 142 143 It("returns an error if it fails to override peer's config", func() { 144 msg := "failed to override" 145 peer.OverrideConfigReturns(errors.New(msg)) 146 147 _, err := peerinitializer.Create(&config.Core{}, peer, "") 148 Expect(err).To(HaveOccurred()) 149 Expect(err.Error()).To(Equal(msg)) 150 }) 151 152 It("returns an error if it fails to generate crypto", func() { 153 msg := "failed to generate crypto" 154 peer.GenerateCryptoReturns(nil, errors.New(msg)) 155 156 _, err := peerinitializer.Create(&config.Core{}, peer, "") 157 Expect(err).To(HaveOccurred()) 158 Expect(err.Error()).To(Equal(msg)) 159 }) 160 161 It("creates and returns response containing config and crypto", func() { 162 _, err := peerinitializer.Create(&config.Core{}, peer, "blah") 163 Expect(err).NotTo(HaveOccurred()) 164 }) 165 }) 166 167 Context("update", func() { 168 var peer *mocks.IBPPeer 169 170 BeforeEach(func() { 171 peer = &mocks.IBPPeer{} 172 }) 173 174 It("returns an error if it fails to override peer's config", func() { 175 msg := "failed to override" 176 peer.OverrideConfigReturns(errors.New(msg)) 177 178 _, err := peerinitializer.Update(&config.Core{}, peer) 179 Expect(err).To(HaveOccurred()) 180 Expect(err.Error()).To(Equal(msg)) 181 }) 182 183 It("creates and returns response containing config and crypto", func() { 184 _, err := peerinitializer.Update(&config.Core{}, peer) 185 Expect(err).NotTo(HaveOccurred()) 186 }) 187 }) 188 189 Context("get init peer", func() { 190 It("returns empty init peer if neither MSP nor enrollment spec is passed", func() { 191 instance.Spec.Secret.MSP.TLS = nil 192 instance.Spec.Secret.Enrollment.TLS = nil 193 initpeer, err := peerinitializer.GetInitPeer(instance, "foo") 194 Expect(err).NotTo(HaveOccurred()) 195 Expect(initpeer.Cryptos).NotTo(BeNil()) 196 Expect(initpeer.Cryptos.TLS).To(BeNil()) 197 }) 198 199 It("returns init peer with ecert, tls, clientauth enrollers", func() { 200 initpeer, err := peerinitializer.GetInitPeer(instance, "foo") 201 Expect(err).NotTo(HaveOccurred()) 202 Expect(initpeer.Cryptos).NotTo(BeNil()) 203 Expect(initpeer.Cryptos.Enrollment).NotTo(BeNil()) 204 Expect(initpeer.Cryptos.TLS).NotTo(BeNil()) 205 Expect(initpeer.Cryptos.ClientAuth).NotTo(BeNil()) 206 }) 207 208 It("returns init peer with ecert, tls, clientauth msp parsers", func() { 209 initpeer, err := peerinitializer.GetInitPeer(instance, "foo") 210 Expect(err).NotTo(HaveOccurred()) 211 Expect(initpeer.Cryptos).NotTo(BeNil()) 212 Expect(initpeer.Cryptos.Enrollment).NotTo(BeNil()) 213 Expect(initpeer.Cryptos.TLS).NotTo(BeNil()) 214 Expect(initpeer.Cryptos.ClientAuth).NotTo(BeNil()) 215 }) 216 217 It("returns ecert msp parsers and tls enrollers", func() { 218 instance.Spec.Secret.Enrollment.Component = nil 219 instance.Spec.Secret.MSP.TLS = nil 220 initpeer, err := peerinitializer.GetInitPeer(instance, "foo") 221 Expect(err).NotTo(HaveOccurred()) 222 Expect(initpeer.Cryptos).NotTo(BeNil()) 223 Expect(initpeer.Cryptos.Enrollment).NotTo(BeNil()) 224 Expect(initpeer.Cryptos.TLS).NotTo(BeNil()) 225 }) 226 }) 227 228 Context("generate secrets", func() { 229 var ( 230 resp *commonconfig.Response 231 ) 232 233 BeforeEach(func() { 234 resp = &commonconfig.Response{ 235 CACerts: [][]byte{[]byte("cacert")}, 236 IntermediateCerts: [][]byte{[]byte("intercert")}, 237 AdminCerts: [][]byte{[]byte("admincert")}, 238 SignCert: []byte("signcert"), 239 Keystore: []byte("key"), 240 } 241 }) 242 243 It("returns an error if fails to create a secret", func() { 244 msg := "admin certs error" 245 mockClient.CreateOrUpdateReturnsOnCall(0, errors.New(msg)) 246 247 err := peerinitializer.GenerateSecrets("ecert", instance, resp) 248 Expect(err).To(HaveOccurred()) 249 Expect(err.Error()).To(ContainSubstring("failed to create admin certs secret: " + msg)) 250 }) 251 252 It("generates", func() { 253 err := peerinitializer.GenerateSecrets("ecert", instance, resp) 254 Expect(err).NotTo(HaveOccurred()) 255 }) 256 }) 257 258 Context("check for missing crypto", func() { 259 It("returns true, if missing any crypto", func() { 260 mockValidator.CheckEcertCryptoReturns(errors.New("not found")) 261 missing := peerinitializer.MissingCrypto(instance) 262 Expect(missing).To(Equal(true)) 263 }) 264 265 It("returns false, if all crypto found and is in proper format", func() { 266 missing := peerinitializer.MissingCrypto(instance) 267 Expect(missing).To(Equal(false)) 268 }) 269 }) 270 271 Context("check if admin certs need to be updated", func() { 272 BeforeEach(func() { 273 instance.Spec.Secret.Enrollment.Component.AdminCerts = []string{testcert} 274 275 testCertBytes, err := base64.StdEncoding.DecodeString(testcert) 276 Expect(err).NotTo(HaveOccurred()) 277 278 mockClient.GetStub = func(ctx context.Context, types types.NamespacedName, obj client.Object) error { 279 switch obj.(type) { 280 case *corev1.Secret: 281 s := obj.(*corev1.Secret) 282 s.Data = map[string][]byte{"cert.pem": testCertBytes} 283 } 284 return nil 285 } 286 }) 287 288 It("does not return an error if it fails to find admin secret", func() { 289 errMsg := "failed to find admin certs secret" 290 mockClient.GetReturns(errors.New(errMsg)) 291 _, err := peerinitializer.CheckIfAdminCertsUpdated(instance) 292 Expect(err).NotTo(HaveOccurred()) 293 }) 294 295 When("admin certs updated as part of enrollment spec", func() { 296 BeforeEach(func() { 297 instance.Spec.Secret.MSP = nil 298 }) 299 300 It("returns false when the same cert in spec as current admin certs secret", func() { 301 needUpdating, err := peerinitializer.CheckIfAdminCertsUpdated(instance) 302 Expect(err).NotTo(HaveOccurred()) 303 Expect(needUpdating).To(Equal(false)) 304 }) 305 306 It("returns an error if non-base64 encoded string passed as cert", func() { 307 instance.Spec.Secret.Enrollment.Component.AdminCerts = []string{"foo"} 308 _, err := peerinitializer.CheckIfAdminCertsUpdated(instance) 309 Expect(err).To(HaveOccurred()) 310 Expect(err.Error()).To(ContainSubstring("illegal base64 data")) 311 }) 312 313 It("returns true when the different cert in spec as current admin certs secret", func() { 314 instance.Spec.Secret.Enrollment.Component.AdminCerts = []string{testkey} 315 needUpdating, err := peerinitializer.CheckIfAdminCertsUpdated(instance) 316 Expect(err).NotTo(HaveOccurred()) 317 Expect(needUpdating).To(Equal(true)) 318 }) 319 }) 320 321 When("admin certs updated as part of MSP spec", func() { 322 BeforeEach(func() { 323 instance.Spec.Secret.Enrollment = nil 324 }) 325 326 It("returns false when the same cert in spec as current admin certs secret", func() { 327 needUpdating, err := peerinitializer.CheckIfAdminCertsUpdated(instance) 328 Expect(err).NotTo(HaveOccurred()) 329 Expect(needUpdating).To(Equal(false)) 330 }) 331 332 It("returns an error if non-base64 encoded string passed as cert", func() { 333 instance.Spec.Secret.MSP.Component.AdminCerts = []string{"foo"} 334 _, err := peerinitializer.CheckIfAdminCertsUpdated(instance) 335 Expect(err).To(HaveOccurred()) 336 Expect(err.Error()).To(ContainSubstring("illegal base64 data")) 337 }) 338 339 It("returns true when the diferent cert in spec as current admin certs secret", func() { 340 instance.Spec.Secret.MSP.Component.AdminCerts = []string{testkey} 341 needUpdating, err := peerinitializer.CheckIfAdminCertsUpdated(instance) 342 Expect(err).NotTo(HaveOccurred()) 343 Expect(needUpdating).To(Equal(true)) 344 }) 345 }) 346 }) 347 }) 348 349 // BeforeEach(func() { 350 // testCertBytes, err := base64.StdEncoding.DecodeString(testcert) 351 // Expect(err).NotTo(HaveOccurred()) 352 353 // mockClient = &mocks.Client{} 354 // mockClient.GetStub = func(ctx context.Context, types types.NamespacedName, obj runtime.Object) error { 355 // switch obj.(type) { 356 // case *corev1.Secret: 357 // s := obj.(*corev1.Secret) 358 // s.Data = map[string][]byte{"cert.pem": testCertBytes} 359 // } 360 // return nil 361 // } 362 363 // resp := &commonconfig.Response{ 364 // CACerts: [][]byte{[]byte("cacert")}, 365 // IntermediateCerts: [][]byte{[]byte("intercert")}, 366 // SignCert: []byte("cert"), 367 // Keystore: []byte("key"), 368 // } 369 // _ = resp 370 371 // peerInitializer = &initializer.Initializer{ 372 // Client: mockClient, 373 // } 374 375 // enrollment := ¤t.Enrollment{ 376 // CAHost: "localhost", 377 // CAPort: "7054", 378 // EnrollID: "admin", 379 // EnrollSecret: "adminpw", 380 // CATLS: ¤t.CATLS{ 381 // CACert: testcert, 382 // }, 383 // } 384 // tlsenrollment := enrollment.DeepCopy() 385 386 // msp := ¤t.MSP{ 387 // KeyStore: testkey, 388 // SignCerts: testcert, 389 // AdminCerts: []string{testcert}, 390 // CACerts: []string{testcert}, 391 // } 392 // tlsmsp := msp.DeepCopy() 393 394 // instance = ¤t.IBPPeer{ 395 // Spec: current.IBPPeerSpec{ 396 // Secret: ¤t.SecretSpec{ 397 // Enrollment: ¤t.EnrollmentSpec{ 398 // Component: enrollment, 399 // TLS: tlsenrollment, 400 // }, 401 // MSP: ¤t.MSPSpec{ 402 // Component: msp, 403 // TLS: tlsmsp, 404 // }, 405 // }, 406 // }, 407 // } 408 // }) 409 410 // Context("check admin certs for existence and proper data", func() { 411 // It("returns error, if secret not found", func() { 412 // errMsg := "ecert admincerts secret not found" 413 // mockClient.GetReturns(errors.New(errMsg)) 414 // err := peerInitializer.CheckAdminCerts(instance, "ecert") 415 // Expect(err).To(HaveOccurred()) 416 // Expect(err.Error()).To(Equal(errMsg)) 417 // }) 418 419 // It("returns error, if secrets found but contains no data", func() { 420 // mockClient.GetStub = func(ctx context.Context, types types.NamespacedName, obj runtime.Object) error { 421 // switch obj.(type) { 422 // case *corev1.Secret: 423 // s := obj.(*corev1.Secret) 424 // s.Data = nil 425 // } 426 // return nil 427 // } 428 // err := peerInitializer.CheckAdminCerts(instance, "ecert") 429 // Expect(err).To(HaveOccurred()) 430 // Expect(err.Error()).To(Equal("no admin certificates found in admincerts secret")) 431 // }) 432 433 // It("returns error, if secrets found but contains bad data", func() { 434 // mockClient.GetStub = func(ctx context.Context, types types.NamespacedName, obj runtime.Object) error { 435 // switch obj.(type) { 436 // case *corev1.Secret: 437 // s := obj.(*corev1.Secret) 438 // s.Data = map[string][]byte{"cert.pem": []byte("foo")} 439 // } 440 // return nil 441 // } 442 // err := peerInitializer.CheckAdminCerts(instance, "ecert") 443 // Expect(err).To(HaveOccurred()) 444 // Expect(err.Error()).To(Equal("not a proper admin cert: failed to get certificate block")) 445 // }) 446 447 // It("returns no error, if secret found and contains proper data", func() { 448 // err := peerInitializer.CheckAdminCerts(instance, "ecert") 449 // Expect(err).NotTo(HaveOccurred()) 450 // }) 451 // }) 452 453 // Context("check ca certs for existence and proper data", func() { 454 // It("returns error, if secret not found", func() { 455 // errMsg := "ecert cacerts secret not found" 456 // mockClient.GetReturns(errors.New(errMsg)) 457 // err := peerInitializer.CheckCACerts(instance, "ecert") 458 // Expect(err).To(HaveOccurred()) 459 // Expect(err.Error()).To(Equal(errMsg)) 460 // }) 461 462 // It("returns error, if secrets found but contains no data", func() { 463 // mockClient.GetStub = func(ctx context.Context, types types.NamespacedName, obj runtime.Object) error { 464 // switch obj.(type) { 465 // case *corev1.Secret: 466 // s := obj.(*corev1.Secret) 467 // s.Data = nil 468 // } 469 // return nil 470 // } 471 // err := peerInitializer.CheckCACerts(instance, "ecert") 472 // Expect(err).To(HaveOccurred()) 473 // Expect(err.Error()).To(Equal("no ca certificates found in cacerts secret")) 474 // }) 475 476 // It("returns error, if secrets found but contains bad data", func() { 477 // mockClient.GetStub = func(ctx context.Context, types types.NamespacedName, obj runtime.Object) error { 478 // switch obj.(type) { 479 // case *corev1.Secret: 480 // s := obj.(*corev1.Secret) 481 // s.Data = map[string][]byte{"cert.pem": []byte("foo")} 482 // } 483 // return nil 484 // } 485 // err := peerInitializer.CheckCACerts(instance, "ecert") 486 // Expect(err).To(HaveOccurred()) 487 // Expect(err.Error()).To(Equal("not a proper ca cert: failed to get certificate block")) 488 // }) 489 490 // It("returns no error, if secret found and contains proper data", func() { 491 // err := peerInitializer.CheckCACerts(instance, "ecert") 492 // Expect(err).NotTo(HaveOccurred()) 493 // }) 494 // }) 495 496 // })