github.com/IBM-Blockchain/fabric-operator@v1.0.4/pkg/offering/k8s/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 k8sca_test
    20  
    21  import (
    22  	"context"
    23  	"encoding/json"
    24  	"errors"
    25  	"os"
    26  	"path/filepath"
    27  
    28  	"k8s.io/apimachinery/pkg/types"
    29  	"sigs.k8s.io/controller-runtime/pkg/client"
    30  
    31  	. "github.com/onsi/ginkgo/v2"
    32  	. "github.com/onsi/gomega"
    33  	"k8s.io/apimachinery/pkg/runtime"
    34  
    35  	current "github.com/IBM-Blockchain/fabric-operator/api/v1beta1"
    36  	"github.com/IBM-Blockchain/fabric-operator/controllers/mocks"
    37  	config "github.com/IBM-Blockchain/fabric-operator/operatorconfig"
    38  	cav1 "github.com/IBM-Blockchain/fabric-operator/pkg/apis/ca/v1"
    39  	"github.com/IBM-Blockchain/fabric-operator/pkg/apis/deployer"
    40  	initializer "github.com/IBM-Blockchain/fabric-operator/pkg/initializer/ca"
    41  	managermocks "github.com/IBM-Blockchain/fabric-operator/pkg/manager/resources/mocks"
    42  	baseca "github.com/IBM-Blockchain/fabric-operator/pkg/offering/base/ca"
    43  	basecamocks "github.com/IBM-Blockchain/fabric-operator/pkg/offering/base/ca/mocks"
    44  	k8sca "github.com/IBM-Blockchain/fabric-operator/pkg/offering/k8s/ca"
    45  	override "github.com/IBM-Blockchain/fabric-operator/pkg/offering/k8s/ca/override"
    46  	"github.com/IBM-Blockchain/fabric-operator/pkg/operatorerrors"
    47  	"github.com/IBM-Blockchain/fabric-operator/version"
    48  	corev1 "k8s.io/api/core/v1"
    49  	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
    50  )
    51  
    52  var _ = Describe("K8s CA", func() {
    53  	const (
    54  		defaultConfigs = "../../../../defaultconfig/ca"
    55  		testdataDir    = "../../../../testdata"
    56  
    57  		keyBase64  = "LS0tLS1CRUdJTiBSU0EgUFJJVkFURSBLRVktLS0tLQpNSUlFb2dJQkFBS0NBUUVBdFJBUDlMemUyZEc1cm1rbmcvdVVtREFZU0VwUElqRFdUUDhqUjMxcUJ5Yjc3YWUrCnk3UTRvRnZod1lDVUhsUWVTWjFKeTdUUHpEcitoUk5hdDJYNGdGYUpGYmVFbC9DSHJ3Rk1mNzNzQStWV1pHdnkKdXhtbjB2bEdYMW5zSEo5aUdIUS9qR2FvV1FJYzlVbnpHWi8yWStlZkpxOWd3cDBNemFzWWZkdXordXVBNlp4VAp5TTdDOWFlWmxYL2ZMYmVkSXVXTzVzaXhPSlZQeUVpcWpkd0RiY1AxYy9mRCtSMm1DbmM3VGovSnVLK1poTGxPCnhGcVlFRmtROHBmSi9LY1pabVF1QURZVFh6RGp6OENxcTRTRU5ySzI0b2hQQkN2SGgyanplWjhGdGR4MmpSSFQKaXdCZWZEYWlSWVBSOUM4enk4K1Z2Wmt6S0hQV3N5aENiNUMrN1FJREFRQUJBb0lCQUZROGhzL2IxdW9Mc3BFOApCdEJXaVVsTWh0K0xBc25yWXFncnd5UU5hdmlzNEdRdXVJdFk2MGRmdCtZb2hjQ2ViZ0RkbG1tWlUxdTJ6cGJtCjdEdUt5MVFaN21rV0dpLytEWUlUM3AxSHBMZ2pTRkFzRUorUFRnN1BQamc2UTZrRlZjUCt3Vm4yb0xmWVRkU28KZE5zbEdxSmNMaVQzVHRMNzhlcjFnTTE5RzN6T3J1ZndrSGJSYU1BRmtvZ1ExUlZLSWpnVGUvbmpIMHFHNW9JagoxNEJLeFFKTUZFTG1pQk50NUx5OVMxWWdxTDRjbmNtUDN5L1QyNEdodVhNckx0eTVOeVhnS0dFZ1pUTDMzZzZvCnYreDFFMFRURWRjMVQvWVBGWkdBSXhHdWRKNWZZZ2JtWU9LZ09mUHZFOE9TbEV6OW56aHNnckVZYjdQVThpZDUKTHFycVJRRUNnWUVBNjIyT3RIUmMxaVY1ZXQxdHQydTVTTTlTS2h2b0lPT3d2Q3NnTEI5dDJzNEhRUlRYN0RXcAo0VDNpUC9leEl5OXI3bTIxNFo5MEgzZlpVNElSUkdHSUxKUVMrYzRQNVA4cHJFTDcyd1dIWlpQTTM3QlZTQ1U3CkxOTXl4TkRjeVdjSUJIVFh4NUY2eXhLNVFXWTg5MVB0eDlDamJFSEcrNVJVdDA4UVlMWDlUQTBDZ1lFQXhPSmYKcXFjeThMOVZyYUFVZG9lbGdIU0NGSkJRR3hMRFNSQlJSTkRIOUJhaWlZOCtwZzd2TExTRXFMRFpsbkZPbFkrQQpiRENEQ0RtdHhwRXViY0x6b3FnOXhlQTZ0eXZZWkNWalY5dXVzNVh1Wmk1VDBBUHhCdm56OHNNa3dRY3RQWkRQCk8zQTN4WllkZzJBRmFrV1BmT1FFbjVaK3F4TU13SG9VZ1ZwQkptRUNnWUJ2Q2FjcTJVOEgrWGpJU0ROOU5TT1kKZ1ovaEdIUnRQcmFXcVVodFJ3MkxDMjFFZHM0NExEOUphdVNSQXdQYThuelhZWXROTk9XU0NmYkllaW9tdEZHRApwUHNtTXRnd1MyQ2VUS0Y0OWF5Y2JnOU0yVi8vdlAraDdxS2RUVjAwNkpGUmVNSms3K3FZYU9aVFFDTTFDN0swCmNXVUNwQ3R6Y014Y0FNQmF2THNRNlFLQmdHbXJMYmxEdjUxaXM3TmFKV0Z3Y0MwL1dzbDZvdVBFOERiNG9RV1UKSUowcXdOV2ZvZm95TGNBS3F1QjIrbkU2SXZrMmFiQ25ZTXc3V0w4b0VJa3NodUtYOVgrTVZ6Y1VPekdVdDNyaQpGeU9mcHJJRXowcm5zcWNSNUJJNUZqTGJqVFpyMEMyUWp2NW5FVFAvaHlpQWFRQ1l5THAyWlVtZ0Vjb0VPNWtwClBhcEJBb0dBZVV0WjE0SVp2cVorQnAxR1VqSG9PR0pQVnlJdzhSRUFETjRhZXRJTUlQRWFVaDdjZUtWdVN6VXMKci9WczA1Zjg0cFBVaStuUTUzaGo2ZFhhYTd1UE1aMFBnNFY4cS9UdzJMZ3BWWndVd0ltZUQrcXNsbldha3VWMQpMSnp3SkhOa3pOWE1OMmJWREFZTndSamNRSmhtbzF0V2xHYlpRQjNoSkEwR2thWGZPa2c9Ci0tLS0tRU5EIFJTQSBQUklWQVRFIEtFWS0tLS0tCg=="
    58  		certBase64 = "LS0tLS1CRUdJTiBDRVJUSUZJQ0FURS0tLS0tCk1JSURBekNDQWV1Z0F3SUJBZ0lKQU9xQ1VmaFNjcWtlTUEwR0NTcUdTSWIzRFFFQkJRVUFNQmd4RmpBVUJnTlYKQkFNTURYQnZjM1JuY21WekxuUmxjM1F3SGhjTk1Ua3dOekl6TVRrd09UVTRXaGNOTWprd056SXdNVGt3T1RVNApXakFZTVJZd0ZBWURWUVFEREExd2IzTjBaM0psY3k1MFpYTjBNSUlCSWpBTkJna3Foa2lHOXcwQkFRRUZBQU9DCkFROEFNSUlCQ2dLQ0FRRUF0UkFQOUx6ZTJkRzVybWtuZy91VW1EQVlTRXBQSWpEV1RQOGpSMzFxQnliNzdhZSsKeTdRNG9Gdmh3WUNVSGxRZVNaMUp5N1RQekRyK2hSTmF0Mlg0Z0ZhSkZiZUVsL0NIcndGTWY3M3NBK1ZXWkd2eQp1eG1uMHZsR1gxbnNISjlpR0hRL2pHYW9XUUljOVVuekdaLzJZK2VmSnE5Z3dwME16YXNZZmR1eit1dUE2WnhUCnlNN0M5YWVabFgvZkxiZWRJdVdPNXNpeE9KVlB5RWlxamR3RGJjUDFjL2ZEK1IybUNuYzdUai9KdUsrWmhMbE8KeEZxWUVGa1E4cGZKL0tjWlptUXVBRFlUWHpEano4Q3FxNFNFTnJLMjRvaFBCQ3ZIaDJqemVaOEZ0ZHgyalJIVAppd0JlZkRhaVJZUFI5Qzh6eTgrVnZaa3pLSFBXc3loQ2I1Qys3UUlEQVFBQm8xQXdUakFkQmdOVkhRNEVGZ1FVCi9mZ01BcExIMXBvcFFoS25KTmgrVk04QUtQZ3dId1lEVlIwakJCZ3dGb0FVL2ZnTUFwTEgxcG9wUWhLbkpOaCsKVk04QUtQZ3dEQVlEVlIwVEJBVXdBd0VCL3pBTkJna3Foa2lHOXcwQkFRVUZBQU9DQVFFQURjOUc4M05LaWw3ZQpoVFlvR1piejhFV1o4c0puVnY4azMwRDlydUY1OXFvT0ppZGorQUhNbzNHOWtud1lvbGFGbmJwb093cElOZ3g1CnYvL21aU3VldlFMZUZKRlN1UjBheVQ1WFYxcjljNUZGQ2JSaEp0cE4rOEdTT29tRUFSYTNBVGVFSG5WeVpaYkMKWkFQQUxMVXlVeUVrSDR3Q0RZUGtYa3dWQVVlR2FGVmNqZWR0eGJ3Z2k0dG0rSFZoTEt5Y0NoZ25YUVhxQ2srTwo2RHJIc0Z0STVTNWQvQlBPbE1Yc28vNUFielBGelpVVVg4OEhkVUhWSWlqM0luMXdUbWhtREtwdzZ6dmcvNjIxCjRhcGhDOWJ2bXAxeUVOUklzb0xiMGlMWVAzRSswU0ZkZC9IRnRhVXV3eUx6cnl4R2xrdG1BVUJWNVdYZEQxMkIKTU1mQnhvNFVYUT09Ci0tLS0tRU5EIENFUlRJRklDQVRFLS0tLS0K"
    59  	)
    60  
    61  	AfterEach(func() {
    62  		err := os.RemoveAll("shared")
    63  		Expect(err).NotTo(HaveOccurred())
    64  	})
    65  
    66  	var (
    67  		ca             *k8sca.CA
    68  		instance       *current.IBPCA
    69  		mockKubeClient *mocks.Client
    70  
    71  		deploymentMgr     *managermocks.ResourceManager
    72  		serviceMgr        *managermocks.ResourceManager
    73  		pvcMgr            *managermocks.ResourceManager
    74  		roleMgr           *managermocks.ResourceManager
    75  		roleBindingMgr    *managermocks.ResourceManager
    76  		serviceAccountMgr *managermocks.ResourceManager
    77  		ingressMgr        *managermocks.ResourceManager
    78  
    79  		initMock *basecamocks.InitializeIBPCA
    80  		update   *basecamocks.Update
    81  		certMgr  *basecamocks.CertificateManager
    82  	)
    83  
    84  	Context("Reconciles", func() {
    85  		BeforeEach(func() {
    86  			mockKubeClient = &mocks.Client{}
    87  			update = &basecamocks.Update{}
    88  
    89  			replicas := int32(1)
    90  			instance = &current.IBPCA{
    91  				TypeMeta: metav1.TypeMeta{
    92  					Kind: "IBPCA",
    93  				},
    94  				ObjectMeta: metav1.ObjectMeta{
    95  					Name:      "ca1",
    96  					Namespace: "test",
    97  				},
    98  				Spec: current.IBPCASpec{
    99  					Domain:        "domain",
   100  					Replicas:      &replicas,
   101  					Images:        &current.CAImages{},
   102  					FabricVersion: "1.4.9-0",
   103  				},
   104  				Status: current.IBPCAStatus{
   105  					CRStatus: current.CRStatus{
   106  						Version: version.Operator,
   107  					},
   108  				},
   109  			}
   110  
   111  			mockKubeClient.GetStub = func(ctx context.Context, types types.NamespacedName, obj client.Object) error {
   112  				switch obj.(type) {
   113  				case *corev1.Secret:
   114  					o := obj.(*corev1.Secret)
   115  					switch types.Name {
   116  					case instance.Name + "-ca-crypto":
   117  						o.Name = instance.Name + "-ca-crypto"
   118  						o.Namespace = instance.Namespace
   119  						o.Data = map[string][]byte{"tls-cert.pem": []byte(certBase64)}
   120  					case instance.Name + "-tlsca-crypto":
   121  						o.Name = instance.Name + "-tlsca-crypto"
   122  						o.Namespace = instance.Namespace
   123  						o.Data = map[string][]byte{"cert.pem": []byte(certBase64)}
   124  					}
   125  				}
   126  				return nil
   127  			}
   128  
   129  			deploymentMgr = &managermocks.ResourceManager{}
   130  			serviceMgr = &managermocks.ResourceManager{}
   131  			pvcMgr = &managermocks.ResourceManager{}
   132  			roleMgr = &managermocks.ResourceManager{}
   133  			roleBindingMgr = &managermocks.ResourceManager{}
   134  			serviceAccountMgr = &managermocks.ResourceManager{}
   135  			ingressMgr = &managermocks.ResourceManager{}
   136  			initMock = &basecamocks.InitializeIBPCA{}
   137  			restartMgr := &basecamocks.RestartManager{}
   138  			certMgr = &basecamocks.CertificateManager{}
   139  
   140  			config := &config.Config{
   141  				CAInitConfig: &initializer.Config{
   142  					CADefaultConfigPath:     filepath.Join(defaultConfigs, "/ca.yaml"),
   143  					CAOverrideConfigPath:    filepath.Join(testdataDir, "init/override.yaml"),
   144  					TLSCADefaultConfigPath:  filepath.Join(defaultConfigs, "tlsca.yaml"),
   145  					TLSCAOverrideConfigPath: filepath.Join(testdataDir, "init/override.yaml"),
   146  					SharedPath:              "shared",
   147  				},
   148  				Operator: config.Operator{
   149  					Versions: &deployer.Versions{
   150  						CA: map[string]deployer.VersionCA{
   151  							"1.4.9-0": {},
   152  						},
   153  					},
   154  				},
   155  			}
   156  
   157  			certMgr.GetSecretReturns(&corev1.Secret{}, nil)
   158  			deploymentMgr.ExistsReturns(true)
   159  			ca = &k8sca.CA{
   160  				CA: &baseca.CA{
   161  					DeploymentManager:     deploymentMgr,
   162  					ServiceManager:        serviceMgr,
   163  					PVCManager:            pvcMgr,
   164  					RoleManager:           roleMgr,
   165  					RoleBindingManager:    roleBindingMgr,
   166  					ServiceAccountManager: serviceAccountMgr,
   167  					Client:                mockKubeClient,
   168  					Scheme:                &runtime.Scheme{},
   169  					Override:              &override.Override{},
   170  					Config:                config,
   171  					Initializer:           initMock,
   172  					Restart:               restartMgr,
   173  					CertificateManager:    certMgr,
   174  				},
   175  				IngressManager: ingressMgr,
   176  				Override:       &override.Override{},
   177  			}
   178  		})
   179  
   180  		It("returns a breaking error if initialization fails", func() {
   181  			initMock.HandleEnrollmentCAInitReturns(nil, errors.New("failed to init"))
   182  			_, err := ca.Reconcile(instance, update)
   183  			Expect(err).To(HaveOccurred())
   184  			Expect(err.Error()).To(ContainSubstring("Code: 20 - failed to initialize ca: failed to init"))
   185  			Expect(operatorerrors.IsBreakingError(err, "msg", nil)).NotTo(HaveOccurred())
   186  		})
   187  
   188  		It("returns an error if pvc manager fails to reconcile", func() {
   189  			pvcMgr.ReconcileReturns(errors.New("failed to reconcile pvc"))
   190  			_, err := ca.Reconcile(instance, update)
   191  			Expect(err).To(HaveOccurred())
   192  			Expect(err.Error()).To(Equal("failed to reconcile managers: failed PVC reconciliation: failed to reconcile pvc"))
   193  		})
   194  
   195  		It("returns an error if service manager fails to reconcile", func() {
   196  			serviceMgr.ReconcileReturns(errors.New("failed to reconcile service"))
   197  			_, err := ca.Reconcile(instance, update)
   198  			Expect(err).To(HaveOccurred())
   199  			Expect(err.Error()).To(Equal("failed to reconcile managers: failed Service reconciliation: failed to reconcile service"))
   200  		})
   201  
   202  		It("returns an error if role manager fails to reconcile", func() {
   203  			roleMgr.ReconcileReturns(errors.New("failed to reconcile role"))
   204  			_, err := ca.Reconcile(instance, update)
   205  			Expect(err).To(HaveOccurred())
   206  			Expect(err.Error()).To(ContainSubstring("failed to reconcile role"))
   207  		})
   208  
   209  		It("returns an error if role binding manager fails to reconcile", func() {
   210  			roleBindingMgr.ReconcileReturns(errors.New("failed to reconcile role binding"))
   211  			_, err := ca.Reconcile(instance, update)
   212  			Expect(err).To(HaveOccurred())
   213  			Expect(err.Error()).To(ContainSubstring("failed to reconcile role binding"))
   214  		})
   215  
   216  		It("returns an error if service account manager fails to reconcile", func() {
   217  			serviceAccountMgr.ReconcileReturns(errors.New("failed to reconcile service account"))
   218  			_, err := ca.Reconcile(instance, update)
   219  			Expect(err).To(HaveOccurred())
   220  			Expect(err.Error()).To(ContainSubstring("failed to reconcile service account"))
   221  		})
   222  
   223  		It("returns an error if deployment manager fails to reconcile", func() {
   224  			deploymentMgr.ReconcileReturns(errors.New("failed to reconcile deployment"))
   225  			_, err := ca.Reconcile(instance, update)
   226  			Expect(err).To(HaveOccurred())
   227  			Expect(err.Error()).To(Equal("failed to reconcile managers: failed Deployment reconciliation: failed to reconcile deployment"))
   228  		})
   229  
   230  		It("returns an error if deployment manager fails to reconcile", func() {
   231  			ingressMgr.ReconcileReturns(errors.New("failed to reconcile ingress"))
   232  			_, err := ca.Reconcile(instance, update)
   233  			Expect(err).To(HaveOccurred())
   234  			Expect(err.Error()).To(Equal("failed to reconcile managers: failed Ingress reconciliation: failed to reconcile ingress"))
   235  		})
   236  
   237  		It("returns an error if restart fails", func() {
   238  			update.RestartNeededReturns(true)
   239  			mockKubeClient.PatchReturns(errors.New("patch failed"))
   240  			_, err := ca.Reconcile(instance, update)
   241  			Expect(err).Should(MatchError(ContainSubstring("patch failed")))
   242  		})
   243  
   244  		It("reconciles IBPCA", func() {
   245  			_, err := ca.Reconcile(instance, update)
   246  			Expect(err).NotTo(HaveOccurred())
   247  		})
   248  	})
   249  
   250  	Context("AddTLSCryptoIfMissing", func() {
   251  		It("adds tls crypto", func() {
   252  			mockKubeClient.GetReturns(errors.New("fake error"))
   253  			err := ca.AddTLSCryptoIfMissing(instance, &current.CAEndpoints{})
   254  			Expect(err).NotTo(HaveOccurred())
   255  
   256  			caOverrides := &cav1.ServerConfig{}
   257  			err = json.Unmarshal(instance.Spec.ConfigOverride.CA.Raw, caOverrides)
   258  			Expect(err).NotTo(HaveOccurred())
   259  
   260  			Expect(caOverrides.TLS.CertFile).NotTo(Equal(""))
   261  			Expect(caOverrides.TLS.KeyFile).NotTo(Equal(""))
   262  		})
   263  	})
   264  })