github.com/IBM-Blockchain/fabric-operator@v1.0.4/pkg/offering/base/console/override/deployment_test.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_test
    20  
    21  import (
    22  	"encoding/json"
    23  	"fmt"
    24  
    25  	. "github.com/onsi/ginkgo/v2"
    26  	. "github.com/onsi/gomega"
    27  
    28  	current "github.com/IBM-Blockchain/fabric-operator/api/v1beta1"
    29  	"github.com/IBM-Blockchain/fabric-operator/pkg/manager/resources"
    30  	"github.com/IBM-Blockchain/fabric-operator/pkg/offering/base/console/override"
    31  	"github.com/IBM-Blockchain/fabric-operator/pkg/util"
    32  	appsv1 "k8s.io/api/apps/v1"
    33  	corev1 "k8s.io/api/core/v1"
    34  	"k8s.io/apimachinery/pkg/runtime"
    35  )
    36  
    37  var _ = Describe("Base Console Deployment Overrides", func() {
    38  	Context("Deployment", func() {
    39  		var (
    40  			overrider                  *override.Override
    41  			instance, instanceWithTags *current.IBPConsole
    42  			deployment                 *appsv1.Deployment
    43  			err                        error
    44  			usetagsFlag                bool
    45  		)
    46  
    47  		BeforeEach(func() {
    48  			overrider = &override.Override{}
    49  
    50  			instance = &current.IBPConsole{
    51  				Spec: current.IBPConsoleSpec{
    52  					License: current.License{
    53  						Accept: true,
    54  					},
    55  					ServiceAccountName:   "test",
    56  					AuthScheme:           "couchdb",
    57  					DeployerTimeout:      30000,
    58  					Components:           "athena-components",
    59  					Sessions:             "athena-sessions",
    60  					System:               "athena-system",
    61  					ConnectionString:     "test.com",
    62  					Service:              &current.Service{},
    63  					Email:                "xyz@ibm.com",
    64  					PasswordSecretName:   "secret",
    65  					Password:             "cGFzc3dvcmQ=",
    66  					KubeconfigSecretName: "kubeconfig-secret",
    67  					SystemChannel:        "testchainid",
    68  					ImagePullSecrets:     []string{"testsecret"},
    69  					Images: &current.ConsoleImages{
    70  						ConsoleInitImage:   "fake-init-image",
    71  						ConsoleInitTag:     "1234",
    72  						CouchDBImage:       "fake-couchdb-image",
    73  						CouchDBTag:         "1234",
    74  						ConsoleImage:       "fake-console-image",
    75  						ConsoleTag:         "1234",
    76  						ConfigtxlatorImage: "fake-configtxlator-image",
    77  						ConfigtxlatorTag:   "1234",
    78  						DeployerImage:      "fake-deployer-image",
    79  						DeployerTag:        "1234",
    80  					},
    81  					RegistryURL: "ghcr.io/ibm-blockchain/",
    82  					NetworkInfo: &current.NetworkInfo{
    83  						Domain:      "test.domain",
    84  						ConsolePort: 31010,
    85  						ProxyPort:   31011,
    86  					},
    87  					TLSSecretName: "secret",
    88  					Resources:     &current.ConsoleResources{},
    89  					Storage: &current.ConsoleStorage{
    90  						Console: &current.StorageSpec{
    91  							Size:  "100m",
    92  							Class: "manual",
    93  						},
    94  					},
    95  				},
    96  			}
    97  			deployment, err = util.GetDeploymentFromFile("../../../../../definitions/console/deployment.yaml")
    98  			Expect(err).NotTo(HaveOccurred())
    99  			usetagsFlag = true
   100  			instanceWithTags = &current.IBPConsole{
   101  				Spec: current.IBPConsoleSpec{
   102  					License: current.License{
   103  						Accept: true,
   104  					},
   105  					ServiceAccountName:   "test",
   106  					AuthScheme:           "couchdb",
   107  					DeployerTimeout:      30000,
   108  					Components:           "athena-components",
   109  					Sessions:             "athena-sessions",
   110  					System:               "athena-system",
   111  					ConnectionString:     "test.com",
   112  					Service:              &current.Service{},
   113  					Email:                "xyz@ibm.com",
   114  					PasswordSecretName:   "secret",
   115  					Password:             "cGFzc3dvcmQ=",
   116  					KubeconfigSecretName: "kubeconfig-secret",
   117  					SystemChannel:        "testchainid",
   118  					ImagePullSecrets:     []string{"testsecret"},
   119  					Images: &current.ConsoleImages{
   120  						ConsoleInitImage:   "fake-init-image",
   121  						ConsoleInitTag:     "1234",
   122  						CouchDBImage:       "fake-couchdb-image",
   123  						CouchDBTag:         "1234",
   124  						ConsoleImage:       "fake-console-image",
   125  						ConsoleTag:         "1234",
   126  						ConfigtxlatorImage: "fake-configtxlator-image",
   127  						ConfigtxlatorTag:   "1234",
   128  						DeployerImage:      "fake-deployer-image",
   129  						DeployerTag:        "1234",
   130  						MustgatherImage:    "fake-mustgather-image",
   131  						MustgatherTag:      "1234",
   132  					},
   133  					RegistryURL: "ghcr.io/ibm-blockchain/",
   134  					NetworkInfo: &current.NetworkInfo{
   135  						Domain:      "test.domain",
   136  						ConsolePort: 31010,
   137  						ProxyPort:   31011,
   138  					},
   139  					TLSSecretName: "secret",
   140  					Resources:     &current.ConsoleResources{},
   141  					Storage: &current.ConsoleStorage{
   142  						Console: &current.StorageSpec{
   143  							Size:  "100m",
   144  							Class: "manual",
   145  						},
   146  					},
   147  					UseTags: &usetagsFlag,
   148  				},
   149  			}
   150  		})
   151  
   152  		Context("create", func() {
   153  			It("overrides values based on spec", func() {
   154  				err := overrider.Deployment(instanceWithTags, deployment, resources.Create)
   155  				Expect(err).NotTo(HaveOccurred())
   156  
   157  				By("setting service account name", func() {
   158  					Expect(deployment.Spec.Template.Spec.ServiceAccountName).To(Equal(instanceWithTags.Name))
   159  				})
   160  
   161  				By("image pull secret", func() {
   162  					Expect(deployment.Spec.Template.Spec.ImagePullSecrets).To(Equal([]corev1.LocalObjectReference{
   163  						corev1.LocalObjectReference{
   164  							Name: instanceWithTags.Spec.ImagePullSecrets[0],
   165  						},
   166  					}))
   167  				})
   168  
   169  				By("setting DEFAULT_USER_PASSWORD_INITIAL env var", func() {
   170  					envVar := corev1.EnvVar{
   171  						Name: "DEFAULT_USER_PASSWORD_INITIAL",
   172  						ValueFrom: &corev1.EnvVarSource{
   173  							SecretKeyRef: &corev1.SecretKeySelector{
   174  								LocalObjectReference: corev1.LocalObjectReference{
   175  									Name: instanceWithTags.Spec.PasswordSecretName,
   176  								},
   177  								Key: "password",
   178  							},
   179  						},
   180  					}
   181  					Expect(deployment.Spec.Template.Spec.Containers[0].Env).To(ContainElement(envVar))
   182  				})
   183  
   184  				By("setting TLS volume and volume mount if TLS secret name provided in spec", func() {
   185  					vm := corev1.VolumeMount{
   186  						Name:      "tls-certs",
   187  						MountPath: "/certs/tls",
   188  					}
   189  					Expect(deployment.Spec.Template.Spec.Containers[0].VolumeMounts).To(ContainElement(vm))
   190  
   191  					v := corev1.Volume{
   192  						Name: "tls-certs",
   193  						VolumeSource: corev1.VolumeSource{
   194  							Secret: &corev1.SecretVolumeSource{
   195  								SecretName: instanceWithTags.Spec.TLSSecretName,
   196  							},
   197  						},
   198  					}
   199  					Expect(deployment.Spec.Template.Spec.Volumes).To(ContainElement(v))
   200  				})
   201  
   202  				By("setting deployer volume", func() {
   203  					v := corev1.Volume{
   204  						Name: "deployer-template",
   205  						VolumeSource: corev1.VolumeSource{
   206  							ConfigMap: &corev1.ConfigMapVolumeSource{
   207  								LocalObjectReference: corev1.LocalObjectReference{
   208  									Name: instanceWithTags.Name + "-deployer",
   209  								},
   210  							},
   211  						},
   212  					}
   213  					Expect(deployment.Spec.Template.Spec.Volumes).To(ContainElement(v))
   214  				})
   215  
   216  				By("setting console volume", func() {
   217  					v := corev1.Volume{
   218  						Name: "template",
   219  						VolumeSource: corev1.VolumeSource{
   220  							ConfigMap: &corev1.ConfigMapVolumeSource{
   221  								LocalObjectReference: corev1.LocalObjectReference{
   222  									Name: instanceWithTags.Name + "-console",
   223  								},
   224  							},
   225  						},
   226  					}
   227  					Expect(deployment.Spec.Template.Spec.Volumes).To(ContainElement(v))
   228  				})
   229  
   230  				By("setting affinity", func() {
   231  					expectedAffinity := overrider.GetAffinity(instanceWithTags)
   232  					Expect(deployment.Spec.Template.Spec.Affinity).To(Equal(expectedAffinity))
   233  				})
   234  
   235  				ConsoleDeploymentCommonOverrides(instanceWithTags, deployment)
   236  			})
   237  
   238  			Context("using couchdb", func() {
   239  				BeforeEach(func() {
   240  					instance.Spec.ConnectionString = "localhost"
   241  				})
   242  
   243  				It("overrides values based on spec", func() {
   244  					err := overrider.Deployment(instance, deployment, resources.Create)
   245  					Expect(err).NotTo(HaveOccurred())
   246  
   247  					By("setting couchdb TLS volume and volume mount", func() {
   248  						vm := corev1.VolumeMount{
   249  							Name:      "couchdb",
   250  							MountPath: "/opt/couchdb/data",
   251  							SubPath:   "data",
   252  						}
   253  						Expect(deployment.Spec.Template.Spec.Containers[3].VolumeMounts).To(ContainElement(vm))
   254  						Expect(deployment.Spec.Template.Spec.InitContainers[0].VolumeMounts).To(ContainElement(vm))
   255  					})
   256  
   257  					By("setting cert volume and volume mount", func() {
   258  						vm := corev1.VolumeMount{
   259  							Name:      "couchdb",
   260  							MountPath: "/certs/",
   261  							SubPath:   "tls",
   262  						}
   263  						Expect(deployment.Spec.Template.Spec.Containers[0].VolumeMounts).To(ContainElement(vm))
   264  						Expect(deployment.Spec.Template.Spec.InitContainers[0].VolumeMounts).To(ContainElement(vm))
   265  					})
   266  				})
   267  			})
   268  
   269  			Context("not using TLS secret name", func() {
   270  				BeforeEach(func() {
   271  					instance.Spec.TLSSecretName = ""
   272  				})
   273  
   274  				It("overrides values based on spec", func() {
   275  					vm := corev1.VolumeMount{
   276  						Name:      "tls-certs",
   277  						MountPath: "/certs/tls",
   278  					}
   279  					Expect(deployment.Spec.Template.Spec.Containers[0].VolumeMounts).NotTo(ContainElement(vm))
   280  
   281  					v := corev1.Volume{
   282  						Name: "tls-certs",
   283  						VolumeSource: corev1.VolumeSource{
   284  							Secret: &corev1.SecretVolumeSource{
   285  								SecretName: instance.Spec.TLSSecretName,
   286  							},
   287  						},
   288  					}
   289  					Expect(deployment.Spec.Template.Spec.Volumes).NotTo(ContainElement(v))
   290  				})
   291  			})
   292  		})
   293  
   294  		Context("enabling activity tracker", func() {
   295  			It("overrides mounts based on spec overrides", func() {
   296  				consoleOverride := &current.ConsoleOverridesConsole{
   297  					ActivityTrackerConsolePath: "fake/path",
   298  					ActivityTrackerHostPath:    "host/path",
   299  				}
   300  				consoleBytes, err := json.Marshal(consoleOverride)
   301  				Expect(err).NotTo(HaveOccurred())
   302  				instance.Spec.ConfigOverride = &current.ConsoleOverrides{
   303  					Console: &runtime.RawExtension{Raw: consoleBytes},
   304  				}
   305  
   306  				err = overrider.Deployment(instance, deployment, resources.Create)
   307  				Expect(err).NotTo(HaveOccurred())
   308  				vm := corev1.VolumeMount{
   309  					Name:      "activity",
   310  					MountPath: "fake/path",
   311  					SubPath:   "",
   312  				}
   313  				Expect(deployment.Spec.Template.Spec.Containers[0].VolumeMounts).To(ContainElement(vm))
   314  				hostPathType := corev1.HostPathDirectoryOrCreate
   315  				v := corev1.Volume{
   316  					Name: "activity",
   317  					VolumeSource: corev1.VolumeSource{
   318  						HostPath: &corev1.HostPathVolumeSource{
   319  							Path: "host/path",
   320  							Type: &hostPathType,
   321  						},
   322  					},
   323  				}
   324  				Expect(deployment.Spec.Template.Spec.Volumes).To(ContainElement(v))
   325  
   326  				By("adding to init container command", func() {
   327  					Expect(deployment.Spec.Template.Spec.InitContainers[0].Command).To(Equal([]string{
   328  						"sh",
   329  						"-c",
   330  						"chmod -R 775 fake/path && chown -R -H 1000:1000 fake/path",
   331  					}))
   332  				})
   333  			})
   334  
   335  			It("overrides mounts based on spec overrides when only console path provided", func() {
   336  				consoleOverride := &current.ConsoleOverridesConsole{
   337  					ActivityTrackerConsolePath: "fake/path",
   338  				}
   339  				consoleBytes, err := json.Marshal(consoleOverride)
   340  				Expect(err).NotTo(HaveOccurred())
   341  				instance.Spec.ConfigOverride = &current.ConsoleOverrides{
   342  					Console: &runtime.RawExtension{Raw: consoleBytes},
   343  				}
   344  
   345  				err = overrider.Deployment(instance, deployment, resources.Create)
   346  				Expect(err).NotTo(HaveOccurred())
   347  				vm := corev1.VolumeMount{
   348  					Name:      "activity",
   349  					MountPath: "fake/path",
   350  					SubPath:   "",
   351  				}
   352  				Expect(deployment.Spec.Template.Spec.Containers[0].VolumeMounts).To(ContainElement(vm))
   353  				hostPathType := corev1.HostPathDirectoryOrCreate
   354  				v := corev1.Volume{
   355  					Name: "activity",
   356  					VolumeSource: corev1.VolumeSource{
   357  						HostPath: &corev1.HostPathVolumeSource{
   358  							Path: "/var/log/at",
   359  							Type: &hostPathType,
   360  						},
   361  					},
   362  				}
   363  				Expect(deployment.Spec.Template.Spec.Volumes).To(ContainElement(v))
   364  			})
   365  
   366  			It("adds command to init container command correctly when not using remote DB", func() {
   367  				consoleOverride := &current.ConsoleOverridesConsole{
   368  					ActivityTrackerConsolePath: "fake/path",
   369  					ActivityTrackerHostPath:    "host/path",
   370  				}
   371  				consoleBytes, err := json.Marshal(consoleOverride)
   372  				Expect(err).NotTo(HaveOccurred())
   373  				instance.Spec.ConfigOverride = &current.ConsoleOverrides{
   374  					Console: &runtime.RawExtension{Raw: consoleBytes},
   375  				}
   376  				instance.Spec.ConnectionString = "localhost"
   377  
   378  				err = overrider.Deployment(instance, deployment, resources.Create)
   379  				Expect(err).NotTo(HaveOccurred())
   380  
   381  				By("appending to init container command", func() {
   382  					Expect(deployment.Spec.Template.Spec.InitContainers[0].Command).To(Equal([]string{
   383  						"sh",
   384  						"-c",
   385  						"chmod -R 775 /opt/couchdb/data/ && chown -R -H 5984:5984 /opt/couchdb/data/ && chmod -R 775 /certs/ && chown -R -H 1000:1000 /certs/ && chmod -R 775 fake/path && chown -R -H 1000:1000 fake/path",
   386  					}))
   387  				})
   388  			})
   389  		})
   390  
   391  		// TODO:OSS
   392  		// as both the console and deployer defaults are blank
   393  		// Context("update", func() {
   394  		// 	It("doesn't overrides images and tags values, when usetags flag is not set", func() {
   395  		// 		err := overrider.Deployment(instance, deployment, resources.Update)
   396  		// 		Expect(err).NotTo(HaveOccurred())
   397  		// 		Expect(deployment.Spec.Template.Spec.Containers[0].Image).To(ContainSubstring("ghcr.io/ibm-blockchain/fake-console-image@sha256"))
   398  		// 		Expect(deployment.Spec.Template.Spec.InitContainers[0].Image).To(ContainSubstring("ghcr.io/ibm-blockchain/fake-init-image@sha256"))
   399  		// 		Expect(deployment.Spec.Template.Spec.Containers[1].Image).To(ContainSubstring("ghcr.io/ibm-blockchain/fake-deployer-image@sha256"))
   400  		// 		Expect(deployment.Spec.Template.Spec.Containers[2].Image).To(ContainSubstring("ghcr.io/ibm-blockchain/fake-configtxlator-image@sha256"))
   401  		// 	})
   402  		// })
   403  
   404  		Context("update when usetags set", func() {
   405  			It("overrides values based on spec, when usetags flag is set", func() {
   406  				err := overrider.Deployment(instanceWithTags, deployment, resources.Update)
   407  				Expect(err).NotTo(HaveOccurred())
   408  				ConsoleDeploymentCommonOverrides(instanceWithTags, deployment)
   409  			})
   410  		})
   411  
   412  		Context("Replicas", func() {
   413  			When("using remote db", func() {
   414  				It("using replica value from spec", func() {
   415  					replicas := int32(2)
   416  					instance.Spec.Replicas = &replicas
   417  					err := overrider.Deployment(instance, deployment, resources.Create)
   418  					Expect(err).NotTo(HaveOccurred())
   419  					Expect(*deployment.Spec.Replicas).To(Equal(replicas))
   420  				})
   421  			})
   422  
   423  			When("Replicas is greater than 1", func() {
   424  				BeforeEach(func() {
   425  					instance.Spec.ConnectionString = "localhost"
   426  				})
   427  
   428  				It("returns an error", func() {
   429  					replicas := int32(2)
   430  					instance.Spec.Replicas = &replicas
   431  					err := overrider.Deployment(instance, deployment, resources.Create)
   432  					Expect(err).To(HaveOccurred())
   433  					Expect(err.Error()).To(Equal("replicas > 1 not allowed in IBPConsole"))
   434  				})
   435  			})
   436  
   437  			When("Replicas is equal to 1", func() {
   438  				It("returns success", func() {
   439  					replicas := int32(1)
   440  					instance.Spec.Replicas = &replicas
   441  					err := overrider.Deployment(instance, deployment, resources.Create)
   442  					Expect(err).NotTo(HaveOccurred())
   443  				})
   444  			})
   445  			When("Replicas is equal to 0", func() {
   446  				It("returns success", func() {
   447  					replicas := int32(0)
   448  					instance.Spec.Replicas = &replicas
   449  					err := overrider.Deployment(instance, deployment, resources.Create)
   450  					Expect(err).NotTo(HaveOccurred())
   451  				})
   452  			})
   453  			When("Replicas is nil", func() {
   454  				It("returns success", func() {
   455  					instance.Spec.Replicas = nil
   456  					err := overrider.Deployment(instance, deployment, resources.Create)
   457  					Expect(err).NotTo(HaveOccurred())
   458  				})
   459  			})
   460  		})
   461  	})
   462  })
   463  
   464  func ConsoleDeploymentCommonOverrides(instance *current.IBPConsole, dep *appsv1.Deployment) {
   465  	By("setting init image", func() {
   466  		Expect(dep.Spec.Template.Spec.InitContainers[0].Image).To(Equal(fmt.Sprintf("%s%s:%s", instance.Spec.RegistryURL, instance.Spec.Images.ConsoleInitImage, instance.Spec.Images.ConsoleInitTag)))
   467  	})
   468  
   469  	By("setting console image", func() {
   470  		Expect(dep.Spec.Template.Spec.Containers[0].Image).To(Equal(fmt.Sprintf("%s%s:%s", instance.Spec.RegistryURL, instance.Spec.Images.ConsoleImage, instance.Spec.Images.ConsoleTag)))
   471  	})
   472  
   473  	By("setting deployer image", func() {
   474  		Expect(dep.Spec.Template.Spec.Containers[1].Image).To(Equal(fmt.Sprintf("%s%s:%s", instance.Spec.RegistryURL, instance.Spec.Images.DeployerImage, instance.Spec.Images.DeployerTag)))
   475  	})
   476  
   477  	By("setting configtxlator image", func() {
   478  		Expect(dep.Spec.Template.Spec.Containers[2].Image).To(Equal(fmt.Sprintf("%s%s:%s", instance.Spec.RegistryURL, instance.Spec.Images.ConfigtxlatorImage, instance.Spec.Images.ConfigtxlatorTag)))
   479  	})
   480  
   481  	By("setting replicas", func() {
   482  		Expect(dep.Spec.Replicas).To(Equal(instance.Spec.Replicas))
   483  	})
   484  
   485  	By("setting KUBECONFIGPATH env var", func() {
   486  		envVar := corev1.EnvVar{
   487  			Name:  "KUBECONFIGPATH",
   488  			Value: "/kubeconfig/kubeconfig.yaml",
   489  		}
   490  		Expect(dep.Spec.Template.Spec.Containers[1].Env).To(ContainElement(envVar))
   491  	})
   492  }