github.com/IBM-Blockchain/fabric-operator@v1.0.4/pkg/offering/base/orderer/orderer.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 baseorderer 20 21 import ( 22 "context" 23 "encoding/json" 24 "fmt" 25 "io/ioutil" 26 "os" 27 "path/filepath" 28 "strings" 29 "time" 30 31 current "github.com/IBM-Blockchain/fabric-operator/api/v1beta1" 32 config "github.com/IBM-Blockchain/fabric-operator/operatorconfig" 33 orderer "github.com/IBM-Blockchain/fabric-operator/pkg/initializer/orderer/config/v1" 34 "github.com/IBM-Blockchain/fabric-operator/pkg/initializer/orderer/configtx" 35 k8sclient "github.com/IBM-Blockchain/fabric-operator/pkg/k8s/controllerclient" 36 "github.com/IBM-Blockchain/fabric-operator/pkg/manager/resources" 37 resourcemanager "github.com/IBM-Blockchain/fabric-operator/pkg/manager/resources/manager" 38 "github.com/IBM-Blockchain/fabric-operator/pkg/offering/common" 39 "github.com/IBM-Blockchain/fabric-operator/pkg/operatorerrors" 40 "github.com/IBM-Blockchain/fabric-operator/pkg/restart" 41 "github.com/IBM-Blockchain/fabric-operator/pkg/util" 42 "github.com/IBM-Blockchain/fabric-operator/version" 43 "github.com/gogo/protobuf/proto" 44 "github.com/hyperledger/fabric-protos-go/msp" 45 "github.com/hyperledger/fabric-protos-go/orderer/etcdraft" 46 "github.com/hyperledger/fabric/bccsp" 47 fmsp "github.com/hyperledger/fabric/msp" 48 "github.com/pkg/errors" 49 "gopkg.in/yaml.v2" 50 corev1 "k8s.io/api/core/v1" 51 k8serrors "k8s.io/apimachinery/pkg/api/errors" 52 metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" 53 v1 "k8s.io/apimachinery/pkg/apis/meta/v1" 54 "k8s.io/apimachinery/pkg/labels" 55 "k8s.io/apimachinery/pkg/runtime" 56 "k8s.io/apimachinery/pkg/types" 57 "k8s.io/apimachinery/pkg/util/wait" 58 "k8s.io/utils/pointer" 59 "sigs.k8s.io/controller-runtime/pkg/client" 60 logf "sigs.k8s.io/controller-runtime/pkg/log" 61 "sigs.k8s.io/controller-runtime/pkg/reconcile" 62 ) 63 64 var log = logf.Log.WithName("base_orderer") 65 66 const ( 67 defaultOrdererNode = "./definitions/orderer/orderernode.yaml" 68 ) 69 70 //go:generate counterfeiter -o mocks/node_manager.go -fake-name NodeManager . NodeManager 71 72 type NodeManager interface { 73 GetNode(int, map[string]*time.Timer, RestartManager) *Node 74 } 75 76 var _ IBPOrderer = &Orderer{} 77 78 type Orderer struct { 79 Client k8sclient.Client 80 Scheme *runtime.Scheme 81 Config *config.Config 82 83 NodeManager NodeManager 84 OrdererNodeManager resources.Manager 85 86 Override Override 87 RenewCertTimers map[string]*time.Timer 88 RestartManager *restart.RestartManager 89 } 90 91 func New(client k8sclient.Client, scheme *runtime.Scheme, config *config.Config, o Override) *Orderer { 92 orderer := &Orderer{ 93 Client: client, 94 Scheme: scheme, 95 Config: config, 96 NodeManager: &Manager{ 97 Client: client, 98 Scheme: scheme, 99 Config: config, 100 }, 101 Override: o, 102 RenewCertTimers: make(map[string]*time.Timer), 103 RestartManager: restart.New(client, config.Operator.Restart.WaitTime.Get(), config.Operator.Restart.Timeout.Get()), 104 } 105 orderer.CreateManagers() 106 return orderer 107 } 108 109 func (o *Orderer) CreateManagers() { 110 resourceManager := resourcemanager.New(o.Client, o.Scheme) 111 o.OrdererNodeManager = resourceManager.CreateOrderernodeManager("", o.Override.OrdererNode, o.GetLabels, defaultOrdererNode) 112 } 113 114 func (o *Orderer) PreReconcileChecks(instance *current.IBPOrderer, update Update) (bool, error) { 115 if strings.ToLower(instance.Spec.OrdererType) != "etcdraft" { 116 return false, operatorerrors.New(operatorerrors.InvalidOrdererType, fmt.Sprintf("orderer type '%s' is not supported", instance.Spec.OrdererType)) 117 } 118 119 size := instance.Spec.ClusterSize 120 if instance.Spec.NodeNumber == nil && instance.Spec.ClusterLocation != nil && instance.Spec.ClusterSize != 0 && len(instance.Spec.ClusterLocation) != size { 121 return false, operatorerrors.New(operatorerrors.InvalidOrdererType, "Number of Cluster Node Locations does not match cluster size") 122 } 123 124 if instance.Spec.NodeNumber == nil && instance.Spec.ClusterSecret == nil { 125 return false, operatorerrors.New(operatorerrors.InvalidOrdererType, "Cluster MSP Secrets should be passed") 126 } 127 128 if instance.Spec.NodeNumber == nil && instance.Spec.ClusterSecret != nil && instance.Spec.ClusterSize != 0 && len(instance.Spec.ClusterSecret) != size { 129 return false, operatorerrors.New(operatorerrors.InvalidOrdererType, "Number of Cluster MSP Secrets does not match cluster size") 130 } 131 132 if instance.Spec.NodeNumber == nil && instance.Spec.ClusterConfigOverride != nil && instance.Spec.ClusterSize != 0 && len(instance.Spec.ClusterConfigOverride) != size { 133 return false, operatorerrors.New(operatorerrors.InvalidOrdererType, "Number of Cluster Override does not match cluster size") 134 } 135 136 var maxNameLength *int 137 if instance.Spec.ConfigOverride != nil { 138 override := &orderer.OrdererOverrides{} 139 err := json.Unmarshal(instance.Spec.ConfigOverride.Raw, override) 140 if err != nil { 141 return false, err 142 } 143 maxNameLength = override.MaxNameLength 144 } 145 146 err := util.ValidationChecks(instance.TypeMeta, instance.ObjectMeta, "IBPOrderer", maxNameLength) 147 if err != nil { 148 return false, err 149 } 150 151 sizeUpdate := o.ClusterSizeUpdate(instance) 152 if sizeUpdate { 153 log.Info("Updating instance with default cluster size of 1") 154 err = o.Client.Patch(context.TODO(), instance, nil, k8sclient.PatchOption{ 155 Resilient: &k8sclient.ResilientPatch{ 156 Retry: 3, 157 Into: ¤t.IBPOrderer{}, 158 Strategy: client.MergeFrom, 159 }, 160 }) 161 if err != nil { 162 return false, err 163 } 164 return true, nil 165 } 166 167 return false, nil 168 } 169 170 func (o *Orderer) ClusterSizeUpdate(instance *current.IBPOrderer) bool { 171 size := instance.Spec.ClusterSize 172 if size == 0 { 173 instance.Spec.ClusterSize = 1 174 return true 175 } 176 177 return false 178 } 179 180 func (o *Orderer) Initialize(instance *current.IBPOrderer, update Update) error { 181 // NO-OP 182 return nil 183 } 184 185 func (o *Orderer) ReconcileManagers(instance *current.IBPOrderer, update Update, genesisBlock []byte) error { 186 var b64GenesisBlock string 187 188 b64GenesisBlock = util.BytesToBase64(genesisBlock) 189 190 for k := 0; k < instance.Spec.ClusterSize; k++ { 191 nodenumber := k + 1 192 nodeinstance := instance.DeepCopy() 193 nodeinstance.Spec.NodeNumber = &nodenumber 194 nodeinstance.Spec.ClusterSize = 1 195 nodeinstance.Spec.GenesisBlock = b64GenesisBlock 196 if len(instance.Spec.ClusterConfigOverride) != 0 { 197 nodeinstance.Spec.ConfigOverride = instance.Spec.ClusterConfigOverride[k] 198 } 199 nodeinstance.Spec.Secret = instance.Spec.ClusterSecret[k] 200 err := o.OrdererNodeManager.Reconcile(nodeinstance, false) 201 if err != nil { 202 return err 203 } 204 } 205 206 return nil 207 } 208 209 func (o *Orderer) UpdateNodesWithGenesisBlock(genesisBlock string, nodes []current.IBPOrderer) error { 210 log.Info("Updating nodes with genesis block if missing") 211 212 for _, node := range nodes { 213 if node.Spec.GenesisBlock == "" { 214 log.Info(fmt.Sprintf("Updating node '%s'", node.Name)) 215 216 node.Spec.GenesisBlock = genesisBlock 217 nodeRef := node 218 err := o.Client.Patch(context.TODO(), &nodeRef, nil, k8sclient.PatchOption{ 219 Resilient: &k8sclient.ResilientPatch{ 220 Retry: 3, 221 Into: ¤t.IBPOrderer{}, 222 Strategy: client.MergeFrom, 223 }, 224 }) 225 if err != nil { 226 return err 227 } 228 } 229 } 230 231 return nil 232 } 233 234 func (o *Orderer) Reconcile(instance *current.IBPOrderer, update Update) (common.Result, error) { 235 return common.Result{}, errors.New("base orderer reconcile not implemented, needs to be implemented by offering") 236 } 237 238 func (o *Orderer) ReconcileCluster(instance *current.IBPOrderer, update Update, addHostPortToProfile func(*configtx.Profile, *current.IBPOrderer) error) (common.Result, error) { 239 log.Info(fmt.Sprintf("Reconciling Orderer Cluster %s", instance.GetName())) 240 var err error 241 242 size := instance.Spec.ClusterSize 243 nodes, err := o.GetClusterNodes(instance) 244 if err != nil { 245 return common.Result{}, err 246 } 247 248 if len(nodes.Items) == size { 249 if instance.Spec.IsPrecreateOrderer() { 250 return common.Result{}, err 251 } 252 } 253 254 for _, node := range nodes.Items { 255 log.Info(fmt.Sprintf("GetClusterNodes returned node '%s'", node.Name)) 256 } 257 258 log.Info(fmt.Sprintf("Size of cluster (number of nodes): %d", size)) 259 260 var genesisBlock []byte 261 if len(nodes.Items) == size && !instance.Spec.IsUsingChannelLess() { 262 // Wait till all nodes are in precreated state before generating genesis block. 263 // Once in precreate state, the TLS certs and service should exists for genesis 264 // block creation 265 deployedNodes := 0 266 for _, node := range nodes.Items { 267 if node.Status.Type == current.Deployed { 268 deployedNodes++ 269 } else { 270 log.Info(fmt.Sprintf("Node '%s' hasn't deployed yet, checking if in precreated state", node.GetName())) 271 if node.Status.Type != current.Precreated { 272 log.Info(fmt.Sprintf("Node '%s' hasn't entered precreated state, requeue request, another check to be made at next reconcile", node.GetName())) 273 return common.Result{ 274 Result: reconcile.Result{ 275 Requeue: true, 276 }, 277 }, nil 278 } 279 } 280 } 281 282 // If all nodes are deployed state and parent hasn't deployed yet, ensure that 283 // all genesis secrets are found. If all required genesis secrets are not present 284 // continue with generating secrets 285 genesisSecretsFound := 0 286 for _, node := range nodes.Items { 287 288 nn := types.NamespacedName{ 289 Name: node.Name + "-genesis", 290 Namespace: node.Namespace, 291 } 292 293 err := o.Client.Get(context.TODO(), nn, &corev1.Secret{}) 294 if err == nil { 295 genesisSecretsFound++ 296 } 297 } 298 299 // If all genesis secrets found, nothing left to do by parent of cluster nodes 300 if genesisSecretsFound == len(nodes.Items) { 301 return common.Result{}, nil 302 } 303 304 log.Info(fmt.Sprintf("All nodes have been precreated by cluster reconcile for parent: %s", instance.GetName())) 305 306 genesisBlock, err = o.GenerateGenesisBlock(instance, addHostPortToProfile) 307 if err != nil { 308 return common.Result{}, err 309 } 310 311 log.Info(fmt.Sprintf("Finished generating genesis block for cluster '%s'", instance.GetName())) 312 313 b64GenesisBlock := util.BytesToBase64(genesisBlock) 314 err = o.UpdateNodesWithGenesisBlock(b64GenesisBlock, nodes.Items) 315 if err != nil { 316 return common.Result{}, err 317 } 318 319 err = o.GenerateGenesisSecretForNodes(genesisBlock, nodes.Items) 320 if err != nil { 321 return common.Result{}, err 322 } 323 324 log.Info("Finished generating genesis secrets") 325 326 return common.Result{}, err 327 } 328 329 if instance.Status.Type == "" || instance.Status.Type == current.Deploying { 330 for i := 1; i <= size; i++ { 331 err := o.CreateNodeCR(instance, i) 332 if err != nil { 333 return common.Result{}, err 334 } 335 } 336 } 337 338 if !version.String(instance.Status.Version).Equal(version.Operator) { 339 log.Info(fmt.Sprintf("[Reconcile cluster] Setting version to %s for instance %s", version.Operator, instance.Name)) 340 instance.Status.Version = version.Operator 341 err = o.PatchStatus(instance) 342 if err != nil { 343 return common.Result{}, err 344 } 345 } 346 347 return common.Result{}, nil 348 } 349 350 func (o *Orderer) GenerateGenesisSecretForNodes(genesisBlock []byte, nodes []current.IBPOrderer) error { 351 log.Info("Generating genesis secret for all nodes") 352 353 for _, node := range nodes { 354 log.Info(fmt.Sprintf("Processing node '%s' for genesis secret", node.Name)) 355 s := &corev1.Secret{ 356 ObjectMeta: v1.ObjectMeta{ 357 Name: node.Name + "-genesis", 358 Namespace: node.Namespace, 359 Labels: node.GetLabels(), 360 }, 361 Data: map[string][]byte{ 362 "orderer.block": genesisBlock, 363 }, 364 } 365 366 log.Info(fmt.Sprintf("Creating secret '%s'", s.Name)) 367 nodeRef := node 368 err := o.Client.Create(context.TODO(), s, k8sclient.CreateOption{Owner: &nodeRef, Scheme: o.Scheme}) 369 if err != nil { 370 return errors.Wrap(err, "failed to create orderer node's genesis secret") 371 } 372 } 373 374 return nil 375 } 376 377 func (o *Orderer) SetVersion(instance *current.IBPOrderer) (bool, error) { 378 if instance.Status.Version == "" || !version.String(instance.Status.Version).Equal(version.Operator) { 379 log.Info("Version of Operator: ", "version", version.Operator) 380 log.Info(fmt.Sprintf("Version of CR '%s': %s", instance.GetName(), instance.Status.Version)) 381 log.Info(fmt.Sprintf("Setting '%s' to version '%s'", instance.Name, version.Operator)) 382 383 instance.Status.Version = version.Operator 384 err := o.PatchStatus(instance) 385 if err != nil { 386 return false, err 387 } 388 return true, nil 389 } 390 return false, nil 391 } 392 393 func (o *Orderer) GetClusterNodes(instance *current.IBPOrderer) (current.IBPOrdererList, error) { 394 ordererList := current.IBPOrdererList{} 395 396 labelSelector, err := labels.Parse(fmt.Sprintf("parent=%s", instance.GetName())) 397 if err != nil { 398 return ordererList, errors.Wrap(err, "failed to parse selector for parent name") 399 } 400 401 listOptions := &client.ListOptions{ 402 LabelSelector: labelSelector, 403 Namespace: instance.GetNamespace(), 404 } 405 406 err = o.Client.List(context.TODO(), &ordererList, listOptions) 407 if err != nil { 408 return ordererList, err 409 } 410 411 return ordererList, nil 412 } 413 414 func (o *Orderer) CreateNodeCR(instance *current.IBPOrderer, number int) error { 415 if instance.Spec.NodeNumber != nil { 416 return fmt.Errorf("only parent orderer can create nodes custom resources, instance '%s' is not a parent", instance.GetName()) 417 } 418 419 if !instance.Spec.License.Accept { 420 return errors.New("user must accept license before continuing") 421 } 422 423 label := os.Getenv("OPERATOR_LABEL_PREFIX") 424 if label == "" { 425 label = "fabric" 426 } 427 428 name := fmt.Sprintf("%snode%d", instance.GetName(), number) 429 node := instance.DeepCopy() 430 node.ObjectMeta = metav1.ObjectMeta{ 431 Name: name, 432 Namespace: instance.GetNamespace(), 433 Labels: map[string]string{ 434 "app": name, 435 "creator": label, 436 "parent": instance.GetName(), 437 "app.kubernetes.io/name": label, 438 "app.kubernetes.io/instance": label + "orderer", 439 "app.kubernetes.io/managed-by": label + "-operator", 440 }, 441 } 442 443 log.Info(fmt.Sprintf("Cluster reconcile is precreating node '%s'", node.Name)) 444 445 if len(node.Spec.ClusterConfigOverride) >= number { 446 node.Spec.ConfigOverride = node.Spec.ClusterConfigOverride[number-1] 447 } 448 449 if len(node.Spec.ClusterSecret) >= number { 450 node.Spec.Secret = node.Spec.ClusterSecret[number-1] 451 } 452 453 if len(node.Spec.ClusterLocation) >= number { 454 node.Spec.Zone = node.Spec.ClusterLocation[number-1].Zone 455 node.Spec.Region = node.Spec.ClusterLocation[number-1].Region 456 457 if node.Spec.Zone != "" && node.Spec.Region == "" { 458 node.Spec.Region = "select" 459 } 460 } 461 462 if instance.Spec.IsUsingChannelLess() { 463 node.Spec.UseChannelLess = instance.Spec.UseChannelLess 464 } else { 465 node.Spec.IsPrecreate = pointer.Bool(true) 466 } 467 node.Spec.NodeNumber = &number 468 node.Spec.ClusterSize = 1 469 node.Spec.ClusterSecret = nil 470 node.Spec.ClusterConfigOverride = nil 471 node.Spec.ClusterLocation = nil 472 473 err := o.Client.Create(context.TODO(), node) 474 if err != nil { 475 return err 476 } 477 478 if instance.Status.Version != version.Operator { 479 log.Info(fmt.Sprintf("[Create Node CR] Setting version to %s for node %s", version.Operator, node.Name)) 480 node.Status.Version = version.Operator 481 // Using Update instead of Patch status;error will be thrown when trying to get and merge instance during 482 // Patch. Update status will work here because the node has just been created so its spec will not have updated 483 // before setting its version. 484 err = o.UpdateStatus(node) 485 if err != nil { 486 return err 487 } 488 } 489 490 return nil 491 } 492 493 func (o *Orderer) ReconcileNode(instance *current.IBPOrderer, update bool) (reconcile.Result, error) { 494 return reconcile.Result{}, errors.New("base orderer reconcile node not implemented, needs to be implemented by offering") 495 } 496 497 func (o *Orderer) GenerateGenesisBlock(instance *current.IBPOrderer, addHostPortToProfile func(*configtx.Profile, *current.IBPOrderer) error) ([]byte, error) { 498 log.Info("Generating genesis block") 499 initProfile, err := o.LoadInitialProfile(instance) 500 if err != nil { 501 return nil, err 502 } 503 504 err = addHostPortToProfile(initProfile, instance) 505 if err != nil { 506 return nil, err 507 } 508 509 conf := initProfile.Orderer 510 mspConfigs := map[string]*msp.MSPConfig{} 511 for _, org := range conf.Organizations { 512 var err error 513 mspConfigs[org.Name], err = o.GetMSPConfig(instance, org.ID) 514 if err != nil { 515 return nil, errors.Wrap(err, "failed to create orderer org") 516 } 517 } 518 519 genesisBlock, err := initProfile.GenerateBlock(instance.Spec.SystemChannelName, mspConfigs) 520 if err != nil { 521 return nil, err 522 } 523 524 return genesisBlock, nil 525 } 526 527 func (o *Orderer) LoadInitialProfile(instance *current.IBPOrderer) (*configtx.Profile, error) { 528 profile := instance.Spec.GenesisProfile 529 if profile == "" { 530 profile = "Initial" 531 } 532 533 log.Info(fmt.Sprintf("Profile '%s' used for genesis creation", profile)) 534 535 configTx := configtx.New() 536 initProfile, err := configTx.GetProfile(profile) 537 if err != nil { 538 return nil, err 539 } 540 541 org := &configtx.Organization{ 542 Name: instance.Spec.OrgName, 543 ID: instance.Spec.MSPID, 544 MSPType: "bccsp", 545 MSPDir: "/certs/msp", 546 AdminPrincipal: "Role.MEMBER", 547 } 548 err = initProfile.AddOrgToOrderer(org) 549 if err != nil { 550 return nil, err 551 } 552 553 return initProfile, nil 554 } 555 556 func (o *Orderer) AddHostPortToProfile(initProfile *configtx.Profile, instance *current.IBPOrderer) error { 557 log.Info("Adding hosts to genesis block") 558 559 nodes := o.GetNodes(instance) 560 for _, node := range nodes { 561 n := types.NamespacedName{ 562 Name: fmt.Sprintf("tls-%s%s-signcert", instance.Name, node.Name), 563 Namespace: instance.Namespace, 564 } 565 566 // To avoid the race condition of the TLS signcert secret not existing, need to poll for it's 567 // existence before proceeding 568 tlsSecret := &corev1.Secret{} 569 err := wait.Poll(500*time.Millisecond, o.Config.Operator.Orderer.Timeouts.SecretPoll.Get(), func() (bool, error) { 570 err := o.Client.Get(context.TODO(), n, tlsSecret) 571 if err == nil { 572 return true, nil 573 } 574 return false, nil 575 }) 576 if err != nil { 577 return errors.Wrapf(err, "failed to find secret '%s'", n.Name) 578 } 579 580 domain := instance.Spec.Domain 581 fqdn := instance.Namespace + "-" + instance.Name + node.Name + "-orderer" + "." + domain 582 583 log.Info(fmt.Sprintf("Adding consentor domain '%s' to genesis block", fqdn)) 584 585 initProfile.AddOrdererAddress(fmt.Sprintf("%s:%d", fqdn, 443)) 586 consentors := &etcdraft.Consenter{ 587 Host: fqdn, 588 Port: 443, 589 ClientTlsCert: tlsSecret.Data["cert.pem"], 590 ServerTlsCert: tlsSecret.Data["cert.pem"], 591 } 592 err = initProfile.AddRaftConsentingNode(consentors) 593 if err != nil { 594 return err 595 } 596 } 597 return nil 598 } 599 600 func (o *Orderer) GetMSPConfig(instance *current.IBPOrderer, ID string) (*msp.MSPConfig, error) { 601 isIntermediate := false 602 admincert := [][]byte{} 603 n := types.NamespacedName{ 604 Name: fmt.Sprintf("ecert-%s%s%d-admincerts", instance.Name, NODE, 1), 605 Namespace: instance.Namespace, 606 } 607 adminCert := &corev1.Secret{} 608 err := o.Client.Get(context.TODO(), n, adminCert) 609 if err != nil { 610 if !k8serrors.IsNotFound(err) { 611 return nil, err 612 } 613 } 614 for _, cert := range adminCert.Data { 615 admincert = append(admincert, cert) 616 } 617 618 cacerts := [][]byte{} 619 n.Name = fmt.Sprintf("ecert-%s%s%d-cacerts", instance.Name, NODE, 1) 620 caCerts := &corev1.Secret{} 621 err = o.Client.Get(context.TODO(), n, caCerts) 622 if err != nil { 623 return nil, err 624 } 625 for _, cert := range caCerts.Data { 626 cacerts = append(cacerts, cert) 627 } 628 629 intermediateCerts := [][]byte{} 630 interCerts := &corev1.Secret{} 631 n.Name = fmt.Sprintf("ecert-%s%s%d-intercerts", instance.Name, NODE, 1) 632 err = o.Client.Get(context.TODO(), n, interCerts) 633 if err != nil { 634 if !k8serrors.IsNotFound(err) { 635 return nil, err 636 } 637 } 638 for _, cert := range interCerts.Data { 639 isIntermediate = true 640 intermediateCerts = append(intermediateCerts, cert) 641 } 642 643 cryptoConfig := &msp.FabricCryptoConfig{ 644 SignatureHashFamily: bccsp.SHA2, 645 IdentityIdentifierHashFunction: bccsp.SHA256, 646 } 647 648 tlsCACerts := [][]byte{} 649 n.Name = fmt.Sprintf("tls-%s%s%d-cacerts", instance.Name, NODE, 1) 650 tlsCerts := &corev1.Secret{} 651 err = o.Client.Get(context.TODO(), n, tlsCerts) 652 if err != nil { 653 return nil, err 654 } 655 for _, cert := range tlsCerts.Data { 656 tlsCACerts = append(tlsCACerts, cert) 657 } 658 659 tlsIntermediateCerts := [][]byte{} 660 tlsInterCerts := &corev1.Secret{} 661 n.Name = fmt.Sprintf("tls-%s%s%d-intercerts", instance.Name, NODE, 1) 662 err = o.Client.Get(context.TODO(), n, tlsInterCerts) 663 if err != nil { 664 if !k8serrors.IsNotFound(err) { 665 return nil, err 666 } 667 } 668 for _, cert := range tlsInterCerts.Data { 669 tlsIntermediateCerts = append(tlsIntermediateCerts, cert) 670 } 671 672 fmspconf := &msp.FabricMSPConfig{ 673 Admins: admincert, 674 RootCerts: cacerts, 675 IntermediateCerts: intermediateCerts, 676 Name: ID, 677 CryptoConfig: cryptoConfig, 678 TlsRootCerts: tlsCACerts, 679 TlsIntermediateCerts: tlsIntermediateCerts, 680 FabricNodeOus: &msp.FabricNodeOUs{ 681 Enable: true, 682 ClientOuIdentifier: &msp.FabricOUIdentifier{ 683 OrganizationalUnitIdentifier: "client", 684 Certificate: cacerts[0], 685 }, 686 PeerOuIdentifier: &msp.FabricOUIdentifier{ 687 OrganizationalUnitIdentifier: "peer", 688 Certificate: cacerts[0], 689 }, 690 AdminOuIdentifier: &msp.FabricOUIdentifier{ 691 OrganizationalUnitIdentifier: "admin", 692 Certificate: cacerts[0], 693 }, 694 OrdererOuIdentifier: &msp.FabricOUIdentifier{ 695 OrganizationalUnitIdentifier: "orderer", 696 Certificate: cacerts[0], 697 }, 698 }, 699 } 700 701 if isIntermediate { 702 fmspconf.FabricNodeOus.ClientOuIdentifier.Certificate = intermediateCerts[0] 703 fmspconf.FabricNodeOus.PeerOuIdentifier.Certificate = intermediateCerts[0] 704 fmspconf.FabricNodeOus.AdminOuIdentifier.Certificate = intermediateCerts[0] 705 fmspconf.FabricNodeOus.OrdererOuIdentifier.Certificate = intermediateCerts[0] 706 } 707 708 fmpsjs, err := proto.Marshal(fmspconf) 709 if err != nil { 710 return nil, err 711 } 712 713 mspconf := &msp.MSPConfig{Config: fmpsjs, Type: int32(fmsp.FABRIC)} 714 715 return mspconf, nil 716 } 717 718 func (o *Orderer) GetLabels(instance v1.Object) map[string]string { 719 label := os.Getenv("OPERATOR_LABEL_PREFIX") 720 if label == "" { 721 label = "fabric" 722 } 723 724 orderernode := instance.(*current.IBPOrderer) 725 726 name := instance.GetName() 727 728 if orderernode.Spec.NodeNumber != nil { 729 nodename := fmt.Sprintf("%snode%d", name, *orderernode.Spec.NodeNumber) 730 name = nodename 731 } 732 733 return map[string]string{ 734 "app": name, 735 "creator": label, 736 "parent": instance.GetName(), 737 "app.kubernetes.io/name": label, 738 "app.kubernetes.io/instance": label + "orderer", 739 "app.kubernetes.io/managed-by": label + "-operator", 740 } 741 } 742 743 func (o *Orderer) ReadOUConfigFile(instance *current.IBPOrderer, configFile string) ([]*msp.FabricOUIdentifier, *msp.FabricNodeOUs, error) { 744 var ouis []*msp.FabricOUIdentifier 745 var nodeOUs *msp.FabricNodeOUs 746 // load the file, if there is a failure in loading it then 747 // return an error 748 raw, err := ioutil.ReadFile(filepath.Clean(configFile)) 749 if err != nil { 750 return nil, nil, errors.Wrapf(err, "failed loading configuration file at [%s]", configFile) 751 } 752 753 configuration := fmsp.Configuration{} 754 err = yaml.Unmarshal(raw, &configuration) 755 if err != nil { 756 return nil, nil, errors.Wrapf(err, "failed unmarshalling configuration file at [%s]", configFile) 757 } 758 759 n := types.NamespacedName{ 760 Name: fmt.Sprintf("ecert-%s%s%d-cacerts", instance.Name, NODE, 1), 761 Namespace: instance.Namespace, 762 } 763 caCerts := &corev1.Secret{} 764 err = o.Client.Get(context.TODO(), n, caCerts) 765 if err != nil { 766 return nil, nil, err 767 } 768 rawCert := caCerts.Data["cacert-0.pem"] 769 770 // Prepare OrganizationalUnitIdentifiers 771 if len(configuration.OrganizationalUnitIdentifiers) > 0 { 772 for _, ouID := range configuration.OrganizationalUnitIdentifiers { 773 oui := &msp.FabricOUIdentifier{ 774 Certificate: rawCert, 775 OrganizationalUnitIdentifier: ouID.OrganizationalUnitIdentifier, 776 } 777 ouis = append(ouis, oui) 778 } 779 } 780 781 // Prepare NodeOUs 782 if configuration.NodeOUs != nil && configuration.NodeOUs.Enable { 783 nodeOUs = &msp.FabricNodeOUs{ 784 Enable: true, 785 } 786 if configuration.NodeOUs.ClientOUIdentifier != nil && len(configuration.NodeOUs.ClientOUIdentifier.OrganizationalUnitIdentifier) != 0 { 787 nodeOUs.ClientOuIdentifier = &msp.FabricOUIdentifier{OrganizationalUnitIdentifier: configuration.NodeOUs.ClientOUIdentifier.OrganizationalUnitIdentifier} 788 } 789 if configuration.NodeOUs.PeerOUIdentifier != nil && len(configuration.NodeOUs.PeerOUIdentifier.OrganizationalUnitIdentifier) != 0 { 790 nodeOUs.PeerOuIdentifier = &msp.FabricOUIdentifier{OrganizationalUnitIdentifier: configuration.NodeOUs.PeerOUIdentifier.OrganizationalUnitIdentifier} 791 } 792 if configuration.NodeOUs.AdminOUIdentifier != nil && len(configuration.NodeOUs.AdminOUIdentifier.OrganizationalUnitIdentifier) != 0 { 793 nodeOUs.AdminOuIdentifier = &msp.FabricOUIdentifier{OrganizationalUnitIdentifier: configuration.NodeOUs.AdminOUIdentifier.OrganizationalUnitIdentifier} 794 } 795 if configuration.NodeOUs.OrdererOUIdentifier != nil && len(configuration.NodeOUs.OrdererOUIdentifier.OrganizationalUnitIdentifier) != 0 { 796 nodeOUs.OrdererOuIdentifier = &msp.FabricOUIdentifier{OrganizationalUnitIdentifier: configuration.NodeOUs.OrdererOUIdentifier.OrganizationalUnitIdentifier} 797 } 798 799 // ClientOU 800 if nodeOUs.ClientOuIdentifier != nil { 801 nodeOUs.ClientOuIdentifier.Certificate = rawCert 802 } 803 // PeerOU 804 if nodeOUs.PeerOuIdentifier != nil { 805 nodeOUs.PeerOuIdentifier.Certificate = rawCert 806 } 807 // AdminOU 808 if nodeOUs.AdminOuIdentifier != nil { 809 nodeOUs.AdminOuIdentifier.Certificate = rawCert 810 } 811 // OrdererOU 812 if nodeOUs.OrdererOuIdentifier != nil { 813 nodeOUs.OrdererOuIdentifier.Certificate = rawCert 814 } 815 } 816 817 return ouis, nodeOUs, nil 818 } 819 820 func (o *Orderer) DeleteNode(instance *current.IBPOrderer, nodes int) error { 821 if nodes == 0 { 822 return errors.New("no cluster nodes left to delete") 823 } 824 825 node := o.GetNode(nodes) 826 err := node.Delete(instance) 827 if err != nil { 828 return errors.Wrapf(err, "failed to delete node '%s'", node.Name) 829 } 830 831 return nil 832 } 833 834 func (o *Orderer) GetNodes(instance *current.IBPOrderer) []*Node { 835 size := instance.Spec.ClusterSize 836 nodes := []*Node{} 837 for i := 1; i <= size; i++ { 838 node := o.GetNode(i) 839 nodes = append(nodes, node) 840 } 841 return nodes 842 } 843 844 func (o *Orderer) GetNode(nodeNumber int) *Node { 845 return o.NodeManager.GetNode(nodeNumber, o.RenewCertTimers, o.RestartManager) 846 } 847 848 func (o *Orderer) CheckCSRHosts(instance *current.IBPOrderer, hosts []string) { 849 if instance.Spec.Secret != nil { 850 if instance.Spec.Secret.Enrollment != nil { 851 if instance.Spec.Secret.Enrollment.TLS == nil { 852 instance.Spec.Secret.Enrollment.TLS = ¤t.Enrollment{} 853 } 854 if instance.Spec.Secret.Enrollment.TLS.CSR == nil { 855 instance.Spec.Secret.Enrollment.TLS.CSR = ¤t.CSR{} 856 instance.Spec.Secret.Enrollment.TLS.CSR.Hosts = hosts 857 } else { 858 for _, host := range instance.Spec.Secret.Enrollment.TLS.CSR.Hosts { 859 hosts = util.AppendStringIfMissing(hosts, host) 860 } 861 instance.Spec.Secret.Enrollment.TLS.CSR.Hosts = hosts 862 } 863 } 864 } 865 } 866 867 func GetDomainPort(address string) (string, string) { 868 u := strings.Split(address, ":") 869 return u[0], u[1] 870 } 871 872 func (o *Orderer) PatchStatus(instance *current.IBPOrderer) error { 873 return o.Client.PatchStatus(context.TODO(), instance, nil, k8sclient.PatchOption{ 874 Resilient: &k8sclient.ResilientPatch{ 875 Retry: 3, 876 Into: ¤t.IBPOrderer{}, 877 Strategy: client.MergeFrom, 878 }, 879 }) 880 } 881 882 func (o *Orderer) UpdateStatus(instance *current.IBPOrderer) error { 883 return o.Client.UpdateStatus(context.TODO(), instance) 884 }