github.com/IBM-Blockchain/fabric-operator@v1.0.4/pkg/offering/base/peer/override/deployment.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 override
    20  
    21  import (
    22  	"context"
    23  	"encoding/json"
    24  	"fmt"
    25  	"path/filepath"
    26  	"strings"
    27  
    28  	current "github.com/IBM-Blockchain/fabric-operator/api/v1beta1"
    29  	"github.com/IBM-Blockchain/fabric-operator/pkg/initializer/common/config"
    30  	"github.com/IBM-Blockchain/fabric-operator/pkg/manager/resources"
    31  	"github.com/IBM-Blockchain/fabric-operator/pkg/manager/resources/container"
    32  	"github.com/IBM-Blockchain/fabric-operator/pkg/manager/resources/deployment"
    33  	dep "github.com/IBM-Blockchain/fabric-operator/pkg/manager/resources/deployment"
    34  	"github.com/IBM-Blockchain/fabric-operator/pkg/manager/resources/serviceaccount"
    35  	"github.com/IBM-Blockchain/fabric-operator/pkg/offering/common"
    36  	"github.com/IBM-Blockchain/fabric-operator/pkg/util"
    37  	"github.com/IBM-Blockchain/fabric-operator/pkg/util/image"
    38  	"github.com/IBM-Blockchain/fabric-operator/version"
    39  	"github.com/pkg/errors"
    40  	appsv1 "k8s.io/api/apps/v1"
    41  	corev1 "k8s.io/api/core/v1"
    42  	"k8s.io/apimachinery/pkg/api/resource"
    43  	v1 "k8s.io/apimachinery/pkg/apis/meta/v1"
    44  	"k8s.io/apimachinery/pkg/types"
    45  )
    46  
    47  // Container names
    48  const (
    49  	INIT        = "init"
    50  	PEER        = "peer"
    51  	DIND        = "dind"
    52  	PROXY       = "proxy"
    53  	FLUENTD     = "chaincode-logs"
    54  	COUCHDB     = "couchdb"
    55  	COUCHDBINIT = "couchdbinit"
    56  	CCLAUNCHER  = "chaincode-launcher"
    57  	HSMCLIENT   = "hsm-client"
    58  )
    59  
    60  type CoreConfig interface {
    61  	UsingPKCS11() bool
    62  }
    63  
    64  func (o *Override) Deployment(object v1.Object, deployment *appsv1.Deployment, action resources.Action) error {
    65  	instance := object.(*current.IBPPeer)
    66  	switch action {
    67  	case resources.Create:
    68  		return o.CreateDeployment(instance, deployment)
    69  	case resources.Update:
    70  		return o.UpdateDeployment(instance, deployment)
    71  	}
    72  
    73  	return nil
    74  }
    75  
    76  func (o *Override) CreateDeployment(instance *current.IBPPeer, k8sDep *appsv1.Deployment) error {
    77  	var err error
    78  	name := instance.GetName()
    79  
    80  	if !instance.Spec.License.Accept {
    81  		return errors.New("user must accept license before continuing")
    82  	}
    83  
    84  	mspID := instance.Spec.MSPID
    85  	if mspID == "" {
    86  		return errors.New("failed to provide MSP ID for peer")
    87  	}
    88  
    89  	deployment := dep.New(k8sDep)
    90  	initContainer, err := deployment.GetContainer(INIT)
    91  	if err != nil {
    92  		return errors.New("init container not found in deployment spec")
    93  	}
    94  	peerContainer, err := deployment.GetContainer(PEER)
    95  	if err != nil {
    96  		return errors.New("peer container not found in deployment spec")
    97  	}
    98  	grpcwebContainer, err := deployment.GetContainer(PROXY)
    99  	if err != nil {
   100  		return errors.New("grpc container not found in deployment spec")
   101  	}
   102  
   103  	stateDB := instance.Spec.StateDb
   104  	if instance.UsingCouchDB() {
   105  		if !deployment.ContainerExists(COUCHDB) { // If coucdb container exists, don't need to create it again
   106  			stateDB = "CouchDB"
   107  			err = o.CreateCouchDBContainers(instance, deployment)
   108  			if err != nil {
   109  				return err
   110  			}
   111  		}
   112  	} else if instance.Spec.UsingLevelDB() {
   113  		stateDB = "goleveldb"
   114  
   115  		peerContainer.AppendVolumeMountWithSubPathIfMissing("db-data", "/data/peer/ledgersData/stateLeveldb/", "data")
   116  		initContainer.AppendVolumeMountWithSubPathIfMissing("db-data", "/data/peer/ledgersData/stateLeveldb/", "data")
   117  
   118  		deployment.UpdateContainer(peerContainer)
   119  		deployment.UpdateInitContainer(initContainer)
   120  	} else {
   121  		return errors.New("unsupported StateDB type")
   122  	}
   123  
   124  	err = o.CommonDeploymentOverrides(instance, deployment)
   125  	if err != nil {
   126  		return err
   127  	}
   128  
   129  	// At this point we know init, peer, and proxy containers exists.
   130  	// Can use MustGetContainer to avoid handling error
   131  	peerContainer = deployment.MustGetContainer(PEER)
   132  	grpcwebContainer = deployment.MustGetContainer(PROXY)
   133  
   134  	deployment.SetImagePullSecrets(instance.Spec.ImagePullSecrets)
   135  	deployment.SetServiceAccountName(serviceaccount.GetName(name))
   136  	deployment.SetAffinity(o.GetAffinity(instance))
   137  
   138  	peerContainer.AppendEnvIfMissing("CORE_PEER_ID", instance.Name)
   139  	peerContainer.AppendEnvIfMissing("CORE_PEER_LOCALMSPID", mspID)
   140  
   141  	claimName := instance.Name + "-statedb-pvc"
   142  	if instance.Spec.CustomNames.PVC.StateDB != "" {
   143  		claimName = instance.Spec.CustomNames.PVC.StateDB
   144  	}
   145  	deployment.AppendPVCVolumeIfMissing("db-data", claimName)
   146  
   147  	peerContainer.AppendEnvIfMissing("CORE_LEDGER_STATE_STATEDATABASE", stateDB)
   148  
   149  	claimName = instance.Name + "-pvc"
   150  	if instance.Spec.CustomNames.PVC.Peer != "" {
   151  		claimName = instance.Spec.CustomNames.PVC.Peer
   152  	}
   153  	deployment.AppendPVCVolumeIfMissing("fabric-peer-0", claimName)
   154  
   155  	deployment.AppendConfigMapVolumeIfMissing("fluentd-config", instance.Name+"-fluentd")
   156  
   157  	ecertintercertSecret := fmt.Sprintf("ecert-%s-intercerts", instance.Name)
   158  	tlsintercertSecret := fmt.Sprintf("tls-%s-intercerts", instance.Name)
   159  	secretName := fmt.Sprintf("tls-%s-cacerts", instance.Name)
   160  	// Check if intermediate ecerts exists
   161  	if util.IntermediateSecretExists(o.Client, instance.Namespace, ecertintercertSecret) {
   162  		peerContainer.AppendVolumeMountIfMissing("ecert-intercerts", "/certs/msp/intermediatecerts")
   163  		deployment.AppendSecretVolumeIfMissing("ecert-intercerts", ecertintercertSecret)
   164  	}
   165  
   166  	// Check if intermediate tlscerts exists
   167  	if util.IntermediateSecretExists(o.Client, instance.Namespace, tlsintercertSecret) {
   168  		peerContainer.AppendVolumeMountIfMissing("tls-intercerts", "/certs/msp/tlsintermediatecerts")
   169  		deployment.AppendSecretVolumeIfMissing("tls-intercerts", tlsintercertSecret)
   170  	}
   171  
   172  	tlsCACertsSecret, err := o.GetTLSCACertsSecret(instance, secretName)
   173  	if err != nil {
   174  		return err
   175  	}
   176  
   177  	var certsData string
   178  	count := 0
   179  	for key, _ := range tlsCACertsSecret.Data {
   180  		v := fmt.Sprintf("/certs/msp/tlscacerts/%s", key)
   181  		if count == 0 {
   182  			certsData = certsData + v
   183  		} else {
   184  			certsData = certsData + " " + v
   185  		}
   186  		count++
   187  	}
   188  	peerContainer.AppendEnvIfMissingOverrideIfPresent("CORE_OPERATIONS_TLS_CLIENTROOTCAS_FILES", certsData)
   189  	peerContainer.AppendEnvIfMissingOverrideIfPresent("CORE_PEER_TLS_ROOTCERT_FILE", certsData)
   190  	grpcwebContainer.AppendEnvIfMissingOverrideIfPresent("SERVER_TLS_CLIENT_CA_FILES", certsData)
   191  	peerContainer.AppendEnvIfMissingOverrideIfPresent("CORE_PEER_TLS_ROOTCERT_FILE", certsData)
   192  
   193  	// Check if intermediate tlscerts exists
   194  	if util.IntermediateSecretExists(o.Client, instance.Namespace, tlsintercertSecret) {
   195  		secretName := fmt.Sprintf("tls-%s-intercerts", instance.Name)
   196  		tlsCAInterCertsSecret, err := o.GetTLSCACertsSecret(instance, secretName)
   197  		if err != nil {
   198  			return err
   199  		}
   200  
   201  		var certsData string
   202  		count := 0
   203  		for key, _ := range tlsCAInterCertsSecret.Data {
   204  			v := fmt.Sprintf("/certs/msp/tlsintermediatecerts/%s", key)
   205  			if count == 0 {
   206  				certsData = certsData + v
   207  			} else {
   208  				certsData = certsData + " " + v
   209  			}
   210  			count++
   211  		}
   212  		peerContainer.AppendEnvIfMissingOverrideIfPresent("CORE_PEER_TLS_ROOTCERT_FILE", certsData)
   213  	}
   214  
   215  	if o.AdminSecretExists(instance) {
   216  		deployment.AppendSecretVolumeIfMissing("ecert-admincerts", fmt.Sprintf("ecert-%s-admincerts", instance.Name))
   217  		peerContainer.AppendVolumeMountIfMissing("ecert-admincerts", "/certs/msp/admincerts")
   218  	}
   219  
   220  	co, err := instance.GetConfigOverride()
   221  	if err != nil {
   222  		return errors.Wrap(err, "failed to get configoverride")
   223  	}
   224  
   225  	configOverride := co.(CoreConfig)
   226  	if !configOverride.UsingPKCS11() {
   227  		deployment.AppendSecretVolumeIfMissing("ecert-keystore", fmt.Sprintf("ecert-%s-keystore", instance.Name))
   228  		peerContainer.AppendVolumeMountIfMissing("ecert-keystore", "/certs/msp/keystore")
   229  	}
   230  
   231  	deployment.AppendSecretVolumeIfMissing("ecert-cacerts", fmt.Sprintf("ecert-%s-cacerts", instance.Name))
   232  	deployment.AppendSecretVolumeIfMissing("ecert-signcert", fmt.Sprintf("ecert-%s-signcert", instance.Name))
   233  	deployment.AppendSecretVolumeIfMissing("tls-cacerts", fmt.Sprintf("tls-%s-cacerts", instance.Name))
   234  	deployment.AppendSecretVolumeIfMissing("tls-keystore", fmt.Sprintf("tls-%s-keystore", instance.Name))
   235  	deployment.AppendSecretVolumeIfMissing("tls-signcert", fmt.Sprintf("tls-%s-signcert", instance.Name))
   236  
   237  	if o.OrdererCACertsSecretExists(instance) {
   238  		deployment.AppendSecretVolumeIfMissing("orderercacerts", fmt.Sprintf("%s-orderercacerts", instance.Name))
   239  		peerContainer.AppendVolumeMountIfMissing("orderercacerts", "/orderer/certs")
   240  	}
   241  
   242  	deployment.AppendConfigMapVolumeIfMissing("peer-config", instance.Name+"-config")
   243  
   244  	secret := &corev1.Secret{}
   245  	err = o.Client.Get(
   246  		context.TODO(),
   247  		types.NamespacedName{Name: instance.GetName() + "-secret", Namespace: instance.GetNamespace()},
   248  		secret,
   249  	)
   250  	if err == nil {
   251  		peerContainer.AppendEnvIfMissing("RESTART_OLD_RESOURCEVER", secret.ObjectMeta.ResourceVersion)
   252  	}
   253  
   254  	deployment.UpdateContainer(grpcwebContainer)
   255  
   256  	if instance.UsingHSMProxy() {
   257  		peerContainer.AppendEnvIfMissing("PKCS11_PROXY_SOCKET", instance.Spec.HSM.PKCS11Endpoint)
   258  	} else if instance.IsHSMEnabled() {
   259  		deployment.AppendVolumeIfMissing(corev1.Volume{
   260  			Name: "shared",
   261  			VolumeSource: corev1.VolumeSource{
   262  				EmptyDir: &corev1.EmptyDirVolumeSource{
   263  					Medium: corev1.StorageMediumMemory,
   264  				},
   265  			},
   266  		})
   267  
   268  		hsmConfig, err := config.ReadHSMConfig(o.Client, instance)
   269  		if err != nil {
   270  			return err
   271  		}
   272  
   273  		hsmSettings(instance, hsmConfig, peerContainer, deployment)
   274  
   275  		deployment.UpdateContainer(peerContainer)
   276  	}
   277  
   278  	if version.GetMajorReleaseVersion(instance.Spec.FabricVersion) == version.V2 {
   279  		err = o.V2Deployment(instance, deployment)
   280  		if err != nil {
   281  			return errors.Wrap(err, "failed during V2 peer deployment overrides")
   282  		}
   283  		peerVersion := version.String(instance.Spec.FabricVersion)
   284  		if peerVersion.EqualWithoutTag(version.V2_4_1) || peerVersion.GreaterThan(version.V2_4_1) {
   285  			err = o.V24Deployment(instance, deployment)
   286  			if err != nil {
   287  				return errors.Wrap(err, "failed during V24 peer deployment overrides")
   288  			}
   289  		}
   290  	} else {
   291  		err = o.V1Deployment(instance, deployment)
   292  		if err != nil {
   293  			return errors.Wrap(err, "failed during V1 peer deployment overrides")
   294  		}
   295  	}
   296  
   297  	return nil
   298  }
   299  
   300  func (o *Override) V1Deployment(instance *current.IBPPeer, deployment *dep.Deployment) error {
   301  	initContainer := deployment.MustGetContainer(INIT)
   302  
   303  	// NOTE: The container doesn't like when these bash commands are listed as separate strings in the command field
   304  	// which is why the command has been formatted into a single string.
   305  	//
   306  	// This command checks the permissions, owner, and group of /data/ and runs chmod/chown on required dirs if they
   307  	// have yet to be set to the default values (775, 1000, and 1000 respectively).
   308  	//
   309  	// cmdFormat is a format string that configured with the list of directories when used.
   310  	cmdFormat := "DEFAULT_PERM=775 && DEFAULT_USER=7051 && DEFAULT_GROUP=1000 "
   311  	cmdFormat += `&& PERM=$(stat -c "%%a" /data/) && USER=$(stat -c "%%u" /data/) && GROUP=$(stat -c "%%g" /data/) ` // %% is used to escape the percent symbol
   312  	cmdFormat += `&& if [ ${PERM} != ${DEFAULT_PERM} ] || [ ${USER} != ${DEFAULT_USER} ] || [ ${GROUP} != ${DEFAULT_GROUP} ]; `
   313  	cmdFormat += `then chmod -R ${DEFAULT_PERM} %[1]s && chown -R -H ${DEFAULT_USER}:${DEFAULT_GROUP} %[1]s; fi`
   314  
   315  	// NOTE: There are two chmod & chown calls for /data/ and /data/peer/... because
   316  	// those are two separate pvc mounts, so we were running the command for both the locations.
   317  	if instance.UsingCouchDB() {
   318  		directories := "/data/"
   319  		cmd := fmt.Sprintf(cmdFormat, directories)
   320  		initContainer.SetCommand([]string{
   321  			"bash",
   322  			"-c",
   323  			cmd,
   324  		})
   325  	} else {
   326  		directories := "/{data/,data/peer/ledgersData/stateLeveldb}"
   327  		cmd := fmt.Sprintf(cmdFormat, directories)
   328  		initContainer.SetCommand([]string{
   329  			"bash",
   330  			"-c",
   331  			cmd,
   332  		})
   333  	}
   334  
   335  	fluentdContainer, err := deployment.GetContainer(FLUENTD)
   336  	if err != nil {
   337  		return errors.New("fluentD container not found in deployment")
   338  	}
   339  
   340  	dindContainer, err := deployment.GetContainer(DIND)
   341  	if err != nil {
   342  		return errors.New("dind container not found in deployment")
   343  	}
   344  
   345  	dindargs := instance.Spec.DindArgs
   346  	if dindargs == nil {
   347  		dindargs = []string{"--log-driver", "fluentd", "--log-opt", "fluentd-address=localhost:9880", "--mtu", "1400"}
   348  	}
   349  	dindContainer.SetArgs(dindargs)
   350  
   351  	image := instance.Spec.Images
   352  	if image != nil {
   353  		dindContainer.SetImage(image.DindImage, image.DindTag)
   354  		fluentdContainer.SetImage(image.FluentdImage, image.FluentdTag)
   355  	}
   356  
   357  	resourcesRequest := instance.Spec.Resources
   358  	if resourcesRequest != nil {
   359  		if resourcesRequest.DinD != nil {
   360  			err = dindContainer.UpdateResources(resourcesRequest.DinD)
   361  			if err != nil {
   362  				return errors.Wrap(err, "resource update for dind failed")
   363  			}
   364  		}
   365  
   366  		if resourcesRequest.FluentD != nil {
   367  			err = fluentdContainer.UpdateResources(resourcesRequest.FluentD)
   368  			if err != nil {
   369  				return errors.Wrap(err, "resource update for fluentd failed")
   370  			}
   371  		}
   372  	}
   373  
   374  	peerContainer := deployment.MustGetContainer(PEER)
   375  	// env vars only required for 1.x peer
   376  	peerContainer.AppendEnvIfMissing("CORE_VM_ENDPOINT", "localhost:2375")
   377  	peerContainer.AppendEnvIfMissing("CORE_CHAINCODE_GOLANG_RUNTIME", "golangruntime:latest")
   378  	peerContainer.AppendEnvIfMissing("CORE_CHAINCODE_CAR_RUNTIME", "carruntime:latest")
   379  	peerContainer.AppendEnvIfMissing("CORE_CHAINCODE_JAVA_RUNTIME", "javaruntime:latest")
   380  	peerContainer.AppendEnvIfMissing("CORE_CHAINCODE_NODE_RUNTIME", "noderuntime:latest")
   381  	peerContainer.AppendEnvIfMissing("CORE_CHAINCODE_BUILDER", "builder:latest")
   382  	peerContainer.AppendEnvIfMissing("CORE_CHAINCODE_GOLANG_DYNAMICLINK", "true")
   383  	peerContainer.AppendEnvIfMissing("CORE_VM_DOCKER_ATTACHSTDOUT", "false")
   384  
   385  	deployment.UpdateInitContainer(initContainer)
   386  	deployment.UpdateContainer(fluentdContainer)
   387  	deployment.UpdateContainer(dindContainer)
   388  	deployment.UpdateContainer(peerContainer)
   389  	return nil
   390  }
   391  
   392  func (o *Override) V2Deployment(instance *current.IBPPeer, deployment *dep.Deployment) error {
   393  
   394  	initContainer := deployment.MustGetContainer(INIT)
   395  	peerContainer := deployment.MustGetContainer(PEER)
   396  
   397  	// NOTE: The container doesn't like when these bash commands are listed as separate strings in the command field
   398  	// which is why the command has been formatted into a single string.
   399  	//
   400  	// This command checks the permissions, owner, and group of /data/ and runs chmod/chown on required dirs if they
   401  	// have yet to be set to the default values (775, 1000, and 1000 respectively).
   402  	//
   403  	// cmdFormat is a format string that configured with the list of directories when used.
   404  	cmdFormat := "DEFAULT_PERM=775 && DEFAULT_USER=7051 && DEFAULT_GROUP=1000 "
   405  	cmdFormat += `&& PERM=$(stat -c "%%a" /data/) && USER=$(stat -c "%%u" /data/) && GROUP=$(stat -c "%%g" /data/) ` // %% is used to escape the percent symbol
   406  	cmdFormat += `&& if [ ${PERM} != ${DEFAULT_PERM} ] || [ ${USER} != ${DEFAULT_USER} ] || [ ${GROUP} != ${DEFAULT_GROUP} ]; `
   407  	cmdFormat += `then chmod -R ${DEFAULT_PERM} %[1]s && chown -R -H ${DEFAULT_USER}:${DEFAULT_GROUP} %[1]s; fi`
   408  
   409  	// NOTE: There are multiple chmod & chown calls for /data/ and /data/peer/... and /cclauncher because
   410  	// those are separate pvc mounts, so we were running the command for all the locations
   411  	dirs := []string{"data/"}
   412  	if !instance.UsingCouchDB() {
   413  		dirs = append(dirs, "data/peer/ledgersData/stateLeveldb")
   414  	}
   415  	if instance.UsingCCLauncherImage() {
   416  		dirs = append(dirs, "cclauncher/")
   417  	}
   418  
   419  	var directories string
   420  	if len(dirs) > 1 {
   421  		directories = fmt.Sprintf("/{%s}", strings.Join(dirs, ","))
   422  	} else {
   423  		directories = "/data/"
   424  	}
   425  
   426  	initContainer.SetCommand([]string{
   427  		"bash",
   428  		"-c",
   429  		fmt.Sprintf(cmdFormat, directories),
   430  	})
   431  
   432  	if instance.UsingCCLauncherImage() {
   433  		err := o.CreateCCLauncherContainer(instance, deployment)
   434  		if err != nil {
   435  			return errors.Wrap(err, "failed to create chaincode launcher container")
   436  		}
   437  
   438  		volumeMountName := fmt.Sprintf("%s-cclauncher", instance.GetName())
   439  		initContainer.AppendVolumeMountIfMissing(volumeMountName, "/cclauncher")
   440  		peerContainer.AppendVolumeMountIfMissing(volumeMountName, "/cclauncher")
   441  
   442  		peerContainer.AppendEnvIfMissing("IBP_BUILDER_SHARED_DIR", "/cclauncher")
   443  		peerContainer.AppendEnvIfMissing("IBP_BUILDER_ENDPOINT", "127.0.0.1:11111")
   444  		peerContainer.AppendEnvIfMissing("PEER_NAME", instance.GetName())
   445  
   446  		// Will delete these envs if found, these are not required for v2
   447  		peerContainer.DeleteEnv("CORE_VM_ENDPOINT")
   448  		peerContainer.DeleteEnv("CORE_CHAINCODE_GOLANG_RUNTIME")
   449  		peerContainer.DeleteEnv("CORE_CHAINCODE_CAR_RUNTIME")
   450  		peerContainer.DeleteEnv("CORE_CHAINCODE_JAVA_RUNTIME")
   451  		peerContainer.DeleteEnv("CORE_CHAINCODE_NODE_RUNTIME")
   452  		peerContainer.DeleteEnv("CORE_CHAINCODE_BUILDER")
   453  		peerContainer.DeleteEnv("CORE_CHAINCODE_GOLANG_DYNAMICLINK")
   454  		peerContainer.DeleteEnv("CORE_VM_DOCKER_ATTACHSTDOUT")
   455  
   456  		deployment.AppendEmptyDirVolumeIfMissing(fmt.Sprintf("%s-cclauncher", instance.Name), corev1.StorageMediumMemory)
   457  	}
   458  
   459  	// Append a k/v JSON substitution map to the peer env.
   460  	if instance.Spec.ChaincodeBuilderConfig != nil {
   461  		configJSON, err := json.Marshal(instance.Spec.ChaincodeBuilderConfig)
   462  		if err != nil {
   463  			return errors.Wrapf(err, "failed to marshal chaincode builder config '%s',", instance.Spec.ChaincodeBuilderConfig)
   464  		}
   465  		peerContainer.AppendEnvIfMissing("CHAINCODE_AS_A_SERVICE_BUILDER_CONFIG", string(configJSON))
   466  	}
   467  
   468  	deployment.UpdateInitContainer(initContainer)
   469  	deployment.UpdateContainer(peerContainer)
   470  	deployment.RemoveContainer(FLUENTD)
   471  	deployment.RemoveContainer(DIND)
   472  	return nil
   473  }
   474  
   475  func (o *Override) V24Deployment(instance *current.IBPPeer, deployment *dep.Deployment) error {
   476  	if instance.UsingCCLauncherImage() {
   477  		launcherContainer := deployment.MustGetContainer(CCLAUNCHER)
   478  
   479  		launcherContainer.LivenessProbe.HTTPGet.Scheme = corev1.URISchemeHTTPS
   480  		launcherContainer.ReadinessProbe.HTTPGet.Scheme = corev1.URISchemeHTTPS
   481  		deployment.UpdateContainer(launcherContainer)
   482  	}
   483  	return nil
   484  }
   485  
   486  func (o *Override) V2DeploymentUpdate(instance *current.IBPPeer, deployment *dep.Deployment) error {
   487  	peerContainer, err := deployment.GetContainer(PEER)
   488  	if err != nil {
   489  		return err
   490  	}
   491  	peerContainer.AppendEnvIfMissing("PEER_NAME", instance.GetName())
   492  
   493  	// For V2Deployments using chaincode-as-a-service and external builders, there is no need to include
   494  	// or modify the chaincode launcher sidecar.
   495  	if !instance.UsingCCLauncherImage() {
   496  		if err := o.V2Deployment(instance, deployment); err != nil {
   497  			return err
   498  		}
   499  		return nil
   500  	}
   501  
   502  	// V2DeploymentUpdate will be triggered when migrating from v1 to v2 peer, during this update we might
   503  	// have to run initialization logic for a v2 fabric deployment. If the chaincode launcher container is
   504  	// not found, we try to initialize the deployment based on v2 deployment to add chaincode launcher
   505  	// before continuing with the remaining update logic. Not ideal, but until a bigger refactor is performed
   506  	// this is the least intrusive way to handle this.
   507  	ccLauncherContainer, err := deployment.GetContainer(CCLAUNCHER)
   508  	if err != nil {
   509  		if err := o.V2Deployment(instance, deployment); err != nil {
   510  			return err
   511  		}
   512  		return nil
   513  	}
   514  
   515  	ccLauncherContainer = deployment.MustGetContainer(CCLAUNCHER)
   516  	images := instance.Spec.Images
   517  	if images != nil {
   518  		if images.CCLauncherImage != "" && images.CCLauncherTag != "" {
   519  			ccLauncherContainer.SetImage(images.CCLauncherImage, images.CCLauncherTag)
   520  		}
   521  
   522  		ccLauncherContainer.AppendEnvIfMissingOverrideIfPresent(
   523  			"FILETRANSFERIMAGE", image.Format(instance.Spec.Images.PeerInitImage, instance.Spec.Images.PeerInitTag),
   524  		)
   525  		ccLauncherContainer.AppendEnvIfMissingOverrideIfPresent(
   526  			"BUILDERIMAGE", image.Format(instance.Spec.Images.BuilderImage, instance.Spec.Images.BuilderTag),
   527  		)
   528  		ccLauncherContainer.AppendEnvIfMissingOverrideIfPresent(
   529  			"GOENVIMAGE", image.Format(instance.Spec.Images.GoEnvImage, instance.Spec.Images.GoEnvTag),
   530  		)
   531  		ccLauncherContainer.AppendEnvIfMissingOverrideIfPresent(
   532  			"JAVAENVIMAGE", image.Format(instance.Spec.Images.JavaEnvImage, instance.Spec.Images.JavaEnvTag),
   533  		)
   534  		ccLauncherContainer.AppendEnvIfMissingOverrideIfPresent(
   535  			"NODEENVIMAGE", image.Format(instance.Spec.Images.NodeEnvImage, instance.Spec.Images.NodeEnvTag),
   536  		)
   537  		ccLauncherContainer.AppendEnvIfMissing("CORE_PEER_LOCALMSPID", instance.Spec.MSPID)
   538  	}
   539  
   540  	resourcesRequest := instance.Spec.Resources
   541  	if resourcesRequest != nil {
   542  		if resourcesRequest.CCLauncher != nil {
   543  			err := ccLauncherContainer.UpdateResources(resourcesRequest.CCLauncher)
   544  			if err != nil {
   545  				return errors.Wrap(err, "resource update for cclauncher failed")
   546  			}
   547  		}
   548  	}
   549  
   550  	return nil
   551  }
   552  
   553  func (o *Override) V24DeploymentUpdate(instance *current.IBPPeer, deployment *dep.Deployment) error {
   554  	if instance.UsingCCLauncherImage() {
   555  		ccLauncherContainer, err := deployment.GetContainer(CCLAUNCHER)
   556  		if err != nil {
   557  			return err
   558  		}
   559  		ccLauncherContainer.LivenessProbe.HTTPGet.Scheme = corev1.URISchemeHTTPS
   560  		ccLauncherContainer.ReadinessProbe.HTTPGet.Scheme = corev1.URISchemeHTTPS
   561  
   562  		deployment.UpdateContainer(ccLauncherContainer)
   563  	}
   564  	return nil
   565  }
   566  
   567  func (o *Override) CreateCCLauncherContainer(instance *current.IBPPeer, deployment *dep.Deployment) error {
   568  	ccLauncherContainer, err := container.LoadFromFile(o.DefaultCCLauncherFile)
   569  	if err != nil {
   570  		return errors.Wrap(err, "failed to read default chaincode launcher container file")
   571  	}
   572  
   573  	images := instance.Spec.Images
   574  	if images == nil || images.CCLauncherImage == "" {
   575  		return errors.New("no image specified for chaincode launcher")
   576  	}
   577  
   578  	ccLauncherContainer.SetImage(images.CCLauncherImage, images.CCLauncherTag)
   579  	ccLauncherContainer.AppendEnvIfMissing("KUBE_NAMESPACE", instance.GetNamespace())
   580  	ccLauncherContainer.AppendEnvIfMissing("SHARED_VOLUME_PATH", "/cclauncher")
   581  	ccLauncherContainer.AppendEnvIfMissing("IMAGEPULLSECRETS", strings.Join(instance.Spec.ImagePullSecrets, " "))
   582  	ccLauncherContainer.AppendEnvIfMissing("CORE_PEER_LOCALMSPID", instance.Spec.MSPID)
   583  
   584  	valueFrom := &corev1.EnvVarSource{
   585  		FieldRef: &corev1.ObjectFieldSelector{
   586  			FieldPath: "metadata.name",
   587  		},
   588  	}
   589  	ccLauncherContainer.AppendEnvVarValueFromIfMissing("PEER_POD_NAME", valueFrom)
   590  
   591  	valueFrom = &corev1.EnvVarSource{
   592  		FieldRef: &corev1.ObjectFieldSelector{
   593  			FieldPath: "metadata.uid",
   594  		},
   595  	}
   596  	ccLauncherContainer.AppendEnvVarValueFromIfMissing("PEER_POD_UID", valueFrom)
   597  
   598  	ccLauncherContainer.AppendEnvIfMissingOverrideIfPresent("FILETRANSFERIMAGE", image.Format(instance.Spec.Images.PeerInitImage, instance.Spec.Images.PeerInitTag))
   599  	ccLauncherContainer.AppendEnvIfMissingOverrideIfPresent("BUILDERIMAGE", image.Format(instance.Spec.Images.BuilderImage, instance.Spec.Images.BuilderTag))
   600  	ccLauncherContainer.AppendEnvIfMissingOverrideIfPresent("GOENVIMAGE", image.Format(instance.Spec.Images.GoEnvImage, instance.Spec.Images.GoEnvTag))
   601  	ccLauncherContainer.AppendEnvIfMissingOverrideIfPresent("JAVAENVIMAGE", image.Format(instance.Spec.Images.JavaEnvImage, instance.Spec.Images.JavaEnvTag))
   602  	ccLauncherContainer.AppendEnvIfMissingOverrideIfPresent("NODEENVIMAGE", image.Format(instance.Spec.Images.NodeEnvImage, instance.Spec.Images.NodeEnvTag))
   603  	ccLauncherContainer.AppendEnvIfMissingOverrideIfPresent("PEER_ID", instance.GetName())
   604  	ccLauncherContainer.AppendVolumeMountIfMissing(fmt.Sprintf("%s-cclauncher", instance.Name), "/cclauncher")
   605  
   606  	resourcesRequest := instance.Spec.Resources
   607  	if resourcesRequest != nil {
   608  		if resourcesRequest.CCLauncher != nil {
   609  			err = ccLauncherContainer.UpdateResources(resourcesRequest.CCLauncher)
   610  			if err != nil {
   611  				return errors.Wrap(err, "resource update for cclauncher failed")
   612  			}
   613  		}
   614  	}
   615  
   616  	deployment.AddContainer(*ccLauncherContainer)
   617  	return nil
   618  }
   619  
   620  func (o *Override) UpdateDeployment(instance *current.IBPPeer, k8sDep *appsv1.Deployment) error {
   621  	deployment := dep.New(k8sDep)
   622  	err := o.CommonDeploymentOverrides(instance, deployment)
   623  	if err != nil {
   624  		return err
   625  	}
   626  
   627  	switch version.GetMajorReleaseVersion(instance.Spec.FabricVersion) {
   628  	case version.V1:
   629  		err = o.V1Deployment(instance, deployment)
   630  		if err != nil {
   631  			return errors.Wrap(err, "failed during V1 peer deployment overrides")
   632  		}
   633  	case version.V2:
   634  		err := o.V2DeploymentUpdate(instance, deployment)
   635  		if err != nil {
   636  			return errors.Wrapf(err, "failed to update V2 fabric deployment for instance '%s'", instance.GetName())
   637  		}
   638  		peerVersion := version.String(instance.Spec.FabricVersion)
   639  		if peerVersion.EqualWithoutTag(version.V2_4_1) || peerVersion.GreaterThan(version.V2_4_1) {
   640  			err := o.V24DeploymentUpdate(instance, deployment)
   641  			if err != nil {
   642  				return errors.Wrapf(err, "failed to update V24 fabric deployment for instance '%s'", instance.GetName())
   643  			}
   644  		}
   645  	}
   646  
   647  	if instance.UsingCouchDB() {
   648  		couchdb := deployment.MustGetContainer(COUCHDB)
   649  
   650  		image := instance.Spec.Images
   651  		if image != nil {
   652  			couchdb.SetImage(image.CouchDBImage, image.CouchDBTag)
   653  		}
   654  
   655  		couchdb.AppendEnvIfMissing("SKIP_PERMISSIONS_UPDATE", "true")
   656  	}
   657  
   658  	if instance.UsingHSMProxy() {
   659  		peerContainer := deployment.MustGetContainer(PEER)
   660  		peerContainer.UpdateEnv("PKCS11_PROXY_SOCKET", instance.Spec.HSM.PKCS11Endpoint)
   661  		deployment.UpdateContainer(peerContainer)
   662  	} else if instance.IsHSMEnabled() {
   663  		hsmInitCont := deployment.MustGetContainer(HSMCLIENT)
   664  		image := instance.Spec.Images
   665  		if image != nil {
   666  			hsmInitCont.SetImage(image.HSMImage, image.HSMTag)
   667  		}
   668  	}
   669  
   670  	return nil
   671  }
   672  
   673  func (o *Override) CommonDeploymentOverrides(instance *current.IBPPeer, deployment *dep.Deployment) error {
   674  	initContainer := deployment.MustGetContainer(INIT)
   675  	peerContainer := deployment.MustGetContainer(PEER)
   676  	grpcContainer, err := deployment.GetContainer(PROXY)
   677  	if err != nil {
   678  		return errors.New("proxy container not found in deployment spec")
   679  	}
   680  
   681  	image := instance.Spec.Images
   682  	if image != nil {
   683  		initContainer.SetImage(image.PeerInitImage, image.PeerInitTag)
   684  		peerContainer.SetImage(image.PeerImage, image.PeerTag)
   685  		grpcContainer.SetImage(image.GRPCWebImage, image.GRPCWebTag)
   686  
   687  		if instance.UsingCouchDB() {
   688  			couchdb := deployment.MustGetContainer(COUCHDB)
   689  			couchdb.SetImage(image.CouchDBImage, image.CouchDBTag)
   690  
   691  			couchdbInitContainer := deployment.MustGetContainer(COUCHDBINIT)
   692  			couchdbInitContainer.SetImage(image.PeerInitImage, image.PeerInitTag)
   693  		}
   694  	}
   695  
   696  	resourcesRequest := instance.Spec.Resources
   697  	if resourcesRequest != nil {
   698  		if resourcesRequest.Peer != nil {
   699  			err = peerContainer.UpdateResources(resourcesRequest.Peer)
   700  			if err != nil {
   701  				return errors.Wrap(err, "resource update for peer failed")
   702  			}
   703  		}
   704  
   705  		if resourcesRequest.GRPCProxy != nil {
   706  			err = grpcContainer.UpdateResources(resourcesRequest.GRPCProxy)
   707  			if err != nil {
   708  				return errors.Wrap(err, "resource update for grpcproxy failed")
   709  			}
   710  		}
   711  
   712  		if instance.UsingCouchDB() {
   713  			couchdb := deployment.MustGetContainer(COUCHDB)
   714  			if resourcesRequest.CouchDB != nil {
   715  				err = couchdb.UpdateResources(resourcesRequest.CouchDB)
   716  				if err != nil {
   717  					return errors.Wrap(err, "resource update for couchdb failed")
   718  				}
   719  			}
   720  
   721  			couchdbinit := deployment.MustGetContainer(COUCHDBINIT)
   722  			if resourcesRequest.Init != nil {
   723  				err = couchdbinit.UpdateResources(resourcesRequest.Init)
   724  				if err != nil {
   725  					return errors.Wrap(err, "resource update for couchdb init failed")
   726  				}
   727  			}
   728  		}
   729  	}
   730  
   731  	externalAddress := instance.Spec.PeerExternalEndpoint
   732  	// Set external address to "do-not-set" in Peer CR spec to disable Service discovery
   733  	if externalAddress != "" && externalAddress != "do-not-set" {
   734  		peerContainer.AppendEnvIfMissing("CORE_PEER_GOSSIP_EXTERNALENDPOINT", externalAddress)
   735  		peerContainer.AppendEnvIfMissing("CORE_PEER_GOSSIP_ENDPOINT", externalAddress)
   736  		grpcContainer.AppendEnvIfMissing("EXTERNAL_ADDRESS", externalAddress)
   737  	}
   738  
   739  	if instance.Spec.Replicas != nil {
   740  		if *instance.Spec.Replicas > 1 {
   741  			return errors.New("replicas > 1 not allowed in IBPPeer")
   742  		}
   743  		deployment.SetReplicas(instance.Spec.Replicas)
   744  	}
   745  
   746  	deployment.UpdateContainer(peerContainer)
   747  	deployment.UpdateContainer(grpcContainer)
   748  	return nil
   749  }
   750  
   751  func (o *Override) CreateCouchDBContainers(instance *current.IBPPeer, deployment *dep.Deployment) error {
   752  	couchdbUser := o.CouchdbUser
   753  	if couchdbUser == "" {
   754  		couchdbUser = util.GenerateRandomString(32)
   755  	}
   756  
   757  	couchdbPassword := o.CouchdbPassword
   758  	if couchdbPassword == "" {
   759  		couchdbPassword = util.GenerateRandomString(32)
   760  	}
   761  
   762  	couchdbContainer, err := container.LoadFromFile(o.DefaultCouchContainerFile)
   763  	if err != nil {
   764  		return errors.Wrap(err, "failed to read default couch container file")
   765  	}
   766  
   767  	couchdbInitContainer, err := container.LoadFromFile(o.DefaultCouchInitContainerFile)
   768  	if err != nil {
   769  		return errors.Wrap(err, "failed to read default couch init container file")
   770  	}
   771  
   772  	image := instance.Spec.Images
   773  	if image != nil {
   774  		couchdbContainer.SetImage(image.CouchDBImage, image.CouchDBTag)
   775  		couchdbInitContainer.SetImage(image.PeerInitImage, image.PeerInitTag)
   776  	}
   777  
   778  	couchdbContainer.AppendEnvIfMissing("COUCHDB_USER", couchdbUser)
   779  	couchdbContainer.AppendEnvIfMissing("COUCHDB_PASSWORD", couchdbPassword)
   780  	couchdbContainer.AppendEnvIfMissing("SKIP_PERMISSIONS_UPDATE", "true")
   781  
   782  	peerContainer := deployment.MustGetContainer(PEER)
   783  	peerContainer.AppendEnvIfMissing("CORE_LEDGER_STATE_COUCHDBCONFIG_USERNAME", couchdbUser)
   784  	peerContainer.AppendEnvIfMissing("CORE_LEDGER_STATE_COUCHDBCONFIG_PASSWORD", couchdbPassword)
   785  	peerContainer.AppendEnvIfMissing("CORE_LEDGER_STATE_COUCHDBCONFIG_COUCHDBADDRESS", "localhost:5984")
   786  	peerContainer.AppendEnvIfMissing("CORE_LEDGER_STATE_COUCHDBCONFIG_MAXRETRIESONSTARTUP", "20")
   787  
   788  	deployment.AddContainer(*couchdbContainer)
   789  	deployment.AddInitContainer(*couchdbInitContainer)
   790  	deployment.UpdateContainer(peerContainer)
   791  
   792  	return nil
   793  }
   794  
   795  func (o *Override) GetAffinity(instance *current.IBPPeer) *corev1.Affinity {
   796  	arch := instance.Spec.Arch
   797  	zone := instance.Spec.Zone
   798  	region := instance.Spec.Region
   799  	nodeSelectorTerms := common.GetNodeSelectorTerms(arch, zone, region)
   800  
   801  	orgName := instance.Spec.MSPID
   802  	podAntiAffinity := common.GetPodAntiAffinity(orgName)
   803  
   804  	affinity := &corev1.Affinity{
   805  		PodAntiAffinity: podAntiAffinity,
   806  	}
   807  
   808  	if len(nodeSelectorTerms[0].MatchExpressions) != 0 {
   809  		affinity.NodeAffinity = &corev1.NodeAffinity{
   810  			RequiredDuringSchedulingIgnoredDuringExecution: &corev1.NodeSelector{
   811  				NodeSelectorTerms: nodeSelectorTerms,
   812  			},
   813  		}
   814  	}
   815  
   816  	return affinity
   817  }
   818  
   819  func (o *Override) AdminSecretExists(instance *current.IBPPeer) bool {
   820  	secret := &corev1.Secret{}
   821  	err := o.Client.Get(context.TODO(), types.NamespacedName{
   822  		Name:      fmt.Sprintf("ecert-%s-admincerts", instance.Name),
   823  		Namespace: instance.Namespace}, secret)
   824  	if err != nil {
   825  		return false
   826  	}
   827  
   828  	return true
   829  }
   830  
   831  func (o *Override) OrdererCACertsSecretExists(instance *current.IBPPeer) bool {
   832  	err := o.Client.Get(context.TODO(), types.NamespacedName{
   833  		Name:      fmt.Sprintf("%s-orderercacerts", instance.Name),
   834  		Namespace: instance.Namespace}, &corev1.Secret{})
   835  	if err != nil {
   836  		return false
   837  	}
   838  
   839  	return true
   840  }
   841  
   842  func (o *Override) GetTLSCACertsSecret(instance *current.IBPPeer, secretName string) (*corev1.Secret, error) {
   843  	secret := &corev1.Secret{}
   844  	err := o.Client.Get(context.TODO(), types.NamespacedName{
   845  		Name:      secretName,
   846  		Namespace: instance.Namespace}, secret)
   847  	if err != nil {
   848  	}
   849  
   850  	return secret, nil
   851  }
   852  
   853  func hsmInitContainer(instance *current.IBPPeer, hsmConfig *config.HSMConfig) *container.Container {
   854  	hsmLibraryPath := hsmConfig.Library.FilePath
   855  	hsmLibraryName := filepath.Base(hsmLibraryPath)
   856  
   857  	f := false
   858  	user := int64(0)
   859  	mountPath := "/shared"
   860  	return &container.Container{
   861  		Container: &corev1.Container{
   862  			Name:            "hsm-client",
   863  			Image:           fmt.Sprintf("%s:%s", instance.Spec.Images.HSMImage, instance.Spec.Images.HSMTag),
   864  			ImagePullPolicy: corev1.PullAlways,
   865  			Command: []string{
   866  				"sh",
   867  				"-c",
   868  				fmt.Sprintf("mkdir -p %s/hsm && dst=\"%s/hsm/%s\" && echo \"Copying %s to ${dst}\" && mkdir -p $(dirname $dst) && cp -r %s $dst", mountPath, mountPath, hsmLibraryName, hsmLibraryPath, hsmLibraryPath),
   869  			},
   870  			SecurityContext: &corev1.SecurityContext{
   871  				RunAsUser:    &user,
   872  				RunAsNonRoot: &f,
   873  			},
   874  			VolumeMounts: []corev1.VolumeMount{
   875  				corev1.VolumeMount{
   876  					Name:      "shared",
   877  					MountPath: mountPath,
   878  				},
   879  			},
   880  			Resources: corev1.ResourceRequirements{
   881  				Requests: corev1.ResourceList{
   882  					corev1.ResourceCPU:    resource.MustParse("0.1"),
   883  					corev1.ResourceMemory: resource.MustParse("100Mi"),
   884  				},
   885  				Limits: corev1.ResourceList{
   886  					corev1.ResourceCPU:    resource.MustParse("2"),
   887  					corev1.ResourceMemory: resource.MustParse("4Gi"),
   888  				},
   889  			},
   890  		},
   891  	}
   892  }
   893  
   894  func hsmSettings(instance *current.IBPPeer, hsmConfig *config.HSMConfig, peerCont container.Container, deployment *deployment.Deployment) {
   895  	for _, v := range hsmConfig.GetVolumes() {
   896  		deployment.AppendVolumeIfMissing(v)
   897  	}
   898  
   899  	for _, vm := range hsmConfig.GetVolumeMounts() {
   900  		peerCont.AppendVolumeMountStructIfMissing(vm)
   901  	}
   902  
   903  	for _, env := range hsmConfig.GetEnvs() {
   904  		peerCont.AppendEnvStructIfMissing(env)
   905  	}
   906  
   907  	peerCont.AppendVolumeMountWithSubPathIfMissing("shared", "/hsm/lib", "hsm")
   908  
   909  	if hsmConfig.Library.Auth != nil {
   910  		deployment.Spec.Template.Spec.ImagePullSecrets = util.AppendPullSecretIfMissing(
   911  			deployment.Spec.Template.Spec.ImagePullSecrets,
   912  			hsmConfig.Library.Auth.ImagePullSecret,
   913  		)
   914  	}
   915  
   916  	deployment.AddInitContainer(*hsmInitContainer(instance, hsmConfig))
   917  
   918  	// If daemon settings are configured in HSM config, create a sidecar that is running the daemon image
   919  	if hsmConfig.Daemon != nil {
   920  		hsmDaemonSettings(instance, hsmConfig, peerCont, deployment)
   921  	}
   922  }
   923  
   924  func hsmDaemonSettings(instance *current.IBPPeer, hsmConfig *config.HSMConfig, peerCont container.Container, deployment *deployment.Deployment) {
   925  	// Unable to launch daemon if not running priviledged moe
   926  	t := true
   927  	peerCont.SecurityContext.Privileged = &t
   928  	peerCont.SecurityContext.AllowPrivilegeEscalation = &t
   929  
   930  	// Update command in deployment to ensure that deamon is running before starting the ca
   931  	peerCont.Command = []string{
   932  		"sh",
   933  		"-c",
   934  		fmt.Sprintf("%s && %s", config.DAEMON_CHECK_CMD, "peer node start"),
   935  	}
   936  
   937  	// This is the shared volume where the file 'pkcsslotd-luanched' is touched to let
   938  	// other containers know that the daemon has successfully launched.
   939  	peerCont.AppendVolumeMountIfMissing("shared", "/shared")
   940  
   941  	pvcVolumeName := "fabric-peer-0"
   942  	// Certain token information requires to be stored in persistent store, the administrator
   943  	// responsible for configuring HSM sets the HSM config to point to the path where the PVC
   944  	// needs to be mounted.
   945  	var pvcMount *corev1.VolumeMount
   946  	for _, vm := range hsmConfig.MountPaths {
   947  		if vm.UsePVC {
   948  			pvcMount = &corev1.VolumeMount{
   949  				Name:      pvcVolumeName,
   950  				MountPath: vm.MountPath,
   951  			}
   952  		}
   953  	}
   954  
   955  	// If a pull secret is required to pull daemon image, update the deployment's image pull secrets
   956  	if hsmConfig.Daemon.Auth != nil {
   957  		deployment.Spec.Template.Spec.ImagePullSecrets = util.AppendPullSecretIfMissing(
   958  			deployment.Spec.Template.Spec.ImagePullSecrets,
   959  			hsmConfig.Daemon.Auth.ImagePullSecret,
   960  		)
   961  	}
   962  
   963  	// Add daemon container to the deployment
   964  	config.AddDaemonContainer(hsmConfig, deployment, instance.GetResource(current.HSMDAEMON), pvcMount)
   965  
   966  	// If a pvc mount has been configured in HSM config, set the volume mount on the ca container
   967  	// and PVC volume to deployment if missing
   968  	if pvcMount != nil {
   969  		peerCont.AppendVolumeMountStructIfMissing(*pvcMount)
   970  		deployment.AppendPVCVolumeIfMissing(pvcVolumeName, instance.PVCName())
   971  	}
   972  }