Skip to content

Commit 4d545ce

Browse files
committed
added to OSN new handler for update config of channel
Signed-off-by: Fedor Partanskiy <[email protected]>
1 parent e06da3c commit 4d545ce

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

58 files changed

+2480
-606
lines changed

cmd/osnadmin/main.go

Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -58,6 +58,10 @@ func executeForArgs(args []string) (output string, exit int, err error) {
5858
remove := channel.Command("remove", "Remove a channel from an Ordering Service Node (OSN).")
5959
removeChannelID := remove.Flag("channelID", "Channel ID").Short('c').Required().String()
6060

61+
update := channel.Command("update", "Update an Ordering Service Node (OSN) to a channel.")
62+
updateChannelID := update.Flag("channelID", "Channel ID").Short('c').Required().String()
63+
configUpdateEnvelopePath := update.Flag("config-update-envelope", "Path to the file containing an up-to-date config update envelope for the channel").Short('e').Required().String()
64+
6165
command, err := app.Parse(args)
6266
if err != nil {
6367
return "", 1, err
@@ -105,6 +109,19 @@ func executeForArgs(args []string) (output string, exit int, err error) {
105109
}
106110
}
107111

112+
var marshaledConfigEnvelope []byte
113+
if *configUpdateEnvelopePath != "" {
114+
marshaledConfigEnvelope, err = os.ReadFile(*configUpdateEnvelopePath)
115+
if err != nil {
116+
return "", 1, fmt.Errorf("reading config updte envelope: %s", err)
117+
}
118+
119+
err = validateEnvelopeChannelID(marshaledConfigEnvelope, *updateChannelID)
120+
if err != nil {
121+
return "", 1, err
122+
}
123+
}
124+
108125
//
109126
// call the underlying implementations
110127
//
@@ -121,6 +138,8 @@ func executeForArgs(args []string) (output string, exit int, err error) {
121138
resp, err = osnadmin.ListAllChannels(osnURL, caCertPool, tlsClientCert)
122139
case remove.FullCommand():
123140
resp, err = osnadmin.Remove(osnURL, *removeChannelID, caCertPool, tlsClientCert)
141+
case update.FullCommand():
142+
resp, err = osnadmin.Update(osnURL, marshaledConfigEnvelope, caCertPool, tlsClientCert)
124143
}
125144
if err != nil {
126145
return errorOutput(err), 1, nil
@@ -186,3 +205,24 @@ func validateBlockChannelID(blockBytes []byte, channelID string) error {
186205

187206
return nil
188207
}
208+
209+
func validateEnvelopeChannelID(envelopeBytes []byte, channelID string) error {
210+
envelope := &common.Envelope{}
211+
err := proto.Unmarshal(envelopeBytes, envelope)
212+
if err != nil {
213+
return fmt.Errorf("unmarshalling envelope: %s", err)
214+
}
215+
216+
envelopeChannelID, err := protoutil.GetChannelIDFromEnvelope(envelope)
217+
if err != nil {
218+
return err
219+
}
220+
221+
// quick sanity check that the orderer admin is joining
222+
// the channel they think they're joining.
223+
if channelID != envelopeChannelID {
224+
return fmt.Errorf("specified --channelID %s does not match channel ID %s in config update envelope", channelID, envelopeChannelID)
225+
}
226+
227+
return nil
228+
}

cmd/osnadmin/main_test.go

Lines changed: 135 additions & 55 deletions
Original file line numberDiff line numberDiff line change
@@ -532,134 +532,183 @@ var _ = Describe("osnadmin", func() {
532532
})
533533
})
534534

535-
Describe("Flags", func() {
536-
It("accepts short versions of the --orderer-address, --channelID, and --config-block flags", func() {
537-
configBlock := blockWithGroups(
538-
map[string]*cb.ConfigGroup{
539-
"Application": {},
540-
},
541-
"testing123",
542-
)
543-
blockPath := createBlockFile(tempDir, configBlock)
544-
mockChannelManagement.JoinChannelReturns(types.ChannelInfo{
545-
Name: "apple",
546-
ConsensusRelation: "banana",
547-
Status: "orange",
548-
Height: 123,
535+
Describe("Update", func() {
536+
var envelopePath string
537+
538+
BeforeEach(func() {
539+
configEnvelope := envelopeUpdateConfigWithGroups("testing123")
540+
envelopePath = createEnvelopeFile(tempDir, configEnvelope)
541+
542+
mockChannelManagement.UpdateChannelReturns(types.ChannelInfo{
543+
Name: "apple",
544+
Height: 123,
549545
}, nil)
546+
})
550547

548+
It("uses the channel participation API to update a channel", func() {
551549
args := []string{
552550
"channel",
553-
"join",
554-
"-o", ordererURL,
555-
"-c", channelID,
556-
"-b", blockPath,
551+
"update",
552+
"--orderer-address", ordererURL,
553+
"--channelID", channelID,
554+
"--config-update-envelope", envelopePath,
557555
"--ca-file", ordererCACert,
558556
"--client-cert", clientCert,
559557
"--client-key", clientKey,
560558
}
561559
output, exit, err := executeForArgs(args)
562560
expectedOutput := types.ChannelInfo{
563-
Name: "apple",
564-
URL: "/participation/v1/channels/apple",
565-
ConsensusRelation: "banana",
566-
Status: "orange",
567-
Height: 123,
561+
Name: "apple",
562+
URL: "/participation/v1/channels/apple",
563+
Height: 123,
568564
}
569565
checkStatusOutput(output, exit, err, 201, expectedOutput)
570566
})
571567

572-
Context("when an unknown flag is used", func() {
573-
It("returns an error for long flags", func() {
574-
_, _, err := executeForArgs([]string{"channel", "list", "--bad-flag"})
575-
Expect(err).To(MatchError("unknown long flag '--bad-flag'"))
568+
Context("when the envelope is empty", func() {
569+
BeforeEach(func() {
570+
envelopePath = createEnvelopeFile(tempDir, &cb.Envelope{})
576571
})
577572

578-
It("returns an error for short flags", func() {
579-
_, _, err := executeForArgs([]string{"channel", "list", "-z"})
580-
Expect(err).To(MatchError("unknown short flag '-z'"))
573+
It("returns with exit code 1 and prints the error", func() {
574+
args := []string{
575+
"channel",
576+
"update",
577+
"--orderer-address", ordererURL,
578+
"--channelID", channelID,
579+
"--config-update-envelope", envelopePath,
580+
"--ca-file", ordererCACert,
581+
"--client-cert", clientCert,
582+
"--client-key", clientKey,
583+
}
584+
output, exit, err := executeForArgs(args)
585+
586+
checkFlagError(output, exit, err, "failed to retrieve channel id - payload header is empty")
581587
})
582588
})
583589

584-
Context("when the ca cert cannot be read", func() {
590+
Context("when the --channelID does not match the channel ID in the envelope", func() {
585591
BeforeEach(func() {
586-
ordererCACert = "not-the-ca-cert-youre-looking-for"
592+
channelID = "not-the-channel-youre-looking-for"
587593
})
588594

589595
It("returns with exit code 1 and prints the error", func() {
590596
args := []string{
591597
"channel",
592-
"list",
598+
"update",
593599
"--orderer-address", ordererURL,
594600
"--channelID", channelID,
601+
"--config-update-envelope", envelopePath,
595602
"--ca-file", ordererCACert,
596603
"--client-cert", clientCert,
597604
"--client-key", clientKey,
598605
}
599606
output, exit, err := executeForArgs(args)
600-
checkFlagError(output, exit, err, "reading orderer CA certificate: open not-the-ca-cert-youre-looking-for: no such file or directory")
607+
608+
checkFlagError(output, exit, err, "specified --channelID not-the-channel-youre-looking-for does not match channel ID testing123 in config update envelope")
601609
})
602610
})
603611

604-
Context("when the ca-file contains a private key instead of certificate(s)", func() {
612+
Context("when the envelope isn't a valid config update", func() {
605613
BeforeEach(func() {
606-
ordererCACert = clientKey
614+
envelope := &cb.Envelope{
615+
Payload: protoutil.MarshalOrPanic(&cb.Payload{
616+
Header: &cb.Header{
617+
ChannelHeader: protoutil.MarshalOrPanic(&cb.ChannelHeader{
618+
Type: int32(cb.HeaderType_ENDORSER_TRANSACTION),
619+
ChannelId: channelID,
620+
}),
621+
},
622+
}),
623+
}
624+
envelopePath = createEnvelopeFile(tempDir, envelope)
607625
})
608626

609-
It("returns with exit code 1 and prints the error", func() {
627+
It("returns 405 bad request", func() {
610628
args := []string{
611629
"channel",
612-
"remove",
630+
"update",
613631
"--orderer-address", ordererURL,
614632
"--channelID", channelID,
633+
"--config-update-envelope", envelopePath,
615634
"--ca-file", ordererCACert,
616635
"--client-cert", clientCert,
617636
"--client-key", clientKey,
618637
}
619638
output, exit, err := executeForArgs(args)
620-
checkFlagError(output, exit, err, "failed to add ca-file PEM to cert pool")
639+
Expect(err).NotTo(HaveOccurred())
640+
Expect(exit).To(Equal(0))
641+
642+
expectedOutput := types.ErrorResponse{
643+
Error: "invalid config update envelope: bad type",
644+
}
645+
checkStatusOutput(output, exit, err, 400, expectedOutput)
621646
})
622647
})
623648

624-
Context("when the client cert/key pair fail to load", func() {
649+
Context("when updating the channel fails", func() {
625650
BeforeEach(func() {
626-
clientKey = "brussel-sprouts"
651+
mockChannelManagement.UpdateChannelReturns(types.ChannelInfo{}, types.ErrChannelNotExist)
627652
})
628653

629-
It("returns with exit code 1 and prints the error", func() {
654+
It("returns 405 not allowed", func() {
630655
args := []string{
631656
"channel",
632-
"list",
657+
"update",
633658
"--orderer-address", ordererURL,
659+
"--channelID", channelID,
660+
"--config-update-envelope", envelopePath,
634661
"--ca-file", ordererCACert,
635662
"--client-cert", clientCert,
636663
"--client-key", clientKey,
637664
}
638665
output, exit, err := executeForArgs(args)
639-
checkFlagError(output, exit, err, "loading client cert/key pair: open brussel-sprouts: no such file or directory")
666+
expectedOutput := types.ErrorResponse{
667+
Error: "cannot update: channel does not exist",
668+
}
669+
checkStatusOutput(output, exit, err, 405, expectedOutput)
640670
})
641-
})
642671

643-
Context("when the config block cannot be read", func() {
644-
var configBlockPath string
672+
It("returns 405 not allowed (without status)", func() {
673+
args := []string{
674+
"channel",
675+
"update",
676+
"--orderer-address", ordererURL,
677+
"--channelID", channelID,
678+
"--config-update-envelope", envelopePath,
679+
"--ca-file", ordererCACert,
680+
"--client-cert", clientCert,
681+
"--client-key", clientKey,
682+
"--no-status",
683+
}
684+
output, exit, err := executeForArgs(args)
685+
expectedOutput := types.ErrorResponse{
686+
Error: "cannot update: channel does not exist",
687+
}
688+
checkOutput(output, exit, err, expectedOutput)
689+
})
690+
})
645691

692+
Context("when TLS is disabled", func() {
646693
BeforeEach(func() {
647-
configBlockPath = "not-the-config-block-youre-looking-for"
694+
tlsConfig = nil
648695
})
649696

650-
It("returns with exit code 1 and prints the error", func() {
697+
It("uses the channel participation API to join a channel", func() {
651698
args := []string{
652699
"channel",
653-
"join",
700+
"update",
654701
"--orderer-address", ordererURL,
655702
"--channelID", channelID,
656-
"--ca-file", ordererCACert,
657-
"--client-cert", clientCert,
658-
"--client-key", clientKey,
659-
"--config-block", configBlockPath,
703+
"--config-update-envelope", envelopePath,
660704
}
661705
output, exit, err := executeForArgs(args)
662-
checkFlagError(output, exit, err, "reading config block: open not-the-config-block-youre-looking-for: no such file or directory")
706+
expectedOutput := types.ChannelInfo{
707+
Name: "apple",
708+
URL: "/participation/v1/channels/apple",
709+
Height: 123,
710+
}
711+
checkStatusOutput(output, exit, err, 201, expectedOutput)
663712
})
664713
})
665714
})
@@ -834,3 +883,34 @@ func createBlockFile(tempDir string, configBlock *cb.Block) string {
834883
Expect(err).NotTo(HaveOccurred())
835884
return blockPath
836885
}
886+
887+
func envelopeUpdateConfigWithGroups(channelID string) *cb.Envelope {
888+
data := &cb.Envelope{
889+
Payload: protoutil.MarshalOrPanic(&cb.Payload{
890+
Data: protoutil.MarshalOrPanic(&cb.ConfigUpdateEnvelope{
891+
ConfigUpdate: protoutil.MarshalOrPanic(&cb.ConfigUpdate{
892+
ChannelId: channelID,
893+
ReadSet: &cb.ConfigGroup{},
894+
WriteSet: &cb.ConfigGroup{},
895+
}),
896+
}),
897+
Header: &cb.Header{
898+
ChannelHeader: protoutil.MarshalOrPanic(&cb.ChannelHeader{
899+
Type: int32(cb.HeaderType_CONFIG_UPDATE),
900+
ChannelId: channelID,
901+
}),
902+
},
903+
}),
904+
}
905+
906+
return data
907+
}
908+
909+
func createEnvelopeFile(tempDir string, configEnvelope *cb.Envelope) string {
910+
envelopeBytes, err := proto.Marshal(configEnvelope)
911+
Expect(err).NotTo(HaveOccurred())
912+
envelopePath := filepath.Join(tempDir, "envelope.pb")
913+
err = os.WriteFile(envelopePath, envelopeBytes, 0o644)
914+
Expect(err).NotTo(HaveOccurred())
915+
return envelopePath
916+
}

0 commit comments

Comments
 (0)