github.com/IBM-Blockchain/fabric-operator@v1.0.4/integration/e2ev2/orderer_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 e2ev2_test
    20  
    21  import (
    22  	"bytes"
    23  	"context"
    24  	"encoding/base64"
    25  	"encoding/json"
    26  	"fmt"
    27  	"time"
    28  
    29  	. "github.com/onsi/ginkgo/v2"
    30  	. "github.com/onsi/gomega"
    31  	"k8s.io/utils/pointer"
    32  	"sigs.k8s.io/controller-runtime/pkg/client"
    33  
    34  	current "github.com/IBM-Blockchain/fabric-operator/api/v1beta1"
    35  	"github.com/IBM-Blockchain/fabric-operator/integration"
    36  	"github.com/IBM-Blockchain/fabric-operator/integration/helper"
    37  	"github.com/IBM-Blockchain/fabric-operator/pkg/apis/common"
    38  	v1 "github.com/IBM-Blockchain/fabric-operator/pkg/apis/orderer/v1"
    39  	v2 "github.com/IBM-Blockchain/fabric-operator/pkg/apis/orderer/v2"
    40  	"github.com/IBM-Blockchain/fabric-operator/pkg/initializer/common/config"
    41  	v2config "github.com/IBM-Blockchain/fabric-operator/pkg/initializer/orderer/config/v2"
    42  	baseorderer "github.com/IBM-Blockchain/fabric-operator/pkg/offering/base/orderer"
    43  
    44  	corev1 "k8s.io/api/core/v1"
    45  	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
    46  	"k8s.io/apimachinery/pkg/runtime"
    47  	"k8s.io/apimachinery/pkg/types"
    48  )
    49  
    50  const (
    51  	IBPORDERERS = "ibporderers"
    52  
    53  	signCert = "LS0tLS1CRUdJTiBDRVJUSUZJQ0FURS0tLS0tCk1JSUNUekNDQWZXZ0F3SUJBZ0lVQWNnakVkOHBkOE43Vjg0YmFleG4yQzU0dWtzd0NnWUlLb1pJemowRUF3SXcKYURFTE1Ba0dBMVVFQmhNQ1ZWTXhGekFWQmdOVkJBZ1REazV2Y25Sb0lFTmhjbTlzYVc1aE1SUXdFZ1lEVlFRSwpFd3RJZVhCbGNteGxaR2RsY2pFUE1BMEdBMVVFQ3hNR1JtRmljbWxqTVJrd0Z3WURWUVFERXhCbVlXSnlhV010ClkyRXRjMlZ5ZG1WeU1CNFhEVEU1TVRFeE1qRTRNell3TUZvWERUSTBNVEV4TURFNE5ERXdNRm93WHpFTE1Ba0cKQTFVRUJoTUNWVk14RnpBVkJnTlZCQWdURGs1dmNuUm9JRU5oY205c2FXNWhNUlF3RWdZRFZRUUtFd3RJZVhCbApjbXhsWkdkbGNqRVBNQTBHQTFVRUN4TUdZMnhwWlc1ME1SQXdEZ1lEVlFRREV3ZHZjbVJsY21WeU1Ga3dFd1lICktvWkl6ajBDQVFZSUtvWkl6ajBEQVFjRFFnQUU2NFJwK1pvVnYyaTg0cE5KUUFNUHJpenJmZVlNT2Y0UnZ1eHkKNHZOUU1Pd3JEemlIZkFLTnZmdUJlbDhpQ2dndHRXM2paZTVkSEFZaFVIS2Ryb3FodmFPQmhUQ0JnakFPQmdOVgpIUThCQWY4RUJBTUNCNEF3REFZRFZSMFRBUUgvQkFJd0FEQWRCZ05WSFE0RUZnUVVWakl3Y1YwYXRNZmZWV1E5CnhtenpXVG9uYmlJd0h3WURWUjBqQkJnd0ZvQVVTUU9ZL0Z5YnNXcTlIWEo3c296aUFyLzhtQkV3SWdZRFZSMFIKQkJzd0dZSVhVMkZoWkhNdFRXRmpRbTl2YXkxUWNtOHViRzlqWVd3d0NnWUlLb1pJemowRUF3SURTQUF3UlFJaApBUGE4Y3VjL3QvOW45ZDZlSHZoUWdialNBK1k2dytERW1ka2RpdnJHaGE5RUFpQXdTZStlVGdsQWJYQVNoTnhwCkJpR0Rjc2IwZ1pmRmhQd1pIN1VnQW1IQjN3PT0KLS0tLS1FTkQgQ0VSVElGSUNBVEUtLS0tLQo="
    54  	certKey  = "LS0tLS1CRUdJTiBQUklWQVRFIEtFWS0tLS0tCk1JR0hBZ0VBTUJNR0J5cUdTTTQ5QWdFR0NDcUdTTTQ5QXdFSEJHMHdhd0lCQVFRZ1p2VWRsUVZ6QlVSc3I2STMKZEVvd0ZlVGkvVkNLZVZqMmFwN2x3QWNYSzJLaFJBTkNBQVRyaEduNW1oVy9hTHppazBsQUF3K3VMT3Q5NWd3NQovaEcrN0hMaTgxQXc3Q3NQT0lkOEFvMjkrNEY2WHlJS0NDMjFiZU5sN2wwY0JpRlFjcDJ1aXFHOQotLS0tLUVORCBQUklWQVRFIEtFWS0tLS0tCg=="
    55  	caCert   = "LS0tLS1CRUdJTiBDRVJUSUZJQ0FURS0tLS0tCk1JSUNGakNDQWIyZ0F3SUJBZ0lVZi84bk94M2NqM1htVzNDSUo1L0Q1ejRRcUVvd0NnWUlLb1pJemowRUF3SXcKYURFTE1Ba0dBMVVFQmhNQ1ZWTXhGekFWQmdOVkJBZ1REazV2Y25Sb0lFTmhjbTlzYVc1aE1SUXdFZ1lEVlFRSwpFd3RJZVhCbGNteGxaR2RsY2pFUE1BMEdBMVVFQ3hNR1JtRmljbWxqTVJrd0Z3WURWUVFERXhCbVlXSnlhV010ClkyRXRjMlZ5ZG1WeU1CNFhEVEU1TVRBek1ERTNNamd3TUZvWERUTTBNVEF5TmpFM01qZ3dNRm93YURFTE1Ba0cKQTFVRUJoTUNWVk14RnpBVkJnTlZCQWdURGs1dmNuUm9JRU5oY205c2FXNWhNUlF3RWdZRFZRUUtFd3RJZVhCbApjbXhsWkdkbGNqRVBNQTBHQTFVRUN4TUdSbUZpY21sak1Sa3dGd1lEVlFRREV4Qm1ZV0p5YVdNdFkyRXRjMlZ5CmRtVnlNRmt3RXdZSEtvWkl6ajBDQVFZSUtvWkl6ajBEQVFjRFFnQUVSbzNmbUc2UHkyUHd6cUMwNnFWZDlFOFgKZ044eldqZzFMb3lnMmsxdkQ4MXY1dENRRytCTVozSUJGQnI2VTRhc0tZTUREakd6TElERmdUUTRjVDd1VktORgpNRU13RGdZRFZSMFBBUUgvQkFRREFnRUdNQklHQTFVZEV3RUIvd1FJTUFZQkFmOENBUUV3SFFZRFZSME9CQllFCkZFa0RtUHhjbTdGcXZSMXllN0tNNGdLLy9KZ1JNQW9HQ0NxR1NNNDlCQU1DQTBjQU1FUUNJRC92QVFVSEh2SWwKQWZZLzM5UWdEU2ltTWpMZnhPTG44NllyR1EvWHpkQVpBaUFpUmlyZmlMdzVGbXBpRDhtYmlmRjV4bzdFUzdqNApaUWQyT0FUNCt5OWE0Zz09Ci0tLS0tRU5EIENFUlRJRklDQVRFLS0tLS0K"
    56  )
    57  
    58  var _ = Describe("orderer", func() {
    59  	var (
    60  		node1 helper.Orderer
    61  	)
    62  
    63  	BeforeEach(func() {
    64  		node1 = orderer.Nodes[0]
    65  		Eventually(node1.PodIsRunning, time.Second*60, time.Second*2).Should((Equal(true)))
    66  
    67  		ClearOperatorConfig()
    68  	})
    69  
    70  	AfterEach(func() {
    71  		// Set flag if a test falls
    72  		if CurrentGinkgoTestDescription().Failed {
    73  			testFailed = true
    74  		}
    75  	})
    76  
    77  	Context("config overrides", func() {
    78  		var (
    79  			podName string
    80  			bytes   []byte
    81  		)
    82  
    83  		BeforeEach(func() {
    84  			cm, err := kclient.CoreV1().ConfigMaps(namespace).Get(context.TODO(), orderer.Name+"node1-config", metav1.GetOptions{})
    85  			Expect(err).NotTo(HaveOccurred())
    86  
    87  			ordererBytes := cm.BinaryData["orderer.yaml"]
    88  			ordererConfig, err := v2config.ReadOrdererFromBytes(ordererBytes)
    89  			Expect(err).NotTo(HaveOccurred())
    90  			Expect(ordererConfig.General.Keepalive.ServerMinInterval.Duration).To(Equal(common.MustParseDuration("30h").Duration))
    91  
    92  			configOverride := &v2config.Orderer{
    93  				Orderer: v2.Orderer{
    94  					General: v2.General{
    95  						Keepalive: v1.Keepalive{
    96  							ServerInterval: common.MustParseDuration("20h"),
    97  						},
    98  					},
    99  				},
   100  			}
   101  			configBytes, err := json.Marshal(configOverride)
   102  			Expect(err).NotTo(HaveOccurred())
   103  			orderer.CR.Spec.ConfigOverride = &runtime.RawExtension{Raw: configBytes}
   104  
   105  			orderer.CR.Name = orderer.CR.Name + "node1"
   106  
   107  			bytes, err = json.Marshal(orderer.CR)
   108  			Expect(err).NotTo(HaveOccurred())
   109  
   110  			podName = node1.GetRunningPods()[0].Name
   111  		})
   112  
   113  		It("updates config based on overrides", func() {
   114  			result := ibpCRClient.Patch(types.MergePatchType).Namespace(namespace).Resource(IBPORDERERS).Name(node1.Name).Body(bytes).Do(context.TODO())
   115  			Expect(result.Error()).NotTo(HaveOccurred())
   116  
   117  			By("updating config in config map", func() {
   118  				var ordererConfig *v2config.Orderer
   119  				Eventually(func() bool {
   120  					cm, err := kclient.CoreV1().ConfigMaps(namespace).Get(context.TODO(), orderer.Name+"node1-config", metav1.GetOptions{})
   121  					if err != nil {
   122  						return false
   123  					}
   124  
   125  					ordererBytes := cm.BinaryData["orderer.yaml"]
   126  					ordererConfig, err = v2config.ReadOrdererFromBytes(ordererBytes)
   127  					if err != nil {
   128  						return false
   129  					}
   130  
   131  					if ordererConfig.General.Keepalive.ServerInterval.Duration == common.MustParseDuration("20h").Duration {
   132  						return true
   133  					}
   134  
   135  					return false
   136  				}).Should(Equal(true))
   137  
   138  				Expect(ordererConfig.General.Keepalive.ServerMinInterval.Duration).To(Equal(common.MustParseDuration("30h").Duration))
   139  				Expect(ordererConfig.General.Keepalive.ServerInterval.Duration).To(Equal(common.MustParseDuration("20h").Duration))
   140  			})
   141  
   142  			By("restarting orderer pods", func() {
   143  				Eventually(func() bool {
   144  					pods := node1.GetRunningPods()
   145  					if len(pods) == 0 {
   146  						return false
   147  					}
   148  
   149  					newPodName := pods[0].Name
   150  					if newPodName != podName {
   151  						return true
   152  					}
   153  
   154  					return false
   155  				}).Should(Equal(true))
   156  			})
   157  		})
   158  	})
   159  
   160  	Context("msp certs", func() {
   161  		var (
   162  			podName     string
   163  			oldsigncert []byte
   164  			oldkeystore []byte
   165  			oldcacert   []byte
   166  		)
   167  
   168  		BeforeEach(func() {
   169  			Eventually(func() int { return len(node1.GetRunningPods()) }).Should(Equal(1))
   170  
   171  			pods := node1.GetPods()
   172  			podName = pods[0].Name
   173  
   174  			// Store original certs
   175  			oldsigncert = EcertSignCert(node1.Name)
   176  			oldkeystore = EcertKeystore(node1.Name)
   177  			oldcacert = EcertCACert(node1.Name)
   178  		})
   179  
   180  		It("updates secrets for new certs passed through MSP spec", func() {
   181  
   182  			patch := func(i client.Object) {
   183  				testOrderer := i.(*current.IBPOrderer)
   184  				testOrderer.Spec.Secret = &current.SecretSpec{
   185  					MSP: &current.MSPSpec{
   186  						Component: &current.MSP{
   187  							SignCerts: signCert,
   188  							KeyStore:  certKey,
   189  							CACerts:   []string{caCert},
   190  						},
   191  					},
   192  				}
   193  			}
   194  
   195  			err := integration.ResilientPatch(ibpCRClient, node1.Name, namespace, "ibporderers", 3, &current.IBPOrderer{}, patch)
   196  			Expect(err).NotTo(HaveOccurred())
   197  
   198  			By("restarting node", func() {
   199  				Eventually(func() bool {
   200  					pods := node1.GetPods()
   201  					if len(pods) != 1 {
   202  						return false
   203  					}
   204  
   205  					newPodName := pods[0].Name
   206  					if newPodName == podName {
   207  						return false
   208  					}
   209  
   210  					return true
   211  				}).Should(Equal(true))
   212  
   213  				Eventually(node1.PodIsRunning).Should((Equal(true)))
   214  			})
   215  
   216  			By("backing up old signcert", func() {
   217  				backup := GetBackup("ecert", node1.Name)
   218  				Expect(len(backup.List)).NotTo(Equal(0))
   219  				Expect(backup.List[len(backup.List)-1].SignCerts).To(Equal(base64.StdEncoding.EncodeToString(oldsigncert)))
   220  				Expect(backup.List[len(backup.List)-1].KeyStore).To(Equal(base64.StdEncoding.EncodeToString(oldkeystore)))
   221  				Expect(backup.List[len(backup.List)-1].CACerts).To(Equal([]string{base64.StdEncoding.EncodeToString(oldcacert)}))
   222  			})
   223  
   224  			By("updating signcert secret", func() {
   225  				Expect(bytes.Equal(oldsigncert, EcertSignCert(node1.Name))).To(Equal(false))
   226  			})
   227  
   228  			By("updating keystore secret", func() {
   229  				Expect(bytes.Equal(oldkeystore, EcertKeystore(node1.Name))).To(Equal(false))
   230  			})
   231  
   232  			By("updating cacert secret", func() {
   233  				Expect(bytes.Equal(oldcacert, EcertCACert(node1.Name))).To(Equal(false))
   234  			})
   235  		})
   236  	})
   237  
   238  	Context("node ou updated", func() {
   239  		var (
   240  			podName    string
   241  			bytes      []byte
   242  			ibporderer *current.IBPOrderer
   243  			secret     *corev1.Secret
   244  		)
   245  
   246  		BeforeEach(func() {
   247  			// Pods seem to run slower and restart slower when running test in Travis.
   248  			SetDefaultEventuallyTimeout(540 * time.Second)
   249  
   250  			Eventually(func() int { return len(node1.GetRunningPods()) }).Should(Equal(1))
   251  			podName = node1.GetRunningPods()[0].Name
   252  
   253  			// Make sure config is in expected state
   254  			cm, err := kclient.CoreV1().ConfigMaps(namespace).Get(context.TODO(), node1.Name+"-config", metav1.GetOptions{})
   255  			Expect(err).NotTo(HaveOccurred())
   256  
   257  			configBytes := cm.BinaryData["config.yaml"]
   258  			cfg, err := config.NodeOUConfigFromBytes(configBytes)
   259  			Expect(err).NotTo(HaveOccurred())
   260  			Expect(cfg.NodeOUs.Enable).To(Equal(true))
   261  
   262  			secret, err = kclient.CoreV1().
   263  				Secrets(namespace).
   264  				Get(context.TODO(), fmt.Sprintf("ecert-%s-signcert", node1.Name), metav1.GetOptions{})
   265  			Expect(err).NotTo(HaveOccurred())
   266  
   267  			result := ibpCRClient.Get().Namespace(namespace).Resource(IBPORDERERS).Name(node1.Name).Do(context.TODO())
   268  			Expect(result.Error()).NotTo(HaveOccurred())
   269  
   270  			ibporderer = &current.IBPOrderer{}
   271  			result.Into(ibporderer)
   272  		})
   273  
   274  		It("disables nodeOU", func() {
   275  			By("providing admin certs", func() {
   276  				var err error
   277  				adminCert := base64.StdEncoding.EncodeToString(secret.Data["cert.pem"])
   278  
   279  				ibporderer.Spec.Secret.Enrollment.Component.AdminCerts = []string{adminCert}
   280  				ibporderer.Spec.Secret.MSP = nil
   281  				bytes, err = json.Marshal(ibporderer)
   282  				Expect(err).NotTo(HaveOccurred())
   283  
   284  				result := ibpCRClient.Put().Namespace(namespace).Resource(IBPORDERERS).Name(node1.Name).Body(bytes).Do(context.TODO())
   285  				Expect(result.Error()).NotTo(HaveOccurred())
   286  
   287  				Eventually(func() bool {
   288  					_, err := kclient.CoreV1().
   289  						Secrets(namespace).
   290  						Get(context.TODO(), fmt.Sprintf("ecert-%s-admincerts", node1.Name), metav1.GetOptions{})
   291  					if err != nil {
   292  						return false
   293  					}
   294  					return true
   295  				}).Should(Equal(true))
   296  			})
   297  
   298  			By("disabling nodeOU", func() {
   299  				result := ibpCRClient.Get().Namespace(namespace).Resource(IBPORDERERS).Name(node1.Name).Do(context.TODO())
   300  				Expect(result.Error()).NotTo(HaveOccurred())
   301  
   302  				ibporderer = &current.IBPOrderer{}
   303  				result.Into(ibporderer)
   304  
   305  				// Disable node ou
   306  				ibporderer.Spec.DisableNodeOU = pointer.Bool(true)
   307  				bytes, err := json.Marshal(ibporderer)
   308  				Expect(err).NotTo(HaveOccurred())
   309  
   310  				result = ibpCRClient.Patch(types.MergePatchType).Namespace(namespace).Resource(IBPORDERERS).Name(node1.Name).Body(bytes).Do(context.TODO())
   311  				Expect(result.Error()).NotTo(HaveOccurred())
   312  			})
   313  
   314  			By("updating config map", func() {
   315  				Eventually(func() bool {
   316  					cm, err := kclient.CoreV1().ConfigMaps(namespace).Get(context.TODO(), node1.Name+"-config", metav1.GetOptions{})
   317  					if err != nil {
   318  						return false
   319  					}
   320  
   321  					configBytes := cm.BinaryData["config.yaml"]
   322  					nodeOUConfig, err := config.NodeOUConfigFromBytes(configBytes)
   323  					if err != nil {
   324  						return false
   325  					}
   326  
   327  					return nodeOUConfig.NodeOUs.Enable
   328  				}).Should(Equal(false))
   329  			})
   330  
   331  			By("restarting orderer node pods", func() {
   332  				Eventually(func() bool {
   333  					pods := node1.GetRunningPods()
   334  					if len(pods) == 0 {
   335  						return false
   336  					}
   337  
   338  					newPodName := pods[0].Name
   339  					if newPodName != podName {
   340  						return true
   341  					}
   342  
   343  					return false
   344  				}).Should(Equal(true))
   345  			})
   346  		})
   347  	})
   348  })
   349  
   350  func GetOrderer(tlsCert, caHost string) *helper.Orderer {
   351  	cr, err := helper.OrdererCR(namespace, domain, ordererUsername, tlsCert, caHost)
   352  	Expect(err).NotTo(HaveOccurred())
   353  
   354  	nodes := []helper.Orderer{
   355  		helper.Orderer{
   356  			Name:      cr.Name + "node1",
   357  			Namespace: namespace,
   358  			CR:        cr.DeepCopy(),
   359  			NodeName:  fmt.Sprintf("%s%s%d", cr.Name, baseorderer.NODE, 1),
   360  			NativeResourcePoller: integration.NativeResourcePoller{
   361  				Name:      cr.Name + "node1",
   362  				Namespace: namespace,
   363  				Client:    kclient,
   364  			},
   365  		},
   366  	}
   367  
   368  	nodes[0].CR.ObjectMeta.Name = cr.Name + "node1"
   369  
   370  	return &helper.Orderer{
   371  		Name:      cr.Name,
   372  		Namespace: namespace,
   373  		CR:        cr,
   374  		NodeName:  fmt.Sprintf("%s-%s%d", cr.Name, baseorderer.NODE, 1),
   375  		NativeResourcePoller: integration.NativeResourcePoller{
   376  			Name:      cr.Name,
   377  			Namespace: namespace,
   378  			Client:    kclient,
   379  		},
   380  		Nodes: nodes,
   381  	}
   382  }