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:     &current.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:     &current.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 = &current.Enrollment{}
   853  			}
   854  			if instance.Spec.Secret.Enrollment.TLS.CSR == nil {
   855  				instance.Spec.Secret.Enrollment.TLS.CSR = &current.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:     &current.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  }