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 = ¤t.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: ¤t.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, ¤t.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 })