From b34e3ec57b51aa2a8c51148a7fb767db2a291273 Mon Sep 17 00:00:00 2001 From: David Viejo Date: Mon, 5 Feb 2024 09:36:06 +0100 Subject: [PATCH] Feat/small feats (#209) * NetworkConfig: filter the peers to be added per organization * Filter peers by org, global peers and global CAs * Add `FabricChaincodeTemplate` CRD * update * Add support for FabricChaincodeTemplateRef in FabricChaincodeSpec Signed-off-by: David VIEJO * update * Update helm chart in pipelien Signed-off-by: David VIEJO * Update Signed-off-by: David VIEJO * update Signed-off-by: David VIEJO * Update Signed-off-by: David VIEJO * update * fabric-config 0.1.0 -> 0.2.1 Add ports 443 for the peer * Upgrade to go 1.21 * Add adminURL in the network config if available * Update pipelines to 1.21 * Add command to get the next sequence and version for a chaincode based on chaincode definition Signed-off-by: David VIEJO * update Signed-off-by: David VIEJO * update Signed-off-by: David VIEJO * update Signed-off-by: David VIEJO --------- Signed-off-by: David VIEJO Signed-off-by: David Viejo --- controllers/ca/ca_controller.go | 85 ++++++--- controllers/chaincode/chaincode_controller.go | 3 + .../followerchannel_controller.go | 5 +- .../mainchannel/mainchannel_controller.go | 4 +- controllers/ordnode/ordnode_controller.go | 30 +++- controllers/peer/peer_controller.go | 38 +++- kubectl-hlf/cmd/chaincode/chaincode.go | 1 + kubectl-hlf/cmd/chaincode/getnext.go | 166 ++++++++++++++++++ kubectl-hlf/cmd/chaincode/query.go | 7 +- main.go | 2 + 10 files changed, 300 insertions(+), 41 deletions(-) create mode 100644 kubectl-hlf/cmd/chaincode/getnext.go diff --git a/controllers/ca/ca_controller.go b/controllers/ca/ca_controller.go index 2c90e72a..3ee12e5b 100644 --- a/controllers/ca/ca_controller.go +++ b/controllers/ca/ca_controller.go @@ -933,6 +933,32 @@ func Reconcile( // it doesn't exist return ctrl.Result{}, err } + } else if exists && helmStatus.Info.Status == release.StatusPendingRollback { + historyAction := action.NewHistory(cfg) + history, err := historyAction.Run(releaseName) + if err != nil { + return ctrl.Result{}, err + } + if len(history) > 0 { + // find the last deployed revision + // and rollback to it + // sort history by revision number descending using raw go + sort.Slice(history, func(i, j int) bool { + return history[i].Version > history[j].Version + }) + for _, historyItem := range history { + if historyItem.Info.Status == release.StatusDeployed { + rollbackStatus := action.NewRollback(cfg) + rollbackStatus.Version = historyItem.Version + err = rollbackStatus.Run(releaseName) + if err != nil { + // it doesn't exist + return ctrl.Result{}, err + } + break + } + } + } } log.Debugf("Release %s exists=%v", releaseName, exists) clientSet, err := utils.GetClientKubeWithConf(r.Config) @@ -969,35 +995,38 @@ func Reconcile( Status: "True", LastTransitionTime: v1.Time{}, }) - c, err := GetConfig(hlf, clientSet, releaseName, req.Namespace) - if err != nil { - return ctrl.Result{}, err - } - inrec, err := json.Marshal(c) - if err != nil { - return ctrl.Result{}, err - } - var inInterface map[string]interface{} - err = json.Unmarshal(inrec, &inInterface) - if err != nil { - return ctrl.Result{}, err - } - cmd := action.NewUpgrade(cfg) - cmd.Timeout = r.Timeout - cmd.Wait = r.Wait - cmd.MaxHistory = r.MaxHistory - settings := cli.New() - chartPath, err := cmd.LocateChart(r.ChartPath, settings) - ch, err := loader.Load(chartPath) - if err != nil { - return ctrl.Result{}, err - } - release, err := cmd.Run(releaseName, ch, inInterface) - if err != nil { - setConditionStatus(hlf, hlfv1alpha1.FailedStatus, false, err, false) - return r.updateCRStatusOrFailReconcile(ctx, r.Log, hlf) + if helmStatus.Info.Status != release.StatusPendingUpgrade { + c, err := GetConfig(hlf, clientSet, releaseName, req.Namespace) + if err != nil { + return ctrl.Result{}, err + } + inrec, err := json.Marshal(c) + if err != nil { + return ctrl.Result{}, err + } + var inInterface map[string]interface{} + err = json.Unmarshal(inrec, &inInterface) + if err != nil { + return ctrl.Result{}, err + } + cmd := action.NewUpgrade(cfg) + cmd.Timeout = r.Timeout + cmd.Wait = r.Wait + cmd.MaxHistory = r.MaxHistory + + settings := cli.New() + chartPath, err := cmd.LocateChart(r.ChartPath, settings) + ch, err := loader.Load(chartPath) + if err != nil { + return ctrl.Result{}, err + } + release, err := cmd.Run(releaseName, ch, inInterface) + if err != nil { + setConditionStatus(hlf, hlfv1alpha1.FailedStatus, false, err, false) + return r.updateCRStatusOrFailReconcile(ctx, r.Log, hlf) + } + log.Debugf("Chart upgraded %s", release.Name) } - log.Debugf("Chart upgraded %s", release.Name) if !reflect.DeepEqual(fca.Status, hlf.Status) { if err := r.Status().Update(ctx, fca); err != nil { log.Debugf("Error updating the status: %v", err) diff --git a/controllers/chaincode/chaincode_controller.go b/controllers/chaincode/chaincode_controller.go index b3c78834..38d0da8b 100644 --- a/controllers/chaincode/chaincode_controller.go +++ b/controllers/chaincode/chaincode_controller.go @@ -459,6 +459,9 @@ func (r *FabricChaincodeReconciler) Reconcile(ctx context.Context, req ctrl.Requ FailureThreshold: 3, }, } + if fabricChaincode.Spec.Resources != nil { + container.Resources = *fabricChaincode.Spec.Resources + } if fabricChaincode.Spec.Command != nil { container.Command = fabricChaincode.Spec.Command } diff --git a/controllers/followerchannel/followerchannel_controller.go b/controllers/followerchannel/followerchannel_controller.go index 4421bfba..325b04ed 100644 --- a/controllers/followerchannel/followerchannel_controller.go +++ b/controllers/followerchannel/followerchannel_controller.go @@ -37,6 +37,7 @@ import ( "sigs.k8s.io/controller-runtime/pkg/controller/controllerutil" "sigs.k8s.io/controller-runtime/pkg/reconcile" "strings" + "time" ) // FabricFollowerChannelReconciler reconciles a FabricFollowerChannel object @@ -385,7 +386,9 @@ func (r *FabricFollowerChannelReconciler) updateCRStatusOrFailReconcile(ctx cont log.Error(err, fmt.Sprintf("%v failed to update the application status", ErrClientK8s)) return reconcile.Result{}, err } - return reconcile.Result{}, nil + return reconcile.Result{ + RequeueAfter: 1 * time.Minute, + }, nil } func (r *FabricFollowerChannelReconciler) setConditionStatus(ctx context.Context, p *hlfv1alpha1.FabricFollowerChannel, conditionType hlfv1alpha1.DeploymentStatus, statusFlag bool, err error, statusUnknown bool) (update bool) { diff --git a/controllers/mainchannel/mainchannel_controller.go b/controllers/mainchannel/mainchannel_controller.go index c591996d..cbad3646 100644 --- a/controllers/mainchannel/mainchannel_controller.go +++ b/controllers/mainchannel/mainchannel_controller.go @@ -763,7 +763,9 @@ func (r *FabricMainChannelReconciler) updateCRStatusOrFailReconcile(ctx context. log.Error(err, fmt.Sprintf("%v failed to update the application status", ErrClientK8s)) return reconcile.Result{}, err } - return reconcile.Result{}, nil + return reconcile.Result{ + RequeueAfter: 1 * time.Minute, + }, nil } func (r *FabricMainChannelReconciler) setConditionStatus(ctx context.Context, p *hlfv1alpha1.FabricMainChannel, conditionType hlfv1alpha1.DeploymentStatus, statusFlag bool, err error, statusUnknown bool) (update bool) { diff --git a/controllers/ordnode/ordnode_controller.go b/controllers/ordnode/ordnode_controller.go index 529558e6..495ae058 100644 --- a/controllers/ordnode/ordnode_controller.go +++ b/controllers/ordnode/ordnode_controller.go @@ -11,6 +11,7 @@ import ( "helm.sh/helm/v3/pkg/release" "os" "reflect" + "sort" "strings" "time" @@ -162,6 +163,32 @@ func (r *FabricOrdererNodeReconciler) Reconcile(ctx context.Context, req ctrl.Re // it doesn't exist return ctrl.Result{}, err } + } else if exists && helmStatus.Info.Status == release.StatusPendingRollback { + historyAction := action.NewHistory(cfg) + history, err := historyAction.Run(releaseName) + if err != nil { + return ctrl.Result{}, err + } + if len(history) > 0 { + // find the last deployed revision + // and rollback to it + // sort history by revision number descending using raw go + sort.Slice(history, func(i, j int) bool { + return history[i].Version > history[j].Version + }) + for _, historyItem := range history { + if historyItem.Info.Status == release.StatusDeployed { + rollbackStatus := action.NewRollback(cfg) + rollbackStatus.Version = historyItem.Version + err = rollbackStatus.Run(releaseName) + if err != nil { + // it doesn't exist + return ctrl.Result{}, err + } + break + } + } + } } log.Printf("Release %s exists=%v", releaseName, exists) clientSet, err := utils.GetClientKubeWithConf(r.Config) @@ -216,7 +243,7 @@ func (r *FabricOrdererNodeReconciler) Reconcile(ctx context.Context, req ctrl.Re lastTimeCertsRenewed = &newTime log.Infof("Certs updated, last time updated: %v", lastTimeCertsRenewed) requeueAfter = time.Minute * 1 - } else { + } else if helmStatus.Info.Status != release.StatusPendingUpgrade { c, err := getConfig(fabricOrdererNode, clientSet, releaseName, req.Namespace, false) if err != nil { return ctrl.Result{}, err @@ -478,6 +505,7 @@ func (r *FabricOrdererNodeReconciler) upgradeChart( cmd.Wait = r.Wait cmd.Timeout = r.Timeout cmd.MaxHistory = r.MaxHistory + release, err := cmd.Run(releaseName, ch, inInterface) if err != nil { return err diff --git a/controllers/peer/peer_controller.go b/controllers/peer/peer_controller.go index c687fc48..1b6bfbdf 100644 --- a/controllers/peer/peer_controller.go +++ b/controllers/peer/peer_controller.go @@ -11,6 +11,7 @@ import ( "helm.sh/helm/v3/pkg/release" "os" "reflect" + "sort" "strings" "time" @@ -378,6 +379,32 @@ func (r *FabricPeerReconciler) Reconcile(ctx context.Context, req ctrl.Request) // it doesn't exist return ctrl.Result{}, err } + } else if exists && helmStatus.Info.Status == release.StatusPendingRollback { + historyAction := action.NewHistory(cfg) + history, err := historyAction.Run(releaseName) + if err != nil { + return ctrl.Result{}, err + } + if len(history) > 0 { + // find the last deployed revision + // and rollback to it + // sort history by revision number descending using raw go + sort.Slice(history, func(i, j int) bool { + return history[i].Version > history[j].Version + }) + for _, historyItem := range history { + if historyItem.Info.Status == release.StatusDeployed { + rollbackStatus := action.NewRollback(cfg) + rollbackStatus.Version = historyItem.Version + err = rollbackStatus.Run(releaseName) + if err != nil { + // it doesn't exist + return ctrl.Result{}, err + } + break + } + } + } } log.Debugf("Release %s exists=%v", releaseName, exists) clientSet, err := utils.GetClientKubeWithConf(r.Config) @@ -449,11 +476,12 @@ func (r *FabricPeerReconciler) Reconcile(ctx context.Context, req ctrl.Request) r.setConditionStatus(ctx, fabricPeer, hlfv1alpha1.FailedStatus, false, err, false) return r.updateCRStatusOrFailReconcile(ctx, r.Log, fabricPeer) } - - err = r.upgradeChart(cfg, err, ns, releaseName, c) - if err != nil { - r.setConditionStatus(ctx, fabricPeer, hlfv1alpha1.FailedStatus, false, err, false) - return r.updateCRStatusOrFailReconcile(ctx, r.Log, fabricPeer) + if helmStatus.Info.Status != release.StatusPendingUpgrade { + err = r.upgradeChart(cfg, err, ns, releaseName, c) + if err != nil { + r.setConditionStatus(ctx, fabricPeer, hlfv1alpha1.FailedStatus, false, err, false) + return r.updateCRStatusOrFailReconcile(ctx, r.Log, fabricPeer) + } } requeueAfter = time.Minute * 10 } diff --git a/kubectl-hlf/cmd/chaincode/chaincode.go b/kubectl-hlf/cmd/chaincode/chaincode.go index 7dd16335..83977172 100644 --- a/kubectl-hlf/cmd/chaincode/chaincode.go +++ b/kubectl-hlf/cmd/chaincode/chaincode.go @@ -22,6 +22,7 @@ func NewChaincodeCmd(stdOut io.Writer, stdErr io.Writer) *cobra.Command { newCalculatePackageIDCMD(stdOut, stdErr), newGetLatestInfoCMD(stdOut, stdErr), newCheckCommitReadiness(stdOut, stdErr), + newGetNextCMD(stdOut, stdErr), ) return consortiumCmd } diff --git a/kubectl-hlf/cmd/chaincode/getnext.go b/kubectl-hlf/cmd/chaincode/getnext.go new file mode 100644 index 00000000..284c2dcd --- /dev/null +++ b/kubectl-hlf/cmd/chaincode/getnext.go @@ -0,0 +1,166 @@ +package chaincode + +import ( + pb "github.com/hyperledger/fabric-protos-go/peer" + "github.com/hyperledger/fabric-sdk-go/pkg/client/resmgmt" + "github.com/hyperledger/fabric-sdk-go/pkg/core/config" + "github.com/hyperledger/fabric-sdk-go/pkg/fabsdk" + "github.com/hyperledger/fabric/common/policydsl" + "github.com/kfsoftware/hlf-operator/kubectl-hlf/cmd/helpers" + "github.com/pkg/errors" + log "github.com/sirupsen/logrus" + "github.com/spf13/cobra" + "io" + "io/ioutil" + "os" + "strconv" +) + +type getNextCmd struct { + configPath string + userName string + channelName string + name string + mspID string + property string + outFile string + peer string + policy string + initRequired bool + collectionsConfig string +} + +func (c *getNextCmd) validate() error { + if c.property != "version" && c.property != "sequence" { + return errors.New("property must be either version or sequence") + } + if c.outFile == "" { + return errors.New("output file is required") + } + return nil +} +func (c *getNextCmd) run(out io.Writer, stdErr io.Writer) error { + mspID := c.mspID + configBackend := config.FromFile(c.configPath) + sdk, err := fabsdk.New(configBackend) + if err != nil { + return err + } + org1AdminClientContext := sdk.Context( + fabsdk.WithUser(c.userName), + fabsdk.WithOrg(mspID), + ) + resClient, err := resmgmt.New(org1AdminClientContext) + if err != nil { + return err + } + committedCCs, err := resClient.LifecycleQueryCommittedCC(c.channelName, resmgmt.LifecycleQueryCommittedCCRequest{Name: c.name}) + if err != nil { + return err + } + if len(committedCCs) == 0 { + return errors.New("no chaincode found") + } + var collections []*pb.CollectionConfig + if c.collectionsConfig != "" { + // + pdcBytes, err := os.ReadFile(c.collectionsConfig) + if err != nil { + return err + } + collections, err = helpers.GetCollectionConfigFromBytes(pdcBytes) + if err != nil { + return err + } + } + sp, err := policydsl.FromString(c.policy) + if err != nil { + return err + } + shouldCommit := len(committedCCs) == 0 + if len(committedCCs) > 0 { + firstCommittedCC := committedCCs[0] + signaturePolicyString := firstCommittedCC.SignaturePolicy.String() + newSignaturePolicyString := sp.String() + if signaturePolicyString != newSignaturePolicyString { + log.Debugf("Signature policy changed, old=%s new=%s", signaturePolicyString, newSignaturePolicyString) + shouldCommit = true + } else { + log.Debugf("Signature policy not changed, signaturePolicy=%s", signaturePolicyString) + } + // compare collections + oldCollections := firstCommittedCC.CollectionConfig + newCollections := collections + if len(oldCollections) != len(newCollections) { + log.Infof("Collection config changed, old=%d new=%d", len(oldCollections), len(newCollections)) + shouldCommit = true + } else { + for idx, oldCollection := range oldCollections { + oldCollectionPayload := oldCollection.Payload.(*pb.CollectionConfig_StaticCollectionConfig) + newCollection := newCollections[idx] + newCollectionPayload := newCollection.Payload.(*pb.CollectionConfig_StaticCollectionConfig) + if oldCollectionPayload.StaticCollectionConfig.Name != newCollectionPayload.StaticCollectionConfig.Name { + log.Infof("Collection config changed, old=%s new=%s", oldCollectionPayload.StaticCollectionConfig.Name, newCollectionPayload.StaticCollectionConfig.Name) + shouldCommit = true + break + } + oldCollectionPolicy := oldCollection.GetStaticCollectionConfig().MemberOrgsPolicy + newCollectionPolicy := newCollection.GetStaticCollectionConfig().MemberOrgsPolicy + if oldCollectionPolicy.GetSignaturePolicy().String() != newCollectionPolicy.GetSignaturePolicy().String() { + log.Infof("Collection config changed, old=%s new=%s", oldCollectionPolicy.GetSignaturePolicy().String(), newCollectionPolicy.GetSignaturePolicy().String()) + shouldCommit = true + break + } + } + } + } + + latestCC := committedCCs[len(committedCCs)-1] + var data []byte + if c.property == "version" { + data = []byte(latestCC.Version) + } else { + if shouldCommit { + data = []byte(strconv.FormatInt(latestCC.Sequence+1, 10)) + } else { + data = []byte(strconv.FormatInt(latestCC.Sequence, 10)) + } + } + err = ioutil.WriteFile(c.outFile, data, 0777) + if err != nil { + return err + } + return nil +} +func newGetNextCMD(out io.Writer, errOut io.Writer) *cobra.Command { + c := &getNextCmd{} + cmd := &cobra.Command{ + Use: "getnext", + RunE: func(cmd *cobra.Command, args []string) error { + if err := c.validate(); err != nil { + return err + } + return c.run(out, errOut) + }, + } + persistentFlags := cmd.PersistentFlags() + persistentFlags.StringVarP(&c.configPath, "config", "", "", "Configuration file for the SDK") + persistentFlags.StringVarP(&c.userName, "user", "", "", "User name for the transaction") + persistentFlags.StringVarP(&c.channelName, "channel", "", "", "Channel name") + persistentFlags.StringVarP(&c.name, "name", "", "", "Chaincode name") + persistentFlags.StringVarP(&c.mspID, "msp-id", "", "", "MSP ID of the organization") + persistentFlags.StringVarP(&c.property, "property", "", "", "Property to get(\"version\" or \"sequence\")") + persistentFlags.StringVarP(&c.outFile, "out", "o", "", "File to write the property to") + persistentFlags.StringVarP(&c.peer, "peer", "p", "", "Peer org to invoke the updates") + persistentFlags.StringVarP(&c.policy, "policy", "", "", "Policy") + persistentFlags.BoolVarP(&c.initRequired, "init-required", "", false, "Init required") + persistentFlags.StringVarP(&c.collectionsConfig, "collections-config", "", "", "Private data collections") + + cmd.MarkPersistentFlagRequired("user") + cmd.MarkPersistentFlagRequired("config") + cmd.MarkPersistentFlagRequired("channel") + cmd.MarkPersistentFlagRequired("name") + cmd.MarkPersistentFlagRequired("msp-id") + cmd.MarkPersistentFlagRequired("out") + return cmd +} diff --git a/kubectl-hlf/cmd/chaincode/query.go b/kubectl-hlf/cmd/chaincode/query.go index bd21b892..aa867913 100644 --- a/kubectl-hlf/cmd/chaincode/query.go +++ b/kubectl-hlf/cmd/chaincode/query.go @@ -3,14 +3,12 @@ package chaincode import ( "encoding/json" "fmt" - "io" - "time" - "github.com/hyperledger/fabric-sdk-go/pkg/client/channel" "github.com/hyperledger/fabric-sdk-go/pkg/core/config" "github.com/hyperledger/fabric-sdk-go/pkg/fabsdk" "github.com/kfsoftware/hlf-operator/kubectl-hlf/cmd/helpers" "github.com/spf13/cobra" + "io" ) type queryChaincodeCmd struct { @@ -73,7 +71,7 @@ func (c *queryChaincodeCmd) run(out io.Writer) error { return err } } - t := time.Now() + response, err := ch.Query( channel.Request{ ChaincodeID: c.chaincode, @@ -88,7 +86,6 @@ func (c *queryChaincodeCmd) run(out io.Writer) error { if err != nil { return err } - fmt.Printf("Query took %s\n", time.Since(t)) _, err = fmt.Fprint(out, string(response.Payload)) if err != nil { return err diff --git a/main.go b/main.go index 636cfb82..a1531c1f 100644 --- a/main.go +++ b/main.go @@ -95,8 +95,10 @@ func main() { flag.Parse() log.Infof("Auto renew peer certificates enabled: %t", autoRenewCertificatesPeerEnabled) log.Infof("Auto renew orderer certificates enabled: %t", autoRenewCertificatesOrdererEnabled) + log.Infof("Auto renew identity certificates enabled: %t", autoRenewCertificatesIdentityEnabled) log.Infof("Auto renew peer certificates delta: %s", autoRenewPeerCertificatesDelta) log.Infof("Auto renew orderer certificates delta: %s", autoRenewOrdererCertificatesDelta) + log.Infof("Auto renew identity certificates delta: %s", autoRenewIdentityCertificatesDelta) // Pass a Config struct // to initialize a Client struct // which implements Client interface