github.com/IBM-Blockchain/fabric-operator@v1.0.4/pkg/offering/base/console/console.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 baseconsole
    20  
    21  import (
    22  	"context"
    23  	"fmt"
    24  	"os"
    25  	"strings"
    26  
    27  	current "github.com/IBM-Blockchain/fabric-operator/api/v1beta1"
    28  	config "github.com/IBM-Blockchain/fabric-operator/operatorconfig"
    29  	k8sclient "github.com/IBM-Blockchain/fabric-operator/pkg/k8s/controllerclient"
    30  	"github.com/IBM-Blockchain/fabric-operator/pkg/manager/resources"
    31  	resourcemanager "github.com/IBM-Blockchain/fabric-operator/pkg/manager/resources/manager"
    32  	"github.com/IBM-Blockchain/fabric-operator/pkg/offering/common"
    33  	"github.com/IBM-Blockchain/fabric-operator/pkg/restart"
    34  	"github.com/IBM-Blockchain/fabric-operator/pkg/util"
    35  	"github.com/IBM-Blockchain/fabric-operator/version"
    36  	"github.com/pkg/errors"
    37  	appsv1 "k8s.io/api/apps/v1"
    38  	corev1 "k8s.io/api/core/v1"
    39  	v1 "k8s.io/apimachinery/pkg/apis/meta/v1"
    40  	"k8s.io/apimachinery/pkg/runtime"
    41  	"k8s.io/apimachinery/pkg/types"
    42  	"sigs.k8s.io/controller-runtime/pkg/client"
    43  	k8sruntime "sigs.k8s.io/controller-runtime/pkg/client"
    44  	logf "sigs.k8s.io/controller-runtime/pkg/log"
    45  	"sigs.k8s.io/controller-runtime/pkg/reconcile"
    46  )
    47  
    48  var log = logf.Log.WithName("base_console")
    49  
    50  type Override interface {
    51  	Deployment(v1.Object, *appsv1.Deployment, resources.Action) error
    52  	Service(v1.Object, *corev1.Service, resources.Action) error
    53  	DeployerService(v1.Object, *corev1.Service, resources.Action) error
    54  	ServiceAccount(v1.Object, *corev1.ServiceAccount, resources.Action) error
    55  	PVC(v1.Object, *corev1.PersistentVolumeClaim, resources.Action) error
    56  	CM(v1.Object, *corev1.ConfigMap, resources.Action, map[string]interface{}) error
    57  	ConsoleCM(v1.Object, *corev1.ConfigMap, resources.Action, map[string]interface{}) error
    58  	DeployerCM(v1.Object, *corev1.ConfigMap, resources.Action, map[string]interface{}) error
    59  }
    60  
    61  //go:generate counterfeiter -o mocks/update.go -fake-name Update . Update
    62  
    63  type Update interface {
    64  	SpecUpdated() bool
    65  	DeployerCMUpdated() bool
    66  	ConsoleCMUpdated() bool
    67  	EnvCMUpdated() bool
    68  	RestartNeeded() bool
    69  }
    70  
    71  //go:generate counterfeiter -o mocks/restart_manager.go -fake-name RestartManager . RestartManager
    72  
    73  type RestartManager interface {
    74  	ForConfigMapUpdate(instance v1.Object) error
    75  	TriggerIfNeeded(instance restart.Instance) error
    76  	ForRestartAction(instance v1.Object) error
    77  }
    78  
    79  type IBPConsole interface {
    80  	PreReconcileChecks(instance *current.IBPConsole) (bool, error)
    81  	CheckStates(instance *current.IBPConsole, update bool) error
    82  	ReconcileManagers(instance *current.IBPConsole, update bool) error
    83  	Reconcile(instance *current.IBPConsole, update Update) (common.Result, error)
    84  }
    85  
    86  var _ IBPConsole = &Console{}
    87  
    88  type Console struct {
    89  	Client k8sclient.Client
    90  	Scheme *runtime.Scheme
    91  	Config *config.Config
    92  
    93  	DeploymentManager        resources.Manager
    94  	ServiceManager           resources.Manager
    95  	DeployerServiceManager   resources.Manager
    96  	PVCManager               resources.Manager
    97  	ConfigMapManager         resources.Manager
    98  	ConsoleConfigMapManager  resources.Manager
    99  	DeployerConfigMapManager resources.Manager
   100  	RoleManager              resources.Manager
   101  	RoleBindingManager       resources.Manager
   102  	ServiceAccountManager    resources.Manager
   103  
   104  	Override Override
   105  
   106  	Restart RestartManager
   107  }
   108  
   109  func New(client k8sclient.Client, scheme *runtime.Scheme, config *config.Config, o Override) *Console {
   110  	console := &Console{
   111  		Client:   client,
   112  		Scheme:   scheme,
   113  		Config:   config,
   114  		Override: o,
   115  		Restart:  restart.New(client, config.Operator.Restart.WaitTime.Get(), config.Operator.Restart.Timeout.Get()),
   116  	}
   117  
   118  	console.CreateManagers()
   119  	return console
   120  }
   121  
   122  func (c *Console) CreateManagers() {
   123  	options := map[string]interface{}{}
   124  
   125  	options["userid"] = util.GenerateRandomString(10)
   126  	options["password"] = util.GenerateRandomString(10)
   127  
   128  	consoleConfig := c.Config.ConsoleInitConfig
   129  
   130  	override := c.Override
   131  	resourceManager := resourcemanager.New(c.Client, c.Scheme)
   132  	c.DeploymentManager = resourceManager.CreateDeploymentManager("", override.Deployment, c.GetLabels, consoleConfig.DeploymentFile)
   133  	c.ServiceManager = resourceManager.CreateServiceManager("", override.Service, c.GetLabels, consoleConfig.ServiceFile)
   134  	c.DeployerServiceManager = resourceManager.CreateServiceManager("", override.Service, c.GetLabels, consoleConfig.DeployerServiceFile)
   135  	c.PVCManager = resourceManager.CreatePVCManager("", override.PVC, c.GetLabels, consoleConfig.PVCFile)
   136  	c.ConfigMapManager = resourceManager.CreateConfigMapManager("", override.CM, c.GetLabels, consoleConfig.CMFile, nil)
   137  	c.ConsoleConfigMapManager = resourceManager.CreateConfigMapManager("console", override.ConsoleCM, c.GetLabels, consoleConfig.ConsoleCMFile, options)
   138  	c.DeployerConfigMapManager = resourceManager.CreateConfigMapManager("deployer", override.DeployerCM, c.GetLabels, consoleConfig.DeployerCMFile, options)
   139  	c.RoleManager = resourceManager.CreateRoleManager("", nil, c.GetLabels, consoleConfig.RoleFile)
   140  	c.RoleBindingManager = resourceManager.CreateRoleBindingManager("", nil, c.GetLabels, consoleConfig.RoleBindingFile)
   141  	c.ServiceAccountManager = resourceManager.CreateServiceAccountManager("", nil, c.GetLabels, consoleConfig.ServiceAccountFile)
   142  }
   143  
   144  func (c *Console) PreReconcileChecks(instance *current.IBPConsole) (bool, error) {
   145  	var maxNameLength *int
   146  	if instance.Spec.ConfigOverride != nil {
   147  		maxNameLength = instance.Spec.ConfigOverride.MaxNameLength
   148  	}
   149  	err := util.ValidationChecks(instance.TypeMeta, instance.ObjectMeta, "IBPConsole", maxNameLength)
   150  	if err != nil {
   151  		return false, err
   152  	}
   153  
   154  	// check if all required values are passed
   155  	err = c.ValidateSpec(instance)
   156  	if err != nil {
   157  		return false, err
   158  	}
   159  
   160  	zoneUpdated, err := c.SelectZone(instance)
   161  	if err != nil {
   162  		return false, err
   163  	}
   164  
   165  	regionUpdated, err := c.SelectRegion(instance)
   166  	if err != nil {
   167  		return false, err
   168  	}
   169  
   170  	passwordUpdated, err := c.CreatePasswordSecretIfRequired(instance)
   171  	if err != nil {
   172  		return false, err
   173  	}
   174  
   175  	kubeconfigUpdated, err := c.CreateKubernetesSecretIfRequired(instance)
   176  	if err != nil {
   177  		return false, err
   178  	}
   179  
   180  	connectionStringUpdated := c.CreateCouchdbCredentials(instance)
   181  
   182  	update := passwordUpdated || zoneUpdated || regionUpdated || kubeconfigUpdated || connectionStringUpdated
   183  
   184  	if update {
   185  		log.Info(fmt.Sprintf("passwordUpdated %t, zoneUpdated %t, regionUpdated %t, kubeconfigUpdated %t, connectionstringUpdated %t",
   186  			passwordUpdated, zoneUpdated, regionUpdated, kubeconfigUpdated, connectionStringUpdated))
   187  	}
   188  
   189  	return update, err
   190  }
   191  
   192  func (c *Console) Reconcile(instance *current.IBPConsole, update Update) (common.Result, error) {
   193  	var err error
   194  
   195  	versionSet, err := c.SetVersion(instance)
   196  	if err != nil {
   197  		return common.Result{}, errors.Wrap(err, fmt.Sprintf("failed updating CR '%s' to version '%s'", instance.Name, version.Operator))
   198  	}
   199  	if versionSet {
   200  		log.Info("Instance version updated, requeuing request...")
   201  		return common.Result{
   202  			Result: reconcile.Result{
   203  				Requeue: true,
   204  			},
   205  		}, nil
   206  	}
   207  
   208  	instanceUpdated, err := c.PreReconcileChecks(instance)
   209  	if err != nil {
   210  		return common.Result{}, errors.Wrap(err, "failed pre reconcile checks")
   211  	}
   212  
   213  	if instanceUpdated {
   214  		log.Info("Updating instance after pre reconcile checks")
   215  		err := c.Client.Patch(context.TODO(), instance, nil, k8sclient.PatchOption{
   216  			Resilient: &k8sclient.ResilientPatch{
   217  				Retry:    3,
   218  				Into:     &current.IBPConsole{},
   219  				Strategy: client.MergeFrom,
   220  			},
   221  		})
   222  		if err != nil {
   223  			return common.Result{}, errors.Wrap(err, "failed to update instance")
   224  		}
   225  
   226  		log.Info("Instance updated, requeuing request...")
   227  		return common.Result{
   228  			Result: reconcile.Result{
   229  				Requeue: true,
   230  			},
   231  		}, nil
   232  	}
   233  
   234  	log.Info("Reconciling managers ...")
   235  	err = c.ReconcileManagers(instance, update.SpecUpdated())
   236  	if err != nil {
   237  		return common.Result{}, errors.Wrap(err, "failed to reconcile managers")
   238  	}
   239  
   240  	err = c.CheckStates(instance, update.SpecUpdated())
   241  	if err != nil {
   242  		return common.Result{}, errors.Wrap(err, "failed to check and restore state")
   243  	}
   244  
   245  	err = c.CheckForConfigMapUpdates(instance, update)
   246  	if err != nil {
   247  		return common.Result{}, errors.Wrap(err, "failed to check for config map updates")
   248  	}
   249  
   250  	err = c.HandleActions(instance, update)
   251  	if err != nil {
   252  		return common.Result{}, err
   253  	}
   254  
   255  	if err := c.HandleRestart(instance, update); err != nil {
   256  		return common.Result{}, err
   257  	}
   258  
   259  	return common.Result{}, nil
   260  }
   261  
   262  func (c *Console) SetVersion(instance *current.IBPConsole) (bool, error) {
   263  	if instance.Status.Version == "" || !version.String(instance.Status.Version).Equal(version.Operator) {
   264  		log.Info("Version of Operator: ", "version", version.Operator)
   265  		log.Info("Version of CR: ", "version", instance.Status.Version)
   266  		log.Info(fmt.Sprintf("Setting '%s' to version '%s'", instance.Name, version.Operator))
   267  
   268  		instance.Status.Version = version.Operator
   269  		err := c.Client.PatchStatus(context.TODO(), instance, nil, k8sclient.PatchOption{
   270  			Resilient: &k8sclient.ResilientPatch{
   271  				Retry:    3,
   272  				Into:     &current.IBPConsole{},
   273  				Strategy: client.MergeFrom,
   274  			},
   275  		})
   276  		if err != nil {
   277  			return false, err
   278  		}
   279  		return true, nil
   280  	}
   281  	return false, nil
   282  }
   283  
   284  func (c *Console) ReconcileManagers(instance *current.IBPConsole, update bool) error {
   285  	var err error
   286  
   287  	if strings.Contains(instance.Spec.ConnectionString, "localhost") || instance.Spec.ConnectionString == "" {
   288  		err = c.PVCManager.Reconcile(instance, update)
   289  		if err != nil {
   290  			return errors.Wrap(err, "failed PVC reconciliation")
   291  		}
   292  	}
   293  
   294  	err = c.ServiceManager.Reconcile(instance, update)
   295  	if err != nil {
   296  		return errors.Wrap(err, "failed Service reconciliation")
   297  	}
   298  
   299  	if instance.Spec.FeatureFlags != nil && instance.Spec.FeatureFlags.DevMode {
   300  		c.DeployerServiceManager.SetCustomName(instance.GetName() + "-deployer-" + instance.Namespace)
   301  		err = c.DeployerServiceManager.Reconcile(instance, update)
   302  		if err != nil {
   303  			return errors.Wrap(err, "failed Deployer Service reconciliation")
   304  		}
   305  	}
   306  
   307  	err = c.ReconcileRBAC(instance)
   308  	if err != nil {
   309  		return errors.Wrap(err, "failed RBAC reconciliation")
   310  	}
   311  
   312  	err = c.ConfigMapManager.Reconcile(instance, update)
   313  	if err != nil {
   314  		return errors.Wrap(err, "failed ConfigMap reconciliation")
   315  	}
   316  
   317  	err = c.DeployerConfigMapManager.Reconcile(instance, update)
   318  	if err != nil {
   319  		return errors.Wrap(err, "failed Deployer ConfigMap reconciliation")
   320  	}
   321  
   322  	err = c.ConsoleConfigMapManager.Reconcile(instance, update)
   323  	if err != nil {
   324  		return errors.Wrap(err, "failed Console ConfigMap reconciliation")
   325  	}
   326  
   327  	err = c.DeploymentManager.Reconcile(instance, update)
   328  	if err != nil {
   329  		return errors.Wrap(err, "failed Deployment reconciliation")
   330  	}
   331  
   332  	return nil
   333  }
   334  
   335  func (c *Console) ReconcileRBAC(instance *current.IBPConsole) error {
   336  	var err error
   337  
   338  	err = c.RoleManager.Reconcile(instance, false)
   339  	if err != nil {
   340  		return err
   341  	}
   342  
   343  	err = c.RoleBindingManager.Reconcile(instance, false)
   344  	if err != nil {
   345  		return err
   346  	}
   347  
   348  	err = c.ServiceAccountManager.Reconcile(instance, false)
   349  	if err != nil {
   350  		return err
   351  	}
   352  
   353  	return nil
   354  }
   355  
   356  func (c *Console) CheckStates(instance *current.IBPConsole, update bool) error {
   357  	// Don't need to check state if the state is being updated via CR. State needs
   358  	// to be checked if operator detects changes to a resources that was not triggered
   359  	// via CR.
   360  	if c.DeploymentManager.Exists(instance) {
   361  		err := c.DeploymentManager.CheckState(instance)
   362  		if err != nil {
   363  			log.Info(fmt.Sprintf("unexpected state found for deployment, restoring state: %s", err.Error()))
   364  			err = c.DeploymentManager.RestoreState(instance)
   365  			if err != nil {
   366  				return err
   367  			}
   368  		}
   369  	}
   370  
   371  	return nil
   372  }
   373  
   374  func (c *Console) SelectZone(instance *current.IBPConsole) (bool, error) {
   375  	if instance.Spec.Zone == "select" {
   376  		zone := util.GetZone(c.Client)
   377  		instance.Spec.Zone = zone
   378  		return true, nil
   379  	}
   380  	if instance.Spec.Zone != "" {
   381  		err := util.ValidateZone(c.Client, instance.Spec.Zone)
   382  		if err != nil {
   383  			return false, err
   384  		}
   385  	}
   386  	return false, nil
   387  }
   388  
   389  func (c *Console) SelectRegion(instance *current.IBPConsole) (bool, error) {
   390  	if instance.Spec.Region == "select" {
   391  		region := util.GetRegion(c.Client)
   392  		instance.Spec.Region = region
   393  		return true, nil
   394  	}
   395  	if instance.Spec.Region != "" {
   396  		err := util.ValidateRegion(c.Client, instance.Spec.Region)
   397  		if err != nil {
   398  			return false, err
   399  		}
   400  	}
   401  	return false, nil
   402  }
   403  
   404  func (c *Console) CreatePasswordSecretIfRequired(instance *current.IBPConsole) (bool, error) {
   405  	namespace := instance.Namespace
   406  	passwordSecretName := instance.Spec.PasswordSecretName
   407  	password := instance.Spec.Password
   408  
   409  	authscheme := instance.Spec.AuthScheme
   410  
   411  	// if password is blank and passwordSecret is set
   412  	if password == "" && passwordSecretName != "" {
   413  		userSecret := &corev1.Secret{}
   414  		err := c.Client.Get(context.TODO(), types.NamespacedName{Name: passwordSecretName, Namespace: namespace}, userSecret)
   415  		if err != nil {
   416  			return false, errors.Wrap(err, "failed to get provided console password secret, password is blank & secret is set")
   417  		}
   418  		return false, nil
   419  	}
   420  
   421  	if passwordSecretName == "" && authscheme == "ibmid" {
   422  		password = "unused"
   423  	}
   424  
   425  	if password == "" && passwordSecretName == "" {
   426  		return false, errors.New("both password and password secret are NOT set")
   427  	}
   428  
   429  	if passwordSecretName == "" && password != "" {
   430  		passwordSecretName = instance.Name + "-console-pw"
   431  		err := c.CreateUserSecret(instance, passwordSecretName, password)
   432  		if err != nil {
   433  			return false, errors.Wrap(err, "failed to create user secret")
   434  		} else {
   435  			instance.Spec.Password = ""
   436  			instance.Spec.PasswordSecretName = passwordSecretName
   437  			return true, nil
   438  		}
   439  	}
   440  
   441  	return false, nil
   442  
   443  }
   444  
   445  func (c *Console) CreateKubernetesSecretIfRequired(instance *current.IBPConsole) (bool, error) {
   446  	namespace := instance.Namespace
   447  	kubeconfigsecretname := instance.Spec.KubeconfigSecretName
   448  	kubeconfig := instance.Spec.Kubeconfig
   449  
   450  	// if password is blank and passwordSecret is set
   451  	if kubeconfig == nil && kubeconfigsecretname != "" {
   452  		kubeconfigSecret := &corev1.Secret{}
   453  		err := c.Client.Get(context.TODO(), types.NamespacedName{Name: kubeconfigsecretname, Namespace: namespace}, kubeconfigSecret)
   454  		if err != nil {
   455  			return false, errors.Wrap(err, "failed to get kubeconifg secret")
   456  		}
   457  		return false, nil
   458  	}
   459  
   460  	if kubeconfigsecretname == "" && kubeconfig != nil && string(*kubeconfig) != "" {
   461  		kubeconfigsecretname = instance.Name + "-kubeconfig"
   462  		err := c.CreateKubeconfigSecret(instance, kubeconfigsecretname, kubeconfig)
   463  		if err != nil {
   464  			return false, errors.Wrap(err, "failed to create kubeconfig secret")
   465  		} else {
   466  			empty := make([]byte, 0)
   467  			instance.Spec.Kubeconfig = &empty
   468  			instance.Spec.KubeconfigSecretName = kubeconfigsecretname
   469  			return true, nil
   470  		}
   471  	}
   472  
   473  	if kubeconfig != nil && string(*kubeconfig) != "" && kubeconfigsecretname != "" {
   474  		return false, errors.New("both kubeconfig and kubeconfig secret name are set")
   475  	}
   476  
   477  	return false, nil
   478  }
   479  
   480  func (c *Console) CreateKubeconfigSecret(instance *current.IBPConsole, kubeocnfigSecretName string, kubeconfig *[]byte) error {
   481  	kubeconfigSecret := &corev1.Secret{}
   482  	kubeconfigSecret.Name = kubeocnfigSecretName
   483  	kubeconfigSecret.Namespace = instance.Namespace
   484  	kubeconfigSecret.Labels = c.GetLabels(instance)
   485  
   486  	kubeconfigSecret.Data = map[string][]byte{}
   487  	kubeconfigSecret.Data["kubeconfig.yaml"] = *kubeconfig
   488  
   489  	err := c.Client.Create(context.TODO(), kubeconfigSecret, k8sclient.CreateOption{Owner: instance, Scheme: c.Scheme})
   490  	if err != nil {
   491  		return err
   492  	}
   493  
   494  	return nil
   495  }
   496  
   497  func (c *Console) CreateUserSecret(instance *current.IBPConsole, passwordSecretName, password string) error {
   498  	userSecret := &corev1.Secret{}
   499  	userSecret.Name = passwordSecretName
   500  	userSecret.Namespace = instance.Namespace
   501  	userSecret.Labels = c.GetLabels(instance)
   502  
   503  	userSecret.Data = map[string][]byte{}
   504  	userSecret.Data["password"] = []byte(password)
   505  
   506  	err := c.Client.Create(context.TODO(), userSecret, k8sclient.CreateOption{Owner: instance, Scheme: c.Scheme})
   507  	if err != nil {
   508  		return err
   509  	}
   510  
   511  	return nil
   512  }
   513  
   514  func (c *Console) ValidateSpec(instance *current.IBPConsole) error {
   515  	if instance.Spec.NetworkInfo == nil {
   516  		return errors.New("network information not provided")
   517  	}
   518  
   519  	if instance.Spec.NetworkInfo.Domain == "" {
   520  		return errors.New("domain not provided in network information")
   521  	}
   522  
   523  	if !instance.Spec.License.Accept {
   524  		return errors.New("user must accept license before continuing")
   525  	}
   526  
   527  	if instance.Spec.ServiceAccountName == "" {
   528  		return errors.New("Service account name not provided")
   529  	}
   530  
   531  	if instance.Spec.Email == "" {
   532  		return errors.New("email not provided")
   533  	}
   534  
   535  	if instance.Spec.AuthScheme != "ibmid" && instance.Spec.Password == "" && instance.Spec.PasswordSecretName == "" {
   536  		return errors.New("password and passwordSecretName both not provided, at least one expected")
   537  	}
   538  
   539  	if instance.Spec.ImagePullSecrets == nil || len(instance.Spec.ImagePullSecrets) == 0 {
   540  		return errors.New("imagepullsecrets required")
   541  	}
   542  
   543  	if instance.Spec.RegistryURL != "" && !strings.HasSuffix(instance.Spec.RegistryURL, "/") {
   544  		instance.Spec.RegistryURL = instance.Spec.RegistryURL + "/"
   545  	}
   546  
   547  	return nil
   548  }
   549  
   550  func (c *Console) GetLabels(instance v1.Object) map[string]string {
   551  	label := os.Getenv("OPERATOR_LABEL_PREFIX")
   552  	if label == "" {
   553  		label = "fabric"
   554  	}
   555  
   556  	return map[string]string{
   557  		"app":                          instance.GetName(),
   558  		"creator":                      label,
   559  		"release":                      "operator",
   560  		"helm.sh/chart":                "ibm-" + label,
   561  		"app.kubernetes.io/name":       label,
   562  		"app.kubernetes.io/instance":   label + "console",
   563  		"app.kubernetes.io/managed-by": label + "-operator",
   564  	}
   565  }
   566  
   567  func (c *Console) HandleActions(instance *current.IBPConsole, update Update) error {
   568  	orig := instance.DeepCopy()
   569  
   570  	if update.RestartNeeded() {
   571  		if err := c.Restart.ForRestartAction(instance); err != nil {
   572  			return errors.Wrap(err, "failed to restart console pods")
   573  		}
   574  		instance.ResetRestart()
   575  	}
   576  
   577  	if err := c.Client.Patch(context.TODO(), instance, client.MergeFrom(orig)); err != nil {
   578  		return errors.Wrap(err, "failed to reset action flag")
   579  	}
   580  
   581  	return nil
   582  }
   583  
   584  func (c *Console) CreateCouchdbCredentials(instance *current.IBPConsole) bool {
   585  	if instance.Spec.ConnectionString != "" && instance.Spec.ConnectionString != "http://localhost:5984" {
   586  		return false
   587  	}
   588  
   589  	couchdbUser := util.GenerateRandomString(32)
   590  	couchdbPassword := util.GenerateRandomString(32)
   591  	connectionString := fmt.Sprintf("http://%s:%s@localhost:5984", couchdbUser, couchdbPassword)
   592  	instance.Spec.ConnectionString = connectionString
   593  	// TODO save deployer docs for SW?
   594  	// instance.Spec.Deployer.ConnectionString = connectionString
   595  
   596  	return true
   597  }
   598  
   599  func (c *Console) CheckForConfigMapUpdates(instance *current.IBPConsole, update Update) error {
   600  	if update.DeployerCMUpdated() || update.ConsoleCMUpdated() || update.EnvCMUpdated() {
   601  		err := c.Restart.ForConfigMapUpdate(instance)
   602  		if err != nil {
   603  			return errors.Wrap(err, "failed to update restart config")
   604  		}
   605  	}
   606  
   607  	return nil
   608  }
   609  
   610  func (c *Console) HandleRestart(instance *current.IBPConsole, update Update) error {
   611  	// If restart is disabled for components, can return immediately
   612  	if c.Config.Operator.Restart.Disable.Components {
   613  		return nil
   614  	}
   615  
   616  	err := c.Restart.TriggerIfNeeded(instance)
   617  	if err != nil {
   618  		return errors.Wrap(err, "failed to restart deployment")
   619  	}
   620  
   621  	return nil
   622  }
   623  
   624  func (c *Console) NetworkPolicyReconcile(instance *current.IBPConsole) error {
   625  	if c.Config.Operator.Console.ApplyNetworkPolicy == "" || c.Config.Operator.Console.ApplyNetworkPolicy == "false" {
   626  		return nil
   627  	}
   628  
   629  	log.Info("IBPOPERATOR_CONSOLE_APPLYNETWORKPOLICY set applying network policy")
   630  	err := c.CreateNetworkPolicyIfNotExists(instance, c.Config.ConsoleInitConfig.NetworkPolicyIngressFile, instance.GetName()+"-ingress")
   631  	if err != nil {
   632  		log.Error(err, "Cannot install ingress network policy")
   633  	}
   634  
   635  	err = c.CreateNetworkPolicyIfNotExists(instance, c.Config.ConsoleInitConfig.NetworkPolicyDenyAllFile, instance.GetName()+"-denyall")
   636  	if err != nil {
   637  		log.Error(err, "Cannot install denyall network policy")
   638  	}
   639  
   640  	return nil
   641  }
   642  
   643  func (c *Console) CreateNetworkPolicyIfNotExists(instance *current.IBPConsole, filename string, policyname string) error {
   644  	policy, err := util.GetNetworkPolicyFromFile(filename)
   645  	if err != nil {
   646  		return err
   647  	}
   648  
   649  	policy.Namespace = instance.Namespace
   650  	policy.Name = policyname
   651  	policy.Spec.PodSelector.MatchLabels = c.GetLabelsForNetworkPolicy(instance)
   652  
   653  	newPolicy := policy.DeepCopy()
   654  	err = c.Client.Get(context.TODO(), types.NamespacedName{Namespace: instance.Namespace, Name: instance.GetName()}, newPolicy)
   655  	if err != nil {
   656  		if k8sruntime.IgnoreNotFound(err) == nil {
   657  			log.Info("network policy not found, applying now")
   658  			err1 := c.Client.Create(context.TODO(), policy, k8sclient.CreateOption{Owner: instance, Scheme: c.Scheme})
   659  			if err1 != nil {
   660  				log.Error(err1, "Error applying network policy")
   661  			}
   662  		} else {
   663  			log.Error(err, "Error getting network policy")
   664  			return nil
   665  		}
   666  	} else {
   667  		log.Info("network policy found, not applying")
   668  		return nil
   669  	}
   670  	return nil
   671  }
   672  
   673  func (c *Console) GetLabelsForNetworkPolicy(instance v1.Object) map[string]string {
   674  	label := os.Getenv("OPERATOR_LABEL_PREFIX")
   675  	if label == "" {
   676  		label = "fabric"
   677  	}
   678  
   679  	return map[string]string{
   680  		"app.kubernetes.io/name": label,
   681  	}
   682  }