Skip to content

Commit

Permalink
Add inspect option into checkcommitreadiness command to output discre…
Browse files Browse the repository at this point in the history
…pancy details

Signed-off-by: Tatsuya Sato <tatsuya.sato.so@hitachi.com>
  • Loading branch information
satota2 authored and denyeart committed Oct 11, 2023
1 parent ca9d10f commit e308da8
Show file tree
Hide file tree
Showing 4 changed files with 105 additions and 1 deletion.
1 change: 1 addition & 0 deletions docs/source/commands/peerlifecycle.md
Original file line number Diff line number Diff line change
Expand Up @@ -311,6 +311,7 @@ Flags:
-E, --endorsement-plugin string The name of the endorsement plugin to be used for this chaincode
-h, --help help for checkcommitreadiness
--init-required Whether the chaincode requires invoking 'init'
--inspect If inspect is enabled, output additional information to identify discrepancies when an organization's approval is false
-n, --name string Name of the chaincode
-O, --output string The output format for query results. Default is human-readable plain-text. json is currently the only supported format.
--peerAddresses stringArray The addresses of the peers to connect to
Expand Down
2 changes: 2 additions & 0 deletions internal/peer/lifecycle/chaincode/chaincode.go
Original file line number Diff line number Diff line change
Expand Up @@ -70,6 +70,7 @@ var (
sequence int
initRequired bool
output string
inspectionEnabled bool
outputDirectory string
)

Expand Down Expand Up @@ -119,6 +120,7 @@ func ResetFlags() {
flags.IntVarP(&sequence, "sequence", "", 0, "The sequence number of the chaincode definition for the channel")
flags.BoolVarP(&initRequired, "init-required", "", false, "Whether the chaincode requires invoking 'init'")
flags.StringVarP(&output, "output", "O", "", "The output format for query results. Default is human-readable plain-text. json is currently the only supported format.")
flags.BoolVarP(&inspectionEnabled, "inspect", "", false, "If inspect is enabled, output additional information to identify discrepancies when an organization's approval is false")
flags.StringVarP(&outputDirectory, "output-directory", "", "", "The output directory to use when writing a chaincode install package to disk. Default is the current working directory.")
}

Expand Down
51 changes: 50 additions & 1 deletion internal/peer/lifecycle/chaincode/checkcommitreadiness.go
Original file line number Diff line number Diff line change
Expand Up @@ -57,6 +57,7 @@ type CommitReadinessCheckInput struct {
PeerAddresses []string
TxID string
OutputFormat string
InspectionEnabled bool
}

// Validate the input for a CheckCommitReadiness proposal
Expand Down Expand Up @@ -137,6 +138,7 @@ func CheckCommitReadinessCmd(c *CommitReadinessChecker, cryptoProvider bccsp.BCC
"tlsRootCertFiles",
"connectionProfile",
"output",
"inspect",
}
attachFlags(chaincodeCheckCommitReadinessCmd, flagList)

Expand Down Expand Up @@ -185,11 +187,52 @@ func (c *CommitReadinessChecker) ReadinessCheck() error {
}

if strings.ToLower(c.Input.OutputFormat) == "json" {
// Unmarshal the proposal response to add descriptions to mismatch items
readinessResult := &lb.CheckCommitReadinessResult{}
err := proto.Unmarshal(proposalResponse.Response.Payload, readinessResult)
if err != nil {
return errors.Wrap(err, "failed to unmarshal readiness result")
}

if c.Input.InspectionEnabled {
for org, mismatches := range readinessResult.Mismatches {
for i, item := range mismatches.Items {
mismatches.Items[i] = c.mismatchItemWithDescription(item)
}
readinessResult.Mismatches[org] = mismatches
}
} else {
// If InspectionEnabled flag is OFF, clear the Mismatches
readinessResult.Mismatches = nil
}

// Marshal back to proposalResponse
updatedPayload, err := proto.Marshal(readinessResult)
if err != nil {
return errors.Wrap(err, "failed to marshal updated readiness result")
}
proposalResponse.Response.Payload = updatedPayload

return printResponseAsJSON(proposalResponse, &lb.CheckCommitReadinessResult{}, c.Writer)
}
return c.printResponse(proposalResponse)
}

// mismatchItemWithDescription returns the item with its corresponding description
func (c *CommitReadinessChecker) mismatchItemWithDescription(item string) string {
descriptions := map[string]string{
"ChaincodeParameters": "ChaincodeParameters (Check the Sequence, ChaincodeName)",
"EndorsementInfo": "EndorsementInfo (Check the Version, InitRequired, EndorsementPlugin)",
"ValidationInfo": "ValidationInfo (Check the ValidationParameter, ValidationPlugin)",
"Collections": "Collections (Check the Collections)",
}

if description, ok := descriptions[item]; ok {
return description
}
return item
}

// printResponse prints the information included in the response
// from the server as human readable plain-text.
func (c *CommitReadinessChecker) printResponse(proposalResponse *pb.ProposalResponse) error {
Expand All @@ -207,7 +250,12 @@ func (c *CommitReadinessChecker) printResponse(proposalResponse *pb.ProposalResp

fmt.Fprintf(c.Writer, "Chaincode definition for chaincode '%s', version '%s', sequence '%d' on channel '%s' approval status by org:\n", c.Input.Name, c.Input.Version, c.Input.Sequence, c.Input.ChannelID)
for _, org := range orgs {
fmt.Fprintf(c.Writer, "%s: %t\n", org, result.Approvals[org])
fmt.Fprintf(c.Writer, "%s: %t", org, result.Approvals[org])

if mismatch, ok := result.Mismatches[org]; ok && c.Input.InspectionEnabled && len(mismatch.Items) > 0 {
fmt.Fprintf(c.Writer, " (mismatch: [%s])", strings.Join(result.Mismatches[org].Items, ", "))
}
fmt.Fprintln(c.Writer)
}

return nil
Expand Down Expand Up @@ -238,6 +286,7 @@ func (c *CommitReadinessChecker) createInput() (*CommitReadinessCheckInput, erro
CollectionConfigPackage: ccp,
PeerAddresses: peerAddresses,
OutputFormat: output,
InspectionEnabled: inspectionEnabled,
}

return input, nil
Expand Down
52 changes: 52 additions & 0 deletions internal/peer/lifecycle/chaincode/checkcommitreadiness_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ package chaincode_test

import (
"encoding/json"
"fmt"

"github.com/golang/protobuf/proto"
pb "github.com/hyperledger/fabric-protos-go/peer"
Expand Down Expand Up @@ -41,6 +42,11 @@ var _ = Describe("CheckCommitReadiness", func() {
"well...ok": true,
"absolutely-not": false,
},
Mismatches: map[string]*lb.CheckCommitReadinessResult_Mismatches{
"absolutely-not": {
Items: []string{"ChaincodeParameters", "EndorsementInfo", "ValidationInfo", "Collections"},
},
},
}
mockResultBytes, err := proto.Marshal(mockResult)
Expect(err).NotTo(HaveOccurred())
Expand Down Expand Up @@ -81,6 +87,21 @@ var _ = Describe("CheckCommitReadiness", func() {
Eventually(commitReadinessChecker.Writer).Should(gbytes.Say("well...ok: true"))
})

Context("when inspect is enabled", func() {
BeforeEach(func() {
commitReadinessChecker.Input.InspectionEnabled = true
})

It("checks whether a chaincode definition is ready to commit and writes the output as human readable plain-text with mismatch details", func() {
err := commitReadinessChecker.ReadinessCheck()
Expect(err).NotTo(HaveOccurred())
Eventually(commitReadinessChecker.Writer).Should(gbytes.Say("Chaincode definition for chaincode 'testcc', version '1.0', sequence '1' on channel 'testchannel' approval status by org"))
Eventually(commitReadinessChecker.Writer).Should(gbytes.Say("absolutely-not: false \\(mismatch: \\[ChaincodeParameters, EndorsementInfo, ValidationInfo, Collections\\]\\)"))
Eventually(commitReadinessChecker.Writer).Should(gbytes.Say("seemsfinetome: true"))
Eventually(commitReadinessChecker.Writer).Should(gbytes.Say("well...ok: true"))
})
})

Context("when JSON-formatted output is requested", func() {
BeforeEach(func() {
commitReadinessChecker.Input.OutputFormat = "json"
Expand All @@ -100,6 +121,37 @@ var _ = Describe("CheckCommitReadiness", func() {
Expect(err).NotTo(HaveOccurred())
Eventually(commitReadinessChecker.Writer).Should(gbytes.Say(string(json)))
})

Context("when inspect is enabled", func() {
BeforeEach(func() {
commitReadinessChecker.Input.InspectionEnabled = true
})

It("checks whether a chaincode definition is ready to commit and writes the output as JSON with mismatch details", func() {
err := commitReadinessChecker.ReadinessCheck()
Expect(err).NotTo(HaveOccurred())
expectedOutput := &lb.CheckCommitReadinessResult{
Approvals: map[string]bool{
"absolutely-not": false,
"well...ok": true,
"seemsfinetome": true,
},
Mismatches: map[string]*lb.CheckCommitReadinessResult_Mismatches{
"absolutely-not": {
Items: []string{
"ChaincodeParameters (Check the Sequence, ChaincodeName)",
"EndorsementInfo (Check the Version, InitRequired, EndorsementPlugin)",
"ValidationInfo (Check the ValidationParameter, ValidationPlugin)",
"Collections (Check the Collections)",
},
},
},
}
json, err := json.MarshalIndent(expectedOutput, "", "\t")
Expect(err).NotTo(HaveOccurred())
Eventually(commitReadinessChecker.Writer).Should(gbytes.Say(fmt.Sprintf(`\Q%s\E`, string(json))))
})
})
})

Context("when the channel name is not provided", func() {
Expand Down

0 comments on commit e308da8

Please sign in to comment.