From 2565e7b153a68bf456391a8b208146ec56e3d2aa Mon Sep 17 00:00:00 2001 From: Sam Yuan Date: Sat, 2 Jul 2022 19:07:02 +0800 Subject: [PATCH 01/41] upgrade go mod to ginkgo v2 Signed-off-by: Sam Yuan --- controllers/ibpca/ibpca_controller_test.go | 2 +- controllers/ibpca/ibpca_suite_test.go | 2 +- controllers/ibpca/predicate_test.go | 2 +- .../ibpconsole/ibpconsole_controller_test.go | 2 +- .../ibpconsole/ibpconsole_suite_test.go | 2 +- .../ibporderer/ibporderer_controller_test.go | 2 +- .../ibporderer/ibporderer_suite_test.go | 2 +- controllers/ibporderer/predicate_test.go | 2 +- .../ibppeer/ibppeer_controller_test.go | 2 +- controllers/ibppeer/ibppeer_suite_test.go | 2 +- controllers/suite_test.go | 13 +-- docs/CONTRIBUTING.md | 2 +- go.mod | 17 ++-- go.sum | 31 +++++-- integration/actions/ca/ca_suite_test.go | 2 +- integration/actions/ca/ca_test.go | 2 +- .../actions/orderer/orderer_suite_test.go | 2 +- integration/actions/orderer/orderer_test.go | 2 +- integration/actions/peer/peer_suite_test.go | 2 +- integration/actions/peer/peer_test.go | 2 +- integration/actions/peer/reenroll_test.go | 2 +- integration/autorenew/autorenew_suite_test.go | 2 +- integration/autorenew/autorenew_test.go | 2 +- integration/ca/ca_suite_test.go | 2 +- integration/ca/ca_test.go | 2 +- .../cclauncher/cclauncher_suite_test.go | 2 +- integration/cclauncher/cclauncher_test.go | 2 +- integration/console/console_suite_test.go | 2 +- integration/console/console_test.go | 2 +- integration/e2ev2/ca_test.go | 2 +- integration/e2ev2/console_test.go | 2 +- integration/e2ev2/e2ev2_suite_test.go | 2 +- integration/e2ev2/orderer_test.go | 2 +- integration/e2ev2/peer_test.go | 2 +- integration/helper/session.go | 2 +- integration/init/init_suite_test.go | 2 +- integration/init/init_test.go | 2 +- integration/init/orderer_test.go | 2 +- integration/init/peer_test.go | 2 +- .../migration/fabric/fabric_suite_test.go | 2 +- integration/migration/fabric/orderer_test.go | 2 +- integration/migration/fabric/peer_test.go | 2 +- integration/migration/migration_suite_test.go | 2 +- integration/migration/migration_test.go | 2 +- integration/nativeresourcepoller.go | 2 +- .../operatorrestart_suite_test.go | 2 +- .../operatorrestart/operatorrestart_test.go | 2 +- integration/orderer/orderer_suite_test.go | 2 +- integration/orderer/orderer_test.go | 2 +- integration/peer/peer_suite_test.go | 2 +- integration/peer/peer_test.go | 2 +- .../restartmgr/restartmgr_suite_test.go | 2 +- integration/restartmgr/restartmgr_test.go | 2 +- pkg/action/action_suite_test.go | 2 +- pkg/action/action_test.go | 2 +- pkg/action/enroll_test.go | 2 +- pkg/action/upgradedbs_test.go | 2 +- pkg/certificate/certificate_suite_test.go | 2 +- pkg/certificate/certificate_test.go | 2 +- .../reenroller/reenroller_suite_test.go | 61 ++++++++++++- pkg/certificate/reenroller/reenroller_test.go | 58 +------------ pkg/client/client_suite_test.go | 2 +- pkg/client/client_test.go | 2 +- pkg/command/command_suite_test.go | 2 +- pkg/command/operator_test.go | 2 +- pkg/crd/crd_suite_test.go | 2 +- pkg/crd/manager_test.go | 2 +- pkg/global/config_test.go | 2 +- pkg/global/global_suite_test.go | 2 +- pkg/initializer/ca/ca_suite_test.go | 2 +- pkg/initializer/ca/ca_test.go | 2 +- pkg/initializer/ca/config/ca_test.go | 2 +- .../ca/config/config_suite_test.go | 2 +- pkg/initializer/ca/config/config_test.go | 2 +- pkg/initializer/ca/config/db_test.go | 2 +- .../ca/config/intermediate_test.go | 2 +- pkg/initializer/ca/config/operations_test.go | 2 +- pkg/initializer/ca/config/tls_test.go | 2 +- pkg/initializer/ca/hsm_test.go | 2 +- pkg/initializer/ca/initializer_test.go | 2 +- pkg/initializer/ca/tls/tls_suite_test.go | 2 +- pkg/initializer/ca/tls/tls_test.go | 2 +- pkg/initializer/common/common_suite_test.go | 2 +- pkg/initializer/common/common_test.go | 2 +- .../common/config/config_suite_test.go | 2 +- pkg/initializer/common/config/config_test.go | 2 +- .../common/config/hsmconfig_test.go | 2 +- .../common/enroller/enroller_suite_test.go | 32 ++++++- .../common/enroller/enroller_test.go | 2 +- .../common/enroller/fabcaclient_test.go | 32 +------ .../common/enroller/factory_test.go | 2 +- .../common/enroller/hsmdaemonenroller_test.go | 2 +- .../common/enroller/hsmenroller_test.go | 2 +- .../common/enroller/swenroller_test.go | 2 +- .../common/mspparser/mspparser_suite_test.go | 2 +- .../common/mspparser/mspparser_test.go | 2 +- .../secretmanager/secretmanager_suite_test.go | 2 +- .../secretmanager/secretmanager_test.go | 2 +- .../orderer/config/v1/config_suite_test.go | 2 +- .../orderer/config/v1/config_test.go | 2 +- .../orderer/config/v2/config_suite_test.go | 2 +- .../orderer/config/v2/config_test.go | 2 +- .../orderer/config/v24/config_suite_test.go | 2 +- .../orderer/config/v24/config_test.go | 2 +- .../orderer/configtx/configtx_suite_test.go | 2 +- .../orderer/configtx/configtx_test.go | 2 +- .../orderer/configtx/profile_test.go | 2 +- pkg/initializer/orderer/initializer_test.go | 2 +- pkg/initializer/orderer/orderer_suite_test.go | 2 +- .../commoncore/commoncore_suite_test.go | 2 +- .../peer/config/commoncore/commoncore_test.go | 2 +- .../peer/config/v1/config_suite_test.go | 2 +- pkg/initializer/peer/config/v1/config_test.go | 2 +- pkg/initializer/peer/config/v2/config_test.go | 2 +- .../peer/config/v2/v2_suite_test.go | 2 +- pkg/initializer/peer/coreconfigmap_test.go | 2 +- pkg/initializer/peer/initializer_test.go | 2 +- pkg/initializer/peer/peer_suite_test.go | 2 +- pkg/initializer/peer/peer_test.go | 2 +- .../validator/validator_suite_test.go | 2 +- pkg/initializer/validator/validator_test.go | 2 +- .../configmap/configmap_suite_test.go | 2 +- .../resources/configmap/manager_test.go | 2 +- .../container/container_suite_test.go | 2 +- .../resources/container/container_test.go | 2 +- .../deployment/deployment_suite_test.go | 2 +- .../resources/deployment/manager_test.go | 2 +- .../resources/ingress/ingress_suite_test.go | 2 +- pkg/manager/resources/ingress/manager_test.go | 2 +- .../ingressv1beta1/ingress_suite_test.go | 2 +- .../resources/ingressv1beta1/manager_test.go | 2 +- pkg/manager/resources/job/job_suite_test.go | 2 +- pkg/manager/resources/job/job_test.go | 2 +- .../resources/orderernode/manager_test.go | 2 +- .../orderernode/orderernode_suite_test.go | 2 +- pkg/manager/resources/pv/manager_test.go | 2 +- pkg/manager/resources/pv/pvc_suite_test.go | 2 +- pkg/manager/resources/pvc/manager_test.go | 2 +- pkg/manager/resources/pvc/pvc_suite_test.go | 2 +- pkg/manager/resources/role/manager_test.go | 2 +- pkg/manager/resources/role/role_suite_test.go | 2 +- .../resources/rolebinding/manager_test.go | 2 +- .../rolebinding/rolebinding_suite_test.go | 2 +- pkg/manager/resources/route/manager_test.go | 2 +- .../resources/route/route_suite_test.go | 2 +- pkg/manager/resources/service/manager_test.go | 2 +- .../resources/service/service_suite_test.go | 2 +- .../resources/serviceaccount/manager_test.go | 2 +- .../serviceaccount_suite_test.go | 2 +- pkg/migrator/peer/fabric/fabric_suite_test.go | 2 +- pkg/migrator/peer/fabric/migrator_test.go | 2 +- pkg/migrator/peer/fabric/v2/peer_test.go | 2 +- pkg/migrator/peer/fabric/v2/v2_suite_test.go | 2 +- pkg/migrator/peer/peer_suite_test.go | 2 +- pkg/offering/base/ca/ca_suite_test.go | 2 +- pkg/offering/base/ca/ca_test.go | 2 +- pkg/offering/base/ca/initialize_test.go | 2 +- .../base/ca/override/deployment_test.go | 87 +++++++++---------- .../base/ca/override/override_suite_test.go | 2 +- .../base/ca/override/override_test.go | 2 +- pkg/offering/base/ca/override/pvc_test.go | 2 +- pkg/offering/base/ca/override/service_test.go | 2 +- .../base/ca/override/serviceaccount_test.go | 2 +- .../base/console/console_suite_test.go | 2 +- pkg/offering/base/console/console_test.go | 2 +- .../base/console/override/consolecm_test.go | 2 +- .../base/console/override/deployercm_test.go | 2 +- .../console/override/deployerservice_test.go | 2 +- .../base/console/override/deployment_test.go | 2 +- .../base/console/override/envcm_test.go | 2 +- .../console/override/override_suite_test.go | 2 +- .../base/console/override/pvc_test.go | 2 +- .../base/console/override/service_test.go | 2 +- .../console/override/serviceaccount_test.go | 2 +- pkg/offering/base/orderer/node_test.go | 2 +- .../base/orderer/orderer_suite_test.go | 2 +- pkg/offering/base/orderer/orderer_test.go | 2 +- .../base/orderer/override/deployment_test.go | 2 +- .../orderer/override/override_suite_test.go | 2 +- .../base/orderer/override/override_test.go | 2 +- .../base/orderer/override/pvc_test.go | 2 +- .../base/orderer/override/service_test.go | 2 +- .../orderer/override/serviceaccount_test.go | 2 +- .../base/peer/override/deployment_test.go | 2 +- .../base/peer/override/override_suite_test.go | 2 +- .../base/peer/override/override_test.go | 2 +- pkg/offering/base/peer/override/pvc_test.go | 2 +- .../base/peer/override/service_test.go | 2 +- .../base/peer/override/serviceaccount_test.go | 2 +- pkg/offering/base/peer/peer_suite_test.go | 2 +- pkg/offering/base/peer/peer_test.go | 2 +- pkg/offering/common/common_suite_test.go | 2 +- pkg/offering/common/common_test.go | 2 +- .../reconcilechecks/fabricversion_test.go | 2 +- .../images/fabricversion_test.go | 2 +- .../images/images_suite_test.go | 2 +- .../reconcilechecks/images/images_test.go | 2 +- .../reconcilechecks_suite_test.go | 2 +- pkg/offering/k8s/ca/ca_suite_test.go | 2 +- pkg/offering/k8s/ca/ca_test.go | 2 +- pkg/offering/k8s/ca/override/ingress_test.go | 2 +- .../k8s/ca/override/ingressv1beta1_test.go | 2 +- .../k8s/ca/override/override_suite_test.go | 2 +- pkg/offering/k8s/ca/override/override_test.go | 2 +- .../k8s/console/console_suite_test.go | 2 +- pkg/offering/k8s/console/console_test.go | 2 +- .../k8s/console/override/consolecm_test.go | 2 +- .../k8s/console/override/deployercm_test.go | 2 +- .../k8s/console/override/envcm_test.go | 2 +- .../k8s/console/override/ingress_test.go | 2 +- .../console/override/ingressv1beta1_test.go | 2 +- .../console/override/override_suite_test.go | 2 +- .../k8s/console/override/override_test.go | 2 +- .../k8s/orderer/orderer_suite_test.go | 2 +- pkg/offering/k8s/orderer/orderer_test.go | 2 +- .../k8s/orderer/override/ingress_test.go | 2 +- .../orderer/override/ingressv1beta1_test.go | 2 +- .../orderer/override/override_suite_test.go | 2 +- .../k8s/orderer/override/override_test.go | 2 +- .../k8s/peer/override/ingress_test.go | 2 +- .../k8s/peer/override/ingressv1beta1_test.go | 2 +- .../k8s/peer/override/override_suite_test.go | 2 +- pkg/offering/k8s/peer/peer_suite_test.go | 2 +- pkg/offering/k8s/peer/peer_test.go | 2 +- pkg/offering/offering_suite_test.go | 2 +- pkg/offering/offering_test.go | 2 +- pkg/offering/openshift/ca/ca_suite_test.go | 2 +- pkg/offering/openshift/ca/ca_test.go | 2 +- .../ca/override/override_suite_test.go | 2 +- .../openshift/ca/override/override_test.go | 2 +- .../openshift/console/console_suite_test.go | 2 +- .../openshift/console/console_test.go | 2 +- .../console/override/consolecm_test.go | 2 +- .../console/override/consoleroute_test.go | 2 +- .../console/override/deployercm_test.go | 2 +- .../openshift/console/override/envcm_test.go | 2 +- .../console/override/override_suite_test.go | 2 +- .../console/override/proxyroute_test.go | 2 +- .../openshift/orderer/orderer_suite_test.go | 2 +- .../openshift/orderer/orderer_test.go | 2 +- .../orderer/override/override_suite_test.go | 2 +- .../orderer/override/override_test.go | 2 +- .../peer/override/override_suite_test.go | 2 +- .../openshift/peer/override/override_test.go | 2 +- .../openshift/peer/peer_suite_test.go | 2 +- pkg/offering/openshift/peer/peer_test.go | 2 +- pkg/operatorerrors/errors_test.go | 2 +- .../operatorerrors_suite_test.go | 2 +- pkg/restart/configmap/configmap_suite_test.go | 2 +- pkg/restart/configmap/configmap_test.go | 2 +- pkg/restart/restart_suite_test.go | 2 +- pkg/restart/restart_test.go | 2 +- .../staggerrestarts_suite_test.go | 2 +- .../staggerrestarts/staggerrestarts_test.go | 2 +- pkg/util/merge/merge_suite_test.go | 2 +- pkg/util/merge/merge_test.go | 2 +- pkg/util/util_suite_test.go | 2 +- pkg/util/util_test.go | 2 +- version/version_suite_test.go | 2 +- version/version_test.go | 2 +- 260 files changed, 423 insertions(+), 412 deletions(-) diff --git a/controllers/ibpca/ibpca_controller_test.go b/controllers/ibpca/ibpca_controller_test.go index d00af8a3..cd2dba6b 100644 --- a/controllers/ibpca/ibpca_controller_test.go +++ b/controllers/ibpca/ibpca_controller_test.go @@ -29,7 +29,7 @@ import ( "github.com/IBM-Blockchain/fabric-operator/pkg/offering/common" "github.com/IBM-Blockchain/fabric-operator/pkg/util" - . "github.com/onsi/ginkgo" + . "github.com/onsi/ginkgo/v2" . "github.com/onsi/gomega" camocks "github.com/IBM-Blockchain/fabric-operator/controllers/ibpca/mocks" diff --git a/controllers/ibpca/ibpca_suite_test.go b/controllers/ibpca/ibpca_suite_test.go index a9c9ae47..ad08193a 100644 --- a/controllers/ibpca/ibpca_suite_test.go +++ b/controllers/ibpca/ibpca_suite_test.go @@ -21,7 +21,7 @@ package ibpca_test import ( "testing" - . "github.com/onsi/ginkgo" + . "github.com/onsi/ginkgo/v2" . "github.com/onsi/gomega" ) diff --git a/controllers/ibpca/predicate_test.go b/controllers/ibpca/predicate_test.go index e97d0ff6..897e46f8 100644 --- a/controllers/ibpca/predicate_test.go +++ b/controllers/ibpca/predicate_test.go @@ -35,7 +35,7 @@ import ( "sigs.k8s.io/controller-runtime/pkg/event" yaml "sigs.k8s.io/yaml" - . "github.com/onsi/ginkgo" + . "github.com/onsi/ginkgo/v2" . "github.com/onsi/gomega" ) diff --git a/controllers/ibpconsole/ibpconsole_controller_test.go b/controllers/ibpconsole/ibpconsole_controller_test.go index bf7b2317..ee562bf8 100644 --- a/controllers/ibpconsole/ibpconsole_controller_test.go +++ b/controllers/ibpconsole/ibpconsole_controller_test.go @@ -22,7 +22,7 @@ import ( "context" "fmt" - . "github.com/onsi/ginkgo" + . "github.com/onsi/ginkgo/v2" . "github.com/onsi/gomega" "github.com/pkg/errors" diff --git a/controllers/ibpconsole/ibpconsole_suite_test.go b/controllers/ibpconsole/ibpconsole_suite_test.go index 6b6eb0d8..2b882446 100644 --- a/controllers/ibpconsole/ibpconsole_suite_test.go +++ b/controllers/ibpconsole/ibpconsole_suite_test.go @@ -21,7 +21,7 @@ package ibpconsole_test import ( "testing" - . "github.com/onsi/ginkgo" + . "github.com/onsi/ginkgo/v2" . "github.com/onsi/gomega" ) diff --git a/controllers/ibporderer/ibporderer_controller_test.go b/controllers/ibporderer/ibporderer_controller_test.go index 7480997b..6bbf45b7 100644 --- a/controllers/ibporderer/ibporderer_controller_test.go +++ b/controllers/ibporderer/ibporderer_controller_test.go @@ -26,7 +26,7 @@ import ( "sync" "time" - . "github.com/onsi/ginkgo" + . "github.com/onsi/ginkgo/v2" . "github.com/onsi/gomega" current "github.com/IBM-Blockchain/fabric-operator/api/v1beta1" diff --git a/controllers/ibporderer/ibporderer_suite_test.go b/controllers/ibporderer/ibporderer_suite_test.go index f0235965..1b5a40fd 100644 --- a/controllers/ibporderer/ibporderer_suite_test.go +++ b/controllers/ibporderer/ibporderer_suite_test.go @@ -21,7 +21,7 @@ package ibporderer_test import ( "testing" - . "github.com/onsi/ginkgo" + . "github.com/onsi/ginkgo/v2" . "github.com/onsi/gomega" ) diff --git a/controllers/ibporderer/predicate_test.go b/controllers/ibporderer/predicate_test.go index 776e8b97..ce118187 100644 --- a/controllers/ibporderer/predicate_test.go +++ b/controllers/ibporderer/predicate_test.go @@ -24,7 +24,7 @@ import ( "fmt" "sync" - . "github.com/onsi/ginkgo" + . "github.com/onsi/ginkgo/v2" . "github.com/onsi/gomega" current "github.com/IBM-Blockchain/fabric-operator/api/v1beta1" diff --git a/controllers/ibppeer/ibppeer_controller_test.go b/controllers/ibppeer/ibppeer_controller_test.go index ee5ab516..9f08ab21 100644 --- a/controllers/ibppeer/ibppeer_controller_test.go +++ b/controllers/ibppeer/ibppeer_controller_test.go @@ -24,7 +24,7 @@ import ( "fmt" "sync" - . "github.com/onsi/ginkgo" + . "github.com/onsi/ginkgo/v2" . "github.com/onsi/gomega" current "github.com/IBM-Blockchain/fabric-operator/api/v1beta1" diff --git a/controllers/ibppeer/ibppeer_suite_test.go b/controllers/ibppeer/ibppeer_suite_test.go index ddb226dd..aef38eea 100644 --- a/controllers/ibppeer/ibppeer_suite_test.go +++ b/controllers/ibppeer/ibppeer_suite_test.go @@ -21,7 +21,7 @@ package ibppeer_test import ( "testing" - . "github.com/onsi/ginkgo" + . "github.com/onsi/ginkgo/v2" . "github.com/onsi/gomega" ) diff --git a/controllers/suite_test.go b/controllers/suite_test.go index 1fb16213..4a7cc566 100644 --- a/controllers/suite_test.go +++ b/controllers/suite_test.go @@ -22,13 +22,12 @@ import ( "path/filepath" "testing" - . "github.com/onsi/ginkgo" + . "github.com/onsi/ginkgo/v2" . "github.com/onsi/gomega" "k8s.io/client-go/kubernetes/scheme" "k8s.io/client-go/rest" "sigs.k8s.io/controller-runtime/pkg/client" "sigs.k8s.io/controller-runtime/pkg/envtest" - "sigs.k8s.io/controller-runtime/pkg/envtest/printer" logf "sigs.k8s.io/controller-runtime/pkg/log" "sigs.k8s.io/controller-runtime/pkg/log/zap" @@ -45,13 +44,9 @@ var testEnv *envtest.Environment func TestAPIs(t *testing.T) { RegisterFailHandler(Fail) - - RunSpecsWithDefaultAndCustomReporters(t, - "Controller Suite", - []Reporter{printer.NewlineReporter{}}) } -var _ = BeforeSuite(func(done Done) { +var _ = BeforeSuite(func() { logf.SetLogger(zap.New()) By("bootstrapping test environment") @@ -81,9 +76,7 @@ var _ = BeforeSuite(func(done Done) { k8sClient, err = client.New(cfg, client.Options{Scheme: scheme.Scheme}) Expect(err).ToNot(HaveOccurred()) Expect(k8sClient).ToNot(BeNil()) - - close(done) -}, 60) +}) var _ = AfterSuite(func() { By("tearing down the test environment") diff --git a/docs/CONTRIBUTING.md b/docs/CONTRIBUTING.md index 539d52f8..15f38d84 100644 --- a/docs/CONTRIBUTING.md +++ b/docs/CONTRIBUTING.md @@ -1,3 +1,3 @@ # Contributing to this repository -## TODO \ No newline at end of file +## TODO diff --git a/go.mod b/go.mod index 8e882f12..f3ff8891 100644 --- a/go.mod +++ b/go.mod @@ -14,8 +14,8 @@ require ( github.com/imdario/mergo v0.3.12 github.com/lib/pq v1.8.0 github.com/maxbrunsfeld/counterfeiter/v6 v6.2.3 - github.com/onsi/ginkgo v1.16.4 - github.com/onsi/gomega v1.13.0 + github.com/onsi/ginkgo/v2 v2.1.4 + github.com/onsi/gomega v1.19.0 github.com/openshift/api v3.9.1-0.20190924102528-32369d4db2ad+incompatible github.com/operator-framework/operator-lib v0.8.0 github.com/pkg/errors v0.9.1 @@ -94,6 +94,7 @@ require ( github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect github.com/modern-go/reflect2 v1.0.1 // indirect github.com/nxadm/tail v1.4.8 // indirect + github.com/onsi/ginkgo v1.16.4 // indirect github.com/op/go-logging v0.0.0-20160315200505-970db520ece7 // indirect github.com/pelletier/go-toml v1.2.0 // indirect github.com/pierrec/lz4 v2.6.1+incompatible // indirect @@ -115,15 +116,15 @@ require ( github.com/zmap/zlint v0.0.0-20190806154020-fd021b4cfbeb // indirect go.uber.org/atomic v1.7.0 // indirect go.uber.org/multierr v1.6.0 // indirect - golang.org/x/crypto v0.0.0-20210920023735-84f357641f63 // indirect - golang.org/x/mod v0.4.2 // indirect - golang.org/x/net v0.0.0-20210917221730-978cfadd31cf // indirect + golang.org/x/crypto v0.0.0-20210921155107-089bfa567519 // indirect + golang.org/x/mod v0.6.0-dev.0.20220106191415-9b9b3d81d5e3 // indirect + golang.org/x/net v0.0.0-20220225172249-27dd8689420f // indirect golang.org/x/oauth2 v0.0.0-20200107190931-bf48bf16ab8d // indirect - golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1 // indirect - golang.org/x/term v0.0.0-20210220032956-6a3ed077a48d // indirect + golang.org/x/sys v0.0.0-20220319134239-a9b59b0215f8 // indirect + golang.org/x/term v0.0.0-20210927222741-03fcf44c2211 // indirect golang.org/x/text v0.3.7 // indirect golang.org/x/time v0.0.0-20210220033141-f8bda1e9f3ba // indirect - golang.org/x/tools v0.1.2 // indirect + golang.org/x/tools v0.1.10 // indirect golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1 // indirect gomodules.xyz/jsonpatch/v2 v2.2.0 // indirect google.golang.org/appengine v1.6.7 // indirect diff --git a/go.sum b/go.sum index 749d2c99..4d80c22c 100644 --- a/go.sum +++ b/go.sum @@ -252,6 +252,7 @@ github.com/google/pprof v0.0.0-20200212024743-f11f1df84d12/go.mod h1:ZgVRPoUq/hf github.com/google/pprof v0.0.0-20200229191704-1ebb73c60ed3/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM= github.com/google/pprof v0.0.0-20200430221834-fc25d7d30c6d/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM= github.com/google/pprof v0.0.0-20200507031123-427632fa3b1c/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM= +github.com/google/pprof v0.0.0-20210407192527-94a9f03dee38/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE= github.com/google/renameio v0.1.0/go.mod h1:KWCgfxg9yswjAJkECMjeO8J8rahYeXnNhOm40UhjYkI= github.com/google/uuid v1.0.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= github.com/google/uuid v1.1.1/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= @@ -320,6 +321,7 @@ github.com/hyperledger/fabric-lib-go v1.0.0/go.mod h1:H362nMlunurmHwkYqR5uHL2UDW github.com/hyperledger/fabric-protos-go v0.0.0-20200113171556-368e201877dd h1:dv8PcTulQ2/DEio+3NzUVy17A1YYt+0VaXnQ4FnjAKE= github.com/hyperledger/fabric-protos-go v0.0.0-20200113171556-368e201877dd/go.mod h1:xVYTjK4DtZRBxZ2D9aE4y6AbLaPwue2o/criQyQbVD0= github.com/ianlancetaylor/demangle v0.0.0-20181102032728-5e5cf60278f6/go.mod h1:aSSvb/t6k1mPoxDqO4vJh6VOCGPwU4O0C2/Eqndh1Sc= +github.com/ianlancetaylor/demangle v0.0.0-20200824232613-28f6c0f3b639/go.mod h1:aSSvb/t6k1mPoxDqO4vJh6VOCGPwU4O0C2/Eqndh1Sc= github.com/imdario/mergo v0.3.5/go.mod h1:2EnlNZ0deacrJVfApfmtdGgDfMuh/nq6Ok1EcJh5FfA= github.com/imdario/mergo v0.3.12 h1:b6R2BslTbIEToALKP7LxUvijTsNI9TAe80pLWN2g/HU= github.com/imdario/mergo v0.3.12/go.mod h1:jmQim1M+e3UYxmgPu/WyfjB3N3VflVyUjjjwH0dnCYA= @@ -455,14 +457,19 @@ github.com/onsi/ginkgo v1.14.2/go.mod h1:iSB4RoI2tjJc9BBv4NKIKWKya62Rps+oPG/Lv9k github.com/onsi/ginkgo v1.16.2/go.mod h1:CObGmKUOKaSC0RjmoAK7tKyn4Azo5P2IWuoMnvwxz1E= github.com/onsi/ginkgo v1.16.4 h1:29JGrr5oVBm5ulCWet69zQkzWipVXIol6ygQUe/EzNc= github.com/onsi/ginkgo v1.16.4/go.mod h1:dX+/inL/fNMqNlz0e9LfyB9TswhZpCVdJM/Z6Vvnwo0= +github.com/onsi/ginkgo/v2 v2.1.3/go.mod h1:vw5CSIxN1JObi/U8gcbwft7ZxR2dgaR70JSE3/PpL4c= +github.com/onsi/ginkgo/v2 v2.1.4 h1:GNapqRSid3zijZ9H77KrgVG4/8KqiyRsxcSxe+7ApXY= +github.com/onsi/ginkgo/v2 v2.1.4/go.mod h1:um6tUpWM/cxCK3/FK8BXqEiUMUwRgSM4JXG47RKZmLU= github.com/onsi/gomega v0.0.0-20170829124025-dcabb60a477c/go.mod h1:C1qb7wdrVGGVU+Z6iS04AVkA3Q65CEZX59MT0QO5uiA= github.com/onsi/gomega v1.7.0/go.mod h1:ex+gbHU/CVuBBDIJjb2X0qEXbFg53c61hWP/1CpauHY= github.com/onsi/gomega v1.7.1/go.mod h1:XdKZgCCFLUoM/7CFJVPcG8C1xQ1AJ0vpAezJrB7JYyY= github.com/onsi/gomega v1.9.0/go.mod h1:Ho0h+IUsWyvy1OpqCwxlQ/21gkhVunqlU8fDGcoTdcA= github.com/onsi/gomega v1.10.1/go.mod h1:iN09h71vgCQne3DLsj+A5owkum+a2tYe+TOCB1ybHNo= github.com/onsi/gomega v1.10.3/go.mod h1:V9xEwhxec5O8UDM77eCW8vLymOMltsqPVYWrpDsH8xc= -github.com/onsi/gomega v1.13.0 h1:7lLHu94wT9Ij0o6EWWclhu0aOh32VxhkwEJvzuWPeak= github.com/onsi/gomega v1.13.0/go.mod h1:lRk9szgn8TxENtWd0Tp4c3wjlRfMTMH27I+3Je41yGY= +github.com/onsi/gomega v1.17.0/go.mod h1:HnhC7FXeEQY45zxNK3PPoIUhzk/80Xly9PcubAlGdZY= +github.com/onsi/gomega v1.19.0 h1:4ieX6qQjPP/BfC3mpsAtIGGlxTWPeA3Inl/7DtXw1tw= +github.com/onsi/gomega v1.19.0/go.mod h1:LY+I3pBVzYsTBU1AnDwOSxaYi9WoWiqgwooUqq9yPro= github.com/op/go-logging v0.0.0-20160315200505-970db520ece7 h1:lDH9UUVJtmYCjyT0CI4q8xvlXPxeZ0gYCVvWbmPlp88= github.com/op/go-logging v0.0.0-20160315200505-970db520ece7/go.mod h1:HzydrMdWErDVzsI23lYNej1Htcns9BCg93Dk0bBINWk= github.com/openshift/api v3.9.1-0.20190924102528-32369d4db2ad+incompatible h1:6il8W875Oq9vycPkRV5TteLP9IfMEX3lyOl5yN+CtdI= @@ -576,6 +583,7 @@ github.com/yuin/goldmark v1.1.25/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9de github.com/yuin/goldmark v1.1.27/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= github.com/yuin/goldmark v1.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= github.com/yuin/goldmark v1.3.5/go.mod h1:mwnBkeHKe2W/ZEtQ+71ViKU8L12m81fl3OWwC1Zlc8k= +github.com/yuin/goldmark v1.4.1/go.mod h1:mwnBkeHKe2W/ZEtQ+71ViKU8L12m81fl3OWwC1Zlc8k= github.com/ziutek/mymysql v1.5.4/go.mod h1:LMSpPZ6DbqWFxNCHW77HeMg9I646SAhApZ/wKdgO/C0= github.com/zmap/rc2 v0.0.0-20131011165748-24b9757f5521/go.mod h1:3YZ9o3WnatTIZhuOtot4IcUfzoKVjUHqu6WALIyI0nE= github.com/zmap/zcertificate v0.0.0-20180516150559-0e3d58b1bac4/go.mod h1:5iU54tB79AMBcySS0R2XIyZBAVmeHranShAFELYx7is= @@ -622,8 +630,9 @@ golang.org/x/crypto v0.0.0-20201002170205-7f63de1d35b0/go.mod h1:LzIPMQfyMNhhGPh golang.org/x/crypto v0.0.0-20201112155050-0c6587e931a9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= golang.org/x/crypto v0.0.0-20201117144127-c1f2f97bffc9/go.mod h1:jdWPYTVW3xRLrWPugEBEK3UY2ZEsg3UU495nc5E+M+I= golang.org/x/crypto v0.0.0-20210220033148-5ea612d1eb83/go.mod h1:jdWPYTVW3xRLrWPugEBEK3UY2ZEsg3UU495nc5E+M+I= -golang.org/x/crypto v0.0.0-20210920023735-84f357641f63 h1:kETrAMYZq6WVGPa8IIixL0CaEcIUNi+1WX7grUoi3y8= golang.org/x/crypto v0.0.0-20210920023735-84f357641f63/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc= +golang.org/x/crypto v0.0.0-20210921155107-089bfa567519 h1:7I4JAnoQBe7ZtJcBaYHi5UtiO8tQHbUSXxL+pnGRANg= +golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc= golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= golang.org/x/exp v0.0.0-20190306152737-a1d7652674e8/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= golang.org/x/exp v0.0.0-20190510132918-efd6b22b2522/go.mod h1:ZjyILWgesfNpC6sMxTJOJm9Kp84zZh5NQWvqDGG3Qr8= @@ -656,8 +665,9 @@ golang.org/x/mod v0.1.1-0.20191107180719-034126e5016b/go.mod h1:QqPTAvyqsEbceGzB golang.org/x/mod v0.2.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= golang.org/x/mod v0.3.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= golang.org/x/mod v0.3.1-0.20200828183125-ce943fd02449/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= -golang.org/x/mod v0.4.2 h1:Gz96sIWK3OalVv/I/qNygP42zyoKp3xptRVCWRFEBvo= golang.org/x/mod v0.4.2/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= +golang.org/x/mod v0.6.0-dev.0.20220106191415-9b9b3d81d5e3 h1:kQgndtyPBW/JIYERgdxfwMYh3AVStj88WQTlNDi2a+o= +golang.org/x/mod v0.6.0-dev.0.20220106191415-9b9b3d81d5e3/go.mod h1:3p9vT2HGsQu2K1YbXdKPJLVgG5VJdoTa1poYQBtP1AY= golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20180826012351-8a410e7b638d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20180906233101-161cd47e91fd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= @@ -696,8 +706,10 @@ golang.org/x/net v0.0.0-20210224082022-3d97a244fca7/go.mod h1:m0MpNAwzfU5UDzcl9v golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg= golang.org/x/net v0.0.0-20210405180319-a5a99cb37ef4/go.mod h1:p54w0d4576C0XHj96bSt6lcn1PtDYWL6XObtHCRCNQM= golang.org/x/net v0.0.0-20210428140749-89ef3d95e781/go.mod h1:OJAsFXCWl8Ukc7SiCT/9KSuxbyM7479/AVlXFRxuMCk= -golang.org/x/net v0.0.0-20210917221730-978cfadd31cf h1:R150MpwJIv1MpS0N/pc+NhTM8ajzvlmxlY5OYsrevXQ= golang.org/x/net v0.0.0-20210917221730-978cfadd31cf/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= +golang.org/x/net v0.0.0-20211015210444-4f30a5c0130f/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= +golang.org/x/net v0.0.0-20220225172249-27dd8689420f h1:oA4XRj0qtSt8Yo1Zms0CUlsT3KG69V2UGQWPBxujDmc= +golang.org/x/net v0.0.0-20220225172249-27dd8689420f/go.mod h1:CfG3xpIq0wQ8r1q4Su4UZFWDARRcnwPjda9FqA0JpMk= golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= golang.org/x/oauth2 v0.0.0-20190226205417-e64efc72b421/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= golang.org/x/oauth2 v0.0.0-20190604053449-0f29369cfe45/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= @@ -768,12 +780,16 @@ golang.org/x/sys v0.0.0-20210330210617-4fbd30eecc44/go.mod h1:h1NjWce9XRLGQEsW7w golang.org/x/sys v0.0.0-20210423082822-04245dca01da/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210426230700-d19ff857e887/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210510120138-977fb7262007/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1 h1:SrN+KX8Art/Sf4HNj6Zcz06G7VEz+7w9tdXTPOZ7+l4= golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20211019181941-9d821ace8654/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20211216021012-1d35b9e2eb4e/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20220319134239-a9b59b0215f8 h1:OH54vjqzRWmbJ62fjuhxy7AxFFgoHN0/DPc/UrL8cAs= +golang.org/x/sys v0.0.0-20220319134239-a9b59b0215f8/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/term v0.0.0-20201117132131-f5c789dd3221/go.mod h1:Nr5EML6q2oocZ2LXRh80K7BxOlk5/8JxuGnuhpl+muw= golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= -golang.org/x/term v0.0.0-20210220032956-6a3ed077a48d h1:SZxvLBoTP5yHO3Frd4z4vrF+DBX9vMVanchswa69toE= golang.org/x/term v0.0.0-20210220032956-6a3ed077a48d/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= +golang.org/x/term v0.0.0-20210927222741-03fcf44c2211 h1:JGgROgKl9N8DuW20oFS5gxc+lE67/N3FcwmBPMe7ArY= +golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8= golang.org/x/text v0.0.0-20170915032832-14c0d48ead0c/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.1-0.20180807135948-17ff2d5776d2/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= @@ -843,8 +859,9 @@ golang.org/x/tools v0.0.0-20200622203043-20e05c1c8ffa/go.mod h1:EkVYQZoAsY45+roY golang.org/x/tools v0.0.0-20201224043029-2b0845dc783e/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= golang.org/x/tools v0.0.0-20210106214847-113979e3529a/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= golang.org/x/tools v0.1.0/go.mod h1:xkSsbof2nBLbhDlRMhhhyNLN/zl3eTqcnHD5viDpcZ0= -golang.org/x/tools v0.1.2 h1:kRBLX7v7Af8W7Gdbbc908OJcdgtK8bOz9Uaj8/F1ACA= golang.org/x/tools v0.1.2/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk= +golang.org/x/tools v0.1.10 h1:QjFRCZxdOhBJ/UNgnBZLbNV13DlbnK0quyivTnXJM20= +golang.org/x/tools v0.1.10/go.mod h1:Uh6Zz+xoGYZom868N8YTex3t7RhtHDBrE8Gzo9bV56E= golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= diff --git a/integration/actions/ca/ca_suite_test.go b/integration/actions/ca/ca_suite_test.go index 02bc9899..57118d5a 100644 --- a/integration/actions/ca/ca_suite_test.go +++ b/integration/actions/ca/ca_suite_test.go @@ -26,7 +26,7 @@ import ( "testing" "time" - . "github.com/onsi/ginkgo" + . "github.com/onsi/ginkgo/v2" . "github.com/onsi/gomega" "github.com/onsi/gomega/gexec" diff --git a/integration/actions/ca/ca_test.go b/integration/actions/ca/ca_test.go index 783b19cc..ae47a614 100644 --- a/integration/actions/ca/ca_test.go +++ b/integration/actions/ca/ca_test.go @@ -39,7 +39,7 @@ import ( "github.com/IBM-Blockchain/fabric-operator/pkg/offering/common" "github.com/IBM-Blockchain/fabric-operator/pkg/util" "github.com/IBM-Blockchain/fabric-operator/pkg/util/pointer" - . "github.com/onsi/ginkgo" + . "github.com/onsi/ginkgo/v2" . "github.com/onsi/gomega" "github.com/pkg/errors" corev1 "k8s.io/api/core/v1" diff --git a/integration/actions/orderer/orderer_suite_test.go b/integration/actions/orderer/orderer_suite_test.go index 7dada9e0..cad59b43 100644 --- a/integration/actions/orderer/orderer_suite_test.go +++ b/integration/actions/orderer/orderer_suite_test.go @@ -27,7 +27,7 @@ import ( "testing" "time" - . "github.com/onsi/ginkgo" + . "github.com/onsi/ginkgo/v2" . "github.com/onsi/gomega" "github.com/onsi/gomega/gexec" diff --git a/integration/actions/orderer/orderer_test.go b/integration/actions/orderer/orderer_test.go index 9d6570b5..2990db1b 100644 --- a/integration/actions/orderer/orderer_test.go +++ b/integration/actions/orderer/orderer_test.go @@ -26,7 +26,7 @@ import ( "fmt" "time" - . "github.com/onsi/ginkgo" + . "github.com/onsi/ginkgo/v2" . "github.com/onsi/gomega" "sigs.k8s.io/controller-runtime/pkg/client" diff --git a/integration/actions/peer/peer_suite_test.go b/integration/actions/peer/peer_suite_test.go index 82ac606e..94e79f12 100644 --- a/integration/actions/peer/peer_suite_test.go +++ b/integration/actions/peer/peer_suite_test.go @@ -29,7 +29,7 @@ import ( "testing" "time" - . "github.com/onsi/ginkgo" + . "github.com/onsi/ginkgo/v2" . "github.com/onsi/gomega" "github.com/onsi/gomega/gexec" diff --git a/integration/actions/peer/peer_test.go b/integration/actions/peer/peer_test.go index bed58697..444d75fe 100644 --- a/integration/actions/peer/peer_test.go +++ b/integration/actions/peer/peer_test.go @@ -25,7 +25,7 @@ import ( "encoding/json" "fmt" - . "github.com/onsi/ginkgo" + . "github.com/onsi/ginkgo/v2" . "github.com/onsi/gomega" "sigs.k8s.io/controller-runtime/pkg/client" diff --git a/integration/actions/peer/reenroll_test.go b/integration/actions/peer/reenroll_test.go index c5657d32..556d63e8 100644 --- a/integration/actions/peer/reenroll_test.go +++ b/integration/actions/peer/reenroll_test.go @@ -24,7 +24,7 @@ import ( "fmt" "time" - . "github.com/onsi/ginkgo" + . "github.com/onsi/ginkgo/v2" . "github.com/onsi/gomega" "sigs.k8s.io/controller-runtime/pkg/client" diff --git a/integration/autorenew/autorenew_suite_test.go b/integration/autorenew/autorenew_suite_test.go index 04c099ba..6fdf88f5 100644 --- a/integration/autorenew/autorenew_suite_test.go +++ b/integration/autorenew/autorenew_suite_test.go @@ -29,7 +29,7 @@ import ( "testing" "time" - . "github.com/onsi/ginkgo" + . "github.com/onsi/ginkgo/v2" . "github.com/onsi/gomega" "github.com/onsi/gomega/gexec" diff --git a/integration/autorenew/autorenew_test.go b/integration/autorenew/autorenew_test.go index f69a6498..ea27a19d 100644 --- a/integration/autorenew/autorenew_test.go +++ b/integration/autorenew/autorenew_test.go @@ -29,7 +29,7 @@ import ( current "github.com/IBM-Blockchain/fabric-operator/api/v1beta1" "github.com/IBM-Blockchain/fabric-operator/integration/helper" "github.com/IBM-Blockchain/fabric-operator/pkg/offering/common" - . "github.com/onsi/ginkgo" + . "github.com/onsi/ginkgo/v2" . "github.com/onsi/gomega" k8serrors "k8s.io/apimachinery/pkg/api/errors" diff --git a/integration/ca/ca_suite_test.go b/integration/ca/ca_suite_test.go index 275a9a29..0119afc4 100644 --- a/integration/ca/ca_suite_test.go +++ b/integration/ca/ca_suite_test.go @@ -28,7 +28,7 @@ import ( "github.com/IBM-Blockchain/fabric-operator/integration" "github.com/IBM-Blockchain/fabric-operator/integration/helper" ibpclient "github.com/IBM-Blockchain/fabric-operator/pkg/client" - . "github.com/onsi/ginkgo" + . "github.com/onsi/ginkgo/v2" . "github.com/onsi/gomega" corev1 "k8s.io/api/core/v1" "k8s.io/apimachinery/pkg/api/resource" diff --git a/integration/ca/ca_test.go b/integration/ca/ca_test.go index 2627f8af..0e6f86b6 100644 --- a/integration/ca/ca_test.go +++ b/integration/ca/ca_test.go @@ -33,7 +33,7 @@ import ( v1 "github.com/IBM-Blockchain/fabric-operator/pkg/apis/ca/v1" "github.com/IBM-Blockchain/fabric-operator/pkg/util" "github.com/IBM-Blockchain/fabric-operator/pkg/util/pointer" - . "github.com/onsi/ginkgo" + . "github.com/onsi/ginkgo/v2" . "github.com/onsi/gomega" appsv1 "k8s.io/api/apps/v1" corev1 "k8s.io/api/core/v1" diff --git a/integration/cclauncher/cclauncher_suite_test.go b/integration/cclauncher/cclauncher_suite_test.go index 26be1ba0..2e1382da 100644 --- a/integration/cclauncher/cclauncher_suite_test.go +++ b/integration/cclauncher/cclauncher_suite_test.go @@ -29,7 +29,7 @@ import ( "testing" "time" - . "github.com/onsi/ginkgo" + . "github.com/onsi/ginkgo/v2" . "github.com/onsi/gomega" "github.com/onsi/gomega/gexec" diff --git a/integration/cclauncher/cclauncher_test.go b/integration/cclauncher/cclauncher_test.go index 5ca4e655..0c20cc4d 100644 --- a/integration/cclauncher/cclauncher_test.go +++ b/integration/cclauncher/cclauncher_test.go @@ -22,7 +22,7 @@ import ( "context" "fmt" - . "github.com/onsi/ginkgo" + . "github.com/onsi/ginkgo/v2" . "github.com/onsi/gomega" v2 "github.com/IBM-Blockchain/fabric-operator/pkg/apis/peer/v2" diff --git a/integration/console/console_suite_test.go b/integration/console/console_suite_test.go index 59728c38..7ae1ec82 100644 --- a/integration/console/console_suite_test.go +++ b/integration/console/console_suite_test.go @@ -26,7 +26,7 @@ import ( "github.com/IBM-Blockchain/fabric-operator/integration" ibpclient "github.com/IBM-Blockchain/fabric-operator/pkg/client" - . "github.com/onsi/ginkgo" + . "github.com/onsi/ginkgo/v2" . "github.com/onsi/gomega" k8serrors "k8s.io/apimachinery/pkg/api/errors" "k8s.io/client-go/kubernetes" diff --git a/integration/console/console_test.go b/integration/console/console_test.go index 40a6f813..3c137f04 100644 --- a/integration/console/console_test.go +++ b/integration/console/console_test.go @@ -24,7 +24,7 @@ import ( "math/rand" "time" - . "github.com/onsi/ginkgo" + . "github.com/onsi/ginkgo/v2" . "github.com/onsi/gomega" appsv1 "k8s.io/api/apps/v1" corev1 "k8s.io/api/core/v1" diff --git a/integration/e2ev2/ca_test.go b/integration/e2ev2/ca_test.go index 1bc9a05e..3f84ee73 100644 --- a/integration/e2ev2/ca_test.go +++ b/integration/e2ev2/ca_test.go @@ -19,7 +19,7 @@ package e2ev2_test import ( - . "github.com/onsi/ginkgo" + . "github.com/onsi/ginkgo/v2" . "github.com/onsi/gomega" current "github.com/IBM-Blockchain/fabric-operator/api/v1beta1" diff --git a/integration/e2ev2/console_test.go b/integration/e2ev2/console_test.go index 72be55e4..72af43ca 100644 --- a/integration/e2ev2/console_test.go +++ b/integration/e2ev2/console_test.go @@ -24,7 +24,7 @@ import ( "math/rand" "time" - . "github.com/onsi/ginkgo" + . "github.com/onsi/ginkgo/v2" . "github.com/onsi/gomega" current "github.com/IBM-Blockchain/fabric-operator/api/v1beta1" diff --git a/integration/e2ev2/e2ev2_suite_test.go b/integration/e2ev2/e2ev2_suite_test.go index d5d64218..6ed738e2 100644 --- a/integration/e2ev2/e2ev2_suite_test.go +++ b/integration/e2ev2/e2ev2_suite_test.go @@ -32,7 +32,7 @@ import ( "github.com/IBM-Blockchain/fabric-operator/integration" "github.com/IBM-Blockchain/fabric-operator/integration/helper" "github.com/IBM-Blockchain/fabric-operator/pkg/util" - . "github.com/onsi/ginkgo" + . "github.com/onsi/ginkgo/v2" . "github.com/onsi/gomega" "github.com/onsi/gomega/gexec" diff --git a/integration/e2ev2/orderer_test.go b/integration/e2ev2/orderer_test.go index 1ea7ed53..a1cc3283 100644 --- a/integration/e2ev2/orderer_test.go +++ b/integration/e2ev2/orderer_test.go @@ -26,7 +26,7 @@ import ( "fmt" "time" - . "github.com/onsi/ginkgo" + . "github.com/onsi/ginkgo/v2" . "github.com/onsi/gomega" "sigs.k8s.io/controller-runtime/pkg/client" diff --git a/integration/e2ev2/peer_test.go b/integration/e2ev2/peer_test.go index d76df336..b76e858f 100644 --- a/integration/e2ev2/peer_test.go +++ b/integration/e2ev2/peer_test.go @@ -23,7 +23,7 @@ import ( "encoding/json" "time" - . "github.com/onsi/ginkgo" + . "github.com/onsi/ginkgo/v2" . "github.com/onsi/gomega" current "github.com/IBM-Blockchain/fabric-operator/api/v1beta1" diff --git a/integration/helper/session.go b/integration/helper/session.go index 7ebc8d1e..4648058e 100644 --- a/integration/helper/session.go +++ b/integration/helper/session.go @@ -24,7 +24,7 @@ import ( "path/filepath" "strings" - "github.com/onsi/ginkgo" + "github.com/onsi/ginkgo/v2" "github.com/onsi/gomega/gexec" ) diff --git a/integration/init/init_suite_test.go b/integration/init/init_suite_test.go index 70c10775..6ad024a3 100644 --- a/integration/init/init_suite_test.go +++ b/integration/init/init_suite_test.go @@ -21,7 +21,7 @@ package init_test import ( "testing" - . "github.com/onsi/ginkgo" + . "github.com/onsi/ginkgo/v2" . "github.com/onsi/gomega" ) diff --git a/integration/init/init_test.go b/integration/init/init_test.go index deaad1ad..b1f22a87 100644 --- a/integration/init/init_test.go +++ b/integration/init/init_test.go @@ -28,7 +28,7 @@ import ( cfconfig "github.com/cloudflare/cfssl/config" "github.com/hyperledger/fabric-ca/lib" "github.com/hyperledger/fabric-ca/lib/tls" - . "github.com/onsi/ginkgo" + . "github.com/onsi/ginkgo/v2" . "github.com/onsi/gomega" corev1 "k8s.io/api/core/v1" "k8s.io/apimachinery/pkg/runtime" diff --git a/integration/init/orderer_test.go b/integration/init/orderer_test.go index 180f6abd..82fa06e7 100644 --- a/integration/init/orderer_test.go +++ b/integration/init/orderer_test.go @@ -29,7 +29,7 @@ import ( ordererconfig "github.com/IBM-Blockchain/fabric-operator/pkg/initializer/orderer/config/v1" baseorderer "github.com/IBM-Blockchain/fabric-operator/pkg/offering/base/orderer" "github.com/IBM-Blockchain/fabric-operator/pkg/offering/base/peer/mocks" - . "github.com/onsi/ginkgo" + . "github.com/onsi/ginkgo/v2" . "github.com/onsi/gomega" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" ) diff --git a/integration/init/peer_test.go b/integration/init/peer_test.go index b726213b..363941e0 100644 --- a/integration/init/peer_test.go +++ b/integration/init/peer_test.go @@ -34,7 +34,7 @@ import ( "github.com/IBM-Blockchain/fabric-operator/pkg/initializer/validator" basepeer "github.com/IBM-Blockchain/fabric-operator/pkg/offering/base/peer" "github.com/IBM-Blockchain/fabric-operator/pkg/offering/base/peer/mocks" - . "github.com/onsi/ginkgo" + . "github.com/onsi/ginkgo/v2" . "github.com/onsi/gomega" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" ) diff --git a/integration/migration/fabric/fabric_suite_test.go b/integration/migration/fabric/fabric_suite_test.go index 902769b0..ccd13529 100644 --- a/integration/migration/fabric/fabric_suite_test.go +++ b/integration/migration/fabric/fabric_suite_test.go @@ -27,7 +27,7 @@ import ( "testing" "time" - . "github.com/onsi/ginkgo" + . "github.com/onsi/ginkgo/v2" . "github.com/onsi/gomega" "github.com/onsi/gomega/gexec" diff --git a/integration/migration/fabric/orderer_test.go b/integration/migration/fabric/orderer_test.go index ae1aeeea..342a3f07 100644 --- a/integration/migration/fabric/orderer_test.go +++ b/integration/migration/fabric/orderer_test.go @@ -24,7 +24,7 @@ import ( "encoding/json" "fmt" - . "github.com/onsi/ginkgo" + . "github.com/onsi/ginkgo/v2" . "github.com/onsi/gomega" current "github.com/IBM-Blockchain/fabric-operator/api/v1beta1" diff --git a/integration/migration/fabric/peer_test.go b/integration/migration/fabric/peer_test.go index 7186c66f..11f8e62e 100644 --- a/integration/migration/fabric/peer_test.go +++ b/integration/migration/fabric/peer_test.go @@ -28,7 +28,7 @@ import ( "github.com/IBM-Blockchain/fabric-operator/integration" "github.com/IBM-Blockchain/fabric-operator/integration/helper" "github.com/IBM-Blockchain/fabric-operator/version" - . "github.com/onsi/ginkgo" + . "github.com/onsi/ginkgo/v2" . "github.com/onsi/gomega" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" ) diff --git a/integration/migration/migration_suite_test.go b/integration/migration/migration_suite_test.go index 5306ce39..099b0ffa 100644 --- a/integration/migration/migration_suite_test.go +++ b/integration/migration/migration_suite_test.go @@ -27,7 +27,7 @@ import ( apis "github.com/IBM-Blockchain/fabric-operator/api" "github.com/IBM-Blockchain/fabric-operator/pkg/global" "github.com/IBM-Blockchain/fabric-operator/pkg/k8s/controllerclient" - . "github.com/onsi/ginkgo" + . "github.com/onsi/ginkgo/v2" . "github.com/onsi/gomega" corev1 "k8s.io/api/core/v1" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" diff --git a/integration/migration/migration_test.go b/integration/migration/migration_test.go index 06b3e2de..e57d8974 100644 --- a/integration/migration/migration_test.go +++ b/integration/migration/migration_test.go @@ -40,7 +40,7 @@ import ( "github.com/IBM-Blockchain/fabric-operator/pkg/migrator/initsecret" "github.com/IBM-Blockchain/fabric-operator/pkg/offering" "github.com/IBM-Blockchain/fabric-operator/version" - . "github.com/onsi/ginkgo" + . "github.com/onsi/ginkgo/v2" . "github.com/onsi/gomega" corev1 "k8s.io/api/core/v1" networkingv1 "k8s.io/api/networking/v1" diff --git a/integration/nativeresourcepoller.go b/integration/nativeresourcepoller.go index 6d480676..a4ca7be8 100644 --- a/integration/nativeresourcepoller.go +++ b/integration/nativeresourcepoller.go @@ -23,7 +23,7 @@ import ( "fmt" "strings" - . "github.com/onsi/ginkgo" + . "github.com/onsi/ginkgo/v2" appsv1 "k8s.io/api/apps/v1" corev1 "k8s.io/api/core/v1" diff --git a/integration/operatorrestart/operatorrestart_suite_test.go b/integration/operatorrestart/operatorrestart_suite_test.go index 874ab0e9..2aa5adcd 100644 --- a/integration/operatorrestart/operatorrestart_suite_test.go +++ b/integration/operatorrestart/operatorrestart_suite_test.go @@ -29,7 +29,7 @@ import ( "testing" "time" - . "github.com/onsi/ginkgo" + . "github.com/onsi/ginkgo/v2" . "github.com/onsi/gomega" "github.com/onsi/gomega/gexec" diff --git a/integration/operatorrestart/operatorrestart_test.go b/integration/operatorrestart/operatorrestart_test.go index 436f2d68..5f278213 100644 --- a/integration/operatorrestart/operatorrestart_test.go +++ b/integration/operatorrestart/operatorrestart_test.go @@ -23,7 +23,7 @@ import ( "time" "github.com/IBM-Blockchain/fabric-operator/integration/helper" - . "github.com/onsi/ginkgo" + . "github.com/onsi/ginkgo/v2" . "github.com/onsi/gomega" ) diff --git a/integration/orderer/orderer_suite_test.go b/integration/orderer/orderer_suite_test.go index 9fef120f..cc9785a2 100644 --- a/integration/orderer/orderer_suite_test.go +++ b/integration/orderer/orderer_suite_test.go @@ -29,7 +29,7 @@ import ( "github.com/IBM-Blockchain/fabric-operator/integration" "github.com/IBM-Blockchain/fabric-operator/integration/helper" ibpclient "github.com/IBM-Blockchain/fabric-operator/pkg/client" - . "github.com/onsi/ginkgo" + . "github.com/onsi/ginkgo/v2" . "github.com/onsi/gomega" "github.com/onsi/gomega/gexec" "k8s.io/client-go/kubernetes" diff --git a/integration/orderer/orderer_test.go b/integration/orderer/orderer_test.go index b4a89f87..79b0ce0a 100644 --- a/integration/orderer/orderer_test.go +++ b/integration/orderer/orderer_test.go @@ -37,7 +37,7 @@ import ( config "github.com/IBM-Blockchain/fabric-operator/pkg/initializer/orderer/config/v2" baseorderer "github.com/IBM-Blockchain/fabric-operator/pkg/offering/base/orderer" "github.com/IBM-Blockchain/fabric-operator/pkg/util" - . "github.com/onsi/ginkgo" + . "github.com/onsi/ginkgo/v2" . "github.com/onsi/gomega" appsv1 "k8s.io/api/apps/v1" corev1 "k8s.io/api/core/v1" diff --git a/integration/peer/peer_suite_test.go b/integration/peer/peer_suite_test.go index 75ded632..923efced 100644 --- a/integration/peer/peer_suite_test.go +++ b/integration/peer/peer_suite_test.go @@ -32,7 +32,7 @@ import ( "github.com/IBM-Blockchain/fabric-operator/integration" "github.com/IBM-Blockchain/fabric-operator/integration/helper" ibpclient "github.com/IBM-Blockchain/fabric-operator/pkg/client" - . "github.com/onsi/ginkgo" + . "github.com/onsi/ginkgo/v2" . "github.com/onsi/gomega" "github.com/onsi/gomega/gexec" corev1 "k8s.io/api/core/v1" diff --git a/integration/peer/peer_test.go b/integration/peer/peer_test.go index a735115b..aa9f7935 100644 --- a/integration/peer/peer_test.go +++ b/integration/peer/peer_test.go @@ -34,7 +34,7 @@ import ( v1 "github.com/IBM-Blockchain/fabric-operator/pkg/apis/peer/v1" v2 "github.com/IBM-Blockchain/fabric-operator/pkg/apis/peer/v2" config "github.com/IBM-Blockchain/fabric-operator/pkg/initializer/peer/config/v2" - . "github.com/onsi/ginkgo" + . "github.com/onsi/ginkgo/v2" . "github.com/onsi/gomega" appsv1 "k8s.io/api/apps/v1" corev1 "k8s.io/api/core/v1" diff --git a/integration/restartmgr/restartmgr_suite_test.go b/integration/restartmgr/restartmgr_suite_test.go index 40c8ef1a..28fa1f91 100644 --- a/integration/restartmgr/restartmgr_suite_test.go +++ b/integration/restartmgr/restartmgr_suite_test.go @@ -29,7 +29,7 @@ import ( "testing" "time" - . "github.com/onsi/ginkgo" + . "github.com/onsi/ginkgo/v2" . "github.com/onsi/gomega" "github.com/onsi/gomega/gexec" diff --git a/integration/restartmgr/restartmgr_test.go b/integration/restartmgr/restartmgr_test.go index c530dd59..75e06f51 100644 --- a/integration/restartmgr/restartmgr_test.go +++ b/integration/restartmgr/restartmgr_test.go @@ -33,7 +33,7 @@ import ( "github.com/IBM-Blockchain/fabric-operator/pkg/offering/common" "github.com/IBM-Blockchain/fabric-operator/pkg/restart" "github.com/IBM-Blockchain/fabric-operator/pkg/restart/staggerrestarts" - . "github.com/onsi/ginkgo" + . "github.com/onsi/ginkgo/v2" . "github.com/onsi/gomega" corev1 "k8s.io/api/core/v1" diff --git a/pkg/action/action_suite_test.go b/pkg/action/action_suite_test.go index 7f03718b..c7559c01 100644 --- a/pkg/action/action_suite_test.go +++ b/pkg/action/action_suite_test.go @@ -21,7 +21,7 @@ package action_test import ( "testing" - . "github.com/onsi/ginkgo" + . "github.com/onsi/ginkgo/v2" . "github.com/onsi/gomega" ) diff --git a/pkg/action/action_test.go b/pkg/action/action_test.go index 0226d400..64bcf111 100644 --- a/pkg/action/action_test.go +++ b/pkg/action/action_test.go @@ -21,7 +21,7 @@ package action_test import ( "errors" - . "github.com/onsi/ginkgo" + . "github.com/onsi/ginkgo/v2" . "github.com/onsi/gomega" appsv1 "k8s.io/api/apps/v1" diff --git a/pkg/action/enroll_test.go b/pkg/action/enroll_test.go index 3d5bbd0f..4681e295 100644 --- a/pkg/action/enroll_test.go +++ b/pkg/action/enroll_test.go @@ -19,7 +19,7 @@ package action_test import ( - . "github.com/onsi/ginkgo" + . "github.com/onsi/ginkgo/v2" . "github.com/onsi/gomega" "k8s.io/apimachinery/pkg/runtime" diff --git a/pkg/action/upgradedbs_test.go b/pkg/action/upgradedbs_test.go index 90f86b17..4fc06263 100644 --- a/pkg/action/upgradedbs_test.go +++ b/pkg/action/upgradedbs_test.go @@ -25,7 +25,7 @@ import ( controllermocks "github.com/IBM-Blockchain/fabric-operator/controllers/mocks" config "github.com/IBM-Blockchain/fabric-operator/operatorconfig" - . "github.com/onsi/ginkgo" + . "github.com/onsi/ginkgo/v2" . "github.com/onsi/gomega" appsv1 "k8s.io/api/apps/v1" batchv1 "k8s.io/api/batch/v1" diff --git a/pkg/certificate/certificate_suite_test.go b/pkg/certificate/certificate_suite_test.go index 5840f12e..d327bbb5 100644 --- a/pkg/certificate/certificate_suite_test.go +++ b/pkg/certificate/certificate_suite_test.go @@ -21,7 +21,7 @@ package certificate_test import ( "testing" - . "github.com/onsi/ginkgo" + . "github.com/onsi/ginkgo/v2" . "github.com/onsi/gomega" ) diff --git a/pkg/certificate/certificate_test.go b/pkg/certificate/certificate_test.go index 1a656c70..58d65208 100644 --- a/pkg/certificate/certificate_test.go +++ b/pkg/certificate/certificate_test.go @@ -35,7 +35,7 @@ import ( "github.com/IBM-Blockchain/fabric-operator/pkg/certificate/mocks" "github.com/IBM-Blockchain/fabric-operator/pkg/initializer/common" "github.com/IBM-Blockchain/fabric-operator/pkg/initializer/common/config" - . "github.com/onsi/ginkgo" + . "github.com/onsi/ginkgo/v2" . "github.com/onsi/gomega" corev1 "k8s.io/api/core/v1" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" diff --git a/pkg/certificate/reenroller/reenroller_suite_test.go b/pkg/certificate/reenroller/reenroller_suite_test.go index 2ba87ff9..94698fe5 100644 --- a/pkg/certificate/reenroller/reenroller_suite_test.go +++ b/pkg/certificate/reenroller/reenroller_suite_test.go @@ -19,9 +19,20 @@ package reenroller_test import ( + "encoding/pem" + "io/ioutil" + "net/http" + "net/http/httptest" + "net/url" + "os" + "path/filepath" "testing" - . "github.com/onsi/ginkgo" + current "github.com/IBM-Blockchain/fabric-operator/api/v1beta1" + "github.com/IBM-Blockchain/fabric-operator/pkg/certificate/reenroller" + "github.com/IBM-Blockchain/fabric-operator/pkg/certificate/reenroller/mocks" + "github.com/IBM-Blockchain/fabric-operator/pkg/util" + . "github.com/onsi/ginkgo/v2" . "github.com/onsi/gomega" ) @@ -29,3 +40,51 @@ func TestReenroller(t *testing.T) { RegisterFailHandler(Fail) RunSpecs(t, "Reenroller Suite") } + +var ( + err error + + testReenroller *reenroller.Reenroller + config *current.Enrollment + mockIdentity *mocks.Identity + + server *httptest.Server + serverCert string + serverURL string + serverUrlObj *url.URL +) + +var _ = BeforeSuite(func() { + // Start a local HTTP server + server = httptest.NewTLSServer(http.HandlerFunc(func(rw http.ResponseWriter, req *http.Request) { + // Test request parameters + Expect(req.URL.String()).To(Equal("/cainfo")) + return + })) + + serverURL = server.URL + rawCert := server.Certificate().Raw + pemCert := pem.EncodeToMemory(&pem.Block{Type: "CERTIFICATE", Bytes: rawCert}) + serverCert = string(util.BytesToBase64(pemCert)) + + urlObj, err := url.Parse(serverURL) + Expect(err).NotTo(HaveOccurred()) + serverUrlObj = urlObj + + // Generate temporary key for reenroll test + keystorePath := filepath.Join(homeDir, "msp", "keystore") + err = os.MkdirAll(keystorePath, 0755) + Expect(err).NotTo(HaveOccurred()) + + key, err := util.Base64ToBytes(testkey) + Expect(err).NotTo(HaveOccurred()) + err = ioutil.WriteFile(filepath.Join(keystorePath, "key.pem"), key, 0755) +}) + +var _ = AfterSuite(func() { + // Close the server when test finishes + server.Close() + + err = os.RemoveAll(homeDir) + Expect(err).NotTo(HaveOccurred()) +}) diff --git a/pkg/certificate/reenroller/reenroller_test.go b/pkg/certificate/reenroller/reenroller_test.go index 956c33b4..30998e68 100644 --- a/pkg/certificate/reenroller/reenroller_test.go +++ b/pkg/certificate/reenroller/reenroller_test.go @@ -19,25 +19,17 @@ package reenroller_test import ( - "encoding/pem" "fmt" - "io/ioutil" - "net/http" - "net/http/httptest" - "net/url" - "os" - "path/filepath" "time" current "github.com/IBM-Blockchain/fabric-operator/api/v1beta1" "github.com/IBM-Blockchain/fabric-operator/pkg/certificate/reenroller" "github.com/IBM-Blockchain/fabric-operator/pkg/certificate/reenroller/mocks" - "github.com/IBM-Blockchain/fabric-operator/pkg/util" "github.com/hyperledger/fabric-ca/lib" "github.com/hyperledger/fabric-ca/lib/client/credential" fabricx509 "github.com/hyperledger/fabric-ca/lib/client/credential/x509" "github.com/hyperledger/fabric-ca/lib/tls" - . "github.com/onsi/ginkgo" + . "github.com/onsi/ginkgo/v2" . "github.com/onsi/gomega" "github.com/pkg/errors" ) @@ -48,46 +40,6 @@ const ( ) var _ = Describe("Reenroller", func() { - var ( - err error - - testReenroller *reenroller.Reenroller - config *current.Enrollment - mockIdentity *mocks.Identity - - server *httptest.Server - serverURL string - serverCert string - serverUrlObj *url.URL - ) - - BeforeSuite(func() { - // Start a local HTTP server - server = httptest.NewTLSServer(http.HandlerFunc(func(rw http.ResponseWriter, req *http.Request) { - // Test request parameters - Expect(req.URL.String()).To(Equal("/cainfo")) - return - })) - - serverURL = server.URL - rawCert := server.Certificate().Raw - pemCert := pem.EncodeToMemory(&pem.Block{Type: "CERTIFICATE", Bytes: rawCert}) - serverCert = string(util.BytesToBase64(pemCert)) - - urlObj, err := url.Parse(serverURL) - Expect(err).NotTo(HaveOccurred()) - serverUrlObj = urlObj - - // Generate temporary key for reenroll test - keystorePath := filepath.Join(homeDir, "msp", "keystore") - err = os.MkdirAll(keystorePath, 0755) - Expect(err).NotTo(HaveOccurred()) - - key, err := util.Base64ToBytes(testkey) - Expect(err).NotTo(HaveOccurred()) - err = ioutil.WriteFile(filepath.Join(keystorePath, "key.pem"), key, 0755) - }) - BeforeEach(func() { mockIdentity = &mocks.Identity{} @@ -132,14 +84,6 @@ var _ = Describe("Reenroller", func() { }, nil) }) - AfterSuite(func() { - // Close the server when test finishes - server.Close() - - err = os.RemoveAll(homeDir) - Expect(err).NotTo(HaveOccurred()) - }) - Context("Enrollment configuration validation", func() { It("returns an error if missing CA host", func() { config.CAHost = "" diff --git a/pkg/client/client_suite_test.go b/pkg/client/client_suite_test.go index 101c1adf..ebb2eafb 100644 --- a/pkg/client/client_suite_test.go +++ b/pkg/client/client_suite_test.go @@ -21,7 +21,7 @@ package client_test import ( "testing" - . "github.com/onsi/ginkgo" + . "github.com/onsi/ginkgo/v2" . "github.com/onsi/gomega" ) diff --git a/pkg/client/client_test.go b/pkg/client/client_test.go index ba1e13be..0f8d8501 100644 --- a/pkg/client/client_test.go +++ b/pkg/client/client_test.go @@ -19,7 +19,7 @@ package client import ( - . "github.com/onsi/ginkgo" + . "github.com/onsi/ginkgo/v2" . "github.com/onsi/gomega" "k8s.io/client-go/rest" ) diff --git a/pkg/command/command_suite_test.go b/pkg/command/command_suite_test.go index d4e797d5..a3b563ab 100644 --- a/pkg/command/command_suite_test.go +++ b/pkg/command/command_suite_test.go @@ -21,7 +21,7 @@ package command_test import ( "testing" - . "github.com/onsi/ginkgo" + . "github.com/onsi/ginkgo/v2" . "github.com/onsi/gomega" ) diff --git a/pkg/command/operator_test.go b/pkg/command/operator_test.go index 51291ec6..0c2490a6 100644 --- a/pkg/command/operator_test.go +++ b/pkg/command/operator_test.go @@ -21,7 +21,7 @@ package command_test import ( "os" - . "github.com/onsi/ginkgo" + . "github.com/onsi/ginkgo/v2" . "github.com/onsi/gomega" oconfig "github.com/IBM-Blockchain/fabric-operator/operatorconfig" diff --git a/pkg/crd/crd_suite_test.go b/pkg/crd/crd_suite_test.go index 8f0fc7ba..e5c03419 100644 --- a/pkg/crd/crd_suite_test.go +++ b/pkg/crd/crd_suite_test.go @@ -21,7 +21,7 @@ package crd_test import ( "testing" - . "github.com/onsi/ginkgo" + . "github.com/onsi/ginkgo/v2" . "github.com/onsi/gomega" ) diff --git a/pkg/crd/manager_test.go b/pkg/crd/manager_test.go index 62085427..148f326e 100644 --- a/pkg/crd/manager_test.go +++ b/pkg/crd/manager_test.go @@ -23,7 +23,7 @@ import ( "github.com/IBM-Blockchain/fabric-operator/pkg/crd" "github.com/IBM-Blockchain/fabric-operator/pkg/crd/mocks" - . "github.com/onsi/ginkgo" + . "github.com/onsi/ginkgo/v2" . "github.com/onsi/gomega" ) diff --git a/pkg/global/config_test.go b/pkg/global/config_test.go index de6ab852..7b088515 100644 --- a/pkg/global/config_test.go +++ b/pkg/global/config_test.go @@ -19,7 +19,7 @@ package global_test import ( - . "github.com/onsi/ginkgo" + . "github.com/onsi/ginkgo/v2" . "github.com/onsi/gomega" . "github.com/onsi/gomega/gstruct" diff --git a/pkg/global/global_suite_test.go b/pkg/global/global_suite_test.go index 9cb833d2..a17cec59 100644 --- a/pkg/global/global_suite_test.go +++ b/pkg/global/global_suite_test.go @@ -21,7 +21,7 @@ package global_test import ( "testing" - . "github.com/onsi/ginkgo" + . "github.com/onsi/ginkgo/v2" . "github.com/onsi/gomega" ) diff --git a/pkg/initializer/ca/ca_suite_test.go b/pkg/initializer/ca/ca_suite_test.go index 3fe60afd..27606bc1 100644 --- a/pkg/initializer/ca/ca_suite_test.go +++ b/pkg/initializer/ca/ca_suite_test.go @@ -21,7 +21,7 @@ package initializer_test import ( "testing" - . "github.com/onsi/ginkgo" + . "github.com/onsi/ginkgo/v2" . "github.com/onsi/gomega" ) diff --git a/pkg/initializer/ca/ca_test.go b/pkg/initializer/ca/ca_test.go index 4c93e56e..609c2acf 100644 --- a/pkg/initializer/ca/ca_test.go +++ b/pkg/initializer/ca/ca_test.go @@ -26,7 +26,7 @@ import ( "github.com/IBM-Blockchain/fabric-operator/pkg/initializer/ca/config" "github.com/IBM-Blockchain/fabric-operator/pkg/initializer/ca/mocks" "github.com/IBM-Blockchain/fabric-operator/pkg/util/pointer" - . "github.com/onsi/ginkgo" + . "github.com/onsi/ginkgo/v2" . "github.com/onsi/gomega" "github.com/pkg/errors" ) diff --git a/pkg/initializer/ca/config/ca_test.go b/pkg/initializer/ca/config/ca_test.go index 3561eb64..841758fa 100644 --- a/pkg/initializer/ca/config/ca_test.go +++ b/pkg/initializer/ca/config/ca_test.go @@ -24,7 +24,7 @@ import ( v1 "github.com/IBM-Blockchain/fabric-operator/pkg/apis/ca/v1" "github.com/IBM-Blockchain/fabric-operator/pkg/initializer/ca/config" - . "github.com/onsi/ginkgo" + . "github.com/onsi/ginkgo/v2" . "github.com/onsi/gomega" ) diff --git a/pkg/initializer/ca/config/config_suite_test.go b/pkg/initializer/ca/config/config_suite_test.go index eff0b39f..e6309966 100644 --- a/pkg/initializer/ca/config/config_suite_test.go +++ b/pkg/initializer/ca/config/config_suite_test.go @@ -21,7 +21,7 @@ package config_test import ( "testing" - . "github.com/onsi/ginkgo" + . "github.com/onsi/ginkgo/v2" . "github.com/onsi/gomega" ) diff --git a/pkg/initializer/ca/config/config_test.go b/pkg/initializer/ca/config/config_test.go index 8ceb46ed..4b3f2729 100644 --- a/pkg/initializer/ca/config/config_test.go +++ b/pkg/initializer/ca/config/config_test.go @@ -24,7 +24,7 @@ import ( v1 "github.com/IBM-Blockchain/fabric-operator/pkg/apis/ca/v1" "github.com/IBM-Blockchain/fabric-operator/pkg/initializer/ca/config" "github.com/IBM-Blockchain/fabric-operator/pkg/util/pointer" - . "github.com/onsi/ginkgo" + . "github.com/onsi/ginkgo/v2" . "github.com/onsi/gomega" ) diff --git a/pkg/initializer/ca/config/db_test.go b/pkg/initializer/ca/config/db_test.go index 9a6c1533..ea13540f 100644 --- a/pkg/initializer/ca/config/db_test.go +++ b/pkg/initializer/ca/config/db_test.go @@ -25,7 +25,7 @@ import ( v1 "github.com/IBM-Blockchain/fabric-operator/pkg/apis/ca/v1" "github.com/IBM-Blockchain/fabric-operator/pkg/initializer/ca/config" "github.com/IBM-Blockchain/fabric-operator/pkg/util/pointer" - . "github.com/onsi/ginkgo" + . "github.com/onsi/ginkgo/v2" . "github.com/onsi/gomega" ) diff --git a/pkg/initializer/ca/config/intermediate_test.go b/pkg/initializer/ca/config/intermediate_test.go index 71c82762..afafca74 100644 --- a/pkg/initializer/ca/config/intermediate_test.go +++ b/pkg/initializer/ca/config/intermediate_test.go @@ -25,7 +25,7 @@ import ( v1 "github.com/IBM-Blockchain/fabric-operator/pkg/apis/ca/v1" "github.com/IBM-Blockchain/fabric-operator/pkg/initializer/ca/config" "github.com/IBM-Blockchain/fabric-operator/pkg/util/pointer" - . "github.com/onsi/ginkgo" + . "github.com/onsi/ginkgo/v2" . "github.com/onsi/gomega" ) diff --git a/pkg/initializer/ca/config/operations_test.go b/pkg/initializer/ca/config/operations_test.go index d3fe0541..e45d71cf 100644 --- a/pkg/initializer/ca/config/operations_test.go +++ b/pkg/initializer/ca/config/operations_test.go @@ -25,7 +25,7 @@ import ( v1 "github.com/IBM-Blockchain/fabric-operator/pkg/apis/ca/v1" "github.com/IBM-Blockchain/fabric-operator/pkg/initializer/ca/config" "github.com/IBM-Blockchain/fabric-operator/pkg/util/pointer" - . "github.com/onsi/ginkgo" + . "github.com/onsi/ginkgo/v2" . "github.com/onsi/gomega" ) diff --git a/pkg/initializer/ca/config/tls_test.go b/pkg/initializer/ca/config/tls_test.go index 1587b167..75098d5c 100644 --- a/pkg/initializer/ca/config/tls_test.go +++ b/pkg/initializer/ca/config/tls_test.go @@ -22,7 +22,7 @@ import ( "os" "path/filepath" - . "github.com/onsi/ginkgo" + . "github.com/onsi/ginkgo/v2" . "github.com/onsi/gomega" v1 "github.com/IBM-Blockchain/fabric-operator/pkg/apis/ca/v1" diff --git a/pkg/initializer/ca/hsm_test.go b/pkg/initializer/ca/hsm_test.go index ec785d04..3e97fd3d 100644 --- a/pkg/initializer/ca/hsm_test.go +++ b/pkg/initializer/ca/hsm_test.go @@ -22,7 +22,7 @@ import ( "context" "fmt" - . "github.com/onsi/ginkgo" + . "github.com/onsi/ginkgo/v2" . "github.com/onsi/gomega" "github.com/pkg/errors" diff --git a/pkg/initializer/ca/initializer_test.go b/pkg/initializer/ca/initializer_test.go index ad295334..9708363b 100644 --- a/pkg/initializer/ca/initializer_test.go +++ b/pkg/initializer/ca/initializer_test.go @@ -22,7 +22,7 @@ import ( v1 "github.com/IBM-Blockchain/fabric-operator/pkg/apis/ca/v1" initializer "github.com/IBM-Blockchain/fabric-operator/pkg/initializer/ca" "github.com/IBM-Blockchain/fabric-operator/pkg/initializer/ca/mocks" - . "github.com/onsi/ginkgo" + . "github.com/onsi/ginkgo/v2" . "github.com/onsi/gomega" "github.com/pkg/errors" ) diff --git a/pkg/initializer/ca/tls/tls_suite_test.go b/pkg/initializer/ca/tls/tls_suite_test.go index c7b8648d..2e6e28bd 100644 --- a/pkg/initializer/ca/tls/tls_suite_test.go +++ b/pkg/initializer/ca/tls/tls_suite_test.go @@ -21,7 +21,7 @@ package tls_test import ( "testing" - . "github.com/onsi/ginkgo" + . "github.com/onsi/ginkgo/v2" . "github.com/onsi/gomega" ) diff --git a/pkg/initializer/ca/tls/tls_test.go b/pkg/initializer/ca/tls/tls_test.go index 5854548b..cd5b637d 100644 --- a/pkg/initializer/ca/tls/tls_test.go +++ b/pkg/initializer/ca/tls/tls_test.go @@ -29,7 +29,7 @@ import ( cfcsr "github.com/cloudflare/cfssl/csr" "github.com/hyperledger/fabric-ca/api" "github.com/hyperledger/fabric/bccsp/factory" - . "github.com/onsi/ginkgo" + . "github.com/onsi/ginkgo/v2" . "github.com/onsi/gomega" ) diff --git a/pkg/initializer/common/common_suite_test.go b/pkg/initializer/common/common_suite_test.go index 9dbd6afc..22c05df0 100644 --- a/pkg/initializer/common/common_suite_test.go +++ b/pkg/initializer/common/common_suite_test.go @@ -21,7 +21,7 @@ package common_test import ( "testing" - . "github.com/onsi/ginkgo" + . "github.com/onsi/ginkgo/v2" . "github.com/onsi/gomega" ) diff --git a/pkg/initializer/common/common_test.go b/pkg/initializer/common/common_test.go index d91c973c..699dc4b7 100644 --- a/pkg/initializer/common/common_test.go +++ b/pkg/initializer/common/common_test.go @@ -24,7 +24,7 @@ import ( current "github.com/IBM-Blockchain/fabric-operator/api/v1beta1" "github.com/IBM-Blockchain/fabric-operator/pkg/initializer/common" "github.com/IBM-Blockchain/fabric-operator/pkg/initializer/common/mocks" - . "github.com/onsi/ginkgo" + . "github.com/onsi/ginkgo/v2" . "github.com/onsi/gomega" "github.com/pkg/errors" ) diff --git a/pkg/initializer/common/config/config_suite_test.go b/pkg/initializer/common/config/config_suite_test.go index eff0b39f..e6309966 100644 --- a/pkg/initializer/common/config/config_suite_test.go +++ b/pkg/initializer/common/config/config_suite_test.go @@ -21,7 +21,7 @@ package config_test import ( "testing" - . "github.com/onsi/ginkgo" + . "github.com/onsi/ginkgo/v2" . "github.com/onsi/gomega" ) diff --git a/pkg/initializer/common/config/config_test.go b/pkg/initializer/common/config/config_test.go index ef9a1a89..cff8b4d2 100644 --- a/pkg/initializer/common/config/config_test.go +++ b/pkg/initializer/common/config/config_test.go @@ -30,7 +30,7 @@ import ( "github.com/IBM-Blockchain/fabric-operator/pkg/initializer/common/config" common "github.com/IBM-Blockchain/fabric-operator/pkg/initializer/common/config" "github.com/IBM-Blockchain/fabric-operator/pkg/initializer/common/config/mocks" - . "github.com/onsi/ginkgo" + . "github.com/onsi/ginkgo/v2" . "github.com/onsi/gomega" "github.com/pkg/errors" ) diff --git a/pkg/initializer/common/config/hsmconfig_test.go b/pkg/initializer/common/config/hsmconfig_test.go index a1f0ae43..42f9dbb0 100644 --- a/pkg/initializer/common/config/hsmconfig_test.go +++ b/pkg/initializer/common/config/hsmconfig_test.go @@ -19,7 +19,7 @@ package config_test import ( - . "github.com/onsi/ginkgo" + . "github.com/onsi/ginkgo/v2" . "github.com/onsi/gomega" "github.com/IBM-Blockchain/fabric-operator/pkg/initializer/common/config" diff --git a/pkg/initializer/common/enroller/enroller_suite_test.go b/pkg/initializer/common/enroller/enroller_suite_test.go index cf8f8b10..76a7cf01 100644 --- a/pkg/initializer/common/enroller/enroller_suite_test.go +++ b/pkg/initializer/common/enroller/enroller_suite_test.go @@ -19,9 +19,13 @@ package enroller_test import ( + "net/http" + "net/http/httptest" "testing" - . "github.com/onsi/ginkgo" + "github.com/IBM-Blockchain/fabric-operator/pkg/initializer/common/enroller" + "github.com/hyperledger/fabric-ca/lib" + . "github.com/onsi/ginkgo/v2" . "github.com/onsi/gomega" ) @@ -30,4 +34,30 @@ func TestEnroller(t *testing.T) { RunSpecs(t, "Enroller Suite") } +var ( + server *httptest.Server + fabCaClient *enroller.FabCAClient +) + +var _ = BeforeSuite(func() { + server = httptest.NewServer(http.HandlerFunc(func(rw http.ResponseWriter, req *http.Request) { + // Test request parameters + Expect(req.URL.String()).To(Equal("/cainfo")) + // Send response to be tested + rw.Write([]byte(`OK`)) + })) + + fabCaClient = &enroller.FabCAClient{ + Client: &lib.Client{ + Config: &lib.ClientConfig{ + URL: server.URL, + }, + }, + } +}) + +var _ = AfterSuite(func() { + server.Close() +}) + //go:generate counterfeiter -o mocks/client.go -fake-name Client ../../../k8s/controllerclient Client diff --git a/pkg/initializer/common/enroller/enroller_test.go b/pkg/initializer/common/enroller/enroller_test.go index c5c19dc7..ffd141a7 100644 --- a/pkg/initializer/common/enroller/enroller_test.go +++ b/pkg/initializer/common/enroller/enroller_test.go @@ -19,7 +19,7 @@ package enroller_test import ( - . "github.com/onsi/ginkgo" + . "github.com/onsi/ginkgo/v2" . "github.com/onsi/gomega" "github.com/pkg/errors" diff --git a/pkg/initializer/common/enroller/fabcaclient_test.go b/pkg/initializer/common/enroller/fabcaclient_test.go index c6672568..884c568c 100644 --- a/pkg/initializer/common/enroller/fabcaclient_test.go +++ b/pkg/initializer/common/enroller/fabcaclient_test.go @@ -19,43 +19,13 @@ package enroller_test import ( - "net/http" - "net/http/httptest" "time" - "github.com/IBM-Blockchain/fabric-operator/pkg/initializer/common/enroller" - "github.com/hyperledger/fabric-ca/lib" - . "github.com/onsi/ginkgo" + . "github.com/onsi/ginkgo/v2" . "github.com/onsi/gomega" ) var _ = Describe("Fabric CA client", func() { - var ( - server *httptest.Server - fabCaClient *enroller.FabCAClient - ) - - BeforeSuite(func() { - server = httptest.NewServer(http.HandlerFunc(func(rw http.ResponseWriter, req *http.Request) { - // Test request parameters - Expect(req.URL.String()).To(Equal("/cainfo")) - // Send response to be tested - rw.Write([]byte(`OK`)) - })) - - fabCaClient = &enroller.FabCAClient{ - Client: &lib.Client{ - Config: &lib.ClientConfig{ - URL: server.URL, - }, - }, - } - }) - - AfterSuite(func() { - server.Close() - }) - Context("ping CA", func() { It("pings /cainfo endpoint", func() { err := fabCaClient.PingCA(30 * time.Second) diff --git a/pkg/initializer/common/enroller/factory_test.go b/pkg/initializer/common/enroller/factory_test.go index 8a249cd9..e03a2c8a 100644 --- a/pkg/initializer/common/enroller/factory_test.go +++ b/pkg/initializer/common/enroller/factory_test.go @@ -19,7 +19,7 @@ package enroller_test import ( - . "github.com/onsi/ginkgo" + . "github.com/onsi/ginkgo/v2" . "github.com/onsi/gomega" current "github.com/IBM-Blockchain/fabric-operator/api/v1beta1" diff --git a/pkg/initializer/common/enroller/hsmdaemonenroller_test.go b/pkg/initializer/common/enroller/hsmdaemonenroller_test.go index 50c19687..744dd1f5 100644 --- a/pkg/initializer/common/enroller/hsmdaemonenroller_test.go +++ b/pkg/initializer/common/enroller/hsmdaemonenroller_test.go @@ -22,7 +22,7 @@ import ( "context" "fmt" - . "github.com/onsi/ginkgo" + . "github.com/onsi/ginkgo/v2" . "github.com/onsi/gomega" "github.com/pkg/errors" diff --git a/pkg/initializer/common/enroller/hsmenroller_test.go b/pkg/initializer/common/enroller/hsmenroller_test.go index 808bba64..860a1445 100644 --- a/pkg/initializer/common/enroller/hsmenroller_test.go +++ b/pkg/initializer/common/enroller/hsmenroller_test.go @@ -21,7 +21,7 @@ package enroller_test import ( "context" - . "github.com/onsi/ginkgo" + . "github.com/onsi/ginkgo/v2" . "github.com/onsi/gomega" "github.com/pkg/errors" diff --git a/pkg/initializer/common/enroller/swenroller_test.go b/pkg/initializer/common/enroller/swenroller_test.go index 62c24e38..dec7071e 100644 --- a/pkg/initializer/common/enroller/swenroller_test.go +++ b/pkg/initializer/common/enroller/swenroller_test.go @@ -19,7 +19,7 @@ package enroller_test import ( - . "github.com/onsi/ginkgo" + . "github.com/onsi/ginkgo/v2" . "github.com/onsi/gomega" "github.com/hyperledger/fabric-ca/lib" diff --git a/pkg/initializer/common/mspparser/mspparser_suite_test.go b/pkg/initializer/common/mspparser/mspparser_suite_test.go index 84288193..550ebd0e 100644 --- a/pkg/initializer/common/mspparser/mspparser_suite_test.go +++ b/pkg/initializer/common/mspparser/mspparser_suite_test.go @@ -21,7 +21,7 @@ package mspparser_test import ( "testing" - . "github.com/onsi/ginkgo" + . "github.com/onsi/ginkgo/v2" . "github.com/onsi/gomega" ) diff --git a/pkg/initializer/common/mspparser/mspparser_test.go b/pkg/initializer/common/mspparser/mspparser_test.go index 2c573d44..120de363 100644 --- a/pkg/initializer/common/mspparser/mspparser_test.go +++ b/pkg/initializer/common/mspparser/mspparser_test.go @@ -21,7 +21,7 @@ package mspparser_test import ( current "github.com/IBM-Blockchain/fabric-operator/api/v1beta1" "github.com/IBM-Blockchain/fabric-operator/pkg/initializer/common/mspparser" - . "github.com/onsi/ginkgo" + . "github.com/onsi/ginkgo/v2" . "github.com/onsi/gomega" ) diff --git a/pkg/initializer/common/secretmanager/secretmanager_suite_test.go b/pkg/initializer/common/secretmanager/secretmanager_suite_test.go index d5256d7a..c0dbb59d 100644 --- a/pkg/initializer/common/secretmanager/secretmanager_suite_test.go +++ b/pkg/initializer/common/secretmanager/secretmanager_suite_test.go @@ -21,7 +21,7 @@ package secretmanager_test import ( "testing" - . "github.com/onsi/ginkgo" + . "github.com/onsi/ginkgo/v2" . "github.com/onsi/gomega" ) diff --git a/pkg/initializer/common/secretmanager/secretmanager_test.go b/pkg/initializer/common/secretmanager/secretmanager_test.go index 8be1d14d..e02ee49b 100644 --- a/pkg/initializer/common/secretmanager/secretmanager_test.go +++ b/pkg/initializer/common/secretmanager/secretmanager_test.go @@ -22,7 +22,7 @@ import ( "context" "errors" - . "github.com/onsi/ginkgo" + . "github.com/onsi/ginkgo/v2" . "github.com/onsi/gomega" corev1 "k8s.io/api/core/v1" v1 "k8s.io/apimachinery/pkg/apis/meta/v1" diff --git a/pkg/initializer/orderer/config/v1/config_suite_test.go b/pkg/initializer/orderer/config/v1/config_suite_test.go index 7969f062..a5be2625 100644 --- a/pkg/initializer/orderer/config/v1/config_suite_test.go +++ b/pkg/initializer/orderer/config/v1/config_suite_test.go @@ -21,7 +21,7 @@ package v1_test import ( "testing" - . "github.com/onsi/ginkgo" + . "github.com/onsi/ginkgo/v2" . "github.com/onsi/gomega" ) diff --git a/pkg/initializer/orderer/config/v1/config_test.go b/pkg/initializer/orderer/config/v1/config_test.go index 078e27ff..04482531 100644 --- a/pkg/initializer/orderer/config/v1/config_test.go +++ b/pkg/initializer/orderer/config/v1/config_test.go @@ -22,7 +22,7 @@ import ( commonapi "github.com/IBM-Blockchain/fabric-operator/pkg/apis/common" v1 "github.com/IBM-Blockchain/fabric-operator/pkg/apis/orderer/v1" config "github.com/IBM-Blockchain/fabric-operator/pkg/initializer/orderer/config/v1" - . "github.com/onsi/ginkgo" + . "github.com/onsi/ginkgo/v2" . "github.com/onsi/gomega" ) diff --git a/pkg/initializer/orderer/config/v2/config_suite_test.go b/pkg/initializer/orderer/config/v2/config_suite_test.go index bbd7a82d..154ae895 100644 --- a/pkg/initializer/orderer/config/v2/config_suite_test.go +++ b/pkg/initializer/orderer/config/v2/config_suite_test.go @@ -21,7 +21,7 @@ package v2_test import ( "testing" - . "github.com/onsi/ginkgo" + . "github.com/onsi/ginkgo/v2" . "github.com/onsi/gomega" ) diff --git a/pkg/initializer/orderer/config/v2/config_test.go b/pkg/initializer/orderer/config/v2/config_test.go index b3b8990e..10e66b5c 100644 --- a/pkg/initializer/orderer/config/v2/config_test.go +++ b/pkg/initializer/orderer/config/v2/config_test.go @@ -19,7 +19,7 @@ package v2_test import ( - . "github.com/onsi/ginkgo" + . "github.com/onsi/ginkgo/v2" . "github.com/onsi/gomega" commonapi "github.com/IBM-Blockchain/fabric-operator/pkg/apis/common" diff --git a/pkg/initializer/orderer/config/v24/config_suite_test.go b/pkg/initializer/orderer/config/v24/config_suite_test.go index 522327f9..cab8aeba 100644 --- a/pkg/initializer/orderer/config/v24/config_suite_test.go +++ b/pkg/initializer/orderer/config/v24/config_suite_test.go @@ -21,7 +21,7 @@ package v24_test import ( "testing" - . "github.com/onsi/ginkgo" + . "github.com/onsi/ginkgo/v2" . "github.com/onsi/gomega" ) diff --git a/pkg/initializer/orderer/config/v24/config_test.go b/pkg/initializer/orderer/config/v24/config_test.go index 7e126311..17149250 100644 --- a/pkg/initializer/orderer/config/v24/config_test.go +++ b/pkg/initializer/orderer/config/v24/config_test.go @@ -19,7 +19,7 @@ package v24_test import ( - . "github.com/onsi/ginkgo" + . "github.com/onsi/ginkgo/v2" . "github.com/onsi/gomega" commonapi "github.com/IBM-Blockchain/fabric-operator/pkg/apis/common" diff --git a/pkg/initializer/orderer/configtx/configtx_suite_test.go b/pkg/initializer/orderer/configtx/configtx_suite_test.go index c6ef6fcf..6e6afb28 100644 --- a/pkg/initializer/orderer/configtx/configtx_suite_test.go +++ b/pkg/initializer/orderer/configtx/configtx_suite_test.go @@ -21,7 +21,7 @@ package configtx_test import ( "testing" - . "github.com/onsi/ginkgo" + . "github.com/onsi/ginkgo/v2" . "github.com/onsi/gomega" ) diff --git a/pkg/initializer/orderer/configtx/configtx_test.go b/pkg/initializer/orderer/configtx/configtx_test.go index 2e5c5955..18c477f8 100644 --- a/pkg/initializer/orderer/configtx/configtx_test.go +++ b/pkg/initializer/orderer/configtx/configtx_test.go @@ -20,7 +20,7 @@ package configtx_test import ( "github.com/IBM-Blockchain/fabric-operator/pkg/initializer/orderer/configtx" - . "github.com/onsi/ginkgo" + . "github.com/onsi/ginkgo/v2" . "github.com/onsi/gomega" ) diff --git a/pkg/initializer/orderer/configtx/profile_test.go b/pkg/initializer/orderer/configtx/profile_test.go index a4c3d320..196e8a46 100644 --- a/pkg/initializer/orderer/configtx/profile_test.go +++ b/pkg/initializer/orderer/configtx/profile_test.go @@ -23,7 +23,7 @@ import ( "github.com/hyperledger/fabric-protos-go/msp" "github.com/hyperledger/fabric-protos-go/orderer/etcdraft" "github.com/hyperledger/fabric/common/channelconfig" - . "github.com/onsi/ginkgo" + . "github.com/onsi/ginkgo/v2" . "github.com/onsi/gomega" ) diff --git a/pkg/initializer/orderer/initializer_test.go b/pkg/initializer/orderer/initializer_test.go index 0a036574..65a1fc72 100644 --- a/pkg/initializer/orderer/initializer_test.go +++ b/pkg/initializer/orderer/initializer_test.go @@ -29,7 +29,7 @@ import ( commonconfig "github.com/IBM-Blockchain/fabric-operator/pkg/initializer/common/config" commonmocks "github.com/IBM-Blockchain/fabric-operator/pkg/initializer/common/mocks" initializer "github.com/IBM-Blockchain/fabric-operator/pkg/initializer/orderer" - . "github.com/onsi/ginkgo" + . "github.com/onsi/ginkgo/v2" . "github.com/onsi/gomega" "github.com/pkg/errors" corev1 "k8s.io/api/core/v1" diff --git a/pkg/initializer/orderer/orderer_suite_test.go b/pkg/initializer/orderer/orderer_suite_test.go index 6bb2ed17..6d9e7d9f 100644 --- a/pkg/initializer/orderer/orderer_suite_test.go +++ b/pkg/initializer/orderer/orderer_suite_test.go @@ -21,7 +21,7 @@ package initializer_test import ( "testing" - . "github.com/onsi/ginkgo" + . "github.com/onsi/ginkgo/v2" . "github.com/onsi/gomega" ) diff --git a/pkg/initializer/peer/config/commoncore/commoncore_suite_test.go b/pkg/initializer/peer/config/commoncore/commoncore_suite_test.go index aec5ce87..b446773f 100644 --- a/pkg/initializer/peer/config/commoncore/commoncore_suite_test.go +++ b/pkg/initializer/peer/config/commoncore/commoncore_suite_test.go @@ -20,7 +20,7 @@ package commoncore_test import ( "testing" - . "github.com/onsi/ginkgo" + . "github.com/onsi/ginkgo/v2" . "github.com/onsi/gomega" ) diff --git a/pkg/initializer/peer/config/commoncore/commoncore_test.go b/pkg/initializer/peer/config/commoncore/commoncore_test.go index 2232dacd..5cf8dd5d 100644 --- a/pkg/initializer/peer/config/commoncore/commoncore_test.go +++ b/pkg/initializer/peer/config/commoncore/commoncore_test.go @@ -20,7 +20,7 @@ package commoncore_test import ( "io/ioutil" - . "github.com/onsi/ginkgo" + . "github.com/onsi/ginkgo/v2" . "github.com/onsi/gomega" "sigs.k8s.io/yaml" diff --git a/pkg/initializer/peer/config/v1/config_suite_test.go b/pkg/initializer/peer/config/v1/config_suite_test.go index 7969f062..a5be2625 100644 --- a/pkg/initializer/peer/config/v1/config_suite_test.go +++ b/pkg/initializer/peer/config/v1/config_suite_test.go @@ -21,7 +21,7 @@ package v1_test import ( "testing" - . "github.com/onsi/ginkgo" + . "github.com/onsi/ginkgo/v2" . "github.com/onsi/gomega" ) diff --git a/pkg/initializer/peer/config/v1/config_test.go b/pkg/initializer/peer/config/v1/config_test.go index d14de050..032681e0 100644 --- a/pkg/initializer/peer/config/v1/config_test.go +++ b/pkg/initializer/peer/config/v1/config_test.go @@ -23,7 +23,7 @@ import ( v1 "github.com/IBM-Blockchain/fabric-operator/pkg/apis/peer/v1" config "github.com/IBM-Blockchain/fabric-operator/pkg/initializer/peer/config/v1" "github.com/IBM-Blockchain/fabric-operator/pkg/util/pointer" - . "github.com/onsi/ginkgo" + . "github.com/onsi/ginkgo/v2" . "github.com/onsi/gomega" ) diff --git a/pkg/initializer/peer/config/v2/config_test.go b/pkg/initializer/peer/config/v2/config_test.go index 581bd075..aff372ef 100644 --- a/pkg/initializer/peer/config/v2/config_test.go +++ b/pkg/initializer/peer/config/v2/config_test.go @@ -22,7 +22,7 @@ import ( "github.com/IBM-Blockchain/fabric-operator/pkg/apis/common" v2core "github.com/IBM-Blockchain/fabric-operator/pkg/apis/peer/v2" v2 "github.com/IBM-Blockchain/fabric-operator/pkg/initializer/peer/config/v2" - . "github.com/onsi/ginkgo" + . "github.com/onsi/ginkgo/v2" . "github.com/onsi/gomega" ) diff --git a/pkg/initializer/peer/config/v2/v2_suite_test.go b/pkg/initializer/peer/config/v2/v2_suite_test.go index bbd7a82d..154ae895 100644 --- a/pkg/initializer/peer/config/v2/v2_suite_test.go +++ b/pkg/initializer/peer/config/v2/v2_suite_test.go @@ -21,7 +21,7 @@ package v2_test import ( "testing" - . "github.com/onsi/ginkgo" + . "github.com/onsi/ginkgo/v2" . "github.com/onsi/gomega" ) diff --git a/pkg/initializer/peer/coreconfigmap_test.go b/pkg/initializer/peer/coreconfigmap_test.go index c67e8f44..7c73ef8d 100644 --- a/pkg/initializer/peer/coreconfigmap_test.go +++ b/pkg/initializer/peer/coreconfigmap_test.go @@ -22,7 +22,7 @@ import ( "context" "fmt" - . "github.com/onsi/ginkgo" + . "github.com/onsi/ginkgo/v2" . "github.com/onsi/gomega" corev1 "k8s.io/api/core/v1" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" diff --git a/pkg/initializer/peer/initializer_test.go b/pkg/initializer/peer/initializer_test.go index 4a5bf395..40b13b52 100644 --- a/pkg/initializer/peer/initializer_test.go +++ b/pkg/initializer/peer/initializer_test.go @@ -24,7 +24,7 @@ import ( "encoding/pem" "net/url" - . "github.com/onsi/ginkgo" + . "github.com/onsi/ginkgo/v2" . "github.com/onsi/gomega" "github.com/pkg/errors" corev1 "k8s.io/api/core/v1" diff --git a/pkg/initializer/peer/peer_suite_test.go b/pkg/initializer/peer/peer_suite_test.go index 25d28c17..41ed6174 100644 --- a/pkg/initializer/peer/peer_suite_test.go +++ b/pkg/initializer/peer/peer_suite_test.go @@ -23,7 +23,7 @@ import ( "net/http/httptest" "testing" - . "github.com/onsi/ginkgo" + . "github.com/onsi/ginkgo/v2" . "github.com/onsi/gomega" ) diff --git a/pkg/initializer/peer/peer_test.go b/pkg/initializer/peer/peer_test.go index 8c2bb826..f2e6038c 100644 --- a/pkg/initializer/peer/peer_test.go +++ b/pkg/initializer/peer/peer_test.go @@ -19,7 +19,7 @@ package initializer_test import ( - . "github.com/onsi/ginkgo" + . "github.com/onsi/ginkgo/v2" . "github.com/onsi/gomega" "github.com/pkg/errors" diff --git a/pkg/initializer/validator/validator_suite_test.go b/pkg/initializer/validator/validator_suite_test.go index 2b16c8a4..c8682880 100644 --- a/pkg/initializer/validator/validator_suite_test.go +++ b/pkg/initializer/validator/validator_suite_test.go @@ -21,7 +21,7 @@ package validator_test import ( "testing" - . "github.com/onsi/ginkgo" + . "github.com/onsi/ginkgo/v2" . "github.com/onsi/gomega" ) diff --git a/pkg/initializer/validator/validator_test.go b/pkg/initializer/validator/validator_test.go index 28e9d1f4..dfb5edd1 100644 --- a/pkg/initializer/validator/validator_test.go +++ b/pkg/initializer/validator/validator_test.go @@ -23,7 +23,7 @@ import ( "encoding/base64" "strings" - . "github.com/onsi/ginkgo" + . "github.com/onsi/ginkgo/v2" . "github.com/onsi/gomega" corev1 "k8s.io/api/core/v1" "k8s.io/apimachinery/pkg/types" diff --git a/pkg/manager/resources/configmap/configmap_suite_test.go b/pkg/manager/resources/configmap/configmap_suite_test.go index 6656157b..b05445aa 100644 --- a/pkg/manager/resources/configmap/configmap_suite_test.go +++ b/pkg/manager/resources/configmap/configmap_suite_test.go @@ -21,7 +21,7 @@ package configmap_test import ( "testing" - . "github.com/onsi/ginkgo" + . "github.com/onsi/ginkgo/v2" . "github.com/onsi/gomega" ) diff --git a/pkg/manager/resources/configmap/manager_test.go b/pkg/manager/resources/configmap/manager_test.go index 38cc2810..6612eea1 100644 --- a/pkg/manager/resources/configmap/manager_test.go +++ b/pkg/manager/resources/configmap/manager_test.go @@ -22,7 +22,7 @@ import ( "github.com/IBM-Blockchain/fabric-operator/controllers/mocks" "github.com/IBM-Blockchain/fabric-operator/pkg/manager/resources" "github.com/IBM-Blockchain/fabric-operator/pkg/manager/resources/configmap" - . "github.com/onsi/ginkgo" + . "github.com/onsi/ginkgo/v2" . "github.com/onsi/gomega" "github.com/pkg/errors" corev1 "k8s.io/api/core/v1" diff --git a/pkg/manager/resources/container/container_suite_test.go b/pkg/manager/resources/container/container_suite_test.go index effd7354..2428723e 100644 --- a/pkg/manager/resources/container/container_suite_test.go +++ b/pkg/manager/resources/container/container_suite_test.go @@ -21,7 +21,7 @@ package container_test import ( "testing" - . "github.com/onsi/ginkgo" + . "github.com/onsi/ginkgo/v2" . "github.com/onsi/gomega" ) diff --git a/pkg/manager/resources/container/container_test.go b/pkg/manager/resources/container/container_test.go index 91b485e2..1ad5810a 100644 --- a/pkg/manager/resources/container/container_test.go +++ b/pkg/manager/resources/container/container_test.go @@ -19,7 +19,7 @@ package container_test import ( - . "github.com/onsi/ginkgo" + . "github.com/onsi/ginkgo/v2" . "github.com/onsi/gomega" "github.com/IBM-Blockchain/fabric-operator/pkg/manager/resources/container" diff --git a/pkg/manager/resources/deployment/deployment_suite_test.go b/pkg/manager/resources/deployment/deployment_suite_test.go index fbff7fd4..faae0c2c 100644 --- a/pkg/manager/resources/deployment/deployment_suite_test.go +++ b/pkg/manager/resources/deployment/deployment_suite_test.go @@ -21,7 +21,7 @@ package deployment_test import ( "testing" - . "github.com/onsi/ginkgo" + . "github.com/onsi/ginkgo/v2" . "github.com/onsi/gomega" ) diff --git a/pkg/manager/resources/deployment/manager_test.go b/pkg/manager/resources/deployment/manager_test.go index 435dc4bd..06880878 100644 --- a/pkg/manager/resources/deployment/manager_test.go +++ b/pkg/manager/resources/deployment/manager_test.go @@ -24,7 +24,7 @@ import ( "github.com/IBM-Blockchain/fabric-operator/controllers/mocks" "github.com/IBM-Blockchain/fabric-operator/pkg/manager/resources" "github.com/IBM-Blockchain/fabric-operator/pkg/manager/resources/deployment" - . "github.com/onsi/ginkgo" + . "github.com/onsi/ginkgo/v2" . "github.com/onsi/gomega" "github.com/pkg/errors" appsv1 "k8s.io/api/apps/v1" diff --git a/pkg/manager/resources/ingress/ingress_suite_test.go b/pkg/manager/resources/ingress/ingress_suite_test.go index aa7b356e..508217b7 100644 --- a/pkg/manager/resources/ingress/ingress_suite_test.go +++ b/pkg/manager/resources/ingress/ingress_suite_test.go @@ -21,7 +21,7 @@ package ingress_test import ( "testing" - . "github.com/onsi/ginkgo" + . "github.com/onsi/ginkgo/v2" . "github.com/onsi/gomega" ) diff --git a/pkg/manager/resources/ingress/manager_test.go b/pkg/manager/resources/ingress/manager_test.go index abf622b3..dbcbb9e3 100644 --- a/pkg/manager/resources/ingress/manager_test.go +++ b/pkg/manager/resources/ingress/manager_test.go @@ -24,7 +24,7 @@ import ( "github.com/IBM-Blockchain/fabric-operator/controllers/mocks" "github.com/IBM-Blockchain/fabric-operator/pkg/manager/resources" ingress "github.com/IBM-Blockchain/fabric-operator/pkg/manager/resources/ingress" - . "github.com/onsi/ginkgo" + . "github.com/onsi/ginkgo/v2" . "github.com/onsi/gomega" "github.com/pkg/errors" networkingv1 "k8s.io/api/networking/v1" diff --git a/pkg/manager/resources/ingressv1beta1/ingress_suite_test.go b/pkg/manager/resources/ingressv1beta1/ingress_suite_test.go index e5cfa4fb..50f112f7 100644 --- a/pkg/manager/resources/ingressv1beta1/ingress_suite_test.go +++ b/pkg/manager/resources/ingressv1beta1/ingress_suite_test.go @@ -21,7 +21,7 @@ package ingressv1beta1_test import ( "testing" - . "github.com/onsi/ginkgo" + . "github.com/onsi/ginkgo/v2" . "github.com/onsi/gomega" ) diff --git a/pkg/manager/resources/ingressv1beta1/manager_test.go b/pkg/manager/resources/ingressv1beta1/manager_test.go index 93643032..1902666d 100644 --- a/pkg/manager/resources/ingressv1beta1/manager_test.go +++ b/pkg/manager/resources/ingressv1beta1/manager_test.go @@ -24,7 +24,7 @@ import ( "github.com/IBM-Blockchain/fabric-operator/controllers/mocks" "github.com/IBM-Blockchain/fabric-operator/pkg/manager/resources" ingressv1beta1 "github.com/IBM-Blockchain/fabric-operator/pkg/manager/resources/ingressv1beta1" - . "github.com/onsi/ginkgo" + . "github.com/onsi/ginkgo/v2" . "github.com/onsi/gomega" "github.com/pkg/errors" networkingv1beta1 "k8s.io/api/networking/v1beta1" diff --git a/pkg/manager/resources/job/job_suite_test.go b/pkg/manager/resources/job/job_suite_test.go index f8a8b7f8..e28de696 100644 --- a/pkg/manager/resources/job/job_suite_test.go +++ b/pkg/manager/resources/job/job_suite_test.go @@ -21,7 +21,7 @@ package job_test import ( "testing" - . "github.com/onsi/ginkgo" + . "github.com/onsi/ginkgo/v2" . "github.com/onsi/gomega" ) diff --git a/pkg/manager/resources/job/job_test.go b/pkg/manager/resources/job/job_test.go index bd472960..42b0e223 100644 --- a/pkg/manager/resources/job/job_test.go +++ b/pkg/manager/resources/job/job_test.go @@ -23,7 +23,7 @@ import ( "errors" "time" - . "github.com/onsi/ginkgo" + . "github.com/onsi/ginkgo/v2" . "github.com/onsi/gomega" "github.com/IBM-Blockchain/fabric-operator/pkg/manager/resources/container" diff --git a/pkg/manager/resources/orderernode/manager_test.go b/pkg/manager/resources/orderernode/manager_test.go index e80b6e57..c0ea9e39 100644 --- a/pkg/manager/resources/orderernode/manager_test.go +++ b/pkg/manager/resources/orderernode/manager_test.go @@ -25,7 +25,7 @@ import ( "github.com/IBM-Blockchain/fabric-operator/controllers/mocks" "github.com/IBM-Blockchain/fabric-operator/pkg/manager/resources" "github.com/IBM-Blockchain/fabric-operator/pkg/manager/resources/orderernode" - . "github.com/onsi/ginkgo" + . "github.com/onsi/ginkgo/v2" . "github.com/onsi/gomega" "github.com/pkg/errors" k8serror "k8s.io/apimachinery/pkg/api/errors" diff --git a/pkg/manager/resources/orderernode/orderernode_suite_test.go b/pkg/manager/resources/orderernode/orderernode_suite_test.go index e193d321..06bb2392 100644 --- a/pkg/manager/resources/orderernode/orderernode_suite_test.go +++ b/pkg/manager/resources/orderernode/orderernode_suite_test.go @@ -21,7 +21,7 @@ package orderernode_test import ( "testing" - . "github.com/onsi/ginkgo" + . "github.com/onsi/ginkgo/v2" . "github.com/onsi/gomega" ) diff --git a/pkg/manager/resources/pv/manager_test.go b/pkg/manager/resources/pv/manager_test.go index edc2c0ac..d9930c10 100644 --- a/pkg/manager/resources/pv/manager_test.go +++ b/pkg/manager/resources/pv/manager_test.go @@ -22,7 +22,7 @@ import ( "github.com/IBM-Blockchain/fabric-operator/controllers/mocks" "github.com/IBM-Blockchain/fabric-operator/pkg/manager/resources" "github.com/IBM-Blockchain/fabric-operator/pkg/manager/resources/pvc" - . "github.com/onsi/ginkgo" + . "github.com/onsi/ginkgo/v2" . "github.com/onsi/gomega" "github.com/pkg/errors" corev1 "k8s.io/api/core/v1" diff --git a/pkg/manager/resources/pv/pvc_suite_test.go b/pkg/manager/resources/pv/pvc_suite_test.go index c65db070..b5ba35e5 100644 --- a/pkg/manager/resources/pv/pvc_suite_test.go +++ b/pkg/manager/resources/pv/pvc_suite_test.go @@ -21,7 +21,7 @@ package pv_test import ( "testing" - . "github.com/onsi/ginkgo" + . "github.com/onsi/ginkgo/v2" . "github.com/onsi/gomega" ) diff --git a/pkg/manager/resources/pvc/manager_test.go b/pkg/manager/resources/pvc/manager_test.go index 83e8d9cb..2365b84a 100644 --- a/pkg/manager/resources/pvc/manager_test.go +++ b/pkg/manager/resources/pvc/manager_test.go @@ -22,7 +22,7 @@ import ( "github.com/IBM-Blockchain/fabric-operator/controllers/mocks" "github.com/IBM-Blockchain/fabric-operator/pkg/manager/resources" "github.com/IBM-Blockchain/fabric-operator/pkg/manager/resources/pvc" - . "github.com/onsi/ginkgo" + . "github.com/onsi/ginkgo/v2" . "github.com/onsi/gomega" "github.com/pkg/errors" corev1 "k8s.io/api/core/v1" diff --git a/pkg/manager/resources/pvc/pvc_suite_test.go b/pkg/manager/resources/pvc/pvc_suite_test.go index 367b23bd..9d62bde1 100644 --- a/pkg/manager/resources/pvc/pvc_suite_test.go +++ b/pkg/manager/resources/pvc/pvc_suite_test.go @@ -21,7 +21,7 @@ package pvc_test import ( "testing" - . "github.com/onsi/ginkgo" + . "github.com/onsi/ginkgo/v2" . "github.com/onsi/gomega" ) diff --git a/pkg/manager/resources/role/manager_test.go b/pkg/manager/resources/role/manager_test.go index 131b4864..46f5accb 100644 --- a/pkg/manager/resources/role/manager_test.go +++ b/pkg/manager/resources/role/manager_test.go @@ -22,7 +22,7 @@ import ( "github.com/IBM-Blockchain/fabric-operator/controllers/mocks" "github.com/IBM-Blockchain/fabric-operator/pkg/manager/resources" "github.com/IBM-Blockchain/fabric-operator/pkg/manager/resources/role" - . "github.com/onsi/ginkgo" + . "github.com/onsi/ginkgo/v2" . "github.com/onsi/gomega" "github.com/pkg/errors" rbacv1 "k8s.io/api/rbac/v1" diff --git a/pkg/manager/resources/role/role_suite_test.go b/pkg/manager/resources/role/role_suite_test.go index 1dd291d7..46d92230 100644 --- a/pkg/manager/resources/role/role_suite_test.go +++ b/pkg/manager/resources/role/role_suite_test.go @@ -21,7 +21,7 @@ package role_test import ( "testing" - . "github.com/onsi/ginkgo" + . "github.com/onsi/ginkgo/v2" . "github.com/onsi/gomega" ) diff --git a/pkg/manager/resources/rolebinding/manager_test.go b/pkg/manager/resources/rolebinding/manager_test.go index 18f90525..6258a737 100644 --- a/pkg/manager/resources/rolebinding/manager_test.go +++ b/pkg/manager/resources/rolebinding/manager_test.go @@ -22,7 +22,7 @@ import ( "github.com/IBM-Blockchain/fabric-operator/controllers/mocks" "github.com/IBM-Blockchain/fabric-operator/pkg/manager/resources" "github.com/IBM-Blockchain/fabric-operator/pkg/manager/resources/rolebinding" - . "github.com/onsi/ginkgo" + . "github.com/onsi/ginkgo/v2" . "github.com/onsi/gomega" "github.com/pkg/errors" rbacv1 "k8s.io/api/rbac/v1" diff --git a/pkg/manager/resources/rolebinding/rolebinding_suite_test.go b/pkg/manager/resources/rolebinding/rolebinding_suite_test.go index 9275964e..c87c5448 100644 --- a/pkg/manager/resources/rolebinding/rolebinding_suite_test.go +++ b/pkg/manager/resources/rolebinding/rolebinding_suite_test.go @@ -21,7 +21,7 @@ package rolebinding_test import ( "testing" - . "github.com/onsi/ginkgo" + . "github.com/onsi/ginkgo/v2" . "github.com/onsi/gomega" ) diff --git a/pkg/manager/resources/route/manager_test.go b/pkg/manager/resources/route/manager_test.go index e528937a..07d5682c 100644 --- a/pkg/manager/resources/route/manager_test.go +++ b/pkg/manager/resources/route/manager_test.go @@ -22,7 +22,7 @@ import ( "github.com/IBM-Blockchain/fabric-operator/controllers/mocks" "github.com/IBM-Blockchain/fabric-operator/pkg/manager/resources" "github.com/IBM-Blockchain/fabric-operator/pkg/manager/resources/route" - . "github.com/onsi/ginkgo" + . "github.com/onsi/ginkgo/v2" . "github.com/onsi/gomega" routev1 "github.com/openshift/api/route/v1" "github.com/pkg/errors" diff --git a/pkg/manager/resources/route/route_suite_test.go b/pkg/manager/resources/route/route_suite_test.go index 78be1555..e6462925 100644 --- a/pkg/manager/resources/route/route_suite_test.go +++ b/pkg/manager/resources/route/route_suite_test.go @@ -21,7 +21,7 @@ package route_test import ( "testing" - . "github.com/onsi/ginkgo" + . "github.com/onsi/ginkgo/v2" . "github.com/onsi/gomega" ) diff --git a/pkg/manager/resources/service/manager_test.go b/pkg/manager/resources/service/manager_test.go index b530033f..19349c8a 100644 --- a/pkg/manager/resources/service/manager_test.go +++ b/pkg/manager/resources/service/manager_test.go @@ -22,7 +22,7 @@ import ( "github.com/IBM-Blockchain/fabric-operator/controllers/mocks" "github.com/IBM-Blockchain/fabric-operator/pkg/manager/resources" "github.com/IBM-Blockchain/fabric-operator/pkg/manager/resources/service" - . "github.com/onsi/ginkgo" + . "github.com/onsi/ginkgo/v2" . "github.com/onsi/gomega" "github.com/pkg/errors" corev1 "k8s.io/api/core/v1" diff --git a/pkg/manager/resources/service/service_suite_test.go b/pkg/manager/resources/service/service_suite_test.go index 34738308..ca9d7fc8 100644 --- a/pkg/manager/resources/service/service_suite_test.go +++ b/pkg/manager/resources/service/service_suite_test.go @@ -21,7 +21,7 @@ package service_test import ( "testing" - . "github.com/onsi/ginkgo" + . "github.com/onsi/ginkgo/v2" . "github.com/onsi/gomega" ) diff --git a/pkg/manager/resources/serviceaccount/manager_test.go b/pkg/manager/resources/serviceaccount/manager_test.go index 5936a605..b0da2fb9 100644 --- a/pkg/manager/resources/serviceaccount/manager_test.go +++ b/pkg/manager/resources/serviceaccount/manager_test.go @@ -22,7 +22,7 @@ import ( "github.com/IBM-Blockchain/fabric-operator/controllers/mocks" "github.com/IBM-Blockchain/fabric-operator/pkg/manager/resources" "github.com/IBM-Blockchain/fabric-operator/pkg/manager/resources/serviceaccount" - . "github.com/onsi/ginkgo" + . "github.com/onsi/ginkgo/v2" . "github.com/onsi/gomega" "github.com/pkg/errors" corev1 "k8s.io/api/core/v1" diff --git a/pkg/manager/resources/serviceaccount/serviceaccount_suite_test.go b/pkg/manager/resources/serviceaccount/serviceaccount_suite_test.go index cd508d2f..05fc83a1 100644 --- a/pkg/manager/resources/serviceaccount/serviceaccount_suite_test.go +++ b/pkg/manager/resources/serviceaccount/serviceaccount_suite_test.go @@ -21,7 +21,7 @@ package serviceaccount_test import ( "testing" - . "github.com/onsi/ginkgo" + . "github.com/onsi/ginkgo/v2" . "github.com/onsi/gomega" ) diff --git a/pkg/migrator/peer/fabric/fabric_suite_test.go b/pkg/migrator/peer/fabric/fabric_suite_test.go index 2384c88a..37944b69 100644 --- a/pkg/migrator/peer/fabric/fabric_suite_test.go +++ b/pkg/migrator/peer/fabric/fabric_suite_test.go @@ -21,7 +21,7 @@ package fabric_test import ( "testing" - . "github.com/onsi/ginkgo" + . "github.com/onsi/ginkgo/v2" . "github.com/onsi/gomega" ) diff --git a/pkg/migrator/peer/fabric/migrator_test.go b/pkg/migrator/peer/fabric/migrator_test.go index 9d403e01..077b6ff3 100644 --- a/pkg/migrator/peer/fabric/migrator_test.go +++ b/pkg/migrator/peer/fabric/migrator_test.go @@ -21,7 +21,7 @@ package fabric_test import ( "errors" - . "github.com/onsi/ginkgo" + . "github.com/onsi/ginkgo/v2" . "github.com/onsi/gomega" current "github.com/IBM-Blockchain/fabric-operator/api/v1beta1" diff --git a/pkg/migrator/peer/fabric/v2/peer_test.go b/pkg/migrator/peer/fabric/v2/peer_test.go index 1366bc69..239acd5f 100644 --- a/pkg/migrator/peer/fabric/v2/peer_test.go +++ b/pkg/migrator/peer/fabric/v2/peer_test.go @@ -22,7 +22,7 @@ import ( "context" "strings" - . "github.com/onsi/ginkgo" + . "github.com/onsi/ginkgo/v2" . "github.com/onsi/gomega" "github.com/pkg/errors" diff --git a/pkg/migrator/peer/fabric/v2/v2_suite_test.go b/pkg/migrator/peer/fabric/v2/v2_suite_test.go index bbd7a82d..154ae895 100644 --- a/pkg/migrator/peer/fabric/v2/v2_suite_test.go +++ b/pkg/migrator/peer/fabric/v2/v2_suite_test.go @@ -21,7 +21,7 @@ package v2_test import ( "testing" - . "github.com/onsi/ginkgo" + . "github.com/onsi/ginkgo/v2" . "github.com/onsi/gomega" ) diff --git a/pkg/migrator/peer/peer_suite_test.go b/pkg/migrator/peer/peer_suite_test.go index e4cc62d5..9f67ab94 100644 --- a/pkg/migrator/peer/peer_suite_test.go +++ b/pkg/migrator/peer/peer_suite_test.go @@ -21,7 +21,7 @@ package peer_test import ( "testing" - . "github.com/onsi/ginkgo" + . "github.com/onsi/ginkgo/v2" . "github.com/onsi/gomega" ) diff --git a/pkg/offering/base/ca/ca_suite_test.go b/pkg/offering/base/ca/ca_suite_test.go index ceff7a0f..ea488559 100644 --- a/pkg/offering/base/ca/ca_suite_test.go +++ b/pkg/offering/base/ca/ca_suite_test.go @@ -22,7 +22,7 @@ import ( "net" "testing" - . "github.com/onsi/ginkgo" + . "github.com/onsi/ginkgo/v2" . "github.com/onsi/gomega" ) diff --git a/pkg/offering/base/ca/ca_test.go b/pkg/offering/base/ca/ca_test.go index 46bcd4ef..9cb0c094 100644 --- a/pkg/offering/base/ca/ca_test.go +++ b/pkg/offering/base/ca/ca_test.go @@ -27,7 +27,7 @@ import ( "os" "path/filepath" - . "github.com/onsi/ginkgo" + . "github.com/onsi/ginkgo/v2" . "github.com/onsi/gomega" corev1 "k8s.io/api/core/v1" "k8s.io/apimachinery/pkg/runtime" diff --git a/pkg/offering/base/ca/initialize_test.go b/pkg/offering/base/ca/initialize_test.go index 6ded68d6..ea2d2b19 100644 --- a/pkg/offering/base/ca/initialize_test.go +++ b/pkg/offering/base/ca/initialize_test.go @@ -19,7 +19,7 @@ package baseca_test import ( - . "github.com/onsi/ginkgo" + . "github.com/onsi/ginkgo/v2" . "github.com/onsi/gomega" "github.com/pkg/errors" diff --git a/pkg/offering/base/ca/override/deployment_test.go b/pkg/offering/base/ca/override/deployment_test.go index 28653c3e..4cc396ed 100644 --- a/pkg/offering/base/ca/override/deployment_test.go +++ b/pkg/offering/base/ca/override/deployment_test.go @@ -22,7 +22,7 @@ import ( "context" "encoding/json" - . "github.com/onsi/ginkgo" + . "github.com/onsi/ginkgo/v2" . "github.com/onsi/gomega" appsv1 "k8s.io/api/apps/v1" @@ -268,59 +268,56 @@ var _ = Describe("Deployment Overrides", func() { Expect(*deployment.Spec.Template.Spec.Affinity).To(Equal(affinity)) }) - Context("volumes", func() { - - By("creating a ca crypto volume", func() { - volume := corev1.Volume{ - Name: "ca-crypto", - VolumeSource: corev1.VolumeSource{ - Secret: &corev1.SecretVolumeSource{ - SecretName: instance.Name + "-ca-crypto", - }, + By("volumes creating a ca crypto volume", func() { + volume := corev1.Volume{ + Name: "ca-crypto", + VolumeSource: corev1.VolumeSource{ + Secret: &corev1.SecretVolumeSource{ + SecretName: instance.Name + "-ca-crypto", }, - } - Expect(deployment.Spec.Template.Spec.Volumes).To(ContainElement(volume)) - }) + }, + } + Expect(deployment.Spec.Template.Spec.Volumes).To(ContainElement(volume)) + }) - By("creating a tlsca crypto volume", func() { - volume := corev1.Volume{ - Name: "tlsca-crypto", - VolumeSource: corev1.VolumeSource{ - Secret: &corev1.SecretVolumeSource{ - SecretName: instance.Name + "-tlsca-crypto", - }, + By("volumes creating a tlsca crypto volume", func() { + volume := corev1.Volume{ + Name: "tlsca-crypto", + VolumeSource: corev1.VolumeSource{ + Secret: &corev1.SecretVolumeSource{ + SecretName: instance.Name + "-tlsca-crypto", }, - } - Expect(deployment.Spec.Template.Spec.Volumes).To(ContainElement(volume)) - }) + }, + } + Expect(deployment.Spec.Template.Spec.Volumes).To(ContainElement(volume)) + }) - By("creating a ca config volume", func() { - volume := corev1.Volume{ - Name: "ca-config", - VolumeSource: corev1.VolumeSource{ - ConfigMap: &corev1.ConfigMapVolumeSource{ - LocalObjectReference: corev1.LocalObjectReference{ - Name: instance.Name + "-ca-config", - }, + By("volumes creating a ca config volume", func() { + volume := corev1.Volume{ + Name: "ca-config", + VolumeSource: corev1.VolumeSource{ + ConfigMap: &corev1.ConfigMapVolumeSource{ + LocalObjectReference: corev1.LocalObjectReference{ + Name: instance.Name + "-ca-config", }, }, - } - Expect(deployment.Spec.Template.Spec.Volumes).To(ContainElement(volume)) - }) + }, + } + Expect(deployment.Spec.Template.Spec.Volumes).To(ContainElement(volume)) + }) - By("creating a tlsca config volume", func() { - volume := corev1.Volume{ - Name: "tlsca-config", - VolumeSource: corev1.VolumeSource{ - ConfigMap: &corev1.ConfigMapVolumeSource{ - LocalObjectReference: corev1.LocalObjectReference{ - Name: instance.Name + "-tlsca-config", - }, + By("volumes creating a tlsca config volume", func() { + volume := corev1.Volume{ + Name: "tlsca-config", + VolumeSource: corev1.VolumeSource{ + ConfigMap: &corev1.ConfigMapVolumeSource{ + LocalObjectReference: corev1.LocalObjectReference{ + Name: instance.Name + "-tlsca-config", }, }, - } - Expect(deployment.Spec.Template.Spec.Volumes).To(ContainElement(volume)) - }) + }, + } + Expect(deployment.Spec.Template.Spec.Volumes).To(ContainElement(volume)) }) }) diff --git a/pkg/offering/base/ca/override/override_suite_test.go b/pkg/offering/base/ca/override/override_suite_test.go index e44a1014..b9598cfb 100644 --- a/pkg/offering/base/ca/override/override_suite_test.go +++ b/pkg/offering/base/ca/override/override_suite_test.go @@ -21,7 +21,7 @@ package override_test import ( "testing" - . "github.com/onsi/ginkgo" + . "github.com/onsi/ginkgo/v2" . "github.com/onsi/gomega" ) diff --git a/pkg/offering/base/ca/override/override_test.go b/pkg/offering/base/ca/override/override_test.go index 3d02d44e..f5d8e8ac 100644 --- a/pkg/offering/base/ca/override/override_test.go +++ b/pkg/offering/base/ca/override/override_test.go @@ -21,7 +21,7 @@ package override_test import ( "encoding/json" - . "github.com/onsi/ginkgo" + . "github.com/onsi/ginkgo/v2" . "github.com/onsi/gomega" "k8s.io/apimachinery/pkg/runtime" diff --git a/pkg/offering/base/ca/override/pvc_test.go b/pkg/offering/base/ca/override/pvc_test.go index 1db20cde..1a7a215d 100644 --- a/pkg/offering/base/ca/override/pvc_test.go +++ b/pkg/offering/base/ca/override/pvc_test.go @@ -19,7 +19,7 @@ package override_test import ( - . "github.com/onsi/ginkgo" + . "github.com/onsi/ginkgo/v2" . "github.com/onsi/gomega" corev1 "k8s.io/api/core/v1" diff --git a/pkg/offering/base/ca/override/service_test.go b/pkg/offering/base/ca/override/service_test.go index b6361184..c9c000c7 100644 --- a/pkg/offering/base/ca/override/service_test.go +++ b/pkg/offering/base/ca/override/service_test.go @@ -19,7 +19,7 @@ package override_test import ( - . "github.com/onsi/ginkgo" + . "github.com/onsi/ginkgo/v2" . "github.com/onsi/gomega" corev1 "k8s.io/api/core/v1" diff --git a/pkg/offering/base/ca/override/serviceaccount_test.go b/pkg/offering/base/ca/override/serviceaccount_test.go index 2a3806aa..ef22be31 100644 --- a/pkg/offering/base/ca/override/serviceaccount_test.go +++ b/pkg/offering/base/ca/override/serviceaccount_test.go @@ -19,7 +19,7 @@ package override_test import ( - . "github.com/onsi/ginkgo" + . "github.com/onsi/ginkgo/v2" . "github.com/onsi/gomega" corev1 "k8s.io/api/core/v1" diff --git a/pkg/offering/base/console/console_suite_test.go b/pkg/offering/base/console/console_suite_test.go index 413b7752..b1abc553 100644 --- a/pkg/offering/base/console/console_suite_test.go +++ b/pkg/offering/base/console/console_suite_test.go @@ -21,7 +21,7 @@ package baseconsole_test import ( "testing" - . "github.com/onsi/ginkgo" + . "github.com/onsi/ginkgo/v2" . "github.com/onsi/gomega" ) diff --git a/pkg/offering/base/console/console_test.go b/pkg/offering/base/console/console_test.go index 9f13a525..816d0117 100644 --- a/pkg/offering/base/console/console_test.go +++ b/pkg/offering/base/console/console_test.go @@ -27,7 +27,7 @@ import ( baseconsole "github.com/IBM-Blockchain/fabric-operator/pkg/offering/base/console" "github.com/IBM-Blockchain/fabric-operator/pkg/offering/base/console/mocks" "github.com/IBM-Blockchain/fabric-operator/version" - . "github.com/onsi/ginkgo" + . "github.com/onsi/ginkgo/v2" . "github.com/onsi/gomega" "github.com/pkg/errors" "k8s.io/apimachinery/pkg/runtime" diff --git a/pkg/offering/base/console/override/consolecm_test.go b/pkg/offering/base/console/override/consolecm_test.go index e3779dea..6cf43a74 100644 --- a/pkg/offering/base/console/override/consolecm_test.go +++ b/pkg/offering/base/console/override/consolecm_test.go @@ -19,7 +19,7 @@ package override_test import ( - . "github.com/onsi/ginkgo" + . "github.com/onsi/ginkgo/v2" . "github.com/onsi/gomega" corev1 "k8s.io/api/core/v1" "sigs.k8s.io/yaml" diff --git a/pkg/offering/base/console/override/deployercm_test.go b/pkg/offering/base/console/override/deployercm_test.go index bf308909..a261b082 100644 --- a/pkg/offering/base/console/override/deployercm_test.go +++ b/pkg/offering/base/console/override/deployercm_test.go @@ -19,7 +19,7 @@ package override_test import ( - . "github.com/onsi/ginkgo" + . "github.com/onsi/ginkgo/v2" . "github.com/onsi/gomega" corev1 "k8s.io/api/core/v1" "sigs.k8s.io/yaml" diff --git a/pkg/offering/base/console/override/deployerservice_test.go b/pkg/offering/base/console/override/deployerservice_test.go index e516e707..02fee482 100644 --- a/pkg/offering/base/console/override/deployerservice_test.go +++ b/pkg/offering/base/console/override/deployerservice_test.go @@ -19,7 +19,7 @@ package override_test import ( - . "github.com/onsi/ginkgo" + . "github.com/onsi/ginkgo/v2" . "github.com/onsi/gomega" corev1 "k8s.io/api/core/v1" diff --git a/pkg/offering/base/console/override/deployment_test.go b/pkg/offering/base/console/override/deployment_test.go index 509106f7..d1caf41d 100644 --- a/pkg/offering/base/console/override/deployment_test.go +++ b/pkg/offering/base/console/override/deployment_test.go @@ -22,7 +22,7 @@ import ( "encoding/json" "fmt" - . "github.com/onsi/ginkgo" + . "github.com/onsi/ginkgo/v2" . "github.com/onsi/gomega" current "github.com/IBM-Blockchain/fabric-operator/api/v1beta1" diff --git a/pkg/offering/base/console/override/envcm_test.go b/pkg/offering/base/console/override/envcm_test.go index 1465a02d..12fef4fa 100644 --- a/pkg/offering/base/console/override/envcm_test.go +++ b/pkg/offering/base/console/override/envcm_test.go @@ -21,7 +21,7 @@ package override_test import ( "fmt" - . "github.com/onsi/ginkgo" + . "github.com/onsi/ginkgo/v2" . "github.com/onsi/gomega" corev1 "k8s.io/api/core/v1" diff --git a/pkg/offering/base/console/override/override_suite_test.go b/pkg/offering/base/console/override/override_suite_test.go index fa47c9b8..27096c13 100644 --- a/pkg/offering/base/console/override/override_suite_test.go +++ b/pkg/offering/base/console/override/override_suite_test.go @@ -21,7 +21,7 @@ package override_test import ( "testing" - . "github.com/onsi/ginkgo" + . "github.com/onsi/ginkgo/v2" . "github.com/onsi/gomega" ) diff --git a/pkg/offering/base/console/override/pvc_test.go b/pkg/offering/base/console/override/pvc_test.go index 1c9895ca..599c061b 100644 --- a/pkg/offering/base/console/override/pvc_test.go +++ b/pkg/offering/base/console/override/pvc_test.go @@ -19,7 +19,7 @@ package override_test import ( - . "github.com/onsi/ginkgo" + . "github.com/onsi/ginkgo/v2" . "github.com/onsi/gomega" corev1 "k8s.io/api/core/v1" "k8s.io/apimachinery/pkg/api/resource" diff --git a/pkg/offering/base/console/override/service_test.go b/pkg/offering/base/console/override/service_test.go index 56e7b93a..6ee1f481 100644 --- a/pkg/offering/base/console/override/service_test.go +++ b/pkg/offering/base/console/override/service_test.go @@ -19,7 +19,7 @@ package override_test import ( - . "github.com/onsi/ginkgo" + . "github.com/onsi/ginkgo/v2" . "github.com/onsi/gomega" corev1 "k8s.io/api/core/v1" diff --git a/pkg/offering/base/console/override/serviceaccount_test.go b/pkg/offering/base/console/override/serviceaccount_test.go index a9d18e96..df16a835 100644 --- a/pkg/offering/base/console/override/serviceaccount_test.go +++ b/pkg/offering/base/console/override/serviceaccount_test.go @@ -19,7 +19,7 @@ package override_test import ( - . "github.com/onsi/ginkgo" + . "github.com/onsi/ginkgo/v2" . "github.com/onsi/gomega" corev1 "k8s.io/api/core/v1" diff --git a/pkg/offering/base/orderer/node_test.go b/pkg/offering/base/orderer/node_test.go index f9ccd366..5200c7ed 100644 --- a/pkg/offering/base/orderer/node_test.go +++ b/pkg/offering/base/orderer/node_test.go @@ -43,7 +43,7 @@ import ( orderermocks "github.com/IBM-Blockchain/fabric-operator/pkg/offering/base/orderer/mocks" "github.com/IBM-Blockchain/fabric-operator/pkg/operatorerrors" "github.com/IBM-Blockchain/fabric-operator/version" - . "github.com/onsi/ginkgo" + . "github.com/onsi/ginkgo/v2" . "github.com/onsi/gomega" "github.com/pkg/errors" corev1 "k8s.io/api/core/v1" diff --git a/pkg/offering/base/orderer/orderer_suite_test.go b/pkg/offering/base/orderer/orderer_suite_test.go index 45430173..f834b106 100644 --- a/pkg/offering/base/orderer/orderer_suite_test.go +++ b/pkg/offering/base/orderer/orderer_suite_test.go @@ -22,7 +22,7 @@ import ( "net" "testing" - . "github.com/onsi/ginkgo" + . "github.com/onsi/ginkgo/v2" . "github.com/onsi/gomega" ) diff --git a/pkg/offering/base/orderer/orderer_test.go b/pkg/offering/base/orderer/orderer_test.go index 59eff4b2..a96530f7 100644 --- a/pkg/offering/base/orderer/orderer_test.go +++ b/pkg/offering/base/orderer/orderer_test.go @@ -29,7 +29,7 @@ import ( baseorderer "github.com/IBM-Blockchain/fabric-operator/pkg/offering/base/orderer" "github.com/IBM-Blockchain/fabric-operator/pkg/offering/base/orderer/mocks" orderermocks "github.com/IBM-Blockchain/fabric-operator/pkg/offering/base/orderer/mocks" - . "github.com/onsi/ginkgo" + . "github.com/onsi/ginkgo/v2" . "github.com/onsi/gomega" corev1 "k8s.io/api/core/v1" "k8s.io/apimachinery/pkg/runtime" diff --git a/pkg/offering/base/orderer/override/deployment_test.go b/pkg/offering/base/orderer/override/deployment_test.go index bb3b5c9d..4980503b 100644 --- a/pkg/offering/base/orderer/override/deployment_test.go +++ b/pkg/offering/base/orderer/override/deployment_test.go @@ -24,7 +24,7 @@ import ( "errors" "fmt" - . "github.com/onsi/ginkgo" + . "github.com/onsi/ginkgo/v2" . "github.com/onsi/gomega" "gopkg.in/yaml.v2" appsv1 "k8s.io/api/apps/v1" diff --git a/pkg/offering/base/orderer/override/override_suite_test.go b/pkg/offering/base/orderer/override/override_suite_test.go index fa47c9b8..27096c13 100644 --- a/pkg/offering/base/orderer/override/override_suite_test.go +++ b/pkg/offering/base/orderer/override/override_suite_test.go @@ -21,7 +21,7 @@ package override_test import ( "testing" - . "github.com/onsi/ginkgo" + . "github.com/onsi/ginkgo/v2" . "github.com/onsi/gomega" ) diff --git a/pkg/offering/base/orderer/override/override_test.go b/pkg/offering/base/orderer/override/override_test.go index 2a913066..aeb92dc4 100644 --- a/pkg/offering/base/orderer/override/override_test.go +++ b/pkg/offering/base/orderer/override/override_test.go @@ -19,7 +19,7 @@ package override_test import ( - . "github.com/onsi/ginkgo" + . "github.com/onsi/ginkgo/v2" . "github.com/onsi/gomega" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" diff --git a/pkg/offering/base/orderer/override/pvc_test.go b/pkg/offering/base/orderer/override/pvc_test.go index c9ed0c42..0d3b846e 100644 --- a/pkg/offering/base/orderer/override/pvc_test.go +++ b/pkg/offering/base/orderer/override/pvc_test.go @@ -19,7 +19,7 @@ package override_test import ( - . "github.com/onsi/ginkgo" + . "github.com/onsi/ginkgo/v2" . "github.com/onsi/gomega" corev1 "k8s.io/api/core/v1" "k8s.io/apimachinery/pkg/api/resource" diff --git a/pkg/offering/base/orderer/override/service_test.go b/pkg/offering/base/orderer/override/service_test.go index af7f72ec..2121bcb1 100644 --- a/pkg/offering/base/orderer/override/service_test.go +++ b/pkg/offering/base/orderer/override/service_test.go @@ -19,7 +19,7 @@ package override_test import ( - . "github.com/onsi/ginkgo" + . "github.com/onsi/ginkgo/v2" . "github.com/onsi/gomega" corev1 "k8s.io/api/core/v1" diff --git a/pkg/offering/base/orderer/override/serviceaccount_test.go b/pkg/offering/base/orderer/override/serviceaccount_test.go index f7bfdf38..a98de78d 100644 --- a/pkg/offering/base/orderer/override/serviceaccount_test.go +++ b/pkg/offering/base/orderer/override/serviceaccount_test.go @@ -19,7 +19,7 @@ package override_test import ( - . "github.com/onsi/ginkgo" + . "github.com/onsi/ginkgo/v2" . "github.com/onsi/gomega" corev1 "k8s.io/api/core/v1" diff --git a/pkg/offering/base/peer/override/deployment_test.go b/pkg/offering/base/peer/override/deployment_test.go index cc21e743..b7762457 100644 --- a/pkg/offering/base/peer/override/deployment_test.go +++ b/pkg/offering/base/peer/override/deployment_test.go @@ -24,7 +24,7 @@ import ( "fmt" "path/filepath" - . "github.com/onsi/ginkgo" + . "github.com/onsi/ginkgo/v2" . "github.com/onsi/gomega" "github.com/pkg/errors" appsv1 "k8s.io/api/apps/v1" diff --git a/pkg/offering/base/peer/override/override_suite_test.go b/pkg/offering/base/peer/override/override_suite_test.go index fa47c9b8..27096c13 100644 --- a/pkg/offering/base/peer/override/override_suite_test.go +++ b/pkg/offering/base/peer/override/override_suite_test.go @@ -21,7 +21,7 @@ package override_test import ( "testing" - . "github.com/onsi/ginkgo" + . "github.com/onsi/ginkgo/v2" . "github.com/onsi/gomega" ) diff --git a/pkg/offering/base/peer/override/override_test.go b/pkg/offering/base/peer/override/override_test.go index 92ac6a9a..08c8c508 100644 --- a/pkg/offering/base/peer/override/override_test.go +++ b/pkg/offering/base/peer/override/override_test.go @@ -19,7 +19,7 @@ package override_test import ( - . "github.com/onsi/ginkgo" + . "github.com/onsi/ginkgo/v2" . "github.com/onsi/gomega" current "github.com/IBM-Blockchain/fabric-operator/api/v1beta1" diff --git a/pkg/offering/base/peer/override/pvc_test.go b/pkg/offering/base/peer/override/pvc_test.go index b10fb064..df2b3f30 100644 --- a/pkg/offering/base/peer/override/pvc_test.go +++ b/pkg/offering/base/peer/override/pvc_test.go @@ -19,7 +19,7 @@ package override_test import ( - . "github.com/onsi/ginkgo" + . "github.com/onsi/ginkgo/v2" . "github.com/onsi/gomega" corev1 "k8s.io/api/core/v1" "k8s.io/apimachinery/pkg/api/resource" diff --git a/pkg/offering/base/peer/override/service_test.go b/pkg/offering/base/peer/override/service_test.go index 2cd3fc7d..e5200169 100644 --- a/pkg/offering/base/peer/override/service_test.go +++ b/pkg/offering/base/peer/override/service_test.go @@ -19,7 +19,7 @@ package override_test import ( - . "github.com/onsi/ginkgo" + . "github.com/onsi/ginkgo/v2" . "github.com/onsi/gomega" corev1 "k8s.io/api/core/v1" diff --git a/pkg/offering/base/peer/override/serviceaccount_test.go b/pkg/offering/base/peer/override/serviceaccount_test.go index a5eacfbe..bc271fe2 100644 --- a/pkg/offering/base/peer/override/serviceaccount_test.go +++ b/pkg/offering/base/peer/override/serviceaccount_test.go @@ -19,7 +19,7 @@ package override_test import ( - . "github.com/onsi/ginkgo" + . "github.com/onsi/ginkgo/v2" . "github.com/onsi/gomega" corev1 "k8s.io/api/core/v1" diff --git a/pkg/offering/base/peer/peer_suite_test.go b/pkg/offering/base/peer/peer_suite_test.go index 1c54df97..32fd5f14 100644 --- a/pkg/offering/base/peer/peer_suite_test.go +++ b/pkg/offering/base/peer/peer_suite_test.go @@ -22,7 +22,7 @@ import ( "net" "testing" - . "github.com/onsi/ginkgo" + . "github.com/onsi/ginkgo/v2" . "github.com/onsi/gomega" ) diff --git a/pkg/offering/base/peer/peer_test.go b/pkg/offering/base/peer/peer_test.go index c48bcf63..e7c01c8d 100644 --- a/pkg/offering/base/peer/peer_test.go +++ b/pkg/offering/base/peer/peer_test.go @@ -47,7 +47,7 @@ import ( "github.com/IBM-Blockchain/fabric-operator/pkg/operatorerrors" "github.com/IBM-Blockchain/fabric-operator/pkg/util" "github.com/IBM-Blockchain/fabric-operator/version" - . "github.com/onsi/ginkgo" + . "github.com/onsi/ginkgo/v2" . "github.com/onsi/gomega" "github.com/pkg/errors" corev1 "k8s.io/api/core/v1" diff --git a/pkg/offering/common/common_suite_test.go b/pkg/offering/common/common_suite_test.go index 9dbd6afc..22c05df0 100644 --- a/pkg/offering/common/common_suite_test.go +++ b/pkg/offering/common/common_suite_test.go @@ -21,7 +21,7 @@ package common_test import ( "testing" - . "github.com/onsi/ginkgo" + . "github.com/onsi/ginkgo/v2" . "github.com/onsi/gomega" ) diff --git a/pkg/offering/common/common_test.go b/pkg/offering/common/common_test.go index 1550105b..5004e361 100644 --- a/pkg/offering/common/common_test.go +++ b/pkg/offering/common/common_test.go @@ -25,7 +25,7 @@ import ( "errors" "time" - . "github.com/onsi/ginkgo" + . "github.com/onsi/ginkgo/v2" . "github.com/onsi/gomega" corev1 "k8s.io/api/core/v1" k8serrors "k8s.io/apimachinery/pkg/api/errors" diff --git a/pkg/offering/common/reconcilechecks/fabricversion_test.go b/pkg/offering/common/reconcilechecks/fabricversion_test.go index aed44f7e..e5a13c23 100644 --- a/pkg/offering/common/reconcilechecks/fabricversion_test.go +++ b/pkg/offering/common/reconcilechecks/fabricversion_test.go @@ -21,7 +21,7 @@ package reconcilechecks_test import ( "errors" - . "github.com/onsi/ginkgo" + . "github.com/onsi/ginkgo/v2" . "github.com/onsi/gomega" "github.com/IBM-Blockchain/fabric-operator/pkg/offering/common/reconcilechecks" diff --git a/pkg/offering/common/reconcilechecks/images/fabricversion_test.go b/pkg/offering/common/reconcilechecks/images/fabricversion_test.go index 4a52b949..4fd61742 100644 --- a/pkg/offering/common/reconcilechecks/images/fabricversion_test.go +++ b/pkg/offering/common/reconcilechecks/images/fabricversion_test.go @@ -19,7 +19,7 @@ package images_test import ( - . "github.com/onsi/ginkgo" + . "github.com/onsi/ginkgo/v2" . "github.com/onsi/gomega" current "github.com/IBM-Blockchain/fabric-operator/api/v1beta1" diff --git a/pkg/offering/common/reconcilechecks/images/images_suite_test.go b/pkg/offering/common/reconcilechecks/images/images_suite_test.go index ab2967f4..3fdaa9e1 100644 --- a/pkg/offering/common/reconcilechecks/images/images_suite_test.go +++ b/pkg/offering/common/reconcilechecks/images/images_suite_test.go @@ -21,7 +21,7 @@ package images_test import ( "testing" - . "github.com/onsi/ginkgo" + . "github.com/onsi/ginkgo/v2" . "github.com/onsi/gomega" ) diff --git a/pkg/offering/common/reconcilechecks/images/images_test.go b/pkg/offering/common/reconcilechecks/images/images_test.go index 8ee1085f..e104c36c 100644 --- a/pkg/offering/common/reconcilechecks/images/images_test.go +++ b/pkg/offering/common/reconcilechecks/images/images_test.go @@ -19,7 +19,7 @@ package images_test import ( - . "github.com/onsi/ginkgo" + . "github.com/onsi/ginkgo/v2" . "github.com/onsi/gomega" current "github.com/IBM-Blockchain/fabric-operator/api/v1beta1" diff --git a/pkg/offering/common/reconcilechecks/reconcilechecks_suite_test.go b/pkg/offering/common/reconcilechecks/reconcilechecks_suite_test.go index 0ca0c859..9a4721be 100644 --- a/pkg/offering/common/reconcilechecks/reconcilechecks_suite_test.go +++ b/pkg/offering/common/reconcilechecks/reconcilechecks_suite_test.go @@ -21,7 +21,7 @@ package reconcilechecks_test import ( "testing" - . "github.com/onsi/ginkgo" + . "github.com/onsi/ginkgo/v2" . "github.com/onsi/gomega" ) diff --git a/pkg/offering/k8s/ca/ca_suite_test.go b/pkg/offering/k8s/ca/ca_suite_test.go index 0c8b2e76..79d259f3 100644 --- a/pkg/offering/k8s/ca/ca_suite_test.go +++ b/pkg/offering/k8s/ca/ca_suite_test.go @@ -21,7 +21,7 @@ package k8sca_test import ( "testing" - . "github.com/onsi/ginkgo" + . "github.com/onsi/ginkgo/v2" . "github.com/onsi/gomega" ) diff --git a/pkg/offering/k8s/ca/ca_test.go b/pkg/offering/k8s/ca/ca_test.go index 273a7dcc..9f88d879 100644 --- a/pkg/offering/k8s/ca/ca_test.go +++ b/pkg/offering/k8s/ca/ca_test.go @@ -28,7 +28,7 @@ import ( "k8s.io/apimachinery/pkg/types" "sigs.k8s.io/controller-runtime/pkg/client" - . "github.com/onsi/ginkgo" + . "github.com/onsi/ginkgo/v2" . "github.com/onsi/gomega" "k8s.io/apimachinery/pkg/runtime" diff --git a/pkg/offering/k8s/ca/override/ingress_test.go b/pkg/offering/k8s/ca/override/ingress_test.go index f448e922..d631d7a2 100644 --- a/pkg/offering/k8s/ca/override/ingress_test.go +++ b/pkg/offering/k8s/ca/override/ingress_test.go @@ -19,7 +19,7 @@ package override_test import ( - . "github.com/onsi/ginkgo" + . "github.com/onsi/ginkgo/v2" . "github.com/onsi/gomega" networkingv1 "k8s.io/api/networking/v1" diff --git a/pkg/offering/k8s/ca/override/ingressv1beta1_test.go b/pkg/offering/k8s/ca/override/ingressv1beta1_test.go index 5947d540..e9f3f413 100644 --- a/pkg/offering/k8s/ca/override/ingressv1beta1_test.go +++ b/pkg/offering/k8s/ca/override/ingressv1beta1_test.go @@ -19,7 +19,7 @@ package override_test import ( - . "github.com/onsi/ginkgo" + . "github.com/onsi/ginkgo/v2" . "github.com/onsi/gomega" networkingv1beta1 "k8s.io/api/networking/v1beta1" "k8s.io/apimachinery/pkg/util/intstr" diff --git a/pkg/offering/k8s/ca/override/override_suite_test.go b/pkg/offering/k8s/ca/override/override_suite_test.go index fa47c9b8..27096c13 100644 --- a/pkg/offering/k8s/ca/override/override_suite_test.go +++ b/pkg/offering/k8s/ca/override/override_suite_test.go @@ -21,7 +21,7 @@ package override_test import ( "testing" - . "github.com/onsi/ginkgo" + . "github.com/onsi/ginkgo/v2" . "github.com/onsi/gomega" ) diff --git a/pkg/offering/k8s/ca/override/override_test.go b/pkg/offering/k8s/ca/override/override_test.go index a1541404..c842600c 100644 --- a/pkg/offering/k8s/ca/override/override_test.go +++ b/pkg/offering/k8s/ca/override/override_test.go @@ -19,7 +19,7 @@ package override_test import ( - . "github.com/onsi/ginkgo" + . "github.com/onsi/ginkgo/v2" . "github.com/onsi/gomega" current "github.com/IBM-Blockchain/fabric-operator/api/v1beta1" diff --git a/pkg/offering/k8s/console/console_suite_test.go b/pkg/offering/k8s/console/console_suite_test.go index 9235e8e1..68e867d9 100644 --- a/pkg/offering/k8s/console/console_suite_test.go +++ b/pkg/offering/k8s/console/console_suite_test.go @@ -21,7 +21,7 @@ package k8sconsole_test import ( "testing" - . "github.com/onsi/ginkgo" + . "github.com/onsi/ginkgo/v2" . "github.com/onsi/gomega" ) diff --git a/pkg/offering/k8s/console/console_test.go b/pkg/offering/k8s/console/console_test.go index d75a218e..cba9e9aa 100644 --- a/pkg/offering/k8s/console/console_test.go +++ b/pkg/offering/k8s/console/console_test.go @@ -27,7 +27,7 @@ import ( baseconsolemocks "github.com/IBM-Blockchain/fabric-operator/pkg/offering/base/console/mocks" k8sconsole "github.com/IBM-Blockchain/fabric-operator/pkg/offering/k8s/console" "github.com/IBM-Blockchain/fabric-operator/version" - . "github.com/onsi/ginkgo" + . "github.com/onsi/ginkgo/v2" . "github.com/onsi/gomega" "github.com/pkg/errors" "k8s.io/apimachinery/pkg/runtime" diff --git a/pkg/offering/k8s/console/override/consolecm_test.go b/pkg/offering/k8s/console/override/consolecm_test.go index 0d00b540..53c09d26 100644 --- a/pkg/offering/k8s/console/override/consolecm_test.go +++ b/pkg/offering/k8s/console/override/consolecm_test.go @@ -19,7 +19,7 @@ package override_test import ( - . "github.com/onsi/ginkgo" + . "github.com/onsi/ginkgo/v2" . "github.com/onsi/gomega" corev1 "k8s.io/api/core/v1" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" diff --git a/pkg/offering/k8s/console/override/deployercm_test.go b/pkg/offering/k8s/console/override/deployercm_test.go index 928798ea..1127960c 100644 --- a/pkg/offering/k8s/console/override/deployercm_test.go +++ b/pkg/offering/k8s/console/override/deployercm_test.go @@ -21,7 +21,7 @@ package override_test import ( "fmt" - . "github.com/onsi/ginkgo" + . "github.com/onsi/ginkgo/v2" . "github.com/onsi/gomega" corev1 "k8s.io/api/core/v1" "sigs.k8s.io/yaml" diff --git a/pkg/offering/k8s/console/override/envcm_test.go b/pkg/offering/k8s/console/override/envcm_test.go index afa0225a..ded8f1e9 100644 --- a/pkg/offering/k8s/console/override/envcm_test.go +++ b/pkg/offering/k8s/console/override/envcm_test.go @@ -21,7 +21,7 @@ package override_test import ( "fmt" - . "github.com/onsi/ginkgo" + . "github.com/onsi/ginkgo/v2" . "github.com/onsi/gomega" corev1 "k8s.io/api/core/v1" diff --git a/pkg/offering/k8s/console/override/ingress_test.go b/pkg/offering/k8s/console/override/ingress_test.go index 13044871..b6266e39 100644 --- a/pkg/offering/k8s/console/override/ingress_test.go +++ b/pkg/offering/k8s/console/override/ingress_test.go @@ -19,7 +19,7 @@ package override_test import ( - . "github.com/onsi/ginkgo" + . "github.com/onsi/ginkgo/v2" . "github.com/onsi/gomega" networkingv1 "k8s.io/api/networking/v1" diff --git a/pkg/offering/k8s/console/override/ingressv1beta1_test.go b/pkg/offering/k8s/console/override/ingressv1beta1_test.go index 847038fb..09c2d264 100644 --- a/pkg/offering/k8s/console/override/ingressv1beta1_test.go +++ b/pkg/offering/k8s/console/override/ingressv1beta1_test.go @@ -19,7 +19,7 @@ package override_test import ( - . "github.com/onsi/ginkgo" + . "github.com/onsi/ginkgo/v2" . "github.com/onsi/gomega" networkingv1beta1 "k8s.io/api/networking/v1beta1" "k8s.io/apimachinery/pkg/util/intstr" diff --git a/pkg/offering/k8s/console/override/override_suite_test.go b/pkg/offering/k8s/console/override/override_suite_test.go index fa47c9b8..27096c13 100644 --- a/pkg/offering/k8s/console/override/override_suite_test.go +++ b/pkg/offering/k8s/console/override/override_suite_test.go @@ -21,7 +21,7 @@ package override_test import ( "testing" - . "github.com/onsi/ginkgo" + . "github.com/onsi/ginkgo/v2" . "github.com/onsi/gomega" ) diff --git a/pkg/offering/k8s/console/override/override_test.go b/pkg/offering/k8s/console/override/override_test.go index 06476a22..99260db3 100644 --- a/pkg/offering/k8s/console/override/override_test.go +++ b/pkg/offering/k8s/console/override/override_test.go @@ -19,7 +19,7 @@ package override_test import ( - . "github.com/onsi/ginkgo" + . "github.com/onsi/ginkgo/v2" . "github.com/onsi/gomega" networkingv1 "k8s.io/api/networking/v1" diff --git a/pkg/offering/k8s/orderer/orderer_suite_test.go b/pkg/offering/k8s/orderer/orderer_suite_test.go index 99e4d4f3..161bfa44 100644 --- a/pkg/offering/k8s/orderer/orderer_suite_test.go +++ b/pkg/offering/k8s/orderer/orderer_suite_test.go @@ -21,7 +21,7 @@ package k8sorderer_test import ( "testing" - . "github.com/onsi/ginkgo" + . "github.com/onsi/ginkgo/v2" . "github.com/onsi/gomega" ) diff --git a/pkg/offering/k8s/orderer/orderer_test.go b/pkg/offering/k8s/orderer/orderer_test.go index 91311c30..9ef5e3e4 100644 --- a/pkg/offering/k8s/orderer/orderer_test.go +++ b/pkg/offering/k8s/orderer/orderer_test.go @@ -26,7 +26,7 @@ import ( baseorderer "github.com/IBM-Blockchain/fabric-operator/pkg/offering/base/orderer" "github.com/IBM-Blockchain/fabric-operator/pkg/offering/base/orderer/mocks" k8sorderer "github.com/IBM-Blockchain/fabric-operator/pkg/offering/k8s/orderer" - . "github.com/onsi/ginkgo" + . "github.com/onsi/ginkgo/v2" . "github.com/onsi/gomega" "k8s.io/apimachinery/pkg/runtime" ) diff --git a/pkg/offering/k8s/orderer/override/ingress_test.go b/pkg/offering/k8s/orderer/override/ingress_test.go index 8bd72bd2..28b20dc2 100644 --- a/pkg/offering/k8s/orderer/override/ingress_test.go +++ b/pkg/offering/k8s/orderer/override/ingress_test.go @@ -19,7 +19,7 @@ package override_test import ( - . "github.com/onsi/ginkgo" + . "github.com/onsi/ginkgo/v2" . "github.com/onsi/gomega" networkingv1 "k8s.io/api/networking/v1" diff --git a/pkg/offering/k8s/orderer/override/ingressv1beta1_test.go b/pkg/offering/k8s/orderer/override/ingressv1beta1_test.go index 2fefb0d5..7c1411e2 100644 --- a/pkg/offering/k8s/orderer/override/ingressv1beta1_test.go +++ b/pkg/offering/k8s/orderer/override/ingressv1beta1_test.go @@ -19,7 +19,7 @@ package override_test import ( - . "github.com/onsi/ginkgo" + . "github.com/onsi/ginkgo/v2" . "github.com/onsi/gomega" networkingv1beta1 "k8s.io/api/networking/v1beta1" "k8s.io/apimachinery/pkg/util/intstr" diff --git a/pkg/offering/k8s/orderer/override/override_suite_test.go b/pkg/offering/k8s/orderer/override/override_suite_test.go index fa47c9b8..27096c13 100644 --- a/pkg/offering/k8s/orderer/override/override_suite_test.go +++ b/pkg/offering/k8s/orderer/override/override_suite_test.go @@ -21,7 +21,7 @@ package override_test import ( "testing" - . "github.com/onsi/ginkgo" + . "github.com/onsi/ginkgo/v2" . "github.com/onsi/gomega" ) diff --git a/pkg/offering/k8s/orderer/override/override_test.go b/pkg/offering/k8s/orderer/override/override_test.go index 176afc85..66a9be1c 100644 --- a/pkg/offering/k8s/orderer/override/override_test.go +++ b/pkg/offering/k8s/orderer/override/override_test.go @@ -19,7 +19,7 @@ package override_test import ( - . "github.com/onsi/ginkgo" + . "github.com/onsi/ginkgo/v2" . "github.com/onsi/gomega" networkingv1 "k8s.io/api/networking/v1" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" diff --git a/pkg/offering/k8s/peer/override/ingress_test.go b/pkg/offering/k8s/peer/override/ingress_test.go index 0ee00237..26cb984c 100644 --- a/pkg/offering/k8s/peer/override/ingress_test.go +++ b/pkg/offering/k8s/peer/override/ingress_test.go @@ -19,7 +19,7 @@ package override_test import ( - . "github.com/onsi/ginkgo" + . "github.com/onsi/ginkgo/v2" . "github.com/onsi/gomega" current "github.com/IBM-Blockchain/fabric-operator/api/v1beta1" diff --git a/pkg/offering/k8s/peer/override/ingressv1beta1_test.go b/pkg/offering/k8s/peer/override/ingressv1beta1_test.go index 27eaeb13..ac14462d 100644 --- a/pkg/offering/k8s/peer/override/ingressv1beta1_test.go +++ b/pkg/offering/k8s/peer/override/ingressv1beta1_test.go @@ -19,7 +19,7 @@ package override_test import ( - . "github.com/onsi/ginkgo" + . "github.com/onsi/ginkgo/v2" . "github.com/onsi/gomega" current "github.com/IBM-Blockchain/fabric-operator/api/v1beta1" diff --git a/pkg/offering/k8s/peer/override/override_suite_test.go b/pkg/offering/k8s/peer/override/override_suite_test.go index fa47c9b8..27096c13 100644 --- a/pkg/offering/k8s/peer/override/override_suite_test.go +++ b/pkg/offering/k8s/peer/override/override_suite_test.go @@ -21,7 +21,7 @@ package override_test import ( "testing" - . "github.com/onsi/ginkgo" + . "github.com/onsi/ginkgo/v2" . "github.com/onsi/gomega" ) diff --git a/pkg/offering/k8s/peer/peer_suite_test.go b/pkg/offering/k8s/peer/peer_suite_test.go index ad9830b2..3e57cf2f 100644 --- a/pkg/offering/k8s/peer/peer_suite_test.go +++ b/pkg/offering/k8s/peer/peer_suite_test.go @@ -21,7 +21,7 @@ package k8speer_test import ( "testing" - . "github.com/onsi/ginkgo" + . "github.com/onsi/ginkgo/v2" . "github.com/onsi/gomega" ) diff --git a/pkg/offering/k8s/peer/peer_test.go b/pkg/offering/k8s/peer/peer_test.go index b55d9120..be33a190 100644 --- a/pkg/offering/k8s/peer/peer_test.go +++ b/pkg/offering/k8s/peer/peer_test.go @@ -32,7 +32,7 @@ import ( k8speer "github.com/IBM-Blockchain/fabric-operator/pkg/offering/k8s/peer" "github.com/IBM-Blockchain/fabric-operator/pkg/operatorerrors" "github.com/IBM-Blockchain/fabric-operator/version" - . "github.com/onsi/ginkgo" + . "github.com/onsi/ginkgo/v2" . "github.com/onsi/gomega" "github.com/pkg/errors" corev1 "k8s.io/api/core/v1" diff --git a/pkg/offering/offering_suite_test.go b/pkg/offering/offering_suite_test.go index 110495f3..5f9f7eb0 100644 --- a/pkg/offering/offering_suite_test.go +++ b/pkg/offering/offering_suite_test.go @@ -21,7 +21,7 @@ package offering_test import ( "testing" - . "github.com/onsi/ginkgo" + . "github.com/onsi/ginkgo/v2" . "github.com/onsi/gomega" ) diff --git a/pkg/offering/offering_test.go b/pkg/offering/offering_test.go index 6eb853b7..6af68072 100644 --- a/pkg/offering/offering_test.go +++ b/pkg/offering/offering_test.go @@ -20,7 +20,7 @@ package offering_test import ( "github.com/IBM-Blockchain/fabric-operator/pkg/offering" - . "github.com/onsi/ginkgo" + . "github.com/onsi/ginkgo/v2" . "github.com/onsi/gomega" ) diff --git a/pkg/offering/openshift/ca/ca_suite_test.go b/pkg/offering/openshift/ca/ca_suite_test.go index 8cf7db26..87e125c8 100644 --- a/pkg/offering/openshift/ca/ca_suite_test.go +++ b/pkg/offering/openshift/ca/ca_suite_test.go @@ -21,7 +21,7 @@ package openshiftca_test import ( "testing" - . "github.com/onsi/ginkgo" + . "github.com/onsi/ginkgo/v2" . "github.com/onsi/gomega" ) diff --git a/pkg/offering/openshift/ca/ca_test.go b/pkg/offering/openshift/ca/ca_test.go index 2325bbce..2e662031 100644 --- a/pkg/offering/openshift/ca/ca_test.go +++ b/pkg/offering/openshift/ca/ca_test.go @@ -22,7 +22,7 @@ import ( "encoding/json" "path/filepath" - . "github.com/onsi/ginkgo" + . "github.com/onsi/ginkgo/v2" . "github.com/onsi/gomega" "k8s.io/apimachinery/pkg/types" "sigs.k8s.io/controller-runtime/pkg/client" diff --git a/pkg/offering/openshift/ca/override/override_suite_test.go b/pkg/offering/openshift/ca/override/override_suite_test.go index fa47c9b8..27096c13 100644 --- a/pkg/offering/openshift/ca/override/override_suite_test.go +++ b/pkg/offering/openshift/ca/override/override_suite_test.go @@ -21,7 +21,7 @@ package override_test import ( "testing" - . "github.com/onsi/ginkgo" + . "github.com/onsi/ginkgo/v2" . "github.com/onsi/gomega" ) diff --git a/pkg/offering/openshift/ca/override/override_test.go b/pkg/offering/openshift/ca/override/override_test.go index 5ec03cc2..525d6f43 100644 --- a/pkg/offering/openshift/ca/override/override_test.go +++ b/pkg/offering/openshift/ca/override/override_test.go @@ -21,7 +21,7 @@ package override_test import ( "fmt" - . "github.com/onsi/ginkgo" + . "github.com/onsi/ginkgo/v2" . "github.com/onsi/gomega" "k8s.io/apimachinery/pkg/util/intstr" diff --git a/pkg/offering/openshift/console/console_suite_test.go b/pkg/offering/openshift/console/console_suite_test.go index 75e0e62c..994617dd 100644 --- a/pkg/offering/openshift/console/console_suite_test.go +++ b/pkg/offering/openshift/console/console_suite_test.go @@ -21,7 +21,7 @@ package openshiftconsole_test import ( "testing" - . "github.com/onsi/ginkgo" + . "github.com/onsi/ginkgo/v2" . "github.com/onsi/gomega" ) diff --git a/pkg/offering/openshift/console/console_test.go b/pkg/offering/openshift/console/console_test.go index c99e70c9..48250753 100644 --- a/pkg/offering/openshift/console/console_test.go +++ b/pkg/offering/openshift/console/console_test.go @@ -19,7 +19,7 @@ package openshiftconsole_test import ( - . "github.com/onsi/ginkgo" + . "github.com/onsi/ginkgo/v2" . "github.com/onsi/gomega" current "github.com/IBM-Blockchain/fabric-operator/api/v1beta1" diff --git a/pkg/offering/openshift/console/override/consolecm_test.go b/pkg/offering/openshift/console/override/consolecm_test.go index 0f34c990..211f3f4d 100644 --- a/pkg/offering/openshift/console/override/consolecm_test.go +++ b/pkg/offering/openshift/console/override/consolecm_test.go @@ -19,7 +19,7 @@ package override_test import ( - . "github.com/onsi/ginkgo" + . "github.com/onsi/ginkgo/v2" . "github.com/onsi/gomega" corev1 "k8s.io/api/core/v1" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" diff --git a/pkg/offering/openshift/console/override/consoleroute_test.go b/pkg/offering/openshift/console/override/consoleroute_test.go index 15158346..a5982d60 100644 --- a/pkg/offering/openshift/console/override/consoleroute_test.go +++ b/pkg/offering/openshift/console/override/consoleroute_test.go @@ -21,7 +21,7 @@ package override_test import ( "fmt" - . "github.com/onsi/ginkgo" + . "github.com/onsi/ginkgo/v2" . "github.com/onsi/gomega" "k8s.io/apimachinery/pkg/util/intstr" diff --git a/pkg/offering/openshift/console/override/deployercm_test.go b/pkg/offering/openshift/console/override/deployercm_test.go index 3bbd2ee6..51ddfc20 100644 --- a/pkg/offering/openshift/console/override/deployercm_test.go +++ b/pkg/offering/openshift/console/override/deployercm_test.go @@ -19,7 +19,7 @@ package override_test import ( - . "github.com/onsi/ginkgo" + . "github.com/onsi/ginkgo/v2" . "github.com/onsi/gomega" corev1 "k8s.io/api/core/v1" "sigs.k8s.io/yaml" diff --git a/pkg/offering/openshift/console/override/envcm_test.go b/pkg/offering/openshift/console/override/envcm_test.go index 108b90de..008cac03 100644 --- a/pkg/offering/openshift/console/override/envcm_test.go +++ b/pkg/offering/openshift/console/override/envcm_test.go @@ -21,7 +21,7 @@ package override_test import ( "fmt" - . "github.com/onsi/ginkgo" + . "github.com/onsi/ginkgo/v2" . "github.com/onsi/gomega" corev1 "k8s.io/api/core/v1" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" diff --git a/pkg/offering/openshift/console/override/override_suite_test.go b/pkg/offering/openshift/console/override/override_suite_test.go index fa47c9b8..27096c13 100644 --- a/pkg/offering/openshift/console/override/override_suite_test.go +++ b/pkg/offering/openshift/console/override/override_suite_test.go @@ -21,7 +21,7 @@ package override_test import ( "testing" - . "github.com/onsi/ginkgo" + . "github.com/onsi/ginkgo/v2" . "github.com/onsi/gomega" ) diff --git a/pkg/offering/openshift/console/override/proxyroute_test.go b/pkg/offering/openshift/console/override/proxyroute_test.go index b4542408..94c81a32 100644 --- a/pkg/offering/openshift/console/override/proxyroute_test.go +++ b/pkg/offering/openshift/console/override/proxyroute_test.go @@ -21,7 +21,7 @@ package override_test import ( "fmt" - . "github.com/onsi/ginkgo" + . "github.com/onsi/ginkgo/v2" . "github.com/onsi/gomega" "k8s.io/apimachinery/pkg/util/intstr" diff --git a/pkg/offering/openshift/orderer/orderer_suite_test.go b/pkg/offering/openshift/orderer/orderer_suite_test.go index 443e5799..c05addf8 100644 --- a/pkg/offering/openshift/orderer/orderer_suite_test.go +++ b/pkg/offering/openshift/orderer/orderer_suite_test.go @@ -21,7 +21,7 @@ package openshiftorderer_test import ( "testing" - . "github.com/onsi/ginkgo" + . "github.com/onsi/ginkgo/v2" . "github.com/onsi/gomega" ) diff --git a/pkg/offering/openshift/orderer/orderer_test.go b/pkg/offering/openshift/orderer/orderer_test.go index 250b4e37..5a9c3fb0 100644 --- a/pkg/offering/openshift/orderer/orderer_test.go +++ b/pkg/offering/openshift/orderer/orderer_test.go @@ -26,7 +26,7 @@ import ( baseorderer "github.com/IBM-Blockchain/fabric-operator/pkg/offering/base/orderer" "github.com/IBM-Blockchain/fabric-operator/pkg/offering/base/orderer/mocks" openshiftorderer "github.com/IBM-Blockchain/fabric-operator/pkg/offering/openshift/orderer" - . "github.com/onsi/ginkgo" + . "github.com/onsi/ginkgo/v2" . "github.com/onsi/gomega" "k8s.io/apimachinery/pkg/runtime" ) diff --git a/pkg/offering/openshift/orderer/override/override_suite_test.go b/pkg/offering/openshift/orderer/override/override_suite_test.go index fa47c9b8..27096c13 100644 --- a/pkg/offering/openshift/orderer/override/override_suite_test.go +++ b/pkg/offering/openshift/orderer/override/override_suite_test.go @@ -21,7 +21,7 @@ package override_test import ( "testing" - . "github.com/onsi/ginkgo" + . "github.com/onsi/ginkgo/v2" . "github.com/onsi/gomega" ) diff --git a/pkg/offering/openshift/orderer/override/override_test.go b/pkg/offering/openshift/orderer/override/override_test.go index cf295316..2b022bdc 100644 --- a/pkg/offering/openshift/orderer/override/override_test.go +++ b/pkg/offering/openshift/orderer/override/override_test.go @@ -21,7 +21,7 @@ package override_test import ( "fmt" - . "github.com/onsi/ginkgo" + . "github.com/onsi/ginkgo/v2" . "github.com/onsi/gomega" "k8s.io/apimachinery/pkg/util/intstr" diff --git a/pkg/offering/openshift/peer/override/override_suite_test.go b/pkg/offering/openshift/peer/override/override_suite_test.go index fa47c9b8..27096c13 100644 --- a/pkg/offering/openshift/peer/override/override_suite_test.go +++ b/pkg/offering/openshift/peer/override/override_suite_test.go @@ -21,7 +21,7 @@ package override_test import ( "testing" - . "github.com/onsi/ginkgo" + . "github.com/onsi/ginkgo/v2" . "github.com/onsi/gomega" ) diff --git a/pkg/offering/openshift/peer/override/override_test.go b/pkg/offering/openshift/peer/override/override_test.go index 3e72b053..296c4b7b 100644 --- a/pkg/offering/openshift/peer/override/override_test.go +++ b/pkg/offering/openshift/peer/override/override_test.go @@ -21,7 +21,7 @@ package override_test import ( "fmt" - . "github.com/onsi/ginkgo" + . "github.com/onsi/ginkgo/v2" . "github.com/onsi/gomega" "k8s.io/apimachinery/pkg/util/intstr" diff --git a/pkg/offering/openshift/peer/peer_suite_test.go b/pkg/offering/openshift/peer/peer_suite_test.go index 2d60b312..455d92e7 100644 --- a/pkg/offering/openshift/peer/peer_suite_test.go +++ b/pkg/offering/openshift/peer/peer_suite_test.go @@ -21,7 +21,7 @@ package openshiftpeer_test import ( "testing" - . "github.com/onsi/ginkgo" + . "github.com/onsi/ginkgo/v2" . "github.com/onsi/gomega" ) diff --git a/pkg/offering/openshift/peer/peer_test.go b/pkg/offering/openshift/peer/peer_test.go index ba2768ff..ae6b9049 100644 --- a/pkg/offering/openshift/peer/peer_test.go +++ b/pkg/offering/openshift/peer/peer_test.go @@ -33,7 +33,7 @@ import ( openshiftpeer "github.com/IBM-Blockchain/fabric-operator/pkg/offering/openshift/peer" "github.com/IBM-Blockchain/fabric-operator/pkg/operatorerrors" "github.com/IBM-Blockchain/fabric-operator/version" - . "github.com/onsi/ginkgo" + . "github.com/onsi/ginkgo/v2" . "github.com/onsi/gomega" "github.com/pkg/errors" corev1 "k8s.io/api/core/v1" diff --git a/pkg/operatorerrors/errors_test.go b/pkg/operatorerrors/errors_test.go index 096ac474..3006abce 100644 --- a/pkg/operatorerrors/errors_test.go +++ b/pkg/operatorerrors/errors_test.go @@ -21,7 +21,7 @@ package operatorerrors_test import ( "errors" - . "github.com/onsi/ginkgo" + . "github.com/onsi/ginkgo/v2" . "github.com/onsi/gomega" "github.com/IBM-Blockchain/fabric-operator/pkg/operatorerrors" diff --git a/pkg/operatorerrors/operatorerrors_suite_test.go b/pkg/operatorerrors/operatorerrors_suite_test.go index c25c246b..9b5047f6 100644 --- a/pkg/operatorerrors/operatorerrors_suite_test.go +++ b/pkg/operatorerrors/operatorerrors_suite_test.go @@ -21,7 +21,7 @@ package operatorerrors_test import ( "testing" - . "github.com/onsi/ginkgo" + . "github.com/onsi/ginkgo/v2" . "github.com/onsi/gomega" ) diff --git a/pkg/restart/configmap/configmap_suite_test.go b/pkg/restart/configmap/configmap_suite_test.go index 6656157b..b05445aa 100644 --- a/pkg/restart/configmap/configmap_suite_test.go +++ b/pkg/restart/configmap/configmap_suite_test.go @@ -21,7 +21,7 @@ package configmap_test import ( "testing" - . "github.com/onsi/ginkgo" + . "github.com/onsi/ginkgo/v2" . "github.com/onsi/gomega" ) diff --git a/pkg/restart/configmap/configmap_test.go b/pkg/restart/configmap/configmap_test.go index 6c90a7ce..30266929 100644 --- a/pkg/restart/configmap/configmap_test.go +++ b/pkg/restart/configmap/configmap_test.go @@ -23,7 +23,7 @@ import ( "encoding/json" "errors" - . "github.com/onsi/ginkgo" + . "github.com/onsi/ginkgo/v2" . "github.com/onsi/gomega" "sigs.k8s.io/controller-runtime/pkg/client" diff --git a/pkg/restart/restart_suite_test.go b/pkg/restart/restart_suite_test.go index e30d4dbf..ad3a0e83 100644 --- a/pkg/restart/restart_suite_test.go +++ b/pkg/restart/restart_suite_test.go @@ -21,7 +21,7 @@ package restart_test import ( "testing" - . "github.com/onsi/ginkgo" + . "github.com/onsi/ginkgo/v2" . "github.com/onsi/gomega" ) diff --git a/pkg/restart/restart_test.go b/pkg/restart/restart_test.go index 0e2bc1ba..a8ce56a6 100644 --- a/pkg/restart/restart_test.go +++ b/pkg/restart/restart_test.go @@ -24,7 +24,7 @@ import ( "errors" "time" - . "github.com/onsi/ginkgo" + . "github.com/onsi/ginkgo/v2" . "github.com/onsi/gomega" "sigs.k8s.io/controller-runtime/pkg/client" diff --git a/pkg/restart/staggerrestarts/staggerrestarts_suite_test.go b/pkg/restart/staggerrestarts/staggerrestarts_suite_test.go index ea8d20b5..3664f76f 100644 --- a/pkg/restart/staggerrestarts/staggerrestarts_suite_test.go +++ b/pkg/restart/staggerrestarts/staggerrestarts_suite_test.go @@ -21,7 +21,7 @@ package staggerrestarts_test import ( "testing" - . "github.com/onsi/ginkgo" + . "github.com/onsi/ginkgo/v2" . "github.com/onsi/gomega" ) diff --git a/pkg/restart/staggerrestarts/staggerrestarts_test.go b/pkg/restart/staggerrestarts/staggerrestarts_test.go index 9100fbe0..739170fe 100644 --- a/pkg/restart/staggerrestarts/staggerrestarts_test.go +++ b/pkg/restart/staggerrestarts/staggerrestarts_test.go @@ -24,7 +24,7 @@ import ( "errors" "time" - . "github.com/onsi/ginkgo" + . "github.com/onsi/ginkgo/v2" . "github.com/onsi/gomega" current "github.com/IBM-Blockchain/fabric-operator/api/v1beta1" diff --git a/pkg/util/merge/merge_suite_test.go b/pkg/util/merge/merge_suite_test.go index 10fc32a6..480e6c1c 100644 --- a/pkg/util/merge/merge_suite_test.go +++ b/pkg/util/merge/merge_suite_test.go @@ -21,7 +21,7 @@ package merge_test import ( "testing" - . "github.com/onsi/ginkgo" + . "github.com/onsi/ginkgo/v2" . "github.com/onsi/gomega" ) diff --git a/pkg/util/merge/merge_test.go b/pkg/util/merge/merge_test.go index 867c7b40..6408ac9e 100644 --- a/pkg/util/merge/merge_test.go +++ b/pkg/util/merge/merge_test.go @@ -20,7 +20,7 @@ package merge_test import ( "github.com/IBM-Blockchain/fabric-operator/pkg/util/merge" - . "github.com/onsi/ginkgo" + . "github.com/onsi/ginkgo/v2" . "github.com/onsi/gomega" ) diff --git a/pkg/util/util_suite_test.go b/pkg/util/util_suite_test.go index 71e17126..2e561367 100644 --- a/pkg/util/util_suite_test.go +++ b/pkg/util/util_suite_test.go @@ -22,7 +22,7 @@ import ( "net" "testing" - . "github.com/onsi/ginkgo" + . "github.com/onsi/ginkgo/v2" . "github.com/onsi/gomega" ) diff --git a/pkg/util/util_test.go b/pkg/util/util_test.go index eb1ffcb8..30e385ea 100644 --- a/pkg/util/util_test.go +++ b/pkg/util/util_test.go @@ -22,7 +22,7 @@ import ( "errors" "github.com/IBM-Blockchain/fabric-operator/pkg/util" - . "github.com/onsi/ginkgo" + . "github.com/onsi/ginkgo/v2" . "github.com/onsi/gomega" corev1 "k8s.io/api/core/v1" "k8s.io/apimachinery/pkg/api/resource" diff --git a/version/version_suite_test.go b/version/version_suite_test.go index ca689e55..8c09f260 100644 --- a/version/version_suite_test.go +++ b/version/version_suite_test.go @@ -21,7 +21,7 @@ package version_test import ( "testing" - . "github.com/onsi/ginkgo" + . "github.com/onsi/ginkgo/v2" . "github.com/onsi/gomega" ) diff --git a/version/version_test.go b/version/version_test.go index 08bc785b..9f91445c 100644 --- a/version/version_test.go +++ b/version/version_test.go @@ -19,7 +19,7 @@ package version_test import ( - . "github.com/onsi/ginkgo" + . "github.com/onsi/ginkgo/v2" . "github.com/onsi/gomega" "github.com/IBM-Blockchain/fabric-operator/version" From 224b6199efd25177175ad2c286a2ea9428f0d0f6 Mon Sep 17 00:00:00 2001 From: Josh Kneubuhl Date: Fri, 8 Jul 2022 07:43:19 -0400 Subject: [PATCH 02/41] bump sample network to use fabric CA v1.5.5 Signed-off-by: Josh Kneubuhl --- sample-network/network | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sample-network/network b/sample-network/network index 326d95ae..933dc5f5 100755 --- a/sample-network/network +++ b/sample-network/network @@ -32,7 +32,7 @@ function context() { } context FABRIC_VERSION 2.4.4 -context FABRIC_CA_VERSION 1.5.4 +context FABRIC_CA_VERSION 1.5.5 context CLUSTER_RUNTIME kind # or k3s for Rancher context CONTAINER_CLI docker # or nerdctl for containerd From 3282311eca605ee74ce40995a566c99ba15b8ba6 Mon Sep 17 00:00:00 2001 From: asararatnakar Date: Tue, 26 Jul 2022 09:37:53 -0400 Subject: [PATCH 03/41] Adding changes for auto-cert renewal Signed-off-by: asararatnakar --- pkg/offering/base/peer/peer.go | 167 +++++++++++++++++ pkg/offering/base/peer/peer_test.go | 277 ++++++++++++++++++++++++++++ 2 files changed, 444 insertions(+) diff --git a/pkg/offering/base/peer/peer.go b/pkg/offering/base/peer/peer.go index 5eb4896c..b4d0d301 100644 --- a/pkg/offering/base/peer/peer.go +++ b/pkg/offering/base/peer/peer.go @@ -77,6 +77,8 @@ const ( defaultServiceAccount = "./definitions/peer/serviceaccount.yaml" defaultRoleBinding = "./definitions/peer/rolebinding.yaml" defaultFluentdConfigMap = "./definitions/peer/fluentd-configmap.yaml" + + DaysToSecondsConversion = int64(24 * 60 * 60) ) type Override interface { @@ -1582,5 +1584,170 @@ func (p *Peer) RenewCert(certType commoninit.SecretType, obj runtime.Object, new func (p *Peer) CustomLogic(instance *current.IBPPeer, update Update) (*current.CRStatus, *common.Result, error) { var status *current.CRStatus var err error + + if !p.CanSetCertificateTimer(instance, update) { + log.Info("Certificate update detected but peer not yet deployed, requeuing request...") + return status, &common.Result{ + Result: reconcile.Result{ + Requeue: true, + }, + }, nil + } + + // Check if crypto needs to be backed up before an update overrides exisitng secrets + if update.CryptoBackupNeeded() { + log.Info("Performing backup of TLS and ecert crypto") + err = common.BackupCrypto(p.Client, p.Scheme, instance, p.GetLabels(instance)) + if err != nil { + return status, nil, errors.Wrap(err, "failed to backup TLS and ecert crypto") + } + } + + status, err = p.CheckCertificates(instance) + if err != nil { + return status, nil, errors.Wrap(err, "failed to check for expiring certificates") + } + + if update.CertificateCreated() { + log.Info(fmt.Sprintf("%s certificate was created", update.GetCreatedCertType())) + err = p.SetCertificateTimer(instance, update.GetCreatedCertType()) + if err != nil { + return status, nil, errors.Wrap(err, "failed to set timer for certificate renewal") + } + } + + if update.EcertUpdated() { + log.Info("Ecert was updated") + err = p.SetCertificateTimer(instance, commoninit.ECERT) + if err != nil { + return status, nil, errors.Wrap(err, "failed to set timer for certificate renewal") + } + } + + if update.TLSCertUpdated() { + log.Info("TLS cert was updated") + err = p.SetCertificateTimer(instance, commoninit.TLS) + if err != nil { + return status, nil, errors.Wrap(err, "failed to set timer for certificate renewal") + } + } + return status, nil, err + +} + +func (p *Peer) CheckCertificates(instance *current.IBPPeer) (*current.CRStatus, error) { + numSecondsBeforeExpire := instance.Spec.GetNumSecondsWarningPeriod() + statusType, message, err := p.CertificateManager.CheckCertificatesForExpire(instance, numSecondsBeforeExpire) + if err != nil { + return nil, err + } + + crStatus := ¤t.CRStatus{ + Type: statusType, + Message: message, + } + + switch statusType { + case current.Deployed: + crStatus.Reason = "allPodsDeployed" + default: + crStatus.Reason = "certRenewalRequired" + } + + return crStatus, nil +} + +func (p *Peer) SetCertificateTimer(instance *current.IBPPeer, certType commoninit.SecretType) error { + certName := fmt.Sprintf("%s-%s-signcert", certType, instance.Name) + numSecondsBeforeExpire := instance.Spec.GetNumSecondsWarningPeriod() + duration, err := p.CertificateManager.GetDurationToNextRenewal(certType, instance, numSecondsBeforeExpire) + if err != nil { + return err + } + + log.Info((fmt.Sprintf("Setting timer to renew %s %d days before it expires", certName, int(numSecondsBeforeExpire/DaysToSecondsConversion)))) + + if p.RenewCertTimers[certName] != nil { + p.RenewCertTimers[certName].Stop() + p.RenewCertTimers[certName] = nil + } + p.RenewCertTimers[certName] = time.AfterFunc(duration, func() { + // Check certs for updated status & set status so that reconcile is triggered after cert renewal. Reconcile loop will handle + // checking certs again to determine whether instance status can return to Deployed + err := p.UpdateCRStatus(instance) + if err != nil { + log.Error(err, "failed to update CR status") + } + + // get instance + instanceLatest := ¤t.IBPPeer{} + err = p.Client.Get(context.TODO(), types.NamespacedName{Namespace: instance.Namespace, Name: instance.Name}, instanceLatest) + if err != nil { + log.Error(err, "failed to get latest instance") + return + } + + err = common.BackupCrypto(p.Client, p.Scheme, instance, p.GetLabels(instance)) + if err != nil { + log.Error(err, "failed to backup crypto before renewing cert") + return + } + + err = p.RenewCert(certType, instanceLatest, false) + if err != nil { + log.Info(fmt.Sprintf("Failed to renew %s certificate: %s, status of %s remaining in Warning phase", certType, err, instanceLatest.GetName())) + return + } + log.Info(fmt.Sprintf("%s renewal complete", certName)) + }) + + return nil +} + +// NOTE: This is called by the timer's subroutine when it goes off, not during a reconcile loop. +// Therefore, it won't be overriden by the "SetStatus" method in ibppeer_controller.go +func (p *Peer) UpdateCRStatus(instance *current.IBPPeer) error { + status, err := p.CheckCertificates(instance) + if err != nil { + return errors.Wrap(err, "failed to check certificates") + } + + // Get most up-to-date instance at the time of update + updatedInstance := ¤t.IBPPeer{} + err = p.Client.Get(context.TODO(), types.NamespacedName{Name: instance.Name, Namespace: instance.Namespace}, updatedInstance) + if err != nil { + return errors.Wrap(err, "failed to get new instance") + } + + // Don't trigger reconcile if status remaining the same + if updatedInstance.Status.Type == status.Type && updatedInstance.Status.Reason == status.Reason && updatedInstance.Status.Message == status.Message { + return nil + } + + updatedInstance.Status.Type = status.Type + updatedInstance.Status.Reason = status.Reason + updatedInstance.Status.Message = status.Message + updatedInstance.Status.Status = current.True + updatedInstance.Status.LastHeartbeatTime = time.Now().String() + + log.Info(fmt.Sprintf("Updating status of IBPPeer custom resource %s to %s phase", instance.Name, status.Type)) + err = p.Client.UpdateStatus(context.TODO(), updatedInstance) + if err != nil { + return errors.Wrapf(err, "failed to update status to %s phase", status.Type) + } + + return nil +} + +// This function checks whether the instance is in Deployed or Warning state when a cert +// update is detected. Only if Deployed or in Warning will a timer be set; otherwise, +// the update will be requeued until the Peer has completed deploying. +func (p *Peer) CanSetCertificateTimer(instance *current.IBPPeer, update Update) bool { + if update.CertificateCreated() || update.CertificateUpdated() { + if !(instance.Status.Type == current.Deployed || instance.Status.Type == current.Warning) { + return false + } + } + return true } diff --git a/pkg/offering/base/peer/peer_test.go b/pkg/offering/base/peer/peer_test.go index e7c01c8d..de6db024 100644 --- a/pkg/offering/base/peer/peer_test.go +++ b/pkg/offering/base/peer/peer_test.go @@ -29,12 +29,15 @@ import ( "math/big" "time" + k8serrors "k8s.io/apimachinery/pkg/api/errors" + current "github.com/IBM-Blockchain/fabric-operator/api/v1beta1" cmocks "github.com/IBM-Blockchain/fabric-operator/controllers/mocks" config "github.com/IBM-Blockchain/fabric-operator/operatorconfig" commonapi "github.com/IBM-Blockchain/fabric-operator/pkg/apis/common" "github.com/IBM-Blockchain/fabric-operator/pkg/apis/deployer" v1 "github.com/IBM-Blockchain/fabric-operator/pkg/apis/peer/v1" + "github.com/IBM-Blockchain/fabric-operator/pkg/certificate" commonconfig "github.com/IBM-Blockchain/fabric-operator/pkg/initializer/common/config" "github.com/IBM-Blockchain/fabric-operator/pkg/initializer/common/enroller" "github.com/IBM-Blockchain/fabric-operator/pkg/initializer/common/mspparser" @@ -54,6 +57,7 @@ import ( k8serror "k8s.io/apimachinery/pkg/api/errors" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" "k8s.io/apimachinery/pkg/runtime" + "k8s.io/apimachinery/pkg/runtime/schema" "k8s.io/apimachinery/pkg/types" "k8s.io/apimachinery/pkg/util/intstr" "sigs.k8s.io/controller-runtime/pkg/client" @@ -625,6 +629,279 @@ var _ = Describe("Base Peer", func() { Expect(instance.Spec.Secret.Enrollment.TLS.CSR.Hosts).To(ContainElement(hosts[1])) }) }) + Context("check certificates", func() { + It("returns error if fails to get certificate expiry info", func() { + certificateMgr.CheckCertificatesForExpireReturns("", "", errors.New("cert expiry error")) + _, err := peer.CheckCertificates(instance) + Expect(err).To(HaveOccurred()) + }) + + It("sets cr status with certificate expiry info", func() { + certificateMgr.CheckCertificatesForExpireReturns(current.Warning, "message", nil) + status, err := peer.CheckCertificates(instance) + Expect(err).NotTo(HaveOccurred()) + Expect(status.Type).To(Equal(current.Warning)) + Expect(status.Message).To(Equal("message")) + Expect(status.Reason).To(Equal("certRenewalRequired")) + }) + }) + + Context("set certificate timer", func() { + BeforeEach(func() { + instance.Spec.Secret = ¤t.SecretSpec{ + Enrollment: ¤t.EnrollmentSpec{ + TLS: ¤t.Enrollment{ + EnrollID: "enrollID", + }, + }, + } + mockKubeClient.GetStub = func(ctx context.Context, types types.NamespacedName, obj client.Object) error { + switch obj.(type) { + case *current.IBPPeer: + o := obj.(*current.IBPPeer) + o.Kind = "IBPPeer" + o.Name = "peer1" + o.Namespace = "random" + o.Spec.Secret = ¤t.SecretSpec{ + Enrollment: ¤t.EnrollmentSpec{ + TLS: ¤t.Enrollment{ + EnrollID: "enrollID", + }, + }, + } + case *corev1.Secret: + o := obj.(*corev1.Secret) + switch types.Name { + case "tls-" + instance.Name + "-signcert": + o.Name = "tls-" + instance.Name + "-signcert" + o.Namespace = instance.Namespace + o.Data = map[string][]byte{"cert.pem": generateCertPemBytes(29)} + case "tls-" + instance.Name + "-keystore": + o.Name = "tls-" + instance.Name + "-keystore" + o.Namespace = instance.Namespace + o.Data = map[string][]byte{"key.pem": []byte("")} + case instance.Name + "-crypto-backup": + return k8serrors.NewNotFound(schema.GroupResource{}, "not found") + } + } + return nil + } + }) + + It("returns error if unable to get duration to next renewal", func() { + certificateMgr.GetDurationToNextRenewalReturns(time.Duration(0), errors.New("failed to get duration")) + err := peer.SetCertificateTimer(instance, "tls") + Expect(err).To(HaveOccurred()) + Expect(err.Error()).To(Equal("failed to get duration")) + }) + + Context("sets timer to renew TLS certificate", func() { + BeforeEach(func() { + certificateMgr.GetDurationToNextRenewalReturns(time.Duration(3*time.Second), nil) + mockKubeClient.UpdateStatusReturns(nil) + certificateMgr.RenewCertReturns(nil) + }) + + It("does not return error, but certificate fails to renew after timer", func() { + certificateMgr.RenewCertReturns(errors.New("failed to renew cert")) + err := peer.SetCertificateTimer(instance, "tls") + Expect(err).NotTo(HaveOccurred()) + Expect(peer.RenewCertTimers["tls-peer1-signcert"]).NotTo(BeNil()) + + By("certificate fails to be renewed", func() { + Eventually(func() bool { + return mockKubeClient.UpdateStatusCallCount() == 1 && + certificateMgr.RenewCertCallCount() == 1 + }, time.Duration(5*time.Second)).Should(Equal(true)) + }) + + // timer.Stop() == false means that it already fired + Expect(peer.RenewCertTimers["tls-peer1-signcert"].Stop()).To(Equal(false)) + }) + + It("does not return error, and certificate is successfully renewed after timer", func() { + err := peer.SetCertificateTimer(instance, "tls") + Expect(err).NotTo(HaveOccurred()) + Expect(peer.RenewCertTimers["tls-peer1-signcert"]).NotTo(BeNil()) + + By("certificate successfully renewed", func() { + Eventually(func() bool { + return mockKubeClient.UpdateStatusCallCount() == 1 && + certificateMgr.RenewCertCallCount() == 1 + }, time.Duration(5*time.Second)).Should(Equal(true)) + }) + + // timer.Stop() == false means that it already fired + Expect(peer.RenewCertTimers["tls-peer1-signcert"].Stop()).To(Equal(false)) + }) + + It("does not return error, and timer is set to renew certificate at a later time", func() { + // Set expiration date of certificate to be > 30 days from now + certificateMgr.GetDurationToNextRenewalReturns(time.Duration(35*24*time.Hour), nil) + + err := peer.SetCertificateTimer(instance, "tls") + Expect(err).NotTo(HaveOccurred()) + Expect(peer.RenewCertTimers["tls-peer1-signcert"]).NotTo(BeNil()) + + // timer.Stop() == true means that it has not fired but is now stopped + Expect(peer.RenewCertTimers["tls-peer1-signcert"].Stop()).To(Equal(true)) + }) + }) + + Context("read certificate expiration date to set timer correctly", func() { + BeforeEach(func() { + peer.CertificateManager = &certificate.CertificateManager{ + Client: mockKubeClient, + Scheme: &runtime.Scheme{}, + } + + // set to 30 days + instance.Spec.NumSecondsWarningPeriod = 30 * basepeer.DaysToSecondsConversion + }) + + It("doesn't return error if timer is set correctly, but error in renewing certificate when timer goes off", func() { + // Set tls signcert expiration date to be 29 days from now, cert is renewed if expires within 30 days + mockKubeClient.GetStub = func(ctx context.Context, types types.NamespacedName, obj client.Object) error { + switch obj.(type) { + case *current.IBPPeer: + o := obj.(*current.IBPPeer) + o.Kind = "IBPPeer" + instance = o + + case *corev1.Secret: + o := obj.(*corev1.Secret) + switch types.Name { + case "tls-" + instance.Name + "-signcert": + o.Name = "tls-" + instance.Name + "-signcert" + o.Namespace = instance.Namespace + o.Data = map[string][]byte{"cert.pem": generateCertPemBytes(29)} + case "tls-" + instance.Name + "-keystore": + o.Name = "tls-" + instance.Name + "-keystore" + o.Namespace = instance.Namespace + o.Data = map[string][]byte{"key.pem": []byte("")} + case instance.Name + "-crypto-backup": + return k8serrors.NewNotFound(schema.GroupResource{}, "not found") + } + } + return nil + } + + err := peer.SetCertificateTimer(instance, "tls") + Expect(err).NotTo(HaveOccurred()) + Expect(peer.RenewCertTimers["tls-peer1-signcert"]).NotTo(BeNil()) + + // Wait for timer to go off + time.Sleep(5 * time.Second) + + // timer.Stop() == false means that it already fired + Expect(peer.RenewCertTimers["tls-peer1-signcert"].Stop()).To(Equal(false)) + }) + + It("doesn't return error if timer is set correctly, timer doesn't go off certificate isn't ready for renewal", func() { + // Set tls signcert expiration date to be 50 days from now, cert is renewed if expires within 30 days + mockKubeClient.GetStub = func(ctx context.Context, types types.NamespacedName, obj client.Object) error { + switch obj.(type) { + case *current.IBPPeer: + o := obj.(*current.IBPPeer) + o.Kind = "IBPPeer" + instance = o + + case *corev1.Secret: + o := obj.(*corev1.Secret) + switch types.Name { + case "tls-" + instance.Name + "-signcert": + o.Name = "tls-" + instance.Name + "-signcert" + o.Namespace = instance.Namespace + o.Data = map[string][]byte{"cert.pem": generateCertPemBytes(50)} + case "tls-" + instance.Name + "-keystore": + o.Name = "tls-" + instance.Name + "-keystore" + o.Namespace = instance.Namespace + o.Data = map[string][]byte{"key.pem": []byte("")} + case instance.Name + "-crypto-backup": + return k8serrors.NewNotFound(schema.GroupResource{}, "not found") + } + } + return nil + } + + err := peer.SetCertificateTimer(instance, "tls") + Expect(err).NotTo(HaveOccurred()) + + // Timer shouldn't go off + time.Sleep(5 * time.Second) + + Expect(peer.RenewCertTimers["tls-peer1-signcert"]).NotTo(BeNil()) + // timer.Stop() == true means that it has not fired but is now stopped + Expect(peer.RenewCertTimers["tls-peer1-signcert"].Stop()).To(Equal(true)) + }) + }) + }) + + Context("renew cert", func() { + BeforeEach(func() { + instance.Spec.Secret = ¤t.SecretSpec{ + Enrollment: ¤t.EnrollmentSpec{ + TLS: ¤t.Enrollment{}, + }, + } + + certificateMgr.RenewCertReturns(nil) + }) + + It("returns error if secret spec is missing", func() { + instance.Spec.Secret = nil + err := peer.RenewCert("tls", instance, true) + Expect(err).To(HaveOccurred()) + Expect(err.Error()).To(Equal("missing secret spec for instance 'peer1'")) + }) + + It("returns error if certificate generated by MSP", func() { + instance.Spec.Secret = ¤t.SecretSpec{ + MSP: ¤t.MSPSpec{}, + } + err := peer.RenewCert("tls", instance, true) + Expect(err).To(HaveOccurred()) + Expect(err.Error()).To(Equal("cannot auto-renew certificate created by MSP, force renewal required")) + }) + + It("returns error if certificate manager fails to renew certificate", func() { + certificateMgr.RenewCertReturns(errors.New("failed to renew cert")) + err := peer.RenewCert("tls", instance, true) + Expect(err).To(HaveOccurred()) + Expect(err.Error()).To(Equal("failed to renew cert")) + }) + + It("does not return error if certificate manager successfully renews cert", func() { + err := peer.RenewCert("tls", instance, true) + Expect(err).NotTo(HaveOccurred()) + }) + }) + + Context("set cr status", func() { + It("returns error if fails to get current instance", func() { + mockKubeClient.GetReturns(errors.New("get error")) + err := peer.UpdateCRStatus(instance) + Expect(err).To(HaveOccurred()) + Expect(err.Error()).To(Equal("failed to get new instance: get error")) + }) + + It("returns error if fails to update instance status", func() { + mockKubeClient.UpdateStatusReturns(errors.New("update status error")) + certificateMgr.CheckCertificatesForExpireReturns(current.Warning, "cert renewal required", nil) + err := peer.UpdateCRStatus(instance) + Expect(err).To(HaveOccurred()) + Expect(err.Error()).To(Equal("failed to update status to Warning phase: update status error")) + }) + + It("sets instance CR status to Warning", func() { + certificateMgr.CheckCertificatesForExpireReturns(current.Warning, "message", nil) + err := peer.UpdateCRStatus(instance) + Expect(err).NotTo(HaveOccurred()) + Expect(instance.Status.Type).To(Equal(current.Warning)) + Expect(instance.Status.Reason).To(Equal("certRenewalRequired")) + Expect(instance.Status.Message).To(Equal("message")) + }) + }) Context("fabric peer migration", func() { BeforeEach(func() { From 43c83c2ab80574988bcc02270ba10d01eb180a0b Mon Sep 17 00:00:00 2001 From: Josh Kneubuhl Date: Fri, 29 Jul 2022 07:51:20 -0400 Subject: [PATCH 04/41] Bundle a localhost:5000 container registry for local CC development Signed-off-by: Josh Kneubuhl --- sample-network/network | 3 ++- sample-network/scripts/kind.sh | 22 +++++++++++++++++++++- 2 files changed, 23 insertions(+), 2 deletions(-) diff --git a/sample-network/network b/sample-network/network index 933dc5f5..656b0fbb 100755 --- a/sample-network/network +++ b/sample-network/network @@ -51,6 +51,7 @@ context COREDNS_DOMAIN_OVERRIDE true context LOG_FILE network.log context DEBUG_FILE network-debug.log context LOG_ERROR_LINES 1 +context USE_LOCAL_REGISTRY true context LOCAL_REGISTRY_NAME kind-registry context LOCAL_REGISTRY_PORT 5000 context NGINX_HTTP_PORT 80 @@ -162,7 +163,7 @@ if [ "${MODE}" == "kind" ]; then elif [ "${MODE}" == "unkind" ]; then log "Deleting kind cluster \"${CLUSTER_NAME}\":" - kind_delete + kind_unkind log "🏁 - Cluster is gone." elif [[ "${MODE}" == "cluster" || "${MODE}" == "k8s" || "${MODE}" == "kube" ]]; then diff --git a/sample-network/scripts/kind.sh b/sample-network/scripts/kind.sh index 840ee048..d3623ea0 100644 --- a/sample-network/scripts/kind.sh +++ b/sample-network/scripts/kind.sh @@ -107,6 +107,15 @@ EOF pop_fn } +function stop_docker_registry() { + push_fn "Deleting container registry \"${LOCAL_REGISTRY_NAME}\" at localhost:${LOCAL_REGISTRY_PORT}" + + docker kill kind-registry || true + docker rm kind-registry || true + + pop_fn +} + function kind_delete() { push_fn "Deleting KIND cluster ${CLUSTER_NAME}" @@ -119,6 +128,17 @@ function kind_init() { set -o errexit kind_create - #launch_docker_registry + + if [ "${USE_LOCAL_REGISTRY}" == true ]; then + launch_docker_registry + fi } +function kind_unkind() { + + kind_delete + + if [ "${USE_LOCAL_REGISTRY}" == true ]; then + stop_docker_registry + fi +} From 3224bdaf468f5698678b19d719dfee2845d605e5 Mon Sep 17 00:00:00 2001 From: Josh Kneubuhl Date: Mon, 8 Aug 2022 12:28:07 -0400 Subject: [PATCH 05/41] Optionally bind localhost:5000 registry to alternate NIC Signed-off-by: Josh Kneubuhl --- sample-network/network | 1 + sample-network/scripts/kind.sh | 8 ++++++-- 2 files changed, 7 insertions(+), 2 deletions(-) diff --git a/sample-network/network b/sample-network/network index 656b0fbb..43ae1493 100755 --- a/sample-network/network +++ b/sample-network/network @@ -54,6 +54,7 @@ context LOG_ERROR_LINES 1 context USE_LOCAL_REGISTRY true context LOCAL_REGISTRY_NAME kind-registry context LOCAL_REGISTRY_PORT 5000 +context LOCAL_REGISTRY_INTERFACE 127.0.0.1 context NGINX_HTTP_PORT 80 context NGINX_HTTPS_PORT 443 diff --git a/sample-network/scripts/kind.sh b/sample-network/scripts/kind.sh index d3623ea0..cab17dea 100644 --- a/sample-network/scripts/kind.sh +++ b/sample-network/scripts/kind.sh @@ -77,11 +77,15 @@ function launch_docker_registry() { # create registry container unless it already exists local reg_name=${LOCAL_REGISTRY_NAME} local reg_port=${LOCAL_REGISTRY_PORT} + local reg_interface=${LOCAL_REGISTRY_INTERFACE} running="$(docker inspect -f '{{.State.Running}}' "${reg_name}" 2>/dev/null || true)" if [ "${running}" != 'true' ]; then - docker run \ - -d --restart=always -p "127.0.0.1:${reg_port}:5000" --name "${reg_name}" \ + docker run \ + --detach \ + --restart always \ + --name "${reg_name}" \ + --publish "${reg_interface}:${reg_port}:5000" \ registry:2 fi From 4973cb15bb9da2ed9cbce43b26aee653990eaec5 Mon Sep 17 00:00:00 2001 From: Josh Kneubuhl Date: Mon, 8 Aug 2022 13:37:25 -0400 Subject: [PATCH 06/41] fulfill an 'rcaadmin' enrollment after spinning up the CAs. This can be used to register/enroll new gateway client identities at the CA. Signed-off-by: Josh Kneubuhl --- sample-network/config/cas/org0-ca.yaml | 4 +-- sample-network/config/cas/org1-ca.yaml | 4 +-- sample-network/config/cas/org2-ca.yaml | 4 +-- sample-network/scripts/test_network.sh | 40 ++++++++++++++++++++++++++ 4 files changed, 46 insertions(+), 6 deletions(-) diff --git a/sample-network/config/cas/org0-ca.yaml b/sample-network/config/cas/org0-ca.yaml index 393a1f90..61d0f69d 100644 --- a/sample-network/config/cas/org0-ca.yaml +++ b/sample-network/config/cas/org0-ca.yaml @@ -33,8 +33,8 @@ spec: - department1 registry: identities: - - name: admin - pass: adminpw + - name: rcaadmin + pass: rcaadminpw type: client attrs: hf.Registrar.Roles: "*" diff --git a/sample-network/config/cas/org1-ca.yaml b/sample-network/config/cas/org1-ca.yaml index 4cc8d206..0681b22f 100644 --- a/sample-network/config/cas/org1-ca.yaml +++ b/sample-network/config/cas/org1-ca.yaml @@ -33,8 +33,8 @@ spec: - department1 registry: identities: - - name: admin - pass: adminpw + - name: rcaadmin + pass: rcaadminpw type: client attrs: hf.Registrar.Roles: "*" diff --git a/sample-network/config/cas/org2-ca.yaml b/sample-network/config/cas/org2-ca.yaml index eafb299d..f0a6ed4d 100644 --- a/sample-network/config/cas/org2-ca.yaml +++ b/sample-network/config/cas/org2-ca.yaml @@ -33,8 +33,8 @@ spec: - department1 registry: identities: - - name: admin - pass: adminpw + - name: rcaadmin + pass: rcaadminpw type: client attrs: hf.Registrar.Roles: "*" diff --git a/sample-network/scripts/test_network.sh b/sample-network/scripts/test_network.sh index 20f0c10f..89fd2ce2 100644 --- a/sample-network/scripts/test_network.sh +++ b/sample-network/scripts/test_network.sh @@ -98,9 +98,49 @@ function launch_network_CAs() { export ORG1_CA_CERT=$(kubectl -n $NS get cm/org1-ca-connection-profile -o json | jq -r .binaryData.\"profile.json\" | base64 -d | jq -r .tls.cert) export ORG2_CA_CERT=$(kubectl -n $NS get cm/org2-ca-connection-profile -o json | jq -r .binaryData.\"profile.json\" | base64 -d | jq -r .tls.cert) + enroll_bootstrap_rcaadmin org0 rcaadmin rcaadminpw + enroll_bootstrap_rcaadmin org1 rcaadmin rcaadminpw + enroll_bootstrap_rcaadmin org2 rcaadmin rcaadminpw + pop_fn } +function enroll_bootstrap_rcaadmin() { + local org=$1 + local username=$2 + local password=$3 + + echo "Enrolling $org root CA admin $username" + + ENROLLMENTS_DIR=${TEMP_DIR}/enrollments + ORG_ADMIN_DIR=${ENROLLMENTS_DIR}/${org}/users/${username} + + # skip the enrollment if the admin certificate is available. + if [ -f "${ORG_ADMIN_DIR}/msp/keystore/key.pem" ]; then + echo "Found an existing admin enrollment at ${ORG_ADMIN_DIR}" + return + fi + + # Retrieve the CA information from Kubernetes + CA_NAME=${org}-ca + CA_DIR=${TEMP_DIR}/cas/${CA_NAME} + CONNECTION_PROFILE=${CA_DIR}/connection-profile.json + + get_connection_profile $CA_NAME $CONNECTION_PROFILE + + # extract the CA enrollment URL and tls cert from the org connection profile + CA_AUTH=${username}:${password} + CA_ENDPOINT=$(jq -r .endpoints.api $CONNECTION_PROFILE) + CA_HOST=$(echo ${CA_ENDPOINT} | cut -d/ -f3 | tr ':' '\n' | head -1) + CA_PORT=$(echo ${CA_ENDPOINT} | cut -d/ -f3 | tr ':' '\n' | tail -1) + CA_URL=https://${CA_AUTH}@${CA_HOST}:${CA_PORT} + + jq -r .tls.cert $CONNECTION_PROFILE | base64 -d >& $CA_DIR/tls-cert.pem + + # enroll the admin user + FABRIC_CA_CLIENT_HOME=${ORG_ADMIN_DIR} fabric-ca-client enroll --url ${CA_URL} --tls.certfiles ${CA_DIR}/tls-cert.pem +} + function apply_network_peers() { push_fn "Launching Fabric Peers" From 40f9f31499d24afb275a36db146f921e0ae11bc4 Mon Sep 17 00:00:00 2001 From: Josh Kneubuhl Date: Mon, 8 Aug 2022 14:39:45 -0400 Subject: [PATCH 07/41] bump CI integration tests to run with the k8s-builder v0.7.2 Signed-off-by: Josh Kneubuhl --- sample-network/scripts/run-e2e-test.sh | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/sample-network/scripts/run-e2e-test.sh b/sample-network/scripts/run-e2e-test.sh index c99f7766..fd33f782 100755 --- a/sample-network/scripts/run-e2e-test.sh +++ b/sample-network/scripts/run-e2e-test.sh @@ -81,8 +81,8 @@ peer chaincode query -n asset-transfer-basic -C mychannel -c '{"Args":["org.hype network down -export TEST_NETWORK_PEER_IMAGE=ghcr.io/hyperledgendary/k8s-fabric-peer -export TEST_NETWORK_PEER_IMAGE_LABEL=v0.6.0 +export TEST_NETWORK_PEER_IMAGE=ghcr.io/hyperledger-labs/k8s-fabric-peer +export TEST_NETWORK_PEER_IMAGE_LABEL=v0.7.2 network up network channel create From 0408e9a137b93ef8a472d630dfb54b9aaa6a85b0 Mon Sep 17 00:00:00 2001 From: Josh Kneubuhl Date: Wed, 10 Aug 2022 21:17:32 -0400 Subject: [PATCH 08/41] Use hyperledger-labs operator, not ibm-blockchain operator in sample network Signed-off-by: Josh Kneubuhl --- sample-network/network | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sample-network/network b/sample-network/network index 43ae1493..26fbcdb7 100755 --- a/sample-network/network +++ b/sample-network/network @@ -77,7 +77,7 @@ context ORDERER_IMAGE ${FABRIC_CONTAINER_REGISTRY}/fabric-orderer context ORDERER_IMAGE_LABEL ${FABRIC_VERSION} context TOOLS_IMAGE ${FABRIC_CONTAINER_REGISTRY}/fabric-tools context TOOLS_IMAGE_LABEL ${FABRIC_VERSION} -context OPERATOR_IMAGE ghcr.io/ibm-blockchain/fabric-operator +context OPERATOR_IMAGE ghcr.io/hyperledger-labs/fabric-operator context OPERATOR_IMAGE_LABEL latest-amd64 context INIT_IMAGE registry.access.redhat.com/ubi8/ubi-minimal context INIT_IMAGE_LABEL latest From 930ea11fb7740b7accb2c93367a829c9f5d33685 Mon Sep 17 00:00:00 2001 From: Sam Yuan Date: Sun, 31 Jul 2022 21:11:06 +0800 Subject: [PATCH 09/41] resolve #17 Signed-off-by: Sam Yuan --- README.md | 2 +- docs/CONTRIBUTING.md | 14 ++++++++++++++ docs/images/prometheus.png | Bin 0 -> 159241 bytes docs/prometheus.md | 33 +++++++++++++++++++++++++++++++++ 4 files changed, 48 insertions(+), 1 deletion(-) create mode 100644 docs/images/prometheus.png create mode 100644 docs/prometheus.md diff --git a/README.md b/README.md index 31cdd6e5..3f5ab833 100644 --- a/README.md +++ b/README.md @@ -45,7 +45,7 @@ _Fabric, Ahoy!_ - [ ] Declarative Fabric resources : `Channel`, `Chaincode`, `Organization`, `Consortium` / MSP, ... CRDs - [ ] Service Mesh Overlay (Linkerd, Istio, ...) with mTLS -- [ ] Metrics and observability with Prometheus and Grafana +- [x] Metrics and observability with [Prometheus and Grafana](./docs/prometheus.md) - [ ] Operational management: Log aggregation, monitoring, alerting - [ ] Modular CAs (Fabric CA, cert-manager.io, Vault, letsencrypt, ...) - [ ] Automatic x509 certificate renewal diff --git a/docs/CONTRIBUTING.md b/docs/CONTRIBUTING.md index 15f38d84..c5cb39e6 100644 --- a/docs/CONTRIBUTING.md +++ b/docs/CONTRIBUTING.md @@ -1,3 +1,17 @@ # Contributing to this repository +## Tips: +After changed module define at `/api/v1beta1/*.go` run the following command +``` +make generate +make manifests +``` +to make `crd` files up to date. + +## Guide for operator Development +https://sdk.operatorframework.io/docs/building-operators/golang/tutorial/ + +## Fabric env +for any fabric configuration as core.yaml for peer and orderer.yaml for orderer, please considering check existing structure defined in configoverride. + ## TODO diff --git a/docs/images/prometheus.png b/docs/images/prometheus.png new file mode 100644 index 0000000000000000000000000000000000000000..c8436384f3ca6b08093e5abc2b6d466009815b27 GIT binary patch literal 159241 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 Date: Mon, 19 Sep 2022 13:28:41 -0400 Subject: [PATCH 10/41] handle hsm image tag logic for registries with extra column Signed-off-by: asararatnakar --- pkg/offering/base/ca/ca.go | 7 ++++--- pkg/offering/base/orderer/node.go | 7 ++++--- pkg/offering/base/peer/peer.go | 7 ++++--- 3 files changed, 12 insertions(+), 9 deletions(-) diff --git a/pkg/offering/base/ca/ca.go b/pkg/offering/base/ca/ca.go index 593a6277..c79b0d03 100644 --- a/pkg/offering/base/ca/ca.go +++ b/pkg/offering/base/ca/ca.go @@ -931,9 +931,10 @@ func (ca *CA) ReconcileHSMImages(instance *current.IBPCA) bool { updated := false if hsmConfig.Library.Image != "" { - hsm := strings.Split(hsmConfig.Library.Image, ":") - image := hsm[0] - tag := hsm[1] + hsmImage := hsmConfig.Library.Image + lastIndex := strings.LastIndex(hsmImage, ":") + image := hsmImage[:lastIndex] + tag := hsmImage[lastIndex+1:] if instance.Spec.Images.HSMImage != image { instance.Spec.Images.HSMImage = image diff --git a/pkg/offering/base/orderer/node.go b/pkg/offering/base/orderer/node.go index a0a54286..623de0bb 100644 --- a/pkg/offering/base/orderer/node.go +++ b/pkg/offering/base/orderer/node.go @@ -1562,9 +1562,10 @@ func (n *Node) ReconcileHSMImages(instance *current.IBPOrderer) bool { updated := false if hsmConfig.Library.Image != "" { - hsm := strings.Split(hsmConfig.Library.Image, ":") - image := hsm[0] - tag := hsm[1] + hsmImage := hsmConfig.Library.Image + lastIndex := strings.LastIndex(hsmImage, ":") + image := hsmImage[:lastIndex] + tag := hsmImage[lastIndex+1:] if instance.Spec.Images.HSMImage != image { instance.Spec.Images.HSMImage = image diff --git a/pkg/offering/base/peer/peer.go b/pkg/offering/base/peer/peer.go index b4d0d301..538a8774 100644 --- a/pkg/offering/base/peer/peer.go +++ b/pkg/offering/base/peer/peer.go @@ -1369,9 +1369,10 @@ func (p *Peer) ReconcileHSMImages(instance *current.IBPPeer) bool { updated := false if hsmConfig.Library.Image != "" { - hsm := strings.Split(hsmConfig.Library.Image, ":") - image := hsm[0] - tag := hsm[1] + hsmImage := hsmConfig.Library.Image + lastIndex := strings.LastIndex(hsmImage, ":") + image := hsmImage[:lastIndex] + tag := hsmImage[lastIndex+1:] if instance.Spec.Images.HSMImage != image { instance.Spec.Images.HSMImage = image From 71f5c2d91e2800f28066aa3444b3df1b9dc07f04 Mon Sep 17 00:00:00 2001 From: asararatnakar Date: Mon, 19 Sep 2022 14:01:43 -0400 Subject: [PATCH 11/41] Update peer secrets with tlsca cert on a PATCH request Signed-off-by: asararatnakar --- pkg/offering/base/peer/peer.go | 28 ++++++++++++++++++++++++++-- 1 file changed, 26 insertions(+), 2 deletions(-) diff --git a/pkg/offering/base/peer/peer.go b/pkg/offering/base/peer/peer.go index 538a8774..dc55a6ef 100644 --- a/pkg/offering/base/peer/peer.go +++ b/pkg/offering/base/peer/peer.go @@ -19,6 +19,7 @@ package basepeer import ( + "bytes" "context" "encoding/json" "fmt" @@ -827,10 +828,14 @@ func (p *Peer) ReconcileSecret(instance *current.IBPPeer) error { return nil } return err + } else { + log.Info(fmt.Sprintf("Updating secret '%s'", name)) + updateErr := p.UpdateSecret(instance, secret) + if updateErr != nil { + return updateErr + } } - // TODO: If needed, update logic goes here - return nil } @@ -859,6 +864,25 @@ func (p *Peer) CreateSecret(instance *current.IBPPeer) error { return nil } +func (p *Peer) UpdateSecret(instance *current.IBPPeer, secret *corev1.Secret) error { + secretData := instance.Spec.Secret + bytesData, err := json.Marshal(secretData) + if err != nil { + return err + } + + if secret.Data != nil && !bytes.Equal(secret.Data["secret.json"], bytesData) { + secret.Data["secret.json"] = bytesData + + err = p.Client.Update(context.TODO(), secret, controllerclient.UpdateOption{Owner: instance, Scheme: p.Scheme}) + if err != nil { + return err + } + } + + return nil +} + func (p *Peer) UpdateExternalEndpoint(instance *current.IBPPeer) bool { if instance.Spec.PeerExternalEndpoint == "" { instance.Spec.PeerExternalEndpoint = instance.Namespace + "-" + instance.Name + "-peer." + instance.Spec.Domain + ":443" From 1f2240ec14496e323e877e7164cd0efc15eb45cf Mon Sep 17 00:00:00 2001 From: asararatnakar Date: Mon, 19 Sep 2022 14:26:11 -0400 Subject: [PATCH 12/41] Upgrading couchdb to 3.2.2 Signed-off-by: asararatnakar --- defaultconfig/console/console.go | 2 +- definitions/console/deployer-configmap.yaml | 2 +- integration/images.go | 2 +- operatorconfig/versions.go | 2 +- sample-network/network | 2 +- testdata/deployercm/deployer-configmap.yaml | 2 +- 6 files changed, 6 insertions(+), 6 deletions(-) diff --git a/defaultconfig/console/console.go b/defaultconfig/console/console.go index 35603952..1fb9d7f1 100644 --- a/defaultconfig/console/console.go +++ b/defaultconfig/console/console.go @@ -31,6 +31,6 @@ func GetImages() *deployer.ConsoleImages { DeployerImage: "ghcr.io/ibm-blockchain/fabric-deployer", DeployerTag: "latest", CouchDBImage: "couchdb", - CouchDBTag: "3.1.2", + CouchDBTag: "3.2.2", } } diff --git a/definitions/console/deployer-configmap.yaml b/definitions/console/deployer-configmap.yaml index cc61238b..79fcc118 100644 --- a/definitions/console/deployer-configmap.yaml +++ b/definitions/console/deployer-configmap.yaml @@ -65,7 +65,7 @@ data: peerImage: hyperledger/fabric-peer peerTag: 2.4.3 couchdbImage: couchdb - couchdbTag: 3.1.2 + couchdbTag: 3.2.2 grpcwebImage: ghcr.io/hyperledger-labs/grpc-web grpcwebTag: latest orderer: diff --git a/integration/images.go b/integration/images.go index e0ff6a83..df87eea7 100644 --- a/integration/images.go +++ b/integration/images.go @@ -35,7 +35,7 @@ const ( ConfigtxlatorImage = "hyperledger/fabric-tools" ConfigtxlatorTag = FabricVersion24 CouchdbImage = "couchdb" - CouchdbTag = "3.2.1" + CouchdbTag = "3.2.2" GrpcwebImage = "ghcr.io/hyperledger-labs/grpc-web" GrpcwebTag = "latest" ConsoleImage = "ghcr.io/hyperledger-labs/fabric-console" diff --git a/operatorconfig/versions.go b/operatorconfig/versions.go index 3069176f..546cc4f7 100644 --- a/operatorconfig/versions.go +++ b/operatorconfig/versions.go @@ -51,7 +51,7 @@ func getDefaultVersions() *deployer.Versions { PeerImage: "hyperledger/fabric-peer", PeerTag: FabricVersion, CouchDBImage: "couchdb", - CouchDBTag: "3.1.2", + CouchDBTag: "3.2.2", GRPCWebImage: "ghcr.io/hyperledger-labs/grpc-web", GRPCWebTag: LatestTag, }, diff --git a/sample-network/network b/sample-network/network index 26fbcdb7..51d962e6 100755 --- a/sample-network/network +++ b/sample-network/network @@ -84,7 +84,7 @@ context INIT_IMAGE_LABEL latest context GRPCWEB_IMAGE ghcr.io/hyperledger-labs/grpc-web context GRPCWEB_IMAGE_LABEL latest context COUCHDB_IMAGE couchdb -context COUCHDB_IMAGE_LABEL 3.2.1 +context COUCHDB_IMAGE_LABEL 3.2.2 context CONSOLE_IMAGE ghcr.io/hyperledger-labs/fabric-console context CONSOLE_IMAGE_LABEL latest context DEPLOYER_IMAGE ghcr.io/ibm-blockchain/fabric-deployer diff --git a/testdata/deployercm/deployer-configmap.yaml b/testdata/deployercm/deployer-configmap.yaml index 8b30a3af..ccdd1026 100644 --- a/testdata/deployercm/deployer-configmap.yaml +++ b/testdata/deployercm/deployer-configmap.yaml @@ -66,7 +66,7 @@ data: peerImage: fabric-peer peerTag: latest couchdbImage: fabric-couchdb - couchdbTag: 3.1.2 + couchdbTag: 3.2.2 grpcwebImage: fabric-grpcweb grpcwebTag: latest From 03d6f432313596d877c61979ac661d6d26b9afd7 Mon Sep 17 00:00:00 2001 From: asararatnakar Date: Mon, 19 Sep 2022 13:21:28 -0400 Subject: [PATCH 13/41] Allow Peer property CORE_PEER_GOSSIP_EXTERNALENDPOINT to be modified Signed-off-by: asararatnakar --- go.mod | 5 +-- go.sum | 33 ------------------- pkg/offering/base/peer/override/deployment.go | 3 +- pkg/offering/base/peer/peer.go | 5 +++ 4 files changed, 8 insertions(+), 38 deletions(-) diff --git a/go.mod b/go.mod index f3ff8891..32988538 100644 --- a/go.mod +++ b/go.mod @@ -1,6 +1,6 @@ module github.com/IBM-Blockchain/fabric-operator -go 1.17 +go 1.18 require ( github.com/cloudflare/cfssl v1.4.1 @@ -93,8 +93,6 @@ require ( github.com/mitchellh/mapstructure v1.3.3 // indirect github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect github.com/modern-go/reflect2 v1.0.1 // indirect - github.com/nxadm/tail v1.4.8 // indirect - github.com/onsi/ginkgo v1.16.4 // indirect github.com/op/go-logging v0.0.0-20160315200505-970db520ece7 // indirect github.com/pelletier/go-toml v1.2.0 // indirect github.com/pierrec/lz4 v2.6.1+incompatible // indirect @@ -135,7 +133,6 @@ require ( gopkg.in/inf.v0 v0.9.1 // indirect gopkg.in/ini.v1 v1.51.0 // indirect gopkg.in/ldap.v2 v2.5.1 // indirect - gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7 // indirect gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b // indirect k8s.io/component-base v0.21.5 // indirect k8s.io/gengo v0.0.0-20201214224949-b6c5ce23f027 // indirect diff --git a/go.sum b/go.sum index 4d80c22c..fc1c51aa 100644 --- a/go.sum +++ b/go.sum @@ -58,7 +58,6 @@ github.com/Shopify/sarama v1.30.0/go.mod h1:zujlQQx1kzHsh4jfV1USnptCQrHAEZ2Hk8fT github.com/Shopify/toxiproxy/v2 v2.1.6-0.20210914104332-15ea381dcdae h1:ePgznFqEG1v3AjMklnK8H7BSc++FDSo7xfK9K7Af+0Y= github.com/Shopify/toxiproxy/v2 v2.1.6-0.20210914104332-15ea381dcdae/go.mod h1:/cvHQkZ1fst0EmZnA5dFtiQdWCNCFYzb+uE2vqVgvx0= github.com/VividCortex/gohistogram v1.0.0 h1:6+hBz+qvs0JOrrNhhmR7lFxo5sINxBCGXrdtl/UvroE= -github.com/VividCortex/gohistogram v1.0.0/go.mod h1:Pf5mBqqDxYaXu3hDrrU+w6nw50o/4+TcAqDqk/vUH7g= github.com/akavel/rsrc v0.8.0/go.mod h1:uLoCtb9J+EyAqh+26kdrTgmzRBFPGOolLWKpdxkKq+c= github.com/alecthomas/template v0.0.0-20190718012654-fb15b899a751/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc= github.com/alecthomas/units v0.0.0-20190717042225-c3de453c63f4/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0= @@ -89,7 +88,6 @@ github.com/cockroachdb/datadriven v0.0.0-20190809214429-80d97fb3cbaa/go.mod h1:z github.com/coreos/bbolt v1.3.2/go.mod h1:iRUV2dpdMOn7Bo10OQBFzIJO9kkE559Wcmn+qkEiiKk= github.com/coreos/etcd v3.3.10+incompatible/go.mod h1:uF7uidLiAD3TWHmW31ZFd/JWoc32PjwdhPthX9715RE= github.com/coreos/etcd v3.3.13+incompatible/go.mod h1:uF7uidLiAD3TWHmW31ZFd/JWoc32PjwdhPthX9715RE= -github.com/coreos/go-etcd v2.0.0+incompatible/go.mod h1:Jez6KQU2B/sWsbdaef3ED8NzMklzPG4d5KIOhIy30Tk= github.com/coreos/go-oidc v2.1.0+incompatible/go.mod h1:CgnwVTmzoESiwO9qyAFEMiHoZ1nMCKZlZ9V6mm3/LKc= github.com/coreos/go-semver v0.2.0/go.mod h1:nnelYz7RCh+5ahJtPPxZlU+153eP4D4r3EedlOD2RNk= github.com/coreos/go-semver v0.3.0/go.mod h1:nnelYz7RCh+5ahJtPPxZlU+153eP4D4r3EedlOD2RNk= @@ -97,7 +95,6 @@ github.com/coreos/go-systemd v0.0.0-20180511133405-39ca1b05acc7/go.mod h1:F5haX7 github.com/coreos/go-systemd v0.0.0-20190321100706-95778dfbb74e/go.mod h1:F5haX7vjVVG0kc13fIWeqUViNPyEJxv/OmvnBo0Yme4= github.com/coreos/pkg v0.0.0-20160727233714-3ac0863d7acf/go.mod h1:E3G3o1h8I7cfcXa63jLwjI0eiQQMgzzUDFVpN/nH/eA= github.com/coreos/pkg v0.0.0-20180928190104-399ea9e2e55f/go.mod h1:E3G3o1h8I7cfcXa63jLwjI0eiQQMgzzUDFVpN/nH/eA= -github.com/cpuguy83/go-md2man v1.0.10/go.mod h1:SmD6nW6nTyfqj6ABTjUi3V3JVMnlJmwcJI5acqYI6dE= github.com/cpuguy83/go-md2man/v2 v2.0.0-20190314233015-f79a8a8ca69d/go.mod h1:maD7wRr/U5Z6m/iR4s+kqSMx2CaBsrgA7czyZG/E6dU= github.com/cpuguy83/go-md2man/v2 v2.0.0/go.mod h1:maD7wRr/U5Z6m/iR4s+kqSMx2CaBsrgA7czyZG/E6dU= github.com/creack/pty v1.1.7/go.mod h1:lj5s0c3V2DBrqTV7llrYr5NG6My20zk30Fl46Y7DoTY= @@ -180,10 +177,8 @@ github.com/go-openapi/swag v0.19.5/go.mod h1:POnQmlKehdgb5mhVOsnJFsivZCEZ/vjK9gh github.com/go-playground/locales v0.13.0/go.mod h1:taPMhCMXrRLJO55olJkUXHZBHCxTMfnGwq/HNwmWNS8= github.com/go-playground/universal-translator v0.17.0/go.mod h1:UkSxE5sNxxRwHyU+Scu5vgOQjsIJAF8j9muTVoKLVtA= github.com/go-sql-driver/mysql v1.3.0/go.mod h1:zAC/RDZ24gD3HViQzih4MyKcchzm+sOG5ZlKdlhCg5w= -github.com/go-sql-driver/mysql v1.4.0/go.mod h1:zAC/RDZ24gD3HViQzih4MyKcchzm+sOG5ZlKdlhCg5w= github.com/go-sql-driver/mysql v1.5.0 h1:ozyZYNQW3x3HtqT1jira07DN2PArx2v7/mN66gGcHOs= github.com/go-sql-driver/mysql v1.5.0/go.mod h1:DCzpHaOWr8IXmIStZouvnhqoel9Qv2LBy8hT2VhHyBg= -github.com/go-stack/stack v1.8.0/go.mod h1:v0f6uXyyMGvRgIKkXu+yp6POWl0qKG85gN/melR3HDY= github.com/go-stack/stack v1.8.1 h1:ntEHSVwIt7PNXNpgPmVfMrNhLtgjlmnZha2kOpuRiDw= github.com/go-stack/stack v1.8.1/go.mod h1:dcoOX6HbPZSZptuspn9bctJ+N/CnF5gGygcUP3XYfe4= github.com/go-task/slim-sprig v0.0.0-20210107165309-348f09dbbbc0/go.mod h1:fyg7847qk6SyHyPtNmDHnmrv/HOrqktSC+C9fM+CJOE= @@ -252,7 +247,6 @@ github.com/google/pprof v0.0.0-20200212024743-f11f1df84d12/go.mod h1:ZgVRPoUq/hf github.com/google/pprof v0.0.0-20200229191704-1ebb73c60ed3/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM= github.com/google/pprof v0.0.0-20200430221834-fc25d7d30c6d/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM= github.com/google/pprof v0.0.0-20200507031123-427632fa3b1c/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM= -github.com/google/pprof v0.0.0-20210407192527-94a9f03dee38/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE= github.com/google/renameio v0.1.0/go.mod h1:KWCgfxg9yswjAJkECMjeO8J8rahYeXnNhOm40UhjYkI= github.com/google/uuid v1.0.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= github.com/google/uuid v1.1.1/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= @@ -321,7 +315,6 @@ github.com/hyperledger/fabric-lib-go v1.0.0/go.mod h1:H362nMlunurmHwkYqR5uHL2UDW github.com/hyperledger/fabric-protos-go v0.0.0-20200113171556-368e201877dd h1:dv8PcTulQ2/DEio+3NzUVy17A1YYt+0VaXnQ4FnjAKE= github.com/hyperledger/fabric-protos-go v0.0.0-20200113171556-368e201877dd/go.mod h1:xVYTjK4DtZRBxZ2D9aE4y6AbLaPwue2o/criQyQbVD0= github.com/ianlancetaylor/demangle v0.0.0-20181102032728-5e5cf60278f6/go.mod h1:aSSvb/t6k1mPoxDqO4vJh6VOCGPwU4O0C2/Eqndh1Sc= -github.com/ianlancetaylor/demangle v0.0.0-20200824232613-28f6c0f3b639/go.mod h1:aSSvb/t6k1mPoxDqO4vJh6VOCGPwU4O0C2/Eqndh1Sc= github.com/imdario/mergo v0.3.5/go.mod h1:2EnlNZ0deacrJVfApfmtdGgDfMuh/nq6Ok1EcJh5FfA= github.com/imdario/mergo v0.3.12 h1:b6R2BslTbIEToALKP7LxUvijTsNI9TAe80pLWN2g/HU= github.com/imdario/mergo v0.3.12/go.mod h1:jmQim1M+e3UYxmgPu/WyfjB3N3VflVyUjjjwH0dnCYA= @@ -342,7 +335,6 @@ github.com/jessevdk/go-flags v1.4.0/go.mod h1:4FA24M0QyGHXBuZZK/XkWh8h0e1EYbRYJS github.com/jmhodges/clock v0.0.0-20160418191101-880ee4c33548 h1:dYTbLf4m0a5u0KLmPfB6mgxbcV7588bOCx79hxa5Sr4= github.com/jmhodges/clock v0.0.0-20160418191101-880ee4c33548/go.mod h1:hGT6jSUVzF6no3QaDSMLGLEHtHSBSefs+MgcDWnmhmo= github.com/jmoiron/sqlx v0.0.0-20180124204410-05cef0741ade/go.mod h1:IiEW3SEiiErVyFdH8NTuWjSifiEQKUoyK3LNqr2kCHU= -github.com/jmoiron/sqlx v1.2.0/go.mod h1:1FEQNm3xlJgrMD+FBdI9+xvCksHtbpVBBw5dYhBSsks= github.com/jmoiron/sqlx v1.3.4 h1:wv+0IJZfL5z0uZoUjlpKgHkgaFSYD+r9CfrXjEXsO7w= github.com/jmoiron/sqlx v1.3.4/go.mod h1:2BljVx/86SuTyjE+aPYlHCTNvZrnJXghYGpNiXLBMCQ= github.com/joefitzgerald/rainbow-reporter v0.1.0 h1:AuMG652zjdzI0YCCnXAqATtRBpGXMcAnrajcaTrSeuo= @@ -382,7 +374,6 @@ github.com/kylelemons/go-gypsy v0.0.0-20160905020020-08cad365cd28/go.mod h1:T/T7 github.com/kylelemons/godebug v1.1.0/go.mod h1:9/0rRGxNHcop5bhtWyNeEfOS8JIWk580+fNqagV/RAw= github.com/leodido/go-urn v1.2.0/go.mod h1:+8+nEpDfqqsY+g338gtMEUOtuK+4dEMhiQEgxpxOKII= github.com/lib/pq v0.0.0-20180201184707-88edab080323/go.mod h1:5WUZQaWbwv1U+lTReE5YruASi9Al49XbQIvNi/34Woo= -github.com/lib/pq v1.0.0/go.mod h1:5WUZQaWbwv1U+lTReE5YruASi9Al49XbQIvNi/34Woo= github.com/lib/pq v1.2.0/go.mod h1:5WUZQaWbwv1U+lTReE5YruASi9Al49XbQIvNi/34Woo= github.com/lib/pq v1.8.0 h1:9xohqzkUwzR4Ga4ivdTcawVS89YSDVxXMa3xJX3cGzg= github.com/lib/pq v1.8.0/go.mod h1:AlVN5x4E4T544tWzH6hKfbfQvm3HdbOxrmggDNAPY9o= @@ -404,9 +395,7 @@ github.com/mattn/go-isatty v0.0.10/go.mod h1:qgIWMr58cqv1PHHyhnkY9lrL7etaEgOFcME github.com/mattn/go-isatty v0.0.11/go.mod h1:PhnuNfih5lzO57/f3n+odYbM4JtupLOxQOAqxQCu2WE= github.com/mattn/go-isatty v0.0.12/go.mod h1:cbi8OIDigv2wuxKPP5vlRcQ1OAZbq2CE4Kysco4FUpU= github.com/mattn/go-runewidth v0.0.2/go.mod h1:LwmH8dsx7+W8Uxz3IHJYH5QSwggIsqBzpuz5H//U1FU= -github.com/mattn/go-sqlite3 v1.9.0/go.mod h1:FPy6KqzDD04eiIsT53CuJW3U88zkxoIYsOqkbpncsNc= github.com/mattn/go-sqlite3 v1.10.0/go.mod h1:FPy6KqzDD04eiIsT53CuJW3U88zkxoIYsOqkbpncsNc= -github.com/mattn/go-sqlite3 v1.14.5/go.mod h1:WVKg1VTActs4Qso6iwGbiFih2UIHo0ENGwNd0Lj+XmI= github.com/mattn/go-sqlite3 v1.14.6/go.mod h1:NyWgC/yNuGj7Q9rpYnZvas74GogHl5/Z4A/KQRfk6bU= github.com/mattn/go-sqlite3 v1.14.9 h1:10HX2Td0ocZpYEjhilsuo6WWtUqttj2Kb0KtD86/KYA= github.com/mattn/go-sqlite3 v1.14.9/go.mod h1:NyWgC/yNuGj7Q9rpYnZvas74GogHl5/Z4A/KQRfk6bU= @@ -453,11 +442,9 @@ github.com/onsi/ginkgo v1.6.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+W github.com/onsi/ginkgo v1.8.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE= github.com/onsi/ginkgo v1.11.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE= github.com/onsi/ginkgo v1.12.1/go.mod h1:zj2OWP4+oCPe1qIXoGWkgMRwljMUYCdkwsT2108oapk= -github.com/onsi/ginkgo v1.14.2/go.mod h1:iSB4RoI2tjJc9BBv4NKIKWKya62Rps+oPG/Lv9klQyY= github.com/onsi/ginkgo v1.16.2/go.mod h1:CObGmKUOKaSC0RjmoAK7tKyn4Azo5P2IWuoMnvwxz1E= github.com/onsi/ginkgo v1.16.4 h1:29JGrr5oVBm5ulCWet69zQkzWipVXIol6ygQUe/EzNc= github.com/onsi/ginkgo v1.16.4/go.mod h1:dX+/inL/fNMqNlz0e9LfyB9TswhZpCVdJM/Z6Vvnwo0= -github.com/onsi/ginkgo/v2 v2.1.3/go.mod h1:vw5CSIxN1JObi/U8gcbwft7ZxR2dgaR70JSE3/PpL4c= github.com/onsi/ginkgo/v2 v2.1.4 h1:GNapqRSid3zijZ9H77KrgVG4/8KqiyRsxcSxe+7ApXY= github.com/onsi/ginkgo/v2 v2.1.4/go.mod h1:um6tUpWM/cxCK3/FK8BXqEiUMUwRgSM4JXG47RKZmLU= github.com/onsi/gomega v0.0.0-20170829124025-dcabb60a477c/go.mod h1:C1qb7wdrVGGVU+Z6iS04AVkA3Q65CEZX59MT0QO5uiA= @@ -465,9 +452,7 @@ github.com/onsi/gomega v1.7.0/go.mod h1:ex+gbHU/CVuBBDIJjb2X0qEXbFg53c61hWP/1Cpa github.com/onsi/gomega v1.7.1/go.mod h1:XdKZgCCFLUoM/7CFJVPcG8C1xQ1AJ0vpAezJrB7JYyY= github.com/onsi/gomega v1.9.0/go.mod h1:Ho0h+IUsWyvy1OpqCwxlQ/21gkhVunqlU8fDGcoTdcA= github.com/onsi/gomega v1.10.1/go.mod h1:iN09h71vgCQne3DLsj+A5owkum+a2tYe+TOCB1ybHNo= -github.com/onsi/gomega v1.10.3/go.mod h1:V9xEwhxec5O8UDM77eCW8vLymOMltsqPVYWrpDsH8xc= github.com/onsi/gomega v1.13.0/go.mod h1:lRk9szgn8TxENtWd0Tp4c3wjlRfMTMH27I+3Je41yGY= -github.com/onsi/gomega v1.17.0/go.mod h1:HnhC7FXeEQY45zxNK3PPoIUhzk/80Xly9PcubAlGdZY= github.com/onsi/gomega v1.19.0 h1:4ieX6qQjPP/BfC3mpsAtIGGlxTWPeA3Inl/7DtXw1tw= github.com/onsi/gomega v1.19.0/go.mod h1:LY+I3pBVzYsTBU1AnDwOSxaYi9WoWiqgwooUqq9yPro= github.com/op/go-logging v0.0.0-20160315200505-970db520ece7 h1:lDH9UUVJtmYCjyT0CI4q8xvlXPxeZ0gYCVvWbmPlp88= @@ -487,7 +472,6 @@ github.com/pkg/errors v0.8.0/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINE github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4= github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= -github.com/pkg/profile v1.5.0/go.mod h1:qBsxPvzyUincmltOk6iyRVxHYg4adc0OFOv72ZdLa18= github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= github.com/posener/complete v1.1.1/go.mod h1:em0nMJCgc9GFtwrmVmEMR/ZL6WyhyjMBndrE9hABlRI= @@ -497,7 +481,6 @@ github.com/prometheus/client_golang v0.9.0/go.mod h1:7SWBe2y4D6OKWSNQJUaRYU/AaXP github.com/prometheus/client_model v0.0.0-20190812154241-14fe0d1b01d4/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA= github.com/prometheus/client_model v0.2.0 h1:uq5h0d+GuxiXLJLNABMgp2qUWDPiLvgCzz2dUR+/W/M= github.com/prometheus/client_model v0.2.0/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA= -github.com/prometheus/common v0.0.0-20181126121408-4724e9255275/go.mod h1:daVV7qP5qjZbuso7PdcryaAu0sAZbrN9i7WWcTMWvro= github.com/prometheus/common v0.10.0 h1:RyRA7RzGXQZiW+tGMr7sxa85G1z0yOpM1qq5c8lNawc= github.com/prometheus/common v0.10.0/go.mod h1:Tlit/dnDKsSWFlCLTWaA1cyBgKHSMdTB80sz/V91rCo= github.com/prometheus/procfs v0.2.0 h1:wH4vA7pcjKuZzjF7lM8awk4fnuJO6idemZXoKnULUx4= @@ -506,7 +489,6 @@ github.com/rcrowley/go-metrics v0.0.0-20201227073835-cf1acfcdf475 h1:N/ElC8H3+5X github.com/rcrowley/go-metrics v0.0.0-20201227073835-cf1acfcdf475/go.mod h1:bCqnVzQkZxMG4s8nGwiZ5l3QUCyqpo9Y+/ZMZ9VjZe4= github.com/rogpeppe/fastuuid v0.0.0-20150106093220-6724a57986af/go.mod h1:XWv6SoW27p1b0cqNHllgS5HIMJraePCO15w5zCzIWYg= github.com/rogpeppe/go-internal v1.3.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4= -github.com/russross/blackfriday v1.5.2/go.mod h1:JO/DiYxRf+HjHt06OyowR9PTA263kcR/rfWxYHBV53g= github.com/russross/blackfriday/v2 v2.0.1/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM= github.com/ryanuber/columnize v0.0.0-20160712163229-9b3edd62028f/go.mod h1:sm1tb6uqfes/u+d4ooFouqFdy9/2g9QGwK3SQygK0Ts= github.com/sclevine/spec v1.2.0/go.mod h1:W4J29eT/Kzv7/b9IWLB055Z+qvVC9vt0Arko24q7p+U= @@ -530,7 +512,6 @@ github.com/spf13/cast v1.3.0/go.mod h1:Qx5cxh0v+4UWYiBimWS+eyWzqEqokIECu5etghLkU github.com/spf13/cast v1.3.1 h1:nFm6S0SMdyzrzcmThSipiEubIDy8WEXKNZ0UOgiRpng= github.com/spf13/cast v1.3.1/go.mod h1:Qx5cxh0v+4UWYiBimWS+eyWzqEqokIECu5etghLkUJE= github.com/spf13/cobra v0.0.3/go.mod h1:1l0Ry5zgKvJasoi3XT1TypsSe7PqH0Sj9dhYf7v3XqQ= -github.com/spf13/cobra v0.0.5/go.mod h1:3K3wKZymM7VvHMDS9+Akkh4K60UwM26emMESw8tLCHU= github.com/spf13/cobra v1.0.0/go.mod h1:/6GTrnGXV9HjY+aR4k0oJ5tcvakLuG6EuKReYlHNrgE= github.com/spf13/cobra v1.1.1/go.mod h1:WnodtKOvamDL/PwE2M4iKs8aMDBZ5Q5klgD3qfVJQMI= github.com/spf13/cobra v1.1.3/go.mod h1:pGADOWyqRD/YMrPZigI/zbliZ2wVD/23d+is3pSWzOo= @@ -541,7 +522,6 @@ github.com/spf13/pflag v1.0.1/go.mod h1:DYY7MBk1bdzusC3SYhjObp+wFpr4gzcvqqNjLnIn github.com/spf13/pflag v1.0.3/go.mod h1:DYY7MBk1bdzusC3SYhjObp+wFpr4gzcvqqNjLnInEg4= github.com/spf13/pflag v1.0.5 h1:iy+VFUOCP1a+8yFto/drg2CJ5u0yRoB7fZw3DKv/JXA= github.com/spf13/pflag v1.0.5/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg= -github.com/spf13/viper v1.3.2/go.mod h1:ZiWeW+zYFKm7srdB9IoDzzZXaJaI5eL9QjNiN/DMA2s= github.com/spf13/viper v1.4.0/go.mod h1:PTJ7Z/lr49W6bUbkmS1V3by4uWynFiR9p7+dSq/yZzE= github.com/spf13/viper v1.7.0 h1:xVKxvI7ouOI5I+U9s2eeiUfMaWBVoXA3AWskkrqK0VM= github.com/spf13/viper v1.7.0/go.mod h1:8WkrPz2fc9jxqZNCJI/76HCieCp4Q8HaLFoCha5qpdg= @@ -564,7 +544,6 @@ github.com/sykesm/zap-logfmt v0.0.4/go.mod h1:AuBd9xQjAe3URrWT1BBDk2v2onAZHkZkWR github.com/tmc/grpc-websocket-proxy v0.0.0-20170815181823-89b8d40f7ca8/go.mod h1:ncp9v5uamzpCO7NfCPTXjqaC+bZgJeR0sMTm6dMHP7U= github.com/tmc/grpc-websocket-proxy v0.0.0-20190109142713-0ad062ec5ee5/go.mod h1:ncp9v5uamzpCO7NfCPTXjqaC+bZgJeR0sMTm6dMHP7U= github.com/ugorji/go v1.1.4/go.mod h1:uQMGLiO92mf5W77hV/PUCpI3pbzQx3CRekS0kk+RGrc= -github.com/ugorji/go/codec v0.0.0-20181204163529-d75b2dcb6bc8/go.mod h1:VFNgLljTbGfSG7qAOspJ7OScBnGdDN/yBr0sguwnwf0= github.com/urfave/cli v1.20.0/go.mod h1:70zkFmudgCuE/ngEzBv17Jvp/497gISqfk5gWijbERA= github.com/urfave/cli/v2 v2.3.0/go.mod h1:LJmUH05zAU44vOAcrfzZQKsZbVcdbOG8rtL3/XcUArI= github.com/valyala/bytebufferpool v1.0.0/go.mod h1:6bBcMArwyJ5K/AmCkWv1jt77kVWyCJ6HpOuEn7z0Csc= @@ -583,7 +562,6 @@ github.com/yuin/goldmark v1.1.25/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9de github.com/yuin/goldmark v1.1.27/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= github.com/yuin/goldmark v1.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= github.com/yuin/goldmark v1.3.5/go.mod h1:mwnBkeHKe2W/ZEtQ+71ViKU8L12m81fl3OWwC1Zlc8k= -github.com/yuin/goldmark v1.4.1/go.mod h1:mwnBkeHKe2W/ZEtQ+71ViKU8L12m81fl3OWwC1Zlc8k= github.com/ziutek/mymysql v1.5.4/go.mod h1:LMSpPZ6DbqWFxNCHW77HeMg9I646SAhApZ/wKdgO/C0= github.com/zmap/rc2 v0.0.0-20131011165748-24b9757f5521/go.mod h1:3YZ9o3WnatTIZhuOtot4IcUfzoKVjUHqu6WALIyI0nE= github.com/zmap/zcertificate v0.0.0-20180516150559-0e3d58b1bac4/go.mod h1:5iU54tB79AMBcySS0R2XIyZBAVmeHranShAFELYx7is= @@ -613,12 +591,10 @@ go.uber.org/multierr v1.6.0/go.mod h1:cdWPpRnG4AhwMwsgIHip0KRBQjJy5kYEpYjJxpXp9i go.uber.org/tools v0.0.0-20190618225709-2cfd321de3ee/go.mod h1:vJERXedbb3MVM5f9Ejo0C68/HhF8uaILCdgjnY+goOA= go.uber.org/zap v1.10.0/go.mod h1:vwi/ZaCAaUcBkycHslxD9B2zi4UTXhF60s6SWpuDF0Q= go.uber.org/zap v1.12.0/go.mod h1:zwrFLgMcdUuIBviXEYEH1YKNaOBnKXsx2IPda5bBwHM= -go.uber.org/zap v1.13.0/go.mod h1:zwrFLgMcdUuIBviXEYEH1YKNaOBnKXsx2IPda5bBwHM= go.uber.org/zap v1.17.0 h1:MTjgFu6ZLKvY6Pvaqk97GlxNBuMpV4Hy/3P6tRGlI2U= go.uber.org/zap v1.17.0/go.mod h1:MXVU+bhUf/A7Xi2HNOnopQOrmycQ5Ih87HtOu4q5SSo= golang.org/x/crypto v0.0.0-20180904163835-0709b304e793/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= golang.org/x/crypto v0.0.0-20181029021203-45a5f77698d3/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= -golang.org/x/crypto v0.0.0-20181203042331-505ab145d0a9/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= golang.org/x/crypto v0.0.0-20190510104115-cbcb75029529/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= golang.org/x/crypto v0.0.0-20190605123033-f99c8df09eb5/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= @@ -628,7 +604,6 @@ golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8U golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= golang.org/x/crypto v0.0.0-20201002170205-7f63de1d35b0/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= golang.org/x/crypto v0.0.0-20201112155050-0c6587e931a9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= -golang.org/x/crypto v0.0.0-20201117144127-c1f2f97bffc9/go.mod h1:jdWPYTVW3xRLrWPugEBEK3UY2ZEsg3UU495nc5E+M+I= golang.org/x/crypto v0.0.0-20210220033148-5ea612d1eb83/go.mod h1:jdWPYTVW3xRLrWPugEBEK3UY2ZEsg3UU495nc5E+M+I= golang.org/x/crypto v0.0.0-20210920023735-84f357641f63/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc= golang.org/x/crypto v0.0.0-20210921155107-089bfa567519 h1:7I4JAnoQBe7ZtJcBaYHi5UtiO8tQHbUSXxL+pnGRANg= @@ -700,14 +675,12 @@ golang.org/x/net v0.0.0-20200506145744-7e3656a0809f/go.mod h1:qpuaurCH72eLCgpAm/ golang.org/x/net v0.0.0-20200513185701-a91f0712d120/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A= golang.org/x/net v0.0.0-20200520004742-59133d7f0dd7/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A= golang.org/x/net v0.0.0-20200520182314-0ba52f642ac2/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A= -golang.org/x/net v0.0.0-20201006153459-a7d1128ccaa0/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU= golang.org/x/net v0.0.0-20201021035429-f5854403a974/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU= golang.org/x/net v0.0.0-20210224082022-3d97a244fca7/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg= golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg= golang.org/x/net v0.0.0-20210405180319-a5a99cb37ef4/go.mod h1:p54w0d4576C0XHj96bSt6lcn1PtDYWL6XObtHCRCNQM= golang.org/x/net v0.0.0-20210428140749-89ef3d95e781/go.mod h1:OJAsFXCWl8Ukc7SiCT/9KSuxbyM7479/AVlXFRxuMCk= golang.org/x/net v0.0.0-20210917221730-978cfadd31cf/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= -golang.org/x/net v0.0.0-20211015210444-4f30a5c0130f/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= golang.org/x/net v0.0.0-20220225172249-27dd8689420f h1:oA4XRj0qtSt8Yo1Zms0CUlsT3KG69V2UGQWPBxujDmc= golang.org/x/net v0.0.0-20220225172249-27dd8689420f/go.mod h1:CfG3xpIq0wQ8r1q4Su4UZFWDARRcnwPjda9FqA0JpMk= golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= @@ -731,7 +704,6 @@ golang.org/x/sys v0.0.0-20180905080454-ebe1bf3edb33/go.mod h1:STP8DvDyc/dI5b8T5h golang.org/x/sys v0.0.0-20180909124046-d0be0721c37e/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20181026203630-95b1ffbd15a5/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20181107165924-66b7b1311ac8/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= -golang.org/x/sys v0.0.0-20181205085412-a5c9d58dba9a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20190222072716-a9d3bda3a223/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20190312061237-fead79001313/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= @@ -767,11 +739,9 @@ golang.org/x/sys v0.0.0-20200331124033-c3d80250170d/go.mod h1:h1NjWce9XRLGQEsW7w golang.org/x/sys v0.0.0-20200501052902-10377860bb8e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200511232937-7e40ca221e25/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200515095857-1151b9dac4a9/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20200519105757-fe76b779f299/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200523222454-059865788121/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200831180312-196b9ba8737a/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200930185726-fdedc70b468f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20201015000850-e3ed0017c211/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210112080510-489259a85091/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210119212857-b64e53b001e4/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= @@ -781,8 +751,6 @@ golang.org/x/sys v0.0.0-20210423082822-04245dca01da/go.mod h1:h1NjWce9XRLGQEsW7w golang.org/x/sys v0.0.0-20210426230700-d19ff857e887/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210510120138-977fb7262007/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.0.0-20211019181941-9d821ace8654/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.0.0-20211216021012-1d35b9e2eb4e/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220319134239-a9b59b0215f8 h1:OH54vjqzRWmbJ62fjuhxy7AxFFgoHN0/DPc/UrL8cAs= golang.org/x/sys v0.0.0-20220319134239-a9b59b0215f8/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/term v0.0.0-20201117132131-f5c789dd3221/go.mod h1:Nr5EML6q2oocZ2LXRh80K7BxOlk5/8JxuGnuhpl+muw= @@ -837,7 +805,6 @@ golang.org/x/tools v0.0.0-20191125144606-a911d9008d1f/go.mod h1:b+2E5dAYhXwXZwtn golang.org/x/tools v0.0.0-20191130070609-6e064ea0cf2d/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= golang.org/x/tools v0.0.0-20191216173652-a0e659d51361/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= golang.org/x/tools v0.0.0-20191227053925-7b8e75db28f4/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= -golang.org/x/tools v0.0.0-20200103221440-774c71fcf114/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= golang.org/x/tools v0.0.0-20200117161641-43d50277825c/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= golang.org/x/tools v0.0.0-20200122220014-bf1340f18c4a/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= golang.org/x/tools v0.0.0-20200130002326-2f3ba24bd6e7/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= diff --git a/pkg/offering/base/peer/override/deployment.go b/pkg/offering/base/peer/override/deployment.go index a9da9fb6..ab6233e9 100644 --- a/pkg/offering/base/peer/override/deployment.go +++ b/pkg/offering/base/peer/override/deployment.go @@ -729,7 +729,8 @@ func (o *Override) CommonDeploymentOverrides(instance *current.IBPPeer, deployme } externalAddress := instance.Spec.PeerExternalEndpoint - if externalAddress != "" { + // Set external address to "do-not-set" in Peer CR spec to disable Service discovery + if externalAddress != "" && externalAddress != "do-not-set" { peerContainer.AppendEnvIfMissing("CORE_PEER_GOSSIP_EXTERNALENDPOINT", externalAddress) peerContainer.AppendEnvIfMissing("CORE_PEER_GOSSIP_ENDPOINT", externalAddress) grpcContainer.AppendEnvIfMissing("EXTERNAL_ADDRESS", externalAddress) diff --git a/pkg/offering/base/peer/peer.go b/pkg/offering/base/peer/peer.go index dc55a6ef..dbc8be50 100644 --- a/pkg/offering/base/peer/peer.go +++ b/pkg/offering/base/peer/peer.go @@ -884,6 +884,11 @@ func (p *Peer) UpdateSecret(instance *current.IBPPeer, secret *corev1.Secret) er } func (p *Peer) UpdateExternalEndpoint(instance *current.IBPPeer) bool { + // Disable Service discovery + if instance.Spec.PeerExternalEndpoint == "do-not-set" { + return false + } + if instance.Spec.PeerExternalEndpoint == "" { instance.Spec.PeerExternalEndpoint = instance.Namespace + "-" + instance.Name + "-peer." + instance.Spec.Domain + ":443" return true From 4af1358d58a98821fcc3e7e6f628ef3b6a11f2fb Mon Sep 17 00:00:00 2001 From: asararatnakar Date: Thu, 6 Oct 2022 13:32:37 -0400 Subject: [PATCH 14/41] Using port 8080 for proxy probe checks to fix the errors Signed-off-by: asararatnakar --- definitions/orderer/deployment.yaml | 4 ++-- definitions/peer/deployment.yaml | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/definitions/orderer/deployment.yaml b/definitions/orderer/deployment.yaml index 8d4b5b55..8b37dd47 100644 --- a/definitions/orderer/deployment.yaml +++ b/definitions/orderer/deployment.yaml @@ -139,7 +139,7 @@ spec: livenessProbe: failureThreshold: 6 tcpSocket: - port: 7443 + port: 8080 initialDelaySeconds: 30 timeoutSeconds: 5 name: proxy @@ -150,7 +150,7 @@ spec: name: https readinessProbe: tcpSocket: - port: 7443 + port: 8080 initialDelaySeconds: 26 periodSeconds: 5 timeoutSeconds: 5 diff --git a/definitions/peer/deployment.yaml b/definitions/peer/deployment.yaml index c965927c..c7602d22 100644 --- a/definitions/peer/deployment.yaml +++ b/definitions/peer/deployment.yaml @@ -194,7 +194,7 @@ spec: livenessProbe: failureThreshold: 6 tcpSocket: - port: 7443 + port: 8080 initialDelaySeconds: 30 timeoutSeconds: 5 name: proxy @@ -205,7 +205,7 @@ spec: name: https readinessProbe: tcpSocket: - port: 7443 + port: 8080 initialDelaySeconds: 26 periodSeconds: 5 timeoutSeconds: 5 From 7d7d9a28da861956125f1abeb24daaf2f675554a Mon Sep 17 00:00:00 2001 From: Josh Kneubuhl Date: Fri, 4 Nov 2022 07:26:25 -0400 Subject: [PATCH 15/41] Launch the sample network on Apple Silicon; Pin k8s to 1.24 Signed-off-by: Josh Kneubuhl --- .../config/manager/hlf-operator-manager.yaml | 28 ++++++++----------- sample-network/network | 3 +- sample-network/scripts/kind.sh | 2 +- sample-network/scripts/test_network.sh | 2 +- 4 files changed, 15 insertions(+), 20 deletions(-) diff --git a/sample-network/config/manager/hlf-operator-manager.yaml b/sample-network/config/manager/hlf-operator-manager.yaml index 41791782..9be1e82d 100644 --- a/sample-network/config/manager/hlf-operator-manager.yaml +++ b/sample-network/config/manager/hlf-operator-manager.yaml @@ -42,33 +42,27 @@ spec: app.kubernetes.io/name: "hlf" app.kubernetes.io/instance: "hlf" app.kubernetes.io/managed-by: "fabric-operator" - annotations: - productName: "IBM Support for Hyperledger Fabric" - productID: "5d5997a033594f149a534a09802d60f1" - productVersion: "1.0.0" - productChargedContainers: "" - productMetric: "VIRTUAL_PROCESSOR_CORE" spec: # hostIPC: false # hostNetwork: false # hostPID: false serviceAccountName: hlf-operator - affinity: - nodeAffinity: - requiredDuringSchedulingIgnoredDuringExecution: - nodeSelectorTerms: - - matchExpressions: - - key: kubernetes.io/arch - operator: In - values: - - amd64 +# affinity: +# nodeAffinity: +# requiredDuringSchedulingIgnoredDuringExecution: +# nodeSelectorTerms: +# - matchExpressions: +# - key: kubernetes.io/arch +# operator: In +# values: +# - amd64 # securityContext: # runAsNonRoot: true # runAsUser: 1001 # fsGroup: 2000 - imagePullSecrets: - - name: ghcr-pull-secret +# imagePullSecrets: +# - name: image-pull-secret containers: - name: fabric-operator diff --git a/sample-network/network b/sample-network/network index 51d962e6..98e12b2f 100755 --- a/sample-network/network +++ b/sample-network/network @@ -39,12 +39,13 @@ context CONTAINER_CLI docker # or nerdctl for contain context CONTAINER_NAMESPACE "" # or "--namespace k8s.io" for containerd / nerdctl context STORAGE_CLASS standard context KUSTOMIZE_BUILD "kubectl kustomize" -context STAGE_DOCKER_IMAGES true +context STAGE_DOCKER_IMAGES false context FABRIC_CONTAINER_REGISTRY hyperledger context NAME test-network context NS $NAME context CLUSTER_NAME $CLUSTER_RUNTIME +context CLUSTER_IMAGE kindest/node:v1.24.4 # Important! k8s v1.25.0 brings breaking changes. context KUBE_DNS_DOMAIN ${NS}.svc.cluster.local context INGRESS_DOMAIN localho.st context COREDNS_DOMAIN_OVERRIDE true diff --git a/sample-network/scripts/kind.sh b/sample-network/scripts/kind.sh index cab17dea..496238d7 100644 --- a/sample-network/scripts/kind.sh +++ b/sample-network/scripts/kind.sh @@ -33,7 +33,7 @@ function kind_create() { # the 'ipvs'proxy mode permits better HA abilities - cat < Date: Tue, 20 Sep 2022 11:41:52 -0400 Subject: [PATCH 16/41] Add a project MAINTAINERS file Signed-off-by: Josh Kneubuhl --- MAINTAINERS.md | 9 +++++++++ 1 file changed, 9 insertions(+) create mode 100644 MAINTAINERS.md diff --git a/MAINTAINERS.md b/MAINTAINERS.md new file mode 100644 index 00000000..d8eaaf5e --- /dev/null +++ b/MAINTAINERS.md @@ -0,0 +1,9 @@ +## Maintainers + +### Active Maintainers + +| Name | Github | Discord | +|-------------------|-----------|----------------| +| Josh Kneubuhl | [@jkneubuh](https://github.com/jkneubuh) | jkneubuhl#5919 | +| Ratnakar Asara | [@asararatnakar](https://github.com/asararatnakar) | | +| David Enyeart | [@denyeart](https://github.com/denyeart) | denyeart#0989 | From b9eade713e7dbe5c812e186c6a25f7a6c501d572 Mon Sep 17 00:00:00 2001 From: Josh Kneubuhl Date: Fri, 4 Nov 2022 11:18:56 -0400 Subject: [PATCH 17/41] Add discord handles to MAINTAINERS Signed-off-by: Josh Kneubuhl --- MAINTAINERS.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/MAINTAINERS.md b/MAINTAINERS.md index d8eaaf5e..5ac8896f 100644 --- a/MAINTAINERS.md +++ b/MAINTAINERS.md @@ -5,5 +5,5 @@ | Name | Github | Discord | |-------------------|-----------|----------------| | Josh Kneubuhl | [@jkneubuh](https://github.com/jkneubuh) | jkneubuhl#5919 | -| Ratnakar Asara | [@asararatnakar](https://github.com/asararatnakar) | | +| Ratnakar Asara | [@asararatnakar](https://github.com/asararatnakar) | ratnakar#3494 | | David Enyeart | [@denyeart](https://github.com/denyeart) | denyeart#0989 | From 53bc1f91768c8608b88553963166e4c0091def91 Mon Sep 17 00:00:00 2001 From: Josh Kneubuhl Date: Fri, 4 Nov 2022 09:04:49 -0400 Subject: [PATCH 18/41] Run unit and integration tests with golang 1.18. Signed-off-by: Josh Kneubuhl --- .github/workflows/integration-tests.yaml | 5 +++-- .github/workflows/unit-tests.yaml | 5 ++++- go.mod | 4 ++++ go.sum | 3 +++ 4 files changed, 14 insertions(+), 3 deletions(-) diff --git a/.github/workflows/integration-tests.yaml b/.github/workflows/integration-tests.yaml index 50a712c0..91ad3236 100644 --- a/.github/workflows/integration-tests.yaml +++ b/.github/workflows/integration-tests.yaml @@ -27,6 +27,7 @@ env: KUBECONFIG_PATH: /tmp/kubeconfig.yaml OPERATOR_NAMESPACE: inttest DOCKERCONFIGJSON: ${{ secrets.DOCKERCONFIGJSON }} + GO_VER: 1.18 jobs: suite: @@ -56,11 +57,11 @@ jobs: - name: Set up go uses: actions/setup-go@v3 with: - go-version: "1.17.9" + go-version: ${{ env.GO_VER }} - name: Set up ginkgo run: | - go get github.com/onsi/ginkgo/ginkgo + go install github.com/onsi/ginkgo/ginkgo go get github.com/onsi/gomega/... - name: Set up KIND k8s cluster diff --git a/.github/workflows/unit-tests.yaml b/.github/workflows/unit-tests.yaml index 5c4a5f13..80c2ed84 100644 --- a/.github/workflows/unit-tests.yaml +++ b/.github/workflows/unit-tests.yaml @@ -25,6 +25,9 @@ on: pull_request: branches: [main] +env: + GO_VER: 1.18 + jobs: make-checks: runs-on: ubuntu-latest @@ -33,7 +36,7 @@ jobs: - name: Set up go uses: actions/setup-go@v3 with: - go-version: "1.17.9" + go-version: ${{ env.GO_VER }} - name: license header checks run: scripts/check-license.sh # TODO: run in hyperledger-labs diff --git a/go.mod b/go.mod index 32988538..bb11d11a 100644 --- a/go.mod +++ b/go.mod @@ -58,6 +58,7 @@ require ( github.com/go-openapi/swag v0.19.5 // indirect github.com/go-sql-driver/mysql v1.5.0 // indirect github.com/go-stack/stack v1.8.1 // indirect + github.com/go-task/slim-sprig v0.0.0-20210107165309-348f09dbbbc0 // indirect github.com/golang/groupcache v0.0.0-20200121045136-8c9f03a8e57e // indirect github.com/golang/protobuf v1.5.2 // indirect github.com/golang/snappy v0.0.4 // indirect @@ -93,6 +94,8 @@ require ( github.com/mitchellh/mapstructure v1.3.3 // indirect github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect github.com/modern-go/reflect2 v1.0.1 // indirect + github.com/nxadm/tail v1.4.8 // indirect + github.com/onsi/ginkgo v1.16.5 // indirect github.com/op/go-logging v0.0.0-20160315200505-970db520ece7 // indirect github.com/pelletier/go-toml v1.2.0 // indirect github.com/pierrec/lz4 v2.6.1+incompatible // indirect @@ -133,6 +136,7 @@ require ( gopkg.in/inf.v0 v0.9.1 // indirect gopkg.in/ini.v1 v1.51.0 // indirect gopkg.in/ldap.v2 v2.5.1 // indirect + gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7 // indirect gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b // indirect k8s.io/component-base v0.21.5 // indirect k8s.io/gengo v0.0.0-20201214224949-b6c5ce23f027 // indirect diff --git a/go.sum b/go.sum index fc1c51aa..500a79a7 100644 --- a/go.sum +++ b/go.sum @@ -181,6 +181,7 @@ github.com/go-sql-driver/mysql v1.5.0 h1:ozyZYNQW3x3HtqT1jira07DN2PArx2v7/mN66gG github.com/go-sql-driver/mysql v1.5.0/go.mod h1:DCzpHaOWr8IXmIStZouvnhqoel9Qv2LBy8hT2VhHyBg= github.com/go-stack/stack v1.8.1 h1:ntEHSVwIt7PNXNpgPmVfMrNhLtgjlmnZha2kOpuRiDw= github.com/go-stack/stack v1.8.1/go.mod h1:dcoOX6HbPZSZptuspn9bctJ+N/CnF5gGygcUP3XYfe4= +github.com/go-task/slim-sprig v0.0.0-20210107165309-348f09dbbbc0 h1:p104kn46Q8WdvHunIJ9dAyjPVtrBPhSr3KT2yUst43I= github.com/go-task/slim-sprig v0.0.0-20210107165309-348f09dbbbc0/go.mod h1:fyg7847qk6SyHyPtNmDHnmrv/HOrqktSC+C9fM+CJOE= github.com/go-test/deep v1.0.2 h1:onZX1rnHT3Wv6cqNgYyFOOlgVKJrksuCMCRvJStbMYw= github.com/go-test/deep v1.0.2/go.mod h1:wGDj63lr65AM2AQyKZd/NYHGb0R+1RLqB8NKt3aSFNA= @@ -445,6 +446,8 @@ github.com/onsi/ginkgo v1.12.1/go.mod h1:zj2OWP4+oCPe1qIXoGWkgMRwljMUYCdkwsT2108 github.com/onsi/ginkgo v1.16.2/go.mod h1:CObGmKUOKaSC0RjmoAK7tKyn4Azo5P2IWuoMnvwxz1E= github.com/onsi/ginkgo v1.16.4 h1:29JGrr5oVBm5ulCWet69zQkzWipVXIol6ygQUe/EzNc= github.com/onsi/ginkgo v1.16.4/go.mod h1:dX+/inL/fNMqNlz0e9LfyB9TswhZpCVdJM/Z6Vvnwo0= +github.com/onsi/ginkgo v1.16.5 h1:8xi0RTUf59SOSfEtZMvwTvXYMzG4gV23XVHOZiXNtnE= +github.com/onsi/ginkgo v1.16.5/go.mod h1:+E8gABHa3K6zRBolWtd+ROzc/U5bkGt0FwiG042wbpU= github.com/onsi/ginkgo/v2 v2.1.4 h1:GNapqRSid3zijZ9H77KrgVG4/8KqiyRsxcSxe+7ApXY= github.com/onsi/ginkgo/v2 v2.1.4/go.mod h1:um6tUpWM/cxCK3/FK8BXqEiUMUwRgSM4JXG47RKZmLU= github.com/onsi/gomega v0.0.0-20170829124025-dcabb60a477c/go.mod h1:C1qb7wdrVGGVU+Z6iS04AVkA3Q65CEZX59MT0QO5uiA= From 3161019fd0964474aecf5c19b1920c5fc971f002 Mon Sep 17 00:00:00 2001 From: Josh Kneubuhl Date: Fri, 4 Nov 2022 15:06:16 -0400 Subject: [PATCH 19/41] try not upgrading gomega + transitive Signed-off-by: Josh Kneubuhl --- .github/workflows/integration-tests.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/integration-tests.yaml b/.github/workflows/integration-tests.yaml index 91ad3236..b01253ed 100644 --- a/.github/workflows/integration-tests.yaml +++ b/.github/workflows/integration-tests.yaml @@ -62,7 +62,7 @@ jobs: - name: Set up ginkgo run: | go install github.com/onsi/ginkgo/ginkgo - go get github.com/onsi/gomega/... +# go get github.com/onsi/gomega/... - name: Set up KIND k8s cluster run: | From 4bbf88f8d7081e0d3f60968b6acbe6aafed16504 Mon Sep 17 00:00:00 2001 From: Josh Kneubuhl Date: Fri, 4 Nov 2022 15:18:27 -0400 Subject: [PATCH 20/41] Disable gomega upgrade during integration test runs Signed-off-by: Josh Kneubuhl --- .github/workflows/integration-tests.yaml | 1 - 1 file changed, 1 deletion(-) diff --git a/.github/workflows/integration-tests.yaml b/.github/workflows/integration-tests.yaml index b01253ed..e3713f74 100644 --- a/.github/workflows/integration-tests.yaml +++ b/.github/workflows/integration-tests.yaml @@ -62,7 +62,6 @@ jobs: - name: Set up ginkgo run: | go install github.com/onsi/ginkgo/ginkgo -# go get github.com/onsi/gomega/... - name: Set up KIND k8s cluster run: | From 1cc98adbeb068acc9bd2f1be4d1547d7c368f9a7 Mon Sep 17 00:00:00 2001 From: Abirdcfly Date: Fri, 4 Nov 2022 16:01:24 +0800 Subject: [PATCH 21/41] cleanup: remove BoolTrue and BoolFalse variable Signed-off-by: Abirdcfly --- api/v1beta1/common_struct.go | 3 --- api/v1beta1/ibporderer.go | 20 ++----------------- .../ibporderer/ibporderer_controller_test.go | 3 ++- .../ibppeer/ibppeer_controller_test.go | 5 +++-- go.mod | 2 +- integration/e2ev2/orderer_test.go | 3 ++- integration/e2ev2/peer_test.go | 3 ++- integration/init/orderer_test.go | 5 +++-- integration/init/peer_test.go | 7 ++++--- integration/orderer/orderer_test.go | 13 ++++++------ integration/peer/peer_test.go | 5 +++-- pkg/offering/base/orderer/orderer.go | 3 ++- 12 files changed, 31 insertions(+), 41 deletions(-) diff --git a/api/v1beta1/common_struct.go b/api/v1beta1/common_struct.go index adb6bf27..b13114e1 100644 --- a/api/v1beta1/common_struct.go +++ b/api/v1beta1/common_struct.go @@ -22,9 +22,6 @@ import ( corev1 "k8s.io/api/core/v1" ) -var BoolTrue = true -var BoolFalse = false - // Service is the overrides to be used for Service of the component // +operator-sdk:gen-csv:customresourcedefinitions.specDescriptors=true type Service struct { diff --git a/api/v1beta1/ibporderer.go b/api/v1beta1/ibporderer.go index 7324ec97..b61e3efa 100644 --- a/api/v1beta1/ibporderer.go +++ b/api/v1beta1/ibporderer.go @@ -236,27 +236,11 @@ func (s *IBPOrdererSpec) DomainSet() bool { } func (s *IBPOrdererSpec) IsPrecreateOrderer() bool { - if s.IsPrecreate == nil { - return false - } - - if *s.IsPrecreate == BoolTrue { - return true - } - - return false + return s.IsPrecreate != nil && *s.IsPrecreate } func (s *IBPOrdererSpec) IsUsingChannelLess() bool { - if s.UseChannelLess == nil { - return false - } - - if *s.UseChannelLess == BoolTrue { - return true - } - - return false + return s.UseChannelLess != nil && *s.UseChannelLess } func (s *IBPOrdererSpec) GetNumSecondsWarningPeriod() int64 { diff --git a/controllers/ibporderer/ibporderer_controller_test.go b/controllers/ibporderer/ibporderer_controller_test.go index 6bbf45b7..0a50a0cf 100644 --- a/controllers/ibporderer/ibporderer_controller_test.go +++ b/controllers/ibporderer/ibporderer_controller_test.go @@ -28,6 +28,7 @@ import ( . "github.com/onsi/ginkgo/v2" . "github.com/onsi/gomega" + "k8s.io/utils/pointer" current "github.com/IBM-Blockchain/fabric-operator/api/v1beta1" orderermocks "github.com/IBM-Blockchain/fabric-operator/controllers/ibporderer/mocks" @@ -640,7 +641,7 @@ var _ = Describe("ReconcileIBPOrderer", func() { Name: instance.Name, }, } - newOrderer.Spec.DisableNodeOU = ¤t.BoolTrue + newOrderer.Spec.DisableNodeOU = pointer.Bool(true) e = event.UpdateEvent{ ObjectOld: oldOrderer, diff --git a/controllers/ibppeer/ibppeer_controller_test.go b/controllers/ibppeer/ibppeer_controller_test.go index 9f08ab21..566adcfc 100644 --- a/controllers/ibppeer/ibppeer_controller_test.go +++ b/controllers/ibppeer/ibppeer_controller_test.go @@ -26,6 +26,7 @@ import ( . "github.com/onsi/ginkgo/v2" . "github.com/onsi/gomega" + "k8s.io/utils/pointer" current "github.com/IBM-Blockchain/fabric-operator/api/v1beta1" peermocks "github.com/IBM-Blockchain/fabric-operator/controllers/ibppeer/mocks" @@ -41,7 +42,7 @@ import ( "sigs.k8s.io/controller-runtime/pkg/client" "sigs.k8s.io/controller-runtime/pkg/event" "sigs.k8s.io/controller-runtime/pkg/reconcile" - yaml "sigs.k8s.io/yaml" + "sigs.k8s.io/yaml" ) var _ = Describe("ReconcileIBPPeer", func() { @@ -606,7 +607,7 @@ var _ = Describe("ReconcileIBPPeer", func() { Name: instance.Name, }, } - newPeer.Spec.DisableNodeOU = ¤t.BoolTrue + newPeer.Spec.DisableNodeOU = pointer.Bool(true) e = event.UpdateEvent{ ObjectOld: oldPeer, diff --git a/go.mod b/go.mod index bb11d11a..d053fcd8 100644 --- a/go.mod +++ b/go.mod @@ -28,6 +28,7 @@ require ( k8s.io/apimachinery v0.21.5 k8s.io/client-go v0.21.5 k8s.io/code-generator v0.21.5 + k8s.io/utils v0.0.0-20210527160623-6fdb442a123b sigs.k8s.io/controller-runtime v0.9.0 sigs.k8s.io/yaml v1.2.0 ) @@ -142,7 +143,6 @@ require ( k8s.io/gengo v0.0.0-20201214224949-b6c5ce23f027 // indirect k8s.io/klog/v2 v2.8.0 // indirect k8s.io/kube-openapi v0.0.0-20210305001622-591a79e4bda7 // indirect - k8s.io/utils v0.0.0-20210527160623-6fdb442a123b // indirect sigs.k8s.io/structured-merge-diff/v4 v4.1.2 // indirect ) diff --git a/integration/e2ev2/orderer_test.go b/integration/e2ev2/orderer_test.go index a1cc3283..8dad45cf 100644 --- a/integration/e2ev2/orderer_test.go +++ b/integration/e2ev2/orderer_test.go @@ -28,6 +28,7 @@ import ( . "github.com/onsi/ginkgo/v2" . "github.com/onsi/gomega" + "k8s.io/utils/pointer" "sigs.k8s.io/controller-runtime/pkg/client" current "github.com/IBM-Blockchain/fabric-operator/api/v1beta1" @@ -302,7 +303,7 @@ var _ = Describe("orderer", func() { result.Into(ibporderer) // Disable node ou - ibporderer.Spec.DisableNodeOU = ¤t.BoolTrue + ibporderer.Spec.DisableNodeOU = pointer.Bool(true) bytes, err := json.Marshal(ibporderer) Expect(err).NotTo(HaveOccurred()) diff --git a/integration/e2ev2/peer_test.go b/integration/e2ev2/peer_test.go index b76e858f..1f4bde2b 100644 --- a/integration/e2ev2/peer_test.go +++ b/integration/e2ev2/peer_test.go @@ -25,6 +25,7 @@ import ( . "github.com/onsi/ginkgo/v2" . "github.com/onsi/gomega" + "k8s.io/utils/pointer" current "github.com/IBM-Blockchain/fabric-operator/api/v1beta1" "github.com/IBM-Blockchain/fabric-operator/pkg/apis/common" @@ -154,7 +155,7 @@ var _ = Describe("peer", func() { result.Into(peer) // Disable node ou - peer.Spec.DisableNodeOU = ¤t.BoolTrue + peer.Spec.DisableNodeOU = pointer.Bool(true) bytes, err = json.Marshal(peer) Expect(err).NotTo(HaveOccurred()) }) diff --git a/integration/init/orderer_test.go b/integration/init/orderer_test.go index 82fa06e7..1acd724d 100644 --- a/integration/init/orderer_test.go +++ b/integration/init/orderer_test.go @@ -32,6 +32,7 @@ import ( . "github.com/onsi/ginkgo/v2" . "github.com/onsi/gomega" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + "k8s.io/utils/pointer" ) const ( @@ -86,7 +87,7 @@ var _ = Describe("Orderer init", func() { TLS: msp, }, }, - DisableNodeOU: ¤t.BoolTrue, + DisableNodeOU: pointer.Bool(true), }, } instance.Namespace = namespace @@ -211,7 +212,7 @@ var _ = Describe("Orderer init", func() { TLS: enrollment, }, }, - DisableNodeOU: ¤t.BoolTrue, + DisableNodeOU: pointer.Bool(true), }, } instance.Namespace = namespace diff --git a/integration/init/peer_test.go b/integration/init/peer_test.go index 363941e0..51317a99 100644 --- a/integration/init/peer_test.go +++ b/integration/init/peer_test.go @@ -26,7 +26,7 @@ import ( "path/filepath" current "github.com/IBM-Blockchain/fabric-operator/api/v1beta1" - operatorconfig "github.com/IBM-Blockchain/fabric-operator/operatorconfig" + "github.com/IBM-Blockchain/fabric-operator/operatorconfig" "github.com/IBM-Blockchain/fabric-operator/pkg/initializer/common/enroller" initializer "github.com/IBM-Blockchain/fabric-operator/pkg/initializer/peer" peerinit "github.com/IBM-Blockchain/fabric-operator/pkg/initializer/peer" @@ -37,6 +37,7 @@ import ( . "github.com/onsi/ginkgo/v2" . "github.com/onsi/gomega" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + "k8s.io/utils/pointer" ) const ( @@ -98,7 +99,7 @@ var _ = Describe("Peer init", func() { TLS: msp, }, }, - DisableNodeOU: ¤t.BoolTrue, + DisableNodeOU: pointer.Bool(true), }, } instance.Namespace = namespace @@ -220,7 +221,7 @@ var _ = Describe("Peer init", func() { TLS: enrollment, }, }, - DisableNodeOU: ¤t.BoolTrue, + DisableNodeOU: pointer.Bool(true), }, } instance.Namespace = namespace diff --git a/integration/orderer/orderer_test.go b/integration/orderer/orderer_test.go index 79b0ce0a..b5f0b811 100644 --- a/integration/orderer/orderer_test.go +++ b/integration/orderer/orderer_test.go @@ -27,6 +27,7 @@ import ( "fmt" "time" + "k8s.io/utils/pointer" "sigs.k8s.io/yaml" current "github.com/IBM-Blockchain/fabric-operator/api/v1beta1" @@ -939,7 +940,7 @@ func GetOrderer() (*Orderer, []Orderer) { }, }, ConfigOverride: &runtime.RawExtension{Raw: configBytes}, - DisableNodeOU: ¤t.BoolTrue, + DisableNodeOU: pointer.Bool(true), FabricVersion: integration.FabricVersion + "-1", }, } @@ -1022,7 +1023,7 @@ func GetOrderer2() (*Orderer, []Orderer) { Limits: defaultLimitsProxy, }, }, - DisableNodeOU: ¤t.BoolTrue, + DisableNodeOU: pointer.Bool(true), FabricVersion: integration.FabricVersion + "-1", }, } @@ -1117,7 +1118,7 @@ func GetOrderer3() (*Orderer, []Orderer) { Region: "us-south2", }, }, - DisableNodeOU: ¤t.BoolTrue, + DisableNodeOU: pointer.Bool(true), FabricVersion: integration.FabricVersion + "-1", }, } @@ -1200,7 +1201,7 @@ func GetOrderer4() (*Orderer, []Orderer) { Limits: defaultLimitsProxy, }, }, - DisableNodeOU: ¤t.BoolTrue, + DisableNodeOU: pointer.Bool(true), FabricVersion: integration.FabricVersion + "-1", }, } @@ -1268,7 +1269,7 @@ func GetOrderer5() (*Orderer, []Orderer) { }, OrdererType: "etcdraft", SystemChannelName: "testchainid", - UseChannelLess: ¤t.BoolTrue, + UseChannelLess: pointer.Bool(true), OrgName: "orderermsp", MSPID: "orderermsp", ImagePullSecrets: []string{"regcred"}, @@ -1297,7 +1298,7 @@ func GetOrderer5() (*Orderer, []Orderer) { Limits: defaultLimitsProxy, }, }, - DisableNodeOU: ¤t.BoolTrue, + DisableNodeOU: pointer.Bool(true), FabricVersion: integration.FabricVersion24 + "-1", }, } diff --git a/integration/peer/peer_test.go b/integration/peer/peer_test.go index aa9f7935..48ae1d55 100644 --- a/integration/peer/peer_test.go +++ b/integration/peer/peer_test.go @@ -43,6 +43,7 @@ import ( "k8s.io/apimachinery/pkg/runtime" "k8s.io/apimachinery/pkg/types" "k8s.io/apimachinery/pkg/util/wait" + "k8s.io/utils/pointer" "sigs.k8s.io/yaml" ) @@ -813,7 +814,7 @@ func GetPeer1() *Peer { MSP: testMSPSpec, }, ConfigOverride: &runtime.RawExtension{Raw: configBytes}, - DisableNodeOU: ¤t.BoolTrue, + DisableNodeOU: pointer.Bool(true), FabricVersion: integration.FabricVersion + "-1", }, } @@ -867,7 +868,7 @@ func GetPeer2() *Peer { Secret: ¤t.SecretSpec{ MSP: testMSPSpec, }, - DisableNodeOU: ¤t.BoolTrue, + DisableNodeOU: pointer.Bool(true), FabricVersion: integration.FabricVersion + "-1", }, } diff --git a/pkg/offering/base/orderer/orderer.go b/pkg/offering/base/orderer/orderer.go index 094d3c62..fae32ae3 100644 --- a/pkg/offering/base/orderer/orderer.go +++ b/pkg/offering/base/orderer/orderer.go @@ -55,6 +55,7 @@ import ( "k8s.io/apimachinery/pkg/runtime" "k8s.io/apimachinery/pkg/types" "k8s.io/apimachinery/pkg/util/wait" + "k8s.io/utils/pointer" "sigs.k8s.io/controller-runtime/pkg/client" logf "sigs.k8s.io/controller-runtime/pkg/log" "sigs.k8s.io/controller-runtime/pkg/reconcile" @@ -461,7 +462,7 @@ func (o *Orderer) CreateNodeCR(instance *current.IBPOrderer, number int) error { if instance.Spec.IsUsingChannelLess() { node.Spec.UseChannelLess = instance.Spec.UseChannelLess } else { - node.Spec.IsPrecreate = ¤t.BoolTrue + node.Spec.IsPrecreate = pointer.Bool(true) } node.Spec.NodeNumber = &number node.Spec.ClusterSize = 1 From 44fb8a3052c28c3b87f188c7163bd6938a3b72b7 Mon Sep 17 00:00:00 2001 From: bjwswang Date: Fri, 28 Oct 2022 13:39:29 +0800 Subject: [PATCH 22/41] fix: console typo when stop sample network service Signed-off-by: bjwswang --- sample-network/scripts/test_network.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sample-network/scripts/test_network.sh b/sample-network/scripts/test_network.sh index f0c2a3c1..f7e2394b 100644 --- a/sample-network/scripts/test_network.sh +++ b/sample-network/scripts/test_network.sh @@ -166,7 +166,7 @@ function apply_network_orderers() { function stop_services() { push_fn "Stopping Fabric Services" - undo_kustomization config/consoles + undo_kustomization config/console undo_kustomization config/cas undo_kustomization config/peers undo_kustomization config/orderers From 718edf87dc29a47e4368e7cdd2ced865743ec03a Mon Sep 17 00:00:00 2001 From: Josh Kneubuhl Date: Fri, 4 Nov 2022 22:38:54 -0400 Subject: [PATCH 23/41] Add an OPERATOR_LOCAL_MODE environment variable to launch the operator in a debugger. Signed-off-by: Josh Kneubuhl --- docs/DEVELOPING.md | 10 +++++++--- main.go | 12 ++++++------ pkg/command/operator.go | 11 ++++++++--- 3 files changed, 21 insertions(+), 12 deletions(-) diff --git a/docs/DEVELOPING.md b/docs/DEVELOPING.md index ffa4cfdb..3937d581 100644 --- a/docs/DEVELOPING.md +++ b/docs/DEVELOPING.md @@ -55,10 +55,14 @@ INT_TEST_NAME= make integration-tests ## Debug the Operator -Run / debug `main.go` with env: - +Launch main.go with the following environment: ```shell -KUBECONFIG_PATH=$HOME/.kube/config +export KUBECONFIG=$HOME/.kube/config +export WATCH_NAMESPACE=test-network +export CLUSTERTYPE=k8s +export OPERATOR_LOCAL_MODE=true + +go run . ``` diff --git a/main.go b/main.go index 877a1f4f..5f9570b9 100644 --- a/main.go +++ b/main.go @@ -41,11 +41,11 @@ import ( ) const ( - defaultConfigs = "../../defaultconfig" - defaultPeerDef = "../../definitions/peer" - defaultCADef = "../../definitions/ca" - defaultOrdererDef = "../../definitions/orderer" - defaultConsoleDef = "../../definitions/console" + defaultConfigs = "./defaultconfig" + defaultPeerDef = "./definitions/peer" + defaultCADef = "./definitions/ca" + defaultOrdererDef = "./definitions/orderer" + defaultConsoleDef = "./definitions/console" ) var log = logf.Log.WithName("cmd") @@ -72,7 +72,7 @@ func main() { operatorCfg.Operator.SetDefaults() - if err := command.Operator(operatorCfg, true); err != nil { + if err := command.Operator(operatorCfg); err != nil { log.Error(err, "failed to start operator") time.Sleep(15 * time.Second) } diff --git a/pkg/command/operator.go b/pkg/command/operator.go index 1575b821..90d3a8b4 100644 --- a/pkg/command/operator.go +++ b/pkg/command/operator.go @@ -71,9 +71,14 @@ func printVersion() { log.Info(fmt.Sprintf("Go OS/Arch: %s/%s", runtime.GOOS, runtime.GOARCH)) } -func Operator(operatorCfg *oconfig.Config, blocking bool) error { +func Operator(operatorCfg *oconfig.Config) error { signalHandler := signals.SetupSignalHandler() - return OperatorWithSignal(operatorCfg, signalHandler, blocking, false) + + // In local mode, the operator may be launched and debugged directly as a native process without + // being deployed to a Kubernetes cluster. + local := os.Getenv("OPERATOR_LOCAL_MODE") == "true" + + return OperatorWithSignal(operatorCfg, signalHandler, true, local) } func OperatorWithSignal(operatorCfg *oconfig.Config, signalHandler context.Context, blocking, local bool) error { @@ -118,7 +123,7 @@ func OperatorWithSignal(operatorCfg *oconfig.Config, signalHandler context.Conte return err } } else { - log.Info("Installing operator in own namespace mode") + log.Info("Installing operator in own namespace mode", "WATCH_NAMESPACE", watchNamespace) operatorNamespace = watchNamespace } From db38e856fda7798650de925addadbc75305adc39 Mon Sep 17 00:00:00 2001 From: Josh Kneubuhl Date: Mon, 7 Nov 2022 07:41:05 -0500 Subject: [PATCH 24/41] When running with OPERATOR_LOCAL_MODE, emit log output as unstructured text. Signed-off-by: Josh Kneubuhl --- pkg/command/operator.go | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/pkg/command/operator.go b/pkg/command/operator.go index 90d3a8b4..ec584045 100644 --- a/pkg/command/operator.go +++ b/pkg/command/operator.go @@ -105,7 +105,8 @@ func OperatorWithSignal(operatorCfg *oconfig.Config, signalHandler context.Conte logf.SetLogger(*operatorCfg.Logger) ctrl.SetLogger(*operatorCfg.Logger) } else { - logf.SetLogger(zap.New()) + // Use the unstructured log formatter when running locally. + logf.SetLogger(zap.New(zap.UseDevMode(local))) ctrl.SetLogger(zap.New(zap.UseDevMode(true))) } From 11e5788b328a7c3cfe5e7e2ede8c9bafb693b9dd Mon Sep 17 00:00:00 2001 From: asararatnakar Date: Fri, 11 Nov 2022 07:39:35 -0500 Subject: [PATCH 25/41] Use PodSecurity Admission controller for k8s versions v1.25.x Signed-off-by: asararatnakar --- sample-network/config/rbac/hlf-operator-clusterrole.yaml | 8 -------- sample-network/config/rbac/kustomization.yaml | 1 - sample-network/network | 2 +- sample-network/scripts/test_network.sh | 3 +++ 4 files changed, 4 insertions(+), 10 deletions(-) diff --git a/sample-network/config/rbac/hlf-operator-clusterrole.yaml b/sample-network/config/rbac/hlf-operator-clusterrole.yaml index fb35269b..9a1c1150 100644 --- a/sample-network/config/rbac/hlf-operator-clusterrole.yaml +++ b/sample-network/config/rbac/hlf-operator-clusterrole.yaml @@ -27,14 +27,6 @@ metadata: app.kubernetes.io/instance: "ibm-hlfsupport" app.kubernetes.io/managed-by: "ibm-hlfsupport-operator" rules: - - apiGroups: - - extensions - resourceNames: - - ibm-hlfsupport-psp - resources: - - podsecuritypolicies - verbs: - - use - apiGroups: - apiextensions.k8s.io resources: diff --git a/sample-network/config/rbac/kustomization.yaml b/sample-network/config/rbac/kustomization.yaml index 9a5132c7..c43e0e71 100644 --- a/sample-network/config/rbac/kustomization.yaml +++ b/sample-network/config/rbac/kustomization.yaml @@ -19,7 +19,6 @@ apiVersion: kustomize.config.k8s.io/v1beta1 kind: Kustomization resources: - - hlf-psp.yaml - hlf-operator-serviceaccount.yaml - hlf-operator-clusterrole.yaml - hlf-operator-clusterrolebinding.yaml diff --git a/sample-network/network b/sample-network/network index 98e12b2f..042d935f 100755 --- a/sample-network/network +++ b/sample-network/network @@ -45,7 +45,7 @@ context FABRIC_CONTAINER_REGISTRY hyperledger context NAME test-network context NS $NAME context CLUSTER_NAME $CLUSTER_RUNTIME -context CLUSTER_IMAGE kindest/node:v1.24.4 # Important! k8s v1.25.0 brings breaking changes. +context CLUSTER_IMAGE kindest/node:v1.25.3 # Pin k8s to v1.25.x context KUBE_DNS_DOMAIN ${NS}.svc.cluster.local context INGRESS_DOMAIN localho.st context COREDNS_DOMAIN_OVERRIDE true diff --git a/sample-network/scripts/test_network.sh b/sample-network/scripts/test_network.sh index f7e2394b..afc41664 100644 --- a/sample-network/scripts/test_network.sh +++ b/sample-network/scripts/test_network.sh @@ -59,6 +59,9 @@ metadata: name: test-network EOF + # https://kubernetes.io/docs/tasks/configure-pod-container/migrate-from-psp/ + kubectl label --overwrite namespace $NS pod-security.kubernetes.io/enforce=baseline + pop_fn } From 4b222fe2909803e94241474c1f05d5321b02bfc0 Mon Sep 17 00:00:00 2001 From: asararatnakar Date: Fri, 11 Nov 2022 07:43:09 -0500 Subject: [PATCH 26/41] remove the psp file Signed-off-by: asararatnakar --- sample-network/config/rbac/hlf-psp.yaml | 48 ------------------------- 1 file changed, 48 deletions(-) delete mode 100644 sample-network/config/rbac/hlf-psp.yaml diff --git a/sample-network/config/rbac/hlf-psp.yaml b/sample-network/config/rbac/hlf-psp.yaml deleted file mode 100644 index dcd53c72..00000000 --- a/sample-network/config/rbac/hlf-psp.yaml +++ /dev/null @@ -1,48 +0,0 @@ -# -# Copyright contributors to the Hyperledger Fabric Operator project -# -# SPDX-License-Identifier: Apache-2.0 -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at: -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. -# ---- -apiVersion: policy/v1beta1 -kind: PodSecurityPolicy -metadata: - name: ibm-hlfsupport-psp -spec: - hostIPC: false - hostNetwork: false - hostPID: false - privileged: true - allowPrivilegeEscalation: true - readOnlyRootFilesystem: false - seLinux: - rule: RunAsAny - supplementalGroups: - rule: RunAsAny - runAsUser: - rule: RunAsAny - fsGroup: - rule: RunAsAny - requiredDropCapabilities: - - ALL - allowedCapabilities: - - NET_BIND_SERVICE - - CHOWN - - DAC_OVERRIDE - - SETGID - - SETUID - - FOWNER - volumes: - - '*' From 234effb7c462bb11bd51c8482fb53da4f43a95bf Mon Sep 17 00:00:00 2001 From: Josh Kneubuhl Date: Tue, 6 Dec 2022 14:14:42 -0500 Subject: [PATCH 27/41] Build multi-arch arm64 and amd64 docker images Signed-off-by: Josh Kneubuhl --- .github/workflows/image-build.yaml | 20 ---- .github/workflows/release.yaml | 91 +++++++++++++++++++ Dockerfile | 16 +++- Makefile | 49 +++------- bundle.Dockerfile | 7 +- ...source-operator.clusterserviceversion.yaml | 6 +- bundle/manifests/ibp.com_ibpcas.yaml | 17 ---- bundle/manifests/ibp.com_ibpconsoles.yaml | 17 ---- bundle/manifests/ibp.com_ibporderers.yaml | 17 ---- bundle/manifests/ibp.com_ibppeers.yaml | 17 ---- bundle/metadata/annotations.yaml | 6 +- config/crd/bases/ibp.com_ibpcas.yaml | 17 ---- config/crd/bases/ibp.com_ibpconsoles.yaml | 17 ---- config/crd/bases/ibp.com_ibporderers.yaml | 17 ---- config/crd/bases/ibp.com_ibppeers.yaml | 17 ---- go.sum | 1 - release_notes/v1.0.0.md | 21 +++++ release_notes/v1.0.4.md | 21 +++++ scripts/install-tools.sh | 17 ++-- 19 files changed, 171 insertions(+), 220 deletions(-) delete mode 100644 .github/workflows/image-build.yaml create mode 100644 .github/workflows/release.yaml create mode 100644 release_notes/v1.0.0.md create mode 100644 release_notes/v1.0.4.md diff --git a/.github/workflows/image-build.yaml b/.github/workflows/image-build.yaml deleted file mode 100644 index 8003a025..00000000 --- a/.github/workflows/image-build.yaml +++ /dev/null @@ -1,20 +0,0 @@ -name: Build Operator image - -on: - push: - branches: [main] - -jobs: - image: - runs-on: ubuntu-latest - steps: - - uses: actions/checkout@v2 - - - name: Build - run: | - scripts/install-tools.sh - make image - - name: Push - run: | - echo ${{ secrets.GITHUB_TOKEN }} | docker login ghcr.io -u $GITHUB_ACTOR --password-stdin - make image-push image-push-latest diff --git a/.github/workflows/release.yaml b/.github/workflows/release.yaml new file mode 100644 index 00000000..e6df6be0 --- /dev/null +++ b/.github/workflows/release.yaml @@ -0,0 +1,91 @@ +name: Release Operator + +on: + pull_request: + branches: [ release-1.0 ] + push: + tags: [ v1.* ] + +env: + GO_VER: 1.18.4 + GO_TAGS: "" + REGISTRY: ghcr.io + IMAGE_NAME: ${{ github.repository }} + SEMREV_LABEL: ${{ github.ref_name }} + +permissions: + contents: read + +jobs: + build-and-push-image: + runs-on: ubuntu-20.04 + + permissions: + contents: read + packages: write + + steps: + - name: Set up QEMU + uses: docker/setup-qemu-action@v2 + + - name: Set up Docker Buildx + uses: docker/setup-buildx-action@v2 + with: + buildkitd-flags: --debug + config-inline: | + [worker.oci] + max-parallelism = 1 + + - name: Checkout + uses: actions/checkout@v3 + + - name: Login to the GitHub Container Registry + uses: docker/login-action@v2 + with: + registry: ${{ env.REGISTRY }} + username: ${{ github.actor }} + password: ${{ secrets.GITHUB_TOKEN }} + + - name: Docker meta + id: meta + uses: docker/metadata-action@v4 + with: + images: ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }} + tags: | + type=semver,pattern={{version}} + type=semver,pattern={{major}}.{{minor}} + type=semver,pattern={{major}}.{{minor}}.{{patch}} + + - name: Build and push + id: push + uses: docker/build-push-action@v3 + with: + context: . + file: Dockerfile + platforms: linux/amd64,linux/arm64 + tags: ${{ steps.meta.outputs.tags }} + push: ${{ github.event_name != 'pull_request' }} + labels: ${{ steps.meta.outputs.labels }} + build-args: | + GO_VER=${{ env.GO_VER }} + GO_TAGS=${{ env.GO_TAGS }} + BUILD_ID=${{ env.SEMREV_LABEL }} + BUILD_DATE=${{ env.BUILD_DATE }} + + + create-release: + name: Create GitHub Release + needs: [ build-and-push-image ] + runs-on: ubuntu-20.04 + permissions: + contents: write + steps: + - name: Checkout + uses: actions/checkout@v3 + - name: Release Operator Version + uses: ncipollo/release-action@v1 + with: + allowUpdates: "true" + bodyFile: release_notes/${{ env.SEMREV_LABEL }}.md + tag: ${{ env.SEMREV_LABEL }} + token: ${{ secrets.GITHUB_TOKEN }} diff --git a/Dockerfile b/Dockerfile index 4af4582e..9e0fc266 100644 --- a/Dockerfile +++ b/Dockerfile @@ -1,12 +1,17 @@ -ARG ARCH -ARG REGISTRY ARG GO_VER ########## Build operator binary ########## FROM registry.access.redhat.com/ubi8/go-toolset:$GO_VER as builder -COPY . /go/src/github.com/IBM-Blockchain/fabric-operator -WORKDIR /go/src/github.com/IBM-Blockchain/fabric-operator -RUN GOOS=linux GOARCH=$(go env GOARCH) CGO_ENABLED=1 go build -mod=vendor -tags "pkcs11" -gcflags all=-trimpath=${GOPATH} -asmflags all=-trimpath=${GOPATH} -o /tmp/build/_output/bin/ibp-operator + +COPY . /go/src/github.com/hyperledger-labs/fabric-operator +WORKDIR /go/src/github.com/hyperledger-labs/fabric-operator + +# RUN GOOS=linux GOARCH=$(go env GOARCH) CGO_ENABLED=1 go build +RUN go build \ + -tags "pkcs11" \ + -gcflags all=-trimpath=${GOPATH} \ + -asmflags all=-trimpath=${GOPATH} \ + -o /tmp/build/_output/bin/ibp-operator ########## Final Image ########## FROM registry.access.redhat.com/ubi8/ubi-minimal @@ -19,6 +24,7 @@ COPY definitions /definitions COPY config/crd/bases /deploy/crds COPY defaultconfig /defaultconfig COPY docker-entrypoint.sh . + RUN microdnf update \ && microdnf install -y \ shadow-utils \ diff --git a/Makefile b/Makefile index b3f8e106..26df3734 100644 --- a/Makefile +++ b/Makefile @@ -16,50 +16,37 @@ # limitations under the License. # -IMAGE ?= ghcr.io/hyperledger-labs/fabric-operator -TAG ?= $(shell git rev-parse --short HEAD) +IMAGE ?= hyperledger-labs/fabric-operator ARCH ?= $(shell go env GOARCH) -OSS_GO_VER ?= 1.17.7 -BUILD_DATE = $(shell date -u +"%Y-%m-%dT%H:%M:%SZ") OS = $(shell go env GOOS) +SEMREV_LABEL ?= v1.0.0-$(shell git rev-parse --short HEAD) +BUILD_DATE = $(shell date -u +"%Y-%m-%dT%H:%M:%SZ") +GO_VER ?= 1.18.4 -DOCKER_IMAGE_REPO ?= ghcr.io +# For compatibility with legacy install-fabric.sh conventions, strip the +# leading semrev 'v' character when preparing dist and release artifacts. +VERSION=$(shell echo $(SEMREV_LABEL) | sed -e 's/^v\(.*\)/\1/') -BUILD_ARGS=--build-arg ARCH=$(ARCH) -BUILD_ARGS+=--build-arg BUILD_ID=$(TAG) -BUILD_ARGS+=--build-arg BUILD_DATE=$(BUILD_DATE) -BUILD_ARGS+=--build-arg GO_VER=$(OSS_GO_VER) -ifneq ($(origin TRAVIS_PULL_REQUEST),undefined) - ifneq ($(TRAVIS_PULL_REQUEST), false) - TAG=pr-$(TRAVIS_PULL_REQUEST) - endif -endif +DOCKER_BUILD ?= docker build -NAMESPACE ?= n$(shell echo $(TAG) | tr -d "-") +BUILD_ARGS+=--build-arg BUILD_ID=$(VERSION) +BUILD_ARGS+=--build-arg BUILD_DATE=$(BUILD_DATE) +BUILD_ARGS+=--build-arg GO_VER=$(GO_VER) .PHONY: build -build: ## Builds the starter pack +build: mkdir -p bin && go build -o bin/operator image: setup - docker build --rm . -f Dockerfile $(BUILD_ARGS) -t $(IMAGE):$(TAG)-$(ARCH) - docker tag $(IMAGE):$(TAG)-$(ARCH) $(IMAGE):latest-$(ARCH) + $(DOCKER_BUILD) -f Dockerfile $(BUILD_ARGS) -t $(IMAGE) . govendor: @go mod vendor setup: govendor manifests bundle generate -image-push: - docker push $(IMAGE):$(TAG)-$(ARCH) - -image-push-latest: - docker push $(IMAGE):latest-$(ARCH) - -login: - docker login --username $(DOCKER_USERNAME) --password $(DOCKER_PASSWORD) $(DOCKER_IMAGE_REPO) ####################################### #### part of autogenerate makefile #### @@ -156,14 +143,6 @@ vet: generate: controller-gen $(CONTROLLER_GEN) object:headerFile="boilerplate/boilerplate.go.txt" paths="./..." -# Build the docker image -docker-build: test - docker build . -t ${IMG} - -# Push the docker image -docker-push: - docker push ${IMG} - # find or download controller-gen # download controller-gen if necessary controller-gen: @@ -188,7 +167,7 @@ ifeq (, $(shell which kustomize)) KUSTOMIZE_GEN_TMP_DIR=$$(mktemp -d) ;\ cd $$KUSTOMIZE_GEN_TMP_DIR ;\ go mod init tmp ;\ - go install sigs.k8s.io/kustomize/kustomize/v3@v3.5.4 ;\ + go install sigs.k8s.io/kustomize/kustomize/v4@v4.5.7 ;\ rm -rf $$KUSTOMIZE_GEN_TMP_DIR ;\ } KUSTOMIZE=$(GOBIN)/kustomize diff --git a/bundle.Dockerfile b/bundle.Dockerfile index ebbe8fa3..34e109dd 100644 --- a/bundle.Dockerfile +++ b/bundle.Dockerfile @@ -6,15 +6,10 @@ LABEL operators.operatorframework.io.bundle.manifests.v1=manifests/ LABEL operators.operatorframework.io.bundle.metadata.v1=metadata/ LABEL operators.operatorframework.io.bundle.package.v1=fabric-opensource-operator LABEL operators.operatorframework.io.bundle.channels.v1=alpha -LABEL operators.operatorframework.io.metrics.builder=operator-sdk-v1.19.0+git +LABEL operators.operatorframework.io.metrics.builder=operator-sdk-v1.24.1 LABEL operators.operatorframework.io.metrics.mediatype.v1=metrics+v1 LABEL operators.operatorframework.io.metrics.project_layout=go.kubebuilder.io/v3 -# Labels for testing. -LABEL operators.operatorframework.io.test.mediatype.v1=scorecard+v1 -LABEL operators.operatorframework.io.test.config.v1=tests/scorecard/ - # Copy files to locations specified by labels. COPY bundle/manifests /manifests/ COPY bundle/metadata /metadata/ -COPY bundle/tests/scorecard /tests/scorecard/ diff --git a/bundle/manifests/fabric-opensource-operator.clusterserviceversion.yaml b/bundle/manifests/fabric-opensource-operator.clusterserviceversion.yaml index cb2bdd3a..f74d47d0 100644 --- a/bundle/manifests/fabric-opensource-operator.clusterserviceversion.yaml +++ b/bundle/manifests/fabric-opensource-operator.clusterserviceversion.yaml @@ -9,11 +9,11 @@ metadata: containerImage: todo:update createdAt: "2020-07-14T00:00:00Z" description: TODO - operators.operatorframework.io/builder: operator-sdk-v1.19.0+git + operators.operatorframework.io/builder: operator-sdk-v1.24.1 operators.operatorframework.io/internal-objects: '["ibpcas.ibp.com","ibppeers.ibp.com","ibporderers.ibp.com"]' operators.operatorframework.io/project_layout: go.kubebuilder.io/v3 repository: "" - name: fabric-opensource-operator.v1.0.0 + name: fabric-opensource-operator.v1.0.0-9726bb6 namespace: placeholder spec: apiservicedefinitions: {} @@ -1886,4 +1886,4 @@ spec: maturity: alpha provider: name: Opensource - version: 1.0.0 + version: 1.0.0-9726bb6 diff --git a/bundle/manifests/ibp.com_ibpcas.yaml b/bundle/manifests/ibp.com_ibpcas.yaml index 0796f93c..491f6f0e 100644 --- a/bundle/manifests/ibp.com_ibpcas.yaml +++ b/bundle/manifests/ibp.com_ibpcas.yaml @@ -1,20 +1,3 @@ -# -# Copyright contributors to the Hyperledger Fabric Operator project -# -# SPDX-License-Identifier: Apache-2.0 -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at: -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. -# apiVersion: apiextensions.k8s.io/v1 kind: CustomResourceDefinition metadata: diff --git a/bundle/manifests/ibp.com_ibpconsoles.yaml b/bundle/manifests/ibp.com_ibpconsoles.yaml index 5423ea88..76fc9d40 100644 --- a/bundle/manifests/ibp.com_ibpconsoles.yaml +++ b/bundle/manifests/ibp.com_ibpconsoles.yaml @@ -1,20 +1,3 @@ -# -# Copyright contributors to the Hyperledger Fabric Operator project -# -# SPDX-License-Identifier: Apache-2.0 -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at: -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. -# apiVersion: apiextensions.k8s.io/v1 kind: CustomResourceDefinition metadata: diff --git a/bundle/manifests/ibp.com_ibporderers.yaml b/bundle/manifests/ibp.com_ibporderers.yaml index daa06230..ac2c6df4 100644 --- a/bundle/manifests/ibp.com_ibporderers.yaml +++ b/bundle/manifests/ibp.com_ibporderers.yaml @@ -1,20 +1,3 @@ -# -# Copyright contributors to the Hyperledger Fabric Operator project -# -# SPDX-License-Identifier: Apache-2.0 -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at: -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. -# apiVersion: apiextensions.k8s.io/v1 kind: CustomResourceDefinition metadata: diff --git a/bundle/manifests/ibp.com_ibppeers.yaml b/bundle/manifests/ibp.com_ibppeers.yaml index 37a8b968..c9be0c2f 100644 --- a/bundle/manifests/ibp.com_ibppeers.yaml +++ b/bundle/manifests/ibp.com_ibppeers.yaml @@ -1,20 +1,3 @@ -# -# Copyright contributors to the Hyperledger Fabric Operator project -# -# SPDX-License-Identifier: Apache-2.0 -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at: -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. -# apiVersion: apiextensions.k8s.io/v1 kind: CustomResourceDefinition metadata: diff --git a/bundle/metadata/annotations.yaml b/bundle/metadata/annotations.yaml index 5e677aaa..9e837d2b 100644 --- a/bundle/metadata/annotations.yaml +++ b/bundle/metadata/annotations.yaml @@ -5,10 +5,6 @@ annotations: operators.operatorframework.io.bundle.metadata.v1: metadata/ operators.operatorframework.io.bundle.package.v1: fabric-opensource-operator operators.operatorframework.io.bundle.channels.v1: alpha - operators.operatorframework.io.metrics.builder: operator-sdk-v1.19.0+git + operators.operatorframework.io.metrics.builder: operator-sdk-v1.24.1 operators.operatorframework.io.metrics.mediatype.v1: metrics+v1 operators.operatorframework.io.metrics.project_layout: go.kubebuilder.io/v3 - - # Annotations for testing. - operators.operatorframework.io.test.mediatype.v1: scorecard+v1 - operators.operatorframework.io.test.config.v1: tests/scorecard/ diff --git a/config/crd/bases/ibp.com_ibpcas.yaml b/config/crd/bases/ibp.com_ibpcas.yaml index f8850b2f..881c4084 100644 --- a/config/crd/bases/ibp.com_ibpcas.yaml +++ b/config/crd/bases/ibp.com_ibpcas.yaml @@ -1,20 +1,3 @@ -# -# Copyright contributors to the Hyperledger Fabric Operator project -# -# SPDX-License-Identifier: Apache-2.0 -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at: -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. -# --- apiVersion: apiextensions.k8s.io/v1 kind: CustomResourceDefinition diff --git a/config/crd/bases/ibp.com_ibpconsoles.yaml b/config/crd/bases/ibp.com_ibpconsoles.yaml index b7d6f927..f8522339 100644 --- a/config/crd/bases/ibp.com_ibpconsoles.yaml +++ b/config/crd/bases/ibp.com_ibpconsoles.yaml @@ -1,20 +1,3 @@ -# -# Copyright contributors to the Hyperledger Fabric Operator project -# -# SPDX-License-Identifier: Apache-2.0 -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at: -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. -# --- apiVersion: apiextensions.k8s.io/v1 kind: CustomResourceDefinition diff --git a/config/crd/bases/ibp.com_ibporderers.yaml b/config/crd/bases/ibp.com_ibporderers.yaml index 91adf32c..756d9775 100644 --- a/config/crd/bases/ibp.com_ibporderers.yaml +++ b/config/crd/bases/ibp.com_ibporderers.yaml @@ -1,20 +1,3 @@ -# -# Copyright contributors to the Hyperledger Fabric Operator project -# -# SPDX-License-Identifier: Apache-2.0 -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at: -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. -# --- apiVersion: apiextensions.k8s.io/v1 kind: CustomResourceDefinition diff --git a/config/crd/bases/ibp.com_ibppeers.yaml b/config/crd/bases/ibp.com_ibppeers.yaml index 81d441d6..7380666b 100644 --- a/config/crd/bases/ibp.com_ibppeers.yaml +++ b/config/crd/bases/ibp.com_ibppeers.yaml @@ -1,20 +1,3 @@ -# -# Copyright contributors to the Hyperledger Fabric Operator project -# -# SPDX-License-Identifier: Apache-2.0 -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at: -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. -# --- apiVersion: apiextensions.k8s.io/v1 kind: CustomResourceDefinition diff --git a/go.sum b/go.sum index 500a79a7..4649a870 100644 --- a/go.sum +++ b/go.sum @@ -444,7 +444,6 @@ github.com/onsi/ginkgo v1.8.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+W github.com/onsi/ginkgo v1.11.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE= github.com/onsi/ginkgo v1.12.1/go.mod h1:zj2OWP4+oCPe1qIXoGWkgMRwljMUYCdkwsT2108oapk= github.com/onsi/ginkgo v1.16.2/go.mod h1:CObGmKUOKaSC0RjmoAK7tKyn4Azo5P2IWuoMnvwxz1E= -github.com/onsi/ginkgo v1.16.4 h1:29JGrr5oVBm5ulCWet69zQkzWipVXIol6ygQUe/EzNc= github.com/onsi/ginkgo v1.16.4/go.mod h1:dX+/inL/fNMqNlz0e9LfyB9TswhZpCVdJM/Z6Vvnwo0= github.com/onsi/ginkgo v1.16.5 h1:8xi0RTUf59SOSfEtZMvwTvXYMzG4gV23XVHOZiXNtnE= github.com/onsi/ginkgo v1.16.5/go.mod h1:+E8gABHa3K6zRBolWtd+ROzc/U5bkGt0FwiG042wbpU= diff --git a/release_notes/v1.0.0.md b/release_notes/v1.0.0.md new file mode 100644 index 00000000..83346571 --- /dev/null +++ b/release_notes/v1.0.0.md @@ -0,0 +1,21 @@ +v1.0.0-beta +------------------------ + +Release Notes +------------- + +Known Vulnerabilities +--------------------- +none + +Resolved Vulnerabilities +------------------------ +none + +Known Issues & Workarounds +-------------------------- +none + +Change Log +---------- +none diff --git a/release_notes/v1.0.4.md b/release_notes/v1.0.4.md new file mode 100644 index 00000000..be62dc67 --- /dev/null +++ b/release_notes/v1.0.4.md @@ -0,0 +1,21 @@ +v1.0.4 +------------------------ + +Release Notes +------------- + +Known Vulnerabilities +--------------------- +none + +Resolved Vulnerabilities +------------------------ +none + +Known Issues & Workarounds +-------------------------- +none + +Change Log +---------- +none diff --git a/scripts/install-tools.sh b/scripts/install-tools.sh index 8949ef44..ef625853 100755 --- a/scripts/install-tools.sh +++ b/scripts/install-tools.sh @@ -28,14 +28,13 @@ ## getOperatorSDK sudo rm /usr/local/bin/operator-sdk || true -sdkVersion="1.16.0" -sdkName="operator-sdk" +OPERATOR_SDK_VERSION="v1.24.1" +ARCH=$(go env GOARCH) +OS=$(go env GOOS) +URL="https://github.com/operator-framework/operator-sdk/releases/download/${OPERATOR_SDK_VERSION}/operator-sdk_${OS}_${ARCH}" -url="https://github.com/operator-framework/operator-sdk/releases/download/${sdkVersion}/operator-sdk_linux_amd64" -echo "Installing operator-sdk version $sdkVersion with name of $sdkName" -wget --quiet --progress=dot:giga -t 2 -T 60 -O $sdkName $url || true -sudo mkdir -p /usr/local/bin/ -chmod +x $sdkName -./$sdkName version -sudo mv $sdkName /usr/local/bin +echo "Installing operator-sdk version ${OPERATOR_SDK_VERSION} to /usr/local/bin/operator-sdk" +curl -sL $URL > operator-sdk +chmod +x operator-sdk +sudo mv operator-sdk /usr/local/bin operator-sdk version \ No newline at end of file From 0f551ae183a59afb60539077482ceaa3e34426b2 Mon Sep 17 00:00:00 2001 From: Abirdcfly Date: Thu, 10 Nov 2022 14:29:39 +0800 Subject: [PATCH 28/41] chore: remove todo in unit-tests workflow Signed-off-by: Abirdcfly --- .github/workflows/unit-tests.yaml | 10 ++++------ 1 file changed, 4 insertions(+), 6 deletions(-) diff --git a/.github/workflows/unit-tests.yaml b/.github/workflows/unit-tests.yaml index 80c2ed84..aa6ca8ce 100644 --- a/.github/workflows/unit-tests.yaml +++ b/.github/workflows/unit-tests.yaml @@ -19,9 +19,8 @@ name: unit-tests on: - # TODO: uncomment this when moved to hyperledger-labs repo - # push: - # branches: [main] + push: + branches: [main] pull_request: branches: [main] @@ -39,8 +38,7 @@ jobs: go-version: ${{ env.GO_VER }} - name: license header checks run: scripts/check-license.sh - # TODO: run in hyperledger-labs - # - name: gosec - # run: scripts/go-sec.sh + - name: gosec + run: scripts/go-sec.sh - name: run tests run: make test From 8fdea8ef33ee2790bbb803ef9ed0698a8f5d557f Mon Sep 17 00:00:00 2001 From: Abirdcfly Date: Thu, 10 Nov 2022 14:05:33 +0800 Subject: [PATCH 29/41] chore: remove same code in orderer integration test Signed-off-by: Abirdcfly --- integration/orderer/orderer_suite_test.go | 4 ---- 1 file changed, 4 deletions(-) diff --git a/integration/orderer/orderer_suite_test.go b/integration/orderer/orderer_suite_test.go index cc9785a2..3441fbc6 100644 --- a/integration/orderer/orderer_suite_test.go +++ b/integration/orderer/orderer_suite_test.go @@ -88,10 +88,6 @@ var _ = AfterSuite(func() { return } - if strings.ToLower(os.Getenv("SAVE_TEST")) == "true" { - return - } - err := integration.Cleanup(GinkgoWriter, kclient, namespace) Expect(err).NotTo(HaveOccurred()) }) From 441f9d256f5a7d72caee2c2a9a0cc1c26d5ef965 Mon Sep 17 00:00:00 2001 From: Abirdcfly Date: Fri, 11 Nov 2022 10:10:24 +0800 Subject: [PATCH 30/41] chore: remove duplicate err check in pkg/offering Signed-off-by: Abirdcfly --- pkg/offering/k8s/orderer/node.go | 7 ++----- pkg/offering/openshift/orderer/node.go | 7 ++----- 2 files changed, 4 insertions(+), 10 deletions(-) diff --git a/pkg/offering/k8s/orderer/node.go b/pkg/offering/k8s/orderer/node.go index c4d6826a..4ba96769 100644 --- a/pkg/offering/k8s/orderer/node.go +++ b/pkg/offering/k8s/orderer/node.go @@ -201,11 +201,8 @@ func (n *Node) Reconcile(instance *current.IBPOrderer, update baseorderer.Update } if update.MSPUpdated() { - err = n.UpdateMSPCertificates(instance) - if err != nil { - if err != nil { - return common.Result{}, errors.Wrap(err, "failed to update certificates passed in MSP spec") - } + if err = n.UpdateMSPCertificates(instance); err != nil { + return common.Result{}, errors.Wrap(err, "failed to update certificates passed in MSP spec") } } diff --git a/pkg/offering/openshift/orderer/node.go b/pkg/offering/openshift/orderer/node.go index 3e6c9b9b..4be158d9 100644 --- a/pkg/offering/openshift/orderer/node.go +++ b/pkg/offering/openshift/orderer/node.go @@ -201,11 +201,8 @@ func (n *Node) Reconcile(instance *current.IBPOrderer, update baseorderer.Update } if update.MSPUpdated() { - err = n.UpdateMSPCertificates(instance) - if err != nil { - if err != nil { - return common.Result{}, errors.Wrap(err, "failed to update certificates passed in MSP spec") - } + if err = n.UpdateMSPCertificates(instance); err != nil { + return common.Result{}, errors.Wrap(err, "failed to update certificates passed in MSP spec") } } From c6b4df62b932ca9aec050ed7ac55871ef76e9cc3 Mon Sep 17 00:00:00 2001 From: Abirdcfly Date: Wed, 9 Nov 2022 15:38:42 +0800 Subject: [PATCH 31/41] chore: typo ngress -> ingress Signed-off-by: Abirdcfly --- sample-network/scripts/run-e2e-test.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sample-network/scripts/run-e2e-test.sh b/sample-network/scripts/run-e2e-test.sh index fd33f782..cd51ba8f 100755 --- a/sample-network/scripts/run-e2e-test.sh +++ b/sample-network/scripts/run-e2e-test.sh @@ -42,7 +42,7 @@ printenv | sort # Set up a cluster network kind -# Set up ngress and CRDs +# Set up ingress and CRDs network cluster init # Set up a Fabric Network From 2f65e6db15d99d01347d82e4654b3edd70b8c25c Mon Sep 17 00:00:00 2001 From: 0xff-dev Date: Thu, 22 Dec 2022 00:14:57 +0800 Subject: [PATCH 32/41] fix: selector and labels do not match Signed-off-by: 0xff-dev --- config/manager/manager.yaml | 1 + 1 file changed, 1 insertion(+) diff --git a/config/manager/manager.yaml b/config/manager/manager.yaml index e3339f7e..61c2b02d 100644 --- a/config/manager/manager.yaml +++ b/config/manager/manager.yaml @@ -42,6 +42,7 @@ spec: metadata: labels: control-plane: controller-manager + name: controller-manager spec: containers: - command: From e1976de7798002bdc54dd441ca7b94888ed799cd Mon Sep 17 00:00:00 2001 From: Abirdcfly Date: Mon, 2 Jan 2023 21:37:39 +0800 Subject: [PATCH 33/41] fix: occasional gosec failure to get version (#88) gosec install script will auto get latest version(for example:https://github.com/bestchains/fabric-operator/actions/runs/3799271745/jobs/6461638960#step:5:7). Not only is it unnecessary to get latest version, but this request is easily rejected by github, resulting in a `null` version (for example https://github.com/bestchains/fabric-operator/actions/runs/3799115622/jobs/6461341294#step:5:7) and installation failure. Signed-off-by: Abirdcfly --- scripts/go-sec.sh | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/scripts/go-sec.sh b/scripts/go-sec.sh index a7555226..ddcbf549 100755 --- a/scripts/go-sec.sh +++ b/scripts/go-sec.sh @@ -18,10 +18,6 @@ # limitations under the License. # -RELEASE=$(curl -s -H "Accept: application/vnd.github.v3+json" https://api.github.com/repos/securego/gosec/releases/latest | jq -r .tag_name) - -echo "Latest Gosec release determined to be $RELEASE... Installing..." - curl -sfL https://raw.githubusercontent.com/securego/gosec/master/install.sh | sh -s -- -b $(go env GOPATH)/bin $RELEASE -gosec ./... \ No newline at end of file +gosec ./... From 75d34ad57d3f9255b4dcb9c9f3bfcf3fdd083b1f Mon Sep 17 00:00:00 2001 From: Josh Kneubuhl Date: Mon, 2 Jan 2023 07:54:51 -0500 Subject: [PATCH 34/41] Update CA integration test to use localho.st DNS domain Signed-off-by: Josh Kneubuhl --- docs/DEVELOPING.md | 8 +++++--- integration/ca/ca_suite_test.go | 14 +++++++------- integration/integration.go | 2 +- integration/migration/fabric/fabric_suite_test.go | 2 +- 4 files changed, 14 insertions(+), 12 deletions(-) diff --git a/docs/DEVELOPING.md b/docs/DEVELOPING.md index 3937d581..53c82339 100644 --- a/docs/DEVELOPING.md +++ b/docs/DEVELOPING.md @@ -106,7 +106,7 @@ If for some reason you can't seem to mangle an image into KIND, build, tag, and the `localhost:5000` container registry. (Or use Rancher/k3s.) -## What's up with Ingress, vcap.me, and nip.io domains? +## What's up with Ingress, localho.st, vcap.me, and nip.io domains? Fabric Operator uses Kube Ingress to route traffic through a common, DNS wildcard domain (e.g. *.my-network.example.com.) In cloud-native environments, where a DNS wildcard domain resolvers are readily available, it is possible to @@ -115,11 +115,13 @@ map a top-level A record to a single IP address bound to the cluster ingress. Unfortunately it is _exceedingly annoying_ to emulate a top-level A wildcard DNS domain in a way that can be visible to pods running in a Docker network (e.g. KIND) AND to the host OS using the same domain alias and IP. -Two solutions available are: +Alternate solutions available: + +- Use the `*.localho.st` domain alias for your Fabric network, mapping all sub-domains and hosts to 127.0.0.1. - Use the `*.vcap.me` domain alias for your Fabric network, mapping to 127.0.0.1 in all cases. This is convenient for scenarios where pods in the cluster will have no need to traverse the ingress (e.g. in integration testing). - + (Update: vcap.me stopped resolving host names some time in late 2022.) - Use the [Dead simple wildcard DNS for any IP Address](https://nip.io) *.nip.io domain for the cluster, providing full flexibility for the IP address of the ingress port. diff --git a/integration/ca/ca_suite_test.go b/integration/ca/ca_suite_test.go index 0119afc4..673ff0e3 100644 --- a/integration/ca/ca_suite_test.go +++ b/integration/ca/ca_suite_test.go @@ -42,17 +42,17 @@ func TestCa(t *testing.T) { } const ( - // This TLS certificate is encoded for the DNS domain aliases 127.0.0.1, localhost, and *.vcap.me and is good for 5 years: + // This TLS certificate is encoded for the DNS domain aliases 127.0.0.1, localhost, and *.localho.st and is good for 5 years: // - // notAfter: "2027-05-24T03:14:42Z" - // notBefore: "2022-05-25T03:14:42Z" - // renewalTime: "2025-09-22T19:14:42Z" + // Validity + // Not Before: Jan 2 12:37:24 2023 GMT + // Not After : Jan 1 12:37:24 2028 GMT // // This certificate was generated with cert-manager.io using a self-signed issuer for the root CA. // If tests start to fail for TLS handshake errors, the certificate will need to be renewed or reissued. - tlsCert = "LS0tLS1CRUdJTiBDRVJUSUZJQ0FURS0tLS0tCk1JSUJqakNDQVRTZ0F3SUJBZ0lRVXRIS2NUTWNZS21KblVtbEJNZW94REFLQmdncWhrak9QUVFEQWpBbE1TTXcKSVFZRFZRUURFeHBtWVdKeWFXTXRZMkV0YVc1MFpXZHlZWFJwYjI0dGRHVnpkREFlRncweU1qQTFNalV3TXpFMApORGRhRncweU56QTFNalF3TXpFME5EZGFNQUF3V1RBVEJnY3Foa2pPUFFJQkJnZ3Foa2pPUFFNQkJ3TkNBQVRwCjN2d3RMZFlyUzFTNVFSUmFqRjJReHFIYWllMUo2dzlHM2RwQklLYWwwTTlYaUttR0Q4eFBvRkpkcENNZTZWdDIKeml1UjZrU2FNL3lXQmU4TGd5eExvMnN3YVRBT0JnTlZIUThCQWY4RUJBTUNCYUF3REFZRFZSMFRBUUgvQkFJdwpBREFmQmdOVkhTTUVHREFXZ0JRdkVBWWdjZEwwa0ljWEtDaGVmVzg3NW8vYnd6QW9CZ05WSFJFQkFmOEVIakFjCmdnbHNiMk5oYkdodmMzU0NDU291ZG1OaGNDNXRaWWNFZndBQUFUQUtCZ2dxaGtqT1BRUURBZ05JQURCRkFpQXUKMEpLY29lQmhYajJnbmQ1cjE5THUxeEVwdG1kelFoazh5OXFTRkZ2dkF3SWhBSWp5Z1VLY2tzQkk4a1dBeVNlbQp0VzJ4cVE3RVZkTmR6WDZYbWwrNVBQengKLS0tLS1FTkQgQ0VSVElGSUNBVEUtLS0tLQo=" - tlsKey = "LS0tLS1CRUdJTiBFQyBQUklWQVRFIEtFWS0tLS0tCk1IY0NBUUVFSUhoWWFRbDViYXZVR3FJd2prK3YrODNmYzNIamZuRVdueEFQbjJ5OFRTUWRvQW9HQ0NxR1NNNDkKQXdFSG9VUURRZ0FFNmQ3OExTM1dLMHRVdVVFVVdveGRrTWFoMm9udFNlc1BSdDNhUVNDbXBkRFBWNGlwaGcvTQpUNkJTWGFRakh1bGJkczRya2VwRW1qUDhsZ1h2QzRNc1N3PT0KLS0tLS1FTkQgRUMgUFJJVkFURSBLRVktLS0tLQo=" - trustedRootTLSCert = "LS0tLS1CRUdJTiBDRVJUSUZJQ0FURS0tLS0tCk1JSUJpekNDQVRDZ0F3SUJBZ0lRZXZWM2VUZmh3WlNHYVI4aXhTR1hRakFLQmdncWhrak9QUVFEQWpBbE1TTXcKSVFZRFZRUURFeHBtWVdKeWFXTXRZMkV0YVc1MFpXZHlZWFJwYjI0dGRHVnpkREFlRncweU1qQTFNalV3TXpFMApOREphRncweU56QTFNalF3TXpFME5ESmFNQ1V4SXpBaEJnTlZCQU1UR21aaFluSnBZeTFqWVMxcGJuUmxaM0poCmRHbHZiaTEwWlhOME1Ga3dFd1lIS29aSXpqMENBUVlJS29aSXpqMERBUWNEUWdBRXlzc2d3dFo2dlI3a2svbUsKYUFUZE45TEhmTWsrYXMxcm8rM24za1N2QTFuVEFCa1V6bVdGNlhCS1I5eUh6V3dwZTlHL0o3L3MrenZsME5GOApRZGdzenFOQ01FQXdEZ1lEVlIwUEFRSC9CQVFEQWdLa01BOEdBMVVkRXdFQi93UUZNQU1CQWY4d0hRWURWUjBPCkJCWUVGQzhRQmlCeDB2U1FoeGNvS0Y1OWJ6dm1qOXZETUFvR0NDcUdTTTQ5QkFNQ0Ewa0FNRVlDSVFEaXo1SnoKeGhKcjQ4SlpRRkpzd1dteTRCU21FWXp0NXFmUmsyMFhyRzI4M3dJaEFLaDBXMmkxcFpiY0lPODBXSmhlVkxzSQpDM0JGMk5McTBsVlhXanNGQVVndQotLS0tLUVORCBDRVJUSUZJQ0FURS0tLS0tCg==" + tlsCert = "LS0tLS1CRUdJTiBDRVJUSUZJQ0FURS0tLS0tCk1JSURzRENDQXBpZ0F3SUJBZ0lSQVBuR09XY1NyL3ZLdVlIaW43VUFZbG93RFFZSktvWklodmNOQVFFTEJRQXcKYXpFMU1ETUdBMVVFQ2hNc1NXNTBaWEp1WVhScGIyNWhiQ0JDZFhOcGJtVnpjeUJOWVdOb2FXNWxjeUJKYm1OdgpjbkJ2Y21GMFpXUXhNakF3QmdOVkJBTU1LU291Ykc5allXeG9ieTV6ZENCcGJuUmxaM0poZEdsdmJpQjBaWE4wCklHTmxjblJwWm1sallYUmxNQjRYRFRJek1ERXdNakV5TXpjeU5Gb1hEVEk0TURFd01URXlNemN5TkZvd2F6RTEKTURNR0ExVUVDaE1zU1c1MFpYSnVZWFJwYjI1aGJDQkNkWE5wYm1WemN5Qk5ZV05vYVc1bGN5QkpibU52Y25CdgpjbUYwWldReE1qQXdCZ05WQkFNTUtTb3ViRzlqWVd4b2J5NXpkQ0JwYm5SbFozSmhkR2x2YmlCMFpYTjBJR05sCmNuUnBabWxqWVhSbE1JSUJJakFOQmdrcWhraUc5dzBCQVFFRkFBT0NBUThBTUlJQkNnS0NBUUVBMDRwbTl1WWYKT0g2SFRTWUk4WW5XSGJZb2xWcDdhL0lKVnYvNDR5Wm5YZFJLNXJwZys2TG5TazBBS1p2OHRpa0JrZXZRRTVzWApKYzVtYldhZjFtYmhvbVY0U2RObzRuNkw4aUdTWERjR3FocTBLWUJ2ZjFrOUJ6SGZxKzQ0OEQxaG1nL0ZkTlQwCmFJWUN3akNhZytWT0Jtcm9rY1pjSXFWT3VHL1NTWXd0Q3FiRU1YeExkczUrd0U2NnNYeWx5Si82MGZ5aThOdFoKaDdwcXNvTU9WS0Zla2FwWHFIWXgzTTlVd3ZjUWszYkEyUFZkUXZsZ0RBc3VIZWpqb0xBU0pEN1YrclZ6NVRIMgpsZUhxYzR1cVlScmkvT2o2UzlaVUFHc1AvTnRtMjc3eld2OWlCTkxlR1padkZ6SlQ3Tm5udmpDeGR5YmppUmtVCmp2OFVVTDdxOE82T1h3SURBUUFCbzA4d1RUQVRCZ05WSFNVRUREQUtCZ2dyQmdFRkJRY0RBVEFNQmdOVkhSTUIKQWY4RUFqQUFNQ2dHQTFVZEVRUWhNQitDQ1d4dlkyRnNhRzl6ZElJTUtpNXNiMk5oYkdodkxuTjBod1IvQUFBQgpNQTBHQ1NxR1NJYjNEUUVCQ3dVQUE0SUJBUUM1bDJ6UzY0K3RBYmprVU05MkxFNC82dDdtTHlRNkVqSWxWTHBjCk53WXVlOU9LbHdLU0xGajFlaTdLVW0yRVFWNVpzdmhMejZXTGZndWtsd0NlSWVsMGNxM3RiSEJ1VFFnR0N3QkEKb0VVUjB3Nm82NFp6dmhNWWRRWENzVkJGYjNXWkdTeURnMFZ1b0NZdkJRQ1IxTmFOU2Z5UlF5bXZGSWtBTHJ3bgoxbmNPNnNOVVBaKzRUSW5UYnRTRWY3QUU2eXF3T0F3VXVIcW81amk3bFpuaVhDdW5oM1h4WGhoK29xT01URjZwCmFoNzI1cmdCNWdhbldyL3JmS2RkZUdrc2xTUlVDY2tXTWVEYXJETllRRXFJd1N0enorZC9OS1ZuZUtKaERtMjAKWFRBTUFhNGRQcmhrK1ZMZitwcEZjZVlMa0hYcE1YdjMxV3pRWWN6VHV3QnorUklRCi0tLS0tRU5EIENFUlRJRklDQVRFLS0tLS0K" + tlsKey = "LS0tLS1CRUdJTiBSU0EgUFJJVkFURSBLRVktLS0tLQpNSUlFcFFJQkFBS0NBUUVBMDRwbTl1WWZPSDZIVFNZSThZbldIYllvbFZwN2EvSUpWdi80NHlablhkUks1cnBnCis2TG5TazBBS1p2OHRpa0JrZXZRRTVzWEpjNW1iV2FmMW1iaG9tVjRTZE5vNG42TDhpR1NYRGNHcWhxMEtZQnYKZjFrOUJ6SGZxKzQ0OEQxaG1nL0ZkTlQwYUlZQ3dqQ2FnK1ZPQm1yb2tjWmNJcVZPdUcvU1NZd3RDcWJFTVh4TApkczUrd0U2NnNYeWx5Si82MGZ5aThOdFpoN3Bxc29NT1ZLRmVrYXBYcUhZeDNNOVV3dmNRazNiQTJQVmRRdmxnCkRBc3VIZWpqb0xBU0pEN1YrclZ6NVRIMmxlSHFjNHVxWVJyaS9PajZTOVpVQUdzUC9OdG0yNzd6V3Y5aUJOTGUKR1padkZ6SlQ3Tm5udmpDeGR5YmppUmtVanY4VVVMN3E4TzZPWHdJREFRQUJBb0lCQVFDdktwL3dPc1lIaGQ2TAo1NzdvSTNjRnkxejNyNkViMWFRZVFuL1p1R2RIcnc4RzE3YVBLR25WZ01WdHJ4a256ZlRhM0NYRTFsdm9sbTBDCmtrUXd5YWgxVFFpNk9URlV1KzB1WnRaSFBkbHE2Z25kZzlqUDN4bEY1K3FLK0F4MkFwM2JjTXZVM3JJMEN5UWwKb1JHUnZrTkoxU1VYOE9WQ1d4aEFhWGY4SnZMMUtYa3ZGMjF1ZEZ3VnlmVmhJTk9NT2NyeUNkdERwb0NRd3FlcQoxUTJGeTlvdjZMVVArRXZzdzgwaUVVTDMrVVBmcEVLV1Z6SG9DYXpGRHpwOUNBRFBwbGJ4amd4LzBhWDFhbkIrCnh3M0RmbElNQUdNaUxuWUs2TmIzR2JNOWhLRjJrUVAyUkJEQ3JxVE9LMEJVQ0ttVW1qQ0NnRjY5a3VUWE94b3QKU0RLSWRaekJBb0dCQU9MdldKeTkwSTViNHNEVHRxQjZoRVJiajgwOTlYUlVCd3plR2ZRRlUrRndUOForMlVJZApQc09BQjlJQXFxaFVrbVd4RkJUYkZvWTZsM09pc28wTUU2anJ4bkI5WFZiNlZYNkFJRzl3ZGIyKzUrTHVpTjY5ClgwMTJ0cTVTUWt3bWNlSGtHRUxvaE5ER3dtK0tUZmhTcWdTMmhmSDdCdkdyMGlROGFMSlg3bkU1QW9HQkFPNmkKVURzQjBhMnlycHVHSnlOTloxMGQvKzhOVkpBV0FRZlYwb1lpYk1zR0lXMFpuOUx5M3lZd0tzcUZkSjVMMm41Zwovek03RnluNm55bU5RTlpBd3JRSDhvTm4vWUZBVlJaOGFZZUpsSnZUTEhBcmt3d0tSZ0FteGxnb0FqY0g3eGw3CmJ3QmY5ajNRRE13dDBqSnJRMU15QjNSbmpRVlBKV0lwV0pTam1yUlhBb0dCQUxPK3lsd1VDSTNKZjlnbG1PQ1IKU2hSdXhYN1dWWVZYVE9KSFJSMC8zd21RRU0vekJ4aFQyN096dy8zMUl6Y0REWlhZWlVTRHA5cVhyQUFlWFBoVgpHWGxSanJMb3lUYXNQMjFjQk5UZnFaS3FGRGR0b2lGeXMzckN6YjFUVUVuS3BhYzdLSEJPaFd4c0VmT1JBMkx0Cjd0YWV6NGN6d25OSEdjSXp5dVYvdWxBWkFvR0JBSzdYQzdPQURMR1lOaWhLN1VnSFFWRlBWcUkrZ1JPa201S3oKRGpFcTdjeitxK1QwbmszL2xwR3pQdGJ0V3RsVU9EemFNb0RGclo0Yk94eEZteGlma0VnNWZtemE5emtJK282awpEdW00V3NLa3dXMVo3NzRsbE00dG1xc2lmU1QyMGk4NGFjYTdpSDRYZmhqbkJaZmRVUkdXbVRHbllRSmZ6OE1SCkNnNjFvL2EzQW9HQVJyR1pLUzRXcWtKazlZa3BsNmxxMlZOeXA5bVNQQS80dWFTcFhTdWR6RzhoeHFvSm5RSFIKV1E5VWUvSGY5Mm5Hd284RXkwZURzTXJrU0xNOVQvajV0QkpQbUZicHhwandGbjhFYkhjUmNsZkhZOFNkQ0k1TApHeDhrM1MxZ3VWRW9QYmo2YnVyOFRwSFdyVjFtR2lDOENqTXh5bi93V2dXcjNpSG9jV1VSaElNPQotLS0tLUVORCBSU0EgUFJJVkFURSBLRVktLS0tLQo=" + trustedRootTLSCert = "LS0tLS1CRUdJTiBDRVJUSUZJQ0FURS0tLS0tCk1JSURzRENDQXBpZ0F3SUJBZ0lSQVBuR09XY1NyL3ZLdVlIaW43VUFZbG93RFFZSktvWklodmNOQVFFTEJRQXcKYXpFMU1ETUdBMVVFQ2hNc1NXNTBaWEp1WVhScGIyNWhiQ0JDZFhOcGJtVnpjeUJOWVdOb2FXNWxjeUJKYm1OdgpjbkJ2Y21GMFpXUXhNakF3QmdOVkJBTU1LU291Ykc5allXeG9ieTV6ZENCcGJuUmxaM0poZEdsdmJpQjBaWE4wCklHTmxjblJwWm1sallYUmxNQjRYRFRJek1ERXdNakV5TXpjeU5Gb1hEVEk0TURFd01URXlNemN5TkZvd2F6RTEKTURNR0ExVUVDaE1zU1c1MFpYSnVZWFJwYjI1aGJDQkNkWE5wYm1WemN5Qk5ZV05vYVc1bGN5QkpibU52Y25CdgpjbUYwWldReE1qQXdCZ05WQkFNTUtTb3ViRzlqWVd4b2J5NXpkQ0JwYm5SbFozSmhkR2x2YmlCMFpYTjBJR05sCmNuUnBabWxqWVhSbE1JSUJJakFOQmdrcWhraUc5dzBCQVFFRkFBT0NBUThBTUlJQkNnS0NBUUVBMDRwbTl1WWYKT0g2SFRTWUk4WW5XSGJZb2xWcDdhL0lKVnYvNDR5Wm5YZFJLNXJwZys2TG5TazBBS1p2OHRpa0JrZXZRRTVzWApKYzVtYldhZjFtYmhvbVY0U2RObzRuNkw4aUdTWERjR3FocTBLWUJ2ZjFrOUJ6SGZxKzQ0OEQxaG1nL0ZkTlQwCmFJWUN3akNhZytWT0Jtcm9rY1pjSXFWT3VHL1NTWXd0Q3FiRU1YeExkczUrd0U2NnNYeWx5Si82MGZ5aThOdFoKaDdwcXNvTU9WS0Zla2FwWHFIWXgzTTlVd3ZjUWszYkEyUFZkUXZsZ0RBc3VIZWpqb0xBU0pEN1YrclZ6NVRIMgpsZUhxYzR1cVlScmkvT2o2UzlaVUFHc1AvTnRtMjc3eld2OWlCTkxlR1padkZ6SlQ3Tm5udmpDeGR5YmppUmtVCmp2OFVVTDdxOE82T1h3SURBUUFCbzA4d1RUQVRCZ05WSFNVRUREQUtCZ2dyQmdFRkJRY0RBVEFNQmdOVkhSTUIKQWY4RUFqQUFNQ2dHQTFVZEVRUWhNQitDQ1d4dlkyRnNhRzl6ZElJTUtpNXNiMk5oYkdodkxuTjBod1IvQUFBQgpNQTBHQ1NxR1NJYjNEUUVCQ3dVQUE0SUJBUUM1bDJ6UzY0K3RBYmprVU05MkxFNC82dDdtTHlRNkVqSWxWTHBjCk53WXVlOU9LbHdLU0xGajFlaTdLVW0yRVFWNVpzdmhMejZXTGZndWtsd0NlSWVsMGNxM3RiSEJ1VFFnR0N3QkEKb0VVUjB3Nm82NFp6dmhNWWRRWENzVkJGYjNXWkdTeURnMFZ1b0NZdkJRQ1IxTmFOU2Z5UlF5bXZGSWtBTHJ3bgoxbmNPNnNOVVBaKzRUSW5UYnRTRWY3QUU2eXF3T0F3VXVIcW81amk3bFpuaVhDdW5oM1h4WGhoK29xT01URjZwCmFoNzI1cmdCNWdhbldyL3JmS2RkZUdrc2xTUlVDY2tXTWVEYXJETllRRXFJd1N0enorZC9OS1ZuZUtKaERtMjAKWFRBTUFhNGRQcmhrK1ZMZitwcEZjZVlMa0hYcE1YdjMxV3pRWWN6VHV3QnorUklRCi0tLS0tRU5EIENFUlRJRklDQVRFLS0tLS0K" ) var ( diff --git a/integration/integration.go b/integration/integration.go index 2e45ba50..883aaa0f 100644 --- a/integration/integration.go +++ b/integration/integration.go @@ -48,7 +48,7 @@ import ( ) const ( - TestAutomation1IngressDomain = "vcap.me" + TestAutomation1IngressDomain = "localho.st" ) var ( diff --git a/integration/migration/fabric/fabric_suite_test.go b/integration/migration/fabric/fabric_suite_test.go index ccd13529..a23ec7b9 100644 --- a/integration/migration/fabric/fabric_suite_test.go +++ b/integration/migration/fabric/fabric_suite_test.go @@ -56,7 +56,7 @@ const ( defaultConsoleDef = "../../../definitions/console" FabricBinaryVersion = "2.2.3" FabricCABinaryVersion = "1.5.1" - domain = "vcap.me" + domain = "localho.st" ) var ( From e6f0acc4abfc5da0dacf8dc204177daf2466ee61 Mon Sep 17 00:00:00 2001 From: jkneubuh <86427252+jkneubuh@users.noreply.github.com> Date: Fri, 6 Jan 2023 08:48:06 -0500 Subject: [PATCH 35/41] Add support for CA Idemix config override stanza (#92) --- pkg/apis/ca/v1/ca.go | 13 +++++++++++++ release_notes/v1.0.4-2.md | 25 +++++++++++++++++++++++++ 2 files changed, 38 insertions(+) create mode 100644 release_notes/v1.0.4-2.md diff --git a/pkg/apis/ca/v1/ca.go b/pkg/apis/ca/v1/ca.go index 1e70fc6a..7c5ff128 100644 --- a/pkg/apis/ca/v1/ca.go +++ b/pkg/apis/ca/v1/ca.go @@ -88,6 +88,7 @@ type CAConfig struct { CSP *BCCSP `json:"bccsp,omitempty"` Intermediate IntermediateCA `json:"intermediate,omitempty"` CRL CRLConfig `json:"crl,omitempty"` + Idemix IdemixConfig `json:"idemix,omitempty"` // Optional client config for an intermediate server which acts as a client // of the root (or parent) server @@ -343,6 +344,18 @@ type CRLConfig struct { Expiry commonapi.Duration `json:"expiry,omitempty"` } +// IdemixConfig encapsulates Idemix related the configuration options +type IdemixConfig struct { + Curve string `json:"curve,omitempty"` + IssuerPublicKeyfile string `json:"issuerpublickeyfile,omitempty"` + IssuerSecretKeyfile string `json:"issuersecretkeyfile,omitempty"` + RevocationPublicKeyfile string `json:"revocationpublickeyfile,omitempty"` + RevocationPrivateKeyfile string `json:"revocationprivatekeyfile,omitempty"` + RHPoolSize int `json:"rhpoolsize,omitempty"` + NonceExpiration string `json:"nonceexpiration,omitempty"` + NonceSweepInterval string `json:"noncesweepinterval,omitempty"` +} + // Options contains configuration for the operations system type Options struct { ListenAddress string `json:"listenaddress,omitempty"` diff --git a/release_notes/v1.0.4-2.md b/release_notes/v1.0.4-2.md new file mode 100644 index 00000000..3c42a197 --- /dev/null +++ b/release_notes/v1.0.4-2.md @@ -0,0 +1,25 @@ +v1.0.4-2 Release notes - Jan 5, 2023 +------------------------ + +Release Notes +------------- + +v1.0.4-2 is a patch release, providing updates for the following issues in the operator: + +- Adds support for [Idemix config](https://github.com/hyperledger/fabric-ca/blob/main/lib/server/idemix/config.go#L29) overrides in CA CRD spec.configoverride + +Known Vulnerabilities +--------------------- +none + +Resolved Vulnerabilities +------------------------ +none + +Known Issues & Workarounds +-------------------------- +none + +Change Log +---------- +none From e3e9790d4d343fd0aa877c4e44eb34e5afc28803 Mon Sep 17 00:00:00 2001 From: Ratnakar Date: Tue, 14 Feb 2023 11:48:07 -0500 Subject: [PATCH 36/41] Fixing gosec issues (#98) Signed-off-by: asararatnakar Signed-off-by: asararatnakar --- .github/workflows/unit-tests.yaml | 2 +- Makefile | 4 ++++ pkg/util/util.go | 6 +++++- 3 files changed, 10 insertions(+), 2 deletions(-) diff --git a/.github/workflows/unit-tests.yaml b/.github/workflows/unit-tests.yaml index aa6ca8ce..4a06520d 100644 --- a/.github/workflows/unit-tests.yaml +++ b/.github/workflows/unit-tests.yaml @@ -39,6 +39,6 @@ jobs: - name: license header checks run: scripts/check-license.sh - name: gosec - run: scripts/go-sec.sh + run: make go-sec - name: run tests run: make test diff --git a/Makefile b/Makefile index 26df3734..39f8c3fd 100644 --- a/Makefile +++ b/Makefile @@ -139,6 +139,10 @@ fmt: vet: @scripts/checks.sh +# Run go sec against code +go-sec: + @scripts/go-sec.sh + # Generate code generate: controller-gen $(CONTROLLER_GEN) object:headerFile="boilerplate/boilerplate.go.txt" paths="./..." diff --git a/pkg/util/util.go b/pkg/util/util.go index f5671b0d..a43443cd 100644 --- a/pkg/util/util.go +++ b/pkg/util/util.go @@ -838,7 +838,11 @@ func IsTCPReachable(url string) bool { return false } - defer conn.Close() + defer func() { + if err := conn.Close(); err != nil { + return + } + }() return true } From 8390864fffedd9c84e04290d1c95439d9762bc28 Mon Sep 17 00:00:00 2001 From: asararatnakar Date: Tue, 14 Feb 2023 10:46:15 -0500 Subject: [PATCH 37/41] Updating maintainers list to add and remove mainatiners Signed-off-by: asararatnakar --- MAINTAINERS.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/MAINTAINERS.md b/MAINTAINERS.md index 5ac8896f..6b0d9d02 100644 --- a/MAINTAINERS.md +++ b/MAINTAINERS.md @@ -6,4 +6,4 @@ |-------------------|-----------|----------------| | Josh Kneubuhl | [@jkneubuh](https://github.com/jkneubuh) | jkneubuhl#5919 | | Ratnakar Asara | [@asararatnakar](https://github.com/asararatnakar) | ratnakar#3494 | -| David Enyeart | [@denyeart](https://github.com/denyeart) | denyeart#0989 | +| Shoaeb Jindani | [@shoaebjindani](https://github.com/shoaebjindani) | shoaebmjindani#9890 | From cc26bdb71599428a2879b40274376dde37f341a5 Mon Sep 17 00:00:00 2001 From: Josh Kneubuhl Date: Fri, 10 Feb 2023 05:40:00 -0500 Subject: [PATCH 38/41] Move hyperledgendary sample to fabric-operator Signed-off-by: Josh Kneubuhl --- README.md | 4 +- sample-network-multi-org/LICENSE | 201 +++++ sample-network-multi-org/README.md | 198 +++++ .../channel-config/.gitignore | 3 + .../channel-config/README.md | 16 + .../channel-config/config/configtx.yaml | 428 ++++++++++ .../channel-config/config/core.yaml | 775 +++++++++++++++++ .../channel-config/create_genesis_block.sh | 46 + sample-network-multi-org/cloud-config.yaml | 61 ++ sample-network-multi-org/config/configtx.yaml | 640 ++++++++++++++ sample-network-multi-org/config/core.yaml | 800 ++++++++++++++++++ sample-network-multi-org/config/orderer.yaml | 427 ++++++++++ sample-network-multi-org/justfile | 189 +++++ .../kind/cert-manager/.gitignore | 1 + .../kind/cert-manager/ca-issuer-secret.yaml | 22 + .../kind/cert-manager/ca-issuer.yaml | 34 + .../kind/cert-manager/kustomization.yaml | 11 + .../kind/cert-manager/root-tls-issuer.yaml | 7 + .../kind/nginx/ingress-nginx-controller.yaml | 39 + .../kind/nginx/kustomization.yaml | 26 + .../kind/operator/kustomization.yaml | 27 + .../kind/operator/operator-clusterrole.yaml | 205 +++++ .../operator/operator-clusterrolebinding.yaml | 42 + .../kind/operator/operator-manager.yaml | 66 ++ .../kind/operator/operator-psp.yaml | 48 ++ .../operator/operator-serviceaccount.yaml | 22 + .../organizations/.gitignore | 3 + .../organizations/org0/enroll.sh | 44 + .../organizations/org0/export_msp.sh | 46 + .../organizations/org0/join_channel.sh | 54 ++ .../organizations/org0/org0-ca.yaml | 135 +++ .../organizations/org0/org0-orderer.yaml | 151 ++++ .../organizations/org0/start.sh | 55 ++ .../organizations/org1/enroll.sh | 53 ++ .../organizations/org1/export_msp.sh | 37 + .../organizations/org1/install_chaincode.sh | 89 ++ .../organizations/org1/join_channel.sh | 39 + .../organizations/org1/org1-ca.yaml | 115 +++ .../organizations/org1/org1-peer-gateway.yaml | 59 ++ .../organizations/org1/org1-peer1.yaml | 103 +++ .../organizations/org1/org1-peer2.yaml | 103 +++ .../organizations/org1/start.sh | 65 ++ .../organizations/org2/enroll.sh | 53 ++ .../organizations/org2/export_msp.sh | 37 + .../organizations/org2/install_chaincode.sh | 89 ++ .../organizations/org2/join_channel.sh | 39 + .../organizations/org2/org2-ca.yaml | 113 +++ .../organizations/org2/org2-peer-gateway.yaml | 59 ++ .../organizations/org2/org2-peer1.yaml | 103 +++ .../organizations/org2/org2-peer2.yaml | 103 +++ .../organizations/org2/start.sh | 63 ++ .../scripts/check-kube.sh | 49 ++ .../scripts/check-network.sh | 130 +++ sample-network-multi-org/scripts/check.sh | 131 +++ .../scripts/kind_with_nginx.sh | 220 +++++ .../scripts/start_operator.sh | 19 + sample-network-multi-org/scripts/test-e2e.sh | 124 +++ sample-network-multi-org/scripts/utils.sh | 158 ++++ 58 files changed, 6977 insertions(+), 2 deletions(-) create mode 100644 sample-network-multi-org/LICENSE create mode 100644 sample-network-multi-org/README.md create mode 100644 sample-network-multi-org/channel-config/.gitignore create mode 100644 sample-network-multi-org/channel-config/README.md create mode 100644 sample-network-multi-org/channel-config/config/configtx.yaml create mode 100644 sample-network-multi-org/channel-config/config/core.yaml create mode 100755 sample-network-multi-org/channel-config/create_genesis_block.sh create mode 100644 sample-network-multi-org/cloud-config.yaml create mode 100644 sample-network-multi-org/config/configtx.yaml create mode 100644 sample-network-multi-org/config/core.yaml create mode 100644 sample-network-multi-org/config/orderer.yaml create mode 100644 sample-network-multi-org/justfile create mode 100644 sample-network-multi-org/kind/cert-manager/.gitignore create mode 100644 sample-network-multi-org/kind/cert-manager/ca-issuer-secret.yaml create mode 100644 sample-network-multi-org/kind/cert-manager/ca-issuer.yaml create mode 100644 sample-network-multi-org/kind/cert-manager/kustomization.yaml create mode 100644 sample-network-multi-org/kind/cert-manager/root-tls-issuer.yaml create mode 100644 sample-network-multi-org/kind/nginx/ingress-nginx-controller.yaml create mode 100644 sample-network-multi-org/kind/nginx/kustomization.yaml create mode 100644 sample-network-multi-org/kind/operator/kustomization.yaml create mode 100644 sample-network-multi-org/kind/operator/operator-clusterrole.yaml create mode 100644 sample-network-multi-org/kind/operator/operator-clusterrolebinding.yaml create mode 100644 sample-network-multi-org/kind/operator/operator-manager.yaml create mode 100644 sample-network-multi-org/kind/operator/operator-psp.yaml create mode 100644 sample-network-multi-org/kind/operator/operator-serviceaccount.yaml create mode 100644 sample-network-multi-org/organizations/.gitignore create mode 100755 sample-network-multi-org/organizations/org0/enroll.sh create mode 100755 sample-network-multi-org/organizations/org0/export_msp.sh create mode 100755 sample-network-multi-org/organizations/org0/join_channel.sh create mode 100644 sample-network-multi-org/organizations/org0/org0-ca.yaml create mode 100644 sample-network-multi-org/organizations/org0/org0-orderer.yaml create mode 100755 sample-network-multi-org/organizations/org0/start.sh create mode 100755 sample-network-multi-org/organizations/org1/enroll.sh create mode 100755 sample-network-multi-org/organizations/org1/export_msp.sh create mode 100755 sample-network-multi-org/organizations/org1/install_chaincode.sh create mode 100755 sample-network-multi-org/organizations/org1/join_channel.sh create mode 100644 sample-network-multi-org/organizations/org1/org1-ca.yaml create mode 100644 sample-network-multi-org/organizations/org1/org1-peer-gateway.yaml create mode 100644 sample-network-multi-org/organizations/org1/org1-peer1.yaml create mode 100644 sample-network-multi-org/organizations/org1/org1-peer2.yaml create mode 100755 sample-network-multi-org/organizations/org1/start.sh create mode 100755 sample-network-multi-org/organizations/org2/enroll.sh create mode 100755 sample-network-multi-org/organizations/org2/export_msp.sh create mode 100755 sample-network-multi-org/organizations/org2/install_chaincode.sh create mode 100755 sample-network-multi-org/organizations/org2/join_channel.sh create mode 100644 sample-network-multi-org/organizations/org2/org2-ca.yaml create mode 100644 sample-network-multi-org/organizations/org2/org2-peer-gateway.yaml create mode 100644 sample-network-multi-org/organizations/org2/org2-peer1.yaml create mode 100644 sample-network-multi-org/organizations/org2/org2-peer2.yaml create mode 100755 sample-network-multi-org/organizations/org2/start.sh create mode 100755 sample-network-multi-org/scripts/check-kube.sh create mode 100755 sample-network-multi-org/scripts/check-network.sh create mode 100755 sample-network-multi-org/scripts/check.sh create mode 100755 sample-network-multi-org/scripts/kind_with_nginx.sh create mode 100755 sample-network-multi-org/scripts/start_operator.sh create mode 100755 sample-network-multi-org/scripts/test-e2e.sh create mode 100755 sample-network-multi-org/scripts/utils.sh diff --git a/README.md b/README.md index 3f5ab833..3ea04a90 100644 --- a/README.md +++ b/README.md @@ -31,7 +31,7 @@ _Fabric, Ahoy!_ - [x] It configures Fabric networks with native Fabric CLI binaries - [x] It configures Fabric networks with CI/CD and git-ops best-practices - [x] It deploys _Chaincode Now!!!_ (integrated `ccaas` and `k8s` external builders) -- [x] It detects expiring and expired x509 certificates +- [x] It detects and automatically re-enrolls TLS certificates - [x] It will provide migration and future LTS revision support - [x] It manages hybrid cloud, multi-org, and multi-cluster Fabric networks - [x] It runs on pure containerd _and_ mobyd (no dependencies on Docker/DIND) @@ -48,7 +48,6 @@ _Fabric, Ahoy!_ - [x] Metrics and observability with [Prometheus and Grafana](./docs/prometheus.md) - [ ] Operational management: Log aggregation, monitoring, alerting - [ ] Modular CAs (Fabric CA, cert-manager.io, Vault, letsencrypt, ...) -- [ ] Automatic x509 certificate renewal - [ ] Backup / Recovery / Upgrade - [ ] Idemixer, Token SDK, BFT Orderer - [ ] Layer II blockchain integration (Cactus, Weaver, Token SDK, ...) @@ -57,6 +56,7 @@ _Fabric, Ahoy!_ ## Build a Fabric Network +- Build a [multi-org](sample-network-multi-org) network on a local KIND development cluster. - Build a [sample-network](sample-network) with Kube APIs. - [Build a Network](https://cloud.ibm.com/docs/blockchain?topic=blockchain-ibp-console-build-network) with the [Fabric Operations Console](https://github.com/hyperledger-labs/fabric-operations-console). - Automate your network with [Ansible Playbooks](https://cloud.ibm.com/docs/blockchain?topic=blockchain-ansible) and the Console REST APIs. diff --git a/sample-network-multi-org/LICENSE b/sample-network-multi-org/LICENSE new file mode 100644 index 00000000..261eeb9e --- /dev/null +++ b/sample-network-multi-org/LICENSE @@ -0,0 +1,201 @@ + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS + + APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "[]" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + + Copyright [yyyy] [name of copyright owner] + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. diff --git a/sample-network-multi-org/README.md b/sample-network-multi-org/README.md new file mode 100644 index 00000000..537b9f0b --- /dev/null +++ b/sample-network-multi-org/README.md @@ -0,0 +1,198 @@ +# Hyperledger Fabric Kubernetes Test Network + +Create a +Hyperledger Fabric [test-network](https://github.com/hyperledger/fabric-samples/tree/main/test-network) +on [KIND](https://kind.sigs.k8s.io) +with [fabric-operator](https://github.com/hyperledger-labs/fabric-operator). + +Objective: provide _crystal clarity_ to Fabric's _MSP_ and certificate structures, +focusing on the inductive construction of a multi-organization network. + +![Dark Side of the Moon](https://upload.wikimedia.org/wikipedia/en/3/3b/Dark_Side_of_the_Moon.png) +###### The Dark Side of the Moon - Pink Floyd ([From Wikipedia, the free encyclopedia](https://en.wikipedia.org/wiki/File:Dark_Side_of_the_Moon.png) ) + + +## The Venue: + +To run this sample locally, clone the git repo and follow the dependency checklist: +```shell +./scripts/check.sh +``` + +This scenario is _slow_ but _predictable_. The focus in this example is not efficiency, but to +demonstrate the construction of a multi-org network, highlighting a production-realistic scenario +of running a Fabric network spanning multiple Kubernetes clusters, namespaces, or cloud-vendors. + +In typical examples of constructing a fabric test network, the use of `cryptogen` is highlighted as +an efficient and convenient mechanism to avoid complexities of CA bootstrap, node enrollments, and +the exchange of consortium MSP certificates as part of the channel configuration. + +By contrast, this scenario sets up a multi-org Fabric network, illustrating a _correct_ ordering of +CA initialization, node / admin enrollments, MSP certificate exchange, and channel construction +without the assumption of a central file system or volume mount. With minor modifications, this +example can be extended to use `rsync` or an SSH protocol to exchange channel MSP for a network +spanning multiple, independent Kubernetes clusters. For convenience, this example allocates a +dedicated k8s namespace for each organization, running on a shared virtual KIND cluster. + +For best results, start a new terminal for each organization in the consortium. (Imagine that each +shell is running commands on behalf of the org's Fabric administrator.) + + +## The Stage: + +```shell +git clone https://github.com/hyperledger-labs/fabric-operator.git +cd sample-network-multi-org +``` + +Create a KIND kubernetes cluster, *.localho.st ingress, and local container registry: +```shell +just kind +``` + + +## Act I: Launch CAs, peers, and orderers + +Start the nodes in the network: +```shell +just start org0 +just start org1 +just start org2 +``` + +Enroll admin, rcaadmin, and gateway users at the org CAs: +```shell +just enroll org0 +just enroll org1 +just enroll org2 +``` + +```shell +just check-network +``` + +## Act II: Build a Consortium + +```shell +just export-msp org0 +just export-msp org1 +just export-msp org2 +``` + +```shell +just create-genesis-block + +just inspect-genesis-block +``` + +```shell +just join org0 +just join org1 +just join org2 +``` + + +## Act III: Chaincode and Gateway Application + +Install [asset-transfer](https://github.com/hyperledger/fabric-samples/tree/main/full-stack-asset-transfer-guide/contracts/asset-transfer-typescript) +version [0.1.4](https://github.com/hyperledgendary/full-stack-asset-transfer-guide/releases/tag/v0.1.4) with the +Kubernetes [chaincode builder](https://github.com/hyperledger-labs/fabric-builder-k8s): + +```shell +just install-cc org1 +just install-cc org2 +``` + +### Ad Hoc peer CLI: + +org1: +```shell +export ORG=org1 +export MSP_ID=Org1MSP + +export $(just show-context $MSP_ID $ORG peer1) + +peer chaincode query \ + -n asset-transfer \ + -C mychannel \ + -c '{"Args":["org.hyperledger.fabric:GetMetadata"]}' +``` + +org2: +```shell +export ORG=org2 +export MSP_ID=Org2MSP + +export $(just show-context $MSP_ID $ORG peer1) + +peer chaincode query \ + -n asset-transfer \ + -C mychannel \ + -c '{"Args":["org.hyperledger.fabric:GetMetadata"]}' +``` + + +### Gateway Client + +When the org1 and org2 CAs are created, they include a bootstrap [registration](organizations/org1/org1-ca.yaml#L50-L52) +and [enrollment](organizations/org1/enroll.sh#L48) of a client identity for use in gateway application development. + +If the `just show-context` commands (above) have been loaded into the terminal, the peer, orderer, and +CA certificate paths have been loaded into the environment. + +In an org admin shell, load the gateway client environment for [trader-typescript](https://github.com/hyperledger/fabric-samples/tree/main/full-stack-asset-transfer-guide/applications/trader-typescript): +```shell +# local MSP enrollment folder for the org client user +export USER_MSP_DIR=$PWD/organizations/$ORG/enrollments/${ORG}user/msp + +# Path to private key file +export PRIVATE_KEY=$USER_MSP_DIR/keystore/key.pem + +# Path to user certificate file +export CERTIFICATE=$USER_MSP_DIR/signcerts/cert.pem + +# Path to CA certificate +export TLS_CERT=$CORE_PEER_TLS_ROOTCERT_FILE + +# Connect client applications to the load-balancing gateway peer alias: +export ENDPOINT=${ORG}-peer-gateway.${ORG}.localho.st:443 +``` + +- Compile the trader-typescript application: +```shell +git clone https://github.com/hyperledger/fabric-samples.git /tmp/fabric-samples +pushd /tmp/fabric-samples/full-stack-asset-transfer-guide/applications/trader-typescript + +npm install +``` + +```shell +# Create a yellow banana token +npm start create banana bananaman yellow + +npm start getAllAssets + +# Transfer the banana among users / orgs +npm start transfer banana appleman Org1MSP + +npm start getAllAssets + +# Transfer the banana among users / orgs +npm start transfer banana bananaman Org2MSP + +# Error! Which org owns the banana? +npm start transfer banana bananaman Org1MSP +``` + + +## Teardown + +```shell +# Tear down the network +just destroy +``` +or +```shell +# Tear down the kubernetes cluster +just unkind +``` diff --git a/sample-network-multi-org/channel-config/.gitignore b/sample-network-multi-org/channel-config/.gitignore new file mode 100644 index 00000000..c41bb5a9 --- /dev/null +++ b/sample-network-multi-org/channel-config/.gitignore @@ -0,0 +1,3 @@ +organizations/ +mychannel_genesis_block.pb +mychannel_genesis_block.json \ No newline at end of file diff --git a/sample-network-multi-org/channel-config/README.md b/sample-network-multi-org/channel-config/README.md new file mode 100644 index 00000000..57c5dc6e --- /dev/null +++ b/sample-network-multi-org/channel-config/README.md @@ -0,0 +1,16 @@ +# Channel Configuration + +TODO : this guide / notes. + + +Notes : + +- [ ] describe how `organizations/` folder is populated by the export_msp.sh scripts +- [ ] configtx uses the internal k8s `$service.svc.cluster.local` DNS domain to communicate between nodes. +- [ ] describe configtx.yaml assumes / enforces working dir is FABRIC_CFG_PATH + +TODOs: + +- [ ] Deploy org nodes across multiple namespaces. Use kube DNS to resolve in the channel config. `$service.$namespace.svc.cluster.local` +- [ ] Deploy org nodes across multiple k8s clusters. Use INGRESS URLs to resolve services. `$ingress-hostname.$org.localho.st:443` +- \ No newline at end of file diff --git a/sample-network-multi-org/channel-config/config/configtx.yaml b/sample-network-multi-org/channel-config/config/configtx.yaml new file mode 100644 index 00000000..aa7b6efb --- /dev/null +++ b/sample-network-multi-org/channel-config/config/configtx.yaml @@ -0,0 +1,428 @@ +# +# Copyright contributors to the Hyperledger Fabric Operator project +# +# SPDX-License-Identifier: Apache-2.0 +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at: +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# + +--- +################################################################################ +# +# Section: Organizations +# +# - This section defines the different organizational identities which will +# be referenced later in the configuration. +# +################################################################################ +Organizations: + + # SampleOrg defines an MSP using the sampleconfig. It should never be used + # in production but may be used as a template for other definitions + - &OrdererOrg + # DefaultOrg defines the organization which is used in the sampleconfig + # of the fabric.git development environment + Name: OrdererOrg + + # ID to load the MSP definition as + ID: OrdererMSP + + # MSPDir is the filesystem path which contains the MSP configuration + MSPDir: ../organizations/ordererOrganizations/org0.localho.st/msp + + # Policies defines the set of policies at this level of the config tree + # For organization policies, their canonical path is usually + # /Channel/// + Policies: + Readers: + Type: Signature + Rule: "OR('OrdererMSP.member')" + Writers: + Type: Signature + Rule: "OR('OrdererMSP.member')" + Admins: + Type: Signature + Rule: "OR('OrdererMSP.admin')" + + OrdererEndpoints: + - orderernode1.org0.svc.cluster.local:7050 + - orderernode2.org0.svc.cluster.local:7050 + - orderernode3.org0.svc.cluster.local:7050 + + - &Org1 + # DefaultOrg defines the organization which is used in the sampleconfig + # of the fabric.git development environment + Name: Org1MSP + + # ID to load the MSP definition as + ID: Org1MSP + + MSPDir: ../organizations/peerOrganizations/org1.localho.st/msp + + # Policies defines the set of policies at this level of the config tree + # For organization policies, their canonical path is usually + # /Channel/// + Policies: + Readers: + Type: Signature + Rule: "OR('Org1MSP.admin', 'Org1MSP.peer', 'Org1MSP.client')" + Writers: + Type: Signature + Rule: "OR('Org1MSP.admin', 'Org1MSP.client')" + Admins: + Type: Signature + Rule: "OR('Org1MSP.admin')" + Endorsement: + Type: Signature + Rule: "OR('Org1MSP.peer')" + + # leave this flag set to true. + AnchorPeers: + # AnchorPeers defines the location of peers which can be used + # for cross org gossip communication. Note, this value is only + # encoded in the genesis block in the Application section context + - Host: peer1.org1.svc.cluster.local + Port: 7051 + + - &Org2 + # DefaultOrg defines the organization which is used in the sampleconfig + # of the fabric.git development environment + Name: Org2MSP + + # ID to load the MSP definition as + ID: Org2MSP + + MSPDir: ../organizations/peerOrganizations/org2.localho.st/msp + + # Policies defines the set of policies at this level of the config tree + # For organization policies, their canonical path is usually + # /Channel/// + Policies: + Readers: + Type: Signature + Rule: "OR('Org2MSP.admin', 'Org2MSP.peer', 'Org2MSP.client')" + Writers: + Type: Signature + Rule: "OR('Org2MSP.admin', 'Org2MSP.client')" + Admins: + Type: Signature + Rule: "OR('Org2MSP.admin')" + Endorsement: + Type: Signature + Rule: "OR('Org2MSP.peer')" + + AnchorPeers: + # AnchorPeers defines the location of peers which can be used + # for cross org gossip communication. Note, this value is only + # encoded in the genesis block in the Application section context + - Host: peer1.org2.svc.cluster.local + Port: 7051 + +################################################################################ +# +# SECTION: Capabilities +# +# - This section defines the capabilities of fabric network. This is a new +# concept as of v1.1.0 and should not be utilized in mixed networks with +# v1.0.x peers and orderers. Capabilities define features which must be +# present in a fabric binary for that binary to safely participate in the +# fabric network. For instance, if a new MSP type is added, newer binaries +# might recognize and validate the signatures from this type, while older +# binaries without this support would be unable to validate those +# transactions. This could lead to different versions of the fabric binaries +# having different world states. Instead, defining a capability for a channel +# informs those binaries without this capability that they must cease +# processing transactions until they have been upgraded. For v1.0.x if any +# capabilities are defined (including a map with all capabilities turned off) +# then the v1.0.x peer will deliberately crash. +# +################################################################################ +Capabilities: + # Channel capabilities apply to both the orderers and the peers and must be + # supported by both. + # Set the value of the capability to true to require it. + Channel: &ChannelCapabilities + # V2_0 capability ensures that orderers and peers behave according + # to v2.0 channel capabilities. Orderers and peers from + # prior releases would behave in an incompatible way, and are therefore + # not able to participate in channels at v2.0 capability. + # Prior to enabling V2.0 channel capabilities, ensure that all + # orderers and peers on a channel are at v2.0.0 or later. + V2_0: true + + # Orderer capabilities apply only to the orderers, and may be safely + # used with prior release peers. + # Set the value of the capability to true to require it. + Orderer: &OrdererCapabilities + # V2_0 orderer capability ensures that orderers behave according + # to v2.0 orderer capabilities. Orderers from + # prior releases would behave in an incompatible way, and are therefore + # not able to participate in channels at v2.0 orderer capability. + # Prior to enabling V2.0 orderer capabilities, ensure that all + # orderers on channel are at v2.0.0 or later. + V2_0: true + + # Application capabilities apply only to the peer network, and may be safely + # used with prior release orderers. + # Set the value of the capability to true to require it. + Application: &ApplicationCapabilities + # V2_0 application capability ensures that peers behave according + # to v2.0 application capabilities. Peers from + # prior releases would behave in an incompatible way, and are therefore + # not able to participate in channels at v2.0 application capability. + # Prior to enabling V2.0 application capabilities, ensure that all + # peers on channel are at v2.0.0 or later. + V2_0: true + +################################################################################ +# +# SECTION: Application +# +# - This section defines the values to encode into a config transaction or +# genesis block for application related parameters +# +################################################################################ +Application: &ApplicationDefaults + + # Organizations is the list of orgs which are defined as participants on + # the application side of the network + Organizations: + + # Policies defines the set of policies at this level of the config tree + # For Application policies, their canonical path is + # /Channel/Application/ + Policies: + Readers: + Type: ImplicitMeta + Rule: "ANY Readers" + Writers: + Type: ImplicitMeta + Rule: "ANY Writers" + Admins: + Type: ImplicitMeta + Rule: "MAJORITY Admins" + LifecycleEndorsement: + Type: Signature + Rule: "OR('Org1MSP.peer','Org2MSP.peer')" + Endorsement: + Type: Signature + Rule: "OR('Org1MSP.peer','Org2MSP.peer')" + + Capabilities: + <<: *ApplicationCapabilities +################################################################################ +# +# SECTION: Orderer +# +# - This section defines the values to encode into a config transaction or +# genesis block for orderer related parameters +# +################################################################################ +Orderer: &OrdererDefaults + + # Orderer Type: The orderer implementation to start + OrdererType: etcdraft + + EtcdRaft: + Consenters: + - Host: orderernode1.org0.svc.cluster.local + Port: 7050 + ClientTLSCert: ../organizations/ordererOrganizations/org0.localho.st/orderers/orderernode1/tls/signcerts/tls-cert.pem + ServerTLSCert: ../organizations/ordererOrganizations/org0.localho.st/orderers/orderernode1/tls/signcerts/tls-cert.pem + - Host: orderernode2.org0.svc.cluster.local + Port: 7050 + ClientTLSCert: ../organizations/ordererOrganizations/org0.localho.st/orderers/orderernode2/tls/signcerts/tls-cert.pem + ServerTLSCert: ../organizations/ordererOrganizations/org0.localho.st/orderers/orderernode2/tls/signcerts/tls-cert.pem + - Host: orderernode3.org0.svc.cluster.local + Port: 7050 + ClientTLSCert: ../organizations/ordererOrganizations/org0.localho.st/orderers/orderernode3/tls/signcerts/tls-cert.pem + ServerTLSCert: ../organizations/ordererOrganizations/org0.localho.st/orderers/orderernode3/tls/signcerts/tls-cert.pem + + + # Options to be specified for all the etcd/raft nodes. The values here + # are the defaults for all new channels and can be modified on a + # per-channel basis via configuration updates. + Options: + # TickInterval is the time interval between two Node.Tick invocations. + #TickInterval: 500ms default + TickInterval: 2500ms + + # ElectionTick is the number of Node.Tick invocations that must pass + # between elections. That is, if a follower does not receive any + # message from the leader of current term before ElectionTick has + # elapsed, it will become candidate and start an election. + # ElectionTick must be greater than HeartbeatTick. + # ElectionTick: 10 default + ElectionTick: 5 + + # HeartbeatTick is the number of Node.Tick invocations that must + # pass between heartbeats. That is, a leader sends heartbeat + # messages to maintain its leadership every HeartbeatTick ticks. + HeartbeatTick: 1 + + # MaxInflightBlocks limits the max number of in-flight append messages + # during optimistic replication phase. + MaxInflightBlocks: 5 + + # SnapshotIntervalSize defines number of bytes per which a snapshot is taken + SnapshotIntervalSize: 16 MB + + # Batch Timeout: The amount of time to wait before creating a batch + BatchTimeout: 2s + + # Batch Size: Controls the number of messages batched into a block + BatchSize: + + # Max Message Count: The maximum number of messages to permit in a batch + MaxMessageCount: 10 + + # Absolute Max Bytes: The absolute maximum number of bytes allowed for + # the serialized messages in a batch. + AbsoluteMaxBytes: 99 MB + + # Preferred Max Bytes: The preferred maximum number of bytes allowed for + # the serialized messages in a batch. A message larger than the preferred + # max bytes will result in a batch larger than preferred max bytes. + PreferredMaxBytes: 512 KB + + # Organizations is the list of orgs which are defined as participants on + # the orderer side of the network + Organizations: + + # Policies defines the set of policies at this level of the config tree + # For Orderer policies, their canonical path is + # /Channel/Orderer/ + Policies: + Readers: + Type: ImplicitMeta + Rule: "ANY Readers" + Writers: + Type: ImplicitMeta + Rule: "ANY Writers" + Admins: + Type: ImplicitMeta + Rule: "MAJORITY Admins" + # BlockValidation specifies what signatures must be included in the block + # from the orderer for the peer to validate it. + BlockValidation: + Type: ImplicitMeta + Rule: "ANY Writers" + +################################################################################ +# +# CHANNEL +# +# This section defines the values to encode into a config transaction or +# genesis block for channel related parameters. +# +################################################################################ +Channel: &ChannelDefaults + # Policies defines the set of policies at this level of the config tree + # For Channel policies, their canonical path is + # /Channel/ + Policies: + # Who may invoke the 'Deliver' API + Readers: + Type: ImplicitMeta + Rule: "ANY Readers" + # Who may invoke the 'Broadcast' API + Writers: + Type: ImplicitMeta + Rule: "ANY Writers" + # By default, who may modify elements at this config level + Admins: + Type: ImplicitMeta + Rule: "MAJORITY Admins" + + # Capabilities describes the channel level capabilities, see the + # dedicated Capabilities section elsewhere in this file for a full + # description + Capabilities: + <<: *ChannelCapabilities + +################################################################################ +# +# Profile +# +# - Different configuration profiles may be encoded here to be specified +# as parameters to the configtxgen tool +# +################################################################################ +Profiles: + + # test network profile with application (not system) channel. + TwoOrgsApplicationGenesis: + <<: *ChannelDefaults + Orderer: + <<: *OrdererDefaults + Organizations: + - *OrdererOrg + Capabilities: *OrdererCapabilities + Application: + <<: *ApplicationDefaults + Organizations: + - *Org1 + - *Org2 + Capabilities: *ApplicationCapabilities + + + # + # Unclear lineage for these profiles: nano-fab? + # + # TwoOrgsOrdererGenesis will construct a system channel as it has a Consortiums stanza, which is not + # compatible with osnadmin. + # + # @enyeart - which profile should be used for the kube test network? + # + TwoOrgsOrdererGenesis: + <<: *ChannelDefaults + Orderer: + <<: *OrdererDefaults + OrdererType: etcdraft + Organizations: + - *OrdererOrg + Capabilities: + <<: *OrdererCapabilities + Consortiums: + SampleConsortium: + Organizations: + - *Org1 + - *Org2 + TwoOrgsChannel: + Consortium: SampleConsortium + <<: *ChannelDefaults + Application: + <<: *ApplicationDefaults + Organizations: + - *Org1 + - *Org2 + Capabilities: + <<: *ApplicationCapabilities + Org1Channel: + Consortium: SampleConsortium + <<: *ChannelDefaults + Application: + <<: *ApplicationDefaults + Organizations: + - *Org1 + Capabilities: + <<: *ApplicationCapabilities + Org2Channel: + Consortium: SampleConsortium + <<: *ChannelDefaults + Application: + <<: *ApplicationDefaults + Organizations: + - *Org2 + Capabilities: + <<: *ApplicationCapabilities diff --git a/sample-network-multi-org/channel-config/config/core.yaml b/sample-network-multi-org/channel-config/config/core.yaml new file mode 100644 index 00000000..fa5eeeb3 --- /dev/null +++ b/sample-network-multi-org/channel-config/config/core.yaml @@ -0,0 +1,775 @@ +# +# Copyright contributors to the Hyperledger Fabric Operator project +# +# SPDX-License-Identifier: Apache-2.0 +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at: +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# + +############################################################################### +# +# Peer section +# +############################################################################### +peer: + + # The peer id provides a name for this peer instance and is used when + # naming docker resources. + id: jdoe + + # The networkId allows for logical separation of networks and is used when + # naming docker resources. + networkId: dev + + # The Address at local network interface this Peer will listen on. + # By default, it will listen on all network interfaces + listenAddress: 0.0.0.0:7051 + + # The endpoint this peer uses to listen for inbound chaincode connections. + # If this is commented-out, the listen address is selected to be + # the peer's address (see below) with port 7052 + # chaincodeListenAddress: 0.0.0.0:7052 + + # The endpoint the chaincode for this peer uses to connect to the peer. + # If this is not specified, the chaincodeListenAddress address is selected. + # And if chaincodeListenAddress is not specified, address is selected from + # peer address (see below). If specified peer address is invalid then it + # will fallback to the auto detected IP (local IP) regardless of the peer + # addressAutoDetect value. + # chaincodeAddress: 0.0.0.0:7052 + + # When used as peer config, this represents the endpoint to other peers + # in the same organization. For peers in other organization, see + # gossip.externalEndpoint for more info. + # When used as CLI config, this means the peer's endpoint to interact with + address: 0.0.0.0:7051 + + # Whether the Peer should programmatically determine its address + # This case is useful for docker containers. + # When set to true, will override peer address. + addressAutoDetect: false + + # Keepalive settings for peer server and clients + keepalive: + # Interval is the duration after which if the server does not see + # any activity from the client it pings the client to see if it's alive + interval: 7200s + # Timeout is the duration the server waits for a response + # from the client after sending a ping before closing the connection + timeout: 20s + # MinInterval is the minimum permitted time between client pings. + # If clients send pings more frequently, the peer server will + # disconnect them + minInterval: 60s + # Client keepalive settings for communicating with other peer nodes + client: + # Interval is the time between pings to peer nodes. This must + # greater than or equal to the minInterval specified by peer + # nodes + interval: 60s + # Timeout is the duration the client waits for a response from + # peer nodes before closing the connection + timeout: 20s + # DeliveryClient keepalive settings for communication with ordering + # nodes. + deliveryClient: + # Interval is the time between pings to ordering nodes. This must + # greater than or equal to the minInterval specified by ordering + # nodes. + interval: 60s + # Timeout is the duration the client waits for a response from + # ordering nodes before closing the connection + timeout: 20s + + + # Gossip related configuration + gossip: + # Bootstrap set to initialize gossip with. + # This is a list of other peers that this peer reaches out to at startup. + # Important: The endpoints here have to be endpoints of peers in the same + # organization, because the peer would refuse connecting to these endpoints + # unless they are in the same organization as the peer. + bootstrap: 127.0.0.1:7051 + + # NOTE: orgLeader and useLeaderElection parameters are mutual exclusive. + # Setting both to true would result in the termination of the peer + # since this is undefined state. If the peers are configured with + # useLeaderElection=false, make sure there is at least 1 peer in the + # organization that its orgLeader is set to true. + + # Defines whenever peer will initialize dynamic algorithm for + # "leader" selection, where leader is the peer to establish + # connection with ordering service and use delivery protocol + # to pull ledger blocks from ordering service. + useLeaderElection: false + # Statically defines peer to be an organization "leader", + # where this means that current peer will maintain connection + # with ordering service and disseminate block across peers in + # its own organization. Multiple peers or all peers in an organization + # may be configured as org leaders, so that they all pull + # blocks directly from ordering service. + orgLeader: true + + # Interval for membershipTracker polling + membershipTrackerInterval: 5s + + # Overrides the endpoint that the peer publishes to peers + # in its organization. For peers in foreign organizations + # see 'externalEndpoint' + endpoint: + # Maximum count of blocks stored in memory + maxBlockCountToStore: 10 + # Max time between consecutive message pushes(unit: millisecond) + maxPropagationBurstLatency: 10ms + # Max number of messages stored until a push is triggered to remote peers + maxPropagationBurstSize: 10 + # Number of times a message is pushed to remote peers + propagateIterations: 1 + # Number of peers selected to push messages to + propagatePeerNum: 3 + # Determines frequency of pull phases(unit: second) + # Must be greater than digestWaitTime + responseWaitTime + pullInterval: 4s + # Number of peers to pull from + pullPeerNum: 3 + # Determines frequency of pulling state info messages from peers(unit: second) + requestStateInfoInterval: 4s + # Determines frequency of pushing state info messages to peers(unit: second) + publishStateInfoInterval: 4s + # Maximum time a stateInfo message is kept until expired + stateInfoRetentionInterval: + # Time from startup certificates are included in Alive messages(unit: second) + publishCertPeriod: 10s + # Should we skip verifying block messages or not (currently not in use) + skipBlockVerification: false + # Dial timeout(unit: second) + dialTimeout: 3s + # Connection timeout(unit: second) + connTimeout: 2s + # Buffer size of received messages + recvBuffSize: 20 + # Buffer size of sending messages + sendBuffSize: 200 + # Time to wait before pull engine processes incoming digests (unit: second) + # Should be slightly smaller than requestWaitTime + digestWaitTime: 1s + # Time to wait before pull engine removes incoming nonce (unit: milliseconds) + # Should be slightly bigger than digestWaitTime + requestWaitTime: 1500ms + # Time to wait before pull engine ends pull (unit: second) + responseWaitTime: 2s + # Alive check interval(unit: second) + aliveTimeInterval: 5s + # Alive expiration timeout(unit: second) + aliveExpirationTimeout: 25s + # Reconnect interval(unit: second) + reconnectInterval: 25s + # Max number of attempts to connect to a peer + maxConnectionAttempts: 120 + # Message expiration factor for alive messages + msgExpirationFactor: 20 + # This is an endpoint that is published to peers outside of the organization. + # If this isn't set, the peer will not be known to other organizations. + externalEndpoint: + # Leader election service configuration + election: + # Longest time peer waits for stable membership during leader election startup (unit: second) + startupGracePeriod: 15s + # Interval gossip membership samples to check its stability (unit: second) + membershipSampleInterval: 1s + # Time passes since last declaration message before peer decides to perform leader election (unit: second) + leaderAliveThreshold: 10s + # Time between peer sends propose message and declares itself as a leader (sends declaration message) (unit: second) + leaderElectionDuration: 5s + + pvtData: + # pullRetryThreshold determines the maximum duration of time private data corresponding for a given block + # would be attempted to be pulled from peers until the block would be committed without the private data + pullRetryThreshold: 60s + # As private data enters the transient store, it is associated with the peer's ledger's height at that time. + # transientstoreMaxBlockRetention defines the maximum difference between the current ledger's height upon commit, + # and the private data residing inside the transient store that is guaranteed not to be purged. + # Private data is purged from the transient store when blocks with sequences that are multiples + # of transientstoreMaxBlockRetention are committed. + transientstoreMaxBlockRetention: 1000 + # pushAckTimeout is the maximum time to wait for an acknowledgement from each peer + # at private data push at endorsement time. + pushAckTimeout: 3s + # Block to live pulling margin, used as a buffer + # to prevent peer from trying to pull private data + # from peers that is soon to be purged in next N blocks. + # This helps a newly joined peer catch up to current + # blockchain height quicker. + btlPullMargin: 10 + # the process of reconciliation is done in an endless loop, while in each iteration reconciler tries to + # pull from the other peers the most recent missing blocks with a maximum batch size limitation. + # reconcileBatchSize determines the maximum batch size of missing private data that will be reconciled in a + # single iteration. + reconcileBatchSize: 10 + # reconcileSleepInterval determines the time reconciler sleeps from end of an iteration until the beginning + # of the next reconciliation iteration. + reconcileSleepInterval: 1m + # reconciliationEnabled is a flag that indicates whether private data reconciliation is enable or not. + reconciliationEnabled: true + # skipPullingInvalidTransactionsDuringCommit is a flag that indicates whether pulling of invalid + # transaction's private data from other peers need to be skipped during the commit time and pulled + # only through reconciler. + skipPullingInvalidTransactionsDuringCommit: false + # implicitCollectionDisseminationPolicy specifies the dissemination policy for the peer's own implicit collection. + # When a peer endorses a proposal that writes to its own implicit collection, below values override the default values + # for disseminating private data. + # Note that it is applicable to all channels the peer has joined. The implication is that requiredPeerCount has to + # be smaller than the number of peers in a channel that has the lowest numbers of peers from the organization. + implicitCollectionDisseminationPolicy: + # requiredPeerCount defines the minimum number of eligible peers to which the peer must successfully + # disseminate private data for its own implicit collection during endorsement. Default value is 0. + requiredPeerCount: 0 + # maxPeerCount defines the maximum number of eligible peers to which the peer will attempt to + # disseminate private data for its own implicit collection during endorsement. Default value is 1. + maxPeerCount: 1 + + # Gossip state transfer related configuration + state: + # indicates whenever state transfer is enabled or not + # default value is true, i.e. state transfer is active + # and takes care to sync up missing blocks allowing + # lagging peer to catch up to speed with rest network. + # Keep in mind that when peer.gossip.useLeaderElection is true + # and there are several peers in the organization, + # or peer.gossip.useLeaderElection is false alongside with + # peer.gossip.orgleader being false, the peer's ledger may lag behind + # the rest of the peers and will never catch up due to state transfer + # being disabled. + enabled: false + # checkInterval interval to check whether peer is lagging behind enough to + # request blocks via state transfer from another peer. + checkInterval: 10s + # responseTimeout amount of time to wait for state transfer response from + # other peers + responseTimeout: 3s + # batchSize the number of blocks to request via state transfer from another peer + batchSize: 10 + # blockBufferSize reflects the size of the re-ordering buffer + # which captures blocks and takes care to deliver them in order + # down to the ledger layer. The actual buffer size is bounded between + # 0 and 2*blockBufferSize, each channel maintains its own buffer + blockBufferSize: 20 + # maxRetries maximum number of re-tries to ask + # for single state transfer request + maxRetries: 3 + + # TLS Settings + tls: + # Require server-side TLS + enabled: true + # Require client certificates / mutual TLS for inbound connections. + # Note that clients that are not configured to use a certificate will + # fail to connect to the peer. + clientAuthRequired: false + # X.509 certificate used for TLS server + cert: + file: tls/server.crt + # Private key used for TLS server + key: + file: tls/server.key + # rootcert.file represents the trusted root certificate chain used for verifying certificates + # of other nodes during outbound connections. + # It is not required to be set, but can be used to augment the set of TLS CA certificates + # available from the MSPs of each channel’s configuration. + rootcert: + file: tls/ca.crt + # If mutual TLS is enabled, clientRootCAs.files contains a list of additional root certificates + # used for verifying certificates of client connections. + # It augments the set of TLS CA certificates available from the MSPs of each channel’s configuration. + # Minimally, set your organization's TLS CA root certificate so that the peer can receive join channel requests. + clientRootCAs: + files: + - tls/ca.crt + # Private key used for TLS when making client connections. + # If not set, peer.tls.key.file will be used instead + clientKey: + file: + # X.509 certificate used for TLS when making client connections. + # If not set, peer.tls.cert.file will be used instead + clientCert: + file: + + # Authentication contains configuration parameters related to authenticating + # client messages + authentication: + # the acceptable difference between the current server time and the + # client's time as specified in a client request message + timewindow: 15m + + # Path on the file system where peer will store data (eg ledger). This + # location must be access control protected to prevent unintended + # modification that might corrupt the peer operations. + fileSystemPath: /var/hyperledger/production + + # BCCSP (Blockchain crypto provider): Select which crypto implementation or + # library to use + BCCSP: + Default: SW + # Settings for the SW crypto provider (i.e. when DEFAULT: SW) + SW: + # TODO: The default Hash and Security level needs refactoring to be + # fully configurable. Changing these defaults requires coordination + # SHA2 is hardcoded in several places, not only BCCSP + Hash: SHA2 + Security: 256 + # Location of Key Store + FileKeyStore: + # If "", defaults to 'mspConfigPath'/keystore + KeyStore: + # Settings for the PKCS#11 crypto provider (i.e. when DEFAULT: PKCS11) + PKCS11: + # Location of the PKCS11 module library + Library: + # Token Label + Label: + # User PIN + Pin: + Hash: + Security: + + # Path on the file system where peer will find MSP local configurations + mspConfigPath: msp + + # Identifier of the local MSP + # ----!!!!IMPORTANT!!!-!!!IMPORTANT!!!-!!!IMPORTANT!!!!---- + # Deployers need to change the value of the localMspId string. + # In particular, the name of the local MSP ID of a peer needs + # to match the name of one of the MSPs in each of the channel + # that this peer is a member of. Otherwise this peer's messages + # will not be identified as valid by other nodes. + localMspId: Org1MSP + + # CLI common client config options + client: + # connection timeout + connTimeout: 15s + + # Delivery service related config + deliveryclient: + # It sets the total time the delivery service may spend in reconnection + # attempts until its retry logic gives up and returns an error + reconnectTotalTimeThreshold: 3600s + + # It sets the delivery service <-> ordering service node connection timeout + connTimeout: 15s + + # It sets the delivery service maximal delay between consecutive retries + reConnectBackoffThreshold: 3600s + + # A list of orderer endpoint addresses which should be overridden + # when found in channel configurations. + addressOverrides: + # - from: + # to: + # caCertsFile: + # - from: + # to: + # caCertsFile: + + # Type for the local MSP - by default it's of type bccsp + localMspType: bccsp + + # Used with Go profiling tools only in none production environment. In + # production, it should be disabled (eg enabled: false) + profile: + enabled: false + listenAddress: 0.0.0.0:6060 + + # Handlers defines custom handlers that can filter and mutate + # objects passing within the peer, such as: + # Auth filter - reject or forward proposals from clients + # Decorators - append or mutate the chaincode input passed to the chaincode + # Endorsers - Custom signing over proposal response payload and its mutation + # Valid handler definition contains: + # - A name which is a factory method name defined in + # core/handlers/library/library.go for statically compiled handlers + # - library path to shared object binary for pluggable filters + # Auth filters and decorators are chained and executed in the order that + # they are defined. For example: + # authFilters: + # - + # name: FilterOne + # library: /opt/lib/filter.so + # - + # name: FilterTwo + # decorators: + # - + # name: DecoratorOne + # - + # name: DecoratorTwo + # library: /opt/lib/decorator.so + # Endorsers are configured as a map that its keys are the endorsement system chaincodes that are being overridden. + # Below is an example that overrides the default ESCC and uses an endorsement plugin that has the same functionality + # as the default ESCC. + # If the 'library' property is missing, the name is used as the constructor method in the builtin library similar + # to auth filters and decorators. + # endorsers: + # escc: + # name: DefaultESCC + # library: /etc/hyperledger/fabric/plugin/escc.so + handlers: + authFilters: + - + name: DefaultAuth + - + name: ExpirationCheck # This filter checks identity x509 certificate expiration + decorators: + - + name: DefaultDecorator + endorsers: + escc: + name: DefaultEndorsement + library: + validators: + vscc: + name: DefaultValidation + library: + + # library: /etc/hyperledger/fabric/plugin/escc.so + # Number of goroutines that will execute transaction validation in parallel. + # By default, the peer chooses the number of CPUs on the machine. Set this + # variable to override that choice. + # NOTE: overriding this value might negatively influence the performance of + # the peer so please change this value only if you know what you're doing + validatorPoolSize: + + # The discovery service is used by clients to query information about peers, + # such as - which peers have joined a certain channel, what is the latest + # channel config, and most importantly - given a chaincode and a channel, + # what possible sets of peers satisfy the endorsement policy. + discovery: + enabled: true + # Whether the authentication cache is enabled or not. + authCacheEnabled: true + # The maximum size of the cache, after which a purge takes place + authCacheMaxSize: 1000 + # The proportion (0 to 1) of entries that remain in the cache after the cache is purged due to overpopulation + authCachePurgeRetentionRatio: 0.75 + # Whether to allow non-admins to perform non channel scoped queries. + # When this is false, it means that only peer admins can perform non channel scoped queries. + orgMembersAllowedAccess: false + + # Limits is used to configure some internal resource limits. + limits: + # Concurrency limits the number of concurrently running requests to a service on each peer. + # Currently this option is only applied to endorser service and deliver service. + # When the property is missing or the value is 0, the concurrency limit is disabled for the service. + concurrency: + # endorserService limits concurrent requests to endorser service that handles chaincode deployment, query and invocation, + # including both user chaincodes and system chaincodes. + endorserService: 2500 + # deliverService limits concurrent event listeners registered to deliver service for blocks and transaction events. + deliverService: 2500 + +############################################################################### +# +# VM section +# +############################################################################### +vm: + + # Endpoint of the vm management system. For docker can be one of the following in general + # unix:///var/run/docker.sock + # http://localhost:2375 + # https://localhost:2376 + # endpoint: unix:///var/run/docker.sock + + # DISABLE the docker daemon endpoint to prevent /healthz from checking for docker in "External Builder" mode. + endpoint: + + # settings for docker vms + docker: + tls: + enabled: false + ca: + file: docker/ca.crt + cert: + file: docker/tls.crt + key: + file: docker/tls.key + + # Enables/disables the standard out/err from chaincode containers for + # debugging purposes + attachStdout: false + + # Parameters on creating docker container. + # Container may be efficiently created using ipam & dns-server for cluster + # NetworkMode - sets the networking mode for the container. Supported + # standard values are: `host`(default),`bridge`,`ipvlan`,`none`. + # Dns - a list of DNS servers for the container to use. + # Note: `Privileged` `Binds` `Links` and `PortBindings` properties of + # Docker Host Config are not supported and will not be used if set. + # LogConfig - sets the logging driver (Type) and related options + # (Config) for Docker. For more info, + # https://docs.docker.com/engine/admin/logging/overview/ + # Note: Set LogConfig using Environment Variables is not supported. + hostConfig: + NetworkMode: host + Dns: + # - 192.168.0.1 + LogConfig: + Type: json-file + Config: + max-size: "50m" + max-file: "5" + Memory: 2147483648 + +############################################################################### +# +# Chaincode section +# +############################################################################### +chaincode: + + # The id is used by the Chaincode stub to register the executing Chaincode + # ID with the Peer and is generally supplied through ENV variables + # the `path` form of ID is provided when installing the chaincode. + # The `name` is used for all other requests and can be any string. + id: + path: + name: + + # Generic builder environment, suitable for most chaincode types + builder: $(DOCKER_NS)/fabric-ccenv:$(TWO_DIGIT_VERSION) + + # Enables/disables force pulling of the base docker images (listed below) + # during user chaincode instantiation. + # Useful when using moving image tags (such as :latest) + pull: false + + golang: + # golang will never need more than baseos + runtime: $(DOCKER_NS)/fabric-baseos:$(TWO_DIGIT_VERSION) + + # whether or not golang chaincode should be linked dynamically + dynamicLink: false + + java: + # This is an image based on java:openjdk-8 with addition compiler + # tools added for java shim layer packaging. + # This image is packed with shim layer libraries that are necessary + # for Java chaincode runtime. + runtime: $(DOCKER_NS)/fabric-javaenv:$(TWO_DIGIT_VERSION) + + node: + # This is an image based on node:$(NODE_VER)-alpine + runtime: $(DOCKER_NS)/fabric-nodeenv:$(TWO_DIGIT_VERSION) + + # List of directories to treat as external builders and launchers for + # chaincode. The external builder detection processing will iterate over the + # builders in the order specified below. + externalBuilders: + - path: /var/hyperledger/fabric/chaincode/ccs-builder + name: ccs-builder + propagateEnvironment: + - HOME + - CORE_PEER_ID + - CORE_PEER_LOCALMSPID + + # The maximum duration to wait for the chaincode build and install process + # to complete. + installTimeout: 300s + + # Timeout duration for starting up a container and waiting for Register + # to come through. + startuptimeout: 300s + + # Timeout duration for Invoke and Init calls to prevent runaway. + # This timeout is used by all chaincodes in all the channels, including + # system chaincodes. + # Note that during Invoke, if the image is not available (e.g. being + # cleaned up when in development environment), the peer will automatically + # build the image, which might take more time. In production environment, + # the chaincode image is unlikely to be deleted, so the timeout could be + # reduced accordingly. + executetimeout: 30s + + # There are 2 modes: "dev" and "net". + # In dev mode, user runs the chaincode after starting peer from + # command line on local machine. + # In net mode, peer will run chaincode in a docker container. + mode: net + + # keepalive in seconds. In situations where the communication goes through a + # proxy that does not support keep-alive, this parameter will maintain connection + # between peer and chaincode. + # A value <= 0 turns keepalive off + keepalive: 0 + + # enabled system chaincodes + system: + _lifecycle: enable + cscc: enable + lscc: enable + qscc: enable + + # Logging section for the chaincode container + logging: + # Default level for all loggers within the chaincode container + level: info + # Override default level for the 'shim' logger + shim: warning + # Format for the chaincode container logs + format: '%{color}%{time:2006-01-02 15:04:05.000 MST} [%{module}] %{shortfunc} -> %{level:.4s} %{id:03x}%{color:reset} %{message}' + +############################################################################### +# +# Ledger section - ledger configuration encompasses both the blockchain +# and the state +# +############################################################################### +ledger: + + blockchain: + + state: + # stateDatabase - options are "goleveldb", "CouchDB" + # goleveldb - default state database stored in goleveldb. + # CouchDB - store state database in CouchDB + stateDatabase: goleveldb + # Limit on the number of records to return per query + totalQueryLimit: 100000 + couchDBConfig: + # It is recommended to run CouchDB on the same server as the peer, and + # not map the CouchDB container port to a server port in docker-compose. + # Otherwise proper security must be provided on the connection between + # CouchDB client (on the peer) and server. + couchDBAddress: 127.0.0.1:5984 + # This username must have read and write authority on CouchDB + username: + # The password is recommended to pass as an environment variable + # during start up (eg CORE_LEDGER_STATE_COUCHDBCONFIG_PASSWORD). + # If it is stored here, the file must be access control protected + # to prevent unintended users from discovering the password. + password: + # Number of retries for CouchDB errors + maxRetries: 3 + # Number of retries for CouchDB errors during peer startup. + # The delay between retries doubles for each attempt. + # Default of 10 retries results in 11 attempts over 2 minutes. + maxRetriesOnStartup: 10 + # CouchDB request timeout (unit: duration, e.g. 20s) + requestTimeout: 35s + # Limit on the number of records per each CouchDB query + # Note that chaincode queries are only bound by totalQueryLimit. + # Internally the chaincode may execute multiple CouchDB queries, + # each of size internalQueryLimit. + internalQueryLimit: 1000 + # Limit on the number of records per CouchDB bulk update batch + maxBatchUpdateSize: 1000 + # Warm indexes after every N blocks. + # This option warms any indexes that have been + # deployed to CouchDB after every N blocks. + # A value of 1 will warm indexes after every block commit, + # to ensure fast selector queries. + # Increasing the value may improve write efficiency of peer and CouchDB, + # but may degrade query response time. + warmIndexesAfterNBlocks: 1 + # Create the _global_changes system database + # This is optional. Creating the global changes database will require + # additional system resources to track changes and maintain the database + createGlobalChangesDB: false + # CacheSize denotes the maximum mega bytes (MB) to be allocated for the in-memory state + # cache. Note that CacheSize needs to be a multiple of 32 MB. If it is not a multiple + # of 32 MB, the peer would round the size to the next multiple of 32 MB. + # To disable the cache, 0 MB needs to be assigned to the cacheSize. + cacheSize: 64 + + history: + # enableHistoryDatabase - options are true or false + # Indicates if the history of key updates should be stored. + # All history 'index' will be stored in goleveldb, regardless if using + # CouchDB or alternate database for the state. + enableHistoryDatabase: true + + pvtdataStore: + # the maximum db batch size for converting + # the ineligible missing data entries to eligible missing data entries + collElgProcMaxDbBatchSize: 5000 + # the minimum duration (in milliseconds) between writing + # two consecutive db batches for converting the ineligible missing data entries to eligible missing data entries + collElgProcDbBatchesInterval: 1000 + # The missing data entries are classified into two categories: + # (1) prioritized + # (2) deprioritized + # Initially, all missing data are in the prioritized list. When the + # reconciler is unable to fetch the missing data from other peers, + # the unreconciled missing data would be moved to the deprioritized list. + # The reconciler would retry deprioritized missing data after every + # deprioritizedDataReconcilerInterval (unit: minutes). Note that the + # interval needs to be greater than the reconcileSleepInterval + deprioritizedDataReconcilerInterval: 60m + + snapshots: + # Path on the file system where peer will store ledger snapshots + rootDir: /var/hyperledger/production/snapshots + +############################################################################### +# +# Operations section +# +############################################################################### +operations: + # host and port for the operations server + listenAddress: 127.0.0.1:9443 + + # TLS configuration for the operations endpoint + tls: + # TLS enabled + enabled: false + + # path to PEM encoded server certificate for the operations server + cert: + file: + + # path to PEM encoded server key for the operations server + key: + file: + + # most operations service endpoints require client authentication when TLS + # is enabled. clientAuthRequired requires client certificate authentication + # at the TLS layer to access all resources. + clientAuthRequired: false + + # paths to PEM encoded ca certificates to trust for client authentication + clientRootCAs: + files: [] + +############################################################################### +# +# Metrics section +# +############################################################################### +metrics: + # metrics provider is one of statsd, prometheus, or disabled + provider: disabled + + # statsd configuration + statsd: + # network type: tcp or udp + network: udp + + # statsd server address + address: 127.0.0.1:8125 + + # the interval at which locally cached counters and gauges are pushed + # to statsd; timings are pushed immediately + writeInterval: 10s + + # prefix is prepended to all emitted statsd metrics + prefix: diff --git a/sample-network-multi-org/channel-config/create_genesis_block.sh b/sample-network-multi-org/channel-config/create_genesis_block.sh new file mode 100755 index 00000000..c882e4dc --- /dev/null +++ b/sample-network-multi-org/channel-config/create_genesis_block.sh @@ -0,0 +1,46 @@ +#!/usr/bin/env bash +# +# Copyright contributors to the Hyperledgendary Kubernetes Test Network project +# +# SPDX-License-Identifier: Apache-2.0 +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at: +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# +set -euo pipefail +. scripts/utils.sh + +GENESIS_BLOCK=${CHANNEL_NAME}_genesis_block.pb +CHANNEL_CONFIG=channel-config/config/configtx-multi-namespace.yaml + +print "Creating channel-config/$GENESIS_BLOCK from $CHANNEL_CONFIG" + +# +# The working directories and environment for configtxgen are confusing. +# +# Run configtxgen from the channel-config folder. This instructs the +# routine to read configtxgen.yaml from the local configuration, not the +# default config created when the Fabric binaries were downloaded. +# +# In configtx.yaml, path references will be relative to the config folder, +# not the current working directory. +# +cd channel-config +export FABRIC_CFG_PATH=$PWD/config + +configtxgen \ + -profile TwoOrgsApplicationGenesis \ + -channelID $CHANNEL_NAME \ + -outputBlock $GENESIS_BLOCK + + +#configtxgen -inspectBlock $GENESIS_BLOCK | tee ${CHANNEL_NAME}_genesis_block.json | jq diff --git a/sample-network-multi-org/cloud-config.yaml b/sample-network-multi-org/cloud-config.yaml new file mode 100644 index 00000000..7f429311 --- /dev/null +++ b/sample-network-multi-org/cloud-config.yaml @@ -0,0 +1,61 @@ +#cloud-config +users: + - name: ubuntu + groups: + - sudo + - docker + +write_files: + - path: /config/provision-root.sh + permissions: '0744' + content: | + #!/usr/bin/env bash + set -ex + # set -o errexit + # set -o pipefail + + # Install kind + KIND_VERSION=0.17.0 + if [ ! -x "/usr/local/bin/kind" ]; then + KIND_ARCH=$(dpkg --print-architecture) + curl --fail --silent --show-error -L "https://kind.sigs.k8s.io/dl/v${KIND_VERSION}/kind-linux-${KIND_ARCH}" -o /usr/local/bin/kind + chmod 755 /usr/local/bin/kind + fi + + # Install just + JUST_VERSION=1.5.0 + if [ ! -x "/usr/local/bin/just" ]; then + curl --proto '=https' --tlsv1.2 -sSf https://just.systems/install.sh | bash -s -- --tag ${JUST_VERSION} --to /usr/local/bin + chown root:root /usr/local/bin/just + chmod 755 /usr/local/bin/just + fi + + snap install kubectl --classic + snap install k9s --classic + snap install yq --classic + snap install jq --classic + snap install docker + + - path: /config/provision-user.sh + permissions: '0777' + owner: ubuntu:ubuntu + content: | + export NVM_DIR="$HOME/.nvm" + [ -s "$NVM_DIR/nvm.sh" ] || curl --fail --silent --show-error -o- https://raw.githubusercontent.com/creationix/nvm/v0.31.3/install.sh | bash + . "$NVM_DIR/nvm.sh" + + # Install latest node v16.x, latest typescript, weft + nvm install 16 + npm install -g typescript + npm install -g @hyperledger-labs/weft + +# Use Google DNS as the mac resolvers are not 100% reliable for the npm dependency builds in Docker +bootcmd: + - printf "[Resolve]\nDNS=8.8.8.8" > /etc/systemd/resolved.conf + - [systemctl, restart, systemd-resolved] + +runcmd: + - /config/provision-root.sh + - su -c /config/provision-user.sh ubuntu + +final_message: "The system is finally up, after $UPTIME seconds" \ No newline at end of file diff --git a/sample-network-multi-org/config/configtx.yaml b/sample-network-multi-org/config/configtx.yaml new file mode 100644 index 00000000..9bc4e1fc --- /dev/null +++ b/sample-network-multi-org/config/configtx.yaml @@ -0,0 +1,640 @@ +# Copyright IBM Corp. All Rights Reserved. +# +# SPDX-License-Identifier: Apache-2.0 +# + +--- +################################################################################ +# +# ORGANIZATIONS +# +# This section defines the organizational identities that can be referenced +# in the configuration profiles. +# +################################################################################ +Organizations: + + # SampleOrg defines an MSP using the sampleconfig. It should never be used + # in production but may be used as a template for other definitions. + - &SampleOrg + # Name is the key by which this org will be referenced in channel + # configuration transactions. + # Name can include alphanumeric characters as well as dots and dashes. + Name: SampleOrg + + # SkipAsForeign can be set to true for org definitions which are to be + # inherited from the orderer system channel during channel creation. This + # is especially useful when an admin of a single org without access to the + # MSP directories of the other orgs wishes to create a channel. Note + # this property must always be set to false for orgs included in block + # creation. + SkipAsForeign: false + + # ID is the key by which this org's MSP definition will be referenced. + # ID can include alphanumeric characters as well as dots and dashes. + ID: SampleOrg + + # MSPDir is the filesystem path which contains the MSP configuration. + MSPDir: msp + + # Policies defines the set of policies at this level of the config tree + # For organization policies, their canonical path is usually + # /Channel/// + Policies: &SampleOrgPolicies + Readers: + Type: Signature + Rule: "OR('SampleOrg.member')" + # If your MSP is configured with the new NodeOUs, you might + # want to use a more specific rule like the following: + # Rule: "OR('SampleOrg.admin', 'SampleOrg.peer', 'SampleOrg.client')" + Writers: + Type: Signature + Rule: "OR('SampleOrg.member')" + # If your MSP is configured with the new NodeOUs, you might + # want to use a more specific rule like the following: + # Rule: "OR('SampleOrg.admin', 'SampleOrg.client')" + Admins: + Type: Signature + Rule: "OR('SampleOrg.admin')" + Endorsement: + Type: Signature + Rule: "OR('SampleOrg.member')" + + # OrdererEndpoints is a list of all orderers this org runs which clients + # and peers may to connect to to push transactions and receive blocks respectively. + OrdererEndpoints: + - "127.0.0.1:7050" + + # AnchorPeers defines the location of peers which can be used for + # cross-org gossip communication. + # + # NOTE: this value should only be set when using the deprecated + # `configtxgen --outputAnchorPeersUpdate` command. It is recommended + # to instead use the channel configuration update process to set the + # anchor peers for each organization. + AnchorPeers: + - Host: 127.0.0.1 + Port: 7051 + +################################################################################ +# +# CAPABILITIES +# +# This section defines the capabilities of fabric network. This is a new +# concept as of v1.1.0 and should not be utilized in mixed networks with +# v1.0.x peers and orderers. Capabilities define features which must be +# present in a fabric binary for that binary to safely participate in the +# fabric network. For instance, if a new MSP type is added, newer binaries +# might recognize and validate the signatures from this type, while older +# binaries without this support would be unable to validate those +# transactions. This could lead to different versions of the fabric binaries +# having different world states. Instead, defining a capability for a channel +# informs those binaries without this capability that they must cease +# processing transactions until they have been upgraded. For v1.0.x if any +# capabilities are defined (including a map with all capabilities turned off) +# then the v1.0.x peer will deliberately crash. +# +################################################################################ +Capabilities: + # Channel capabilities apply to both the orderers and the peers and must be + # supported by both. + # Set the value of the capability to true to require it. + Channel: &ChannelCapabilities + # V2.0 for Channel is a catchall flag for behavior which has been + # determined to be desired for all orderers and peers running at the v2.0.0 + # level, but which would be incompatible with orderers and peers from + # prior releases. + # Prior to enabling V2.0 channel capabilities, ensure that all + # orderers and peers on a channel are at v2.0.0 or later. + V2_0: true + + # Orderer capabilities apply only to the orderers, and may be safely + # used with prior release peers. + # Set the value of the capability to true to require it. + Orderer: &OrdererCapabilities + # V1.1 for Orderer is a catchall flag for behavior which has been + # determined to be desired for all orderers running at the v1.1.x + # level, but which would be incompatible with orderers from prior releases. + # Prior to enabling V2.0 orderer capabilities, ensure that all + # orderers on a channel are at v2.0.0 or later. + V2_0: true + + # Application capabilities apply only to the peer network, and may be safely + # used with prior release orderers. + # Set the value of the capability to true to require it. + Application: &ApplicationCapabilities + # V2.5 for Application enables the new non-backwards compatible + # features of fabric v2.5, namely the ability to purge private data. + # Prior to enabling V2.5 application capabilities, ensure that all + # peers on a channel are at v2.5.0 or later. + V2_5: true + +################################################################################ +# +# APPLICATION +# +# This section defines the values to encode into a config transaction or +# genesis block for application-related parameters. +# +################################################################################ +Application: &ApplicationDefaults + ACLs: &ACLsDefault + # This section provides defaults for policies for various resources + # in the system. These "resources" could be functions on system chaincodes + # (e.g., "GetBlockByNumber" on the "qscc" system chaincode) or other resources + # (e.g.,who can receive Block events). This section does NOT specify the resource's + # definition or API, but just the ACL policy for it. + # + # Users can override these defaults with their own policy mapping by defining the + # mapping under ACLs in their channel definition + + #---New Lifecycle System Chaincode (_lifecycle) function to policy mapping for access control--# + + # ACL policy for _lifecycle's "CheckCommitReadiness" function + _lifecycle/CheckCommitReadiness: /Channel/Application/Writers + + # ACL policy for _lifecycle's "CommitChaincodeDefinition" function + _lifecycle/CommitChaincodeDefinition: /Channel/Application/Writers + + # ACL policy for _lifecycle's "QueryChaincodeDefinition" function + _lifecycle/QueryChaincodeDefinition: /Channel/Application/Writers + + # ACL policy for _lifecycle's "QueryChaincodeDefinitions" function + _lifecycle/QueryChaincodeDefinitions: /Channel/Application/Writers + + #---Lifecycle System Chaincode (lscc) function to policy mapping for access control---# + + # ACL policy for lscc's "getid" function + lscc/ChaincodeExists: /Channel/Application/Readers + + # ACL policy for lscc's "getdepspec" function + lscc/GetDeploymentSpec: /Channel/Application/Readers + + # ACL policy for lscc's "getccdata" function + lscc/GetChaincodeData: /Channel/Application/Readers + + # ACL Policy for lscc's "getchaincodes" function + lscc/GetInstantiatedChaincodes: /Channel/Application/Readers + + #---Query System Chaincode (qscc) function to policy mapping for access control---# + + # ACL policy for qscc's "GetChainInfo" function + qscc/GetChainInfo: /Channel/Application/Readers + + # ACL policy for qscc's "GetBlockByNumber" function + qscc/GetBlockByNumber: /Channel/Application/Readers + + # ACL policy for qscc's "GetBlockByHash" function + qscc/GetBlockByHash: /Channel/Application/Readers + + # ACL policy for qscc's "GetTransactionByID" function + qscc/GetTransactionByID: /Channel/Application/Readers + + # ACL policy for qscc's "GetBlockByTxID" function + qscc/GetBlockByTxID: /Channel/Application/Readers + + #---Configuration System Chaincode (cscc) function to policy mapping for access control---# + + # ACL policy for cscc's "GetConfigBlock" function + cscc/GetConfigBlock: /Channel/Application/Readers + + # ACL policy for cscc's "GetChannelConfig" function + cscc/GetChannelConfig: /Channel/Application/Readers + + #---Miscellaneous peer function to policy mapping for access control---# + + # ACL policy for invoking chaincodes on peer + peer/Propose: /Channel/Application/Writers + + # ACL policy for chaincode to chaincode invocation + peer/ChaincodeToChaincode: /Channel/Application/Writers + + #---Events resource to policy mapping for access control###---# + + # ACL policy for sending block events + event/Block: /Channel/Application/Readers + + # ACL policy for sending filtered block events + event/FilteredBlock: /Channel/Application/Readers + + # Organizations lists the orgs participating on the application side of the + # network. + Organizations: + + # Policies defines the set of policies at this level of the config tree + # For Application policies, their canonical path is + # /Channel/Application/ + Policies: &ApplicationDefaultPolicies + LifecycleEndorsement: + Type: ImplicitMeta + Rule: "MAJORITY Endorsement" + Endorsement: + Type: ImplicitMeta + Rule: "MAJORITY Endorsement" + Readers: + Type: ImplicitMeta + Rule: "ANY Readers" + Writers: + Type: ImplicitMeta + Rule: "ANY Writers" + Admins: + Type: ImplicitMeta + Rule: "MAJORITY Admins" + + # Capabilities describes the application level capabilities, see the + # dedicated Capabilities section elsewhere in this file for a full + # description + Capabilities: + <<: *ApplicationCapabilities + +################################################################################ +# +# ORDERER +# +# This section defines the values to encode into a config transaction or +# genesis block for orderer related parameters. +# +################################################################################ +Orderer: &OrdererDefaults + + # Orderer Type: The orderer implementation to start. + # Available types are "solo", "kafka" and "etcdraft". + OrdererType: solo + + # Addresses used to be the list of orderer addresses that clients and peers + # could connect to. However, this does not allow clients to associate orderer + # addresses and orderer organizations which can be useful for things such + # as TLS validation. The preferred way to specify orderer addresses is now + # to include the OrdererEndpoints item in your org definition + Addresses: + # - 127.0.0.1:7050 + + # Batch Timeout: The amount of time to wait before creating a batch. + BatchTimeout: 2s + + # Batch Size: Controls the number of messages batched into a block. + # The orderer views messages opaquely, but typically, messages may + # be considered to be Fabric transactions. The 'batch' is the group + # of messages in the 'data' field of the block. Blocks will be a few kb + # larger than the batch size, when signatures, hashes, and other metadata + # is applied. + BatchSize: + + # Max Message Count: The maximum number of messages to permit in a + # batch. No block will contain more than this number of messages. + MaxMessageCount: 500 + + # Absolute Max Bytes: The absolute maximum number of bytes allowed for + # the serialized messages in a batch. The maximum block size is this value + # plus the size of the associated metadata (usually a few KB depending + # upon the size of the signing identities). Any transaction larger than + # this value will be rejected by ordering. + # It is recommended not to exceed 49 MB, given the default grpc max message size of 100 MB + # configured on orderer and peer nodes (and allowing for message expansion during communication). + AbsoluteMaxBytes: 10 MB + + # Preferred Max Bytes: The preferred maximum number of bytes allowed + # for the serialized messages in a batch. Roughly, this field may be considered + # the best effort maximum size of a batch. A batch will fill with messages + # until this size is reached (or the max message count, or batch timeout is + # exceeded). If adding a new message to the batch would cause the batch to + # exceed the preferred max bytes, then the current batch is closed and written + # to a block, and a new batch containing the new message is created. If a + # message larger than the preferred max bytes is received, then its batch + # will contain only that message. Because messages may be larger than + # preferred max bytes (up to AbsoluteMaxBytes), some batches may exceed + # the preferred max bytes, but will always contain exactly one transaction. + PreferredMaxBytes: 2 MB + + # Max Channels is the maximum number of channels to allow on the ordering + # network. When set to 0, this implies no maximum number of channels. + MaxChannels: 0 + + Kafka: + # Brokers: A list of Kafka brokers to which the orderer connects. Edit + # this list to identify the brokers of the ordering service. + # NOTE: Use IP:port notation. + Brokers: + - kafka0:9092 + - kafka1:9092 + - kafka2:9092 + + # EtcdRaft defines configuration which must be set when the "etcdraft" + # orderertype is chosen. + EtcdRaft: + # The set of Raft replicas for this network. For the etcd/raft-based + # implementation, we expect every replica to also be an OSN. Therefore, + # a subset of the host:port items enumerated in this list should be + # replicated under the Orderer.Addresses key above. + Consenters: + - Host: raft0.example.com + Port: 7050 + ClientTLSCert: path/to/ClientTLSCert0 + ServerTLSCert: path/to/ServerTLSCert0 + - Host: raft1.example.com + Port: 7050 + ClientTLSCert: path/to/ClientTLSCert1 + ServerTLSCert: path/to/ServerTLSCert1 + - Host: raft2.example.com + Port: 7050 + ClientTLSCert: path/to/ClientTLSCert2 + ServerTLSCert: path/to/ServerTLSCert2 + + # Options to be specified for all the etcd/raft nodes. The values here + # are the defaults for all new channels and can be modified on a + # per-channel basis via configuration updates. + Options: + # TickInterval is the time interval between two Node.Tick invocations. + TickInterval: 500ms + + # ElectionTick is the number of Node.Tick invocations that must pass + # between elections. That is, if a follower does not receive any + # message from the leader of current term before ElectionTick has + # elapsed, it will become candidate and start an election. + # ElectionTick must be greater than HeartbeatTick. + ElectionTick: 10 + + # HeartbeatTick is the number of Node.Tick invocations that must + # pass between heartbeats. That is, a leader sends heartbeat + # messages to maintain its leadership every HeartbeatTick ticks. + HeartbeatTick: 1 + + # MaxInflightBlocks limits the max number of in-flight append messages + # during optimistic replication phase. + MaxInflightBlocks: 5 + + # SnapshotIntervalSize defines number of bytes per which a snapshot is taken + SnapshotIntervalSize: 16 MB + + # Organizations lists the orgs participating on the orderer side of the + # network. + Organizations: + + # Policies defines the set of policies at this level of the config tree + # For Orderer policies, their canonical path is + # /Channel/Orderer/ + Policies: + Readers: + Type: ImplicitMeta + Rule: "ANY Readers" + Writers: + Type: ImplicitMeta + Rule: "ANY Writers" + Admins: + Type: ImplicitMeta + Rule: "MAJORITY Admins" + # BlockValidation specifies what signatures must be included in the block + # from the orderer for the peer to validate it. + BlockValidation: + Type: ImplicitMeta + Rule: "ANY Writers" + + # Capabilities describes the orderer level capabilities, see the + # dedicated Capabilities section elsewhere in this file for a full + # description + Capabilities: + <<: *OrdererCapabilities + +################################################################################ +# +# CHANNEL +# +# This section defines the values to encode into a config transaction or +# genesis block for channel related parameters. +# +################################################################################ +Channel: &ChannelDefaults + # Policies defines the set of policies at this level of the config tree + # For Channel policies, their canonical path is + # /Channel/ + Policies: + # Who may invoke the 'Deliver' API + Readers: + Type: ImplicitMeta + Rule: "ANY Readers" + # Who may invoke the 'Broadcast' API + Writers: + Type: ImplicitMeta + Rule: "ANY Writers" + # By default, who may modify elements at this config level + Admins: + Type: ImplicitMeta + Rule: "MAJORITY Admins" + + + # Capabilities describes the channel level capabilities, see the + # dedicated Capabilities section elsewhere in this file for a full + # description + Capabilities: + <<: *ChannelCapabilities + +################################################################################ +# +# PROFILES +# +# Different configuration profiles may be encoded here to be specified as +# parameters to the configtxgen tool. The profiles which specify consortiums +# are to be used for generating the orderer genesis block. With the correct +# consortium members defined in the orderer genesis block, channel creation +# requests may be generated with only the org member names and a consortium +# name. +# +################################################################################ +Profiles: + + # SampleSingleMSPSolo defines a configuration which uses the Solo orderer, + # and contains a single MSP definition (the MSP sampleconfig). + # The Consortium SampleConsortium has only a single member, SampleOrg. + SampleSingleMSPSolo: + <<: *ChannelDefaults + Orderer: + <<: *OrdererDefaults + Organizations: + - *SampleOrg + Consortiums: + SampleConsortium: + Organizations: + - *SampleOrg + + # SampleSingleMSPKafka defines a configuration that differs from the + # SampleSingleMSPSolo one only in that it uses the Kafka-based orderer. + SampleSingleMSPKafka: + <<: *ChannelDefaults + Orderer: + <<: *OrdererDefaults + OrdererType: kafka + Organizations: + - *SampleOrg + Consortiums: + SampleConsortium: + Organizations: + - *SampleOrg + + # SampleInsecureSolo defines a configuration which uses the Solo orderer, + # contains no MSP definitions, and allows all transactions and channel + # creation requests for the consortium SampleConsortium. + SampleInsecureSolo: + <<: *ChannelDefaults + Orderer: + <<: *OrdererDefaults + Consortiums: + SampleConsortium: + Organizations: + + # SampleInsecureKafka defines a configuration that differs from the + # SampleInsecureSolo one only in that it uses the Kafka-based orderer. + SampleInsecureKafka: + <<: *ChannelDefaults + Orderer: + <<: *OrdererDefaults + OrdererType: kafka + Consortiums: + SampleConsortium: + Organizations: + + # SampleDevModeSolo defines a configuration which uses the Solo orderer, + # contains the sample MSP as both orderer and consortium member, and + # requires only basic membership for admin privileges. It also defines + # an Application on the ordering system channel, which should usually + # be avoided. + SampleDevModeSolo: + <<: *ChannelDefaults + Orderer: + <<: *OrdererDefaults + Organizations: + - <<: *SampleOrg + Policies: + <<: *SampleOrgPolicies + Admins: + Type: Signature + Rule: "OR('SampleOrg.member')" + Application: + <<: *ApplicationDefaults + Organizations: + - <<: *SampleOrg + Policies: + <<: *SampleOrgPolicies + Admins: + Type: Signature + Rule: "OR('SampleOrg.member')" + Consortiums: + SampleConsortium: + Organizations: + - <<: *SampleOrg + Policies: + <<: *SampleOrgPolicies + Admins: + Type: Signature + Rule: "OR('SampleOrg.member')" + + # SampleDevModeKafka defines a configuration that differs from the + # SampleDevModeSolo one only in that it uses the Kafka-based orderer. + SampleDevModeKafka: + <<: *ChannelDefaults + Orderer: + <<: *OrdererDefaults + OrdererType: kafka + Organizations: + - <<: *SampleOrg + Policies: + <<: *SampleOrgPolicies + Admins: + Type: Signature + Rule: "OR('SampleOrg.member')" + Application: + <<: *ApplicationDefaults + Organizations: + - <<: *SampleOrg + Policies: + <<: *SampleOrgPolicies + Admins: + Type: Signature + Rule: "OR('SampleOrg.member')" + Consortiums: + SampleConsortium: + Organizations: + - <<: *SampleOrg + Policies: + <<: *SampleOrgPolicies + Admins: + Type: Signature + Rule: "OR('SampleOrg.member')" + + # SampleSingleMSPChannel defines a channel with only the sample org as a + # member. It is designed to be used in conjunction with SampleSingleMSPSolo + # and SampleSingleMSPKafka orderer profiles. Note, for channel creation + # profiles, only the 'Application' section and consortium # name are + # considered. + SampleSingleMSPChannel: + <<: *ChannelDefaults + Consortium: SampleConsortium + Application: + <<: *ApplicationDefaults + Organizations: + - <<: *SampleOrg + + # SampleDevModeEtcdRaft defines a configuration that differs from the + # SampleDevModeSolo one only in that it uses the etcd/raft-based orderer. + SampleDevModeEtcdRaft: + <<: *ChannelDefaults + Orderer: + <<: *OrdererDefaults + OrdererType: etcdraft + Organizations: + - <<: *SampleOrg + Policies: + <<: *SampleOrgPolicies + Admins: + Type: Signature + Rule: "OR('SampleOrg.member')" + Application: + <<: *ApplicationDefaults + Organizations: + - <<: *SampleOrg + Policies: + <<: *SampleOrgPolicies + Admins: + Type: Signature + Rule: "OR('SampleOrg.member')" + Consortiums: + SampleConsortium: + Organizations: + - <<: *SampleOrg + Policies: + <<: *SampleOrgPolicies + Admins: + Type: Signature + Rule: "OR('SampleOrg.member')" + + # SampleAppChannelInsecureSolo defines an application channel configuration + # which uses the Solo orderer and contains no MSP definitions. + SampleAppChannelInsecureSolo: + <<: *ChannelDefaults + Orderer: + <<: *OrdererDefaults + Application: + <<: *ApplicationDefaults + + # SampleAppChannelEtcdRaft defines an application channel configuration + # that uses the etcd/raft-based orderer. + SampleAppChannelEtcdRaft: + <<: *ChannelDefaults + Orderer: + <<: *OrdererDefaults + OrdererType: etcdraft + Organizations: + - <<: *SampleOrg + Policies: + <<: *SampleOrgPolicies + Admins: + Type: Signature + Rule: "OR('SampleOrg.member')" + Application: + <<: *ApplicationDefaults + Organizations: + - <<: *SampleOrg + Policies: + <<: *SampleOrgPolicies + Admins: + Type: Signature + Rule: "OR('SampleOrg.member')" diff --git a/sample-network-multi-org/config/core.yaml b/sample-network-multi-org/config/core.yaml new file mode 100644 index 00000000..7809b001 --- /dev/null +++ b/sample-network-multi-org/config/core.yaml @@ -0,0 +1,800 @@ +# Copyright IBM Corp. All Rights Reserved. +# +# SPDX-License-Identifier: Apache-2.0 +# + +############################################################################### +# +# Peer section +# +############################################################################### +peer: + + # The peer id provides a name for this peer instance and is used when + # naming docker resources. + id: jdoe + + # The networkId allows for logical separation of networks and is used when + # naming docker resources. + networkId: dev + + # The Address at local network interface this Peer will listen on. + # By default, it will listen on all network interfaces + listenAddress: 0.0.0.0:7051 + + # The endpoint this peer uses to listen for inbound chaincode connections. + # If this is commented-out, the listen address is selected to be + # the peer's address (see below) with port 7052 + # chaincodeListenAddress: 0.0.0.0:7052 + + # The endpoint the chaincode for this peer uses to connect to the peer. + # If this is not specified, the chaincodeListenAddress address is selected. + # And if chaincodeListenAddress is not specified, address is selected from + # peer address (see below). If specified peer address is invalid then it + # will fallback to the auto detected IP (local IP) regardless of the peer + # addressAutoDetect value. + # chaincodeAddress: 0.0.0.0:7052 + + # When used as peer config, this represents the endpoint to other peers + # in the same organization. For peers in other organization, see + # gossip.externalEndpoint for more info. + # When used as CLI config, this means the peer's endpoint to interact with + address: 0.0.0.0:7051 + + # Whether the Peer should programmatically determine its address + # This case is useful for docker containers. + # When set to true, will override peer address. + addressAutoDetect: false + + # Settings for the Peer's gateway server. + gateway: + # Whether the gateway is enabled for this Peer. + enabled: true + # endorsementTimeout is the duration the gateway waits for a response + # from other endorsing peers before returning a timeout error to the client. + endorsementTimeout: 30s + # broadcastTimeout is the duration the gateway waits for a response + # from ordering nodes before returning a timeout error to the client. + broadcastTimeout: 30s + # dialTimeout is the duration the gateway waits for a connection + # to other network nodes. + dialTimeout: 2m + + + # Keepalive settings for peer server and clients + keepalive: + # Interval is the duration after which if the server does not see + # any activity from the client it pings the client to see if it's alive + interval: 7200s + # Timeout is the duration the server waits for a response + # from the client after sending a ping before closing the connection + timeout: 20s + # MinInterval is the minimum permitted time between client pings. + # If clients send pings more frequently, the peer server will + # disconnect them + minInterval: 60s + # Client keepalive settings for communicating with other peer nodes + client: + # Interval is the time between pings to peer nodes. This must + # greater than or equal to the minInterval specified by peer + # nodes + interval: 60s + # Timeout is the duration the client waits for a response from + # peer nodes before closing the connection + timeout: 20s + # DeliveryClient keepalive settings for communication with ordering + # nodes. + deliveryClient: + # Interval is the time between pings to ordering nodes. This must + # greater than or equal to the minInterval specified by ordering + # nodes. + interval: 60s + # Timeout is the duration the client waits for a response from + # ordering nodes before closing the connection + timeout: 20s + + + # Gossip related configuration + gossip: + # Bootstrap set to initialize gossip with. + # This is a list of other peers that this peer reaches out to at startup. + # Important: The endpoints here have to be endpoints of peers in the same + # organization, because the peer would refuse connecting to these endpoints + # unless they are in the same organization as the peer. + bootstrap: 127.0.0.1:7051 + + # NOTE: orgLeader and useLeaderElection parameters are mutual exclusive. + # Setting both to true would result in the termination of the peer + # since this is undefined state. If the peers are configured with + # useLeaderElection=false, make sure there is at least 1 peer in the + # organization that its orgLeader is set to true. + + # Defines whenever peer will initialize dynamic algorithm for + # "leader" selection, where leader is the peer to establish + # connection with ordering service and use delivery protocol + # to pull ledger blocks from ordering service. + useLeaderElection: false + # Statically defines peer to be an organization "leader", + # where this means that current peer will maintain connection + # with ordering service and disseminate block across peers in + # its own organization. Multiple peers or all peers in an organization + # may be configured as org leaders, so that they all pull + # blocks directly from ordering service. + orgLeader: true + + # Interval for membershipTracker polling + membershipTrackerInterval: 5s + + # Overrides the endpoint that the peer publishes to peers + # in its organization. For peers in foreign organizations + # see 'externalEndpoint' + endpoint: + # Maximum count of blocks stored in memory + maxBlockCountToStore: 10 + # Max time between consecutive message pushes(unit: millisecond) + maxPropagationBurstLatency: 10ms + # Max number of messages stored until a push is triggered to remote peers + maxPropagationBurstSize: 10 + # Number of times a message is pushed to remote peers + propagateIterations: 1 + # Number of peers selected to push messages to + propagatePeerNum: 3 + # Determines frequency of pull phases(unit: second) + # Must be greater than digestWaitTime + responseWaitTime + pullInterval: 4s + # Number of peers to pull from + pullPeerNum: 3 + # Determines frequency of pulling state info messages from peers(unit: second) + requestStateInfoInterval: 4s + # Determines frequency of pushing state info messages to peers(unit: second) + publishStateInfoInterval: 4s + # Maximum time a stateInfo message is kept until expired + stateInfoRetentionInterval: + # Time from startup certificates are included in Alive messages(unit: second) + publishCertPeriod: 10s + # Should we skip verifying block messages or not (currently not in use) + skipBlockVerification: false + # Dial timeout(unit: second) + dialTimeout: 3s + # Connection timeout(unit: second) + connTimeout: 2s + # Buffer size of received messages + recvBuffSize: 20 + # Buffer size of sending messages + sendBuffSize: 200 + # Time to wait before pull engine processes incoming digests (unit: second) + # Should be slightly smaller than requestWaitTime + digestWaitTime: 1s + # Time to wait before pull engine removes incoming nonce (unit: milliseconds) + # Should be slightly bigger than digestWaitTime + requestWaitTime: 1500ms + # Time to wait before pull engine ends pull (unit: second) + responseWaitTime: 2s + # Alive check interval(unit: second) + aliveTimeInterval: 5s + # Alive expiration timeout(unit: second) + aliveExpirationTimeout: 25s + # Reconnect interval(unit: second) + reconnectInterval: 25s + # Max number of attempts to connect to a peer + maxConnectionAttempts: 120 + # Message expiration factor for alive messages + msgExpirationFactor: 20 + # This is an endpoint that is published to peers outside of the organization. + # If this isn't set, the peer will not be known to other organizations and will not be exposed via service discovery. + externalEndpoint: + # Leader election service configuration + election: + # Longest time peer waits for stable membership during leader election startup (unit: second) + startupGracePeriod: 15s + # Interval gossip membership samples to check its stability (unit: second) + membershipSampleInterval: 1s + # Time passes since last declaration message before peer decides to perform leader election (unit: second) + leaderAliveThreshold: 10s + # Time between peer sends propose message and declares itself as a leader (sends declaration message) (unit: second) + leaderElectionDuration: 5s + + pvtData: + # pullRetryThreshold determines the maximum duration of time private data corresponding for a given block + # would be attempted to be pulled from peers until the block would be committed without the private data + pullRetryThreshold: 60s + # As private data enters the transient store, it is associated with the peer's ledger's height at that time. + # transientstoreMaxBlockRetention defines the maximum difference between the current ledger's height upon commit, + # and the private data residing inside the transient store that is guaranteed not to be purged. + # Private data is purged from the transient store when blocks with sequences that are multiples + # of transientstoreMaxBlockRetention are committed. + transientstoreMaxBlockRetention: 1000 + # pushAckTimeout is the maximum time to wait for an acknowledgement from each peer + # at private data push at endorsement time. + pushAckTimeout: 3s + # Block to live pulling margin, used as a buffer + # to prevent peer from trying to pull private data + # from peers that is soon to be purged in next N blocks. + # This helps a newly joined peer catch up to current + # blockchain height quicker. + btlPullMargin: 10 + # the process of reconciliation is done in an endless loop, while in each iteration reconciler tries to + # pull from the other peers the most recent missing blocks with a maximum batch size limitation. + # reconcileBatchSize determines the maximum batch size of missing private data that will be reconciled in a + # single iteration. + reconcileBatchSize: 10 + # reconcileSleepInterval determines the time reconciler sleeps from end of an iteration until the beginning + # of the next reconciliation iteration. + reconcileSleepInterval: 1m + # reconciliationEnabled is a flag that indicates whether private data reconciliation is enable or not. + reconciliationEnabled: true + # skipPullingInvalidTransactionsDuringCommit is a flag that indicates whether pulling of invalid + # transaction's private data from other peers need to be skipped during the commit time and pulled + # only through reconciler. + skipPullingInvalidTransactionsDuringCommit: false + # implicitCollectionDisseminationPolicy specifies the dissemination policy for the peer's own implicit collection. + # When a peer endorses a proposal that writes to its own implicit collection, below values override the default values + # for disseminating private data. + # Note that it is applicable to all channels the peer has joined. The implication is that requiredPeerCount has to + # be smaller than the number of peers in a channel that has the lowest numbers of peers from the organization. + implicitCollectionDisseminationPolicy: + # requiredPeerCount defines the minimum number of eligible peers to which the peer must successfully + # disseminate private data for its own implicit collection during endorsement. Default value is 0. + requiredPeerCount: 0 + # maxPeerCount defines the maximum number of eligible peers to which the peer will attempt to + # disseminate private data for its own implicit collection during endorsement. Default value is 1. + maxPeerCount: 1 + + # Gossip state transfer related configuration + state: + # indicates whenever state transfer is enabled or not + # default value is false, i.e. state transfer is active + # and takes care to sync up missing blocks allowing + # lagging peer to catch up to speed with rest network. + # Keep in mind that when peer.gossip.useLeaderElection is true + # and there are several peers in the organization, + # or peer.gossip.useLeaderElection is false alongside with + # peer.gossip.orgleader being false, the peer's ledger may lag behind + # the rest of the peers and will never catch up due to state transfer + # being disabled. + enabled: false + # checkInterval interval to check whether peer is lagging behind enough to + # request blocks via state transfer from another peer. + checkInterval: 10s + # responseTimeout amount of time to wait for state transfer response from + # other peers + responseTimeout: 3s + # batchSize the number of blocks to request via state transfer from another peer + batchSize: 10 + # blockBufferSize reflects the size of the re-ordering buffer + # which captures blocks and takes care to deliver them in order + # down to the ledger layer. The actual buffer size is bounded between + # 0 and 2*blockBufferSize, each channel maintains its own buffer + blockBufferSize: 20 + # maxRetries maximum number of re-tries to ask + # for single state transfer request + maxRetries: 3 + + # TLS Settings + tls: + # Require server-side TLS + enabled: false + # Require client certificates / mutual TLS for inbound connections. + # Note that clients that are not configured to use a certificate will + # fail to connect to the peer. + clientAuthRequired: false + # X.509 certificate used for TLS server + cert: + file: tls/server.crt + # Private key used for TLS server + key: + file: tls/server.key + # rootcert.file represents the trusted root certificate chain used for verifying certificates + # of other nodes during outbound connections. + # It is not required to be set, but can be used to augment the set of TLS CA certificates + # available from the MSPs of each channel’s configuration. + rootcert: + file: tls/ca.crt + # If mutual TLS is enabled, clientRootCAs.files contains a list of additional root certificates + # used for verifying certificates of client connections. + # It augments the set of TLS CA certificates available from the MSPs of each channel’s configuration. + # Minimally, set your organization's TLS CA root certificate so that the peer can receive join channel requests. + clientRootCAs: + files: + - tls/ca.crt + # Private key used for TLS when making client connections. + # If not set, peer.tls.key.file will be used instead + clientKey: + file: + # X.509 certificate used for TLS when making client connections. + # If not set, peer.tls.cert.file will be used instead + clientCert: + file: + + # Authentication contains configuration parameters related to authenticating + # client messages + authentication: + # the acceptable difference between the current server time and the + # client's time as specified in a client request message + timewindow: 15m + + # Path on the file system where peer will store data (eg ledger). This + # location must be access control protected to prevent unintended + # modification that might corrupt the peer operations. + # The path may be relative to FABRIC_CFG_PATH or an absolute path. + fileSystemPath: /var/hyperledger/production + + # BCCSP (Blockchain crypto provider): Select which crypto implementation or + # library to use + BCCSP: + Default: SW + # Settings for the SW crypto provider (i.e. when DEFAULT: SW) + SW: + # TODO: The default Hash and Security level needs refactoring to be + # fully configurable. Changing these defaults requires coordination + # SHA2 is hardcoded in several places, not only BCCSP + Hash: SHA2 + Security: 256 + # Location of Key Store + FileKeyStore: + # If "", defaults to 'mspConfigPath'/keystore + KeyStore: + # Settings for the PKCS#11 crypto provider (i.e. when DEFAULT: PKCS11) + PKCS11: + # Location of the PKCS11 module library + Library: + # Token Label + Label: + # User PIN + Pin: + Hash: + Security: + SoftwareVerify: + Immutable: + AltID: + KeyIds: + + # Path on the file system where peer will find MSP local configurations + # The path may be relative to FABRIC_CFG_PATH or an absolute path. + mspConfigPath: msp + + # Identifier of the local MSP + # ----!!!!IMPORTANT!!!-!!!IMPORTANT!!!-!!!IMPORTANT!!!!---- + # Deployers need to change the value of the localMspId string. + # In particular, the name of the local MSP ID of a peer needs + # to match the name of one of the MSPs in each of the channel + # that this peer is a member of. Otherwise this peer's messages + # will not be identified as valid by other nodes. + localMspId: SampleOrg + + # CLI common client config options + client: + # connection timeout + connTimeout: 3s + + # Delivery service related config + deliveryclient: + # Enables this peer to disseminate blocks it pulled from the ordering service + # via gossip. + # Note that 'gossip.state.enabled' controls point to point block replication + # of blocks committed in the past. + blockGossipEnabled: true + # It sets the total time the delivery service may spend in reconnection + # attempts until its retry logic gives up and returns an error, + # ignored if peer is a static leader + reconnectTotalTimeThreshold: 3600s + + # It sets the delivery service <-> ordering service node connection timeout + connTimeout: 3s + + # It sets the delivery service maximal delay between consecutive retries. + # Time between retries will have exponential backoff until hitting this threshold. + reConnectBackoffThreshold: 3600s + + # A list of orderer endpoint addresses which should be overridden + # when found in channel configurations. + addressOverrides: + # - from: + # to: + # caCertsFile: + # - from: + # to: + # caCertsFile: + + # Type for the local MSP - by default it's of type bccsp + localMspType: bccsp + + # Used with Go profiling tools only in none production environment. In + # production, it should be disabled (eg enabled: false) + profile: + enabled: false + listenAddress: 0.0.0.0:6060 + + # Handlers defines custom handlers that can filter and mutate + # objects passing within the peer, such as: + # Auth filter - reject or forward proposals from clients + # Decorators - append or mutate the chaincode input passed to the chaincode + # Endorsers - Custom signing over proposal response payload and its mutation + # Valid handler definition contains: + # - A name which is a factory method name defined in + # core/handlers/library/library.go for statically compiled handlers + # - library path to shared object binary for pluggable filters + # Auth filters and decorators are chained and executed in the order that + # they are defined. For example: + # authFilters: + # - + # name: FilterOne + # library: /opt/lib/filter.so + # - + # name: FilterTwo + # decorators: + # - + # name: DecoratorOne + # - + # name: DecoratorTwo + # library: /opt/lib/decorator.so + # Endorsers are configured as a map that its keys are the endorsement system chaincodes that are being overridden. + # Below is an example that overrides the default ESCC and uses an endorsement plugin that has the same functionality + # as the default ESCC. + # If the 'library' property is missing, the name is used as the constructor method in the builtin library similar + # to auth filters and decorators. + # endorsers: + # escc: + # name: DefaultESCC + # library: /etc/hyperledger/fabric/plugin/escc.so + handlers: + authFilters: + - + name: DefaultAuth + - + name: ExpirationCheck # This filter checks identity x509 certificate expiration + decorators: + - + name: DefaultDecorator + endorsers: + escc: + name: DefaultEndorsement + library: + validators: + vscc: + name: DefaultValidation + library: + + # library: /etc/hyperledger/fabric/plugin/escc.so + # Number of goroutines that will execute transaction validation in parallel. + # By default, the peer chooses the number of CPUs on the machine. Set this + # variable to override that choice. + # NOTE: overriding this value might negatively influence the performance of + # the peer so please change this value only if you know what you're doing + validatorPoolSize: + + # The discovery service is used by clients to query information about peers, + # such as - which peers have joined a certain channel, what is the latest + # channel config, and most importantly - given a chaincode and a channel, + # what possible sets of peers satisfy the endorsement policy. + discovery: + enabled: true + # Whether the authentication cache is enabled or not. + authCacheEnabled: true + # The maximum size of the cache, after which a purge takes place + authCacheMaxSize: 1000 + # The proportion (0 to 1) of entries that remain in the cache after the cache is purged due to overpopulation + authCachePurgeRetentionRatio: 0.75 + # Whether to allow non-admins to perform non channel scoped queries. + # When this is false, it means that only peer admins can perform non channel scoped queries. + orgMembersAllowedAccess: false + + # Limits is used to configure some internal resource limits. + limits: + # Concurrency limits the number of concurrently running requests to a service on each peer. + # Currently this option is only applied to endorser service and deliver service. + # When the property is missing or the value is 0, the concurrency limit is disabled for the service. + concurrency: + # endorserService limits concurrent requests to endorser service that handles chaincode deployment, query and invocation, + # including both user chaincodes and system chaincodes. + endorserService: 2500 + # deliverService limits concurrent event listeners registered to deliver service for blocks and transaction events. + deliverService: 2500 + # gatewayService limits concurrent requests to gateway service that handles the submission and evaluation of transactions. + gatewayService: 500 + + # Since all nodes should be consistent it is recommended to keep + # the default value of 100MB for MaxRecvMsgSize & MaxSendMsgSize + # Max message size in bytes GRPC server and client can receive + maxRecvMsgSize: 104857600 + # Max message size in bytes GRPC server and client can send + maxSendMsgSize: 104857600 + +############################################################################### +# +# VM section +# +############################################################################### +vm: + + # Endpoint of the vm management system. For docker can be one of the following in general + # unix:///var/run/docker.sock + # http://localhost:2375 + # https://localhost:2376 + # If you utilize external chaincode builders and don't need the default Docker chaincode builder, + # the endpoint should be unconfigured so that the peer's Docker health checker doesn't get registered. + endpoint: unix:///var/run/docker.sock + + # settings for docker vms + docker: + tls: + enabled: false + ca: + file: docker/ca.crt + cert: + file: docker/tls.crt + key: + file: docker/tls.key + + # Enables/disables the standard out/err from chaincode containers for + # debugging purposes + attachStdout: false + + # Parameters on creating docker container. + # Container may be efficiently created using ipam & dns-server for cluster + # NetworkMode - sets the networking mode for the container. Supported + # standard values are: `host`(default),`bridge`,`ipvlan`,`none`. + # Dns - a list of DNS servers for the container to use. + # Note: `Privileged` `Binds` `Links` and `PortBindings` properties of + # Docker Host Config are not supported and will not be used if set. + # LogConfig - sets the logging driver (Type) and related options + # (Config) for Docker. For more info, + # https://docs.docker.com/engine/admin/logging/overview/ + # Note: Set LogConfig using Environment Variables is not supported. + hostConfig: + NetworkMode: host + Dns: + # - 192.168.0.1 + LogConfig: + Type: json-file + Config: + max-size: "50m" + max-file: "5" + Memory: 2147483648 + +############################################################################### +# +# Chaincode section +# +############################################################################### +chaincode: + + # The id is used by the Chaincode stub to register the executing Chaincode + # ID with the Peer and is generally supplied through ENV variables + # the `path` form of ID is provided when installing the chaincode. + # The `name` is used for all other requests and can be any string. + id: + path: + name: + + # Generic builder environment, suitable for most chaincode types + builder: $(DOCKER_NS)/fabric-ccenv:$(TWO_DIGIT_VERSION) + + # Enables/disables force pulling of the base docker images (listed below) + # during user chaincode instantiation. + # Useful when using moving image tags (such as :latest) + pull: false + + golang: + # golang will never need more than baseos + runtime: $(DOCKER_NS)/fabric-baseos:$(TWO_DIGIT_VERSION) + + # whether or not golang chaincode should be linked dynamically + dynamicLink: false + + java: + # This is an image based on java:openjdk-8 with addition compiler + # tools added for java shim layer packaging. + # This image is packed with shim layer libraries that are necessary + # for Java chaincode runtime. + runtime: $(DOCKER_NS)/fabric-javaenv:$(TWO_DIGIT_VERSION) + + node: + # This is an image based on node:$(NODE_VER)-alpine + runtime: $(DOCKER_NS)/fabric-nodeenv:$(TWO_DIGIT_VERSION) + + # List of directories to treat as external builders and launchers for + # chaincode. The external builder detection processing will iterate over the + # builders in the order specified below. + # If you don't need to fallback to the default Docker builder, also unconfigure vm.endpoint above. + # To override this property via env variable use CORE_CHAINCODE_EXTERNALBUILDERS: [{name: x, path: dir1}, {name: y, path: dir2}] + # The path must be an absolute path. + externalBuilders: + - name: ccaas_builder + path: /opt/hyperledger/ccaas_builder + propagateEnvironment: + - CHAINCODE_AS_A_SERVICE_BUILDER_CONFIG + + + # The maximum duration to wait for the chaincode build and install process + # to complete. + installTimeout: 300s + + # Timeout duration for starting up a container and waiting for Register + # to come through. + startuptimeout: 300s + + # Timeout duration for Invoke and Init calls to prevent runaway. + # This timeout is used by all chaincodes in all the channels, including + # system chaincodes. + # Note that during Invoke, if the image is not available (e.g. being + # cleaned up when in development environment), the peer will automatically + # build the image, which might take more time. In production environment, + # the chaincode image is unlikely to be deleted, so the timeout could be + # reduced accordingly. + executetimeout: 30s + + # There are 2 modes: "dev" and "net". + # In dev mode, user runs the chaincode after starting peer from + # command line on local machine. + # In net mode, peer will run chaincode in a docker container. + mode: net + + # keepalive in seconds. In situations where the communication goes through a + # proxy that does not support keep-alive, this parameter will maintain connection + # between peer and chaincode. + # A value <= 0 turns keepalive off + keepalive: 0 + + # enabled system chaincodes + system: + _lifecycle: enable + cscc: enable + lscc: enable + qscc: enable + + # Logging section for the chaincode container + logging: + # Default level for all loggers within the chaincode container + level: info + # Override default level for the 'shim' logger + shim: warning + # Format for the chaincode container logs + format: '%{color}%{time:2006-01-02 15:04:05.000 MST} [%{module}] %{shortfunc} -> %{level:.4s} %{id:03x}%{color:reset} %{message}' + +############################################################################### +# +# Ledger section - ledger configuration encompasses both the blockchain +# and the state +# +############################################################################### +ledger: + + blockchain: + + state: + # stateDatabase - options are "goleveldb", "CouchDB" + # goleveldb - default state database stored in goleveldb. + # CouchDB - store state database in CouchDB + stateDatabase: goleveldb + # Limit on the number of records to return per query + totalQueryLimit: 100000 + couchDBConfig: + # It is recommended to run CouchDB on the same server as the peer, and + # not map the CouchDB container port to a server port in docker-compose. + # Otherwise proper security must be provided on the connection between + # CouchDB client (on the peer) and server. + couchDBAddress: 127.0.0.1:5984 + # This username must have read and write authority on CouchDB + username: + # The password is recommended to pass as an environment variable + # during start up (eg CORE_LEDGER_STATE_COUCHDBCONFIG_PASSWORD). + # If it is stored here, the file must be access control protected + # to prevent unintended users from discovering the password. + password: + # Number of retries for CouchDB errors + maxRetries: 3 + # Number of retries for CouchDB errors during peer startup. + # The delay between retries doubles for each attempt. + # Default of 10 retries results in 11 attempts over 2 minutes. + maxRetriesOnStartup: 10 + # CouchDB request timeout (unit: duration, e.g. 20s) + requestTimeout: 35s + # Limit on the number of records per each CouchDB query + # Note that chaincode queries are only bound by totalQueryLimit. + # Internally the chaincode may execute multiple CouchDB queries, + # each of size internalQueryLimit. + internalQueryLimit: 1000 + # Limit on the number of records per CouchDB bulk update batch + maxBatchUpdateSize: 1000 + # Create the _global_changes system database + # This is optional. Creating the global changes database will require + # additional system resources to track changes and maintain the database + createGlobalChangesDB: false + # CacheSize denotes the maximum mega bytes (MB) to be allocated for the in-memory state + # cache. Note that CacheSize needs to be a multiple of 32 MB. If it is not a multiple + # of 32 MB, the peer would round the size to the next multiple of 32 MB. + # To disable the cache, 0 MB needs to be assigned to the cacheSize. + cacheSize: 64 + + history: + # enableHistoryDatabase - options are true or false + # Indicates if the history of key updates should be stored. + # All history 'index' will be stored in goleveldb, regardless if using + # CouchDB or alternate database for the state. + enableHistoryDatabase: true + + pvtdataStore: + # the maximum db batch size for converting + # the ineligible missing data entries to eligible missing data entries + collElgProcMaxDbBatchSize: 5000 + # the minimum duration (in milliseconds) between writing + # two consecutive db batches for converting the ineligible missing data entries to eligible missing data entries + collElgProcDbBatchesInterval: 1000 + # The missing data entries are classified into two categories: + # (1) prioritized + # (2) deprioritized + # Initially, all missing data are in the prioritized list. When the + # reconciler is unable to fetch the missing data from other peers, + # the unreconciled missing data would be moved to the deprioritized list. + # The reconciler would retry deprioritized missing data after every + # deprioritizedDataReconcilerInterval (unit: minutes). Note that the + # interval needs to be greater than the reconcileSleepInterval + deprioritizedDataReconcilerInterval: 60m + # The frequency to purge private data (in number of blocks). + # Private data is purged from the peer's private data store based on + # the collection property blockToLive or an explicit chaincode call to PurgePrivateData(). + purgeInterval: 100 + # Whether to log private data keys purged from private data store (INFO level) when explicitly purged via chaincode + purgedKeyAuditLogging: true + + snapshots: + # Path on the file system where peer will store ledger snapshots + # The path must be an absolute path. + rootDir: /var/hyperledger/production/snapshots + +############################################################################### +# +# Operations section +# +############################################################################### +operations: + # host and port for the operations server + listenAddress: 127.0.0.1:9443 + + # TLS configuration for the operations endpoint + tls: + # TLS enabled + enabled: false + + # path to PEM encoded server certificate for the operations server + # The paths in this section may be relative to FABRIC_CFG_PATH or an absolute path. + cert: + file: + + # path to PEM encoded server key for the operations server + key: + file: + + # most operations service endpoints require client authentication when TLS + # is enabled. clientAuthRequired requires client certificate authentication + # at the TLS layer to access all resources. + clientAuthRequired: false + + # paths to PEM encoded ca certificates to trust for client authentication + clientRootCAs: + files: [] + +############################################################################### +# +# Metrics section +# +############################################################################### +metrics: + # metrics provider is one of statsd, prometheus, or disabled + provider: disabled + + # statsd configuration + statsd: + # network type: tcp or udp + network: udp + + # statsd server address + address: 127.0.0.1:8125 + + # the interval at which locally cached counters and gauges are pushed + # to statsd; timings are pushed immediately + writeInterval: 10s + + # prefix is prepended to all emitted statsd metrics + prefix: diff --git a/sample-network-multi-org/config/orderer.yaml b/sample-network-multi-org/config/orderer.yaml new file mode 100644 index 00000000..6c555f93 --- /dev/null +++ b/sample-network-multi-org/config/orderer.yaml @@ -0,0 +1,427 @@ +# Copyright IBM Corp. All Rights Reserved. +# +# SPDX-License-Identifier: Apache-2.0 +# + +--- +################################################################################ +# +# Orderer Configuration +# +# - This controls the type and configuration of the orderer. +# +################################################################################ +General: + # Listen address: The IP on which to bind to listen. + ListenAddress: 127.0.0.1 + + # Listen port: The port on which to bind to listen. + ListenPort: 7050 + + # TLS: TLS settings for the GRPC server. + TLS: + # Require server-side TLS + Enabled: false + # PrivateKey governs the file location of the private key of the TLS certificate. + PrivateKey: tls/server.key + # Certificate governs the file location of the server TLS certificate. + Certificate: tls/server.crt + # RootCAs contains a list of additional root certificates used for verifying certificates + # of other orderer nodes during outbound connections. + # It is not required to be set, but can be used to augment the set of TLS CA certificates + # available from the MSPs of each channel’s configuration. + RootCAs: + - tls/ca.crt + # Require client certificates / mutual TLS for inbound connections. + ClientAuthRequired: false + # If mutual TLS is enabled, ClientRootCAs contains a list of additional root certificates + # used for verifying certificates of client connections. + # It is not required to be set, but can be used to augment the set of TLS CA certificates + # available from the MSPs of each channel’s configuration. + ClientRootCAs: + # Keepalive settings for the GRPC server. + Keepalive: + # ServerMinInterval is the minimum permitted time between client pings. + # If clients send pings more frequently, the server will + # disconnect them. + ServerMinInterval: 60s + # ServerInterval is the time between pings to clients. + ServerInterval: 7200s + # ServerTimeout is the duration the server waits for a response from + # a client before closing the connection. + ServerTimeout: 20s + + # Since all nodes should be consistent it is recommended to keep + # the default value of 100MB for MaxRecvMsgSize & MaxSendMsgSize + # Max message size in bytes the GRPC server and client can receive + MaxRecvMsgSize: 104857600 + # Max message size in bytes the GRPC server and client can send + MaxSendMsgSize: 104857600 + + # Cluster settings for ordering service nodes that communicate with other ordering service nodes + # such as Raft based ordering service. + Cluster: + # SendBufferSize is the maximum number of messages in the egress buffer. + # Consensus messages are dropped if the buffer is full, and transaction + # messages are waiting for space to be freed. + SendBufferSize: 100 + + # ClientCertificate governs the file location of the client TLS certificate + # used to establish mutual TLS connections with other ordering service nodes. + # If not set, the server General.TLS.Certificate is re-used. + ClientCertificate: + # ClientPrivateKey governs the file location of the private key of the client TLS certificate. + # If not set, the server General.TLS.PrivateKey is re-used. + ClientPrivateKey: + + # The below 4 properties should be either set together, or be unset together. + # If they are set, then the orderer node uses a separate listener for intra-cluster + # communication. If they are unset, then the general orderer listener is used. + # This is useful if you want to use a different TLS server certificates on the + # client-facing and the intra-cluster listeners. + + # ListenPort defines the port on which the cluster listens to connections. + ListenPort: + # ListenAddress defines the IP on which to listen to intra-cluster communication. + ListenAddress: + # ServerCertificate defines the file location of the server TLS certificate used for intra-cluster + # communication. + ServerCertificate: + # ServerPrivateKey defines the file location of the private key of the TLS certificate. + ServerPrivateKey: + + # Bootstrap method: The method by which to obtain the bootstrap block + # system channel is specified. The option can be one of: + # "file" - path to a file containing the genesis block or config block of system channel + # "none" - allows an orderer to start without a system channel configuration + BootstrapMethod: file + + # Bootstrap file: The file containing the bootstrap block to use when + # initializing the orderer system channel and BootstrapMethod is set to + # "file". The bootstrap file can be the genesis block, and it can also be + # a config block for late bootstrap of some consensus methods like Raft. + # Generate a genesis block by updating $FABRIC_CFG_PATH/configtx.yaml and + # using configtxgen command with "-outputBlock" option. + # Defaults to file "genesisblock" (in $FABRIC_CFG_PATH directory) if not specified. + BootstrapFile: + + # LocalMSPDir is where to find the private crypto material needed by the + # orderer. It is set relative here as a default for dev environments but + # should be changed to the real location in production. + LocalMSPDir: msp + + # LocalMSPID is the identity to register the local MSP material with the MSP + # manager. IMPORTANT: The local MSP ID of an orderer needs to match the MSP + # ID of one of the organizations defined in the orderer system channel's + # /Channel/Orderer configuration. The sample organization defined in the + # sample configuration provided has an MSP ID of "SampleOrg". + LocalMSPID: SampleOrg + + # Enable an HTTP service for Go "pprof" profiling as documented at: + # https://golang.org/pkg/net/http/pprof + Profile: + Enabled: false + Address: 0.0.0.0:6060 + + # BCCSP configures the blockchain crypto service providers. + BCCSP: + # Default specifies the preferred blockchain crypto service provider + # to use. If the preferred provider is not available, the software + # based provider ("SW") will be used. + # Valid providers are: + # - SW: a software based crypto provider + # - PKCS11: a CA hardware security module crypto provider. + Default: SW + + # SW configures the software based blockchain crypto provider. + SW: + # TODO: The default Hash and Security level needs refactoring to be + # fully configurable. Changing these defaults requires coordination + # SHA2 is hardcoded in several places, not only BCCSP + Hash: SHA2 + Security: 256 + # Location of key store. If this is unset, a location will be + # chosen using: 'LocalMSPDir'/keystore + FileKeyStore: + KeyStore: + + # Settings for the PKCS#11 crypto provider (i.e. when DEFAULT: PKCS11) + PKCS11: + # Location of the PKCS11 module library + Library: + # Token Label + Label: + # User PIN + Pin: + Hash: + Security: + FileKeyStore: + KeyStore: + + # Authentication contains configuration parameters related to authenticating + # client messages + Authentication: + # the acceptable difference between the current server time and the + # client's time as specified in a client request message + TimeWindow: 15m + + +################################################################################ +# +# SECTION: File Ledger +# +# - This section applies to the configuration of the file ledger. +# +################################################################################ +FileLedger: + + # Location: The directory to store the blocks in. + Location: /var/hyperledger/production/orderer + +################################################################################ +# +# SECTION: Kafka +# +# - This section applies to the configuration of the Kafka-based orderer, and +# its interaction with the Kafka cluster. +# +################################################################################ +Kafka: + + # Retry: What do if a connection to the Kafka cluster cannot be established, + # or if a metadata request to the Kafka cluster needs to be repeated. + Retry: + # When a new channel is created, or when an existing channel is reloaded + # (in case of a just-restarted orderer), the orderer interacts with the + # Kafka cluster in the following ways: + # 1. It creates a Kafka producer (writer) for the Kafka partition that + # corresponds to the channel. + # 2. It uses that producer to post a no-op CONNECT message to that + # partition + # 3. It creates a Kafka consumer (reader) for that partition. + # If any of these steps fail, they will be re-attempted every + # for a total of , and then every + # for a total of until they succeed. + # Note that the orderer will be unable to write to or read from a + # channel until all of the steps above have been completed successfully. + ShortInterval: 5s + ShortTotal: 10m + LongInterval: 5m + LongTotal: 12h + # Affects the socket timeouts when waiting for an initial connection, a + # response, or a transmission. See Config.Net for more info: + # https://godoc.org/github.com/Shopify/sarama#Config + NetworkTimeouts: + DialTimeout: 10s + ReadTimeout: 10s + WriteTimeout: 10s + # Affects the metadata requests when the Kafka cluster is in the middle + # of a leader election.See Config.Metadata for more info: + # https://godoc.org/github.com/Shopify/sarama#Config + Metadata: + RetryBackoff: 250ms + RetryMax: 3 + # What to do if posting a message to the Kafka cluster fails. See + # Config.Producer for more info: + # https://godoc.org/github.com/Shopify/sarama#Config + Producer: + RetryBackoff: 100ms + RetryMax: 3 + # What to do if reading from the Kafka cluster fails. See + # Config.Consumer for more info: + # https://godoc.org/github.com/Shopify/sarama#Config + Consumer: + RetryBackoff: 2s + # Settings to use when creating Kafka topics. Only applies when + # Kafka.Version is v0.10.1.0 or higher + Topic: + # The number of Kafka brokers across which to replicate the topic + ReplicationFactor: 3 + # Verbose: Enable logging for interactions with the Kafka cluster. + Verbose: false + + # TLS: TLS settings for the orderer's connection to the Kafka cluster. + TLS: + + # Enabled: Use TLS when connecting to the Kafka cluster. + Enabled: false + + # PrivateKey: PEM-encoded private key the orderer will use for + # authentication. + PrivateKey: + # As an alternative to specifying the PrivateKey here, uncomment the + # following "File" key and specify the file name from which to load the + # value of PrivateKey. + #File: path/to/PrivateKey + + # Certificate: PEM-encoded signed public key certificate the orderer will + # use for authentication. + Certificate: + # As an alternative to specifying the Certificate here, uncomment the + # following "File" key and specify the file name from which to load the + # value of Certificate. + #File: path/to/Certificate + + # RootCAs: PEM-encoded trusted root certificates used to validate + # certificates from the Kafka cluster. + RootCAs: + # As an alternative to specifying the RootCAs here, uncomment the + # following "File" key and specify the file name from which to load the + # value of RootCAs. + #File: path/to/RootCAs + + # SASLPlain: Settings for using SASL/PLAIN authentication with Kafka brokers + SASLPlain: + # Enabled: Use SASL/PLAIN to authenticate with Kafka brokers + Enabled: false + # User: Required when Enabled is set to true + User: + # Password: Required when Enabled is set to true + Password: + + # Kafka protocol version used to communicate with the Kafka cluster brokers + # (defaults to 0.10.2.0 if not specified) + Version: + +################################################################################ +# +# Debug Configuration +# +# - This controls the debugging options for the orderer +# +################################################################################ +Debug: + + # BroadcastTraceDir when set will cause each request to the Broadcast service + # for this orderer to be written to a file in this directory + BroadcastTraceDir: + + # DeliverTraceDir when set will cause each request to the Deliver service + # for this orderer to be written to a file in this directory + DeliverTraceDir: + +################################################################################ +# +# Operations Configuration +# +# - This configures the operations server endpoint for the orderer +# +################################################################################ +Operations: + # host and port for the operations server + ListenAddress: 127.0.0.1:8443 + + # TLS configuration for the operations endpoint + TLS: + # TLS enabled + Enabled: false + + # Certificate is the location of the PEM encoded TLS certificate + Certificate: + + # PrivateKey points to the location of the PEM-encoded key + PrivateKey: + + # Most operations service endpoints require client authentication when TLS + # is enabled. ClientAuthRequired requires client certificate authentication + # at the TLS layer to access all resources. + ClientAuthRequired: false + + # Paths to PEM encoded ca certificates to trust for client authentication + ClientRootCAs: [] + +################################################################################ +# +# Metrics Configuration +# +# - This configures metrics collection for the orderer +# +################################################################################ +Metrics: + # The metrics provider is one of statsd, prometheus, or disabled + Provider: disabled + + # The statsd configuration + Statsd: + # network type: tcp or udp + Network: udp + + # the statsd server address + Address: 127.0.0.1:8125 + + # The interval at which locally cached counters and gauges are pushed + # to statsd; timings are pushed immediately + WriteInterval: 30s + + # The prefix is prepended to all emitted statsd metrics + Prefix: + +################################################################################ +# +# Admin Configuration +# +# - This configures the admin server endpoint for the orderer +# +################################################################################ +Admin: + # host and port for the admin server + ListenAddress: 127.0.0.1:9443 + + # TLS configuration for the admin endpoint + TLS: + # TLS enabled + Enabled: false + + # Certificate is the location of the PEM encoded TLS certificate + Certificate: + + # PrivateKey points to the location of the PEM-encoded key + PrivateKey: + + # Most admin service endpoints require client authentication when TLS + # is enabled. ClientAuthRequired requires client certificate authentication + # at the TLS layer to access all resources. + # + # NOTE: When TLS is enabled, the admin endpoint requires mutual TLS. The + # orderer will panic on startup if this value is set to false. + ClientAuthRequired: true + + # Paths to PEM encoded ca certificates to trust for client authentication + ClientRootCAs: [] + +################################################################################ +# +# Channel participation API Configuration +# +# - This provides the channel participation API configuration for the orderer. +# - Channel participation uses the ListenAddress and TLS settings of the Admin +# service. +# +################################################################################ +ChannelParticipation: + # Channel participation API is enabled. + Enabled: false + + # The maximum size of the request body when joining a channel. + MaxRequestBodySize: 1 MB + + +################################################################################ +# +# Consensus Configuration +# +# - This section contains config options for a consensus plugin. It is opaque +# to orderer, and completely up to consensus implementation to make use of. +# +################################################################################ +Consensus: + # The allowed key-value pairs here depend on consensus plugin. For etcd/raft, + # we use following options: + + # WALDir specifies the location at which Write Ahead Logs for etcd/raft are + # stored. Each channel will have its own subdir named after channel ID. + WALDir: /var/hyperledger/production/orderer/etcdraft/wal + + # SnapDir specifies the location at which snapshots for etcd/raft are + # stored. Each channel will have its own subdir named after channel ID. + SnapDir: /var/hyperledger/production/orderer/etcdraft/snapshot diff --git a/sample-network-multi-org/justfile b/sample-network-multi-org/justfile new file mode 100644 index 00000000..f2ab07c8 --- /dev/null +++ b/sample-network-multi-org/justfile @@ -0,0 +1,189 @@ +# +# Copyright contributors to the Hyperledgendary Full Stack Asset Transfer project +# +# SPDX-License-Identifier: Apache-2.0 +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at: +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# + +# Main justfile to run all the development scripts +# To install 'just' see https://github.com/casey/just#installation + + +############################################################################### +# +############################################################################### + +# Ensure all properties are exported as shell env-vars +set export + +# Use environment variables from the (git-ignored and hidden) .env files +set dotenv-load + +# set the current directory, and the location of the test dats +CWDIR := justfile_directory() + +_default: + @just -f {{justfile()}} --list + +# Run the check script to validate third party dependencies +check: + ${CWDIR}/scripts/check.sh + + +############################################################################### +# Environment and just parameters +############################################################################### + +CLUSTER_NAME := env_var_or_default("TEST_NETWORK_CLUSTER_NAME", "kind") +NAMESPACE := env_var_or_default("TEST_NETWORK_NAMESPACE", "test-network") +OPERATOR_IMAGE := env_var_or_default("TEST_NETWORK_OPERATOR_IMAGE", "ghcr.io/hyperledger-labs/fabric-operator:1.0") +FABRIC_VERSION := env_var_or_default("TEST_NETWORK_FABRIC_VERSION", "2.5.0-beta") +FABRIC_CA_VERSION := env_var_or_default("TEST_NETWORK_FABRIC_CA_VERSION", "1.5.6-beta3") +CA_IMAGE := env_var_or_default("TEST_NETWORK_CA_IMAGE", "hyperledger/fabric-ca") +CA_IMAGE_TAG := env_var_or_default("TEST_NETWORK_CA_IMAGE_TAG", FABRIC_CA_VERSION) +PEER_IMAGE := env_var_or_default("TEST_NETWORK_PEER_IMAGE", "ghcr.io/hyperledger-labs/k8s-fabric-peer") +PEER_IMAGE_TAG := env_var_or_default("TEST_NETWORK_PEER_IMAGE_TAG", "v0.8.0") +ORDERER_IMAGE := env_var_or_default("TEST_NETWORK_ORDERER_IMAGE", "hyperledger/fabric-orderer") +ORDERER_IMAGE_TAG := env_var_or_default("TEST_NETWORK_ORDERER_IMAGE_TAG", FABRIC_VERSION) +CHANNEL_NAME := env_var_or_default("TEST_NETWORK_CHANNEL_NAME", "mychannel") +CHAINCODE_NAME := env_var_or_default("TEST_NETWORK_CHAINCODE_NAME", "asset-transfer") +CHAINCODE_VERSION := env_var_or_default("TEST_NETWORK_CHAINCODE_VERSION", "v0.1.4") +CHAINCODE_SEQUENCE := env_var_or_default("TEST_NETWORK_CHAINCODE_SEQUENCE","1") +CHAINCODE_PKG_NAME := env_var_or_default("TEST_NETWORK_CHAINCODE_PKG_NAME","asset-transfer-typescript-v0.1.4.tgz") +CHAINCODE_PKG_URL := env_var_or_default("TEST_NETWORK_CHAINCODE_PKG_URL", "https://github.com/hyperledgendary/full-stack-asset-transfer-guide/releases/download/v0.1.4/" + CHAINCODE_PKG_NAME) + + +############################################################################### +# KIND / k8s targets +############################################################################### + +# Start a local KIND cluster with nginx ingress +kind: check unkind + scripts/kind_with_nginx.sh {{CLUSTER_NAME}} + +# Shut down the KIND cluster +unkind: + #!/usr/bin/env bash + kind delete cluster --name {{CLUSTER_NAME}} + + if docker inspect kind-registry &>/dev/null; then + echo "Stopping container registry" + docker kill kind-registry + docker rm kind-registry + fi + + +############################################################################### +# TL/DR actions. These don't exist, other than for convenience to run the +# entire flow without splitting across multiple "org" terminals. +############################################################################### + +start-network: + just start org0 + just start org1 + just start org2 + +# Shut down the test network and remove all certificates +destroy: + #!/usr/bin/env bash + rm -rf organizations/org0/enrollments && echo "org0 enrollments deleted" + rm -rf organizations/org1/enrollments && echo "org1 enrollments deleted" + rm -rf organizations/org2/enrollments && echo "org2 enrollments deleted" + rm -rf organizations/org0/chaincode && echo "org0 chaincode packages deleted" + rm -rf organizations/org1/chaincode && echo "org1 chaincode packages deleted" + rm -rf organizations/org2/chaincode && echo "org2 chaincode packages deleted" + + rm -rf channel-config/organizations && echo "consortium MSP deleted" + rm channel-config/{{CHANNEL_NAME}}_genesis_block.pb && echo {{CHANNEL_NAME}} " genesis block deleted" + + kubectl delete ns org0 --ignore-not-found=true + kubectl delete ns org1 --ignore-not-found=true + kubectl delete ns org2 --ignore-not-found=true + +# Check that all network services are running +check-network: + scripts/check-network.sh + + +############################################################################### +# Test Network +############################################################################### + +# Create the org namespace and start the operator for an org +init org: + #!/usr/bin/env bash + export NAMESPACE={{org}} # todo: move to an org directory? + scripts/start_operator.sh + +# Start the nodes for an org +start org: (init org) + organizations/{{org}}/start.sh + +# todo: clear enrollments, cc packages, etc. +# Stop the nodes for an org +stop org: + kubectl delete ns {{org}} --ignore-not-found=true + +# todo: + dependency (start org)? +# Enroll the users for an org +enroll org: + organizations/{{org}}/enroll.sh + + +############################################################################### +# Channel Construction +############################################################################### + +# Create the channel genesis block +create-genesis-block: check-network gather-msp + channel-config/create_genesis_block.sh + +# todo: include this? Which org is running the target? +# Export the MSP certificates for all orgs +gather-msp: + just export-msp org0 + just export-msp org1 + just export-msp org2 + +# Export org MSP certificates to the consortium organizer +export-msp org: + organizations/{{org}}/export_msp.sh + +# inspect the genesis block +inspect-genesis-block: + #!/usr/bin/env bash + configtxgen -inspectBlock channel-config/mychannel_genesis_block.pb | jq + +# Join an org to the channel +join org: + organizations/{{org}}/join_channel.sh + + +############################################################################### +# Chaincode and Gateway Appplication Development +############################################################################### + +# Install a smart contract on all peers in an org +install-cc org: + organizations/{{org}}/install_chaincode.sh + +# Display env for targeting a peer with the Fabric binaries +show-context msp org peer: + #!/usr/bin/env bash + . {{CWDIR}}/scripts/utils.sh + appear_as {{msp}} {{org}} {{peer}} + + # use export to load the peer context into the current environment: + # export $(just show-context Org1MSP org1 peer1) + printenv | egrep "CORE_PEER|FABRIC_|ORDERER_" | sort diff --git a/sample-network-multi-org/kind/cert-manager/.gitignore b/sample-network-multi-org/kind/cert-manager/.gitignore new file mode 100644 index 00000000..149f80c6 --- /dev/null +++ b/sample-network-multi-org/kind/cert-manager/.gitignore @@ -0,0 +1 @@ +ca-issuer-secret.yaml diff --git a/sample-network-multi-org/kind/cert-manager/ca-issuer-secret.yaml b/sample-network-multi-org/kind/cert-manager/ca-issuer-secret.yaml new file mode 100644 index 00000000..1e628a93 --- /dev/null +++ b/sample-network-multi-org/kind/cert-manager/ca-issuer-secret.yaml @@ -0,0 +1,22 @@ +apiVersion: v1 +data: + ca.crt: LS0tLS1CRUdJTiBDRVJUSUZJQ0FURS0tLS0tCk1JSURsakNDQW42Z0F3SUJBZ0lRSHJ4UFNoU1lJT3lraWJoV2lqRjdWakFOQmdrcWhraUc5dzBCQVFzRkFEQmwKTVRVd013WURWUVFLRXl4SmJuUmxjbTVoZEdsdmJtRnNJRUoxYzJsdVpYTnpJRTFoWTJocGJtVnpJRWx1WTI5eQpjRzl5WVhSbFpERXNNQ29HQTFVRUF3d2pLaTVzYjJOaGJHaHZMbk4wSUV0MVltVWdMeUJMU1U1RUlGUk1VeUJKCmMzTjFaWEl3SGhjTk1qSXhNVEl3TURNd016VXhXaGNOTWpNd01qRTRNRE13TXpVeFdqQmxNVFV3TXdZRFZRUUsKRXl4SmJuUmxjbTVoZEdsdmJtRnNJRUoxYzJsdVpYTnpJRTFoWTJocGJtVnpJRWx1WTI5eWNHOXlZWFJsWkRFcwpNQ29HQTFVRUF3d2pLaTVzYjJOaGJHaHZMbk4wSUV0MVltVWdMeUJMU1U1RUlGUk1VeUJKYzNOMVpYSXdnZ0VpCk1BMEdDU3FHU0liM0RRRUJBUVVBQTRJQkR3QXdnZ0VLQW9JQkFRRGlYSDhBbmo0MXRTa21wbEg0TUhMaW43bk0KZFFtWlppbEpUVHQwakdwRzhJK2xXcTUrcDd3NDhUNVJYTGNaNElIL0d1V1VKQ09adjYrRHg3WXBzTG9SYWVaagpXNHRGT3luYWdQL3lybTRDTjFKTjBXcTdKWis4ZVRzU1JIa3JCK3hodm1abHNzeE41YmNoRmhiNVZkdm81SVF5CjNYK1o2cm1QaDlCbkppckk4UTNNRmhTLzhHVUw3YzI2VnhkRGt6dS9HR0dXdEhySVJRZ3VEc2t6Znp2SjlQbkYKemhOalYrNXVoM0hTOEY1RUoyQ0xZc2VoRGRQSW95dGdmUSt3YVA5N3JIenp1M2ZuN0lMM0p0SGtDcy9Fekh5YQp0TzdmZTlwVVR5bGVXN1F0QUFmbFpLSHdBMUVMUytQMnNwbHBzT1lYV3hjUkQ5endoWC84UVN2aE1FT05BZ01CCkFBR2pRakJBTUE0R0ExVWREd0VCL3dRRUF3SUNwREFQQmdOVkhSTUJBZjhFQlRBREFRSC9NQjBHQTFVZERnUVcKQkJSaWNBVUQ4YkNtZmdQWTRZR1lralhiRlNxTXNEQU5CZ2txaGtpRzl3MEJBUXNGQUFPQ0FRRUFHbjZHblFIaAp3Qm9LdmhaTTcyT2pXUnFPYjJBWU1VaDhsclF1NGxSNUZoaFN5TXI1ejA5aUJjaXNMaFZPc1hpdTVrZWtsbHNoCkN5Nm94QTd4TnFHV1d6VCtqb2tGYUEzdzM0eFpDLzN5Mnh4c1dnMGZ6Z3BEc3QyK05Gai9hVHFGSWJ2ZW5ETjYKZ2crM1lDSXRGeXI5QmNFWTh6Yk0rNlV2QWF5RlNram9lNCtybUFOMHpwRUg0M3RaMmlRY010Qy9VVER3bkV2LwpVNnI1QmEvUUlSMDh1eHpJOGd0TnVPc2RlUnRGVy9kTHk0UHhwbXp0YkgzUnczTTJTMCs2ZS8zZkRNcWRKcVdUCmJFdWFWSEtLQlFXOWwzWjluYS9xdHJKM0Qzc0FYQ0pLbHdQN2orSkpFM3dHNFdEVTZUcHJnV0ZiQTNaVC9zTlkKY0sxZG5ZSTlkTnRWN1E9PQotLS0tLUVORCBDRVJUSUZJQ0FURS0tLS0tCg== + tls.crt: LS0tLS1CRUdJTiBDRVJUSUZJQ0FURS0tLS0tCk1JSURsakNDQW42Z0F3SUJBZ0lRSHJ4UFNoU1lJT3lraWJoV2lqRjdWakFOQmdrcWhraUc5dzBCQVFzRkFEQmwKTVRVd013WURWUVFLRXl4SmJuUmxjbTVoZEdsdmJtRnNJRUoxYzJsdVpYTnpJRTFoWTJocGJtVnpJRWx1WTI5eQpjRzl5WVhSbFpERXNNQ29HQTFVRUF3d2pLaTVzYjJOaGJHaHZMbk4wSUV0MVltVWdMeUJMU1U1RUlGUk1VeUJKCmMzTjFaWEl3SGhjTk1qSXhNVEl3TURNd016VXhXaGNOTWpNd01qRTRNRE13TXpVeFdqQmxNVFV3TXdZRFZRUUsKRXl4SmJuUmxjbTVoZEdsdmJtRnNJRUoxYzJsdVpYTnpJRTFoWTJocGJtVnpJRWx1WTI5eWNHOXlZWFJsWkRFcwpNQ29HQTFVRUF3d2pLaTVzYjJOaGJHaHZMbk4wSUV0MVltVWdMeUJMU1U1RUlGUk1VeUJKYzNOMVpYSXdnZ0VpCk1BMEdDU3FHU0liM0RRRUJBUVVBQTRJQkR3QXdnZ0VLQW9JQkFRRGlYSDhBbmo0MXRTa21wbEg0TUhMaW43bk0KZFFtWlppbEpUVHQwakdwRzhJK2xXcTUrcDd3NDhUNVJYTGNaNElIL0d1V1VKQ09adjYrRHg3WXBzTG9SYWVaagpXNHRGT3luYWdQL3lybTRDTjFKTjBXcTdKWis4ZVRzU1JIa3JCK3hodm1abHNzeE41YmNoRmhiNVZkdm81SVF5CjNYK1o2cm1QaDlCbkppckk4UTNNRmhTLzhHVUw3YzI2VnhkRGt6dS9HR0dXdEhySVJRZ3VEc2t6Znp2SjlQbkYKemhOalYrNXVoM0hTOEY1RUoyQ0xZc2VoRGRQSW95dGdmUSt3YVA5N3JIenp1M2ZuN0lMM0p0SGtDcy9Fekh5YQp0TzdmZTlwVVR5bGVXN1F0QUFmbFpLSHdBMUVMUytQMnNwbHBzT1lYV3hjUkQ5endoWC84UVN2aE1FT05BZ01CCkFBR2pRakJBTUE0R0ExVWREd0VCL3dRRUF3SUNwREFQQmdOVkhSTUJBZjhFQlRBREFRSC9NQjBHQTFVZERnUVcKQkJSaWNBVUQ4YkNtZmdQWTRZR1lralhiRlNxTXNEQU5CZ2txaGtpRzl3MEJBUXNGQUFPQ0FRRUFHbjZHblFIaAp3Qm9LdmhaTTcyT2pXUnFPYjJBWU1VaDhsclF1NGxSNUZoaFN5TXI1ejA5aUJjaXNMaFZPc1hpdTVrZWtsbHNoCkN5Nm94QTd4TnFHV1d6VCtqb2tGYUEzdzM0eFpDLzN5Mnh4c1dnMGZ6Z3BEc3QyK05Gai9hVHFGSWJ2ZW5ETjYKZ2crM1lDSXRGeXI5QmNFWTh6Yk0rNlV2QWF5RlNram9lNCtybUFOMHpwRUg0M3RaMmlRY010Qy9VVER3bkV2LwpVNnI1QmEvUUlSMDh1eHpJOGd0TnVPc2RlUnRGVy9kTHk0UHhwbXp0YkgzUnczTTJTMCs2ZS8zZkRNcWRKcVdUCmJFdWFWSEtLQlFXOWwzWjluYS9xdHJKM0Qzc0FYQ0pLbHdQN2orSkpFM3dHNFdEVTZUcHJnV0ZiQTNaVC9zTlkKY0sxZG5ZSTlkTnRWN1E9PQotLS0tLUVORCBDRVJUSUZJQ0FURS0tLS0tCg== + tls.key: LS0tLS1CRUdJTiBSU0EgUFJJVkFURSBLRVktLS0tLQpNSUlFb3dJQkFBS0NBUUVBNGx4L0FKNCtOYlVwSnFaUitEQnk0cCs1ekhVSm1XWXBTVTA3ZEl4cVJ2Q1BwVnF1CmZxZThPUEUrVVZ5M0dlQ0IveHJsbENRam1iK3ZnOGUyS2JDNkVXbm1ZMXVMUlRzcDJvRC84cTV1QWpkU1RkRnEKdXlXZnZIazdFa1I1S3dmc1liNW1aYkxNVGVXM0lSWVcrVlhiNk9TRU10MS9tZXE1ajRmUVp5WXF5UEVOekJZVQp2L0JsQyszTnVsY1hRNU03dnhoaGxyUjZ5RVVJTGc3Sk0zODd5ZlQ1eGM0VFkxZnVib2R4MHZCZVJDZGdpMkxICm9RM1R5S01yWUgwUHNHai9lNng4ODd0MzUreUM5eWJSNUFyUHhNeDhtclR1MzN2YVZFOHBYbHUwTFFBSDVXU2gKOEFOUkMwdmo5cktaYWJEbUYxc1hFUS9jOElWLy9FRXI0VEJEalFJREFRQUJBb0lCQUNpSkY5VXNnVWRzNGFtaQpMeHVhMFhmejBubmltNDEwMWYvaWJMczZTZTNhTmw4T0ZpRm9PRFNhUHVhakM4YitoVWtCc0FzUFRiREN1dE9HCmVBQ1BQVUxSREFqTzQrbko1bnpTalFNUWFYTE1KVmo2SDNyVUNmN2VWczIycFZ3blZ4VkoyMXhxNEZzeXY5Q1UKL0JnNlg5OGN6Tyt1NnFMTmZkMU9IT3ZiMGQyWnR0aG9yWWxlcUZ3anNjTnZBbUsveVFoc0VscDlQNE04RUhCdQpmWktlcStRWHp1SXdZcmI1dWRNMXVDWXhQUUk2WGo1dUlqTC9mcGVCenlMcEg4ZEJXRFpyUVFtRlFEcjhHbVltClZSb2xzYW5OYzlkQXBvQ3JDY1Fnekd3eFpmUm43eXFBTHN2dWtjNUIrK241dUdXenNpQmt0NHhDYno3emVSUWYKaW5sTDJxRUNnWUVBLzNQVFZGZXhjYi9td1NOd0p1QTVVdzZ0cHdjVjJrZ25LWjUybzJsc084R1FPempqUnU0Lwo1blRHbkVlWlo1Yk9XU0tic21TMmRjUVlLREhwTG9MZ0wrekRMNDNtVEJYbGxpQzlTNFB5SFFiSUNzQ3BqVDc5Ck1LVkFyTlZXMlJJR0VnMDZwVUJhMW14OFhZS2xraHNPZUpTWUZEQTF2OENuMHNQWmxFcEg4NGNDZ1lFQTR0aTEKR1FMdzZKZFRXcHpSaGJvSWdibm5RKzJ2Mi84VU1RRUw0M1B6UmNaWmd0TnU5NU1ERXEveWZyckdaeWhqVUlLQwpVRjVWUFE3VWdrc3c0RXdNWmxZZkQ5NGF3c05HSno5eTRKV2IxK3hIMnZuaGpJYlBEcEQ4VTJyZ2d3Y2crTUlFCkYwdTVSK2lMUHY1OFQ3MWJPNi83NXNMMzRNY2FaMjFFTXJUMWZVc0NnWUJpZEpiUDNCaWsrY3lMUmdoVXczajAKblNTcXlwMU9peDZrK05GSy9EZmQ5Q1dOM2NnakwzSnJkVGlUUlRsSDVxVFRUL1pvVkU3S3B2Q1VsV0FGTUNZTgo4cGZyL1NuMHl6KzRsQmZCUWpLUG8yeDRVSGRJM0MwamtaMlN2NHNBa09UTUVsTTNHODJtOVJzZHcxdmpLeEJ4Cnd2dTJWRHB6RkdMYVplZTNNc1gyZ3dLQmdRQytKamNQZ3lhYllSV08wL3JSWkpKeTQza1d1S3Q3OW9KZlhXZ3cKdmVZQzYvUG1OUU5FWmFmaXh6ZTJ3U3RFRjFmQWlkVmdOdUt1YnJyMWlMK3NsREtrcWJZWjMreUFxNTBua3dqaApkcWNPeE5HcW5XRlNJVUo1REZGbVB5VjR6OFgwbnZVODdjMmVtQy80bXV0ckQrZmt6V3lURDRVbWx0N3NLV3hNCk1PSENwd0tCZ0FVejJ2WWlVaHRET1k0TDNNV3NkaVRWeW16KzlmYXZ0d0Z1bnBCNEN5bC8xVm1ZODA0N0tvUTUKQzI3QlF0TGRmMFd5UmUvbWVQRi9EUWNtWlpKK0dDRHhpYkczZ2phMzgvdytDWlcrL3FNY3B4ckNhbUltNHZUYgoxcjNIUThDUCtNZE5TTUszaGRmNW9vMW9nUUdUdm5idkhIMjBPV0Vhazc2OFp5YUpYdmkwCi0tLS0tRU5EIFJTQSBQUklWQVRFIEtFWS0tLS0tCg== +kind: Secret +metadata: + annotations: + cert-manager.io/alt-names: "" + cert-manager.io/certificate-name: ca-issuer + cert-manager.io/common-name: '*.localho.st Kube / KIND TLS Issuer' + cert-manager.io/ip-sans: "" + cert-manager.io/issuer-group: cert-manager.io + cert-manager.io/issuer-kind: ClusterIssuer + cert-manager.io/issuer-name: root-tls-cert-issuer + cert-manager.io/uri-sans: "" + creationTimestamp: "2022-11-20T03:03:51Z" + name: ca-issuer-secret + namespace: cert-manager + resourceVersion: "644" + uid: 493e496e-9145-444b-9463-7e87687f9536 +type: kubernetes.io/tls diff --git a/sample-network-multi-org/kind/cert-manager/ca-issuer.yaml b/sample-network-multi-org/kind/cert-manager/ca-issuer.yaml new file mode 100644 index 00000000..7abe061d --- /dev/null +++ b/sample-network-multi-org/kind/cert-manager/ca-issuer.yaml @@ -0,0 +1,34 @@ +# see https://cert-manager.io/docs/configuration/selfsigned/#bootstrapping-ca-issuers + +--- +apiVersion: cert-manager.io/v1 +kind: Certificate +metadata: + name: ca-issuer +spec: + isCA: true + privateKey: + algorithm: RSA + encoding: PKCS1 + size: 2048 + commonName: "*.localho.st Kube / KIND TLS Issuer" + subject: + organizations: + - "International Business Machines Incorporated" + secretName: ca-issuer-secret + issuerRef: + name: root-tls-cert-issuer + kind: ClusterIssuer + group: cert-manager.io + +--- +apiVersion: cert-manager.io/v1 +kind: ClusterIssuer +metadata: + name: ca-issuer +spec: + ca: + secretName: ca-issuer-secret + + + diff --git a/sample-network-multi-org/kind/cert-manager/kustomization.yaml b/sample-network-multi-org/kind/cert-manager/kustomization.yaml new file mode 100644 index 00000000..9eab4a0c --- /dev/null +++ b/sample-network-multi-org/kind/cert-manager/kustomization.yaml @@ -0,0 +1,11 @@ +--- +apiVersion: kustomize.config.k8s.io/v1beta1 +kind: Kustomization +resources: + - root-tls-issuer.yaml + - ca-issuer.yaml + + # The CA issuer secret / cert is created by the KIND setup script, rather than + # in the kustomization. This allows for a certificate created by a previously + # configured KIND cluster to be re-used as the root CA. + # - ca-issuer-secret.yaml diff --git a/sample-network-multi-org/kind/cert-manager/root-tls-issuer.yaml b/sample-network-multi-org/kind/cert-manager/root-tls-issuer.yaml new file mode 100644 index 00000000..ed9678b7 --- /dev/null +++ b/sample-network-multi-org/kind/cert-manager/root-tls-issuer.yaml @@ -0,0 +1,7 @@ +--- +apiVersion: cert-manager.io/v1 +kind: ClusterIssuer +metadata: + name: root-tls-cert-issuer +spec: + selfSigned: {} diff --git a/sample-network-multi-org/kind/nginx/ingress-nginx-controller.yaml b/sample-network-multi-org/kind/nginx/ingress-nginx-controller.yaml new file mode 100644 index 00000000..6408d3f2 --- /dev/null +++ b/sample-network-multi-org/kind/nginx/ingress-nginx-controller.yaml @@ -0,0 +1,39 @@ +# +# Copyright contributors to the Hyperledger Fabric Operator project +# +# SPDX-License-Identifier: Apache-2.0 +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at: +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# +apiVersion: apps/v1 +kind: Deployment +metadata: + namespace: ingress-nginx + name: ingress-nginx-controller +spec: + template: + spec: + containers: + - name: controller + args: + - /nginx-ingress-controller + - --election-id=ingress-controller-leader + - --controller-class=k8s.io/ingress-nginx + - --ingress-class=nginx + - --configmap=$(POD_NAMESPACE)/ingress-nginx-controller + - --validating-webhook=:8443 + - --validating-webhook-certificate=/usr/local/certificates/cert + - --validating-webhook-key=/usr/local/certificates/key + - --watch-ingress-without-class=true + - --publish-status-address=localhost + - --enable-ssl-passthrough \ No newline at end of file diff --git a/sample-network-multi-org/kind/nginx/kustomization.yaml b/sample-network-multi-org/kind/nginx/kustomization.yaml new file mode 100644 index 00000000..8178699d --- /dev/null +++ b/sample-network-multi-org/kind/nginx/kustomization.yaml @@ -0,0 +1,26 @@ + +# +# Copyright contributors to the Hyperledger Fabric Operator project +# +# SPDX-License-Identifier: Apache-2.0 +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at: +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# +apiVersion: kustomize.config.k8s.io/v1beta1 +kind: Kustomization + +resources: + - https://github.com/kubernetes/ingress-nginx.git/deploy/static/provider/kind?ref=controller-v1.1.2 + +patchesStrategicMerge: + - ingress-nginx-controller.yaml \ No newline at end of file diff --git a/sample-network-multi-org/kind/operator/kustomization.yaml b/sample-network-multi-org/kind/operator/kustomization.yaml new file mode 100644 index 00000000..a775f9a0 --- /dev/null +++ b/sample-network-multi-org/kind/operator/kustomization.yaml @@ -0,0 +1,27 @@ +# +# Copyright contributors to the Hyperledger Fabric Operator project +# +# SPDX-License-Identifier: Apache-2.0 +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at: +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# +apiVersion: kustomize.config.k8s.io/v1beta1 +kind: Kustomization + +resources: + - https://github.com/hyperledger-labs/fabric-operator.git/config/crd + - operator-clusterrole.yaml + - operator-clusterrolebinding.yaml + - operator-serviceaccount.yaml + - operator-psp.yaml + - operator-manager.yaml diff --git a/sample-network-multi-org/kind/operator/operator-clusterrole.yaml b/sample-network-multi-org/kind/operator/operator-clusterrole.yaml new file mode 100644 index 00000000..3a775e76 --- /dev/null +++ b/sample-network-multi-org/kind/operator/operator-clusterrole.yaml @@ -0,0 +1,205 @@ +# +# Copyright contributors to the Hyperledger Fabric Operator project +# +# SPDX-License-Identifier: Apache-2.0 +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at: +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# +--- +apiVersion: rbac.authorization.k8s.io/v1 +kind: ClusterRole +metadata: + name: fabric-operator-role + labels: + release: "operator" + helm.sh/chart: "ibm-hlfsupport" + app.kubernetes.io/name: "ibm-hlfsupport" + app.kubernetes.io/instance: "ibm-hlfsupport" + app.kubernetes.io/managed-by: "ibm-hlfsupport-operator" +rules: + - apiGroups: + - extensions + resourceNames: + - ibm-hlfsupport-psp + resources: + - podsecuritypolicies + verbs: + - use + - apiGroups: + - apiextensions.k8s.io + resources: + - persistentvolumeclaims + - persistentvolumes + verbs: + - get + - list + - create + - update + - patch + - watch + - delete + - deletecollection + - apiGroups: + - apiextensions.k8s.io + resources: + - customresourcedefinitions + verbs: + - get + - apiGroups: + - route.openshift.io + resources: + - routes + - routes/custom-host + verbs: + - get + - list + - create + - update + - patch + - watch + - delete + - deletecollection + - apiGroups: + - "" + resources: + - pods + - pods/log + - persistentvolumeclaims + - persistentvolumes + - services + - endpoints + - events + - configmaps + - secrets + - nodes + - serviceaccounts + verbs: + - get + - list + - create + - update + - patch + - watch + - delete + - deletecollection + - apiGroups: + - "batch" + resources: + - jobs + verbs: + - get + - list + - create + - update + - patch + - watch + - delete + - deletecollection + - apiGroups: + - "authorization.openshift.io" + - "rbac.authorization.k8s.io" + resources: + - roles + - rolebindings + verbs: + - get + - list + - create + - update + - patch + - watch + - delete + - deletecollection + - bind + - escalate + - apiGroups: + - "" + resources: + - namespaces + verbs: + - get + - apiGroups: + - apps + resources: + - deployments + - daemonsets + - replicasets + - statefulsets + verbs: + - get + - list + - create + - update + - patch + - watch + - delete + - deletecollection + - apiGroups: + - monitoring.coreos.com + resources: + - servicemonitors + verbs: + - get + - create + - apiGroups: + - apps + resourceNames: + - ibm-hlfsupport-operator + resources: + - deployments/finalizers + verbs: + - update + - apiGroups: + - ibp.com + resources: + - ibpcas.ibp.com + - ibppeers.ibp.com + - ibporderers.ibp.com + - ibpconsoles.ibp.com + - ibpcas + - ibppeers + - ibporderers + - ibpconsoles + - ibpcas/finalizers + - ibppeers/finalizers + - ibporderers/finalizers + - ibpconsoles/finalizers + - ibpcas/status + - ibppeers/status + - ibporderers/status + - ibpconsoles/status + verbs: + - get + - list + - create + - update + - patch + - watch + - delete + - deletecollection + - apiGroups: + - extensions + - networking.k8s.io + - config.openshift.io + resources: + - ingresses + - networkpolicies + verbs: + - get + - list + - create + - update + - patch + - watch + - delete + - deletecollection diff --git a/sample-network-multi-org/kind/operator/operator-clusterrolebinding.yaml b/sample-network-multi-org/kind/operator/operator-clusterrolebinding.yaml new file mode 100644 index 00000000..34df0b68 --- /dev/null +++ b/sample-network-multi-org/kind/operator/operator-clusterrolebinding.yaml @@ -0,0 +1,42 @@ +# +# Copyright contributors to the Hyperledger Fabric Operator project +# +# SPDX-License-Identifier: Apache-2.0 +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at: +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# +--- +kind: ClusterRoleBinding +apiVersion: rbac.authorization.k8s.io/v1 +metadata: + name: fabric-operator-rolebinding + labels: + release: "operator" + helm.sh/chart: "ibm-hlfsupport" + app.kubernetes.io/name: "ibm-hlfsupport" + app.kubernetes.io/instance: "ibm-hlfsupport" + app.kubernetes.io/managed-by: "ibm-hlfsupport-operator" +subjects: + - kind: ServiceAccount + name: fabric-operator + namespace: org0 + - kind: ServiceAccount + name: fabric-operator + namespace: org1 + - kind: ServiceAccount + name: fabric-operator + namespace: org2 +roleRef: + apiGroup: rbac.authorization.k8s.io + kind: ClusterRole + name: fabric-operator-role diff --git a/sample-network-multi-org/kind/operator/operator-manager.yaml b/sample-network-multi-org/kind/operator/operator-manager.yaml new file mode 100644 index 00000000..3a967801 --- /dev/null +++ b/sample-network-multi-org/kind/operator/operator-manager.yaml @@ -0,0 +1,66 @@ +# +# Copyright contributors to the Hyperledger Fabric Operator project +# +# SPDX-License-Identifier: Apache-2.0 +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at: +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# +--- +apiVersion: apps/v1 +kind: Deployment +metadata: + name: fabric-operator +spec: + replicas: 1 + selector: + matchLabels: + name: fabric-operator + template: + metadata: + labels: + name: fabric-operator + spec: + serviceAccountName: fabric-operator +# imagePullSecrets: +# - name: image-pull-secret + containers: + - name: fabric-operator + image: ${OPERATOR_IMAGE} + command: + - ibp-operator +# livenessProbe: +# tcpSocket: +# port: 8383 +# initialDelaySeconds: 10 +# timeoutSeconds: 5 +# failureThreshold: 5 +# readinessProbe: +# tcpSocket: +# port: 8383 +# initialDelaySeconds: 10 +# timeoutSeconds: 5 +# periodSeconds: 5 + env: + - name: WATCH_NAMESPACE + valueFrom: + fieldRef: + fieldPath: metadata.namespace + - name: POD_NAME + valueFrom: + fieldRef: + fieldPath: metadata.name + - name: OPERATOR_NAME + value: "fabric-operator" + - name: CLUSTERTYPE + value: K8S + diff --git a/sample-network-multi-org/kind/operator/operator-psp.yaml b/sample-network-multi-org/kind/operator/operator-psp.yaml new file mode 100644 index 00000000..dcd53c72 --- /dev/null +++ b/sample-network-multi-org/kind/operator/operator-psp.yaml @@ -0,0 +1,48 @@ +# +# Copyright contributors to the Hyperledger Fabric Operator project +# +# SPDX-License-Identifier: Apache-2.0 +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at: +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# +--- +apiVersion: policy/v1beta1 +kind: PodSecurityPolicy +metadata: + name: ibm-hlfsupport-psp +spec: + hostIPC: false + hostNetwork: false + hostPID: false + privileged: true + allowPrivilegeEscalation: true + readOnlyRootFilesystem: false + seLinux: + rule: RunAsAny + supplementalGroups: + rule: RunAsAny + runAsUser: + rule: RunAsAny + fsGroup: + rule: RunAsAny + requiredDropCapabilities: + - ALL + allowedCapabilities: + - NET_BIND_SERVICE + - CHOWN + - DAC_OVERRIDE + - SETGID + - SETUID + - FOWNER + volumes: + - '*' diff --git a/sample-network-multi-org/kind/operator/operator-serviceaccount.yaml b/sample-network-multi-org/kind/operator/operator-serviceaccount.yaml new file mode 100644 index 00000000..2013b11f --- /dev/null +++ b/sample-network-multi-org/kind/operator/operator-serviceaccount.yaml @@ -0,0 +1,22 @@ +# +# Copyright contributors to the Hyperledger Fabric Operator project +# +# SPDX-License-Identifier: Apache-2.0 +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at: +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# +--- +apiVersion: v1 +kind: ServiceAccount +metadata: + name: fabric-operator diff --git a/sample-network-multi-org/organizations/.gitignore b/sample-network-multi-org/organizations/.gitignore new file mode 100644 index 00000000..8d69b3d7 --- /dev/null +++ b/sample-network-multi-org/organizations/.gitignore @@ -0,0 +1,3 @@ +enrollments/ +chaincode/ + diff --git a/sample-network-multi-org/organizations/org0/enroll.sh b/sample-network-multi-org/organizations/org0/enroll.sh new file mode 100755 index 00000000..f1cc4c8a --- /dev/null +++ b/sample-network-multi-org/organizations/org0/enroll.sh @@ -0,0 +1,44 @@ +#!/usr/bin/env bash +# +# Copyright contributors to the Hyperledgendary Kubernetes Test Network project +# +# SPDX-License-Identifier: Apache-2.0 +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at: +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# +set -euo pipefail +. scripts/utils.sh + +# +# Bind all org0 services to the "org0" namespace +# +export NAMESPACE=org0 + +# +# Save all of the organization enrollments in a local folder. +# +ENROLLMENTS_DIR=${PWD}/organizations/org0/enrollments + +# +# Before we can work with the CA, extract the CA's TLS certificate and +# store in .pem format for access with client utilities. +# +write_pem ca .tls.cert $ENROLLMENTS_DIR/ca-tls-cert.pem + +# Enroll the org0 admin user. Registration is performed by the operator according +# to entries in the org0 ca CRD. +enroll org0 org0admin org0adminpw + +# When connecting to the orderers, the channel admin API requires that the HTTP client +# presents a TLS certificate that has been signed by the organization's TLS CA. +enroll_tls org0 org0admin org0adminpw diff --git a/sample-network-multi-org/organizations/org0/export_msp.sh b/sample-network-multi-org/organizations/org0/export_msp.sh new file mode 100755 index 00000000..30086e47 --- /dev/null +++ b/sample-network-multi-org/organizations/org0/export_msp.sh @@ -0,0 +1,46 @@ +#!/usr/bin/env bash +# +# Copyright contributors to the Hyperledgendary Kubernetes Test Network project +# +# SPDX-License-Identifier: Apache-2.0 +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at: +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# +set -euo pipefail +. scripts/utils.sh + +# +# Bind all org0 services to the "org0" namespace +# +export NAMESPACE=org0 + +print "Exporting org0 channel MSP" + +# +# Prepare a folder structure containing the organization's MSP certificates +# necessary to join the consortium. +# +ORG_DIR=channel-config/organizations/ordererOrganizations/org0.localho.st + +write_pem ca .ca.signcerts $ORG_DIR/msp/cacerts/ca-signcert.pem +write_pem ca .tlsca.signcerts $ORG_DIR/msp/tlscacerts/tlsca-signcert.pem +write_msp_config ca ca-signcert.pem $ORG_DIR/msp + + +# +# Extract the orderer TLS certificates. These will be used by osnadmin for +# TLS connections to the orderers when joining orgs to a channel. +# +write_pem orderernode1 .tls.signcerts $ORG_DIR/orderers/orderernode1/tls/signcerts/tls-cert.pem +write_pem orderernode2 .tls.signcerts $ORG_DIR/orderers/orderernode2/tls/signcerts/tls-cert.pem +write_pem orderernode3 .tls.signcerts $ORG_DIR/orderers/orderernode3/tls/signcerts/tls-cert.pem \ No newline at end of file diff --git a/sample-network-multi-org/organizations/org0/join_channel.sh b/sample-network-multi-org/organizations/org0/join_channel.sh new file mode 100755 index 00000000..14158e97 --- /dev/null +++ b/sample-network-multi-org/organizations/org0/join_channel.sh @@ -0,0 +1,54 @@ +#!/usr/bin/env bash +# +# Copyright contributors to the Hyperledgendary Kubernetes Test Network project +# +# SPDX-License-Identifier: Apache-2.0 +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at: +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# +set -euo pipefail +. scripts/utils.sh + +# +# Bind all org0 services to the "org0" namespace +# +export NAMESPACE=org0 + +# +# As the consortium organizer, the org0 will use osnadmin to join the ordering +# nodes to the channel. +# +function join_orderer() { + local orderer=$1 + print "joining orderer $orderer to $CHANNEL_NAME" + + # orderer URL and TLS certificate: + local orderer_admin_endpoint=org0-${orderer}-admin.org0.localho.st + local ca_file=channel-config/organizations/ordererOrganizations/org0.localho.st/orderers/${orderer}/tls/signcerts/tls-cert.pem + + # mTLS client key pair enrolled the org0 TLS CA: + local client_cert=organizations/org0/enrollments/org0admin/tls/signcerts/cert.pem + local client_key=organizations/org0/enrollments/org0admin/tls/keystore/key.pem + + osnadmin channel join \ + --orderer-address $orderer_admin_endpoint \ + --ca-file $ca_file \ + --client-cert $client_cert \ + --client-key $client_key \ + --channelID $CHANNEL_NAME \ + --config-block channel-config/${CHANNEL_NAME}_genesis_block.pb +} + +join_orderer orderernode1 +join_orderer orderernode2 +join_orderer orderernode3 \ No newline at end of file diff --git a/sample-network-multi-org/organizations/org0/org0-ca.yaml b/sample-network-multi-org/organizations/org0/org0-ca.yaml new file mode 100644 index 00000000..52aab212 --- /dev/null +++ b/sample-network-multi-org/organizations/org0/org0-ca.yaml @@ -0,0 +1,135 @@ +# +# Copyright contributors to the Hyperledger Fabric Operator project +# +# SPDX-License-Identifier: Apache-2.0 +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at: +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# +--- +apiVersion: ibp.com/v1beta1 +kind: IBPCA +metadata: + name: ca +spec: + action: + renew: {} + configoverride: + ca: + affiliations: + org1: + - department1 + - department2 + org2: + - department1 + registry: + identities: + - name: rcaadmin + pass: rcaadminpw + type: client + attrs: + hf.Registrar.Roles: "*" + hf.Registrar.DelegateRoles: "*" + hf.Revoker: true + hf.IntermediateCA: true + hf.GenCRL: true + hf.Registrar.Attributes: "*" + hf.AffiliationMgr: true + - name: orderer1 + pass: orderer1pw + type: orderer + - name: orderer2 + pass: orderer2pw + type: orderer + - name: orderer3 + pass: orderer3pw + type: orderer + - name: org0admin + pass: org0adminpw + type: admin + debug: true + signing: + default: + expiry: 87600h0m0s + tlsca: + affiliations: + org1: + - department1 + - department2 + org0: + - department1 + registry: + identities: + - name: admin + pass: adminpw + type: client # todo: shouldn't this be an admin? + attrs: + hf.Registrar.Roles: "*" + hf.Registrar.DelegateRoles: "*" + hf.Revoker: true + hf.IntermediateCA: true + hf.GenCRL: true + hf.Registrar.Attributes: "*" + hf.AffiliationMgr: true + - name: orderer1 + pass: orderer1pw + type: orderer + - name: orderer2 + pass: orderer2pw + type: orderer + - name: orderer3 + pass: orderer3pw + type: orderer + - name: org0admin + pass: org0adminpw + type: admin + + debug: true + signing: + default: + expiry: 87600h0m0s + customNames: + pvc: {} + domain: org0.localho.st + images: + caImage: ${CA_IMAGE} + caTag: ${CA_IMAGE_TAG} + caInitImage: registry.access.redhat.com/ubi8/ubi-minimal + caInitTag: latest + ingress: + class: "" + tlsSecretName: "" + license: + accept: true + replicas: 1 + resources: + ca: + limits: + cpu: 100m + memory: 200M + requests: + cpu: 10m + memory: 10M + init: + limits: + cpu: 100m + memory: 200M + requests: + cpu: 10m + memory: 10M + service: + type: ClusterIP + storage: + ca: + class: standard + size: 100M + version: 1.5.5 diff --git a/sample-network-multi-org/organizations/org0/org0-orderer.yaml b/sample-network-multi-org/organizations/org0/org0-orderer.yaml new file mode 100644 index 00000000..475c54e3 --- /dev/null +++ b/sample-network-multi-org/organizations/org0/org0-orderer.yaml @@ -0,0 +1,151 @@ +# +# Copyright contributors to the Hyperledger Fabric Operator project +# +# SPDX-License-Identifier: Apache-2.0 +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at: +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# +--- +apiVersion: ibp.com/v1beta1 +kind: IBPOrderer +metadata: + name: orderer +spec: + version: "${FABRIC_VERSION}" + domain: "org0.localho.st" + license: + accept: true + action: + enroll: {} + reenroll: {} + clusterSize: 3 + clusterconfigoverride: + - general: + keepalive: + serverMinInterval: 61s + - general: + keepalive: + serverMinInterval: 61s + - general: + keepalive: + serverMinInterval: 61s + clustersecret: + - enrollment: + component: + caname: ca + cahost: org0-ca-ca.org0.localho.st + caport: "443" + catls: + cacert: "${CA_CERT}" + enrollid: "orderer1" + enrollsecret: "orderer1pw" + tls: + caname: tlsca + cahost: org0-ca-ca.org0.localho.st + caport: "443" + catls: + cacert: "${CA_CERT}" + enrollid: "orderer1" + enrollsecret: "orderer1pw" + csr: + hosts: + - "orderernode1" + - "orderernode1.org0.svc.cluster.local" + - enrollment: + component: + caname: ca + cahost: org0-ca-ca.org0.localho.st + caport: "443" + catls: + cacert: "${CA_CERT}" + enrollid: "orderer2" + enrollsecret: "orderer2pw" + tls: + caname: tlsca + cahost: org0-ca-ca.org0.localho.st + caport: "443" + catls: + cacert: "${CA_CERT}" + enrollid: "orderer2" + enrollsecret: "orderer2pw" + csr: + hosts: + - "orderernode2" + - "orderernode2.org0.svc.cluster.local" + - enrollment: + component: + caname: ca + cahost: org0-ca-ca.org0.localho.st + caport: "443" + catls: + cacert: "${CA_CERT}" + enrollid: "orderer3" + enrollsecret: "orderer3pw" + tls: + caname: tlsca + cahost: org0-ca-ca.org0.localho.st + caport: "443" + catls: + cacert: "${CA_CERT}" + enrollid: "orderer3" + enrollsecret: "orderer3pw" + csr: + hosts: + - "orderernode3" + - "orderernode3.org0.svc.cluster.local" + + customNames: + pvc: {} + images: + ordererInitImage: registry.access.redhat.com/ubi8/ubi-minimal + ordererInitTag: latest + ordererImage: ${ORDERER_IMAGE} + ordererTag: ${ORDERER_IMAGE_TAG} + grpcwebImage: ghcr.io/hyperledger-labs/grpc-web + grpcwebTag: latest + ingress: + class: "" + tlsSecretName: "" + mspID: OrdererMSP + ordererType: etcdraft + orgName: OrdererOrg + useChannelLess: true + systemChannelName: testchainid + resources: + init: + limits: + cpu: 100m + memory: 200M + requests: + cpu: 10m + memory: 10M + orderer: + limits: + cpu: 600m + memory: 1200M + requests: + cpu: 10m + memory: 10M + proxy: + limits: + cpu: 100m + memory: 200M + requests: + cpu: 10m + memory: 10M + service: + type: ClusterIP + storage: + orderer: + class: "standard" + size: 5G diff --git a/sample-network-multi-org/organizations/org0/start.sh b/sample-network-multi-org/organizations/org0/start.sh new file mode 100755 index 00000000..d462d20d --- /dev/null +++ b/sample-network-multi-org/organizations/org0/start.sh @@ -0,0 +1,55 @@ +#!/usr/bin/env bash +# +# Copyright contributors to the Hyperledgendary Kubernetes Test Network project +# +# SPDX-License-Identifier: Apache-2.0 +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at: +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# +set -euo pipefail +. scripts/utils.sh + + +# +# Bind all org0 services to the "org0" namespace +# +export NAMESPACE=org0 + + +# +# CA +# +print "starting org0 CA" + +apply_template organizations/org0/org0-ca.yaml +sleep 5 +wait_for ibpca ca + +# Retrieve the org CA certificate for the bootstrap enrollment of peers/orderers. +# This value will be substituted from the environment into the node CRDs. +export CA_CERT=$(connection_profile_cert ca .tls.cert) + + +# +# Network nodes +# +print "starting org0 orderers" +apply_template organizations/org0/org0-orderer.yaml +sleep 5 + +wait_for ibporderer orderernode1 +wait_for ibporderer orderernode2 +wait_for ibporderer orderernode3 + +print "starting org0 peers" + diff --git a/sample-network-multi-org/organizations/org1/enroll.sh b/sample-network-multi-org/organizations/org1/enroll.sh new file mode 100755 index 00000000..2bf4ab07 --- /dev/null +++ b/sample-network-multi-org/organizations/org1/enroll.sh @@ -0,0 +1,53 @@ +#!/usr/bin/env bash +# +# Copyright contributors to the Hyperledgendary Kubernetes Test Network project +# +# SPDX-License-Identifier: Apache-2.0 +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at: +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# +set -euo pipefail +. scripts/utils.sh + +# +# Bind all org1 services to the "org1" namespace +# +export NAMESPACE=org1 + +# +# Save all of the organization enrollments in a local folder. +# +ENROLLMENTS_DIR=${PWD}/organizations/org1/enrollments + +# +# Before we can work with the CA, extract the CA's TLS certificate and +# store in .pem format for access with client utilities. +# +write_pem ca .tls.cert $ENROLLMENTS_DIR/ca-tls-cert.pem + +# Enroll the org1 admin user. Registration is performed by the operator according +# to entries in the org2-ca CRD. +enroll org1 org1admin org1adminpw + +# create an msp config.yaml to indicate the user is an admin for the org +CA_CERT_NAME=org1-ca-ca-org1-localho-st-ca.pem +write_msp_config ca $CA_CERT_NAME $ENROLLMENTS_DIR/org1admin/msp + +# Enroll the root CA administrator such that users can later be registered and enrolled for +# identities of transactions submitted to the ledger. +enroll org1 rcaadmin rcaadminpw + +# Enroll a client user for submitting transactions through a gateway +# cliant application. This user has been registered at the CA in the +# bootstrap registrations by the operator. +enroll org1 org1user org1userpw \ No newline at end of file diff --git a/sample-network-multi-org/organizations/org1/export_msp.sh b/sample-network-multi-org/organizations/org1/export_msp.sh new file mode 100755 index 00000000..d18ca774 --- /dev/null +++ b/sample-network-multi-org/organizations/org1/export_msp.sh @@ -0,0 +1,37 @@ +#!/usr/bin/env bash +# +# Copyright contributors to the Hyperledgendary Kubernetes Test Network project +# +# SPDX-License-Identifier: Apache-2.0 +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at: +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# +set -euo pipefail +. scripts/utils.sh + +# +# Bind all org1 services to the "org1" namespace +# +export NAMESPACE=org1 + +print "Exporting org1 channel MSP" + +# +# Prepare a folder structure containing the organization's MSP certificates +# necessary to join the consortium. +# +ORG_MSP_DIR=channel-config/organizations/peerOrganizations/org1.localho.st/msp + +write_pem ca .ca.signcerts $ORG_MSP_DIR/cacerts/ca-signcert.pem +write_pem ca .tlsca.signcerts $ORG_MSP_DIR/tlscacerts/tlsca-signcert.pem +write_msp_config ca ca-signcert.pem $ORG_MSP_DIR \ No newline at end of file diff --git a/sample-network-multi-org/organizations/org1/install_chaincode.sh b/sample-network-multi-org/organizations/org1/install_chaincode.sh new file mode 100755 index 00000000..c8c656e9 --- /dev/null +++ b/sample-network-multi-org/organizations/org1/install_chaincode.sh @@ -0,0 +1,89 @@ +#!/usr/bin/env bash +# +# Copyright contributors to the Hyperledgendary Kubernetes Test Network project +# +# SPDX-License-Identifier: Apache-2.0 +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at: +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# +set -euo pipefail +. scripts/utils.sh + +# +# Bind all org1 services to the "org1" namespace +# +export NAMESPACE=org1 + +# +# Download the chaincode package. (Or prepare one here with pkgcc.sh, tar, etc.) +# +CHAINCODE_PACKAGE=organizations/org1/chaincode/$CHAINCODE_PKG_NAME +if [ ! -f "$CHAINCODE_PACKAGE" ]; then + print "downloading k8s chaincode package $CHAINCODE_PKG_URL" + mkdir -p $(dirname $CHAINCODE_PACKAGE) + curl -L $CHAINCODE_PKG_URL > $CHAINCODE_PACKAGE +fi + + +# +# Install the package on all of the org peers +# todo: find a reliable way to test if the chaincode PACKAGE_ID has been installed (queryinstalled, getinstalled, ...) +# + +# org1-peer1 +appear_as Org1MSP org1 peer1 +PACKAGE_ID=$(peer lifecycle chaincode calculatepackageid $CHAINCODE_PACKAGE) + +print "installing $CHAINCODE_PKG_URL to $CORE_PEER_ADDRESS" +echo $PACKAGE_ID +peer lifecycle chaincode install $CHAINCODE_PACKAGE || true + +# org1-peer2 +appear_as Org1MSP org1 peer2 +PACKAGE_ID=$(peer lifecycle chaincode calculatepackageid $CHAINCODE_PACKAGE) + +print "installing $CHAINCODE_PKG_URL to $CORE_PEER_ADDRESS" +echo $PACKAGE_ID +peer lifecycle chaincode install $CHAINCODE_PACKAGE || true + + +# +# Approve the chaincode for the org +# +print "approving $CHAINCODE_NAME for $org" +peer lifecycle \ + chaincode approveformyorg \ + --channelID ${CHANNEL_NAME} \ + --name ${CHAINCODE_NAME} \ + --version ${CHAINCODE_VERSION} \ + --sequence ${CHAINCODE_SEQUENCE} \ + --package-id ${PACKAGE_ID} \ + --orderer ${ORDERER_ENDPOINT} \ + --tls --cafile ${ORDERER_TLS_CERT} \ + --connTimeout 15s + +# +# Commit the chaincode package to the channel +# +# The chaincode contract will be committed to the channel by org2. +# +#print "committing $CHAINCODE_NAME to $CHANNEL_NAME" +#peer lifecycle \ +# chaincode commit \ +# --channelID ${CHANNEL_NAME} \ +# --name ${CHAINCODE_NAME} \ +# --version ${CHAINCODE_VERSION} \ +# --sequence ${CHAINCODE_SEQUENCE} \ +# --orderer ${ORDERER_ENDPOINT} \ +# --tls --cafile ${ORDERER_TLS_CERT} \ +# --connTimeout 15s \ No newline at end of file diff --git a/sample-network-multi-org/organizations/org1/join_channel.sh b/sample-network-multi-org/organizations/org1/join_channel.sh new file mode 100755 index 00000000..49e2ef40 --- /dev/null +++ b/sample-network-multi-org/organizations/org1/join_channel.sh @@ -0,0 +1,39 @@ +#!/usr/bin/env bash +# +# Copyright contributors to the Hyperledgendary Kubernetes Test Network project +# +# SPDX-License-Identifier: Apache-2.0 +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at: +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# +set -euo pipefail +. scripts/utils.sh + +# +# Bind all org1 services to the "org1" namespace +# +export NAMESPACE=org1 + +# +# Join peer1 to the channel +# +print "joining org1 peer1 to $CHANNEL_NAME" +appear_as Org1MSP org1 peer1 +peer channel join --blockpath channel-config/${CHANNEL_NAME}_genesis_block.pb + +# +# Join peer2 to the channel +# +print "joining org1 peer2 to $CHANNEL_NAME" +appear_as Org1MSP org1 peer2 +peer channel join --blockpath channel-config/${CHANNEL_NAME}_genesis_block.pb diff --git a/sample-network-multi-org/organizations/org1/org1-ca.yaml b/sample-network-multi-org/organizations/org1/org1-ca.yaml new file mode 100644 index 00000000..3f5e88cd --- /dev/null +++ b/sample-network-multi-org/organizations/org1/org1-ca.yaml @@ -0,0 +1,115 @@ +# +# Copyright contributors to the Hyperledger Fabric Operator project +# +# SPDX-License-Identifier: Apache-2.0 +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at: +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# +--- +apiVersion: ibp.com/v1beta1 +kind: IBPCA +metadata: + name: ca +spec: + action: + renew: {} + configoverride: + ca: + affiliations: + org1: + - department1 + - department2 + org2: + - department1 + registry: + identities: + - name: org1admin + pass: org1adminpw + type: admin + - name: rcaadmin + pass: rcaadminpw + type: client + attrs: + hf.Registrar.Roles: "*" + hf.Registrar.DelegateRoles: "*" + hf.Revoker: true + hf.IntermediateCA: true + hf.GenCRL: true + hf.Registrar.Attributes: "*" + hf.AffiliationMgr: true + - name: org1user + pass: org1userpw + type: client + - name: peer1 + pass: peer1pw + type: peer + - name: peer2 + pass: peer2pw + type: peer + debug: true + signing: + default: + expiry: 87600h0m0s + tlsca: + affiliations: + org1: + - department1 + - department2 + registry: + identities: + - name: peer1 + pass: peer1pw + type: peer + - name: peer2 + pass: peer2pw + type: peer + debug: true + signing: + default: + expiry: 87600h0m0s + customNames: + pvc: {} + domain: org1.localho.st + images: + caImage: ${CA_IMAGE} + caTag: ${CA_IMAGE_TAG} + caInitImage: registry.access.redhat.com/ubi8/ubi-minimal + caInitTag: latest + ingress: + class: "" + tlsSecretName: "" + license: + accept: true + replicas: 1 + resources: + ca: + limits: + cpu: 100m + memory: 200M + requests: + cpu: 10m + memory: 10M + init: + limits: + cpu: 100m + memory: 200M + requests: + cpu: 10m + memory: 10M + service: + type: ClusterIP + storage: + ca: + class: standard + size: 100M + version: 1.5.5 diff --git a/sample-network-multi-org/organizations/org1/org1-peer-gateway.yaml b/sample-network-multi-org/organizations/org1/org1-peer-gateway.yaml new file mode 100644 index 00000000..20c399ac --- /dev/null +++ b/sample-network-multi-org/organizations/org1/org1-peer-gateway.yaml @@ -0,0 +1,59 @@ +--- +apiVersion: v1 +kind: Service +metadata: + name: peer-gateway + labels: + app: peer-gateway + app.kubernetes.io/instance: fabricpeer + app.kubernetes.io/managed-by: fabric-operator + app.kubernetes.io/name: fabric + creator: fabric + orgname: Org1MSP +spec: + # This selector stanza will match on the orgname: label below, distributing connections to all + # peers matching the org MSP. + selector: + # app: peer1 + app.kubernetes.io/instance: fabricpeer + app.kubernetes.io/managed-by: fabric-operator + app.kubernetes.io/name: fabric + creator: fabric + orgname: Org1MSP + ports: + - name: peer-api + port: 7051 + protocol: TCP + targetPort: 7051 + +--- +apiVersion: networking.k8s.io/v1 +kind: Ingress +metadata: + name: peer-gateway + annotations: + nginx.ingress.kubernetes.io/proxy-connect-timeout: 60s + nginx.ingress.kubernetes.io/ssl-passthrough: "true" + labels: + app: peer-gateway + app.kubernetes.io/instance: fabricpeer + app.kubernetes.io/managed-by: fabric-operator + app.kubernetes.io/name: fabric + creator: fabric + orgname: Org1MSP +spec: + ingressClassName: nginx + rules: + - host: org1-peer-gateway.org1.localho.st + http: + paths: + - backend: + service: + name: peer-gateway + port: + name: peer-api + path: / + pathType: ImplementationSpecific + tls: + - hosts: + - org1-peer-gateway.org1.localho.st \ No newline at end of file diff --git a/sample-network-multi-org/organizations/org1/org1-peer1.yaml b/sample-network-multi-org/organizations/org1/org1-peer1.yaml new file mode 100644 index 00000000..8eacec85 --- /dev/null +++ b/sample-network-multi-org/organizations/org1/org1-peer1.yaml @@ -0,0 +1,103 @@ +# +# Copyright contributors to the Hyperledger Fabric Operator project +# +# SPDX-License-Identifier: Apache-2.0 +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at: +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# +--- +apiVersion: ibp.com/v1beta1 +kind: IBPPeer +metadata: + name: peer1 +spec: + version: "${FABRIC_VERSION}" + domain: "org1.localho.st" + peerExternalEndpoint: "org1-peer1-peer.org1.localho.st:443" + license: + accept: true + action: + enroll: {} + reenroll: {} + configoverride: + peer: + keepalive: + minInterval: 61s + customNames: + pvc: {} + images: + peerInitImage: registry.access.redhat.com/ubi8/ubi-minimal + peerInitTag: latest + peerImage: ${PEER_IMAGE} + peerTag: ${PEER_IMAGE_TAG} + grpcwebImage: ghcr.io/hyperledger-labs/grpc-web + grpcwebTag: latest + mspID: Org1MSP + mspSecret: peer1-secret + secret: + enrollment: + component: + caname: ca + cahost: "org1-ca-ca.org1.localho.st" + caport: "443" + catls: + cacert: "${CA_CERT}" + enrollid: "peer1" + enrollsecret: "peer1pw" + tls: + caname: tlsca + cahost: "org1-ca-ca.org1.localho.st" + caport: "443" + catls: + cacert: "${CA_CERT}" + enrollid: "peer1" + enrollsecret: "peer1pw" + csr: + hosts: + - "peer1" + - "peer1.org1.svc.cluster.local" + - "org1-peer-gateway.org1.localho.st" + chaincodeBuilderConfig: + peername: org1-peer1 + service: + type: ClusterIP + stateDb: leveldb + storage: + peer: + class: "standard" + size: 5G + statedb: + class: "standard" + size: 10Gi + resources: + init: + limits: + cpu: 100m + memory: 200M + requests: + cpu: 10m + memory: 10M + peer: + limits: + cpu: 500m + memory: 1G + requests: + cpu: 10m + memory: 10M + proxy: + limits: + cpu: 100m + memory: 200M + requests: + cpu: 10m + memory: 10M \ No newline at end of file diff --git a/sample-network-multi-org/organizations/org1/org1-peer2.yaml b/sample-network-multi-org/organizations/org1/org1-peer2.yaml new file mode 100644 index 00000000..985b23a9 --- /dev/null +++ b/sample-network-multi-org/organizations/org1/org1-peer2.yaml @@ -0,0 +1,103 @@ +# +# Copyright contributors to the Hyperledger Fabric Operator project +# +# SPDX-License-Identifier: Apache-2.0 +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at: +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# +--- +apiVersion: ibp.com/v1beta1 +kind: IBPPeer +metadata: + name: peer2 +spec: + version: "${FABRIC_VERSION}" + domain: "org1.localho.st" + peerExternalEndpoint: "org1-peer2-peer.org1.localho.st:443" + license: + accept: true + action: + enroll: {} + reenroll: {} + configoverride: + peer: + keepalive: + minInterval: 61s + customNames: + pvc: {} + images: + peerInitImage: registry.access.redhat.com/ubi8/ubi-minimal + peerInitTag: latest + peerImage: ${PEER_IMAGE} + peerTag: ${PEER_IMAGE_TAG} + grpcwebImage: ghcr.io/hyperledger-labs/grpc-web + grpcwebTag: latest + mspID: Org1MSP + mspSecret: peer2-secret + secret: + enrollment: + component: + caname: ca + cahost: "org1-ca-ca.org1.localho.st" + caport: "443" + catls: + cacert: "${CA_CERT}" + enrollid: "peer1" + enrollsecret: "peer1pw" + tls: + caname: tlsca + cahost: "org1-ca-ca.org1.localho.st" + caport: "443" + catls: + cacert: "${CA_CERT}" + enrollid: "peer1" + enrollsecret: "peer1pw" + csr: + hosts: + - "peer2" + - "peer2.org1.svc.cluster.local" + - "org1-peer-gateway.org1.localho.st" + chaincodeBuilderConfig: + peername: peer2 + service: + type: ClusterIP + stateDb: leveldb + storage: + peer: + class: "standard" + size: 5G + statedb: + class: "standard" + size: 10Gi + resources: + init: + limits: + cpu: 100m + memory: 200M + requests: + cpu: 10m + memory: 10M + peer: + limits: + cpu: 500m + memory: 1G + requests: + cpu: 10m + memory: 10M + proxy: + limits: + cpu: 100m + memory: 200M + requests: + cpu: 10m + memory: 10M \ No newline at end of file diff --git a/sample-network-multi-org/organizations/org1/start.sh b/sample-network-multi-org/organizations/org1/start.sh new file mode 100755 index 00000000..a5907598 --- /dev/null +++ b/sample-network-multi-org/organizations/org1/start.sh @@ -0,0 +1,65 @@ +#!/usr/bin/env bash +# +# Copyright contributors to the Hyperledgendary Kubernetes Test Network project +# +# SPDX-License-Identifier: Apache-2.0 +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at: +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# +set -euo pipefail +. scripts/utils.sh + +# +# Bind all org1 services to the "org1" namespace +# +export NAMESPACE=org1 + +# +# CA +# +print "starting org1 CA" + +apply_template organizations/org1/org1-ca.yaml +sleep 5 +wait_for ibpca ca + +# Retrieve the org CA certificate for the bootstrap enrollment of peers/orderers. +# This value will be substituted from the environment into the node CRDs. +export CA_CERT=$(connection_profile_cert ca .tls.cert) + + +# +# Network nodes +# +print "starting org1 orderers" + +print "starting org1 peers" + +apply_template organizations/org1/org1-peer1.yaml +apply_template organizations/org1/org1-peer2.yaml +sleep 5 + +wait_for ibppeer peer1 +wait_for ibppeer peer2 + + + +# +# Deploy a load-balanced gateway service URL fronting the org's peer nodes. +# When submitting transactions through the gateway, the gateway peers will +# distribute transactions across the peers in the network, maintaining a +# balanced ledger height. +# +print "creating gateway service alias org1-peer-gateway" + +apply_template organizations/org1/org1-peer-gateway.yaml \ No newline at end of file diff --git a/sample-network-multi-org/organizations/org2/enroll.sh b/sample-network-multi-org/organizations/org2/enroll.sh new file mode 100755 index 00000000..1c4a6227 --- /dev/null +++ b/sample-network-multi-org/organizations/org2/enroll.sh @@ -0,0 +1,53 @@ +#!/usr/bin/env bash +# +# Copyright contributors to the Hyperledgendary Kubernetes Test Network project +# +# SPDX-License-Identifier: Apache-2.0 +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at: +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# +set -euo pipefail +. scripts/utils.sh + +# +# Bind all org2 services to the "org2" namespace +# +export NAMESPACE=org2 + +# +# Save all of the organization enrollments in a local folder. +# +ENROLLMENTS_DIR=${PWD}/organizations/org2/enrollments + +# +# Before we can work with the CA, extract the CA's TLS certificate and +# store in .pem format for access with client utilities. +# +write_pem ca .tls.cert $ENROLLMENTS_DIR/ca-tls-cert.pem + +# Enroll the org2 admin user. Registration is performed by the operator according +# to entries in the org2-ca CRD. +enroll org2 org2admin org2adminpw + +# create an msp config.yaml to indicate the user is an admin for the org +CA_CERT_NAME=org2-ca-ca-org2-localho-st-ca.pem +write_msp_config ca $CA_CERT_NAME $ENROLLMENTS_DIR/org2admin/msp + +# Enroll the root CA administrator such that users can later be registered and enrolled for +# identities of transactions submitted to the ledger. +enroll org2 rcaadmin rcaadminpw + +# Enroll a client user for submitting transactions through a gateway +# cliant application. This user has been registered at the CA in the +# bootstrap registrations by the operator. +enroll org2 org2user org2userpw \ No newline at end of file diff --git a/sample-network-multi-org/organizations/org2/export_msp.sh b/sample-network-multi-org/organizations/org2/export_msp.sh new file mode 100755 index 00000000..f9eea5df --- /dev/null +++ b/sample-network-multi-org/organizations/org2/export_msp.sh @@ -0,0 +1,37 @@ +#!/usr/bin/env bash +# +# Copyright contributors to the Hyperledgendary Kubernetes Test Network project +# +# SPDX-License-Identifier: Apache-2.0 +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at: +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# +set -euo pipefail +. scripts/utils.sh + +# +# Bind all org2 services to the "org2" namespace +# +export NAMESPACE=org2 + +print "Exporting org2 channel MSP" + +# +# Prepare a folder structure containing the organization's MSP certificates +# necessary to join the consortium. +# +ORG_MSP_DIR=channel-config/organizations/peerOrganizations/org2.localho.st/msp + +write_pem ca .ca.signcerts $ORG_MSP_DIR/cacerts/ca-signcert.pem +write_pem ca .tlsca.signcerts $ORG_MSP_DIR/tlscacerts/tlsca-signcert.pem +write_msp_config ca ca-signcert.pem $ORG_MSP_DIR diff --git a/sample-network-multi-org/organizations/org2/install_chaincode.sh b/sample-network-multi-org/organizations/org2/install_chaincode.sh new file mode 100755 index 00000000..0094f7f8 --- /dev/null +++ b/sample-network-multi-org/organizations/org2/install_chaincode.sh @@ -0,0 +1,89 @@ +#!/usr/bin/env bash +# +# Copyright contributors to the Hyperledgendary Kubernetes Test Network project +# +# SPDX-License-Identifier: Apache-2.0 +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at: +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# +set -euo pipefail +. scripts/utils.sh + +# +# Bind all org2 services to the "org2" namespace +# +export NAMESPACE=org2 + + + +# +# Download the chaincode package. (Or prepare one here with pkgcc.sh, tar, etc.) +# +CHAINCODE_PACKAGE=organizations/org2/chaincode/$CHAINCODE_PKG_NAME +if [ ! -f "$CHAINCODE_PACKAGE" ]; then + print "downloading k8s chaincode package $CHAINCODE_PKG_URL" + mkdir -p $(dirname $CHAINCODE_PACKAGE) + curl -L $CHAINCODE_PKG_URL > $CHAINCODE_PACKAGE +fi + + +# +# Install the package on all of the org peers +# todo: find a reliable way to test if the chaincode PACKAGE_ID has been installed (queryinstalled, getinstalled, ...) +# + +# org2-peer1 +appear_as Org2MSP org2 peer1 +export PACKAGE_ID=$(peer lifecycle chaincode calculatepackageid $CHAINCODE_PACKAGE) + +print "installing $CHAINCODE_PKG_URL to $CORE_PEER_ADDRESS" +echo $PACKAGE_ID +peer lifecycle chaincode install $CHAINCODE_PACKAGE || true + +# org2-peer2 +appear_as Org2MSP org2 peer2 +export PACKAGE_ID=$(peer lifecycle chaincode calculatepackageid $CHAINCODE_PACKAGE) + +print "installing $CHAINCODE_PKG_URL to $CORE_PEER_ADDRESS" +echo $PACKAGE_ID +peer lifecycle chaincode install $CHAINCODE_PACKAGE || true + + +# +# Approve the chaincode for the org +# +print "approving $CHAINCODE_NAME for $org" +peer lifecycle \ + chaincode approveformyorg \ + --channelID ${CHANNEL_NAME} \ + --name ${CHAINCODE_NAME} \ + --version ${CHAINCODE_VERSION} \ + --sequence ${CHAINCODE_SEQUENCE} \ + --package-id ${PACKAGE_ID} \ + --orderer ${ORDERER_ENDPOINT} \ + --tls --cafile ${ORDERER_TLS_CERT} \ + --connTimeout 15s + +# +# Commit the chaincode to the channel +# +print "committing $CHAINCODE_NAME to $CHANNEL_NAME" +peer lifecycle \ + chaincode commit \ + --channelID ${CHANNEL_NAME} \ + --name ${CHAINCODE_NAME} \ + --version ${CHAINCODE_VERSION} \ + --sequence ${CHAINCODE_SEQUENCE} \ + --orderer ${ORDERER_ENDPOINT} \ + --tls --cafile ${ORDERER_TLS_CERT} \ + --connTimeout 15s \ No newline at end of file diff --git a/sample-network-multi-org/organizations/org2/join_channel.sh b/sample-network-multi-org/organizations/org2/join_channel.sh new file mode 100755 index 00000000..ce66dcbd --- /dev/null +++ b/sample-network-multi-org/organizations/org2/join_channel.sh @@ -0,0 +1,39 @@ +#!/usr/bin/env bash +# +# Copyright contributors to the Hyperledgendary Kubernetes Test Network project +# +# SPDX-License-Identifier: Apache-2.0 +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at: +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# +set -euo pipefail +. scripts/utils.sh + +# +# Bind all org2 services to the "org2" namespace +# +export NAMESPACE=org2 + +# +# Join peer1 to the channel +# +print "joining org2 peer1 to $CHANNEL_NAME" +appear_as Org2MSP org2 peer1 +peer channel join --blockpath channel-config/${CHANNEL_NAME}_genesis_block.pb + +# +# Join peer2 to the channel +# +print "joining org2 peer2 to $CHANNEL_NAME" +appear_as Org2MSP org2 peer2 +peer channel join --blockpath channel-config/${CHANNEL_NAME}_genesis_block.pb diff --git a/sample-network-multi-org/organizations/org2/org2-ca.yaml b/sample-network-multi-org/organizations/org2/org2-ca.yaml new file mode 100644 index 00000000..d732f990 --- /dev/null +++ b/sample-network-multi-org/organizations/org2/org2-ca.yaml @@ -0,0 +1,113 @@ +# +# Copyright contributors to the Hyperledger Fabric Operator project +# +# SPDX-License-Identifier: Apache-2.0 +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at: +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# +--- +apiVersion: ibp.com/v1beta1 +kind: IBPCA +metadata: + name: ca +spec: + action: + renew: {} + configoverride: + ca: + affiliations: + org2: + - department1 + - department2 + registry: + identities: + - name: org2admin + pass: org2adminpw + type: admin + - name: rcaadmin + pass: rcaadminpw + type: client + attrs: + hf.Registrar.Roles: "*" + hf.Registrar.DelegateRoles: "*" + hf.Revoker: true + hf.IntermediateCA: true + hf.GenCRL: true + hf.Registrar.Attributes: "*" + hf.AffiliationMgr: true + - name: org2user + pass: org2userpw + type: client + - name: peer1 + pass: peer1pw + type: peer + - name: peer2 + pass: peer2pw + type: peer + debug: true + signing: + default: + expiry: 87600h0m0s + tlsca: + affiliations: + org2: + - department1 + - department2 + registry: + identities: + - name: peer1 + pass: peer1pw + type: peer + - name: peer2 + pass: peer2pw + type: peer + debug: true + signing: + default: + expiry: 87600h0m0s + customNames: + pvc: {} + domain: org2.localho.st + images: + caImage: ${CA_IMAGE} + caTag: ${CA_IMAGE_TAG} + caInitImage: registry.access.redhat.com/ubi8/ubi-minimal + caInitTag: latest + ingress: + class: "" + tlsSecretName: "" + license: + accept: true + replicas: 1 + resources: + ca: + limits: + cpu: 100m + memory: 200M + requests: + cpu: 10m + memory: 10M + init: + limits: + cpu: 100m + memory: 200M + requests: + cpu: 10m + memory: 10M + service: + type: ClusterIP + storage: + ca: + class: standard + size: 100M + version: 1.5.5 diff --git a/sample-network-multi-org/organizations/org2/org2-peer-gateway.yaml b/sample-network-multi-org/organizations/org2/org2-peer-gateway.yaml new file mode 100644 index 00000000..3ac5d31c --- /dev/null +++ b/sample-network-multi-org/organizations/org2/org2-peer-gateway.yaml @@ -0,0 +1,59 @@ +--- +apiVersion: v1 +kind: Service +metadata: + name: peer-gateway + labels: + app: peer-gateway + app.kubernetes.io/instance: fabricpeer + app.kubernetes.io/managed-by: fabric-operator + app.kubernetes.io/name: fabric + creator: fabric + orgname: Org2MSP +spec: + # This selector stanza will match on the orgname: label below, distributing connections to all + # peers matching the org MSP. + selector: + # app: peer1 + app.kubernetes.io/instance: fabricpeer + app.kubernetes.io/managed-by: fabric-operator + app.kubernetes.io/name: fabric + creator: fabric + orgname: Org2MSP + ports: + - name: peer-api + port: 7051 + protocol: TCP + targetPort: 7051 + +--- +apiVersion: networking.k8s.io/v1 +kind: Ingress +metadata: + name: peer-gateway + annotations: + nginx.ingress.kubernetes.io/proxy-connect-timeout: 60s + nginx.ingress.kubernetes.io/ssl-passthrough: "true" + labels: + app: peer-gateway + app.kubernetes.io/instance: fabricpeer + app.kubernetes.io/managed-by: fabric-operator + app.kubernetes.io/name: fabric + creator: fabric + orgname: Org2MSP +spec: + ingressClassName: nginx + rules: + - host: org2-peer-gateway.org2.localho.st + http: + paths: + - backend: + service: + name: peer-gateway + port: + name: peer-api + path: / + pathType: ImplementationSpecific + tls: + - hosts: + - org2-peer-gateway.org2.localho.st \ No newline at end of file diff --git a/sample-network-multi-org/organizations/org2/org2-peer1.yaml b/sample-network-multi-org/organizations/org2/org2-peer1.yaml new file mode 100644 index 00000000..a12b847a --- /dev/null +++ b/sample-network-multi-org/organizations/org2/org2-peer1.yaml @@ -0,0 +1,103 @@ +# +# Copyright contributors to the Hyperledger Fabric Operator project +# +# SPDX-License-Identifier: Apache-2.0 +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at: +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# +--- +apiVersion: ibp.com/v1beta1 +kind: IBPPeer +metadata: + name: peer1 +spec: + version: "${FABRIC_VERSION}" + domain: "org2.localho.st" + peerExternalEndpoint: "org2-peer1-peer.org2.localho.st:443" + license: + accept: true + action: + enroll: {} + reenroll: {} + configoverride: + peer: + keepalive: + minInterval: 61s + customNames: + pvc: {} + images: + peerInitImage: registry.access.redhat.com/ubi8/ubi-minimal + peerInitTag: latest + peerImage: ${PEER_IMAGE} + peerTag: ${PEER_IMAGE_TAG} + grpcwebImage: ghcr.io/hyperledger-labs/grpc-web + grpcwebTag: latest + mspID: Org2MSP + mspSecret: org2-peer1-secret + secret: + enrollment: + component: + caname: ca + cahost: "org2-ca-ca.org2.localho.st" + caport: "443" + catls: + cacert: "${CA_CERT}" + enrollid: "peer1" + enrollsecret: "peer1pw" + tls: + caname: tlsca + cahost: "org2-ca-ca.org2.localho.st" + caport: "443" + catls: + cacert: "${CA_CERT}" + enrollid: "peer1" + enrollsecret: "peer1pw" + csr: + hosts: + - "peer1" + - "peer1.org2.svc.cluster.local" + - "org2-peer-gateway.org2.localho.st" + chaincodeBuilderConfig: + peername: org2-peer1 + service: + type: ClusterIP + stateDb: leveldb + storage: + peer: + class: "standard" + size: 5G + statedb: + class: "standard" + size: 10Gi + resources: + init: + limits: + cpu: 100m + memory: 200M + requests: + cpu: 10m + memory: 10M + peer: + limits: + cpu: 500m + memory: 1G + requests: + cpu: 10m + memory: 10M + proxy: + limits: + cpu: 100m + memory: 200M + requests: + cpu: 10m + memory: 10M \ No newline at end of file diff --git a/sample-network-multi-org/organizations/org2/org2-peer2.yaml b/sample-network-multi-org/organizations/org2/org2-peer2.yaml new file mode 100644 index 00000000..6902817e --- /dev/null +++ b/sample-network-multi-org/organizations/org2/org2-peer2.yaml @@ -0,0 +1,103 @@ +# +# Copyright contributors to the Hyperledger Fabric Operator project +# +# SPDX-License-Identifier: Apache-2.0 +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at: +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# +--- +apiVersion: ibp.com/v1beta1 +kind: IBPPeer +metadata: + name: peer2 +spec: + version: "${FABRIC_VERSION}" + domain: "org2.localho.st" + peerExternalEndpoint: "org2-peer2-peer.org2.localho.st:443" + license: + accept: true + action: + enroll: {} + reenroll: {} + configoverride: + peer: + keepalive: + minInterval: 61s + customNames: + pvc: {} + images: + peerInitImage: registry.access.redhat.com/ubi8/ubi-minimal + peerInitTag: latest + peerImage: ${PEER_IMAGE} + peerTag: ${PEER_IMAGE_TAG} + grpcwebImage: ghcr.io/hyperledger-labs/grpc-web + grpcwebTag: latest + mspID: Org2MSP + mspSecret: org2-peer2-secret + secret: + enrollment: + component: + caname: ca + cahost: "org2-ca-ca.org2.localho.st" + caport: "443" + catls: + cacert: "${CA_CERT}" + enrollid: "peer1" + enrollsecret: "peer1pw" + tls: + caname: tlsca + cahost: "org2-ca-ca.org2.localho.st" + caport: "443" + catls: + cacert: "${CA_CERT}" + enrollid: "peer1" + enrollsecret: "peer1pw" + csr: + hosts: + - "peer2" + - "org2-peer2.org2.svc.cluster.local" + - "org2-peer-gateway.org2.localho.st" + chaincodeBuilderConfig: + peername: org2-peer2 + service: + type: ClusterIP + stateDb: leveldb + storage: + peer: + class: "standard" + size: 5G + statedb: + class: "standard" + size: 10Gi + resources: + init: + limits: + cpu: 100m + memory: 200M + requests: + cpu: 10m + memory: 10M + peer: + limits: + cpu: 500m + memory: 1G + requests: + cpu: 10m + memory: 10M + proxy: + limits: + cpu: 100m + memory: 200M + requests: + cpu: 10m + memory: 10M \ No newline at end of file diff --git a/sample-network-multi-org/organizations/org2/start.sh b/sample-network-multi-org/organizations/org2/start.sh new file mode 100755 index 00000000..c1d44c90 --- /dev/null +++ b/sample-network-multi-org/organizations/org2/start.sh @@ -0,0 +1,63 @@ +#!/usr/bin/env bash +# +# Copyright contributors to the Hyperledgendary Kubernetes Test Network project +# +# SPDX-License-Identifier: Apache-2.0 +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at: +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# +set -euo pipefail +. scripts/utils.sh + +# +# Bind all org2 services to the "org2" namespace +# +export NAMESPACE=org2 + +# +# CA +# +print "starting org2 CA" + +apply_template organizations/org2/org2-ca.yaml +sleep 5 +wait_for ibpca ca + +# Retrieve the org CA certificate for the bootstrap enrollment of peers/orderers. +# This value will be substituted from the environment into the node CRDs. +export CA_CERT=$(connection_profile_cert ca .tls.cert) + +# +# Network nodes +# +print "starting org2 orderers" + +print "starting org2 peers" + +apply_template organizations/org2/org2-peer1.yaml +apply_template organizations/org2/org2-peer2.yaml +sleep 5 + +wait_for ibppeer peer1 +wait_for ibppeer peer2 + + +# +# Deploy a load-balanced gateway service URL fronting the org's peer nodes. +# When submitting transactions through the gateway, the gateway peers will +# distribute transactions across the peers in the network, maintaining a +# balanced ledger height. +# +print "creating gateway service alias org2-peer-gateway" + +apply_template organizations/org2/org2-peer-gateway.yaml \ No newline at end of file diff --git a/sample-network-multi-org/scripts/check-kube.sh b/sample-network-multi-org/scripts/check-kube.sh new file mode 100755 index 00000000..8ea77ccf --- /dev/null +++ b/sample-network-multi-org/scripts/check-kube.sh @@ -0,0 +1,49 @@ +#!/usr/bin/env bash +# +# Copyright contributors to the Hyperledgendary Kubernetes Test Network project +# +# SPDX-License-Identifier: Apache-2.0 +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at: +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# + +# All checks run in the workshop root folder +cd "$(dirname "$0")"/.. + +. scripts/utils.sh + +EXIT=0 + + +function cluster_info() { + kubectl cluster-info &>/dev/null +} + +function nginx() { + kubectl -n ingress-nginx get all &>/dev/null + kubectl -n ingress-nginx get deployment.apps/ingress-nginx-controller &>/dev/null + curl http://localho.st &>/dev/null + curl --insecure https://localho.st:443 &>/dev/null +} + +function container_registry() { + curl --fail http://localhost2:5000/v2/_catalog &>/dev/null +} + + +check cluster_info "k8s API controller is running" +check nginx "Nginx ingress is running at https://localho.st" +check container_registry "Container registry is running at localhost:5000" + +exit $EXIT + diff --git a/sample-network-multi-org/scripts/check-network.sh b/sample-network-multi-org/scripts/check-network.sh new file mode 100755 index 00000000..af5e1d32 --- /dev/null +++ b/sample-network-multi-org/scripts/check-network.sh @@ -0,0 +1,130 @@ +#!/usr/bin/env bash +# +# Copyright contributors to the Hyperledgendary Kubernetes Test Network project +# +# SPDX-License-Identifier: Apache-2.0 +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at: +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# + +# All checks run in the workshop root folder +cd "$(dirname "$0")"/.. + +. scripts/utils.sh + +# todo: need to check the enrollments here (just enroll org) +# todo: need to check the MSP exports here in the channel-config/organizations (just export-msp org) + + + +EXIT=0 + +function operator_crds() { + kubectl get customresourcedefinition.apiextensions.k8s.io/ibpcas.ibp.com + kubectl get customresourcedefinition.apiextensions.k8s.io/ibpconsoles.ibp.com + kubectl get customresourcedefinition.apiextensions.k8s.io/ibporderers.ibp.com + kubectl get customresourcedefinition.apiextensions.k8s.io/ibppeers.ibp.com +} + +function org0_operator_deployed() { + kubectl -n org0 get deployment fabric-operator +} + +function org1_operator_deployed() { + kubectl -n org1 get deployment fabric-operator +} + +function org2_operator_deployed() { + kubectl -n org2 get deployment fabric-operator +} + + +# Did it apply the CRDs? +function org0_custom_resources() { + kubectl -n org0 get ibpca ca + kubectl -n org0 get ibporderer orderernode1 + kubectl -n org0 get ibporderer orderernode2 + kubectl -n org0 get ibporderer orderernode3 +} + +function org1_custom_resources() { + kubectl -n org1 get ibpca ca + kubectl -n org1 get ibppeer peer1 + kubectl -n org1 get ibppeer peer2 +} + +function org2_custom_resources() { + kubectl -n org2 get ibpca ca + kubectl -n org2 get ibppeer peer1 + kubectl -n org2 get ibppeer peer2 +} + +function org0_deployments() { + kubectl -n org0 get deployment ca + kubectl -n org0 get deployment orderernode1 + kubectl -n org0 get deployment orderernode2 + kubectl -n org0 get deployment orderernode3 +} + +function org1_deployments() { + kubectl -n org1 get deployment ca + kubectl -n org1 get deployment peer1 + kubectl -n org1 get deployment peer2 +} + +function org2_deployments() { + kubectl -n org2 get deployment ca + kubectl -n org2 get deployment peer1 + kubectl -n org2 get deployment peer2 +} + +# Hit the CAs using the TLS certs, etc. +function org0_cas_ready() { + curl --fail -s --cacert organizations/org0/enrollments/ca-tls-cert.pem https://org0-ca-ca.org0.localho.st/cainfo +} + +function org1_cas_ready() { + curl --fail -s --cacert organizations/org1/enrollments/ca-tls-cert.pem https://org1-ca-ca.org1.localho.st/cainfo +} + +function org2_cas_ready() { + curl --fail -s --cacert organizations/org2/enrollments/ca-tls-cert.pem https://org2-ca-ca.org2.localho.st/cainfo +} + +function channel_msp() { + find channel-config/organizations +} + + +check operator_crds "fabric-operator CRDs have been installed" + +check org0_operator_deployed "org0 fabric-operator has been deployed" +check org1_operator_deployed "org1 fabric-operator has been deployed" +check org2_operator_deployed "org2 fabric-operator has been deployed" + +check org0_custom_resources "org0 CAs, Orderers, and Peers have been created" +check org1_custom_resources "org1 CAs, Orderers, and Peers have been created" +check org2_custom_resources "org2 CAs, Orderers, and Peers have been created" + +check org0_deployments "org0 services have been deployed" +check org1_deployments "org1 services have been deployed" +check org2_deployments "org2 services have been deployed" + +check org0_cas_ready "org0 CAs are available at ingress" +check org1_cas_ready "org1 CAs are available at ingress" +check org2_cas_ready "org2 CAs are available at ingress" + +#check channel_msp "Channel MSP has been exported" + +exit $EXIT + diff --git a/sample-network-multi-org/scripts/check.sh b/sample-network-multi-org/scripts/check.sh new file mode 100755 index 00000000..6349cda6 --- /dev/null +++ b/sample-network-multi-org/scripts/check.sh @@ -0,0 +1,131 @@ +#!/usr/bin/env bash + +SUCCESS="✅" +WARN="⚠️ " +EXIT=0 + +if ! command -v docker &> /tmp/cmdpath +then + echo "${WARN} Please install Docker; suggested install commands:" + EXIT=1 +else + echo -e "${SUCCESS} Docker found:\t$(cat /tmp/cmdpath)" +fi + +KUBECTL_VERSION=v1.24.4 # $(curl -L -s https://dl.k8s.io/release/stable.txt) +if ! command -v kubectl &> /tmp/cmdpath +then + echo "${WARN} Please install kubectl if you want to use k8s; suggested install commands:" + + if [ $(uname -s) = Darwin ]; then + if [ $(uname -m) = arm64 ]; then + echo "curl -LO https://dl.k8s.io/release/${KUBECTL_VERSION}/bin/darwin/arm64/kubectl" + echo "chmod +x ./kubectl" + echo "sudo mv ./kubectl /usr/local/bin/kubectl" + echo "sudo chown root: /usr/local/bin/kubectl" + else + echo "curl -LO https://dl.k8s.io/release/${KUBECTL_VERSION}/bin/darwin/amd64/kubectl" + echo "chmod +x ./kubectl" + echo "sudo mv ./kubectl /usr/local/bin/kubectl" + echo "sudo chown root: /usr/local/bin/kubectl" + fi + else + echo "curl -LO https://dl.k8s.io/release/${KUBECTL_VERSION}/bin/linux/amd64/kubectl" + echo "sudo install -o root -g root -m 0755 kubectl /usr/local/bin/kubectl" + fi + EXIT=1 +else + echo -e "${SUCCESS} kubectl found:\t$(cat /tmp/cmdpath)" + + KUBECTL_CLIENT_VERSION=$(kubectl version --client --output=yaml | grep gitVersion | cut -c 15-) + KUBECTL_CLIENT_MINOR_VERSION=$(kubectl version --client --output=yaml | grep minor | cut -c 11-12) + if [ "${KUBECTL_CLIENT_MINOR_VERSION}" -lt "24" ]; then + echo -e "${WARN} Found kubectl client version ${KUBECTL_CLIENT_VERSION}, which may be out of date. Please ensure client version >= ${KUBECTL_VERSION}" + EXIT=1 + fi +fi + +# Install kind +KIND_VERSION=0.14.0 +if ! command -v kind &> /tmp/cmdpath +then + echo "${WARN} Please install kind; suggested install commands:" + echo + if [ $(uname -s) = Darwin ]; then + if [ $(uname -m) = arm64 ]; then + echo "sudo curl --fail --silent --show-error -L https://kind.sigs.k8s.io/dl/v${KIND_VERSION}/kind-darwin-arm64 -o /usr/local/bin/kind" + else + echo "sudo curl --fail --silent --show-error -L https://kind.sigs.k8s.io/dl/v${KIND_VERSION}/kind-darwin-amd64 -o /usr/local/bin/kind" + fi + else + echo "sudo curl --fail --silent --show-error -L https://kind.sigs.k8s.io/dl/v${KIND_VERSION}/kind-linux-amd64 -o /usr/local/bin/kind" + fi + echo "sudo chmod 755 /usr/local/bin/kind" + echo + EXIT=1 +else + echo -e "${SUCCESS} kind found:\t\t$(cat /tmp/cmdpath)" +fi + +# Install just +JUST_VERSION=1.2.0 +if ! command -v just &> /tmp/cmdpath +then + echo "${WARN} Please install just; suggested install commands:" + echo "curl --proto '=https' --tlsv1.2 -sSf https://just.systems/install.sh | bash -s -- --tag ${JUST_VERSION} --to /usr/local/bin" + EXIT=1 +else + echo -e "${SUCCESS} Just found:\t\t$(cat /tmp/cmdpath)" +fi + +# Install jq +if ! command -v jq &> /tmp/cmdpath +then + echo "${WARN} Please install jq; suggested install commands:" + echo "sudo apt-update && sudo apt-install -y jq" + EXIT=1 +else + echo -e "${SUCCESS} jq found:\t\t$(cat /tmp/cmdpath)" +fi + +FABRIC_VERSION=2.5.0-beta +FABRIC_CA_VERSION=1.5.6-beta3 +if ! command -v peer &> /tmp/cmdpath +then + echo "${WARN} Please install the Fabric CLI binaries; suggested install commands:" + echo "curl -sSL https://raw.githubusercontent.com/hyperledger/fabric/main/scripts/install-fabric.sh | bash -s -- binary --fabric-version $FABRIC_VERSION --ca-version $FABRIC_CA_VERSION" + echo 'export PATH=${PWD}/bin:$PATH' + #echo 'export FABRIC_CFG_PATH=${PWD}/config' + EXIT=1 +else + echo -e "${SUCCESS} peer found:\t\t$(cat /tmp/cmdpath)" + + # double-check that the peer binary is compiled for the correct arch. This can occur when installing fabric + # binaries into a multipass VM, then running the Linux binaries from a Mac or windows Host OS via the volume share. + peer version &> /dev/null + rc=$? + if [ $rc -ne 0 ]; then + echo -e "${WARN} Could not execute peer. Was it compiled for the correct architecture?" + peer version + fi +fi + +# tests if varname is defined in the env AND it's an existing directory +function must_declare() { + local varname=$1 + + if [[ ! -d ${!varname} ]]; then + echo "${WARN} ${varname} must be set to a directory" + EXIT=1 + + else + echo -e "${SUCCESS} ${varname}:\t${!varname}" + fi +} + +#must_declare "FABRIC_CFG_PATH" +#must_declare "WORKSHOP_PATH" + +rm /tmp/cmdpath &> /dev/null + +exit $EXIT diff --git a/sample-network-multi-org/scripts/kind_with_nginx.sh b/sample-network-multi-org/scripts/kind_with_nginx.sh new file mode 100755 index 00000000..c90be079 --- /dev/null +++ b/sample-network-multi-org/scripts/kind_with_nginx.sh @@ -0,0 +1,220 @@ +#!/bin/bash + +# +# IBM Confidential +# OCO Source Materials +# +# Organic Growth Ventures +# (C) Copyright IBM Corp. 2022 All Rights Reserved. +# +# The source code for this program is not published or otherwise +# divested of its trade secrets, irrespective of what has been +# deposited with the U.S. Copyright Office. +# + +set -eo pipefail +set -x + +KIND_CLUSTER_NAME=kind +KIND_CLUSTER_IMAGE=${KIND_CLUSTER_IMAGE:-kindest/node:v1.24.4} +KIND_API_SERVER_ADDRESS=${KIND_API_SERVER_ADDRESS:-127.0.0.1} +KIND_API_SERVER_PORT=${KIND_API_SERVER_PORT:-8888} +CONTAINER_REGISTRY_NAME=${CONTAINER_REGISTRY_NAME:-kind-registry} +CONTAINER_REGISTRY_ADDRESS=${CONTAINER_REGISTRY_ADDRESS:-127.0.0.1} +CONTAINER_REGISTRY_PORT=${CONTAINER_REGISTRY_PORT:-5000} + +function kind_with_nginx() { + + delete_cluster + + create_cluster + + #start_cert_manager + + start_nginx + + apply_coredns_override + + launch_docker_registry +} + +# +# Delete a kind cluster if it exists +# +function delete_cluster() { + kind delete cluster --name $KIND_CLUSTER_NAME +} + +# +# Create a local KIND cluster +# +function create_cluster() { + cat << EOF | kind create cluster --name $KIND_CLUSTER_NAME --image $KIND_CLUSTER_IMAGE --config=- +--- +kind: Cluster +apiVersion: kind.x-k8s.io/v1alpha4 +nodes: + - role: control-plane + kubeadmConfigPatches: + - | + kind: InitConfiguration + nodeRegistration: + kubeletExtraArgs: + node-labels: "ingress-ready=true" + extraPortMappings: + - containerPort: 80 + hostPort: 80 + protocol: TCP + - containerPort: 443 + hostPort: 443 + protocol: TCP +networking: + apiServerAddress: ${KIND_API_SERVER_ADDRESS} + apiServerPort: ${KIND_API_SERVER_PORT} + +# create a cluster with the local registry enabled in containerd +containerdConfigPatches: +- |- + [plugins."io.containerd.grpc.v1.cri".registry.mirrors."localhost:${CONTAINER_REGISTRY_PORT}"] + endpoint = ["http://${CONTAINER_REGISTRY_NAME}:${CONTAINER_REGISTRY_PORT}"] +EOF + + # + # Work around a bug in KIND where DNS is not always resolved correctly on machines with IPv6 + # + for node in $(kind get nodes); + do + docker exec "$node" sysctl net.ipv4.conf.all.route_localnet=1; + done +} + +# +# Install cert-manager.io +# +function start_cert_manager() { + kubectl apply -f https://github.com/cert-manager/cert-manager/releases/download/v1.10.0/cert-manager.yaml + + sleep 5 + + kubectl -n cert-manager rollout status deploy/cert-manager + kubectl -n cert-manager rollout status deploy/cert-manager-cainjector + kubectl -n cert-manager rollout status deploy/cert-manager-webhook + + # Check for a root CA certificate / secret created by a previous cluster. If present, re-use the + # cert as it could have been imported into the system's keychain. + # TODO: this would be best stored outside of the project - maybe override with an ENV? + local issuer_secret_path=kind/cert-manager/ca-issuer-secret.yaml + if test -f ${issuer_secret_path}; then + echo "Overriding CA root issuer secret" ${issuer_secret_path} + kubectl -n cert-manager create -f ${issuer_secret_path} + fi + + # Apply the cert-manager cluster-issuers + kubectl -n cert-manager apply -k kind/cert-manager + + # Save the root cert for future use in future KIND clusters + if ! test -f ${issuer_secret_path}; then + # todo: use a better wait for the issuer to be ready / secret to be created + sleep 5 + kubectl -n cert-manager get secret ca-issuer-secret -o yaml > ${issuer_secret_path} + fi +} + +# +# Install an Nginx ingress controller bound to port 80 and 443. +# +function start_nginx() { + kubectl apply -k kind/nginx + + sleep 10 + + kubectl wait \ + --namespace ingress-nginx \ + --for=condition=ready pod \ + --selector=app.kubernetes.io/component=controller \ + --timeout=3m +} + +# +# Override Core DNS with a wildcard matcher for the "*.localho.st" domain, binding to the +# IP address of the Nginx ingress controller on the kubernetes internal network. Effectively this +# "steals" the domain name for *.localho.st, directing traffic to the Nginx load balancer, rather +# than to the loopback interface at 127.0.0.1. +# +function apply_coredns_override() { + CLUSTER_IP=$(kubectl -n ingress-nginx get svc ingress-nginx-controller -o json | jq -r .spec.clusterIP) + + cat << EOF | kubectl apply -f - +--- +kind: ConfigMap +apiVersion: v1 +metadata: + name: coredns + namespace: kube-system +data: + Corefile: | + .:53 { + errors + health { + lameduck 5s + } + ready + rewrite name regex (.*)\.localho\.st host.ingress.internal + hosts { + ${CLUSTER_IP} host.ingress.internal + fallthrough + } + kubernetes cluster.local in-addr.arpa ip6.arpa { + pods insecure + fallthrough in-addr.arpa ip6.arpa + ttl 30 + } + prometheus :9153 + forward . /etc/resolv.conf { + max_concurrent 1000 + } + cache 30 + loop + reload + loadbalance + } +EOF + + kubectl -n kube-system rollout restart deployment/coredns +} + +function launch_docker_registry() { + + # create registry container unless it already exists + running="$(docker inspect -f '{{.State.Running}}' "${reg_name}" 2>/dev/null || true)" + if [ "${running}" != 'true' ]; then + docker run \ + --detach \ + --restart always \ + --name "${CONTAINER_REGISTRY_NAME}" \ + --publish "${CONTAINER_REGISTRY_ADDRESS}:${CONTAINER_REGISTRY_PORT}:${CONTAINER_REGISTRY_PORT}" \ + registry:2 + fi + + # connect the registry to the cluster network + # (the network may already be connected) + docker network connect "kind" "${CONTAINER_REGISTRY_NAME}" || true + + # Document the local registry + # https://github.com/kubernetes/enhancements/tree/master/keps/sig-cluster-lifecycle/generic/1755-communicating-a-local-registry + cat </dev/null ; then + printf "\r%s %-30s" $SUCCESS $name + else + printf "\r%s %-30s" $WARN $name + EXIT=1 + fi + + echo $message +} + +function wait_for() { + local type=$1 + local name=$2 + + kubectl -n ${NAMESPACE} wait $type $name --for jsonpath='{.status.type}'=Deployed --timeout=3m + kubectl -n ${NAMESPACE} rollout status deploy $name +} + +function apply_template() { + local template=$1 + cat ${template} | envsubst | kubectl -n ${NAMESPACE} apply -f - +} + +# Read a certificate by name from a node connection-profile config map. +function connection_profile_cert() { + local node=$1 + local path=$2 + + kubectl -n ${NAMESPACE} get cm/${node}-connection-profile -o json \ + | jq -r .binaryData.\"profile.json\" \ + | base64 -d \ + | jq -r ${path} +} + +# Extract, decode, and save a certificate in .pem format to a local file +function write_pem() { + local node=$1 + local jq_path=$2 + local to_file=$3 + + mkdir -p $(dirname $to_file) + + echo $(connection_profile_cert $node $jq_path) | base64 -d >& $to_file +} + +# create an enrollment MSP config.yaml +function write_msp_config() { + local ca_name=$1 + local ca_cert_name=$2 + local msp_dir=$3 + + cat << EOF > ${msp_dir}/config.yaml +NodeOUs: + Enable: true + ClientOUIdentifier: + Certificate: cacerts/${ca_cert_name} + OrganizationalUnitIdentifier: client + PeerOUIdentifier: + Certificate: cacerts/${ca_cert_name} + OrganizationalUnitIdentifier: peer + AdminOUIdentifier: + Certificate: cacerts/${ca_cert_name} + OrganizationalUnitIdentifier: admin + OrdererOUIdentifier: + Certificate: cacerts/${ca_cert_name} + OrganizationalUnitIdentifier: orderer +EOF +} + +# Enroll a user at an org CA. +function enroll() { + do_enroll msp ca $@ +} + +# Enroll a user at an org TLS CA +function enroll_tls() { + do_enroll tls tlsca $@ +} + +function do_enroll() { + local msp_type=$1 + local caname=$2 + local org=$3 + local user=$4 + local pazz=$5 + + # Skip the enrollment if a previous enrollment key exists. + local user_dir=$ENROLLMENTS_DIR/$user + local user_key=$user_dir/$msp_type/keystore/key.pem + + if [ -f "$user_key" ]; then + print "$user has already been enrolled at $org $caname" + return + fi + + print "enrolling $org $caname $user" + local ca_url=https://${user}:${pazz}@${org}-ca-ca.${org}.localho.st + local tls_certfile=$ENROLLMENTS_DIR/ca-tls-cert.pem + + fabric-ca-client enroll \ + --url $ca_url \ + --tls.certfiles $tls_certfile \ + --mspdir $user_dir/$msp_type \ + --caname $caname + + # Enrollment creates a key with a dynamic, hashed file name. Move this to a predictable location + mv $user_dir/$msp_type/keystore/*_sk $user_key +} + +# Set the peer CLI environment in order to run commands as an org admin +function appear_as() { + local mspid=$1 + local org=$2 + local peer=$3 + + export FABRIC_CFG_PATH=${PWD}/channel-config/config + export CORE_PEER_ADDRESS=${org}-${peer}-peer.${org}.localho.st:443 + export CORE_PEER_LOCALMSPID=${mspid} + export CORE_PEER_MSPCONFIGPATH=$PWD/organizations/${org}/enrollments/${org}admin/msp + export CORE_PEER_TLS_ENABLED=true + export CORE_PEER_TLS_ROOTCERT_FILE=$PWD/channel-config/organizations/peerOrganizations/${org}.localho.st/msp/tlscacerts/tlsca-signcert.pem + export CORE_PEER_CLIENT_CONNTIMEOUT=15s + export CORE_PEER_DELIVERYCLIENT_CONNTIMEOUT=15s + + export ORDERER_ENDPOINT=org0-orderernode1-orderer.org0.localho.st:443 + export ORDERER_TLS_CERT=${PWD}/channel-config/organizations/ordererOrganizations/org0.localho.st/orderers/orderernode1/tls/signcerts/tls-cert.pem +} From 9547bd5048786c345b620f5310de160b391f05bf Mon Sep 17 00:00:00 2001 From: Abirdcfly Date: Wed, 15 Mar 2023 09:23:00 +0800 Subject: [PATCH 39/41] fix: when not using couchdb, the resources of peer's init container does not take effect Signed-off-by: Abirdcfly --- pkg/offering/base/peer/override/deployment.go | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/pkg/offering/base/peer/override/deployment.go b/pkg/offering/base/peer/override/deployment.go index ab6233e9..c52e5f47 100644 --- a/pkg/offering/base/peer/override/deployment.go +++ b/pkg/offering/base/peer/override/deployment.go @@ -709,6 +709,13 @@ func (o *Override) CommonDeploymentOverrides(instance *current.IBPPeer, deployme } } + if resourcesRequest.Init != nil { + err = initContainer.UpdateResources(resourcesRequest.Init) + if err != nil { + return errors.Wrap(err, "resource update for init failed") + } + } + if instance.UsingCouchDB() { couchdb := deployment.MustGetContainer(COUCHDB) if resourcesRequest.CouchDB != nil { From 282ca83c4c3fc3ac013609737a638ec6b7013d6c Mon Sep 17 00:00:00 2001 From: Abirdcfly Date: Wed, 15 Mar 2023 09:33:01 +0800 Subject: [PATCH 40/41] fix: E2E testing failed but displayed success Signed-off-by: Abirdcfly --- .github/workflows/endtoend-tests.yaml | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/.github/workflows/endtoend-tests.yaml b/.github/workflows/endtoend-tests.yaml index ba39aa45..d250b196 100644 --- a/.github/workflows/endtoend-tests.yaml +++ b/.github/workflows/endtoend-tests.yaml @@ -31,4 +31,8 @@ jobs: - uses: actions/checkout@v3 - name: Sample Network E2E Test - run: sample-network/scripts/run-e2e-test.sh || cat sample-network/network-debug.log + run: sample-network/scripts/run-e2e-test.sh + + - name: Show Debug Log + if: ${{ always() }} + run: cat sample-network/network-debug.log From 4082bb8e7cfad9f3801aac9568a9ec6f47b7e717 Mon Sep 17 00:00:00 2001 From: shoaebjindani <40020259+shoaebjindani@users.noreply.github.com> Date: Thu, 18 May 2023 19:02:58 +0530 Subject: [PATCH 41/41] Removed IBM Confidencial License (#110) https://github.com/hyperledger-labs/fabric-operator/issues/109 Signed-off-by: Shoaeb Jindani --- sample-network-multi-org/config/configtx.yaml | 16 ++++++++++++-- sample-network-multi-org/config/core.yaml | 15 ++++++++++++- sample-network-multi-org/config/orderer.yaml | 15 ++++++++++++- .../scripts/kind_with_nginx.sh | 21 ++++++++++++------- sample-network-multi-org/scripts/test-e2e.sh | 15 ++++++++++++- 5 files changed, 69 insertions(+), 13 deletions(-) diff --git a/sample-network-multi-org/config/configtx.yaml b/sample-network-multi-org/config/configtx.yaml index 9bc4e1fc..d03c90eb 100644 --- a/sample-network-multi-org/config/configtx.yaml +++ b/sample-network-multi-org/config/configtx.yaml @@ -1,8 +1,20 @@ -# Copyright IBM Corp. All Rights Reserved. +# +# Copyright contributors to the Hyperledger Fabric Operator project # # SPDX-License-Identifier: Apache-2.0 # - +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at: +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# --- ################################################################################ # diff --git a/sample-network-multi-org/config/core.yaml b/sample-network-multi-org/config/core.yaml index 7809b001..9157e3de 100644 --- a/sample-network-multi-org/config/core.yaml +++ b/sample-network-multi-org/config/core.yaml @@ -1,7 +1,20 @@ -# Copyright IBM Corp. All Rights Reserved. +# +# Copyright contributors to the Hyperledger Fabric Operator project # # SPDX-License-Identifier: Apache-2.0 # +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at: +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# ############################################################################### # diff --git a/sample-network-multi-org/config/orderer.yaml b/sample-network-multi-org/config/orderer.yaml index 6c555f93..b680cf7c 100644 --- a/sample-network-multi-org/config/orderer.yaml +++ b/sample-network-multi-org/config/orderer.yaml @@ -1,7 +1,20 @@ -# Copyright IBM Corp. All Rights Reserved. +# +# Copyright contributors to the Hyperledger Fabric Operator project # # SPDX-License-Identifier: Apache-2.0 # +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at: +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# --- ################################################################################ diff --git a/sample-network-multi-org/scripts/kind_with_nginx.sh b/sample-network-multi-org/scripts/kind_with_nginx.sh index c90be079..a0001bf7 100755 --- a/sample-network-multi-org/scripts/kind_with_nginx.sh +++ b/sample-network-multi-org/scripts/kind_with_nginx.sh @@ -1,15 +1,20 @@ #!/bin/bash - # -# IBM Confidential -# OCO Source Materials +# Copyright contributors to the Hyperledger Fabric Operator project +# +# SPDX-License-Identifier: Apache-2.0 +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at: # -# Organic Growth Ventures -# (C) Copyright IBM Corp. 2022 All Rights Reserved. +# http://www.apache.org/licenses/LICENSE-2.0 # -# The source code for this program is not published or otherwise -# divested of its trade secrets, irrespective of what has been -# deposited with the U.S. Copyright Office. +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. # set -eo pipefail diff --git a/sample-network-multi-org/scripts/test-e2e.sh b/sample-network-multi-org/scripts/test-e2e.sh index ce95d984..3c873792 100755 --- a/sample-network-multi-org/scripts/test-e2e.sh +++ b/sample-network-multi-org/scripts/test-e2e.sh @@ -1,9 +1,22 @@ #!/usr/bin/env bash # -# Copyright IBM Corp All Rights Reserved +# Copyright contributors to the Hyperledger Fabric Operator project # # SPDX-License-Identifier: Apache-2.0 # +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at: +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# + set -euo pipefail function print() {