github.com/IBM-Blockchain/fabric-operator@v1.0.4/controllers/ibporderer/ibporderer_controller.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 ibporderer
    20  
    21  import (
    22  	"context"
    23  	"encoding/json"
    24  	"fmt"
    25  	"reflect"
    26  	"strings"
    27  	"sync"
    28  	"time"
    29  
    30  	current "github.com/IBM-Blockchain/fabric-operator/api/v1beta1"
    31  	commoncontroller "github.com/IBM-Blockchain/fabric-operator/controllers/common"
    32  	config "github.com/IBM-Blockchain/fabric-operator/operatorconfig"
    33  	"github.com/IBM-Blockchain/fabric-operator/pkg/global"
    34  	orderer "github.com/IBM-Blockchain/fabric-operator/pkg/initializer/orderer/config/v1"
    35  	k8sclient "github.com/IBM-Blockchain/fabric-operator/pkg/k8s/controllerclient"
    36  	"github.com/IBM-Blockchain/fabric-operator/pkg/offering"
    37  	baseorderer "github.com/IBM-Blockchain/fabric-operator/pkg/offering/base/orderer"
    38  	"github.com/IBM-Blockchain/fabric-operator/pkg/offering/common"
    39  	k8sorderer "github.com/IBM-Blockchain/fabric-operator/pkg/offering/k8s/orderer"
    40  	openshiftorderer "github.com/IBM-Blockchain/fabric-operator/pkg/offering/openshift/orderer"
    41  	"github.com/IBM-Blockchain/fabric-operator/pkg/operatorerrors"
    42  	"github.com/IBM-Blockchain/fabric-operator/pkg/restart/staggerrestarts"
    43  	"github.com/IBM-Blockchain/fabric-operator/pkg/util"
    44  	"github.com/IBM-Blockchain/fabric-operator/version"
    45  	"github.com/pkg/errors"
    46  	yaml "sigs.k8s.io/yaml"
    47  
    48  	appsv1 "k8s.io/api/apps/v1"
    49  	corev1 "k8s.io/api/core/v1"
    50  	k8serrors "k8s.io/apimachinery/pkg/api/errors"
    51  	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
    52  	"k8s.io/apimachinery/pkg/labels"
    53  	"k8s.io/apimachinery/pkg/runtime"
    54  	"k8s.io/apimachinery/pkg/types"
    55  	ctrl "sigs.k8s.io/controller-runtime"
    56  	"sigs.k8s.io/controller-runtime/pkg/client"
    57  	"sigs.k8s.io/controller-runtime/pkg/controller"
    58  	"sigs.k8s.io/controller-runtime/pkg/event"
    59  	"sigs.k8s.io/controller-runtime/pkg/handler"
    60  	logf "sigs.k8s.io/controller-runtime/pkg/log"
    61  	"sigs.k8s.io/controller-runtime/pkg/manager"
    62  	"sigs.k8s.io/controller-runtime/pkg/predicate"
    63  	"sigs.k8s.io/controller-runtime/pkg/reconcile"
    64  	"sigs.k8s.io/controller-runtime/pkg/source"
    65  )
    66  
    67  const (
    68  	KIND = "IBPOrderer"
    69  )
    70  
    71  var log = logf.Log.WithName("controller_ibporderer")
    72  
    73  // Add creates a new IBPOrderer Controller and adds it to the Manager. The Manager will set fields on the Controller
    74  // and Start it when the Manager is Started.
    75  func Add(mgr manager.Manager, config *config.Config) error {
    76  	r, err := newReconciler(mgr, config)
    77  	if err != nil {
    78  		return err
    79  	}
    80  	return add(mgr, r)
    81  }
    82  
    83  // newReconciler returns a new reconcile.Reconciler
    84  func newReconciler(mgr manager.Manager, cfg *config.Config) (*ReconcileIBPOrderer, error) {
    85  	client := k8sclient.New(mgr.GetClient(), &global.ConfigSetter{Config: cfg.Operator.Globals})
    86  	scheme := mgr.GetScheme()
    87  
    88  	ibporderer := &ReconcileIBPOrderer{
    89  		client:         client,
    90  		scheme:         scheme,
    91  		Config:         cfg,
    92  		update:         map[string][]Update{},
    93  		mutex:          &sync.Mutex{},
    94  		RestartService: staggerrestarts.New(client, cfg.Operator.Restart.Timeout.Get()),
    95  	}
    96  
    97  	switch cfg.Offering {
    98  	case offering.K8S:
    99  		ibporderer.Offering = k8sorderer.New(client, scheme, cfg)
   100  	case offering.OPENSHIFT:
   101  		ibporderer.Offering = openshiftorderer.New(client, scheme, cfg)
   102  	}
   103  
   104  	return ibporderer, nil
   105  }
   106  
   107  // add adds a new Controller to mgr with r as the reconcile.Reconciler
   108  func add(mgr manager.Manager, r *ReconcileIBPOrderer) error {
   109  	// Create a new controller
   110  	predicateFuncs := predicate.Funcs{
   111  		CreateFunc: r.CreateFunc,
   112  		UpdateFunc: r.UpdateFunc,
   113  		DeleteFunc: r.DeleteFunc,
   114  	}
   115  
   116  	c, err := controller.New("ibporderer-controller", mgr, controller.Options{Reconciler: r})
   117  	if err != nil {
   118  		return err
   119  	}
   120  
   121  	// Watch for changes to primary resource IBPOrderer
   122  	err = c.Watch(&source.Kind{Type: &current.IBPOrderer{}}, &handler.EnqueueRequestForObject{}, predicateFuncs)
   123  	if err != nil {
   124  		return err
   125  	}
   126  
   127  	// Watch for changes to config maps (Create and Update funcs handle only watching for restart config map)
   128  	err = c.Watch(&source.Kind{Type: &corev1.ConfigMap{}}, &handler.EnqueueRequestForObject{}, predicateFuncs)
   129  	if err != nil {
   130  		return err
   131  	}
   132  
   133  	// TODO(user): Modify this to be the types you create that are owned by the primary resource
   134  	// Watch for changes to secondary resource Pods and requeue the owner IBPOrderer
   135  	err = c.Watch(&source.Kind{Type: &appsv1.Deployment{}}, &handler.EnqueueRequestForOwner{
   136  		IsController: true,
   137  		OwnerType:    &current.IBPOrderer{},
   138  	})
   139  	if err != nil {
   140  		return err
   141  	}
   142  
   143  	// Watch for changes to tertiary resource Secrets and requeue the owner IBPOrderer
   144  	err = c.Watch(&source.Kind{Type: &corev1.Secret{}}, &handler.EnqueueRequestForOwner{
   145  		IsController: true,
   146  		OwnerType:    &current.IBPOrderer{},
   147  	}, predicateFuncs)
   148  	if err != nil {
   149  		return err
   150  	}
   151  
   152  	return nil
   153  }
   154  
   155  var _ reconcile.Reconciler = &ReconcileIBPOrderer{}
   156  
   157  //go:generate counterfeiter -o mocks/ordererreconcile.go -fake-name OrdererReconcile . ordererReconcile
   158  
   159  type ordererReconcile interface {
   160  	Reconcile(*current.IBPOrderer, baseorderer.Update) (common.Result, error)
   161  }
   162  
   163  // ReconcileIBPOrderer reconciles a IBPOrderer object
   164  type ReconcileIBPOrderer struct {
   165  	// This client, initialized using mgr.Client() above, is a split client
   166  	// that reads objects from the cache and writes to the apiserver
   167  	client k8sclient.Client
   168  	scheme *runtime.Scheme
   169  
   170  	Offering       ordererReconcile
   171  	Config         *config.Config
   172  	RestartService *staggerrestarts.StaggerRestartsService
   173  
   174  	update map[string][]Update
   175  	mutex  *sync.Mutex
   176  }
   177  
   178  // Reconcile reads that state of the cluster for a IBPOrderer object and makes changes based on the state read
   179  // and what is in the IBPOrderer.Spec
   180  // Note:
   181  // The Controller will requeue the Request to be processed again if the returned error is non-nil or
   182  // Result.Requeue is true, otherwise upon completion it will remove the work from the queue.
   183  func (r *ReconcileIBPOrderer) Reconcile(ctx context.Context, request reconcile.Request) (reconcile.Result, error) {
   184  	var err error
   185  
   186  	reqLogger := log.WithValues("Request.Namespace", request.Namespace, "Request.Name", request.Name)
   187  
   188  	// If orderer-restart-config configmap is the object being reconciled, reconcile the
   189  	// restart configmap.
   190  	if request.Name == "orderer-restart-config" {
   191  		requeue, err := r.ReconcileRestart(request.Namespace)
   192  		// Error reconciling restart - requeue the request.
   193  		if err != nil {
   194  			return reconcile.Result{}, err
   195  		}
   196  		// Restart reconciled, requeue request if required.
   197  		return reconcile.Result{
   198  			Requeue: requeue,
   199  		}, nil
   200  	}
   201  
   202  	reqLogger.Info("Reconciling IBPOrderer")
   203  
   204  	// Fetch the IBPOrderer instance
   205  	instance := &current.IBPOrderer{}
   206  	err = r.client.Get(context.TODO(), request.NamespacedName, instance)
   207  	if err != nil {
   208  		if k8serrors.IsNotFound(err) {
   209  			// Request object not found, could have been deleted after reconcile request.
   210  			// Owned objects are automatically garbage collected. For additional cleanup logic use finalizers.
   211  			// Return and don't requeue
   212  			return reconcile.Result{}, nil
   213  		}
   214  		// Error reading the object - requeue the request.
   215  		return reconcile.Result{}, operatorerrors.IsBreakingError(err, "failed to reconcile restart", log)
   216  	}
   217  
   218  	var maxNameLength *int
   219  	if instance.Spec.ConfigOverride != nil {
   220  		override := &orderer.OrdererOverrides{}
   221  		err := json.Unmarshal(instance.Spec.ConfigOverride.Raw, override)
   222  		if err != nil {
   223  			return reconcile.Result{}, err
   224  		}
   225  		maxNameLength = override.MaxNameLength
   226  	}
   227  
   228  	err = util.ValidationChecks(instance.TypeMeta, instance.ObjectMeta, "IBPOrderer", maxNameLength)
   229  	if err != nil {
   230  		return reconcile.Result{}, err
   231  	}
   232  
   233  	if instance.Spec.NodeNumber == nil {
   234  		// If version is nil, then this is a v210 instance and the reconcile
   235  		// loop needs to be triggered to allow for instance migration
   236  		if instance.Status.Version != "" {
   237  			if instance.Status.Type == current.Deployed || instance.Status.Type == current.Warning {
   238  				// This is cluster's update, we don't want to reconcile.
   239  				// It should only be status update
   240  				log.Info(fmt.Sprintf("Update detected on %s cluster spec '%s', not supported", instance.Status.Type, instance.GetName()))
   241  				return reconcile.Result{}, nil
   242  			}
   243  		}
   244  	}
   245  
   246  	reqLogger.Info(fmt.Sprintf("Current update stack to process: %+v", GetUpdateStack(r.update)))
   247  
   248  	update := r.GetUpdateStatus(instance)
   249  	reqLogger.Info(fmt.Sprintf("Reconciling IBPOrderer '%s' with update values of [ %+v ]", instance.GetName(), update.GetUpdateStackWithTrues()))
   250  
   251  	result, err := r.Offering.Reconcile(instance, r.PopUpdate(instance.Name))
   252  	setStatusErr := r.SetStatus(instance, &result, err)
   253  	if setStatusErr != nil {
   254  		return reconcile.Result{}, operatorerrors.IsBreakingError(setStatusErr, "failed to update status", log)
   255  	}
   256  
   257  	if err != nil {
   258  		return reconcile.Result{}, operatorerrors.IsBreakingError(errors.Wrapf(err, "Orderer instance '%s' encountered error", instance.GetName()), "stopping reconcile loop", log)
   259  	}
   260  
   261  	if result.Requeue {
   262  		r.PushUpdate(instance.Name, *update)
   263  	}
   264  
   265  	reqLogger.Info(fmt.Sprintf("Finished reconciling IBPOrderer '%s' with update values of [ %+v ]", instance.GetName(), update.GetUpdateStackWithTrues()))
   266  
   267  	// If the stack still has items that require processing, keep reconciling
   268  	// until the stack has been cleared
   269  	_, found := r.update[instance.GetName()]
   270  	if found {
   271  		if len(r.update[instance.GetName()]) > 0 {
   272  			return reconcile.Result{
   273  				Requeue: true,
   274  			}, nil
   275  		}
   276  	}
   277  
   278  	return result.Result, nil
   279  }
   280  
   281  func (r *ReconcileIBPOrderer) SetStatus(instance *current.IBPOrderer, result *common.Result, reconcileErr error) error {
   282  	err := r.SaveSpecState(instance)
   283  	if err != nil {
   284  		return errors.Wrap(err, "failed to save spec state")
   285  	}
   286  
   287  	// Hierachy of setting status on orderer node instance
   288  	// 1. If error has occurred update status and return
   289  	// 2. If error has not occurred, get list of pods and determine
   290  	// if pods are all running or still waiting to start. If all pods
   291  	// are running mark status as Deployed otherwise mark status as
   292  	// Deploying, but dont update status yet
   293  	// 3. Check to see if a custom status has been passed. If so,
   294  	// set that status but don't update. However, if OverrideUpdateStatus
   295  	// flag is set to true update the status and return
   296  	// 4. If OverrideUpdateStatus was not set in step 3, determine if genesis
   297  	// secret exists for the instance. If genesis secret does not exit update
   298  	// the status to precreate and return
   299  
   300  	// Need to get to ensure we are working with the latest state of the instance
   301  	err = r.client.Get(context.TODO(), types.NamespacedName{Name: instance.GetName(), Namespace: instance.GetNamespace()}, instance)
   302  	if err != nil {
   303  		return err
   304  	}
   305  
   306  	status := instance.Status.CRStatus
   307  
   308  	if reconcileErr != nil {
   309  		status.Type = current.Error
   310  		status.Status = current.True
   311  		status.Reason = "errorOccurredDuringReconcile"
   312  		status.Message = reconcileErr.Error()
   313  		status.LastHeartbeatTime = time.Now().String()
   314  		status.ErrorCode = operatorerrors.GetErrorCode(reconcileErr)
   315  
   316  		instance.Status = current.IBPOrdererStatus{
   317  			CRStatus: status,
   318  		}
   319  
   320  		log.Info(fmt.Sprintf("Updating status of IBPOrderer custom resource (%s) to %s phase", instance.GetName(), instance.Status.Type))
   321  		err := r.client.PatchStatus(context.TODO(), instance, nil, k8sclient.PatchOption{
   322  			Resilient: &k8sclient.ResilientPatch{
   323  				Retry:    2,
   324  				Into:     &current.IBPOrderer{},
   325  				Strategy: client.MergeFrom,
   326  			},
   327  		})
   328  		if err != nil {
   329  			return err
   330  		}
   331  
   332  		return nil
   333  	}
   334  
   335  	status.Versions.Reconciled = instance.Spec.FabricVersion
   336  
   337  	// If this is a parent (cluster spec), then ignore setting status. Status should
   338  	// be set by the child nodes only, and child nodes should update the status of parent
   339  	// according to the statuses of the child nodes. This needs to stay after the check for
   340  	// reconcile error otherwise the CR won't get updated with error on parent CR if there
   341  	// are validation errors on the spec.
   342  	if instance.Spec.NodeNumber == nil {
   343  		return nil
   344  	}
   345  
   346  	podStatus, err := r.GetPodStatus(instance)
   347  	if err != nil {
   348  		return err
   349  	}
   350  
   351  	numberOfPodsRunning := 0
   352  	for _, status := range podStatus {
   353  		if status.Phase == corev1.PodRunning {
   354  			numberOfPodsRunning++
   355  		}
   356  	}
   357  
   358  	// if numberOfPodsRunning == len(podStatus) && len(podStatus) > 0 {
   359  	if len(podStatus) > 0 {
   360  		if len(podStatus) == numberOfPodsRunning {
   361  			status.Type = current.Deployed
   362  			status.Status = current.True
   363  			status.Reason = "allPodsRunning"
   364  			status.Message = "allPodsRunning"
   365  		} else {
   366  			status.Type = current.Deploying
   367  			status.Status = current.True
   368  			status.Reason = "waitingForPods"
   369  			status.Message = "waitingForPods"
   370  		}
   371  	}
   372  
   373  	// Check if reconcile loop returned an updated status that differs from exisiting status.
   374  	// If so, set status to the reconcile status.
   375  	if result != nil {
   376  		reconcileStatus := result.Status
   377  		if reconcileStatus != nil {
   378  			if instance.Status.Type != reconcileStatus.Type || instance.Status.Reason != reconcileStatus.Reason || instance.Status.Message != reconcileStatus.Message {
   379  				status.Type = reconcileStatus.Type
   380  				status.Status = current.True
   381  				status.Reason = reconcileStatus.Reason
   382  				status.Message = reconcileStatus.Message
   383  				status.LastHeartbeatTime = time.Now().String()
   384  
   385  				if result.OverrideUpdateStatus {
   386  					instance.Status = current.IBPOrdererStatus{
   387  						CRStatus: status,
   388  					}
   389  
   390  					log.Info(fmt.Sprintf("Updating status returned by reconcile loop of IBPOrderer custom resource (%s) to %s phase", instance.GetName(), instance.Status.Type))
   391  					err := r.client.PatchStatus(context.TODO(), instance, nil, k8sclient.PatchOption{
   392  						Resilient: &k8sclient.ResilientPatch{
   393  							Retry:    2,
   394  							Into:     &current.IBPOrderer{},
   395  							Strategy: client.MergeFrom,
   396  						},
   397  					})
   398  					if err != nil {
   399  						return err
   400  					}
   401  
   402  					return nil
   403  				}
   404  			} else {
   405  				// If the reconcile loop returned an updated status that is the same as the current instance status, then no status update required.
   406  				// NOTE: This will only occur once the instance has hit Deployed state for the first time and would only switch between Deployed and
   407  				// Warning states.
   408  				log.Info(fmt.Sprintf("Reconcile loop returned a status that is the same as %s's current status (%s), not updating status", reconcileStatus.Type, instance.Name))
   409  				return nil
   410  			}
   411  		}
   412  
   413  		// There are cases we want to return before checking for genesis secrets, such as updating the spec with default values
   414  		// during prereconcile checks
   415  		if result.OverrideUpdateStatus {
   416  			return nil
   417  		}
   418  	}
   419  
   420  	precreated := false
   421  	if instance.Spec.IsUsingChannelLess() {
   422  		log.Info(fmt.Sprintf("IBPOrderer custom resource (%s) is using channel less mode", instance.GetName()))
   423  		precreated = false
   424  	} else {
   425  		err = r.GetGenesisSecret(instance)
   426  		if err != nil {
   427  			log.Info(fmt.Sprintf("IBPOrderer custom resource (%s) pods are waiting for genesis block, setting status to precreate", instance.GetName()))
   428  			precreated = true
   429  		}
   430  	}
   431  
   432  	if precreated {
   433  		status.Type = current.Precreated
   434  		status.Status = current.True
   435  		status.Reason = "waiting for genesis block"
   436  		status.Message = "waiting for genesis block"
   437  	}
   438  
   439  	// Only update status if status is different from current status
   440  	if status.Type != "" && (instance.Status.Type != status.Type || instance.Status.Reason != status.Reason || instance.Status.Message != status.Message) {
   441  		status.LastHeartbeatTime = time.Now().String()
   442  		log.Info(fmt.Sprintf("Updating status of IBPOrderer custom resource (%s) from %s to %s phase", instance.GetName(), instance.Status.Type, status.Type))
   443  
   444  		instance.Status = current.IBPOrdererStatus{
   445  			CRStatus: status,
   446  		}
   447  
   448  		err = r.client.PatchStatus(context.TODO(), instance, nil, k8sclient.PatchOption{
   449  			Resilient: &k8sclient.ResilientPatch{
   450  				Retry:    2,
   451  				Into:     &current.IBPOrderer{},
   452  				Strategy: client.MergeFrom,
   453  			},
   454  		})
   455  		if err != nil {
   456  			return err
   457  		}
   458  	}
   459  
   460  	return nil
   461  }
   462  
   463  func (r *ReconcileIBPOrderer) SaveSpecState(instance *current.IBPOrderer) error {
   464  	data, err := yaml.Marshal(instance.Spec)
   465  	if err != nil {
   466  		return err
   467  	}
   468  
   469  	cm := &corev1.ConfigMap{
   470  		ObjectMeta: metav1.ObjectMeta{
   471  			Name:      fmt.Sprintf("%s-spec", instance.GetName()),
   472  			Namespace: instance.GetNamespace(),
   473  			Labels:    instance.GetLabels(),
   474  		},
   475  		BinaryData: map[string][]byte{
   476  			"spec": data,
   477  		},
   478  	}
   479  
   480  	err = r.client.CreateOrUpdate(context.TODO(), cm, k8sclient.CreateOrUpdateOption{Owner: instance, Scheme: r.scheme})
   481  	if err != nil {
   482  		return err
   483  	}
   484  
   485  	return nil
   486  }
   487  
   488  func (r *ReconcileIBPOrderer) GetSpecState(instance *current.IBPOrderer) (*corev1.ConfigMap, error) {
   489  	cm := &corev1.ConfigMap{}
   490  	nn := types.NamespacedName{
   491  		Name:      fmt.Sprintf("%s-spec", instance.GetName()),
   492  		Namespace: instance.GetNamespace(),
   493  	}
   494  
   495  	err := r.client.Get(context.TODO(), nn, cm)
   496  	if err != nil {
   497  		return nil, err
   498  	}
   499  
   500  	return cm, nil
   501  }
   502  
   503  func (r *ReconcileIBPOrderer) GetPodStatus(instance *current.IBPOrderer) (map[string]corev1.PodStatus, error) {
   504  	statuses := map[string]corev1.PodStatus{}
   505  
   506  	labelSelector, err := labels.Parse(fmt.Sprintf("app=%s", instance.GetName()))
   507  	if err != nil {
   508  		return statuses, errors.Wrap(err, "failed to parse label selector for app name")
   509  	}
   510  
   511  	listOptions := &client.ListOptions{
   512  		LabelSelector: labelSelector,
   513  		Namespace:     instance.GetNamespace(),
   514  	}
   515  
   516  	podList := &corev1.PodList{}
   517  	err = r.client.List(context.TODO(), podList, listOptions)
   518  	if err != nil {
   519  		return statuses, err
   520  	}
   521  
   522  	for _, pod := range podList.Items {
   523  		statuses[pod.Name] = pod.Status
   524  	}
   525  
   526  	return statuses, nil
   527  }
   528  
   529  func (r *ReconcileIBPOrderer) GetGenesisSecret(instance *current.IBPOrderer) error {
   530  	nn := types.NamespacedName{
   531  		Name:      fmt.Sprintf("%s-genesis", instance.GetName()),
   532  		Namespace: instance.GetNamespace(),
   533  	}
   534  	err := r.client.Get(context.TODO(), nn, &corev1.Secret{})
   535  	if err != nil {
   536  		return err
   537  	}
   538  
   539  	return nil
   540  }
   541  
   542  func (r *ReconcileIBPOrderer) CreateFunc(e event.CreateEvent) bool {
   543  	update := Update{}
   544  
   545  	switch e.Object.(type) {
   546  	case *current.IBPOrderer:
   547  		orderer := e.Object.(*current.IBPOrderer)
   548  		log.Info(fmt.Sprintf("Create event detected for orderer '%s'", orderer.GetName()))
   549  
   550  		if orderer.Status.HasType() {
   551  			log.Info(fmt.Sprintf("Operator restart detected, performing update checks on exisitng orderer '%s'", orderer.GetName()))
   552  
   553  			cm, err := r.GetSpecState(orderer)
   554  			if err != nil {
   555  				log.Info(fmt.Sprintf("Failed getting saved orderer spec '%s', can't perform update checks, triggering reconcile: %s", orderer.GetName(), err.Error()))
   556  				return true
   557  			}
   558  
   559  			specBytes := cm.BinaryData["spec"]
   560  			savedOrderer := &current.IBPOrderer{}
   561  
   562  			err = yaml.Unmarshal(specBytes, &savedOrderer.Spec)
   563  			if err != nil {
   564  				log.Info(fmt.Sprintf("Unmarshal failed for saved orderer spec '%s', can't perform update checks, triggering reconcile: %s", orderer.GetName(), err.Error()))
   565  				return true
   566  			}
   567  
   568  			if !reflect.DeepEqual(orderer.Spec, savedOrderer.Spec) {
   569  				log.Info(fmt.Sprintf("IBPOrderer '%s' spec was updated while operator was down", orderer.GetName()))
   570  				update.specUpdated = true
   571  			}
   572  
   573  			if !reflect.DeepEqual(orderer.Spec.ConfigOverride, savedOrderer.Spec.ConfigOverride) {
   574  				log.Info(fmt.Sprintf("IBPOrderer '%s' overrides were updated while operator was down", orderer.GetName()))
   575  				update.overridesUpdated = true
   576  			}
   577  
   578  			update.imagesUpdated = imagesUpdated(savedOrderer, orderer)
   579  			update.fabricVersionUpdated = fabricVersionUpdated(savedOrderer, orderer)
   580  			if fabricVersionUpdatedTo149plusOr221plus(savedOrderer, orderer) {
   581  				log.Info(fmt.Sprintf("Fabric version update detected from '%s' to '%s' setting tls cert created flag '%s'", savedOrderer.Spec.FabricVersion, orderer.Spec.FabricVersion, orderer.GetName()))
   582  				update.tlsCertCreated = true
   583  			}
   584  
   585  			log.Info(fmt.Sprintf("Create event triggering reconcile for updating orderer '%s'", orderer.GetName()))
   586  			r.PushUpdate(orderer.GetName(), update)
   587  		}
   588  
   589  		// If creating resource for the first time, check that a unique name is provided
   590  		err := commoncontroller.ValidateCRName(r.client, orderer.Name, orderer.Namespace, commoncontroller.IBPORDERER)
   591  		if err != nil {
   592  			log.Error(err, "failed to validate orderer name")
   593  			operror := operatorerrors.Wrap(err, operatorerrors.InvalidCustomResourceCreateRequest, "failed to validate custom resource name")
   594  			err = r.SetStatus(orderer, nil, operror)
   595  			if err != nil {
   596  				log.Error(err, "failed to set status to error", "orderer.name", orderer.Name, "error", "InvalidCustomResourceCreateRequest")
   597  			}
   598  			return false
   599  		}
   600  
   601  		log.Info(fmt.Sprintf("Create event triggering reconcile for creating orderer '%s'", orderer.GetName()))
   602  
   603  	case *corev1.Secret:
   604  		secret := e.Object.(*corev1.Secret)
   605  
   606  		if secret.OwnerReferences == nil || len(secret.OwnerReferences) == 0 {
   607  			isOrdererSecret, err := r.AddOwnerReferenceToSecret(secret)
   608  			if err != nil || !isOrdererSecret {
   609  				return false
   610  			}
   611  		}
   612  
   613  		if secret.OwnerReferences[0].Kind == KIND {
   614  			log.Info(fmt.Sprintf("Create event detected for secret '%s'", secret.GetName()))
   615  			instanceName := secret.OwnerReferences[0].Name
   616  			if util.IsSecretTLSCert(secret.Name) {
   617  				update.tlsCertCreated = true
   618  			} else if util.IsSecretEcert(secret.Name) {
   619  				update.ecertCreated = true
   620  			} else {
   621  				return false
   622  			}
   623  
   624  			log.Info(fmt.Sprintf("Orderer crypto create triggering reconcile on IBPOrderer custom resource %s: update [ %+v ]", instanceName, update.GetUpdateStackWithTrues()))
   625  			r.PushUpdate(instanceName, update)
   626  		}
   627  
   628  	case *appsv1.Deployment:
   629  		dep := e.Object.(*appsv1.Deployment)
   630  		log.Info(fmt.Sprintf("Create event detected by IBPOrderer controller for deployment '%s', triggering reconcile", dep.GetName()))
   631  
   632  	case *corev1.ConfigMap:
   633  		cm := e.Object.(*corev1.ConfigMap)
   634  		if cm.Name == "orderer-restart-config" {
   635  			log.Info(fmt.Sprintf("Create event detected by IBPOrderer contoller for config map '%s', triggering restart reconcile", cm.GetName()))
   636  		} else {
   637  			return false
   638  		}
   639  
   640  	}
   641  
   642  	return true
   643  }
   644  
   645  func (r *ReconcileIBPOrderer) UpdateFunc(e event.UpdateEvent) bool {
   646  	update := Update{}
   647  
   648  	switch e.ObjectOld.(type) {
   649  	case *current.IBPOrderer:
   650  		oldOrderer := e.ObjectOld.(*current.IBPOrderer)
   651  		newOrderer := e.ObjectNew.(*current.IBPOrderer)
   652  		log.Info(fmt.Sprintf("Update event detected for orderer '%s'", oldOrderer.GetName()))
   653  
   654  		if oldOrderer.Spec.NodeNumber == nil {
   655  			if oldOrderer.Status.Type != newOrderer.Status.Type {
   656  				log.Info(fmt.Sprintf("Parent orderer %s status updated from %s to %s", oldOrderer.Name, oldOrderer.Status.Type, newOrderer.Status.Type))
   657  			}
   658  
   659  			if oldOrderer.Status.Type == current.Deployed || oldOrderer.Status.Type == current.Error || oldOrderer.Status.Type == current.Warning {
   660  				// Parent orderer has been fully deployed by this point
   661  				log.Info(fmt.Sprintf("Ignoring the IBPOrderer cluster (parent) update after %s", oldOrderer.Status.Type))
   662  				return false
   663  			}
   664  
   665  		}
   666  
   667  		if util.CheckIfZoneOrRegionUpdated(oldOrderer.Spec.Zone, newOrderer.Spec.Zone) {
   668  			log.Error(errors.New("Zone update is not allowed"), "invalid spec update")
   669  			return false
   670  		}
   671  
   672  		if util.CheckIfZoneOrRegionUpdated(oldOrderer.Spec.Region, newOrderer.Spec.Region) {
   673  			log.Error(errors.New("Region update is not allowed"), "invalid spec update")
   674  			return false
   675  		}
   676  
   677  		// Need to trigger update when status has changed is to allow us update the
   678  		// status of the parent, since the status of the parent depends on the status
   679  		// of its children .Only flag status update when there is a meaninful change
   680  		// and not everytime the heartbeat is updated
   681  		if oldOrderer.Status != newOrderer.Status {
   682  			if oldOrderer.Status.Type != newOrderer.Status.Type ||
   683  				oldOrderer.Status.Reason != newOrderer.Status.Reason ||
   684  				oldOrderer.Status.Message != newOrderer.Status.Message {
   685  
   686  				log.Info(fmt.Sprintf("%s status changed to '%+v' from '%+v'", oldOrderer.GetName(), newOrderer.Status, oldOrderer.Status))
   687  				update.statusUpdated = true
   688  			}
   689  		}
   690  
   691  		if !reflect.DeepEqual(oldOrderer.Spec.ConfigOverride, newOrderer.Spec.ConfigOverride) {
   692  			log.Info(fmt.Sprintf("%s config override updated", oldOrderer.GetName()))
   693  			update.overridesUpdated = true
   694  		}
   695  
   696  		if !reflect.DeepEqual(oldOrderer.Spec, newOrderer.Spec) {
   697  			log.Info(fmt.Sprintf("%s spec updated", oldOrderer.GetName()))
   698  			update.specUpdated = true
   699  		}
   700  
   701  		// Check for changes to orderer tag to determine if any migration logic needs to be executed
   702  		// from old orderer version to new orderer version
   703  		if oldOrderer.Spec.Images != nil && newOrderer.Spec.Images != nil {
   704  			if oldOrderer.Spec.Images.OrdererTag != newOrderer.Spec.Images.OrdererTag {
   705  				log.Info(fmt.Sprintf("%s orderer tag updated from %s to %s", oldOrderer.GetName(), oldOrderer.Spec.Images.OrdererTag, newOrderer.Spec.Images.OrdererTag))
   706  				update.ordererTagUpdated = true
   707  			}
   708  		}
   709  
   710  		if fabricVersionUpdatedTo149plusOr221plus(oldOrderer, newOrderer) {
   711  			log.Info(fmt.Sprintf("Fabric version update detected from '%s' to '%s' setting tls cert created flag '%s'", oldOrderer.Spec.FabricVersion, newOrderer.Spec.FabricVersion, newOrderer.GetName()))
   712  			update.tlsCertCreated = true
   713  		}
   714  
   715  		update.mspUpdated = commoncontroller.MSPInfoUpdateDetected(oldOrderer.Spec.Secret, newOrderer.Spec.Secret)
   716  
   717  		if newOrderer.Spec.Action.Restart {
   718  			update.restartNeeded = true
   719  		}
   720  
   721  		if oldOrderer.Spec.Action.Reenroll.Ecert != newOrderer.Spec.Action.Reenroll.Ecert {
   722  			update.ecertReenrollNeeded = newOrderer.Spec.Action.Reenroll.Ecert
   723  		}
   724  
   725  		if oldOrderer.Spec.Action.Reenroll.TLSCert != newOrderer.Spec.Action.Reenroll.TLSCert {
   726  			update.tlscertReenrollNeeded = newOrderer.Spec.Action.Reenroll.TLSCert
   727  		}
   728  
   729  		if oldOrderer.Spec.Action.Reenroll.EcertNewKey != newOrderer.Spec.Action.Reenroll.EcertNewKey {
   730  			update.ecertNewKeyReenroll = newOrderer.Spec.Action.Reenroll.EcertNewKey
   731  		}
   732  
   733  		if oldOrderer.Spec.Action.Reenroll.TLSCertNewKey != newOrderer.Spec.Action.Reenroll.TLSCertNewKey {
   734  			update.tlscertNewKeyReenroll = newOrderer.Spec.Action.Reenroll.TLSCertNewKey
   735  		}
   736  
   737  		if newOrderer.Spec.Action.Enroll.Ecert {
   738  			update.ecertEnroll = true
   739  		}
   740  
   741  		if newOrderer.Spec.Action.Enroll.TLSCert {
   742  			update.tlscertEnroll = true
   743  		}
   744  
   745  		update.deploymentUpdated = deploymentUpdated(oldOrderer, newOrderer)
   746  		oldVer := version.String(oldOrderer.Spec.FabricVersion)
   747  		newVer := version.String(newOrderer.Spec.FabricVersion)
   748  
   749  		// check if this V1 -> V2.2.x/V2.4.x orderer migration
   750  		if (oldOrderer.Spec.FabricVersion == "" ||
   751  			version.GetMajorReleaseVersion(oldOrderer.Spec.FabricVersion) == version.V1) &&
   752  			version.GetMajorReleaseVersion(newOrderer.Spec.FabricVersion) == version.V2 {
   753  			update.migrateToV2 = true
   754  			if newVer.EqualWithoutTag(version.V2_4_1) || newVer.GreaterThan(version.V2_4_1) {
   755  				update.migrateToV24 = true
   756  				// Re-enrolling tls cert to include admin hostname in SAN (for orderers >=2.4.1)
   757  				update.tlscertReenrollNeeded = true
   758  			}
   759  		}
   760  
   761  		// check if this V2.2.x -> V2.4.x orderer migration
   762  		if (version.GetMajorReleaseVersion(oldOrderer.Spec.FabricVersion) == version.V2) &&
   763  			oldVer.LessThan(version.V2_4_1) &&
   764  			(newVer.EqualWithoutTag(version.V2_4_1) || newVer.GreaterThan(version.V2_4_1)) {
   765  			update.migrateToV24 = true
   766  			// Re-enrolling tls cert to include admin hostname in SAN (for orderers >=2.4.1)
   767  			update.tlscertReenrollNeeded = true
   768  		}
   769  
   770  		if oldOrderer.Spec.NodeOUDisabled() != newOrderer.Spec.NodeOUDisabled() {
   771  			update.nodeOUUpdated = true
   772  		}
   773  
   774  		// if use updates NumSecondsWarningPeriod field once we have already run the reconcile
   775  		// we need to retrigger the timer logic
   776  		if oldOrderer.Spec.NumSecondsWarningPeriod != newOrderer.Spec.NumSecondsWarningPeriod {
   777  			update.ecertUpdated = true
   778  			update.tlsCertUpdated = true
   779  			log.Info(fmt.Sprintf("%s NumSecondsWarningPeriod updated", oldOrderer.GetName()))
   780  		}
   781  
   782  		if update.Detected() {
   783  			log.Info(fmt.Sprintf("Spec update triggering reconcile on IBPOrderer custom resource %s: update [ %+v ]", oldOrderer.GetName(), update.GetUpdateStackWithTrues()))
   784  			r.PushUpdate(oldOrderer.GetName(), update)
   785  			return true
   786  		}
   787  
   788  	case *appsv1.Deployment:
   789  		oldDeployment := e.ObjectOld.(*appsv1.Deployment)
   790  		log.Info(fmt.Sprintf("Spec update detected by IBPOrderer controller on deployment '%s'", oldDeployment.GetName()))
   791  
   792  	case *corev1.Secret:
   793  		oldSecret := e.ObjectOld.(*corev1.Secret)
   794  		newSecret := e.ObjectNew.(*corev1.Secret)
   795  
   796  		if oldSecret.OwnerReferences == nil || len(oldSecret.OwnerReferences) == 0 {
   797  			isOrdererSecret, err := r.AddOwnerReferenceToSecret(oldSecret)
   798  			if err != nil || !isOrdererSecret {
   799  				return false
   800  			}
   801  		}
   802  
   803  		if oldSecret.OwnerReferences[0].Kind == KIND {
   804  			if reflect.DeepEqual(oldSecret.Data, newSecret.Data) {
   805  				return false
   806  			}
   807  
   808  			log.Info(fmt.Sprintf("Update event detected on secret '%s'", oldSecret.GetName()))
   809  			instanceName := oldSecret.OwnerReferences[0].Name
   810  			if util.IsSecretTLSCert(oldSecret.Name) {
   811  				update.tlsCertUpdated = true
   812  				log.Info(fmt.Sprintf("TLS cert updated for %s", instanceName))
   813  			}
   814  			if util.IsSecretEcert(oldSecret.Name) {
   815  				update.ecertUpdated = true
   816  				log.Info(fmt.Sprintf("ecert updated for %s", instanceName))
   817  			}
   818  
   819  			if update.CertificateUpdated() {
   820  				log.Info(fmt.Sprintf("Orderer crypto update triggering reconcile on IBPOrderer custom resource %s: update [ %+v ]", instanceName, update.GetUpdateStackWithTrues()))
   821  				r.PushUpdate(instanceName, update)
   822  				return true
   823  			}
   824  		}
   825  
   826  	case *corev1.ConfigMap:
   827  		cm := e.ObjectOld.(*corev1.ConfigMap)
   828  		if cm.Name == "orderer-restart-config" {
   829  			log.Info("Update event detected for orderer-restart-config, triggering restart reconcile")
   830  			return true
   831  		}
   832  	}
   833  
   834  	return false
   835  }
   836  
   837  func (r *ReconcileIBPOrderer) DeleteFunc(e event.DeleteEvent) bool {
   838  	switch e.Object.(type) {
   839  	case *current.IBPOrderer:
   840  		oldOrderer := e.Object.(*current.IBPOrderer)
   841  
   842  		if oldOrderer.Spec.NodeNumber != nil {
   843  			log.Info(fmt.Sprintf("Orderer node %d (%s) deleted", *oldOrderer.Spec.NodeNumber, oldOrderer.GetName()))
   844  
   845  			// Deleting this config map manually, in 2.5.1 release of operator this config map was created
   846  			// without proper controller references set and was not cleaned up on orderer resource deletion.
   847  			log.Info(fmt.Sprintf("Deleting %s-init-config config map, if found", oldOrderer.GetName()))
   848  			if err := r.client.Delete(context.TODO(), &corev1.ConfigMap{
   849  				ObjectMeta: metav1.ObjectMeta{
   850  					Name:      fmt.Sprintf("%s-init-config", oldOrderer.GetName()),
   851  					Namespace: oldOrderer.GetNamespace(),
   852  				},
   853  			}); client.IgnoreNotFound(err) != nil {
   854  				log.Info(fmt.Sprintf("failed to delete config map: %s", err))
   855  			}
   856  
   857  			parentName := oldOrderer.ObjectMeta.Labels["parent"]
   858  			labelSelector, err := labels.Parse(fmt.Sprintf("parent=%s", parentName))
   859  			if err != nil {
   860  				log.Info(fmt.Sprintf("failed to parse selector for parent name: %s", err.Error()))
   861  				return false
   862  			}
   863  
   864  			listOptions := &client.ListOptions{
   865  				LabelSelector: labelSelector,
   866  				Namespace:     oldOrderer.GetNamespace(),
   867  			}
   868  
   869  			ordererList := &current.IBPOrdererList{}
   870  			err = r.client.List(context.TODO(), ordererList, listOptions)
   871  			if err != nil {
   872  				log.Info(fmt.Sprintf("Ignoring Deletion of Orderer node %d (%s) due to error in getting list of other nodes: %s", *oldOrderer.Spec.NodeNumber, oldOrderer.GetName(), err.Error()))
   873  				return false
   874  			}
   875  
   876  			log.Info(fmt.Sprintf("There are %d child nodes for the orderer parent %s.", len(ordererList.Items), parentName))
   877  
   878  			if len(ordererList.Items) == 0 {
   879  				log.Info(fmt.Sprintf("Deleting Parent (%s) of Orderer node %d (%s) as all nodes are deleted.", parentName, *oldOrderer.Spec.NodeNumber, oldOrderer.GetName()))
   880  				parent := &current.IBPOrderer{}
   881  				parent.SetName(parentName)
   882  				parent.SetNamespace(oldOrderer.GetNamespace())
   883  
   884  				err := r.client.Delete(context.TODO(), parent)
   885  				if err != nil {
   886  					log.Error(err, fmt.Sprintf("Error deleting parent (%s) of Orderer node %d (%s).", parentName, *oldOrderer.Spec.NodeNumber, oldOrderer.GetName()))
   887  				}
   888  				return false
   889  			}
   890  
   891  			log.Info(fmt.Sprintf("Ignoring Deletion of Orderer node %d (%s) as there are %d nodes of parent still around", *oldOrderer.Spec.NodeNumber, oldOrderer.GetName(), len(ordererList.Items)))
   892  			return false
   893  		}
   894  
   895  		log.Info(fmt.Sprintf("Orderer parent %s deleted", oldOrderer.GetName()))
   896  		parentName := oldOrderer.GetName()
   897  		labelSelector, err := labels.Parse(fmt.Sprintf("parent=%s", parentName))
   898  		if err != nil {
   899  			log.Info(fmt.Sprintf("failed to parse selector for parent name: %s", err.Error()))
   900  		}
   901  
   902  		listOptions := &client.ListOptions{
   903  			LabelSelector: labelSelector,
   904  			Namespace:     oldOrderer.GetNamespace(),
   905  		}
   906  
   907  		ordererList := &current.IBPOrdererList{}
   908  		err = r.client.List(context.TODO(), ordererList, listOptions)
   909  		if err != nil {
   910  			log.Info(fmt.Sprintf("Ignoring Deletion of Orderer parent %s due to error in getting list of child nodes: %s", oldOrderer.GetName(), err.Error()))
   911  			return false
   912  		}
   913  
   914  		log.Info(fmt.Sprintf("There are %d child nodes for the orderer parent %s.", len(ordererList.Items), parentName))
   915  
   916  		for _, item := range ordererList.Items {
   917  			log.Info(fmt.Sprintf("Deleting child node %s", item.GetName()))
   918  
   919  			child := &current.IBPOrderer{}
   920  			child.SetName(item.GetName())
   921  			child.SetNamespace(item.GetNamespace())
   922  
   923  			err := r.client.Delete(context.TODO(), child)
   924  			if err != nil {
   925  				log.Error(err, fmt.Sprintf("Error child node (%s) of Orderer (%s).", child.GetName(), parentName))
   926  			}
   927  		}
   928  
   929  		return false
   930  
   931  	case *appsv1.Deployment:
   932  		dep := e.Object.(*appsv1.Deployment)
   933  		log.Info(fmt.Sprintf("Delete detected by IBPOrderer controller on deployment '%s'", dep.GetName()))
   934  	case *corev1.Secret:
   935  		secret := e.Object.(*corev1.Secret)
   936  		log.Info(fmt.Sprintf("Delete detected by IBPOrderer controller on secret '%s'", secret.GetName()))
   937  	case *corev1.ConfigMap:
   938  		cm := e.Object.(*corev1.ConfigMap)
   939  		log.Info(fmt.Sprintf("Delete detected by IBPOrderer controller on configmap '%s'", cm.GetName()))
   940  	}
   941  
   942  	return true
   943  }
   944  
   945  func (r *ReconcileIBPOrderer) GetUpdateStatusAtElement(instance *current.IBPOrderer, index int) *Update {
   946  	r.mutex.Lock()
   947  	defer r.mutex.Unlock()
   948  
   949  	update := Update{}
   950  	_, ok := r.update[instance.GetName()]
   951  	if !ok {
   952  		return &update
   953  	}
   954  
   955  	if len(r.update[instance.GetName()]) >= 1 {
   956  		update = r.update[instance.GetName()][index]
   957  	}
   958  
   959  	return &update
   960  }
   961  
   962  func (r *ReconcileIBPOrderer) GetUpdateStatus(instance *current.IBPOrderer) *Update {
   963  	return r.GetUpdateStatusAtElement(instance, 0)
   964  }
   965  
   966  func (r *ReconcileIBPOrderer) PushUpdate(instanceName string, update Update) {
   967  	r.mutex.Lock()
   968  	defer r.mutex.Unlock()
   969  
   970  	r.update[instanceName] = r.AppendUpdateIfMissing(r.update[instanceName], update)
   971  }
   972  
   973  func (r *ReconcileIBPOrderer) PopUpdate(instanceName string) *Update {
   974  	r.mutex.Lock()
   975  	defer r.mutex.Unlock()
   976  
   977  	update := Update{}
   978  	if len(r.update[instanceName]) >= 1 {
   979  		update = r.update[instanceName][0]
   980  		if len(r.update[instanceName]) == 1 {
   981  			r.update[instanceName] = []Update{}
   982  		} else {
   983  			r.update[instanceName] = r.update[instanceName][1:]
   984  		}
   985  	}
   986  
   987  	return &update
   988  }
   989  
   990  func (r *ReconcileIBPOrderer) AppendUpdateIfMissing(updates []Update, update Update) []Update {
   991  	for _, u := range updates {
   992  		if u == update {
   993  			return updates
   994  		}
   995  	}
   996  	return append(updates, update)
   997  }
   998  
   999  func deploymentUpdated(oldOrderer, newOrderer *current.IBPOrderer) bool {
  1000  	if !reflect.DeepEqual(oldOrderer.Spec.Images, newOrderer.Spec.Images) {
  1001  		log.Info(fmt.Sprintf("Images updated for '%s', deployment will be updated", newOrderer.Name))
  1002  		return true
  1003  	}
  1004  
  1005  	if !reflect.DeepEqual(oldOrderer.Spec.Replicas, newOrderer.Spec.Replicas) {
  1006  		log.Info(fmt.Sprintf("Replica size updated for '%s', deployment will be updated", newOrderer.Name))
  1007  		return true
  1008  	}
  1009  
  1010  	if !reflect.DeepEqual(oldOrderer.Spec.Resources, newOrderer.Spec.Resources) {
  1011  		log.Info(fmt.Sprintf("Resources updated for '%s', deployment will be updated", newOrderer.Name))
  1012  		return true
  1013  	}
  1014  
  1015  	if !reflect.DeepEqual(oldOrderer.Spec.Storage, newOrderer.Spec.Storage) {
  1016  		log.Info(fmt.Sprintf("Storage updated for '%s', deployment will be updated", newOrderer.Name))
  1017  		return true
  1018  	}
  1019  
  1020  	if len(oldOrderer.Spec.ImagePullSecrets) != len(newOrderer.Spec.ImagePullSecrets) {
  1021  		log.Info(fmt.Sprintf("ImagePullSecret updated for '%s', deployment will be updated", newOrderer.Name))
  1022  		return true
  1023  	}
  1024  	for i, v := range newOrderer.Spec.ImagePullSecrets {
  1025  		if v != oldOrderer.Spec.ImagePullSecrets[i] {
  1026  			log.Info(fmt.Sprintf("ImagePullSecret updated for '%s', deployment will be updated", newOrderer.Name))
  1027  			return true
  1028  		}
  1029  	}
  1030  
  1031  	return false
  1032  }
  1033  
  1034  func (r *ReconcileIBPOrderer) AddOwnerReferenceToSecret(secret *corev1.Secret) (bool, error) {
  1035  	// Orderer secrets we are looking to add owner references to are named:
  1036  	// <prefix>-<instance name>-<type>
  1037  	// <instance name>-init-rootcert
  1038  
  1039  	// The following secrets are created by operator, and will have owner references:
  1040  	// <instance name>-genesis
  1041  	// <instance name>-crypto-backup
  1042  	// <instance name>-secret
  1043  
  1044  	items := strings.Split(secret.Name, "-")
  1045  	if len(items) < 3 {
  1046  		// Secret names we are looking for will be split into at least 3 strings:
  1047  		// [prefix, instance name, type] OR [instance name, "init", "rootcert"]
  1048  		return false, nil
  1049  	}
  1050  
  1051  	// Account for the case where the instance's name is hyphenated
  1052  	var instanceName string
  1053  	if strings.Contains(secret.Name, "-init-rootcert") {
  1054  		instanceName = strings.Join(items[:len(items)-2], "-") // instance name contains all but last 2 items
  1055  	} else {
  1056  		instanceName = strings.Join(items[1:len(items)-1], "-") // instance name contains all but first and last item
  1057  	}
  1058  
  1059  	listOptions := &client.ListOptions{
  1060  		Namespace: secret.Namespace,
  1061  	}
  1062  
  1063  	ordererList := &current.IBPOrdererList{}
  1064  	err := r.client.List(context.TODO(), ordererList, listOptions)
  1065  	if err != nil {
  1066  		return false, errors.Wrap(err, "failed to get list of orderers")
  1067  	}
  1068  
  1069  	for _, o := range ordererList.Items {
  1070  		orderer := o
  1071  		if orderer.Name == instanceName {
  1072  			// Instance 'i' found in list of orderers
  1073  			err := r.client.Update(context.TODO(), secret, k8sclient.UpdateOption{
  1074  				Owner:  &orderer,
  1075  				Scheme: r.scheme,
  1076  			})
  1077  			if err != nil {
  1078  				return false, err
  1079  			}
  1080  			return true, nil
  1081  		}
  1082  	}
  1083  
  1084  	return false, nil
  1085  }
  1086  
  1087  func (r *ReconcileIBPOrderer) SetupWithManager(mgr ctrl.Manager) error {
  1088  	return ctrl.NewControllerManagedBy(mgr).
  1089  		For(&current.IBPOrderer{}).
  1090  		Complete(r)
  1091  }
  1092  
  1093  func GetUpdateStack(allUpdates map[string][]Update) string {
  1094  	stack := ""
  1095  
  1096  	for orderer, updates := range allUpdates {
  1097  		currentStack := ""
  1098  		for index, update := range updates {
  1099  			currentStack += fmt.Sprintf("{ %s}", update.GetUpdateStackWithTrues())
  1100  			if index != len(updates)-1 {
  1101  				currentStack += " , "
  1102  			}
  1103  		}
  1104  		stack += fmt.Sprintf("%s: [ %s ] ", orderer, currentStack)
  1105  	}
  1106  
  1107  	return stack
  1108  }
  1109  
  1110  func (r *ReconcileIBPOrderer) ReconcileRestart(namespace string) (bool, error) {
  1111  	requeue, err := r.RestartService.Reconcile("orderer", namespace)
  1112  	if err != nil {
  1113  		log.Error(err, "failed to reconcile restart queues in orderer-restart-config")
  1114  		return false, err
  1115  	}
  1116  
  1117  	return requeue, nil
  1118  }