github.com/IBM-Blockchain/fabric-operator@v1.0.4/pkg/offering/base/peer/peer_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 basepeer_test 20 21 import ( 22 "context" 23 "crypto/ecdsa" 24 "crypto/elliptic" 25 "crypto/rand" 26 "crypto/x509" 27 "encoding/pem" 28 "fmt" 29 "math/big" 30 "time" 31 32 k8serrors "k8s.io/apimachinery/pkg/api/errors" 33 34 current "github.com/IBM-Blockchain/fabric-operator/api/v1beta1" 35 cmocks "github.com/IBM-Blockchain/fabric-operator/controllers/mocks" 36 config "github.com/IBM-Blockchain/fabric-operator/operatorconfig" 37 commonapi "github.com/IBM-Blockchain/fabric-operator/pkg/apis/common" 38 "github.com/IBM-Blockchain/fabric-operator/pkg/apis/deployer" 39 v1 "github.com/IBM-Blockchain/fabric-operator/pkg/apis/peer/v1" 40 "github.com/IBM-Blockchain/fabric-operator/pkg/certificate" 41 commonconfig "github.com/IBM-Blockchain/fabric-operator/pkg/initializer/common/config" 42 "github.com/IBM-Blockchain/fabric-operator/pkg/initializer/common/enroller" 43 "github.com/IBM-Blockchain/fabric-operator/pkg/initializer/common/mspparser" 44 peerinit "github.com/IBM-Blockchain/fabric-operator/pkg/initializer/peer" 45 pconfig "github.com/IBM-Blockchain/fabric-operator/pkg/initializer/peer/config/v1" 46 managermocks "github.com/IBM-Blockchain/fabric-operator/pkg/manager/resources/mocks" 47 basepeer "github.com/IBM-Blockchain/fabric-operator/pkg/offering/base/peer" 48 "github.com/IBM-Blockchain/fabric-operator/pkg/offering/base/peer/mocks" 49 peermocks "github.com/IBM-Blockchain/fabric-operator/pkg/offering/base/peer/mocks" 50 "github.com/IBM-Blockchain/fabric-operator/pkg/operatorerrors" 51 "github.com/IBM-Blockchain/fabric-operator/pkg/util" 52 "github.com/IBM-Blockchain/fabric-operator/version" 53 . "github.com/onsi/ginkgo/v2" 54 . "github.com/onsi/gomega" 55 "github.com/pkg/errors" 56 corev1 "k8s.io/api/core/v1" 57 k8serror "k8s.io/apimachinery/pkg/api/errors" 58 metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" 59 "k8s.io/apimachinery/pkg/runtime" 60 "k8s.io/apimachinery/pkg/runtime/schema" 61 "k8s.io/apimachinery/pkg/types" 62 "k8s.io/apimachinery/pkg/util/intstr" 63 "sigs.k8s.io/controller-runtime/pkg/client" 64 "sigs.k8s.io/yaml" 65 ) 66 67 var _ = Describe("Base Peer", func() { 68 var ( 69 peer *basepeer.Peer 70 instance *current.IBPPeer 71 mockKubeClient *cmocks.Client 72 cfg *config.Config 73 74 deploymentMgr *peermocks.DeploymentManager 75 serviceMgr *managermocks.ResourceManager 76 pvcMgr *managermocks.ResourceManager 77 couchPvcMgr *managermocks.ResourceManager 78 configMapMgr *managermocks.ResourceManager 79 roleMgr *managermocks.ResourceManager 80 roleBindingMgr *managermocks.ResourceManager 81 serviceAccountMgr *managermocks.ResourceManager 82 83 certificateMgr *peermocks.CertificateManager 84 initializer *peermocks.InitializeIBPPeer 85 update *mocks.Update 86 ) 87 88 BeforeEach(func() { 89 mockKubeClient = &cmocks.Client{} 90 update = &mocks.Update{} 91 92 replicas := int32(1) 93 instance = ¤t.IBPPeer{ 94 Spec: current.IBPPeerSpec{ 95 PeerExternalEndpoint: "address", 96 Domain: "domain", 97 HSM: ¤t.HSM{ 98 PKCS11Endpoint: "tcp://0.0.0.0:2347", 99 }, 100 StateDb: "couchdb", 101 Images: ¤t.PeerImages{ 102 PeerTag: "1.4.7-20200611", 103 }, 104 Replicas: &replicas, 105 FabricVersion: "1.4.9", 106 }, 107 } 108 instance.Kind = "IBPPeer" 109 instance.Name = "peer1" 110 instance.Namespace = "random" 111 112 mockKubeClient.GetStub = func(ctx context.Context, types types.NamespacedName, obj client.Object) error { 113 switch obj.(type) { 114 case *current.IBPPeer: 115 o := obj.(*current.IBPPeer) 116 o.Kind = "IBPPeer" 117 instance = o 118 case *corev1.Service: 119 o := obj.(*corev1.Service) 120 o.Spec.Type = corev1.ServiceTypeNodePort 121 o.Spec.Ports = append(o.Spec.Ports, corev1.ServicePort{ 122 Name: "peer-api", 123 TargetPort: intstr.IntOrString{ 124 IntVal: 7051, 125 }, 126 NodePort: int32(7051), 127 }) 128 case *corev1.Secret: 129 o := obj.(*corev1.Secret) 130 switch types.Name { 131 case "tls-" + instance.Name + "-signcert": 132 o.Name = "tls-" + instance.Name + "-signcert" 133 o.Namespace = instance.Namespace 134 o.Data = map[string][]byte{"cert.pem": []byte("LS0tLS1CRUdJTiBDRVJUSUZJQ0FURS0tLS0tCk1JSUNwVENDQWtxZ0F3SUJBZ0lSQU1FeVZVcDRMdlYydEFUREhlWklldDh3Q2dZSUtvWkl6ajBFQXdJd2daVXgKQ3pBSkJnTlZCQVlUQWxWVE1SY3dGUVlEVlFRSUV3NU9iM0owYUNCRFlYSnZiR2x1WVRFUE1BMEdBMVVFQnhNRwpSSFZ5YUdGdE1Rd3dDZ1lEVlFRS0V3TkpRazB4RXpBUkJnTlZCQXNUQ2tKc2IyTnJZMmhoYVc0eE9UQTNCZ05WCkJBTVRNR3BoYmpJeUxXOXlaR1Z5WlhKdmNtZGpZUzFqWVM1aGNIQnpMbkIxYldGekxtOXpMbVo1Y21VdWFXSnQKTG1OdmJUQWVGdzB5TURBeE1qSXhPREExTURCYUZ3MHpNREF4TVRreE9EQTFNREJhTUlHVk1Rc3dDUVlEVlFRRwpFd0pWVXpFWE1CVUdBMVVFQ0JNT1RtOXlkR2dnUTJGeWIyeHBibUV4RHpBTkJnTlZCQWNUQmtSMWNtaGhiVEVNCk1Bb0dBMVVFQ2hNRFNVSk5NUk13RVFZRFZRUUxFd3BDYkc5amEyTm9ZV2x1TVRrd053WURWUVFERXpCcVlXNHkKTWkxdmNtUmxjbVZ5YjNKblkyRXRZMkV1WVhCd2N5NXdkVzFoY3k1dmN5NW1lWEpsTG1saWJTNWpiMjB3V1RBVApCZ2NxaGtqT1BRSUJCZ2dxaGtqT1BRTUJCd05DQUFTR0lHUFkvZC9tQVhMejM4SlROR3F5bldpOTJXUVB6cnN0Cm5vdEFWZlh0dHZ5QWJXdTRNbWNUMEh6UnBTWjNDcGdxYUNXcTg1MUwyV09LcnZ6L0JPREpvM2t3ZHpCMUJnTlYKSFJFRWJqQnNnakJxWVc0eU1pMXZjbVJsY21WeWIzSm5ZMkV0WTJFdVlYQndjeTV3ZFcxaGN5NXZjeTVtZVhKbApMbWxpYlM1amIyMkNPR3BoYmpJeUxXOXlaR1Z5WlhKdmNtZGpZUzF2Y0dWeVlYUnBiMjV6TG1Gd2NITXVjSFZ0CllYTXViM011Wm5seVpTNXBZbTB1WTI5dE1Bb0dDQ3FHU000OUJBTUNBMGtBTUVZQ0lRQzM3Y1pkNFY2RThPQ1IKaDloQXEyK0dyR21FVTFQU0I1eHo5RkdEWThkODZRSWhBT1crM3Urb2d4bFNWNUoyR3ZYbHRaQmpXRkpvYnJxeApwVVQ4cW4yMDA1b0wKLS0tLS1FTkQgQ0VSVElGSUNBVEUtLS0tLQo")} 135 case "tls-" + instance.Name + "-keystore": 136 o.Name = "tls-" + instance.Name + "-keystore" 137 o.Namespace = instance.Namespace 138 o.Data = map[string][]byte{"key.pem": []byte("LS0tLS1CRUdJTiBDRVJUSUZJQ0FURS0tLS0tCk1JSUNwVENDQWtxZ0F3SUJBZ0lSQU1FeVZVcDRMdlYydEFUREhlWklldDh3Q2dZSUtvWkl6ajBFQXdJd2daVXgKQ3pBSkJnTlZCQVlUQWxWVE1SY3dGUVlEVlFRSUV3NU9iM0owYUNCRFlYSnZiR2x1WVRFUE1BMEdBMVVFQnhNRwpSSFZ5YUdGdE1Rd3dDZ1lEVlFRS0V3TkpRazB4RXpBUkJnTlZCQXNUQ2tKc2IyTnJZMmhoYVc0eE9UQTNCZ05WCkJBTVRNR3BoYmpJeUxXOXlaR1Z5WlhKdmNtZGpZUzFqWVM1aGNIQnpMbkIxYldGekxtOXpMbVo1Y21VdWFXSnQKTG1OdmJUQWVGdzB5TURBeE1qSXhPREExTURCYUZ3MHpNREF4TVRreE9EQTFNREJhTUlHVk1Rc3dDUVlEVlFRRwpFd0pWVXpFWE1CVUdBMVVFQ0JNT1RtOXlkR2dnUTJGeWIyeHBibUV4RHpBTkJnTlZCQWNUQmtSMWNtaGhiVEVNCk1Bb0dBMVVFQ2hNRFNVSk5NUk13RVFZRFZRUUxFd3BDYkc5amEyTm9ZV2x1TVRrd053WURWUVFERXpCcVlXNHkKTWkxdmNtUmxjbVZ5YjNKblkyRXRZMkV1WVhCd2N5NXdkVzFoY3k1dmN5NW1lWEpsTG1saWJTNWpiMjB3V1RBVApCZ2NxaGtqT1BRSUJCZ2dxaGtqT1BRTUJCd05DQUFTR0lHUFkvZC9tQVhMejM4SlROR3F5bldpOTJXUVB6cnN0Cm5vdEFWZlh0dHZ5QWJXdTRNbWNUMEh6UnBTWjNDcGdxYUNXcTg1MUwyV09LcnZ6L0JPREpvM2t3ZHpCMUJnTlYKSFJFRWJqQnNnakJxWVc0eU1pMXZjbVJsY21WeWIzSm5ZMkV0WTJFdVlYQndjeTV3ZFcxaGN5NXZjeTVtZVhKbApMbWxpYlM1amIyMkNPR3BoYmpJeUxXOXlaR1Z5WlhKdmNtZGpZUzF2Y0dWeVlYUnBiMjV6TG1Gd2NITXVjSFZ0CllYTXViM011Wm5seVpTNXBZbTB1WTI5dE1Bb0dDQ3FHU000OUJBTUNBMGtBTUVZQ0lRQzM3Y1pkNFY2RThPQ1IKaDloQXEyK0dyR21FVTFQU0I1eHo5RkdEWThkODZRSWhBT1crM3Urb2d4bFNWNUoyR3ZYbHRaQmpXRkpvYnJxeApwVVQ4cW4yMDA1b0wKLS0tLS1FTkQgQ0VSVElGSUNBVEUtLS0tLQo")} 139 case "tls-" + instance.Name + "-cacerts": 140 o.Name = "tls-" + instance.Name + "-cacerts" 141 o.Namespace = instance.Namespace 142 o.Data = map[string][]byte{"key.pem": []byte("LS0tLS1CRUdJTiBDRVJUSUZJQ0FURS0tLS0tCk1JSUNwVENDQWtxZ0F3SUJBZ0lSQU1FeVZVcDRMdlYydEFUREhlWklldDh3Q2dZSUtvWkl6ajBFQXdJd2daVXgKQ3pBSkJnTlZCQVlUQWxWVE1SY3dGUVlEVlFRSUV3NU9iM0owYUNCRFlYSnZiR2x1WVRFUE1BMEdBMVVFQnhNRwpSSFZ5YUdGdE1Rd3dDZ1lEVlFRS0V3TkpRazB4RXpBUkJnTlZCQXNUQ2tKc2IyTnJZMmhoYVc0eE9UQTNCZ05WCkJBTVRNR3BoYmpJeUxXOXlaR1Z5WlhKdmNtZGpZUzFqWVM1aGNIQnpMbkIxYldGekxtOXpMbVo1Y21VdWFXSnQKTG1OdmJUQWVGdzB5TURBeE1qSXhPREExTURCYUZ3MHpNREF4TVRreE9EQTFNREJhTUlHVk1Rc3dDUVlEVlFRRwpFd0pWVXpFWE1CVUdBMVVFQ0JNT1RtOXlkR2dnUTJGeWIyeHBibUV4RHpBTkJnTlZCQWNUQmtSMWNtaGhiVEVNCk1Bb0dBMVVFQ2hNRFNVSk5NUk13RVFZRFZRUUxFd3BDYkc5amEyTm9ZV2x1TVRrd053WURWUVFERXpCcVlXNHkKTWkxdmNtUmxjbVZ5YjNKblkyRXRZMkV1WVhCd2N5NXdkVzFoY3k1dmN5NW1lWEpsTG1saWJTNWpiMjB3V1RBVApCZ2NxaGtqT1BRSUJCZ2dxaGtqT1BRTUJCd05DQUFTR0lHUFkvZC9tQVhMejM4SlROR3F5bldpOTJXUVB6cnN0Cm5vdEFWZlh0dHZ5QWJXdTRNbWNUMEh6UnBTWjNDcGdxYUNXcTg1MUwyV09LcnZ6L0JPREpvM2t3ZHpCMUJnTlYKSFJFRWJqQnNnakJxWVc0eU1pMXZjbVJsY21WeWIzSm5ZMkV0WTJFdVlYQndjeTV3ZFcxaGN5NXZjeTVtZVhKbApMbWxpYlM1amIyMkNPR3BoYmpJeUxXOXlaR1Z5WlhKdmNtZGpZUzF2Y0dWeVlYUnBiMjV6TG1Gd2NITXVjSFZ0CllYTXViM011Wm5seVpTNXBZbTB1WTI5dE1Bb0dDQ3FHU000OUJBTUNBMGtBTUVZQ0lRQzM3Y1pkNFY2RThPQ1IKaDloQXEyK0dyR21FVTFQU0I1eHo5RkdEWThkODZRSWhBT1crM3Urb2d4bFNWNUoyR3ZYbHRaQmpXRkpvYnJxeApwVVQ4cW4yMDA1b0wKLS0tLS1FTkQgQ0VSVElGSUNBVEUtLS0tLQo")} 143 case "ecert-" + instance.Name + "-signcert": 144 o.Name = "ecert-" + instance.Name + "-signcert" 145 o.Namespace = instance.Namespace 146 o.Data = map[string][]byte{"cert.pem": []byte("LS0tLS1CRUdJTiBDRVJUSUZJQ0FURS0tLS0tCk1JSUNwVENDQWtxZ0F3SUJBZ0lSQU1FeVZVcDRMdlYydEFUREhlWklldDh3Q2dZSUtvWkl6ajBFQXdJd2daVXgKQ3pBSkJnTlZCQVlUQWxWVE1SY3dGUVlEVlFRSUV3NU9iM0owYUNCRFlYSnZiR2x1WVRFUE1BMEdBMVVFQnhNRwpSSFZ5YUdGdE1Rd3dDZ1lEVlFRS0V3TkpRazB4RXpBUkJnTlZCQXNUQ2tKc2IyTnJZMmhoYVc0eE9UQTNCZ05WCkJBTVRNR3BoYmpJeUxXOXlaR1Z5WlhKdmNtZGpZUzFqWVM1aGNIQnpMbkIxYldGekxtOXpMbVo1Y21VdWFXSnQKTG1OdmJUQWVGdzB5TURBeE1qSXhPREExTURCYUZ3MHpNREF4TVRreE9EQTFNREJhTUlHVk1Rc3dDUVlEVlFRRwpFd0pWVXpFWE1CVUdBMVVFQ0JNT1RtOXlkR2dnUTJGeWIyeHBibUV4RHpBTkJnTlZCQWNUQmtSMWNtaGhiVEVNCk1Bb0dBMVVFQ2hNRFNVSk5NUk13RVFZRFZRUUxFd3BDYkc5amEyTm9ZV2x1TVRrd053WURWUVFERXpCcVlXNHkKTWkxdmNtUmxjbVZ5YjNKblkyRXRZMkV1WVhCd2N5NXdkVzFoY3k1dmN5NW1lWEpsTG1saWJTNWpiMjB3V1RBVApCZ2NxaGtqT1BRSUJCZ2dxaGtqT1BRTUJCd05DQUFTR0lHUFkvZC9tQVhMejM4SlROR3F5bldpOTJXUVB6cnN0Cm5vdEFWZlh0dHZ5QWJXdTRNbWNUMEh6UnBTWjNDcGdxYUNXcTg1MUwyV09LcnZ6L0JPREpvM2t3ZHpCMUJnTlYKSFJFRWJqQnNnakJxWVc0eU1pMXZjbVJsY21WeWIzSm5ZMkV0WTJFdVlYQndjeTV3ZFcxaGN5NXZjeTVtZVhKbApMbWxpYlM1amIyMkNPR3BoYmpJeUxXOXlaR1Z5WlhKdmNtZGpZUzF2Y0dWeVlYUnBiMjV6TG1Gd2NITXVjSFZ0CllYTXViM011Wm5seVpTNXBZbTB1WTI5dE1Bb0dDQ3FHU000OUJBTUNBMGtBTUVZQ0lRQzM3Y1pkNFY2RThPQ1IKaDloQXEyK0dyR21FVTFQU0I1eHo5RkdEWThkODZRSWhBT1crM3Urb2d4bFNWNUoyR3ZYbHRaQmpXRkpvYnJxeApwVVQ4cW4yMDA1b0wKLS0tLS1FTkQgQ0VSVElGSUNBVEUtLS0tLQo")} 147 case "ecert-" + instance.Name + "-cacerts": 148 o.Name = "ecert-" + instance.Name + "-cacerts" 149 o.Namespace = instance.Namespace 150 o.Data = map[string][]byte{"cacert-0.pem": []byte("LS0tLS1CRUdJTiBDRVJUSUZJQ0FURS0tLS0tCk1JSUNwVENDQWtxZ0F3SUJBZ0lSQU1FeVZVcDRMdlYydEFUREhlWklldDh3Q2dZSUtvWkl6ajBFQXdJd2daVXgKQ3pBSkJnTlZCQVlUQWxWVE1SY3dGUVlEVlFRSUV3NU9iM0owYUNCRFlYSnZiR2x1WVRFUE1BMEdBMVVFQnhNRwpSSFZ5YUdGdE1Rd3dDZ1lEVlFRS0V3TkpRazB4RXpBUkJnTlZCQXNUQ2tKc2IyTnJZMmhoYVc0eE9UQTNCZ05WCkJBTVRNR3BoYmpJeUxXOXlaR1Z5WlhKdmNtZGpZUzFqWVM1aGNIQnpMbkIxYldGekxtOXpMbVo1Y21VdWFXSnQKTG1OdmJUQWVGdzB5TURBeE1qSXhPREExTURCYUZ3MHpNREF4TVRreE9EQTFNREJhTUlHVk1Rc3dDUVlEVlFRRwpFd0pWVXpFWE1CVUdBMVVFQ0JNT1RtOXlkR2dnUTJGeWIyeHBibUV4RHpBTkJnTlZCQWNUQmtSMWNtaGhiVEVNCk1Bb0dBMVVFQ2hNRFNVSk5NUk13RVFZRFZRUUxFd3BDYkc5amEyTm9ZV2x1TVRrd053WURWUVFERXpCcVlXNHkKTWkxdmNtUmxjbVZ5YjNKblkyRXRZMkV1WVhCd2N5NXdkVzFoY3k1dmN5NW1lWEpsTG1saWJTNWpiMjB3V1RBVApCZ2NxaGtqT1BRSUJCZ2dxaGtqT1BRTUJCd05DQUFTR0lHUFkvZC9tQVhMejM4SlROR3F5bldpOTJXUVB6cnN0Cm5vdEFWZlh0dHZ5QWJXdTRNbWNUMEh6UnBTWjNDcGdxYUNXcTg1MUwyV09LcnZ6L0JPREpvM2t3ZHpCMUJnTlYKSFJFRWJqQnNnakJxWVc0eU1pMXZjbVJsY21WeWIzSm5ZMkV0WTJFdVlYQndjeTV3ZFcxaGN5NXZjeTVtZVhKbApMbWxpYlM1amIyMkNPR3BoYmpJeUxXOXlaR1Z5WlhKdmNtZGpZUzF2Y0dWeVlYUnBiMjV6TG1Gd2NITXVjSFZ0CllYTXViM011Wm5seVpTNXBZbTB1WTI5dE1Bb0dDQ3FHU000OUJBTUNBMGtBTUVZQ0lRQzM3Y1pkNFY2RThPQ1IKaDloQXEyK0dyR21FVTFQU0I1eHo5RkdEWThkODZRSWhBT1crM3Urb2d4bFNWNUoyR3ZYbHRaQmpXRkpvYnJxeApwVVQ4cW4yMDA1b0wKLS0tLS1FTkQgQ0VSVElGSUNBVEUtLS0tLQo")} 151 } 152 } 153 return nil 154 } 155 instance.Status.Version = version.Operator 156 157 deploymentMgr = &peermocks.DeploymentManager{} 158 serviceMgr = &managermocks.ResourceManager{} 159 pvcMgr = &managermocks.ResourceManager{} 160 couchPvcMgr = &managermocks.ResourceManager{} 161 configMapMgr = &managermocks.ResourceManager{} 162 roleMgr = &managermocks.ResourceManager{} 163 roleBindingMgr = &managermocks.ResourceManager{} 164 serviceAccountMgr = &managermocks.ResourceManager{} 165 166 scheme := &runtime.Scheme{} 167 cfg = &config.Config{ 168 PeerInitConfig: &peerinit.Config{ 169 OUFile: "../../../../defaultconfig/peer/ouconfig.yaml", 170 CorePeerFile: "../../../../defaultconfig/peer/core.yaml", 171 }, 172 Operator: config.Operator{ 173 Versions: &deployer.Versions{ 174 Peer: map[string]deployer.VersionPeer{ 175 "1.4.9-0": { 176 Default: true, 177 Image: deployer.PeerImages{ 178 PeerImage: "peerimage", 179 PeerTag: "1.4.9", 180 PeerInitImage: "peerinitimage", 181 PeerInitTag: "1.4.9", 182 }, 183 }, 184 }, 185 }, 186 }, 187 } 188 initializer = &peermocks.InitializeIBPPeer{} 189 initializer.GetInitPeerReturns(&peerinit.Peer{}, nil) 190 191 certificateMgr = &peermocks.CertificateManager{} 192 restartMgr := &peermocks.RestartManager{} 193 peer = &basepeer.Peer{ 194 Client: mockKubeClient, 195 Scheme: scheme, 196 Config: cfg, 197 198 DeploymentManager: deploymentMgr, 199 ServiceManager: serviceMgr, 200 PVCManager: pvcMgr, 201 StateDBPVCManager: couchPvcMgr, 202 FluentDConfigMapManager: configMapMgr, 203 RoleManager: roleMgr, 204 RoleBindingManager: roleBindingMgr, 205 ServiceAccountManager: serviceAccountMgr, 206 Initializer: initializer, 207 208 CertificateManager: certificateMgr, 209 RenewCertTimers: make(map[string]*time.Timer), 210 211 Restart: restartMgr, 212 } 213 }) 214 215 Context("pre reconcile checks", func() { 216 Context("version and images", func() { 217 Context("create CR", func() { 218 It("returns an error if fabric version is not set in spec", func() { 219 instance.Spec.FabricVersion = "" 220 _, err := peer.PreReconcileChecks(instance, update) 221 Expect(err).To(MatchError(ContainSubstring("fabric version is not set"))) 222 }) 223 224 Context("images section blank", func() { 225 BeforeEach(func() { 226 instance.Spec.Images = nil 227 }) 228 229 It("normalizes fabric version and requests a requeue", func() { 230 instance.Spec.FabricVersion = "1.4.9" 231 requeue, err := peer.PreReconcileChecks(instance, update) 232 Expect(err).NotTo(HaveOccurred()) 233 Expect(requeue).To(Equal(true)) 234 Expect(instance.Spec.FabricVersion).To(Equal("1.4.9-0")) 235 }) 236 237 It("returns an error if fabric version not supported", func() { 238 instance.Spec.FabricVersion = "0.0.1" 239 _, err := peer.PreReconcileChecks(instance, update) 240 Expect(err).To(MatchError(ContainSubstring("fabric version '0.0.1' is not supported"))) 241 }) 242 243 When("version is passed without hyphen", func() { 244 BeforeEach(func() { 245 instance.Spec.FabricVersion = "1.4.9" 246 }) 247 248 It("finds default version for release and updates images section", func() { 249 requeue, err := peer.PreReconcileChecks(instance, update) 250 Expect(err).NotTo(HaveOccurred()) 251 Expect(requeue).To(Equal(true)) 252 Expect(*instance.Spec.Images).To(Equal(current.PeerImages{ 253 PeerImage: "peerimage", 254 PeerTag: "1.4.9", 255 PeerInitImage: "peerinitimage", 256 PeerInitTag: "1.4.9", 257 })) 258 }) 259 }) 260 261 When("version is passed with hyphen", func() { 262 BeforeEach(func() { 263 instance.Spec.FabricVersion = "1.4.9-0" 264 }) 265 266 It("looks images and updates images section", func() { 267 requeue, err := peer.PreReconcileChecks(instance, update) 268 Expect(err).NotTo(HaveOccurred()) 269 Expect(requeue).To(Equal(true)) 270 Expect(*instance.Spec.Images).To(Equal(current.PeerImages{ 271 PeerImage: "peerimage", 272 PeerTag: "1.4.9", 273 PeerInitImage: "peerinitimage", 274 PeerInitTag: "1.4.9", 275 })) 276 }) 277 }) 278 }) 279 280 Context("images section passed", func() { 281 BeforeEach(func() { 282 instance.Spec.Images = ¤t.PeerImages{ 283 PeerImage: "ghcr.io/ibm-blockchain/peerimage", 284 PeerTag: "2.0.0", 285 PeerInitImage: "ghcr.io/ibm-blockchain/peerinitimage", 286 PeerInitTag: "2.0.0", 287 } 288 }) 289 290 When("version is not passed", func() { 291 BeforeEach(func() { 292 instance.Spec.FabricVersion = "" 293 }) 294 295 It("returns an error", func() { 296 _, err := peer.PreReconcileChecks(instance, update) 297 Expect(err).To(MatchError(ContainSubstring("fabric version is not set"))) 298 }) 299 }) 300 301 When("version is passed", func() { 302 BeforeEach(func() { 303 instance.Spec.FabricVersion = "2.0.0-8" 304 }) 305 306 It("persists current spec configuration", func() { 307 requeue, err := peer.PreReconcileChecks(instance, update) 308 Expect(err).NotTo(HaveOccurred()) 309 Expect(requeue).To(Equal(false)) 310 Expect(instance.Spec.FabricVersion).To(Equal("2.0.0-8")) 311 Expect(*instance.Spec.Images).To(Equal(current.PeerImages{ 312 PeerImage: "ghcr.io/ibm-blockchain/peerimage", 313 PeerTag: "2.0.0", 314 PeerInitImage: "ghcr.io/ibm-blockchain/peerinitimage", 315 PeerInitTag: "2.0.0", 316 })) 317 }) 318 }) 319 }) 320 }) 321 322 Context("update CR", func() { 323 BeforeEach(func() { 324 instance.Spec.FabricVersion = "2.0.1-0" 325 instance.Spec.Images = ¤t.PeerImages{ 326 PeerImage: "ghcr.io/ibm-blockchain/peerimage", 327 PeerTag: "2.0.1", 328 PeerInitImage: "ghcr.io/ibm-blockchain/peerinitimage", 329 PeerInitTag: "2.0.1", 330 } 331 }) 332 333 When("images updated", func() { 334 BeforeEach(func() { 335 update.ImagesUpdatedReturns(true) 336 instance.Spec.Images = ¤t.PeerImages{ 337 PeerImage: "ghcr.io/ibm-blockchain/peerimage", 338 PeerTag: "2.0.8", 339 PeerInitImage: "ghcr.io/ibm-blockchain/peerinitimage", 340 PeerInitTag: "2.0.8", 341 } 342 }) 343 344 Context("and version updated", func() { 345 BeforeEach(func() { 346 update.FabricVersionUpdatedReturns(true) 347 instance.Spec.FabricVersion = "2.0.1-8" 348 }) 349 350 It("persists current spec configuration", func() { 351 requeue, err := peer.PreReconcileChecks(instance, update) 352 Expect(err).NotTo(HaveOccurred()) 353 Expect(requeue).To(Equal(false)) 354 Expect(instance.Spec.FabricVersion).To(Equal("2.0.1-8")) 355 Expect(*instance.Spec.Images).To(Equal(current.PeerImages{ 356 PeerImage: "ghcr.io/ibm-blockchain/peerimage", 357 PeerTag: "2.0.8", 358 PeerInitImage: "ghcr.io/ibm-blockchain/peerinitimage", 359 PeerInitTag: "2.0.8", 360 })) 361 }) 362 }) 363 364 Context("and version not updated", func() { 365 It("persists current spec configuration", func() { 366 requeue, err := peer.PreReconcileChecks(instance, update) 367 Expect(err).NotTo(HaveOccurred()) 368 Expect(requeue).To(Equal(false)) 369 Expect(instance.Spec.FabricVersion).To(Equal("2.0.1-0")) 370 Expect(*instance.Spec.Images).To(Equal(current.PeerImages{ 371 PeerImage: "ghcr.io/ibm-blockchain/peerimage", 372 PeerTag: "2.0.8", 373 PeerInitImage: "ghcr.io/ibm-blockchain/peerinitimage", 374 PeerInitTag: "2.0.8", 375 })) 376 }) 377 }) 378 }) 379 380 When("images not updated", func() { 381 Context("and version updated during operator migration", func() { 382 BeforeEach(func() { 383 update.FabricVersionUpdatedReturns(true) 384 instance.Spec.FabricVersion = "unsupported" 385 }) 386 387 It("persists current spec configuration", func() { 388 requeue, err := peer.PreReconcileChecks(instance, update) 389 Expect(err).NotTo(HaveOccurred()) 390 Expect(requeue).To(Equal(false)) 391 Expect(instance.Spec.FabricVersion).To(Equal("unsupported")) 392 Expect(*instance.Spec.Images).To(Equal(current.PeerImages{ 393 PeerImage: "ghcr.io/ibm-blockchain/peerimage", 394 PeerTag: "2.0.1", 395 PeerInitImage: "ghcr.io/ibm-blockchain/peerinitimage", 396 PeerInitTag: "2.0.1", 397 })) 398 }) 399 }) 400 401 Context("and version updated (not during operator migration)", func() { 402 BeforeEach(func() { 403 update.FabricVersionUpdatedReturns(true) 404 }) 405 406 When("using non-hyphenated version", func() { 407 BeforeEach(func() { 408 instance.Spec.FabricVersion = "1.4.9" 409 }) 410 411 It("looks images and updates images section", func() { 412 requeue, err := peer.PreReconcileChecks(instance, update) 413 Expect(err).NotTo(HaveOccurred()) 414 Expect(requeue).To(Equal(true)) 415 Expect(instance.Spec.FabricVersion).To(Equal("1.4.9-0")) 416 Expect(*instance.Spec.Images).To(Equal(current.PeerImages{ 417 PeerImage: "peerimage", 418 PeerTag: "1.4.9", 419 PeerInitImage: "peerinitimage", 420 PeerInitTag: "1.4.9", 421 })) 422 }) 423 }) 424 425 When("using hyphenated version", func() { 426 BeforeEach(func() { 427 instance.Spec.FabricVersion = "1.4.9-0" 428 }) 429 430 It("looks images and updates images section", func() { 431 instance.Spec.RegistryURL = "test.cr" 432 requeue, err := peer.PreReconcileChecks(instance, update) 433 Expect(err).NotTo(HaveOccurred()) 434 Expect(requeue).To(Equal(true)) 435 Expect(instance.Spec.FabricVersion).To(Equal("1.4.9-0")) 436 Expect(*instance.Spec.Images).To(Equal(current.PeerImages{ 437 PeerImage: "test.cr/peerimage", 438 PeerTag: "1.4.9", 439 PeerInitImage: "test.cr/peerinitimage", 440 PeerInitTag: "1.4.9", 441 })) 442 }) 443 }) 444 }) 445 }) 446 }) 447 }) 448 }) 449 450 Context("Reconciles", func() { 451 It("returns nil and requeues request if instance version updated", func() { 452 instance.Status.Version = "" 453 _, err := peer.Reconcile(instance, update) 454 Expect(err).NotTo(HaveOccurred()) 455 Expect(mockKubeClient.PatchStatusCallCount()).To(Equal(1)) 456 }) 457 It("returns a breaking error if initialization fails", func() { 458 cfg.PeerInitConfig.CorePeerFile = "../../../../../defaultconfig/peer/badfile.yaml" 459 peer.Initializer = peerinit.New(cfg.PeerInitConfig, nil, nil, nil, nil, enroller.HSMEnrollJobTimeouts{}) 460 _, err := peer.Reconcile(instance, update) 461 Expect(err).To(HaveOccurred()) 462 Expect(err.Error()).To(ContainSubstring("Code: 22 - failed to initialize peer: open")) 463 Expect(operatorerrors.IsBreakingError(err, "msg", nil)).NotTo(HaveOccurred()) 464 }) 465 466 It("returns an error for invalid HSM endpoint", func() { 467 instance.Spec.HSM.PKCS11Endpoint = "tcp://:2347" 468 _, err := peer.Reconcile(instance, update) 469 Expect(err).To(HaveOccurred()) 470 Expect(err.Error()).To(Equal(fmt.Sprintf("failed pre reconcile checks: invalid HSM endpoint for peer instance '%s': missing IP address", instance.Name))) 471 }) 472 473 It("returns an error domain is not set", func() { 474 instance.Spec.Domain = "" 475 _, err := peer.Reconcile(instance, update) 476 Expect(err).To(HaveOccurred()) 477 Expect(err.Error()).To(Equal(fmt.Sprintf("failed pre reconcile checks: domain not set for peer instance '%s'", instance.Name))) 478 }) 479 480 It("returns an error if both enroll and reenroll action for ecert set to true", func() { 481 instance.Spec.Action.Enroll.Ecert = true 482 instance.Spec.Action.Reenroll.Ecert = true 483 _, err := peer.Reconcile(instance, update) 484 Expect(err).To(HaveOccurred()) 485 Expect(err.Error()).To(Equal("failed pre reconcile checks: both enroll and renenroll action requested for ecert, must only select one")) 486 }) 487 488 It("returns an error if both enroll and reenroll action for TLS cert set to true", func() { 489 instance.Spec.Action.Enroll.TLSCert = true 490 instance.Spec.Action.Reenroll.TLSCert = true 491 _, err := peer.Reconcile(instance, update) 492 Expect(err).To(HaveOccurred()) 493 Expect(err.Error()).To(Equal("failed pre reconcile checks: both enroll and renenroll action requested for TLS cert, must only select one")) 494 }) 495 496 It("returns an error if pvc manager fails to reconcile", func() { 497 pvcMgr.ReconcileReturns(errors.New("failed to reconcile pvc")) 498 _, err := peer.Reconcile(instance, update) 499 Expect(err).To(HaveOccurred()) 500 Expect(err.Error()).To(Equal("failed to reconcile managers: failed PVC reconciliation: failed to reconcile pvc")) 501 }) 502 503 It("returns an error if couch pvc manager fails to reconcile", func() { 504 couchPvcMgr.ReconcileReturns(errors.New("failed to reconcile couch pvc")) 505 _, err := peer.Reconcile(instance, update) 506 Expect(err).To(HaveOccurred()) 507 Expect(err.Error()).To(Equal("failed to reconcile managers: failed CouchDB PVC reconciliation: failed to reconcile couch pvc")) 508 }) 509 510 It("returns an error if service manager fails to reconcile", func() { 511 serviceMgr.ReconcileReturns(errors.New("failed to reconcile service")) 512 _, err := peer.Reconcile(instance, update) 513 Expect(err).To(HaveOccurred()) 514 Expect(err.Error()).To(Equal("failed to reconcile managers: failed Service reconciliation: failed to reconcile service")) 515 }) 516 517 It("returns an error if deployment manager fails to reconcile", func() { 518 deploymentMgr.ReconcileReturns(errors.New("failed to reconcile deployment")) 519 _, err := peer.Reconcile(instance, update) 520 Expect(err).To(HaveOccurred()) 521 Expect(err.Error()).To(Equal("failed to reconcile managers: failed Deployment reconciliation: failed to reconcile deployment")) 522 }) 523 524 It("returns an error if role manager fails to reconcile", func() { 525 roleMgr.ReconcileReturns(errors.New("failed to reconcile role")) 526 _, err := peer.Reconcile(instance, update) 527 Expect(err).To(HaveOccurred()) 528 Expect(err.Error()).To(ContainSubstring("failed to reconcile role")) 529 }) 530 531 It("returns an error if role binding manager fails to reconcile", func() { 532 roleBindingMgr.ReconcileReturns(errors.New("failed to reconcile role binding")) 533 _, err := peer.Reconcile(instance, update) 534 Expect(err).To(HaveOccurred()) 535 Expect(err.Error()).To(ContainSubstring("failed to reconcile role binding")) 536 }) 537 538 It("returns an error if service account binding manager fails to reconcile", func() { 539 serviceAccountMgr.ReconcileReturns(errors.New("failed to reconcile service account")) 540 _, err := peer.Reconcile(instance, update) 541 Expect(err).To(HaveOccurred()) 542 Expect(err.Error()).To(ContainSubstring("failed to reconcile service account")) 543 }) 544 545 It("returns an error if config map manager fails to reconcile", func() { 546 configMapMgr.ReconcileReturns(errors.New("failed to reconcile config map")) 547 _, err := peer.Reconcile(instance, update) 548 Expect(err).To(HaveOccurred()) 549 Expect(err.Error()).To(Equal("failed to reconcile managers: failed FluentD ConfigMap reconciliation: failed to reconcile config map")) 550 }) 551 552 It("does not return an error on a successful reconcile", func() { 553 _, err := peer.Reconcile(instance, update) 554 Expect(err).NotTo(HaveOccurred()) 555 }) 556 }) 557 558 Context("secret", func() { 559 It("does not try to create secret if the get request returns an error other than 'not found'", func() { 560 errMsg := "connection refused" 561 mockKubeClient.GetReturns(errors.New(errMsg)) 562 err := peer.ReconcileSecret(instance) 563 Expect(err).To(HaveOccurred()) 564 Expect(err.Error()).To(Equal(errMsg)) 565 }) 566 567 When("secret does not exist", func() { 568 BeforeEach(func() { 569 notFoundErr := &k8serror.StatusError{ 570 ErrStatus: metav1.Status{ 571 Reason: metav1.StatusReasonNotFound, 572 }, 573 } 574 mockKubeClient.GetReturns(notFoundErr) 575 }) 576 577 It("returns an error if the creation of the Secret fails", func() { 578 errMsg := "unable to create secret" 579 mockKubeClient.CreateReturns(errors.New(errMsg)) 580 err := peer.ReconcileSecret(instance) 581 Expect(err).To(HaveOccurred()) 582 Expect(err.Error()).To(Equal(errMsg)) 583 }) 584 585 It("does not return an error on a successfull secret creation", func() { 586 err := peer.ReconcileSecret(instance) 587 Expect(err).NotTo(HaveOccurred()) 588 }) 589 }) 590 }) 591 592 Context("check csr hosts", func() { 593 It("adds csr hosts if not present", func() { 594 instance = ¤t.IBPPeer{ 595 Spec: current.IBPPeerSpec{ 596 Secret: ¤t.SecretSpec{ 597 Enrollment: ¤t.EnrollmentSpec{}, 598 }, 599 }, 600 } 601 hosts := []string{"test.com", "127.0.0.1"} 602 peer.CheckCSRHosts(instance, hosts) 603 Expect(instance.Spec.Secret.Enrollment.TLS).NotTo(BeNil()) 604 Expect(instance.Spec.Secret.Enrollment.TLS.CSR).NotTo(BeNil()) 605 Expect(instance.Spec.Secret.Enrollment.TLS.CSR.Hosts).To(Equal(hosts)) 606 }) 607 608 It("appends csr hosts if passed", func() { 609 hostsCustom := []string{"custom.domain.com"} 610 hosts := []string{"test.com", "127.0.0.1"} 611 instance = ¤t.IBPPeer{ 612 Spec: current.IBPPeerSpec{ 613 Secret: ¤t.SecretSpec{ 614 Enrollment: ¤t.EnrollmentSpec{ 615 TLS: ¤t.Enrollment{ 616 CSR: ¤t.CSR{ 617 Hosts: hostsCustom, 618 }, 619 }, 620 }, 621 }, 622 }, 623 } 624 peer.CheckCSRHosts(instance, hosts) 625 Expect(instance.Spec.Secret.Enrollment.TLS).NotTo(BeNil()) 626 Expect(instance.Spec.Secret.Enrollment.TLS.CSR).NotTo(BeNil()) 627 Expect(instance.Spec.Secret.Enrollment.TLS.CSR.Hosts).To(ContainElement(hostsCustom[0])) 628 Expect(instance.Spec.Secret.Enrollment.TLS.CSR.Hosts).To(ContainElement(hosts[0])) 629 Expect(instance.Spec.Secret.Enrollment.TLS.CSR.Hosts).To(ContainElement(hosts[1])) 630 }) 631 }) 632 Context("check certificates", func() { 633 It("returns error if fails to get certificate expiry info", func() { 634 certificateMgr.CheckCertificatesForExpireReturns("", "", errors.New("cert expiry error")) 635 _, err := peer.CheckCertificates(instance) 636 Expect(err).To(HaveOccurred()) 637 }) 638 639 It("sets cr status with certificate expiry info", func() { 640 certificateMgr.CheckCertificatesForExpireReturns(current.Warning, "message", nil) 641 status, err := peer.CheckCertificates(instance) 642 Expect(err).NotTo(HaveOccurred()) 643 Expect(status.Type).To(Equal(current.Warning)) 644 Expect(status.Message).To(Equal("message")) 645 Expect(status.Reason).To(Equal("certRenewalRequired")) 646 }) 647 }) 648 649 Context("set certificate timer", func() { 650 BeforeEach(func() { 651 instance.Spec.Secret = ¤t.SecretSpec{ 652 Enrollment: ¤t.EnrollmentSpec{ 653 TLS: ¤t.Enrollment{ 654 EnrollID: "enrollID", 655 }, 656 }, 657 } 658 mockKubeClient.GetStub = func(ctx context.Context, types types.NamespacedName, obj client.Object) error { 659 switch obj.(type) { 660 case *current.IBPPeer: 661 o := obj.(*current.IBPPeer) 662 o.Kind = "IBPPeer" 663 o.Name = "peer1" 664 o.Namespace = "random" 665 o.Spec.Secret = ¤t.SecretSpec{ 666 Enrollment: ¤t.EnrollmentSpec{ 667 TLS: ¤t.Enrollment{ 668 EnrollID: "enrollID", 669 }, 670 }, 671 } 672 case *corev1.Secret: 673 o := obj.(*corev1.Secret) 674 switch types.Name { 675 case "tls-" + instance.Name + "-signcert": 676 o.Name = "tls-" + instance.Name + "-signcert" 677 o.Namespace = instance.Namespace 678 o.Data = map[string][]byte{"cert.pem": generateCertPemBytes(29)} 679 case "tls-" + instance.Name + "-keystore": 680 o.Name = "tls-" + instance.Name + "-keystore" 681 o.Namespace = instance.Namespace 682 o.Data = map[string][]byte{"key.pem": []byte("")} 683 case instance.Name + "-crypto-backup": 684 return k8serrors.NewNotFound(schema.GroupResource{}, "not found") 685 } 686 } 687 return nil 688 } 689 }) 690 691 It("returns error if unable to get duration to next renewal", func() { 692 certificateMgr.GetDurationToNextRenewalReturns(time.Duration(0), errors.New("failed to get duration")) 693 err := peer.SetCertificateTimer(instance, "tls") 694 Expect(err).To(HaveOccurred()) 695 Expect(err.Error()).To(Equal("failed to get duration")) 696 }) 697 698 Context("sets timer to renew TLS certificate", func() { 699 BeforeEach(func() { 700 certificateMgr.GetDurationToNextRenewalReturns(time.Duration(3*time.Second), nil) 701 mockKubeClient.UpdateStatusReturns(nil) 702 certificateMgr.RenewCertReturns(nil) 703 }) 704 705 It("does not return error, but certificate fails to renew after timer", func() { 706 certificateMgr.RenewCertReturns(errors.New("failed to renew cert")) 707 err := peer.SetCertificateTimer(instance, "tls") 708 Expect(err).NotTo(HaveOccurred()) 709 Expect(peer.RenewCertTimers["tls-peer1-signcert"]).NotTo(BeNil()) 710 711 By("certificate fails to be renewed", func() { 712 Eventually(func() bool { 713 return mockKubeClient.UpdateStatusCallCount() == 1 && 714 certificateMgr.RenewCertCallCount() == 1 715 }, time.Duration(5*time.Second)).Should(Equal(true)) 716 }) 717 718 // timer.Stop() == false means that it already fired 719 Expect(peer.RenewCertTimers["tls-peer1-signcert"].Stop()).To(Equal(false)) 720 }) 721 722 It("does not return error, and certificate is successfully renewed after timer", func() { 723 err := peer.SetCertificateTimer(instance, "tls") 724 Expect(err).NotTo(HaveOccurred()) 725 Expect(peer.RenewCertTimers["tls-peer1-signcert"]).NotTo(BeNil()) 726 727 By("certificate successfully renewed", func() { 728 Eventually(func() bool { 729 return mockKubeClient.UpdateStatusCallCount() == 1 && 730 certificateMgr.RenewCertCallCount() == 1 731 }, time.Duration(5*time.Second)).Should(Equal(true)) 732 }) 733 734 // timer.Stop() == false means that it already fired 735 Expect(peer.RenewCertTimers["tls-peer1-signcert"].Stop()).To(Equal(false)) 736 }) 737 738 It("does not return error, and timer is set to renew certificate at a later time", func() { 739 // Set expiration date of certificate to be > 30 days from now 740 certificateMgr.GetDurationToNextRenewalReturns(time.Duration(35*24*time.Hour), nil) 741 742 err := peer.SetCertificateTimer(instance, "tls") 743 Expect(err).NotTo(HaveOccurred()) 744 Expect(peer.RenewCertTimers["tls-peer1-signcert"]).NotTo(BeNil()) 745 746 // timer.Stop() == true means that it has not fired but is now stopped 747 Expect(peer.RenewCertTimers["tls-peer1-signcert"].Stop()).To(Equal(true)) 748 }) 749 }) 750 751 Context("read certificate expiration date to set timer correctly", func() { 752 BeforeEach(func() { 753 peer.CertificateManager = &certificate.CertificateManager{ 754 Client: mockKubeClient, 755 Scheme: &runtime.Scheme{}, 756 } 757 758 // set to 30 days 759 instance.Spec.NumSecondsWarningPeriod = 30 * basepeer.DaysToSecondsConversion 760 }) 761 762 It("doesn't return error if timer is set correctly, but error in renewing certificate when timer goes off", func() { 763 // Set tls signcert expiration date to be 29 days from now, cert is renewed if expires within 30 days 764 mockKubeClient.GetStub = func(ctx context.Context, types types.NamespacedName, obj client.Object) error { 765 switch obj.(type) { 766 case *current.IBPPeer: 767 o := obj.(*current.IBPPeer) 768 o.Kind = "IBPPeer" 769 instance = o 770 771 case *corev1.Secret: 772 o := obj.(*corev1.Secret) 773 switch types.Name { 774 case "tls-" + instance.Name + "-signcert": 775 o.Name = "tls-" + instance.Name + "-signcert" 776 o.Namespace = instance.Namespace 777 o.Data = map[string][]byte{"cert.pem": generateCertPemBytes(29)} 778 case "tls-" + instance.Name + "-keystore": 779 o.Name = "tls-" + instance.Name + "-keystore" 780 o.Namespace = instance.Namespace 781 o.Data = map[string][]byte{"key.pem": []byte("")} 782 case instance.Name + "-crypto-backup": 783 return k8serrors.NewNotFound(schema.GroupResource{}, "not found") 784 } 785 } 786 return nil 787 } 788 789 err := peer.SetCertificateTimer(instance, "tls") 790 Expect(err).NotTo(HaveOccurred()) 791 Expect(peer.RenewCertTimers["tls-peer1-signcert"]).NotTo(BeNil()) 792 793 // Wait for timer to go off 794 time.Sleep(5 * time.Second) 795 796 // timer.Stop() == false means that it already fired 797 Expect(peer.RenewCertTimers["tls-peer1-signcert"].Stop()).To(Equal(false)) 798 }) 799 800 It("doesn't return error if timer is set correctly, timer doesn't go off certificate isn't ready for renewal", func() { 801 // Set tls signcert expiration date to be 50 days from now, cert is renewed if expires within 30 days 802 mockKubeClient.GetStub = func(ctx context.Context, types types.NamespacedName, obj client.Object) error { 803 switch obj.(type) { 804 case *current.IBPPeer: 805 o := obj.(*current.IBPPeer) 806 o.Kind = "IBPPeer" 807 instance = o 808 809 case *corev1.Secret: 810 o := obj.(*corev1.Secret) 811 switch types.Name { 812 case "tls-" + instance.Name + "-signcert": 813 o.Name = "tls-" + instance.Name + "-signcert" 814 o.Namespace = instance.Namespace 815 o.Data = map[string][]byte{"cert.pem": generateCertPemBytes(50)} 816 case "tls-" + instance.Name + "-keystore": 817 o.Name = "tls-" + instance.Name + "-keystore" 818 o.Namespace = instance.Namespace 819 o.Data = map[string][]byte{"key.pem": []byte("")} 820 case instance.Name + "-crypto-backup": 821 return k8serrors.NewNotFound(schema.GroupResource{}, "not found") 822 } 823 } 824 return nil 825 } 826 827 err := peer.SetCertificateTimer(instance, "tls") 828 Expect(err).NotTo(HaveOccurred()) 829 830 // Timer shouldn't go off 831 time.Sleep(5 * time.Second) 832 833 Expect(peer.RenewCertTimers["tls-peer1-signcert"]).NotTo(BeNil()) 834 // timer.Stop() == true means that it has not fired but is now stopped 835 Expect(peer.RenewCertTimers["tls-peer1-signcert"].Stop()).To(Equal(true)) 836 }) 837 }) 838 }) 839 840 Context("renew cert", func() { 841 BeforeEach(func() { 842 instance.Spec.Secret = ¤t.SecretSpec{ 843 Enrollment: ¤t.EnrollmentSpec{ 844 TLS: ¤t.Enrollment{}, 845 }, 846 } 847 848 certificateMgr.RenewCertReturns(nil) 849 }) 850 851 It("returns error if secret spec is missing", func() { 852 instance.Spec.Secret = nil 853 err := peer.RenewCert("tls", instance, true) 854 Expect(err).To(HaveOccurred()) 855 Expect(err.Error()).To(Equal("missing secret spec for instance 'peer1'")) 856 }) 857 858 It("returns error if certificate generated by MSP", func() { 859 instance.Spec.Secret = ¤t.SecretSpec{ 860 MSP: ¤t.MSPSpec{}, 861 } 862 err := peer.RenewCert("tls", instance, true) 863 Expect(err).To(HaveOccurred()) 864 Expect(err.Error()).To(Equal("cannot auto-renew certificate created by MSP, force renewal required")) 865 }) 866 867 It("returns error if certificate manager fails to renew certificate", func() { 868 certificateMgr.RenewCertReturns(errors.New("failed to renew cert")) 869 err := peer.RenewCert("tls", instance, true) 870 Expect(err).To(HaveOccurred()) 871 Expect(err.Error()).To(Equal("failed to renew cert")) 872 }) 873 874 It("does not return error if certificate manager successfully renews cert", func() { 875 err := peer.RenewCert("tls", instance, true) 876 Expect(err).NotTo(HaveOccurred()) 877 }) 878 }) 879 880 Context("set cr status", func() { 881 It("returns error if fails to get current instance", func() { 882 mockKubeClient.GetReturns(errors.New("get error")) 883 err := peer.UpdateCRStatus(instance) 884 Expect(err).To(HaveOccurred()) 885 Expect(err.Error()).To(Equal("failed to get new instance: get error")) 886 }) 887 888 It("returns error if fails to update instance status", func() { 889 mockKubeClient.UpdateStatusReturns(errors.New("update status error")) 890 certificateMgr.CheckCertificatesForExpireReturns(current.Warning, "cert renewal required", nil) 891 err := peer.UpdateCRStatus(instance) 892 Expect(err).To(HaveOccurred()) 893 Expect(err.Error()).To(Equal("failed to update status to Warning phase: update status error")) 894 }) 895 896 It("sets instance CR status to Warning", func() { 897 certificateMgr.CheckCertificatesForExpireReturns(current.Warning, "message", nil) 898 err := peer.UpdateCRStatus(instance) 899 Expect(err).NotTo(HaveOccurred()) 900 Expect(instance.Status.Type).To(Equal(current.Warning)) 901 Expect(instance.Status.Reason).To(Equal("certRenewalRequired")) 902 Expect(instance.Status.Message).To(Equal("message")) 903 }) 904 }) 905 906 Context("fabric peer migration", func() { 907 BeforeEach(func() { 908 overrides := &pconfig.Core{ 909 Core: v1.Core{ 910 Peer: v1.Peer{ 911 BCCSP: &commonapi.BCCSP{ 912 ProviderName: "pkcs11", 913 PKCS11: &commonapi.PKCS11Opts{ 914 FileKeyStore: &commonapi.FileKeyStoreOpts{ 915 KeyStorePath: "msp/keystore", 916 }, 917 }, 918 }, 919 }, 920 }, 921 } 922 jmRaw, err := util.ConvertToJsonMessage(overrides) 923 Expect(err).NotTo(HaveOccurred()) 924 925 instance.Spec.ConfigOverride = &runtime.RawExtension{Raw: *jmRaw} 926 927 coreBytes, err := yaml.Marshal(overrides) 928 Expect(err).NotTo(HaveOccurred()) 929 930 cm := &corev1.ConfigMap{ 931 BinaryData: map[string][]byte{ 932 "core.yaml": coreBytes, 933 }, 934 } 935 936 mockKubeClient.GetStub = func(ctx context.Context, types types.NamespacedName, obj client.Object) error { 937 switch obj.(type) { 938 case *corev1.ConfigMap: 939 o := obj.(*corev1.ConfigMap) 940 o.Name = "core-config" 941 o.BinaryData = cm.BinaryData 942 } 943 return nil 944 } 945 }) 946 947 It("removes keystore path value", func() { 948 peerConfig, err := peer.FabricPeerMigrationV1_4(instance) 949 Expect(err).NotTo(HaveOccurred()) 950 Expect(peerConfig.Peer.BCCSP.PKCS11.FileKeyStore).To(BeNil()) 951 }) 952 953 When("fabric peer tag is less than 1.4.7", func() { 954 BeforeEach(func() { 955 instance.Spec.Images.PeerTag = "1.4.6-20200611" 956 }) 957 958 It("returns without updating config", func() { 959 peerConfig, err := peer.FabricPeerMigrationV1_4(instance) 960 Expect(err).NotTo(HaveOccurred()) 961 Expect(peerConfig).To(BeNil()) 962 }) 963 }) 964 965 When("hsm is not enabled", func() { 966 BeforeEach(func() { 967 overrides := &pconfig.Core{ 968 Core: v1.Core{ 969 Peer: v1.Peer{ 970 BCCSP: &commonapi.BCCSP{ 971 ProviderName: "sw", 972 SW: &commonapi.SwOpts{ 973 FileKeyStore: commonapi.FileKeyStoreOpts{ 974 KeyStorePath: "msp/keystore", 975 }, 976 }, 977 }, 978 }, 979 }, 980 } 981 jmRaw, err := util.ConvertToJsonMessage(overrides) 982 Expect(err).NotTo(HaveOccurred()) 983 984 instance.Spec.ConfigOverride = &runtime.RawExtension{Raw: *jmRaw} 985 }) 986 987 It("returns without updating config", func() { 988 peerConfig, err := peer.FabricPeerMigrationV1_4(instance) 989 Expect(err).NotTo(HaveOccurred()) 990 Expect(peerConfig).To(BeNil()) 991 }) 992 }) 993 }) 994 995 Context("images override", func() { 996 var images *current.PeerImages 997 998 Context("using registry url", func() { 999 BeforeEach(func() { 1000 images = ¤t.PeerImages{ 1001 PeerInitImage: "peerinitimage", 1002 PeerInitTag: "2.0.0", 1003 PeerImage: "peerimage", 1004 PeerTag: "2.0.0", 1005 DindImage: "dindimage", 1006 DindTag: "2.0.0", 1007 CouchDBImage: "couchimage", 1008 CouchDBTag: "2.0.0", 1009 GRPCWebImage: "grpcimage", 1010 GRPCWebTag: "2.0.0", 1011 FluentdImage: "fluentdimage", 1012 FluentdTag: "2.0.0", 1013 } 1014 }) 1015 1016 It("overrides images based with registry url and does not append more value on each call", func() { 1017 images.Override(images, "ghcr.io/ibm-blockchain/", "amd64") 1018 Expect(images.PeerInitImage).To(Equal("ghcr.io/ibm-blockchain/peerinitimage")) 1019 Expect(images.PeerInitTag).To(Equal("2.0.0")) 1020 Expect(images.PeerImage).To(Equal("ghcr.io/ibm-blockchain/peerimage")) 1021 Expect(images.PeerTag).To(Equal("2.0.0")) 1022 Expect(images.DindImage).To(Equal("ghcr.io/ibm-blockchain/dindimage")) 1023 Expect(images.DindTag).To(Equal("2.0.0")) 1024 Expect(images.CouchDBImage).To(Equal("ghcr.io/ibm-blockchain/couchimage")) 1025 Expect(images.CouchDBTag).To(Equal("2.0.0")) 1026 Expect(images.GRPCWebImage).To(Equal("ghcr.io/ibm-blockchain/grpcimage")) 1027 Expect(images.GRPCWebTag).To(Equal("2.0.0")) 1028 Expect(images.FluentdImage).To(Equal("ghcr.io/ibm-blockchain/fluentdimage")) 1029 Expect(images.FluentdTag).To(Equal("2.0.0")) 1030 }) 1031 1032 It("overrides images based with registry url and does not append more value on each call", func() { 1033 images.Override(images, "ghcr.io/ibm-blockchain/images/", "s390") 1034 Expect(images.PeerInitImage).To(Equal("ghcr.io/ibm-blockchain/images/peerinitimage")) 1035 Expect(images.PeerInitTag).To(Equal("2.0.0")) 1036 Expect(images.PeerImage).To(Equal("ghcr.io/ibm-blockchain/images/peerimage")) 1037 Expect(images.PeerTag).To(Equal("2.0.0")) 1038 Expect(images.DindImage).To(Equal("ghcr.io/ibm-blockchain/images/dindimage")) 1039 Expect(images.DindTag).To(Equal("2.0.0")) 1040 Expect(images.CouchDBImage).To(Equal("ghcr.io/ibm-blockchain/images/couchimage")) 1041 Expect(images.CouchDBTag).To(Equal("2.0.0")) 1042 Expect(images.GRPCWebImage).To(Equal("ghcr.io/ibm-blockchain/images/grpcimage")) 1043 Expect(images.GRPCWebTag).To(Equal("2.0.0")) 1044 Expect(images.FluentdImage).To(Equal("ghcr.io/ibm-blockchain/images/fluentdimage")) 1045 Expect(images.FluentdTag).To(Equal("2.0.0")) 1046 }) 1047 }) 1048 1049 Context("using fully qualified path", func() { 1050 BeforeEach(func() { 1051 images = ¤t.PeerImages{ 1052 PeerInitImage: "ghcr.io/ibm-blockchain/peerinitimage", 1053 PeerInitTag: "2.0.0", 1054 PeerImage: "ghcr.io/ibm-blockchain/peerimage", 1055 PeerTag: "2.0.0", 1056 DindImage: "ghcr.io/ibm-blockchain/dindimage", 1057 DindTag: "2.0.0", 1058 CouchDBImage: "ghcr.io/ibm-blockchain/couchimage", 1059 CouchDBTag: "2.0.0", 1060 GRPCWebImage: "ghcr.io/ibm-blockchain/grpcimage", 1061 GRPCWebTag: "2.0.0", 1062 FluentdImage: "ghcr.io/ibm-blockchain/fluentdimage", 1063 FluentdTag: "2.0.0", 1064 } 1065 }) 1066 1067 It("keeps images and adds arch to tag", func() { 1068 images.Override(images, "", "amd64") 1069 Expect(images.PeerInitImage).To(Equal("ghcr.io/ibm-blockchain/peerinitimage")) 1070 Expect(images.PeerInitTag).To(Equal("2.0.0")) 1071 Expect(images.PeerImage).To(Equal("ghcr.io/ibm-blockchain/peerimage")) 1072 Expect(images.PeerTag).To(Equal("2.0.0")) 1073 Expect(images.DindImage).To(Equal("ghcr.io/ibm-blockchain/dindimage")) 1074 Expect(images.DindTag).To(Equal("2.0.0")) 1075 Expect(images.CouchDBImage).To(Equal("ghcr.io/ibm-blockchain/couchimage")) 1076 Expect(images.CouchDBTag).To(Equal("2.0.0")) 1077 Expect(images.GRPCWebImage).To(Equal("ghcr.io/ibm-blockchain/grpcimage")) 1078 Expect(images.GRPCWebTag).To(Equal("2.0.0")) 1079 Expect(images.FluentdImage).To(Equal("ghcr.io/ibm-blockchain/fluentdimage")) 1080 Expect(images.FluentdTag).To(Equal("2.0.0")) 1081 }) 1082 }) 1083 }) 1084 1085 Context("update connection profile", func() { 1086 It("returns error if fails to get cert", func() { 1087 mockKubeClient.GetReturns(errors.New("get error")) 1088 err := peer.UpdateConnectionProfile(instance) 1089 Expect(err).To(HaveOccurred()) 1090 Expect(err.Error()).To(ContainSubstring("get error")) 1091 }) 1092 1093 It("updates connection profile cm", func() { 1094 err := peer.UpdateConnectionProfile(instance) 1095 Expect(err).NotTo(HaveOccurred()) 1096 Expect(mockKubeClient.GetCallCount()).To(Equal(7)) 1097 }) 1098 }) 1099 1100 Context("update msp certificates", func() { 1101 const testcert = "LS0tLS1CRUdJTiBDRVJUSUZJQ0FURS0tLS0tCk1JSUNpVENDQWkrZ0F3SUJBZ0lVRkd3N0RjK0QvZUoyY08wOHd6d2tialIzK1M4d0NnWUlLb1pJemowRUF3SXcKYURFTE1Ba0dBMVVFQmhNQ1ZWTXhGekFWQmdOVkJBZ1REazV2Y25Sb0lFTmhjbTlzYVc1aE1SUXdFZ1lEVlFRSwpFd3RJZVhCbGNteGxaR2RsY2pFUE1BMEdBMVVFQ3hNR1JtRmljbWxqTVJrd0Z3WURWUVFERXhCbVlXSnlhV010ClkyRXRjMlZ5ZG1WeU1CNFhEVEU1TVRBd09URTBNakF3TUZvWERUSXdNVEF3T0RFME1qQXdNRm93YnpFTE1Ba0cKQTFVRUJoTUNWVk14RnpBVkJnTlZCQWdURGs1dmNuUm9JRU5oY205c2FXNWhNUlF3RWdZRFZRUUtFd3RJZVhCbApjbXhsWkdkbGNqRVBNQTBHQTFVRUN4TUdSbUZpY21sak1TQXdIZ1lEVlFRREV4ZFRZV0ZrY3kxTllXTkNiMjlyCkxWQnlieTVzYjJOaGJEQlpNQk1HQnlxR1NNNDlBZ0VHQ0NxR1NNNDlBd0VIQTBJQUJBK0JBRzhZakJvTllabGgKRjFrVHNUbHd6VERDQTJocDhZTXI5Ky8vbEd0NURoSGZVT1c3bkhuSW1USHlPRjJQVjFPcVRuUWhUbWpLYTdaQwpqeU9BUWxLamdhOHdnYXd3RGdZRFZSMFBBUUgvQkFRREFnT29NQjBHQTFVZEpRUVdNQlFHQ0NzR0FRVUZCd01CCkJnZ3JCZ0VGQlFjREFqQU1CZ05WSFJNQkFmOEVBakFBTUIwR0ExVWREZ1FXQkJTbHJjL0lNQkxvMzR0UktvWnEKNTQreDIyYWEyREFmQmdOVkhTTUVHREFXZ0JSWmpxT3RQZWJzSFI2UjBNQUhrNnd4ei85UFZqQXRCZ05WSFJFRQpKakFrZ2hkVFlXRmtjeTFOWVdOQ2IyOXJMVkJ5Ynk1c2IyTmhiSUlKYkc5allXeG9iM04wTUFvR0NDcUdTTTQ5CkJBTUNBMGdBTUVVQ0lRRGR0Y1QwUE9FQXJZKzgwdEhmWUwvcXBiWWoxMGU2eWlPWlpUQ29wY25mUVFJZ1FNQUQKaFc3T0NSUERNd3lqKzNhb015d2hFenFHYy9jRDJSU2V5ekRiRjFFPQotLS0tLUVORCBDRVJUSUZJQ0FURS0tLS0tCg==" 1102 1103 BeforeEach(func() { 1104 msp := ¤t.MSP{ 1105 SignCerts: testcert, 1106 CACerts: []string{testcert}, 1107 KeyStore: "keystore", 1108 } 1109 1110 initializer.GetUpdatedPeerReturns(&peerinit.Peer{ 1111 Cryptos: &commonconfig.Cryptos{ 1112 TLS: &mspparser.MSPParser{ 1113 Config: msp, 1114 }, 1115 }, 1116 }, nil) 1117 1118 }) 1119 1120 It("returns error if fails to get update msp parsers", func() { 1121 initializer.GetUpdatedPeerReturns(nil, errors.New("get error")) 1122 err := peer.UpdateMSPCertificates(instance) 1123 Expect(err).To(HaveOccurred()) 1124 Expect(err.Error()).To(ContainSubstring("get error")) 1125 }) 1126 1127 It("returns error if fails to generate crypto", func() { 1128 initializer.GetUpdatedPeerReturns(&peerinit.Peer{ 1129 Cryptos: &commonconfig.Cryptos{ 1130 TLS: &mspparser.MSPParser{ 1131 Config: ¤t.MSP{ 1132 SignCerts: "invalid", 1133 }, 1134 }, 1135 }, 1136 }, nil) 1137 err := peer.UpdateMSPCertificates(instance) 1138 Expect(err).To(HaveOccurred()) 1139 }) 1140 1141 It("returns error if fails to update secrets", func() { 1142 initializer.UpdateSecretsFromResponseReturns(errors.New("update error")) 1143 err := peer.UpdateMSPCertificates(instance) 1144 Expect(err).To(HaveOccurred()) 1145 Expect(err.Error()).To(Equal("update error")) 1146 }) 1147 1148 It("updates secrets of certificates passed through MSP spec", func() { 1149 err := peer.UpdateMSPCertificates(instance) 1150 Expect(err).NotTo(HaveOccurred()) 1151 Expect(initializer.UpdateSecretsFromResponseCallCount()).To(Equal(1)) 1152 }) 1153 }) 1154 1155 Context("enroll for ecert", func() { 1156 It("returns error if no enrollment information provided", func() { 1157 err := peer.EnrollForEcert(instance) 1158 Expect(err).To(HaveOccurred()) 1159 Expect(err).To(MatchError(ContainSubstring("unable to enroll, no ecert enrollment information provided"))) 1160 }) 1161 1162 It("returns error if enrollment with ca fails", func() { 1163 instance.Spec.Secret = ¤t.SecretSpec{ 1164 Enrollment: ¤t.EnrollmentSpec{ 1165 Component: ¤t.Enrollment{}, 1166 }, 1167 } 1168 err := peer.EnrollForEcert(instance) 1169 Expect(err).To(HaveOccurred()) 1170 Expect(err).To(MatchError(ContainSubstring("failed to enroll for ecert"))) 1171 }) 1172 }) 1173 1174 Context("enroll for TLS cert", func() { 1175 It("returns error if no enrollment information provided", func() { 1176 err := peer.EnrollForTLSCert(instance) 1177 Expect(err).To(HaveOccurred()) 1178 Expect(err).To(MatchError(ContainSubstring("unable to enroll, no TLS enrollment information provided"))) 1179 }) 1180 1181 It("returns error if enrollment with ca fails", func() { 1182 instance.Spec.Secret = ¤t.SecretSpec{ 1183 Enrollment: ¤t.EnrollmentSpec{ 1184 TLS: ¤t.Enrollment{}, 1185 }, 1186 } 1187 err := peer.EnrollForTLSCert(instance) 1188 Expect(err).To(HaveOccurred()) 1189 Expect(err).To(MatchError(ContainSubstring("failed to enroll for TLS cert"))) 1190 }) 1191 }) 1192 }) 1193 1194 func generateCertPemBytes(daysUntilExpired int) []byte { 1195 certtemplate := x509.Certificate{ 1196 SerialNumber: big.NewInt(1), 1197 NotBefore: time.Now(), 1198 NotAfter: time.Now().Add(time.Duration(daysUntilExpired) * time.Hour * 24), 1199 } 1200 1201 priv, err := ecdsa.GenerateKey(elliptic.P256(), rand.Reader) 1202 Expect(err).NotTo(HaveOccurred()) 1203 1204 cert, err := x509.CreateCertificate(rand.Reader, &certtemplate, &certtemplate, &priv.PublicKey, priv) 1205 Expect(err).NotTo(HaveOccurred()) 1206 1207 block := &pem.Block{ 1208 Type: "CERTIFICATE", 1209 Bytes: cert, 1210 } 1211 1212 return pem.EncodeToMemory(block) 1213 }