github.com/IBM-Blockchain/fabric-operator@v1.0.4/pkg/offering/base/peer/peer.go (about)

     1  /*
     2   * Copyright contributors to the Hyperledger Fabric Operator project
     3   *
     4   * SPDX-License-Identifier: Apache-2.0
     5   *
     6   * Licensed under the Apache License, Version 2.0 (the "License");
     7   * you may not use this file except in compliance with the License.
     8   * You may obtain a copy of the License at:
     9   *
    10   * 	  http://www.apache.org/licenses/LICENSE-2.0
    11   *
    12   * Unless required by applicable law or agreed to in writing, software
    13   * distributed under the License is distributed on an "AS IS" BASIS,
    14   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    15   * See the License for the specific language governing permissions and
    16   * limitations under the License.
    17   */
    18  
    19  package basepeer
    20  
    21  import (
    22  	"bytes"
    23  	"context"
    24  	"encoding/json"
    25  	"fmt"
    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  	"github.com/IBM-Blockchain/fabric-operator/pkg/action"
    34  	commonapi "github.com/IBM-Blockchain/fabric-operator/pkg/apis/common"
    35  	"github.com/IBM-Blockchain/fabric-operator/pkg/certificate"
    36  	commoninit "github.com/IBM-Blockchain/fabric-operator/pkg/initializer/common"
    37  	commonconfig "github.com/IBM-Blockchain/fabric-operator/pkg/initializer/common/config"
    38  	initializer "github.com/IBM-Blockchain/fabric-operator/pkg/initializer/peer"
    39  	peerconfig "github.com/IBM-Blockchain/fabric-operator/pkg/initializer/peer/config/v1"
    40  	"github.com/IBM-Blockchain/fabric-operator/pkg/initializer/validator"
    41  	controllerclient "github.com/IBM-Blockchain/fabric-operator/pkg/k8s/controllerclient"
    42  	"github.com/IBM-Blockchain/fabric-operator/pkg/manager/resources"
    43  	jobv1 "github.com/IBM-Blockchain/fabric-operator/pkg/manager/resources/job"
    44  	resourcemanager "github.com/IBM-Blockchain/fabric-operator/pkg/manager/resources/manager"
    45  	"github.com/IBM-Blockchain/fabric-operator/pkg/migrator/peer/fabric"
    46  	v2 "github.com/IBM-Blockchain/fabric-operator/pkg/migrator/peer/fabric/v2"
    47  	"github.com/IBM-Blockchain/fabric-operator/pkg/offering/common"
    48  	"github.com/IBM-Blockchain/fabric-operator/pkg/offering/common/reconcilechecks"
    49  	"github.com/IBM-Blockchain/fabric-operator/pkg/operatorerrors"
    50  	"github.com/IBM-Blockchain/fabric-operator/pkg/restart"
    51  	"github.com/IBM-Blockchain/fabric-operator/pkg/util"
    52  	"github.com/IBM-Blockchain/fabric-operator/version"
    53  	"github.com/pkg/errors"
    54  	appsv1 "k8s.io/api/apps/v1"
    55  	batchv1 "k8s.io/api/batch/v1"
    56  	corev1 "k8s.io/api/core/v1"
    57  	k8serrors "k8s.io/apimachinery/pkg/api/errors"
    58  	v1 "k8s.io/apimachinery/pkg/apis/meta/v1"
    59  	"k8s.io/apimachinery/pkg/runtime"
    60  	"k8s.io/apimachinery/pkg/types"
    61  	k8sclient "sigs.k8s.io/controller-runtime/pkg/client"
    62  	logf "sigs.k8s.io/controller-runtime/pkg/log"
    63  	"sigs.k8s.io/controller-runtime/pkg/reconcile"
    64  	"sigs.k8s.io/yaml"
    65  )
    66  
    67  var log = logf.Log.WithName("base_peer")
    68  
    69  const (
    70  	DefaultCouchContainer     = "./definitions/peer/couchdb.yaml"
    71  	DefaultCouchInitContainer = "./definitions/peer/couchdb-init.yaml"
    72  
    73  	defaultDeployment       = "./definitions/peer/deployment.yaml"
    74  	defaultPVC              = "./definitions/peer/pvc.yaml"
    75  	defaultCouchDBPVC       = "./definitions/peer/couchdb-pvc.yaml"
    76  	defaultService          = "./definitions/peer/service.yaml"
    77  	defaultRole             = "./definitions/peer/role.yaml"
    78  	defaultServiceAccount   = "./definitions/peer/serviceaccount.yaml"
    79  	defaultRoleBinding      = "./definitions/peer/rolebinding.yaml"
    80  	defaultFluentdConfigMap = "./definitions/peer/fluentd-configmap.yaml"
    81  
    82  	DaysToSecondsConversion = int64(24 * 60 * 60)
    83  )
    84  
    85  type Override interface {
    86  	Deployment(v1.Object, *appsv1.Deployment, resources.Action) error
    87  	Service(v1.Object, *corev1.Service, resources.Action) error
    88  	PVC(v1.Object, *corev1.PersistentVolumeClaim, resources.Action) error
    89  	StateDBPVC(v1.Object, *corev1.PersistentVolumeClaim, resources.Action) error
    90  }
    91  
    92  //go:generate counterfeiter -o mocks/deployment_manager.go -fake-name DeploymentManager . DeploymentManager
    93  
    94  type DeploymentManager interface {
    95  	resources.Manager
    96  	CheckForSecretChange(v1.Object, string, func(string, *appsv1.Deployment) bool) error
    97  	DeploymentStatus(v1.Object) (appsv1.DeploymentStatus, error)
    98  	GetScheme() *runtime.Scheme
    99  }
   100  
   101  //go:generate counterfeiter -o mocks/initializer.go -fake-name InitializeIBPPeer . InitializeIBPPeer
   102  
   103  type InitializeIBPPeer interface {
   104  	GenerateOrdererCACertsSecret(instance *current.IBPPeer, certs map[string][]byte) error
   105  	GenerateSecrets(prefix commoninit.SecretType, instance v1.Object, crypto *commonconfig.Response) error
   106  	Create(initializer.CoreConfig, initializer.IBPPeer, string) (*initializer.Response, error)
   107  	Update(initializer.CoreConfig, initializer.IBPPeer) (*initializer.Response, error)
   108  	CheckIfAdminCertsUpdated(*current.IBPPeer) (bool, error)
   109  	UpdateAdminSecret(*current.IBPPeer) error
   110  	MissingCrypto(*current.IBPPeer) bool
   111  	GetInitPeer(instance *current.IBPPeer, storagePath string) (*initializer.Peer, error)
   112  	GetUpdatedPeer(instance *current.IBPPeer) (*initializer.Peer, error)
   113  	GenerateSecretsFromResponse(instance *current.IBPPeer, cryptoResponse *commonconfig.CryptoResponse) error
   114  	UpdateSecretsFromResponse(instance *current.IBPPeer, cryptoResponse *commonconfig.CryptoResponse) error
   115  	GetCrypto(instance *current.IBPPeer) (*commonconfig.CryptoResponse, error)
   116  	CoreConfigMap() *initializer.CoreConfigMap
   117  }
   118  
   119  //go:generate counterfeiter -o mocks/certificate_manager.go -fake-name CertificateManager . CertificateManager
   120  
   121  type CertificateManager interface {
   122  	CheckCertificatesForExpire(instance v1.Object, numSecondsBeforeExpire int64) (current.IBPCRStatusType, string, error)
   123  	GetSignCert(string, string) ([]byte, error)
   124  	GetDurationToNextRenewal(commoninit.SecretType, v1.Object, int64) (time.Duration, error)
   125  	RenewCert(commoninit.SecretType, certificate.Instance, *current.EnrollmentSpec, *commonapi.BCCSP, string, bool, bool) error
   126  }
   127  
   128  //go:generate counterfeiter -o mocks/restart_manager.go -fake-name RestartManager . RestartManager
   129  
   130  type RestartManager interface {
   131  	ForAdminCertUpdate(instance v1.Object) error
   132  	ForCertUpdate(certType commoninit.SecretType, instance v1.Object) error
   133  	ForConfigOverride(instance v1.Object) error
   134  	ForNodeOU(instance v1.Object) error
   135  	ForRestartAction(instance v1.Object) error
   136  	TriggerIfNeeded(instance restart.Instance) error
   137  }
   138  
   139  //go:generate counterfeiter -o mocks/update.go -fake-name Update . Update
   140  type Update interface {
   141  	SpecUpdated() bool
   142  	ConfigOverridesUpdated() bool
   143  	DindArgsUpdated() bool
   144  	TLSCertUpdated() bool
   145  	EcertUpdated() bool
   146  	PeerTagUpdated() bool
   147  	CertificateUpdated() bool
   148  	SetDindArgsUpdated(updated bool)
   149  	RestartNeeded() bool
   150  	EcertReenrollNeeded() bool
   151  	TLSReenrollNeeded() bool
   152  	EcertNewKeyReenroll() bool
   153  	TLScertNewKeyReenroll() bool
   154  	MigrateToV2() bool
   155  	MigrateToV24() bool
   156  	UpgradeDBs() bool
   157  	MSPUpdated() bool
   158  	EcertEnroll() bool
   159  	TLSCertEnroll() bool
   160  	CertificateCreated() bool
   161  	GetCreatedCertType() commoninit.SecretType
   162  	CryptoBackupNeeded() bool
   163  	NodeOUUpdated() bool
   164  	FabricVersionUpdated() bool
   165  	ImagesUpdated() bool
   166  }
   167  
   168  type IBPPeer interface {
   169  	Initialize(instance *current.IBPPeer, update Update) error
   170  	CheckStates(instance *current.IBPPeer) error
   171  	PreReconcileChecks(instance *current.IBPPeer, update Update) (bool, error)
   172  	ReconcileManagers(instance *current.IBPPeer, update Update) error
   173  	Reconcile(instance *current.IBPPeer, update Update) (common.Result, error)
   174  }
   175  
   176  type CoreConfig interface {
   177  	GetMaxNameLength() *int
   178  	GetAddressOverrides() []peerconfig.AddressOverride
   179  	GetBCCSPSection() *commonapi.BCCSP
   180  	MergeWith(interface{}, bool) error
   181  	SetPKCS11Defaults(bool)
   182  	ToBytes() ([]byte, error)
   183  	UsingPKCS11() bool
   184  	SetBCCSPLibrary(string)
   185  }
   186  
   187  var _ IBPPeer = &Peer{}
   188  
   189  type Peer struct {
   190  	Client controllerclient.Client
   191  	Scheme *runtime.Scheme
   192  	Config *config.Config
   193  
   194  	DeploymentManager       DeploymentManager
   195  	ServiceManager          resources.Manager
   196  	PVCManager              resources.Manager
   197  	StateDBPVCManager       resources.Manager
   198  	FluentDConfigMapManager resources.Manager
   199  	RoleManager             resources.Manager
   200  	RoleBindingManager      resources.Manager
   201  	ServiceAccountManager   resources.Manager
   202  
   203  	Override    Override
   204  	Initializer InitializeIBPPeer
   205  
   206  	CertificateManager CertificateManager
   207  	RenewCertTimers    map[string]*time.Timer
   208  
   209  	Restart RestartManager
   210  }
   211  
   212  func New(client controllerclient.Client, scheme *runtime.Scheme, config *config.Config, o Override) *Peer {
   213  	p := &Peer{
   214  		Client:   client,
   215  		Scheme:   scheme,
   216  		Config:   config,
   217  		Override: o,
   218  	}
   219  
   220  	p.CreateManagers()
   221  
   222  	validator := &validator.Validator{
   223  		Client: client,
   224  	}
   225  
   226  	init := initializer.New(config.PeerInitConfig, scheme, client, p.GetLabels, validator, config.Operator.Peer.Timeouts.EnrollJob)
   227  	p.Initializer = init
   228  
   229  	p.CertificateManager = certificate.New(client, scheme)
   230  	p.RenewCertTimers = make(map[string]*time.Timer)
   231  
   232  	p.Restart = restart.New(client, config.Operator.Restart.WaitTime.Get(), config.Operator.Restart.Timeout.Get())
   233  
   234  	return p
   235  }
   236  
   237  func (p *Peer) CreateManagers() {
   238  	override := p.Override
   239  	resourceManager := resourcemanager.New(p.Client, p.Scheme)
   240  	peerConfig := p.Config.PeerInitConfig
   241  
   242  	p.DeploymentManager = resourceManager.CreateDeploymentManager("", override.Deployment, p.GetLabels, peerConfig.DeploymentFile)
   243  	p.PVCManager = resourceManager.CreatePVCManager("", override.PVC, p.GetLabels, peerConfig.PVCFile)
   244  	p.StateDBPVCManager = resourceManager.CreatePVCManager("statedb", override.StateDBPVC, p.GetLabels, peerConfig.CouchDBPVCFile)
   245  	p.FluentDConfigMapManager = resourceManager.CreateConfigMapManager("fluentd", nil, p.GetLabels, peerConfig.FluentdConfigMapFile, nil)
   246  	p.RoleManager = resourceManager.CreateRoleManager("", nil, p.GetLabels, peerConfig.RoleFile)
   247  	p.RoleBindingManager = resourceManager.CreateRoleBindingManager("", nil, p.GetLabels, peerConfig.RoleBindingFile)
   248  	p.ServiceAccountManager = resourceManager.CreateServiceAccountManager("", nil, p.GetLabels, peerConfig.ServiceAccountFile)
   249  	p.ServiceManager = resourceManager.CreateServiceManager("", override.Service, p.GetLabels, peerConfig.ServiceFile)
   250  }
   251  
   252  func (p *Peer) PreReconcileChecks(instance *current.IBPPeer, update Update) (bool, error) {
   253  	var maxNameLength *int
   254  
   255  	imagesUpdated, err := reconcilechecks.FabricVersionHelper(instance, p.Config.Operator.Versions, update)
   256  	if err != nil {
   257  		return false, errors.Wrap(err, "failed to during version and image checks")
   258  	}
   259  
   260  	co, err := instance.GetConfigOverride()
   261  	if err != nil {
   262  		return false, err
   263  	}
   264  
   265  	configOverride := co.(CoreConfig)
   266  	maxNameLength = configOverride.GetMaxNameLength()
   267  
   268  	err = util.ValidationChecks(instance.TypeMeta, instance.ObjectMeta, "IBPPeer", maxNameLength)
   269  	if err != nil {
   270  		return false, err
   271  	}
   272  
   273  	if instance.Spec.Action.Enroll.Ecert && instance.Spec.Action.Reenroll.Ecert {
   274  		return false, errors.New("both enroll and renenroll action requested for ecert, must only select one")
   275  	}
   276  
   277  	if instance.Spec.Action.Enroll.TLSCert && instance.Spec.Action.Reenroll.TLSCert {
   278  		return false, errors.New("both enroll and renenroll action requested for TLS cert, must only select one")
   279  	}
   280  
   281  	if instance.Spec.Action.Reenroll.Ecert && instance.Spec.Action.Reenroll.EcertNewKey {
   282  		return false, errors.New("both reenroll and renenroll with new action requested for ecert, must only select one")
   283  	}
   284  
   285  	if instance.Spec.Action.Reenroll.TLSCert && instance.Spec.Action.Reenroll.TLSCertNewKey {
   286  		return false, errors.New("both reenroll and renenroll with new action requested for TLS cert, must only select one")
   287  	}
   288  
   289  	if instance.Spec.HSMSet() {
   290  		err = util.ValidateHSMProxyURL(instance.Spec.HSM.PKCS11Endpoint)
   291  		if err != nil {
   292  			return false, errors.Wrapf(err, "invalid HSM endpoint for peer instance '%s'", instance.GetName())
   293  		}
   294  	}
   295  
   296  	hsmImageUpdated := p.ReconcileHSMImages(instance)
   297  
   298  	if !instance.Spec.DomainSet() {
   299  		return false, fmt.Errorf("domain not set for peer instance '%s'", instance.GetName())
   300  	}
   301  
   302  	zoneUpdated, err := p.SelectZone(instance)
   303  	if err != nil {
   304  		return false, err
   305  	}
   306  
   307  	regionUpdated, err := p.SelectRegion(instance)
   308  	if err != nil {
   309  		return false, err
   310  	}
   311  
   312  	var replicasUpdated bool
   313  	if instance.Spec.Replicas == nil {
   314  		replicas := int32(1)
   315  		instance.Spec.Replicas = &replicas
   316  		replicasUpdated = true
   317  	}
   318  
   319  	dbTypeUpdated := p.CheckDBType(instance)
   320  	updated := dbTypeUpdated || zoneUpdated || regionUpdated || update.DindArgsUpdated() || hsmImageUpdated || replicasUpdated || imagesUpdated
   321  
   322  	if updated {
   323  		log.Info(fmt.Sprintf(
   324  			"dbTypeUpdate %t, zoneUpdated %t, regionUpdated %t, dindArgsUpdated %t, hsmImageUpdated %t, replicasUpdated %t, imagesUpdated %t",
   325  			dbTypeUpdated,
   326  			zoneUpdated,
   327  			regionUpdated,
   328  			update.DindArgsUpdated(),
   329  			hsmImageUpdated,
   330  			replicasUpdated,
   331  			imagesUpdated))
   332  	}
   333  
   334  	return updated, nil
   335  }
   336  
   337  func (p *Peer) SetVersion(instance *current.IBPPeer) (bool, error) {
   338  	if instance.Status.Version == "" || !version.String(instance.Status.Version).Equal(version.Operator) {
   339  		log.Info("Version of Operator: ", "version", version.Operator)
   340  		log.Info("Version of CR: ", "version", instance.Status.Version)
   341  		log.Info(fmt.Sprintf("Updating CR '%s' to version '%s'", instance.Name, version.Operator))
   342  
   343  		instance.Status.Version = version.Operator
   344  		err := p.Client.PatchStatus(context.TODO(), instance, nil, controllerclient.PatchOption{
   345  			Resilient: &controllerclient.ResilientPatch{
   346  				Retry:    3,
   347  				Into:     &current.IBPPeer{},
   348  				Strategy: k8sclient.MergeFrom,
   349  			},
   350  		})
   351  		if err != nil {
   352  			return false, err
   353  		}
   354  		return true, nil
   355  	}
   356  	return false, nil
   357  }
   358  
   359  func (p *Peer) Initialize(instance *current.IBPPeer, update Update) error {
   360  	var err error
   361  
   362  	log.Info(fmt.Sprintf("Checking if peer '%s' needs initialization", instance.GetName()))
   363  
   364  	// TODO: Add checks to determine if initialization is neeeded. Split this method into
   365  	// two, one should handle initialization during the create event of a CR and the other
   366  	// should update events
   367  
   368  	// Service account is required by HSM init job
   369  	if err := p.ReconcilePeerRBAC(instance); err != nil {
   370  		return err
   371  	}
   372  
   373  	if instance.IsHSMEnabled() {
   374  		// If HSM config not found, HSM proxy is being used
   375  		if instance.UsingHSMProxy() {
   376  			err = os.Setenv("PKCS11_PROXY_SOCKET", instance.Spec.HSM.PKCS11Endpoint)
   377  			if err != nil {
   378  				return err
   379  			}
   380  		} else {
   381  			hsmConfig, err := commonconfig.ReadHSMConfig(p.Client, instance)
   382  			if err != nil {
   383  				return errors.New("using non-proxy HSM, but no HSM config defined as config map 'ibp-hsm-config'")
   384  			}
   385  
   386  			if hsmConfig.Daemon != nil {
   387  				log.Info("Using daemon based HSM, creating pvc...")
   388  				p.PVCManager.SetCustomName(instance.Spec.CustomNames.PVC.Peer)
   389  				err = p.PVCManager.Reconcile(instance, update.SpecUpdated())
   390  				if err != nil {
   391  					return errors.Wrap(err, "failed PVC reconciliation")
   392  				}
   393  			}
   394  		}
   395  	}
   396  
   397  	peerConfig := p.Config.PeerInitConfig.CorePeerFile
   398  	if version.GetMajorReleaseVersion(instance.Spec.FabricVersion) == version.V2 {
   399  		peerConfig = p.Config.PeerInitConfig.CorePeerV2File
   400  	}
   401  
   402  	if instance.UsingHSMProxy() {
   403  		err = os.Setenv("PKCS11_PROXY_SOCKET", instance.Spec.HSM.PKCS11Endpoint)
   404  		if err != nil {
   405  			return err
   406  		}
   407  	}
   408  
   409  	storagePath := p.GetInitStoragePath(instance)
   410  	initPeer, err := p.Initializer.GetInitPeer(instance, storagePath)
   411  	if err != nil {
   412  		return err
   413  	}
   414  	initPeer.UsingHSMProxy = instance.UsingHSMProxy()
   415  	initPeer.Config, err = initializer.GetCoreConfigFromFile(instance, peerConfig)
   416  	if err != nil {
   417  		return err
   418  	}
   419  
   420  	updated := update.ConfigOverridesUpdated() || update.NodeOUUpdated()
   421  	if update.ConfigOverridesUpdated() {
   422  		err = p.InitializeUpdateConfigOverride(instance, initPeer)
   423  		if err != nil {
   424  			return err
   425  		}
   426  		// Request deployment restart for config override update
   427  		if err = p.Restart.ForConfigOverride(instance); err != nil {
   428  			return err
   429  		}
   430  	}
   431  	if update.NodeOUUpdated() {
   432  		err = p.InitializeUpdateNodeOU(instance)
   433  		if err != nil {
   434  			return err
   435  		}
   436  		// Request deloyment restart for node OU update
   437  		if err = p.Restart.ForNodeOU(instance); err != nil {
   438  			return err
   439  		}
   440  	}
   441  	if !updated {
   442  		err = p.InitializeCreate(instance, initPeer)
   443  		if err != nil {
   444  			return err
   445  		}
   446  	}
   447  
   448  	updateNeeded, err := p.Initializer.CheckIfAdminCertsUpdated(instance)
   449  	if err != nil {
   450  		return err
   451  	}
   452  	if updateNeeded {
   453  		err = p.Initializer.UpdateAdminSecret(instance)
   454  		if err != nil {
   455  			return err
   456  		}
   457  		// Request deployment restart for admin cert updates
   458  		if err = p.Restart.ForAdminCertUpdate(instance); err != nil {
   459  			return err
   460  		}
   461  	}
   462  
   463  	return nil
   464  }
   465  
   466  func (p *Peer) InitializeUpdateConfigOverride(instance *current.IBPPeer, initPeer *initializer.Peer) error {
   467  	var err error
   468  
   469  	if p.Initializer.MissingCrypto(instance) {
   470  		// If crypto is missing, we should run the create logic
   471  		err := p.InitializeCreate(instance, initPeer)
   472  		if err != nil {
   473  			return err
   474  		}
   475  
   476  		return nil
   477  	}
   478  
   479  	log.Info(fmt.Sprintf("Initialize peer '%s' during update config override", instance.GetName()))
   480  
   481  	cm, err := initializer.GetCoreFromConfigMap(p.Client, instance)
   482  	if err != nil {
   483  		return err
   484  	}
   485  
   486  	initPeer.Config, err = initializer.GetCoreConfigFromBytes(instance, cm.BinaryData["core.yaml"])
   487  	if err != nil {
   488  		return err
   489  	}
   490  
   491  	co, err := instance.GetConfigOverride()
   492  	if err != nil {
   493  		return err
   494  	}
   495  	configOverrides := co.(CoreConfig)
   496  
   497  	resp, err := p.Initializer.Update(configOverrides, initPeer)
   498  	if err != nil {
   499  		return err
   500  	}
   501  
   502  	if resp != nil {
   503  		if resp.Config != nil {
   504  			// Update core.yaml in config map
   505  			err = p.Initializer.CoreConfigMap().CreateOrUpdate(instance, resp.Config)
   506  			if err != nil {
   507  				return err
   508  			}
   509  		}
   510  
   511  		if len(resp.DeliveryClientCerts) > 0 {
   512  			log.Info(fmt.Sprintf("Orderer CA Certs detected in DeliveryClient config, creating secret '%s-orderercacerts' with certs", instance.Name))
   513  			err = p.Initializer.GenerateOrdererCACertsSecret(instance, resp.DeliveryClientCerts)
   514  			if err != nil {
   515  				return err
   516  			}
   517  		}
   518  	}
   519  
   520  	return nil
   521  }
   522  
   523  func (p *Peer) InitializeUpdateNodeOU(instance *current.IBPPeer) error {
   524  	log.Info(fmt.Sprintf("Node OU updated with enabled: %t for peer '%s", !instance.Spec.NodeOUDisabled(), instance.GetName()))
   525  
   526  	crypto, err := p.Initializer.GetCrypto(instance)
   527  	if err != nil {
   528  		return err
   529  	}
   530  	if !instance.Spec.NodeOUDisabled() {
   531  		if err := crypto.VerifyCertOU("peer"); err != nil {
   532  			return err
   533  		}
   534  	} else {
   535  		// If nodeOUDisabled, admin certs are required
   536  		if crypto.Enrollment.AdminCerts == nil {
   537  			return errors.New("node OU disabled, admin certs are required but missing")
   538  		}
   539  	}
   540  
   541  	// Update config.yaml in config map
   542  	err = p.Initializer.CoreConfigMap().AddNodeOU(instance)
   543  	if err != nil {
   544  		return err
   545  	}
   546  
   547  	return nil
   548  }
   549  
   550  func (p *Peer) InitializeCreate(instance *current.IBPPeer, initPeer *initializer.Peer) error {
   551  	var err error
   552  
   553  	if p.ConfigExists(instance) {
   554  		log.Info(fmt.Sprintf("Config '%s-config' exists, not reinitializing peer", instance.GetName()))
   555  		return nil
   556  	}
   557  
   558  	log.Info(fmt.Sprintf("Initialize peer '%s' during create", instance.GetName()))
   559  
   560  	storagePath := p.GetInitStoragePath(instance)
   561  
   562  	co, err := instance.GetConfigOverride()
   563  	if err != nil {
   564  		return err
   565  	}
   566  	configOverrides := co.(CoreConfig)
   567  
   568  	resp, err := p.Initializer.Create(configOverrides, initPeer, storagePath)
   569  	if err != nil {
   570  		return err
   571  	}
   572  
   573  	if resp != nil {
   574  		if resp.Crypto != nil {
   575  			if !instance.Spec.NodeOUDisabled() {
   576  				if err := resp.Crypto.VerifyCertOU("peer"); err != nil {
   577  					return err
   578  				}
   579  			}
   580  
   581  			err = p.Initializer.GenerateSecretsFromResponse(instance, resp.Crypto)
   582  			if err != nil {
   583  				return err
   584  			}
   585  		}
   586  
   587  		if len(resp.DeliveryClientCerts) > 0 {
   588  			log.Info(fmt.Sprintf("Orderer CA Certs detected in DeliverClient config, creating secret '%s-orderercacerts' with certs", instance.Name))
   589  			err = p.Initializer.GenerateOrdererCACertsSecret(instance, resp.DeliveryClientCerts)
   590  			if err != nil {
   591  				return err
   592  			}
   593  		}
   594  
   595  		if resp.Config != nil {
   596  			if instance.IsHSMEnabled() && !instance.UsingHSMProxy() {
   597  				hsmConfig, err := commonconfig.ReadHSMConfig(p.Client, instance)
   598  				if err != nil {
   599  					return err
   600  				}
   601  				resp.Config.SetBCCSPLibrary(filepath.Join("/hsm/lib", filepath.Base(hsmConfig.Library.FilePath)))
   602  			}
   603  
   604  			err = p.Initializer.CoreConfigMap().CreateOrUpdate(instance, resp.Config)
   605  			if err != nil {
   606  				return err
   607  			}
   608  		}
   609  	}
   610  
   611  	return nil
   612  }
   613  
   614  func (p *Peer) Reconcile(instance *current.IBPPeer, update Update) (common.Result, error) {
   615  	var err error
   616  	var status *current.CRStatus
   617  
   618  	versionSet, err := p.SetVersion(instance)
   619  	if err != nil {
   620  		return common.Result{}, errors.Wrap(err, fmt.Sprintf("failed updating CR '%s' to version '%s'", instance.Name, version.Operator))
   621  	}
   622  	if versionSet {
   623  		log.Info("Instance version updated, requeuing request...")
   624  		return common.Result{
   625  			Result: reconcile.Result{
   626  				Requeue: true,
   627  			},
   628  		}, nil
   629  	}
   630  
   631  	instanceUpdated, err := p.PreReconcileChecks(instance, update)
   632  	if err != nil {
   633  		return common.Result{}, errors.Wrap(err, "failed pre reconcile checks")
   634  	}
   635  
   636  	// We do not have to wait for service to get the external endpoint
   637  	// thus we call UpdateExternalEndpoint in reconcile before reconcile managers
   638  	externalEndpointUpdated := p.UpdateExternalEndpoint(instance)
   639  
   640  	if instanceUpdated || externalEndpointUpdated {
   641  		log.Info(fmt.Sprintf("Updating instance after pre reconcile checks: %t, updating external endpoint: %t", instanceUpdated, externalEndpointUpdated))
   642  		err = p.Client.Patch(context.TODO(), instance, nil, controllerclient.PatchOption{
   643  			Resilient: &controllerclient.ResilientPatch{
   644  				Retry:    3,
   645  				Into:     &current.IBPPeer{},
   646  				Strategy: k8sclient.MergeFrom,
   647  			},
   648  		})
   649  		if err != nil {
   650  			return common.Result{}, errors.Wrap(err, "failed to update instance")
   651  		}
   652  
   653  		log.Info("Instance updated, requeuing request...")
   654  		return common.Result{
   655  			Result: reconcile.Result{
   656  				Requeue: true,
   657  			},
   658  		}, nil
   659  	}
   660  
   661  	err = p.Initialize(instance, update)
   662  	if err != nil {
   663  		return common.Result{}, operatorerrors.Wrap(err, operatorerrors.PeerInitilizationFailed, "failed to initialize peer")
   664  	}
   665  
   666  	err = p.ReconcileManagers(instance, update)
   667  	if err != nil {
   668  		return common.Result{}, errors.Wrap(err, "failed to reconcile managers")
   669  	}
   670  
   671  	err = p.UpdateConnectionProfile(instance)
   672  	if err != nil {
   673  		return common.Result{}, errors.Wrap(err, "failed to create connection profile")
   674  	}
   675  
   676  	err = p.CheckStates(instance)
   677  	if err != nil {
   678  		return common.Result{}, errors.Wrap(err, "failed to check and restore state")
   679  	}
   680  
   681  	// custom product logic can be implemented here
   682  	// No-Op atm
   683  	status, result, err := p.CustomLogic(instance, update)
   684  	if err != nil {
   685  		return common.Result{}, errors.Wrap(err, "failed to run custom offering logic")
   686  	}
   687  	if result != nil {
   688  		log.Info(fmt.Sprintf("Finished reconciling '%s' with Custom Logic result", instance.GetName()))
   689  		return *result, nil
   690  	}
   691  
   692  	if update.MSPUpdated() {
   693  		err = p.UpdateMSPCertificates(instance)
   694  		if err != nil {
   695  			return common.Result{}, errors.Wrap(err, "failed to update certificates passed in MSP spec")
   696  		}
   697  		// A successful update will trigger a tlsCertUpdated or ecertUpdated event, which will handle restarting deployment
   698  	}
   699  
   700  	if update.EcertUpdated() {
   701  		log.Info("Ecert was updated")
   702  		// Request deployment restart for tls cert update
   703  		err = p.Restart.ForCertUpdate(commoninit.ECERT, instance)
   704  		if err != nil {
   705  			return common.Result{}, errors.Wrap(err, "failed to update restart config")
   706  		}
   707  	}
   708  
   709  	if update.TLSCertUpdated() {
   710  		log.Info("TLS cert was updated")
   711  		// Request deployment restart for ecert update
   712  		err = p.Restart.ForCertUpdate(commoninit.TLS, instance)
   713  		if err != nil {
   714  			return common.Result{}, errors.Wrap(err, "failed to update restart config")
   715  		}
   716  	}
   717  
   718  	if err := p.HandleActions(instance, update); err != nil {
   719  		return common.Result{}, err
   720  	}
   721  
   722  	if err := p.HandleRestart(instance, update); err != nil {
   723  		return common.Result{}, err
   724  	}
   725  
   726  	return common.Result{
   727  		Status: status,
   728  	}, nil
   729  }
   730  
   731  func (p *Peer) ReconcileManagers(instance *current.IBPPeer, updated Update) error {
   732  	var err error
   733  
   734  	update := updated.SpecUpdated()
   735  
   736  	p.PVCManager.SetCustomName(instance.Spec.CustomNames.PVC.Peer)
   737  	err = p.PVCManager.Reconcile(instance, update)
   738  	if err != nil {
   739  		return errors.Wrap(err, "failed PVC reconciliation")
   740  	}
   741  
   742  	p.StateDBPVCManager.SetCustomName(instance.Spec.CustomNames.PVC.StateDB)
   743  	err = p.StateDBPVCManager.Reconcile(instance, update)
   744  	if err != nil {
   745  		return errors.Wrap(err, "failed CouchDB PVC reconciliation")
   746  	}
   747  
   748  	err = p.ReconcileSecret(instance)
   749  	if err != nil {
   750  		return errors.Wrap(err, "failed Secret reconciliation")
   751  	}
   752  
   753  	err = p.ServiceManager.Reconcile(instance, update)
   754  	if err != nil {
   755  		return errors.Wrap(err, "failed Service reconciliation")
   756  	}
   757  
   758  	err = p.DeploymentManager.Reconcile(instance, update)
   759  	if err != nil {
   760  		return errors.Wrap(err, "failed Deployment reconciliation")
   761  	}
   762  
   763  	err = p.ReconcilePeerRBAC(instance)
   764  	if err != nil {
   765  		return errors.Wrap(err, "failed RBAC reconciliation")
   766  	}
   767  
   768  	err = p.FluentDConfigMapManager.Reconcile(instance, update)
   769  	if err != nil {
   770  		return errors.Wrap(err, "failed FluentD ConfigMap reconciliation")
   771  	}
   772  
   773  	return nil
   774  }
   775  
   776  func (p *Peer) ReconcilePeerRBAC(instance *current.IBPPeer) error {
   777  	var err error
   778  
   779  	err = p.RoleManager.Reconcile(instance, false)
   780  	if err != nil {
   781  		return err
   782  	}
   783  
   784  	err = p.RoleBindingManager.Reconcile(instance, false)
   785  	if err != nil {
   786  		return err
   787  	}
   788  
   789  	err = p.ServiceAccountManager.Reconcile(instance, false)
   790  	if err != nil {
   791  		return err
   792  	}
   793  
   794  	return nil
   795  }
   796  
   797  // this function makes sure the deployment spec matches the expected state
   798  func (p *Peer) CheckStates(instance *current.IBPPeer) error {
   799  	if p.DeploymentManager.Exists(instance) {
   800  		err := p.DeploymentManager.CheckState(instance)
   801  		if err != nil {
   802  			log.Error(err, "unexpected state")
   803  			err = p.DeploymentManager.RestoreState(instance)
   804  			if err != nil {
   805  				return err
   806  			}
   807  		}
   808  	}
   809  
   810  	return nil
   811  }
   812  
   813  func (p *Peer) ReconcileSecret(instance *current.IBPPeer) error {
   814  	name := instance.Spec.MSPSecret
   815  	if name == "" {
   816  		name = instance.Name + "-secret" // default value for secret, if none specified
   817  	}
   818  
   819  	secret := &corev1.Secret{}
   820  	err := p.Client.Get(context.TODO(), types.NamespacedName{Name: name, Namespace: instance.Namespace}, secret)
   821  	if err != nil {
   822  		if k8serrors.IsNotFound(err) {
   823  			log.Info(fmt.Sprintf("Creating secret '%s'", name))
   824  			createErr := p.CreateSecret(instance)
   825  			if createErr != nil {
   826  				return createErr
   827  			}
   828  			return nil
   829  		}
   830  		return err
   831  	} else {
   832  		log.Info(fmt.Sprintf("Updating secret '%s'", name))
   833  		updateErr := p.UpdateSecret(instance, secret)
   834  		if updateErr != nil {
   835  			return updateErr
   836  		}
   837  	}
   838  
   839  	return nil
   840  }
   841  
   842  func (p *Peer) CreateSecret(instance *current.IBPPeer) error {
   843  	secret := &corev1.Secret{}
   844  	secret.Name = instance.Spec.MSPSecret
   845  	if secret.Name == "" {
   846  		secret.Name = instance.Name + "-secret" // default value for secret, if none specified
   847  	}
   848  	secret.Namespace = instance.Namespace
   849  	secret.Labels = p.GetLabels(instance)
   850  
   851  	secretData := instance.Spec.Secret
   852  	bytesData, err := json.Marshal(secretData)
   853  	if err != nil {
   854  		return err
   855  	}
   856  	secret.Data = make(map[string][]byte)
   857  	secret.Data["secret.json"] = bytesData
   858  
   859  	err = p.Client.Create(context.TODO(), secret, controllerclient.CreateOption{Owner: instance, Scheme: p.Scheme})
   860  	if err != nil {
   861  		return err
   862  	}
   863  
   864  	return nil
   865  }
   866  
   867  func (p *Peer) UpdateSecret(instance *current.IBPPeer, secret *corev1.Secret) error {
   868  	secretData := instance.Spec.Secret
   869  	bytesData, err := json.Marshal(secretData)
   870  	if err != nil {
   871  		return err
   872  	}
   873  
   874  	if secret.Data != nil && !bytes.Equal(secret.Data["secret.json"], bytesData) {
   875  		secret.Data["secret.json"] = bytesData
   876  
   877  		err = p.Client.Update(context.TODO(), secret, controllerclient.UpdateOption{Owner: instance, Scheme: p.Scheme})
   878  		if err != nil {
   879  			return err
   880  		}
   881  	}
   882  
   883  	return nil
   884  }
   885  
   886  func (p *Peer) UpdateExternalEndpoint(instance *current.IBPPeer) bool {
   887  	// Disable Service discovery
   888  	if instance.Spec.PeerExternalEndpoint == "do-not-set" {
   889  		return false
   890  	}
   891  
   892  	if instance.Spec.PeerExternalEndpoint == "" {
   893  		instance.Spec.PeerExternalEndpoint = instance.Namespace + "-" + instance.Name + "-peer." + instance.Spec.Domain + ":443"
   894  		return true
   895  	}
   896  	return false
   897  }
   898  
   899  func (p *Peer) SelectZone(instance *current.IBPPeer) (bool, error) {
   900  	if instance.Spec.Zone == "select" {
   901  		zone := util.GetZone(p.Client)
   902  		instance.Spec.Zone = zone
   903  		log.Info(fmt.Sprintf("Setting zone to '%s', and updating spec", zone))
   904  		return true, nil
   905  	}
   906  	if instance.Spec.Zone != "" {
   907  		err := util.ValidateZone(p.Client, instance.Spec.Zone)
   908  		if err != nil {
   909  			return false, err
   910  		}
   911  	}
   912  	return false, nil
   913  }
   914  
   915  func (p *Peer) SelectRegion(instance *current.IBPPeer) (bool, error) {
   916  	if instance.Spec.Region == "select" {
   917  		region := util.GetRegion(p.Client)
   918  		instance.Spec.Region = region
   919  		log.Info(fmt.Sprintf("Setting region to '%s', and updating spec", region))
   920  		return true, nil
   921  	}
   922  	if instance.Spec.Region != "" {
   923  		err := util.ValidateRegion(p.Client, instance.Spec.Region)
   924  		if err != nil {
   925  			return false, err
   926  		}
   927  	}
   928  	return false, nil
   929  }
   930  
   931  func (p *Peer) CheckDBType(instance *current.IBPPeer) bool {
   932  	if instance.Spec.StateDb == "" {
   933  		log.Info("Setting statedb type to 'CouchDB', and updating spec")
   934  		instance.Spec.StateDb = "CouchDB"
   935  		return true
   936  	}
   937  
   938  	return false
   939  }
   940  
   941  func (p *Peer) GetLabels(instance v1.Object) map[string]string {
   942  	label := os.Getenv("OPERATOR_LABEL_PREFIX")
   943  	if label == "" {
   944  		label = "fabric"
   945  	}
   946  
   947  	i := instance.(*current.IBPPeer)
   948  	return map[string]string{
   949  		"app":                          instance.GetName(),
   950  		"creator":                      label,
   951  		"orgname":                      i.Spec.MSPID,
   952  		"app.kubernetes.io/name":       label,
   953  		"app.kubernetes.io/instance":   label + "peer",
   954  		"app.kubernetes.io/managed-by": label + "-operator",
   955  	}
   956  }
   957  
   958  func (p *Peer) UpdateConnectionProfile(instance *current.IBPPeer) error {
   959  	var err error
   960  
   961  	endpoints := p.GetEndpoints(instance)
   962  
   963  	tlscert, err := common.GetTLSSignCertEncoded(p.Client, instance)
   964  	if err != nil {
   965  		return err
   966  	}
   967  
   968  	tlscacerts, err := common.GetTLSCACertEncoded(p.Client, instance)
   969  	if err != nil {
   970  		return err
   971  	}
   972  
   973  	tlsintercerts, err := common.GetTLSIntercertEncoded(p.Client, instance)
   974  	if err != nil {
   975  		return err
   976  	}
   977  
   978  	ecert, err := common.GetEcertSignCertEncoded(p.Client, instance)
   979  	if err != nil {
   980  		return err
   981  	}
   982  
   983  	cacert, err := common.GetEcertCACertEncoded(p.Client, instance)
   984  	if err != nil {
   985  		return err
   986  	}
   987  
   988  	admincerts, err := common.GetEcertAdmincertEncoded(p.Client, instance)
   989  	if err != nil {
   990  		return err
   991  	}
   992  
   993  	if len(tlsintercerts) > 0 {
   994  		tlscacerts = tlsintercerts
   995  	}
   996  
   997  	err = p.UpdateConnectionProfileConfigmap(instance, *endpoints, tlscert, tlscacerts, ecert, cacert, admincerts)
   998  	if err != nil {
   999  		return err
  1000  	}
  1001  
  1002  	return nil
  1003  }
  1004  
  1005  func (p *Peer) UpdateConnectionProfileConfigmap(instance *current.IBPPeer, endpoints current.PeerEndpoints, tlscert string, tlscacerts []string, ecert string, cacert []string, admincerts []string) error {
  1006  	// TODO add ecert.intermediatecerts and ecert.admincerts
  1007  	// TODO add tls.cacerts
  1008  	// TODO get the whole PeerConnectionProfile object from caller??
  1009  	name := instance.Name + "-connection-profile"
  1010  	connectionProfile := &current.PeerConnectionProfile{
  1011  		Endpoints: endpoints,
  1012  		TLS: &current.MSP{
  1013  			SignCerts: tlscert,
  1014  			CACerts:   tlscacerts,
  1015  		},
  1016  		Component: &current.MSP{
  1017  			SignCerts:  ecert,
  1018  			CACerts:    cacert,
  1019  			AdminCerts: admincerts,
  1020  		},
  1021  	}
  1022  
  1023  	bytes, err := json.Marshal(connectionProfile)
  1024  	if err != nil {
  1025  		return errors.Wrap(err, "failed to marshal connectionprofile")
  1026  	}
  1027  	cm := &corev1.ConfigMap{
  1028  		BinaryData: map[string][]byte{"profile.json": bytes},
  1029  	}
  1030  	cm.Name = name
  1031  	cm.Namespace = instance.Namespace
  1032  	cm.Labels = p.GetLabels(instance)
  1033  
  1034  	nn := types.NamespacedName{
  1035  		Name:      name,
  1036  		Namespace: instance.GetNamespace(),
  1037  	}
  1038  
  1039  	err = p.Client.Get(context.TODO(), nn, &corev1.ConfigMap{})
  1040  	if err == nil {
  1041  		log.Info(fmt.Sprintf("Updating connection profle configmap for %s", instance.Name))
  1042  		err = p.Client.Update(context.TODO(), cm, controllerclient.UpdateOption{
  1043  			Owner:  instance,
  1044  			Scheme: p.Scheme,
  1045  		})
  1046  		if err != nil {
  1047  			return errors.Wrap(err, "failed to update connection profile configmap")
  1048  		}
  1049  	} else {
  1050  		log.Info(fmt.Sprintf("Creating connection profle configmap for %s", instance.Name))
  1051  		err = p.Client.Create(context.TODO(), cm, controllerclient.CreateOption{
  1052  			Owner:  instance,
  1053  			Scheme: p.Scheme,
  1054  		})
  1055  		if err != nil {
  1056  			return errors.Wrap(err, "failed to create connection profile configmap")
  1057  		}
  1058  	}
  1059  	return nil
  1060  }
  1061  
  1062  func (p *Peer) GetEndpoints(instance *current.IBPPeer) *current.PeerEndpoints {
  1063  	endpoints := &current.PeerEndpoints{
  1064  		API:        "grpcs://" + instance.Namespace + "-" + instance.Name + "-peer." + instance.Spec.Domain + ":443",
  1065  		Operations: "https://" + instance.Namespace + "-" + instance.Name + "-operations." + instance.Spec.Domain + ":443",
  1066  		Grpcweb:    "https://" + instance.Namespace + "-" + instance.Name + "-grpcweb." + instance.Spec.Domain + ":443",
  1067  	}
  1068  	return endpoints
  1069  }
  1070  
  1071  func (p *Peer) ConfigExists(instance *current.IBPPeer) bool {
  1072  	name := fmt.Sprintf("%s-config", instance.GetName())
  1073  	namespacedName := types.NamespacedName{
  1074  		Name:      name,
  1075  		Namespace: instance.Namespace,
  1076  	}
  1077  
  1078  	cm := &corev1.ConfigMap{}
  1079  	err := p.Client.Get(context.TODO(), namespacedName, cm)
  1080  	if err != nil {
  1081  		return false
  1082  	}
  1083  
  1084  	return true
  1085  }
  1086  
  1087  func (p *Peer) CheckCSRHosts(instance *current.IBPPeer, hosts []string) bool {
  1088  	if instance.Spec.Secret != nil {
  1089  		if instance.Spec.Secret.Enrollment != nil {
  1090  			if instance.Spec.Secret.Enrollment.TLS == nil {
  1091  				instance.Spec.Secret.Enrollment.TLS = &current.Enrollment{}
  1092  			}
  1093  			if instance.Spec.Secret.Enrollment.TLS.CSR == nil {
  1094  				instance.Spec.Secret.Enrollment.TLS.CSR = &current.CSR{}
  1095  				instance.Spec.Secret.Enrollment.TLS.CSR.Hosts = hosts
  1096  				return true
  1097  			} else {
  1098  				originalLength := len(instance.Spec.Secret.Enrollment.TLS.CSR.Hosts)
  1099  				for _, host := range instance.Spec.Secret.Enrollment.TLS.CSR.Hosts {
  1100  					hosts = util.AppendStringIfMissing(hosts, host)
  1101  				}
  1102  				instance.Spec.Secret.Enrollment.TLS.CSR.Hosts = hosts
  1103  				newLength := len(instance.Spec.Secret.Enrollment.TLS.CSR.Hosts)
  1104  				return originalLength != newLength
  1105  			}
  1106  		}
  1107  	}
  1108  	return false
  1109  }
  1110  
  1111  func (p *Peer) GetBCCSPSectionForInstance(instance *current.IBPPeer) (*commonapi.BCCSP, error) {
  1112  	var bccsp *commonapi.BCCSP
  1113  	if instance.IsHSMEnabled() {
  1114  		co, err := instance.GetConfigOverride()
  1115  		if err != nil {
  1116  			return nil, errors.Wrap(err, "failed to get configoverride")
  1117  		}
  1118  
  1119  		configOverride := co.(CoreConfig)
  1120  		configOverride.SetPKCS11Defaults(instance.UsingHSMProxy())
  1121  		bccsp = configOverride.GetBCCSPSection()
  1122  	}
  1123  
  1124  	return bccsp, nil
  1125  }
  1126  
  1127  func (p *Peer) GetInitStoragePath(instance *current.IBPPeer) string {
  1128  	if p.Config != nil && p.Config.PeerInitConfig != nil && p.Config.PeerInitConfig.StoragePath != "" {
  1129  		return filepath.Join(p.Config.PeerInitConfig.StoragePath, instance.GetName())
  1130  	}
  1131  
  1132  	return filepath.Join("/", "peerinit", instance.GetName())
  1133  }
  1134  
  1135  func (p *Peer) ReconcileFabricPeerMigrationV1_4(instance *current.IBPPeer) error {
  1136  	peerConfig, err := p.FabricPeerMigrationV1_4(instance)
  1137  	if err != nil {
  1138  		return errors.Wrap(err, "failed to migrate peer between fabric versions")
  1139  	}
  1140  
  1141  	if peerConfig != nil {
  1142  		log.Info("Peer config updated during fabric peer migration, updating config map...")
  1143  		if err := p.Initializer.CoreConfigMap().CreateOrUpdate(instance, peerConfig); err != nil {
  1144  			return errors.Wrapf(err, "failed to create/update '%s' peer's config map", instance.GetName())
  1145  		}
  1146  	}
  1147  
  1148  	return nil
  1149  }
  1150  
  1151  // Moving to fabric version above 1.4.6 require that the `msp/keystore` value be removed
  1152  // from BCCSP section if configured to use PKCS11 (HSM). NOTE: This does not support
  1153  // migration across major release, will not cover migration peer from 1.4.x to 2.x
  1154  func (p *Peer) FabricPeerMigrationV1_4(instance *current.IBPPeer) (*peerconfig.Core, error) {
  1155  	if !instance.IsHSMEnabled() {
  1156  		return nil, nil
  1157  	}
  1158  
  1159  	peerTag := instance.Spec.Images.PeerTag
  1160  	if !strings.Contains(peerTag, "sha") {
  1161  		tag := strings.Split(peerTag, "-")[0]
  1162  
  1163  		peerVersion := version.String(tag)
  1164  		if !peerVersion.GreaterThan(version.V1_4_6) {
  1165  			return nil, nil
  1166  		}
  1167  
  1168  		log.Info(fmt.Sprintf("Peer moving to fabric version %s", peerVersion))
  1169  	} else {
  1170  		if version.GetMajorReleaseVersion(instance.Spec.FabricVersion) == version.V2 {
  1171  			return nil, nil
  1172  		}
  1173  		log.Info(fmt.Sprintf("Peer moving to digest %s", peerTag))
  1174  	}
  1175  
  1176  	// Read peer config map and remove keystore value from BCCSP section
  1177  	cm, err := initializer.GetCoreFromConfigMap(p.Client, instance)
  1178  	if err != nil {
  1179  		return nil, errors.Wrapf(err, "failed to get '%s' peer's config map", instance.GetName())
  1180  	}
  1181  
  1182  	peerConfig := &peerconfig.Core{}
  1183  	if err := yaml.Unmarshal(cm.BinaryData["core.yaml"], peerConfig); err != nil {
  1184  		return nil, errors.Wrap(err, "invalid peer config")
  1185  	}
  1186  
  1187  	// If already nil, don't need to proceed further as config updates are not required
  1188  	if peerConfig.Peer.BCCSP.PKCS11.FileKeyStore == nil {
  1189  		return nil, nil
  1190  	}
  1191  
  1192  	peerConfig.Peer.BCCSP.PKCS11.FileKeyStore = nil
  1193  
  1194  	return peerConfig, nil
  1195  }
  1196  
  1197  func (p *Peer) ReconcileFabricPeerMigrationV2_0(instance *current.IBPPeer) error {
  1198  	log.Info("Migration to V2 requested, checking if migration is needed")
  1199  
  1200  	migrator := &v2.Migrate{
  1201  		DeploymentManager: p.DeploymentManager,
  1202  		ConfigMapManager:  &initializer.CoreConfigMap{Config: p.Config.PeerInitConfig, Scheme: p.Scheme, GetLabels: p.GetLabels, Client: p.Client},
  1203  		Client:            p.Client,
  1204  	}
  1205  
  1206  	if err := fabric.V2Migrate(instance, migrator, instance.Spec.FabricVersion, p.Config.Operator.Peer.Timeouts.DBMigration); err != nil {
  1207  		return err
  1208  	}
  1209  
  1210  	return nil
  1211  }
  1212  
  1213  func (p *Peer) ReconcileFabricPeerMigrationV2_4(instance *current.IBPPeer) error {
  1214  	log.Info("Migration to V2.4.x requested, checking if migration is needed")
  1215  
  1216  	migrator := &v2.Migrate{
  1217  		DeploymentManager: p.DeploymentManager,
  1218  		ConfigMapManager:  &initializer.CoreConfigMap{Config: p.Config.PeerInitConfig, Scheme: p.Scheme, GetLabels: p.GetLabels, Client: p.Client},
  1219  		Client:            p.Client,
  1220  	}
  1221  
  1222  	if err := fabric.V24Migrate(instance, migrator, instance.Spec.FabricVersion, p.Config.Operator.Peer.Timeouts.DBMigration); err != nil {
  1223  		return err
  1224  	}
  1225  
  1226  	return nil
  1227  }
  1228  
  1229  func (p *Peer) HandleMigrationJobs(listOpt k8sclient.ListOption, instance *current.IBPPeer) (bool, error) {
  1230  	status, job, err := p.CheckForRunningJobs(listOpt)
  1231  	if err != nil {
  1232  		return false, err
  1233  	}
  1234  
  1235  	switch status {
  1236  	case RUNNING:
  1237  		return true, nil
  1238  	case COMPLETED:
  1239  		jobName := job.GetName()
  1240  		log.Info(fmt.Sprintf("Migration job '%s' completed, cleaning up...", jobName))
  1241  
  1242  		migrationJob := &batchv1.Job{
  1243  			ObjectMeta: v1.ObjectMeta{
  1244  				Name:      jobName,
  1245  				Namespace: instance.GetNamespace(),
  1246  			},
  1247  		}
  1248  
  1249  		if err := p.Client.Delete(context.TODO(), migrationJob); err != nil {
  1250  			return false, errors.Wrap(err, "failed to delete migration job after completion")
  1251  		}
  1252  
  1253  		// TODO: Need to investigate why job is not adding controller reference to job pod,
  1254  		// this manual cleanup should not be required
  1255  		podList := &corev1.PodList{}
  1256  		if err := p.Client.List(context.TODO(), podList, k8sclient.MatchingLabels{"job-name": jobName}); err != nil {
  1257  			return false, errors.Wrap(err, "failed to list db migraton pods")
  1258  		}
  1259  
  1260  		if len(podList.Items) == 1 {
  1261  			if err := p.Client.Delete(context.TODO(), &podList.Items[0]); err != nil {
  1262  				return false, errors.Wrap(err, "failed to delete db migration pod")
  1263  			}
  1264  		}
  1265  
  1266  		if instance.UsingCouchDB() {
  1267  			couchDBPod := &corev1.Pod{
  1268  				ObjectMeta: v1.ObjectMeta{
  1269  					Name:      fmt.Sprintf("%s-couchdb", instance.GetName()),
  1270  					Namespace: instance.GetNamespace(),
  1271  				},
  1272  			}
  1273  
  1274  			if err := p.Client.Delete(context.TODO(), couchDBPod); err != nil {
  1275  				return false, errors.Wrap(err, "failed to delete couchdb pod")
  1276  			}
  1277  		}
  1278  
  1279  		return false, nil
  1280  	default:
  1281  		return false, nil
  1282  	}
  1283  }
  1284  
  1285  type JobStatus string
  1286  
  1287  const (
  1288  	COMPLETED JobStatus = "completed"
  1289  	RUNNING   JobStatus = "running"
  1290  	NOTFOUND  JobStatus = "not-found"
  1291  	UNKNOWN   JobStatus = "unknown"
  1292  )
  1293  
  1294  func (p *Peer) CheckForRunningJobs(listOpt k8sclient.ListOption) (JobStatus, *jobv1.Job, error) {
  1295  	jobList := &batchv1.JobList{}
  1296  	if err := p.Client.List(context.TODO(), jobList, listOpt); err != nil {
  1297  		return NOTFOUND, nil, nil
  1298  	}
  1299  
  1300  	if len(jobList.Items) == 0 {
  1301  		return NOTFOUND, nil, nil
  1302  	}
  1303  
  1304  	// There should only be one job that is triggered per migration request
  1305  	k8sJob := jobList.Items[0]
  1306  	job := jobv1.NewWithDefaultsUseExistingName(&k8sJob)
  1307  
  1308  	if len(job.Job.Status.Conditions) > 0 {
  1309  		cond := job.Job.Status.Conditions[0]
  1310  		if cond.Type == batchv1.JobFailed {
  1311  			log.Info(fmt.Sprintf("Job '%s' failed for reason: %s: %s", job.Name, cond.Reason, cond.Message))
  1312  		}
  1313  	}
  1314  
  1315  	completed, err := job.ContainerFinished(p.Client, "dbmigration")
  1316  	if err != nil {
  1317  		return UNKNOWN, nil, err
  1318  	}
  1319  
  1320  	if completed {
  1321  		return COMPLETED, job, nil
  1322  
  1323  	}
  1324  
  1325  	return RUNNING, nil, nil
  1326  }
  1327  
  1328  func (p *Peer) UpgradeDBs(instance *current.IBPPeer) error {
  1329  	log.Info("Upgrade DBs action requested")
  1330  	if err := action.UpgradeDBs(p.DeploymentManager, p.Client, instance, p.Config.Operator.Peer.Timeouts.DBMigration); err != nil {
  1331  		return errors.Wrap(err, "failed to reset peer")
  1332  	}
  1333  	orig := instance.DeepCopy()
  1334  
  1335  	instance.Spec.Action.UpgradeDBs = false
  1336  	if err := p.Client.Patch(context.TODO(), instance, k8sclient.MergeFrom(orig)); err != nil {
  1337  		return errors.Wrap(err, "failed to reset reenroll action flag")
  1338  	}
  1339  
  1340  	return nil
  1341  }
  1342  
  1343  func (p *Peer) EnrollForEcert(instance *current.IBPPeer) error {
  1344  	log.Info(fmt.Sprintf("Ecert enroll triggered via action parameter for '%s'", instance.GetName()))
  1345  
  1346  	secret := instance.Spec.Secret
  1347  	if secret == nil || secret.Enrollment == nil || secret.Enrollment.Component == nil {
  1348  		return errors.New("unable to enroll, no ecert enrollment information provided")
  1349  	}
  1350  	ecertSpec := secret.Enrollment.Component
  1351  
  1352  	storagePath := filepath.Join(p.GetInitStoragePath(instance), "ecert")
  1353  	crypto, err := action.Enroll(instance, ecertSpec, storagePath, p.Client, p.Scheme, true, p.Config.Operator.Peer.Timeouts.EnrollJob)
  1354  	if err != nil {
  1355  		return errors.Wrap(err, "failed to enroll for ecert")
  1356  	}
  1357  
  1358  	err = p.Initializer.GenerateSecrets("ecert", instance, crypto)
  1359  	if err != nil {
  1360  		return errors.Wrap(err, "failed to generate ecert secrets")
  1361  	}
  1362  
  1363  	return nil
  1364  }
  1365  
  1366  func (p *Peer) EnrollForTLSCert(instance *current.IBPPeer) error {
  1367  	log.Info(fmt.Sprintf("TLS cert enroll triggered via action parameter for '%s'", instance.GetName()))
  1368  
  1369  	secret := instance.Spec.Secret
  1370  	if secret == nil || secret.Enrollment == nil || secret.Enrollment.TLS == nil {
  1371  		return errors.New("unable to enroll, no TLS enrollment information provided")
  1372  	}
  1373  	tlscertSpec := secret.Enrollment.TLS
  1374  
  1375  	storagePath := filepath.Join(p.GetInitStoragePath(instance), "tls")
  1376  	crypto, err := action.Enroll(instance, tlscertSpec, storagePath, p.Client, p.Scheme, false, p.Config.Operator.Peer.Timeouts.EnrollJob)
  1377  	if err != nil {
  1378  		return errors.Wrap(err, "failed to enroll for TLS cert")
  1379  	}
  1380  
  1381  	err = p.Initializer.GenerateSecrets("tls", instance, crypto)
  1382  	if err != nil {
  1383  		return errors.Wrap(err, "failed to generate ecert secrets")
  1384  	}
  1385  
  1386  	return nil
  1387  }
  1388  
  1389  func (p *Peer) ReconcileHSMImages(instance *current.IBPPeer) bool {
  1390  	hsmConfig, err := commonconfig.ReadHSMConfig(p.Client, instance)
  1391  	if err != nil {
  1392  		return false
  1393  	}
  1394  
  1395  	if hsmConfig.Library.AutoUpdateDisabled {
  1396  		return false
  1397  	}
  1398  
  1399  	updated := false
  1400  	if hsmConfig.Library.Image != "" {
  1401  		hsmImage := hsmConfig.Library.Image
  1402  		lastIndex := strings.LastIndex(hsmImage, ":")
  1403  		image := hsmImage[:lastIndex]
  1404  		tag := hsmImage[lastIndex+1:]
  1405  
  1406  		if instance.Spec.Images.HSMImage != image {
  1407  			instance.Spec.Images.HSMImage = image
  1408  			updated = true
  1409  		}
  1410  
  1411  		if instance.Spec.Images.HSMTag != tag {
  1412  			instance.Spec.Images.HSMTag = tag
  1413  			updated = true
  1414  		}
  1415  	}
  1416  
  1417  	return updated
  1418  }
  1419  
  1420  func (p *Peer) HandleActions(instance *current.IBPPeer, update Update) error {
  1421  	orig := instance.DeepCopy()
  1422  
  1423  	if update.EcertReenrollNeeded() {
  1424  		if err := p.ReenrollEcert(instance); err != nil {
  1425  			log.Error(err, "Resetting action flag on failure")
  1426  			instance.ResetEcertReenroll()
  1427  			return err
  1428  		}
  1429  		instance.ResetEcertReenroll()
  1430  	}
  1431  
  1432  	if update.TLSReenrollNeeded() {
  1433  		if err := p.ReenrollTLSCert(instance); err != nil {
  1434  			log.Error(err, "Resetting action flag on failure")
  1435  			instance.ResetTLSReenroll()
  1436  			return err
  1437  		}
  1438  		instance.ResetTLSReenroll()
  1439  	}
  1440  
  1441  	if update.EcertNewKeyReenroll() {
  1442  		if err := p.ReenrollEcertNewKey(instance); err != nil {
  1443  			log.Error(err, "Resetting action flag on failure")
  1444  			instance.ResetEcertReenroll()
  1445  			return err
  1446  		}
  1447  		instance.ResetEcertReenroll()
  1448  	}
  1449  
  1450  	if update.TLScertNewKeyReenroll() {
  1451  		if err := p.ReenrollTLSCertNewKey(instance); err != nil {
  1452  			log.Error(err, "Resetting action flag on failure")
  1453  			instance.ResetTLSReenroll()
  1454  			return err
  1455  		}
  1456  		instance.ResetTLSReenroll()
  1457  	}
  1458  
  1459  	if update.EcertEnroll() {
  1460  		if err := p.EnrollForEcert(instance); err != nil {
  1461  			log.Error(err, "Resetting action flag on failure")
  1462  			instance.ResetEcertEnroll()
  1463  			return err
  1464  		}
  1465  		instance.ResetEcertEnroll()
  1466  	}
  1467  
  1468  	if update.TLSCertEnroll() {
  1469  		if err := p.EnrollForTLSCert(instance); err != nil {
  1470  			log.Error(err, "Resetting action flag on failure")
  1471  			instance.ResetTLSEnroll()
  1472  			return err
  1473  		}
  1474  		instance.ResetTLSEnroll()
  1475  	}
  1476  
  1477  	// Upgrade DBs needs to be one of the last thing that should be performed to allow for other
  1478  	// update flags to be processed
  1479  	if update.UpgradeDBs() {
  1480  		if err := p.UpgradeDBs(instance); err != nil {
  1481  			// not adding reset as this action should not be run twice
  1482  			// log.Error(err, "Resetting action flag on failure")
  1483  			return err
  1484  		}
  1485  		// Can return without continuing down to restart logic cause resetting a peer will
  1486  		// initiate a restart anyways
  1487  		instance.ResetUpgradeDBs()
  1488  
  1489  	} else if update.RestartNeeded() {
  1490  		if err := p.RestartAction(instance); err != nil {
  1491  			log.Error(err, "Resetting action flag on failure")
  1492  			instance.ResetRestart()
  1493  			return err
  1494  		}
  1495  		instance.ResetRestart()
  1496  	}
  1497  
  1498  	if err := p.Client.Patch(context.TODO(), instance, k8sclient.MergeFrom(orig)); err != nil {
  1499  		return errors.Wrap(err, "failed to reset action flags")
  1500  	}
  1501  
  1502  	return nil
  1503  }
  1504  
  1505  func (p *Peer) ReenrollEcert(instance *current.IBPPeer) error {
  1506  	log.Info("Ecert reenroll triggered via action parameter")
  1507  	if err := p.reenrollCert(instance, commoninit.ECERT, false); err != nil {
  1508  		return errors.Wrap(err, "ecert reenroll reusing existing private key action failed")
  1509  	}
  1510  	return nil
  1511  }
  1512  
  1513  func (p *Peer) ReenrollEcertNewKey(instance *current.IBPPeer) error {
  1514  	log.Info("Ecert with new key reenroll triggered via action parameter")
  1515  	if err := p.reenrollCert(instance, commoninit.ECERT, true); err != nil {
  1516  		return errors.Wrap(err, "ecert reenroll with new key action failed")
  1517  	}
  1518  	return nil
  1519  }
  1520  
  1521  func (p *Peer) ReenrollTLSCert(instance *current.IBPPeer) error {
  1522  	log.Info("TLS reenroll triggered via action parameter")
  1523  	if err := p.reenrollCert(instance, commoninit.TLS, false); err != nil {
  1524  		return errors.Wrap(err, "tls reenroll reusing existing private key action failed")
  1525  	}
  1526  	return nil
  1527  }
  1528  
  1529  func (p *Peer) ReenrollTLSCertNewKey(instance *current.IBPPeer) error {
  1530  	log.Info("TLS with new key reenroll triggered via action parameter")
  1531  	if err := p.reenrollCert(instance, commoninit.TLS, true); err != nil {
  1532  		return errors.Wrap(err, "tls reenroll with new key action failed")
  1533  	}
  1534  	return nil
  1535  }
  1536  
  1537  func (p *Peer) reenrollCert(instance *current.IBPPeer, certType commoninit.SecretType, newKey bool) error {
  1538  	return action.Reenroll(p, p.Client, certType, instance, newKey)
  1539  }
  1540  
  1541  func (p *Peer) RestartAction(instance *current.IBPPeer) error {
  1542  	log.Info("Restart triggered via action parameter")
  1543  	if err := p.Restart.ForRestartAction(instance); err != nil {
  1544  		return errors.Wrap(err, "failed to restart peer pods")
  1545  	}
  1546  	return nil
  1547  }
  1548  
  1549  func (p *Peer) HandleRestart(instance *current.IBPPeer, update Update) error {
  1550  	// If restart is disabled for components, can return immediately
  1551  	if p.Config.Operator.Restart.Disable.Components {
  1552  		return nil
  1553  	}
  1554  
  1555  	err := p.Restart.TriggerIfNeeded(instance)
  1556  	if err != nil {
  1557  		return errors.Wrap(err, "failed to restart deployment")
  1558  	}
  1559  
  1560  	return nil
  1561  }
  1562  
  1563  func (p *Peer) UpdateMSPCertificates(instance *current.IBPPeer) error {
  1564  	log.Info("Updating certificates passed in MSP spec")
  1565  
  1566  	updatedPeer, err := p.Initializer.GetUpdatedPeer(instance)
  1567  	if err != nil {
  1568  		return err
  1569  	}
  1570  
  1571  	crypto, err := updatedPeer.GenerateCrypto()
  1572  	if err != nil {
  1573  		return err
  1574  	}
  1575  
  1576  	if crypto != nil {
  1577  		err = p.Initializer.UpdateSecretsFromResponse(instance, crypto)
  1578  		if err != nil {
  1579  			return err
  1580  		}
  1581  	}
  1582  
  1583  	return nil
  1584  }
  1585  
  1586  func (p *Peer) RenewCert(certType commoninit.SecretType, obj runtime.Object, newKey bool) error {
  1587  	instance := obj.(*current.IBPPeer)
  1588  	if instance.Spec.Secret == nil {
  1589  		return errors.New(fmt.Sprintf("missing secret spec for instance '%s'", instance.GetName()))
  1590  	}
  1591  
  1592  	if instance.Spec.Secret.Enrollment != nil {
  1593  		log.Info(fmt.Sprintf("Renewing %s certificate for instance '%s'", string(certType), instance.Name))
  1594  
  1595  		hsmEnabled := instance.IsHSMEnabled()
  1596  		storagePath := p.GetInitStoragePath(instance)
  1597  		spec := instance.Spec.Secret.Enrollment
  1598  		bccsp, err := p.GetBCCSPSectionForInstance(instance)
  1599  		if err != nil {
  1600  			return err
  1601  		}
  1602  
  1603  		err = p.CertificateManager.RenewCert(certType, instance, spec, bccsp, storagePath, hsmEnabled, newKey)
  1604  		if err != nil {
  1605  			return err
  1606  		}
  1607  	} else {
  1608  		return errors.New("cannot auto-renew certificate created by MSP, force renewal required")
  1609  	}
  1610  
  1611  	return nil
  1612  }
  1613  
  1614  func (p *Peer) CustomLogic(instance *current.IBPPeer, update Update) (*current.CRStatus, *common.Result, error) {
  1615  	var status *current.CRStatus
  1616  	var err error
  1617  
  1618  	if !p.CanSetCertificateTimer(instance, update) {
  1619  		log.Info("Certificate update detected but peer not yet deployed, requeuing request...")
  1620  		return status, &common.Result{
  1621  			Result: reconcile.Result{
  1622  				Requeue: true,
  1623  			},
  1624  		}, nil
  1625  	}
  1626  
  1627  	// Check if crypto needs to be backed up before an update overrides exisitng secrets
  1628  	if update.CryptoBackupNeeded() {
  1629  		log.Info("Performing backup of TLS and ecert crypto")
  1630  		err = common.BackupCrypto(p.Client, p.Scheme, instance, p.GetLabels(instance))
  1631  		if err != nil {
  1632  			return status, nil, errors.Wrap(err, "failed to backup TLS and ecert crypto")
  1633  		}
  1634  	}
  1635  
  1636  	status, err = p.CheckCertificates(instance)
  1637  	if err != nil {
  1638  		return status, nil, errors.Wrap(err, "failed to check for expiring certificates")
  1639  	}
  1640  
  1641  	if update.CertificateCreated() {
  1642  		log.Info(fmt.Sprintf("%s certificate was created", update.GetCreatedCertType()))
  1643  		err = p.SetCertificateTimer(instance, update.GetCreatedCertType())
  1644  		if err != nil {
  1645  			return status, nil, errors.Wrap(err, "failed to set timer for certificate renewal")
  1646  		}
  1647  	}
  1648  
  1649  	if update.EcertUpdated() {
  1650  		log.Info("Ecert was updated")
  1651  		err = p.SetCertificateTimer(instance, commoninit.ECERT)
  1652  		if err != nil {
  1653  			return status, nil, errors.Wrap(err, "failed to set timer for certificate renewal")
  1654  		}
  1655  	}
  1656  
  1657  	if update.TLSCertUpdated() {
  1658  		log.Info("TLS cert was updated")
  1659  		err = p.SetCertificateTimer(instance, commoninit.TLS)
  1660  		if err != nil {
  1661  			return status, nil, errors.Wrap(err, "failed to set timer for certificate renewal")
  1662  		}
  1663  	}
  1664  
  1665  	return status, nil, err
  1666  
  1667  }
  1668  
  1669  func (p *Peer) CheckCertificates(instance *current.IBPPeer) (*current.CRStatus, error) {
  1670  	numSecondsBeforeExpire := instance.Spec.GetNumSecondsWarningPeriod()
  1671  	statusType, message, err := p.CertificateManager.CheckCertificatesForExpire(instance, numSecondsBeforeExpire)
  1672  	if err != nil {
  1673  		return nil, err
  1674  	}
  1675  
  1676  	crStatus := &current.CRStatus{
  1677  		Type:    statusType,
  1678  		Message: message,
  1679  	}
  1680  
  1681  	switch statusType {
  1682  	case current.Deployed:
  1683  		crStatus.Reason = "allPodsDeployed"
  1684  	default:
  1685  		crStatus.Reason = "certRenewalRequired"
  1686  	}
  1687  
  1688  	return crStatus, nil
  1689  }
  1690  
  1691  func (p *Peer) SetCertificateTimer(instance *current.IBPPeer, certType commoninit.SecretType) error {
  1692  	certName := fmt.Sprintf("%s-%s-signcert", certType, instance.Name)
  1693  	numSecondsBeforeExpire := instance.Spec.GetNumSecondsWarningPeriod()
  1694  	duration, err := p.CertificateManager.GetDurationToNextRenewal(certType, instance, numSecondsBeforeExpire)
  1695  	if err != nil {
  1696  		return err
  1697  	}
  1698  
  1699  	log.Info((fmt.Sprintf("Setting timer to renew %s %d days before it expires", certName, int(numSecondsBeforeExpire/DaysToSecondsConversion))))
  1700  
  1701  	if p.RenewCertTimers[certName] != nil {
  1702  		p.RenewCertTimers[certName].Stop()
  1703  		p.RenewCertTimers[certName] = nil
  1704  	}
  1705  	p.RenewCertTimers[certName] = time.AfterFunc(duration, func() {
  1706  		// Check certs for updated status & set status so that reconcile is triggered after cert renewal. Reconcile loop will handle
  1707  		// checking certs again to determine whether instance status can return to Deployed
  1708  		err := p.UpdateCRStatus(instance)
  1709  		if err != nil {
  1710  			log.Error(err, "failed to update CR status")
  1711  		}
  1712  
  1713  		// get instance
  1714  		instanceLatest := &current.IBPPeer{}
  1715  		err = p.Client.Get(context.TODO(), types.NamespacedName{Namespace: instance.Namespace, Name: instance.Name}, instanceLatest)
  1716  		if err != nil {
  1717  			log.Error(err, "failed to get latest instance")
  1718  			return
  1719  		}
  1720  
  1721  		err = common.BackupCrypto(p.Client, p.Scheme, instance, p.GetLabels(instance))
  1722  		if err != nil {
  1723  			log.Error(err, "failed to backup crypto before renewing cert")
  1724  			return
  1725  		}
  1726  
  1727  		err = p.RenewCert(certType, instanceLatest, false)
  1728  		if err != nil {
  1729  			log.Info(fmt.Sprintf("Failed to renew %s certificate: %s, status of %s remaining in Warning phase", certType, err, instanceLatest.GetName()))
  1730  			return
  1731  		}
  1732  		log.Info(fmt.Sprintf("%s renewal complete", certName))
  1733  	})
  1734  
  1735  	return nil
  1736  }
  1737  
  1738  // NOTE: This is called by the timer's subroutine when it goes off, not during a reconcile loop.
  1739  // Therefore, it won't be overriden by the "SetStatus" method in ibppeer_controller.go
  1740  func (p *Peer) UpdateCRStatus(instance *current.IBPPeer) error {
  1741  	status, err := p.CheckCertificates(instance)
  1742  	if err != nil {
  1743  		return errors.Wrap(err, "failed to check certificates")
  1744  	}
  1745  
  1746  	// Get most up-to-date instance at the time of update
  1747  	updatedInstance := &current.IBPPeer{}
  1748  	err = p.Client.Get(context.TODO(), types.NamespacedName{Name: instance.Name, Namespace: instance.Namespace}, updatedInstance)
  1749  	if err != nil {
  1750  		return errors.Wrap(err, "failed to get new instance")
  1751  	}
  1752  
  1753  	// Don't trigger reconcile if status remaining the same
  1754  	if updatedInstance.Status.Type == status.Type && updatedInstance.Status.Reason == status.Reason && updatedInstance.Status.Message == status.Message {
  1755  		return nil
  1756  	}
  1757  
  1758  	updatedInstance.Status.Type = status.Type
  1759  	updatedInstance.Status.Reason = status.Reason
  1760  	updatedInstance.Status.Message = status.Message
  1761  	updatedInstance.Status.Status = current.True
  1762  	updatedInstance.Status.LastHeartbeatTime = time.Now().String()
  1763  
  1764  	log.Info(fmt.Sprintf("Updating status of IBPPeer custom resource %s to %s phase", instance.Name, status.Type))
  1765  	err = p.Client.UpdateStatus(context.TODO(), updatedInstance)
  1766  	if err != nil {
  1767  		return errors.Wrapf(err, "failed to update status to %s phase", status.Type)
  1768  	}
  1769  
  1770  	return nil
  1771  }
  1772  
  1773  // This function checks whether the instance is in Deployed or Warning state when a cert
  1774  // update is detected. Only if Deployed or in Warning will a timer be set; otherwise,
  1775  // the update will be requeued until the Peer has completed deploying.
  1776  func (p *Peer) CanSetCertificateTimer(instance *current.IBPPeer, update Update) bool {
  1777  	if update.CertificateCreated() || update.CertificateUpdated() {
  1778  		if !(instance.Status.Type == current.Deployed || instance.Status.Type == current.Warning) {
  1779  			return false
  1780  		}
  1781  	}
  1782  	return true
  1783  }