github.com/IBM-Blockchain/fabric-operator@v1.0.4/pkg/offering/base/ca/ca_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 baseca_test
    20  
    21  import (
    22  	"context"
    23  	"encoding/base64"
    24  	"encoding/json"
    25  	"errors"
    26  	"fmt"
    27  	"os"
    28  	"path/filepath"
    29  
    30  	. "github.com/onsi/ginkgo/v2"
    31  	. "github.com/onsi/gomega"
    32  	corev1 "k8s.io/api/core/v1"
    33  	"k8s.io/apimachinery/pkg/runtime"
    34  	"k8s.io/apimachinery/pkg/types"
    35  	"sigs.k8s.io/controller-runtime/pkg/client"
    36  	"sigs.k8s.io/yaml"
    37  
    38  	current "github.com/IBM-Blockchain/fabric-operator/api/v1beta1"
    39  	cmocks "github.com/IBM-Blockchain/fabric-operator/controllers/mocks"
    40  	config "github.com/IBM-Blockchain/fabric-operator/operatorconfig"
    41  	v1 "github.com/IBM-Blockchain/fabric-operator/pkg/apis/ca/v1"
    42  	"github.com/IBM-Blockchain/fabric-operator/pkg/apis/deployer"
    43  	initializer "github.com/IBM-Blockchain/fabric-operator/pkg/initializer/ca"
    44  	commonconfig "github.com/IBM-Blockchain/fabric-operator/pkg/initializer/common/config"
    45  	managermocks "github.com/IBM-Blockchain/fabric-operator/pkg/manager/resources/mocks"
    46  	baseca "github.com/IBM-Blockchain/fabric-operator/pkg/offering/base/ca"
    47  	"github.com/IBM-Blockchain/fabric-operator/pkg/offering/base/ca/mocks"
    48  	basecamocks "github.com/IBM-Blockchain/fabric-operator/pkg/offering/base/ca/mocks"
    49  	override "github.com/IBM-Blockchain/fabric-operator/pkg/offering/k8s/ca/override"
    50  	"github.com/IBM-Blockchain/fabric-operator/pkg/operatorerrors"
    51  	"github.com/IBM-Blockchain/fabric-operator/version"
    52  )
    53  
    54  var _ = Describe("Base CA", func() {
    55  	const (
    56  		defaultConfigs = "../../../../defaultconfig/ca"
    57  		testdataDir    = "../../../../testdata"
    58  
    59  		keyBase64  = "LS0tLS1CRUdJTiBSU0EgUFJJVkFURSBLRVktLS0tLQpNSUlFb2dJQkFBS0NBUUVBdFJBUDlMemUyZEc1cm1rbmcvdVVtREFZU0VwUElqRFdUUDhqUjMxcUJ5Yjc3YWUrCnk3UTRvRnZod1lDVUhsUWVTWjFKeTdUUHpEcitoUk5hdDJYNGdGYUpGYmVFbC9DSHJ3Rk1mNzNzQStWV1pHdnkKdXhtbjB2bEdYMW5zSEo5aUdIUS9qR2FvV1FJYzlVbnpHWi8yWStlZkpxOWd3cDBNemFzWWZkdXordXVBNlp4VAp5TTdDOWFlWmxYL2ZMYmVkSXVXTzVzaXhPSlZQeUVpcWpkd0RiY1AxYy9mRCtSMm1DbmM3VGovSnVLK1poTGxPCnhGcVlFRmtROHBmSi9LY1pabVF1QURZVFh6RGp6OENxcTRTRU5ySzI0b2hQQkN2SGgyanplWjhGdGR4MmpSSFQKaXdCZWZEYWlSWVBSOUM4enk4K1Z2Wmt6S0hQV3N5aENiNUMrN1FJREFRQUJBb0lCQUZROGhzL2IxdW9Mc3BFOApCdEJXaVVsTWh0K0xBc25yWXFncnd5UU5hdmlzNEdRdXVJdFk2MGRmdCtZb2hjQ2ViZ0RkbG1tWlUxdTJ6cGJtCjdEdUt5MVFaN21rV0dpLytEWUlUM3AxSHBMZ2pTRkFzRUorUFRnN1BQamc2UTZrRlZjUCt3Vm4yb0xmWVRkU28KZE5zbEdxSmNMaVQzVHRMNzhlcjFnTTE5RzN6T3J1ZndrSGJSYU1BRmtvZ1ExUlZLSWpnVGUvbmpIMHFHNW9JagoxNEJLeFFKTUZFTG1pQk50NUx5OVMxWWdxTDRjbmNtUDN5L1QyNEdodVhNckx0eTVOeVhnS0dFZ1pUTDMzZzZvCnYreDFFMFRURWRjMVQvWVBGWkdBSXhHdWRKNWZZZ2JtWU9LZ09mUHZFOE9TbEV6OW56aHNnckVZYjdQVThpZDUKTHFycVJRRUNnWUVBNjIyT3RIUmMxaVY1ZXQxdHQydTVTTTlTS2h2b0lPT3d2Q3NnTEI5dDJzNEhRUlRYN0RXcAo0VDNpUC9leEl5OXI3bTIxNFo5MEgzZlpVNElSUkdHSUxKUVMrYzRQNVA4cHJFTDcyd1dIWlpQTTM3QlZTQ1U3CkxOTXl4TkRjeVdjSUJIVFh4NUY2eXhLNVFXWTg5MVB0eDlDamJFSEcrNVJVdDA4UVlMWDlUQTBDZ1lFQXhPSmYKcXFjeThMOVZyYUFVZG9lbGdIU0NGSkJRR3hMRFNSQlJSTkRIOUJhaWlZOCtwZzd2TExTRXFMRFpsbkZPbFkrQQpiRENEQ0RtdHhwRXViY0x6b3FnOXhlQTZ0eXZZWkNWalY5dXVzNVh1Wmk1VDBBUHhCdm56OHNNa3dRY3RQWkRQCk8zQTN4WllkZzJBRmFrV1BmT1FFbjVaK3F4TU13SG9VZ1ZwQkptRUNnWUJ2Q2FjcTJVOEgrWGpJU0ROOU5TT1kKZ1ovaEdIUnRQcmFXcVVodFJ3MkxDMjFFZHM0NExEOUphdVNSQXdQYThuelhZWXROTk9XU0NmYkllaW9tdEZHRApwUHNtTXRnd1MyQ2VUS0Y0OWF5Y2JnOU0yVi8vdlAraDdxS2RUVjAwNkpGUmVNSms3K3FZYU9aVFFDTTFDN0swCmNXVUNwQ3R6Y014Y0FNQmF2THNRNlFLQmdHbXJMYmxEdjUxaXM3TmFKV0Z3Y0MwL1dzbDZvdVBFOERiNG9RV1UKSUowcXdOV2ZvZm95TGNBS3F1QjIrbkU2SXZrMmFiQ25ZTXc3V0w4b0VJa3NodUtYOVgrTVZ6Y1VPekdVdDNyaQpGeU9mcHJJRXowcm5zcWNSNUJJNUZqTGJqVFpyMEMyUWp2NW5FVFAvaHlpQWFRQ1l5THAyWlVtZ0Vjb0VPNWtwClBhcEJBb0dBZVV0WjE0SVp2cVorQnAxR1VqSG9PR0pQVnlJdzhSRUFETjRhZXRJTUlQRWFVaDdjZUtWdVN6VXMKci9WczA1Zjg0cFBVaStuUTUzaGo2ZFhhYTd1UE1aMFBnNFY4cS9UdzJMZ3BWWndVd0ltZUQrcXNsbldha3VWMQpMSnp3SkhOa3pOWE1OMmJWREFZTndSamNRSmhtbzF0V2xHYlpRQjNoSkEwR2thWGZPa2c9Ci0tLS0tRU5EIFJTQSBQUklWQVRFIEtFWS0tLS0tCg=="
    60  		certBase64 = "LS0tLS1CRUdJTiBDRVJUSUZJQ0FURS0tLS0tCk1JSURBekNDQWV1Z0F3SUJBZ0lKQU9xQ1VmaFNjcWtlTUEwR0NTcUdTSWIzRFFFQkJRVUFNQmd4RmpBVUJnTlYKQkFNTURYQnZjM1JuY21WekxuUmxjM1F3SGhjTk1Ua3dOekl6TVRrd09UVTRXaGNOTWprd056SXdNVGt3T1RVNApXakFZTVJZd0ZBWURWUVFEREExd2IzTjBaM0psY3k1MFpYTjBNSUlCSWpBTkJna3Foa2lHOXcwQkFRRUZBQU9DCkFROEFNSUlCQ2dLQ0FRRUF0UkFQOUx6ZTJkRzVybWtuZy91VW1EQVlTRXBQSWpEV1RQOGpSMzFxQnliNzdhZSsKeTdRNG9Gdmh3WUNVSGxRZVNaMUp5N1RQekRyK2hSTmF0Mlg0Z0ZhSkZiZUVsL0NIcndGTWY3M3NBK1ZXWkd2eQp1eG1uMHZsR1gxbnNISjlpR0hRL2pHYW9XUUljOVVuekdaLzJZK2VmSnE5Z3dwME16YXNZZmR1eit1dUE2WnhUCnlNN0M5YWVabFgvZkxiZWRJdVdPNXNpeE9KVlB5RWlxamR3RGJjUDFjL2ZEK1IybUNuYzdUai9KdUsrWmhMbE8KeEZxWUVGa1E4cGZKL0tjWlptUXVBRFlUWHpEano4Q3FxNFNFTnJLMjRvaFBCQ3ZIaDJqemVaOEZ0ZHgyalJIVAppd0JlZkRhaVJZUFI5Qzh6eTgrVnZaa3pLSFBXc3loQ2I1Qys3UUlEQVFBQm8xQXdUakFkQmdOVkhRNEVGZ1FVCi9mZ01BcExIMXBvcFFoS25KTmgrVk04QUtQZ3dId1lEVlIwakJCZ3dGb0FVL2ZnTUFwTEgxcG9wUWhLbkpOaCsKVk04QUtQZ3dEQVlEVlIwVEJBVXdBd0VCL3pBTkJna3Foa2lHOXcwQkFRVUZBQU9DQVFFQURjOUc4M05LaWw3ZQpoVFlvR1piejhFV1o4c0puVnY4azMwRDlydUY1OXFvT0ppZGorQUhNbzNHOWtud1lvbGFGbmJwb093cElOZ3g1CnYvL21aU3VldlFMZUZKRlN1UjBheVQ1WFYxcjljNUZGQ2JSaEp0cE4rOEdTT29tRUFSYTNBVGVFSG5WeVpaYkMKWkFQQUxMVXlVeUVrSDR3Q0RZUGtYa3dWQVVlR2FGVmNqZWR0eGJ3Z2k0dG0rSFZoTEt5Y0NoZ25YUVhxQ2srTwo2RHJIc0Z0STVTNWQvQlBPbE1Yc28vNUFielBGelpVVVg4OEhkVUhWSWlqM0luMXdUbWhtREtwdzZ6dmcvNjIxCjRhcGhDOWJ2bXAxeUVOUklzb0xiMGlMWVAzRSswU0ZkZC9IRnRhVXV3eUx6cnl4R2xrdG1BVUJWNVdYZEQxMkIKTU1mQnhvNFVYUT09Ci0tLS0tRU5EIENFUlRJRklDQVRFLS0tLS0K"
    61  	)
    62  
    63  	AfterEach(func() {
    64  		err := os.RemoveAll("shared")
    65  		Expect(err).NotTo(HaveOccurred())
    66  	})
    67  
    68  	var (
    69  		ca             *baseca.CA
    70  		instance       *current.IBPCA
    71  		mockKubeClient *cmocks.Client
    72  
    73  		deploymentMgr     *managermocks.ResourceManager
    74  		serviceMgr        *managermocks.ResourceManager
    75  		pvcMgr            *managermocks.ResourceManager
    76  		roleMgr           *managermocks.ResourceManager
    77  		roleBindingMgr    *managermocks.ResourceManager
    78  		serviceAccountMgr *managermocks.ResourceManager
    79  
    80  		initMock   *basecamocks.InitializeIBPCA
    81  		update     *mocks.Update
    82  		restartMgr *basecamocks.RestartManager
    83  		certMgr    *basecamocks.CertificateManager
    84  	)
    85  
    86  	BeforeEach(func() {
    87  		mockKubeClient = &cmocks.Client{}
    88  		update = &mocks.Update{}
    89  
    90  		replicas := int32(1)
    91  		instance = &current.IBPCA{
    92  			Status: current.IBPCAStatus{
    93  				CRStatus: current.CRStatus{
    94  					Version: version.Operator,
    95  				},
    96  			},
    97  			Spec: current.IBPCASpec{
    98  				Domain: "domain",
    99  				HSM: &current.HSM{
   100  					PKCS11Endpoint: "tcp://0.0.0.0:2345",
   101  				},
   102  				Images: &current.CAImages{
   103  					CAImage:     "caimage",
   104  					CATag:       "2.0.0",
   105  					CAInitImage: "cainitimage",
   106  					CAInitTag:   "2.0.0",
   107  				},
   108  				Replicas:      &replicas,
   109  				FabricVersion: "1.4.9-0",
   110  			},
   111  		}
   112  		instance.Kind = "IBPCA"
   113  		instance.Name = "ca1"
   114  		instance.Namespace = "test"
   115  
   116  		mockKubeClient.GetStub = func(ctx context.Context, types types.NamespacedName, obj client.Object) error {
   117  			switch obj.(type) {
   118  			case *corev1.Secret:
   119  				o := obj.(*corev1.Secret)
   120  				switch types.Name {
   121  				case instance.Name + "-ca-crypto":
   122  					o.Name = instance.Name + "-ca-crypto"
   123  					o.Namespace = instance.Namespace
   124  					o.Data = map[string][]byte{
   125  						"tls-cert.pem":        []byte(certBase64),
   126  						"cert.pem":            []byte(certBase64),
   127  						"operations-cert.pem": []byte(certBase64),
   128  					}
   129  				case instance.Name + "-tlsca-crypto":
   130  					o.Name = instance.Name + "-tlsca-crypto"
   131  					o.Namespace = instance.Namespace
   132  					o.Data = map[string][]byte{
   133  						"cert.pem": []byte(certBase64),
   134  					}
   135  				}
   136  
   137  			}
   138  			return nil
   139  		}
   140  
   141  		deploymentMgr = &managermocks.ResourceManager{}
   142  		serviceMgr = &managermocks.ResourceManager{}
   143  		pvcMgr = &managermocks.ResourceManager{}
   144  		roleMgr = &managermocks.ResourceManager{}
   145  		roleBindingMgr = &managermocks.ResourceManager{}
   146  		serviceAccountMgr = &managermocks.ResourceManager{}
   147  		initMock = &basecamocks.InitializeIBPCA{}
   148  		restartMgr = &basecamocks.RestartManager{}
   149  		certMgr = &basecamocks.CertificateManager{}
   150  
   151  		initMock.SyncDBConfigReturns(instance, nil)
   152  
   153  		config := &config.Config{
   154  			CAInitConfig: &initializer.Config{
   155  				CADefaultConfigPath:     filepath.Join(defaultConfigs, "/ca.yaml"),
   156  				CAOverrideConfigPath:    filepath.Join(testdataDir, "init/override.yaml"),
   157  				TLSCADefaultConfigPath:  filepath.Join(defaultConfigs, "tlsca.yaml"),
   158  				TLSCAOverrideConfigPath: filepath.Join(testdataDir, "init/override.yaml"),
   159  				SharedPath:              "shared",
   160  			},
   161  			Operator: config.Operator{
   162  				Versions: &deployer.Versions{
   163  					CA: map[string]deployer.VersionCA{
   164  						"1.4.9-0": {
   165  							Default: true,
   166  							Image: deployer.CAImages{
   167  								CAImage:     "caimage",
   168  								CATag:       "1.4.9",
   169  								CAInitImage: "cainitimage",
   170  								CAInitTag:   "1.4.9",
   171  							},
   172  						},
   173  					},
   174  				},
   175  			},
   176  		}
   177  
   178  		deploymentMgr.ExistsReturns(true)
   179  		ca = &baseca.CA{
   180  			DeploymentManager:     deploymentMgr,
   181  			ServiceManager:        serviceMgr,
   182  			PVCManager:            pvcMgr,
   183  			RoleManager:           roleMgr,
   184  			RoleBindingManager:    roleBindingMgr,
   185  			ServiceAccountManager: serviceAccountMgr,
   186  			Client:                mockKubeClient,
   187  			Scheme:                &runtime.Scheme{},
   188  			Override:              &override.Override{},
   189  			Config:                config,
   190  			Initializer:           initMock,
   191  			Restart:               restartMgr,
   192  			CertificateManager:    certMgr,
   193  		}
   194  	})
   195  
   196  	Context("Reconciles", func() {
   197  		It("requeues request and returns nil if instance version is updated", func() {
   198  			instance.Status.CRStatus.Version = ""
   199  			_, err := ca.Reconcile(instance, update)
   200  			Expect(err).NotTo(HaveOccurred())
   201  			Expect(mockKubeClient.PatchStatusCallCount()).To(Equal(1))
   202  		})
   203  
   204  		It("returns a breaking error if initialization fails", func() {
   205  			initMock.HandleEnrollmentCAInitReturns(nil, errors.New("failed to init"))
   206  			_, err := ca.Reconcile(instance, update)
   207  			Expect(err).To(HaveOccurred())
   208  			Expect(err.Error()).To(ContainSubstring("Code: 20 - failed to initialize ca: failed to init"))
   209  			Expect(operatorerrors.IsBreakingError(err, "msg", nil)).NotTo(HaveOccurred())
   210  		})
   211  
   212  		It("returns an error for invalid HSM endpoint", func() {
   213  			instance.Spec.HSM.PKCS11Endpoint = "tcp://:2345"
   214  			_, err := ca.Reconcile(instance, update)
   215  			Expect(err).To(HaveOccurred())
   216  			Expect(err.Error()).To(Equal(fmt.Sprintf("failed pre reconcile checks: invalid HSM endpoint for ca instance '%s': missing IP address", instance.Name)))
   217  		})
   218  
   219  		It("returns an error domain is not set", func() {
   220  			instance.Spec.Domain = ""
   221  			_, err := ca.Reconcile(instance, update)
   222  			Expect(err).To(HaveOccurred())
   223  			Expect(err.Error()).To(Equal(fmt.Sprintf("failed pre reconcile checks: domain not set for ca instance '%s'", instance.Name)))
   224  		})
   225  
   226  		It("returns an error if pvc manager fails to reconcile", func() {
   227  			pvcMgr.ReconcileReturns(errors.New("failed to reconcile pvc"))
   228  			_, err := ca.Reconcile(instance, update)
   229  			Expect(err).To(HaveOccurred())
   230  			Expect(err.Error()).To(Equal("failed to reconcile managers: failed PVC reconciliation: failed to reconcile pvc"))
   231  		})
   232  
   233  		It("returns an error if service manager fails to reconcile", func() {
   234  			serviceMgr.ReconcileReturns(errors.New("failed to reconcile service"))
   235  			_, err := ca.Reconcile(instance, update)
   236  			Expect(err).To(HaveOccurred())
   237  			Expect(err.Error()).To(Equal("failed to reconcile managers: failed Service reconciliation: failed to reconcile service"))
   238  		})
   239  
   240  		It("returns an error if role manager fails to reconcile", func() {
   241  			roleMgr.ReconcileReturns(errors.New("failed to reconcile role"))
   242  			_, err := ca.Reconcile(instance, update)
   243  			Expect(err).To(HaveOccurred())
   244  			Expect(err.Error()).To(ContainSubstring("failed to reconcile role"))
   245  		})
   246  
   247  		It("returns an error if role binding manager fails to reconcile", func() {
   248  			roleBindingMgr.ReconcileReturns(errors.New("failed to reconcile role binding"))
   249  			_, err := ca.Reconcile(instance, update)
   250  			Expect(err).To(HaveOccurred())
   251  			Expect(err.Error()).To(ContainSubstring("failed to reconcile role binding"))
   252  		})
   253  
   254  		It("returns an error if service account manager fails to reconcile", func() {
   255  			serviceAccountMgr.ReconcileReturns(errors.New("failed to reconcile service account"))
   256  			_, err := ca.Reconcile(instance, update)
   257  			Expect(err).To(HaveOccurred())
   258  			Expect(err.Error()).To(ContainSubstring("failed to reconcile service account"))
   259  		})
   260  
   261  		It("returns an error if deployment manager fails to reconcile", func() {
   262  			deploymentMgr.ReconcileReturns(errors.New("failed to reconcile deployment"))
   263  			_, err := ca.Reconcile(instance, update)
   264  			Expect(err).To(HaveOccurred())
   265  			Expect(err.Error()).To(Equal("failed to reconcile managers: failed Deployment reconciliation: failed to reconcile deployment"))
   266  		})
   267  
   268  		It("returns an error if restart fails", func() {
   269  			update.RestartNeededReturns(true)
   270  			mockKubeClient.PatchReturns(errors.New("patch failed"))
   271  			_, err := ca.Reconcile(instance, update)
   272  			Expect(err).Should(MatchError(ContainSubstring("patch failed")))
   273  		})
   274  
   275  		It("reconciles IBPCA", func() {
   276  			_, err := ca.Reconcile(instance, update)
   277  			Expect(err).NotTo(HaveOccurred())
   278  		})
   279  	})
   280  
   281  	Context("initialize", func() {
   282  		It("returns an error if enrollment ca init fails", func() {
   283  			msg := "failed to init enrollment ca"
   284  			initMock.HandleEnrollmentCAInitReturns(nil, errors.New(msg))
   285  			err := ca.Initialize(instance, update)
   286  			Expect(err).To(HaveOccurred())
   287  			Expect(err.Error()).To(Equal(msg))
   288  		})
   289  
   290  		It("returns an error if unable to create create config resources for enrollment ca", func() {
   291  			msg := "failed to create config resources for enrollment ca"
   292  			initMock.HandleEnrollmentCAInitReturns(&initializer.Response{}, nil)
   293  			initMock.HandleConfigResourcesReturns(errors.New(msg))
   294  			err := ca.Initialize(instance, update)
   295  			Expect(err).To(HaveOccurred())
   296  			Expect(err.Error()).To(Equal(msg))
   297  		})
   298  
   299  		It("returns an error if tls ca init fails", func() {
   300  			msg := "failed to init tls ca"
   301  			initMock.HandleTLSCAInitReturns(nil, errors.New(msg))
   302  			err := ca.Initialize(instance, update)
   303  			Expect(err).To(HaveOccurred())
   304  			Expect(err.Error()).To(Equal(msg))
   305  		})
   306  
   307  		It("returns an error if unable to create create config resources for tls ca", func() {
   308  			msg := "failed to create config resources for tls ca"
   309  			initMock.HandleEnrollmentCAInitReturns(&initializer.Response{Config: &v1.ServerConfig{}}, nil)
   310  			initMock.HandleTLSCAInitReturns(&initializer.Response{Config: &v1.ServerConfig{}}, nil)
   311  			initMock.HandleConfigResourcesReturnsOnCall(1, errors.New(msg))
   312  			err := ca.Initialize(instance, update)
   313  			Expect(err).To(HaveOccurred())
   314  			Expect(err.Error()).To(Equal(msg))
   315  		})
   316  
   317  		It("triggers deployment restart if deployment exists and overrides update detected", func() {
   318  			deploymentMgr.ExistsReturns(true)
   319  			update.ConfigOverridesUpdatedReturns(true)
   320  
   321  			err := ca.Initialize(instance, update)
   322  			Expect(err).NotTo(HaveOccurred())
   323  			Expect(restartMgr.ForConfigOverrideCallCount()).To(Equal(1))
   324  		})
   325  	})
   326  
   327  	Context("AddTLSCryptoIfMissing", func() {
   328  		It("adds tls crypto", func() {
   329  			mockKubeClient.GetReturns(errors.New("fake error"))
   330  			err := ca.AddTLSCryptoIfMissing(instance, &current.CAEndpoints{})
   331  			Expect(err).NotTo(HaveOccurred())
   332  
   333  			caOverrides := &v1.ServerConfig{}
   334  			err = json.Unmarshal(instance.Spec.ConfigOverride.CA.Raw, caOverrides)
   335  			Expect(err).NotTo(HaveOccurred())
   336  
   337  			Expect(caOverrides.TLS.CertFile).NotTo(Equal(""))
   338  			Expect(caOverrides.TLS.KeyFile).NotTo(Equal(""))
   339  		})
   340  	})
   341  
   342  	Context("image overrides", func() {
   343  		var images *current.CAImages
   344  
   345  		Context("using registry url", func() {
   346  			BeforeEach(func() {
   347  				images = &current.CAImages{
   348  					CAImage:     "caimage",
   349  					CATag:       "2.0.0",
   350  					CAInitImage: "cainitimage",
   351  					CAInitTag:   "2.0.0",
   352  				}
   353  			})
   354  
   355  			It("overrides images based with registry url and does not append more value on each call", func() {
   356  				images.Override(images, "ghcr.io/ibm-blockchain/", "amd64")
   357  				Expect(images.CAImage).To(Equal("ghcr.io/ibm-blockchain/caimage"))
   358  				Expect(images.CATag).To(Equal("2.0.0"))
   359  				Expect(images.CAInitImage).To(Equal("ghcr.io/ibm-blockchain/cainitimage"))
   360  				Expect(images.CAInitTag).To(Equal("2.0.0"))
   361  			})
   362  
   363  			It("overrides images based with registry url and does not append more value on each call", func() {
   364  				images.Override(images, "ghcr.io/ibm-blockchain/images/", "s390x")
   365  				Expect(images.CAImage).To(Equal("ghcr.io/ibm-blockchain/images/caimage"))
   366  				Expect(images.CATag).To(Equal("2.0.0"))
   367  				Expect(images.CAInitImage).To(Equal("ghcr.io/ibm-blockchain/images/cainitimage"))
   368  				Expect(images.CAInitTag).To(Equal("2.0.0"))
   369  
   370  			})
   371  		})
   372  
   373  		Context("using fully qualified path", func() {
   374  			BeforeEach(func() {
   375  				images = &current.CAImages{
   376  					CAImage:     "ghcr.io/ibm-blockchain/caimage",
   377  					CATag:       "2.0.0",
   378  					CAInitImage: "ghcr.io/ibm-blockchain/cainitimage",
   379  					CAInitTag:   "2.0.0",
   380  				}
   381  			})
   382  
   383  			It("keeps images and adds arch to tag", func() {
   384  				images.Override(images, "", "s390")
   385  				Expect(images.CAImage).To(Equal("ghcr.io/ibm-blockchain/caimage"))
   386  				Expect(images.CATag).To(Equal("2.0.0"))
   387  				Expect(images.CAInitImage).To(Equal("ghcr.io/ibm-blockchain/cainitimage"))
   388  				Expect(images.CAInitTag).To(Equal("2.0.0"))
   389  			})
   390  		})
   391  	})
   392  
   393  	Context("pre reconcile checks", func() {
   394  		Context("version and images", func() {
   395  			Context("create CR", func() {
   396  				It("returns an error if fabric version is not set in spec", func() {
   397  					instance.Spec.FabricVersion = ""
   398  					_, err := ca.PreReconcileChecks(instance, update)
   399  					Expect(err).To(MatchError(ContainSubstring("fabric version is not set")))
   400  				})
   401  
   402  				Context("images section blank", func() {
   403  					BeforeEach(func() {
   404  						instance.Spec.Images = nil
   405  					})
   406  
   407  					It("normalizes fabric version and requests a requeue", func() {
   408  						instance.Spec.FabricVersion = "1.4.9"
   409  						requeue, err := ca.PreReconcileChecks(instance, update)
   410  						Expect(err).NotTo(HaveOccurred())
   411  						Expect(requeue).To(Equal(true))
   412  						Expect(instance.Spec.FabricVersion).To(Equal("1.4.9-0"))
   413  					})
   414  
   415  					It("returns an error if fabric version not supported", func() {
   416  						instance.Spec.FabricVersion = "0.0.1"
   417  						_, err := ca.PreReconcileChecks(instance, update)
   418  						Expect(err).To(MatchError(ContainSubstring("fabric version '0.0.1' is not supported")))
   419  					})
   420  
   421  					When("version is passed without hyphen", func() {
   422  						BeforeEach(func() {
   423  							instance.Spec.FabricVersion = "1.4.9"
   424  						})
   425  
   426  						It("finds default version for release and updates images section", func() {
   427  							requeue, err := ca.PreReconcileChecks(instance, update)
   428  							Expect(err).NotTo(HaveOccurred())
   429  							Expect(requeue).To(Equal(true))
   430  							Expect(*instance.Spec.Images).To(Equal(current.CAImages{
   431  								CAImage:     "caimage",
   432  								CATag:       "1.4.9",
   433  								CAInitImage: "cainitimage",
   434  								CAInitTag:   "1.4.9",
   435  							}))
   436  						})
   437  					})
   438  
   439  					When("version is passed with hyphen", func() {
   440  						BeforeEach(func() {
   441  							instance.Spec.FabricVersion = "1.4.9-0"
   442  						})
   443  
   444  						It("looks images and updates images section", func() {
   445  							requeue, err := ca.PreReconcileChecks(instance, update)
   446  							Expect(err).NotTo(HaveOccurred())
   447  							Expect(requeue).To(Equal(true))
   448  							Expect(*instance.Spec.Images).To(Equal(current.CAImages{
   449  								CAImage:     "caimage",
   450  								CATag:       "1.4.9",
   451  								CAInitImage: "cainitimage",
   452  								CAInitTag:   "1.4.9",
   453  							}))
   454  						})
   455  					})
   456  				})
   457  
   458  				Context("images section passed", func() {
   459  					BeforeEach(func() {
   460  						instance.Spec.Images = &current.CAImages{
   461  							CAImage:     "ghcr.io/ibm-blockchain/caimage",
   462  							CATag:       "2.0.0",
   463  							CAInitImage: "ghcr.io/ibm-blockchain/cainitimage",
   464  							CAInitTag:   "2.0.0",
   465  						}
   466  					})
   467  
   468  					When("version is not passed", func() {
   469  						BeforeEach(func() {
   470  							instance.Spec.FabricVersion = ""
   471  						})
   472  
   473  						It("returns an error", func() {
   474  							_, err := ca.PreReconcileChecks(instance, update)
   475  							Expect(err).To(MatchError(ContainSubstring("fabric version is not set")))
   476  						})
   477  					})
   478  
   479  					When("version is passed", func() {
   480  						BeforeEach(func() {
   481  							instance.Spec.FabricVersion = "2.0.0-8"
   482  						})
   483  
   484  						It("persists current spec configuration", func() {
   485  							requeue, err := ca.PreReconcileChecks(instance, update)
   486  							Expect(err).NotTo(HaveOccurred())
   487  							Expect(requeue).To(Equal(false))
   488  							Expect(instance.Spec.FabricVersion).To(Equal("2.0.0-8"))
   489  							Expect(*instance.Spec.Images).To(Equal(current.CAImages{
   490  								CAImage:     "ghcr.io/ibm-blockchain/caimage",
   491  								CATag:       "2.0.0",
   492  								CAInitImage: "ghcr.io/ibm-blockchain/cainitimage",
   493  								CAInitTag:   "2.0.0",
   494  							}))
   495  						})
   496  					})
   497  				})
   498  			})
   499  
   500  			Context("update CR", func() {
   501  				BeforeEach(func() {
   502  					instance.Spec.FabricVersion = "2.0.1-0"
   503  					instance.Spec.Images = &current.CAImages{
   504  						CAImage:     "ghcr.io/ibm-blockchain/caimage",
   505  						CATag:       "2.0.1",
   506  						CAInitImage: "ghcr.io/ibm-blockchain/cainitimage",
   507  						CAInitTag:   "2.0.1",
   508  					}
   509  				})
   510  
   511  				When("images updated", func() {
   512  					BeforeEach(func() {
   513  						update.ImagesUpdatedReturns(true)
   514  						instance.Spec.Images = &current.CAImages{
   515  							CAImage:     "ghcr.io/ibm-blockchain/caimage",
   516  							CATag:       "2.0.8",
   517  							CAInitImage: "ghcr.io/ibm-blockchain/cainitimage",
   518  							CAInitTag:   "2.0.8",
   519  						}
   520  					})
   521  
   522  					Context("and version updated", func() {
   523  						BeforeEach(func() {
   524  							update.FabricVersionUpdatedReturns(true)
   525  							instance.Spec.FabricVersion = "2.0.1-8"
   526  						})
   527  
   528  						It("persists current spec configuration", func() {
   529  							requeue, err := ca.PreReconcileChecks(instance, update)
   530  							Expect(err).NotTo(HaveOccurred())
   531  							Expect(requeue).To(Equal(false))
   532  							Expect(instance.Spec.FabricVersion).To(Equal("2.0.1-8"))
   533  							Expect(*instance.Spec.Images).To(Equal(current.CAImages{
   534  								CAImage:     "ghcr.io/ibm-blockchain/caimage",
   535  								CATag:       "2.0.8",
   536  								CAInitImage: "ghcr.io/ibm-blockchain/cainitimage",
   537  								CAInitTag:   "2.0.8",
   538  							}))
   539  						})
   540  					})
   541  
   542  					Context("and version not updated", func() {
   543  						It("persists current spec configuration", func() {
   544  							requeue, err := ca.PreReconcileChecks(instance, update)
   545  							Expect(err).NotTo(HaveOccurred())
   546  							Expect(requeue).To(Equal(false))
   547  							Expect(instance.Spec.FabricVersion).To(Equal("2.0.1-0"))
   548  							Expect(*instance.Spec.Images).To(Equal(current.CAImages{
   549  								CAImage:     "ghcr.io/ibm-blockchain/caimage",
   550  								CATag:       "2.0.8",
   551  								CAInitImage: "ghcr.io/ibm-blockchain/cainitimage",
   552  								CAInitTag:   "2.0.8",
   553  							}))
   554  						})
   555  					})
   556  				})
   557  
   558  				When("images not updated", func() {
   559  					Context("and version updated during operator migration", func() {
   560  						BeforeEach(func() {
   561  							update.FabricVersionUpdatedReturns(true)
   562  							instance.Spec.FabricVersion = "unsupported"
   563  						})
   564  
   565  						It("persists current spec configuration", func() {
   566  							requeue, err := ca.PreReconcileChecks(instance, update)
   567  							Expect(err).NotTo(HaveOccurred())
   568  							Expect(requeue).To(Equal(false))
   569  							Expect(instance.Spec.FabricVersion).To(Equal("unsupported"))
   570  							Expect(*instance.Spec.Images).To(Equal(current.CAImages{
   571  								CAImage:     "ghcr.io/ibm-blockchain/caimage",
   572  								CATag:       "2.0.1",
   573  								CAInitImage: "ghcr.io/ibm-blockchain/cainitimage",
   574  								CAInitTag:   "2.0.1",
   575  							}))
   576  						})
   577  					})
   578  
   579  					Context("and version updated (not during operator migration)", func() {
   580  						BeforeEach(func() {
   581  							update.FabricVersionUpdatedReturns(true)
   582  						})
   583  
   584  						When("using non-hyphenated version", func() {
   585  							BeforeEach(func() {
   586  								instance.Spec.FabricVersion = "1.4.9"
   587  							})
   588  
   589  							It("looks images and updates images section", func() {
   590  								requeue, err := ca.PreReconcileChecks(instance, update)
   591  								Expect(err).NotTo(HaveOccurred())
   592  								Expect(requeue).To(Equal(true))
   593  								Expect(instance.Spec.FabricVersion).To(Equal("1.4.9-0"))
   594  								Expect(*instance.Spec.Images).To(Equal(current.CAImages{
   595  									CAImage:     "caimage",
   596  									CATag:       "1.4.9",
   597  									CAInitImage: "cainitimage",
   598  									CAInitTag:   "1.4.9",
   599  								}))
   600  							})
   601  						})
   602  
   603  						When("using hyphenated version", func() {
   604  							BeforeEach(func() {
   605  								instance.Spec.FabricVersion = "1.4.9-0"
   606  							})
   607  
   608  							It("looks images and updates images section", func() {
   609  								requeue, err := ca.PreReconcileChecks(instance, update)
   610  								Expect(err).NotTo(HaveOccurred())
   611  								Expect(requeue).To(Equal(true))
   612  								Expect(instance.Spec.FabricVersion).To(Equal("1.4.9-0"))
   613  								Expect(*instance.Spec.Images).To(Equal(current.CAImages{
   614  									CAImage:     "caimage",
   615  									CATag:       "1.4.9",
   616  									CAInitImage: "cainitimage",
   617  									CAInitTag:   "1.4.9",
   618  								}))
   619  							})
   620  						})
   621  					})
   622  				})
   623  			})
   624  		})
   625  
   626  		Context("hsm image updates", func() {
   627  			var (
   628  				hsmConfig = &commonconfig.HSMConfig{
   629  					Library: commonconfig.Library{
   630  						Image: "ghcr.io/ibm-blockchain/hsmimage:1.0.0",
   631  					},
   632  				}
   633  			)
   634  
   635  			BeforeEach(func() {
   636  				mockKubeClient.GetStub = func(ctx context.Context, types types.NamespacedName, obj client.Object) error {
   637  					switch obj.(type) {
   638  					case *corev1.ConfigMap:
   639  						o := obj.(*corev1.ConfigMap)
   640  
   641  						bytes, err := yaml.Marshal(hsmConfig)
   642  						Expect(err).NotTo(HaveOccurred())
   643  
   644  						o.Data = map[string]string{
   645  							"ibp-hsm-config.yaml": string(bytes),
   646  						}
   647  					}
   648  					return nil
   649  				}
   650  			})
   651  
   652  			It("updates hsm image and tag if passed through operator config", func() {
   653  				updated, err := ca.PreReconcileChecks(instance, update)
   654  				Expect(err).NotTo(HaveOccurred())
   655  				Expect(updated).To(Equal(true))
   656  				Expect(instance.Spec.Images.HSMImage).To(Equal("ghcr.io/ibm-blockchain/hsmimage"))
   657  				Expect(instance.Spec.Images.HSMTag).To(Equal("1.0.0"))
   658  			})
   659  
   660  			It("doesn't update hsm image and tag if hsm update is disabled", func() {
   661  				hsmConfig.Library.AutoUpdateDisabled = true
   662  
   663  				updated, err := ca.PreReconcileChecks(instance, update)
   664  				Expect(err).NotTo(HaveOccurred())
   665  				Expect(updated).To(Equal(false))
   666  				Expect(instance.Spec.Images.HSMImage).To(Equal(""))
   667  				Expect(instance.Spec.Images.HSMTag).To(Equal(""))
   668  			})
   669  		})
   670  	})
   671  
   672  	Context("update connection profile", func() {
   673  		It("returns error if fails to get cert", func() {
   674  			mockKubeClient.GetReturns(errors.New("get error"))
   675  			err := ca.UpdateConnectionProfile(instance)
   676  			Expect(err).To(HaveOccurred())
   677  			Expect(err.Error()).To(ContainSubstring("get error"))
   678  		})
   679  
   680  		It("updates connection profile cm", func() {
   681  			err := ca.UpdateConnectionProfile(instance)
   682  			Expect(err).NotTo(HaveOccurred())
   683  			Expect(mockKubeClient.GetCallCount()).To(Equal(3))
   684  
   685  			_, obj, _ := mockKubeClient.UpdateArgsForCall(0)
   686  			configmap := obj.(*corev1.ConfigMap)
   687  			connectionprofile := &current.CAConnectionProfile{}
   688  			err = json.Unmarshal(configmap.BinaryData["profile.json"], connectionprofile)
   689  			Expect(err).NotTo(HaveOccurred())
   690  
   691  			certEncoded := base64.StdEncoding.EncodeToString([]byte(certBase64))
   692  			Expect(connectionprofile.TLS.Cert).To(Equal(certEncoded))
   693  			Expect(connectionprofile.CA.SignCerts).To(Equal(certEncoded))
   694  			Expect(connectionprofile.TLSCA.SignCerts).To(Equal(certEncoded))
   695  		})
   696  	})
   697  })