Skip to content

Commit e15c297

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

File tree

27 files changed

+1344
-222
lines changed

27 files changed

+1344
-222
lines changed

cmd/osnadmin/main.go

Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -58,6 +58,11 @@ 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+
tlsHandshakeTimeShift := update.Flag("tlsHandshakeTimeShift", "The amount of time to shift backwards for certificate expiration checks during TLS handshakes with the orderer endpoint").Short('t').Default("0").Duration()
65+
6166
command, err := app.Parse(args)
6267
if err != nil {
6368
return "", 1, err
@@ -105,6 +110,19 @@ func executeForArgs(args []string) (output string, exit int, err error) {
105110
}
106111
}
107112

113+
var marshaledConfigEnvelope []byte
114+
if *configUpdateEnvelopePath != "" {
115+
marshaledConfigEnvelope, err = os.ReadFile(*configUpdateEnvelopePath)
116+
if err != nil {
117+
return "", 1, fmt.Errorf("reading config updte envelope: %s", err)
118+
}
119+
120+
err = validateEnvelopeChannelID(marshaledConfigEnvelope, *updateChannelID)
121+
if err != nil {
122+
return "", 1, err
123+
}
124+
}
125+
108126
//
109127
// call the underlying implementations
110128
//
@@ -121,6 +139,8 @@ func executeForArgs(args []string) (output string, exit int, err error) {
121139
resp, err = osnadmin.ListAllChannels(osnURL, caCertPool, tlsClientCert)
122140
case remove.FullCommand():
123141
resp, err = osnadmin.Remove(osnURL, *removeChannelID, caCertPool, tlsClientCert)
142+
case update.FullCommand():
143+
resp, err = osnadmin.Update(osnURL, marshaledConfigEnvelope, caCertPool, tlsClientCert, *tlsHandshakeTimeShift)
124144
}
125145
if err != nil {
126146
return errorOutput(err), 1, nil
@@ -186,3 +206,24 @@ func validateBlockChannelID(blockBytes []byte, channelID string) error {
186206

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

cmd/osnadmin/main_test.go

Lines changed: 212 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -532,6 +532,187 @@ var _ = Describe("osnadmin", func() {
532532
})
533533
})
534534

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,
545+
}, nil)
546+
})
547+
548+
It("uses the channel participation API to update a channel", func() {
549+
args := []string{
550+
"channel",
551+
"update",
552+
"--orderer-address", ordererURL,
553+
"--channelID", channelID,
554+
"--config-update-envelope", envelopePath,
555+
"--ca-file", ordererCACert,
556+
"--client-cert", clientCert,
557+
"--client-key", clientKey,
558+
}
559+
output, exit, err := executeForArgs(args)
560+
expectedOutput := types.ChannelInfo{
561+
Name: "apple",
562+
URL: "/participation/v1/channels/apple",
563+
Height: 123,
564+
}
565+
checkStatusOutput(output, exit, err, 201, expectedOutput)
566+
})
567+
568+
Context("when the envelope is empty", func() {
569+
BeforeEach(func() {
570+
envelopePath = createEnvelopeFile(tempDir, &cb.Envelope{})
571+
})
572+
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")
587+
})
588+
})
589+
590+
Context("when the --channelID does not match the channel ID in the envelope", func() {
591+
BeforeEach(func() {
592+
channelID = "not-the-channel-youre-looking-for"
593+
})
594+
595+
It("returns with exit code 1 and prints the error", func() {
596+
args := []string{
597+
"channel",
598+
"update",
599+
"--orderer-address", ordererURL,
600+
"--channelID", channelID,
601+
"--config-update-envelope", envelopePath,
602+
"--ca-file", ordererCACert,
603+
"--client-cert", clientCert,
604+
"--client-key", clientKey,
605+
}
606+
output, exit, err := executeForArgs(args)
607+
608+
checkFlagError(output, exit, err, "specified --channelID not-the-channel-youre-looking-for does not match channel ID testing123 in config update envelope")
609+
})
610+
})
611+
612+
Context("when the envelope isn't a valid config update", func() {
613+
BeforeEach(func() {
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)
625+
})
626+
627+
It("returns 405 bad request", func() {
628+
args := []string{
629+
"channel",
630+
"update",
631+
"--orderer-address", ordererURL,
632+
"--channelID", channelID,
633+
"--config-update-envelope", envelopePath,
634+
"--ca-file", ordererCACert,
635+
"--client-cert", clientCert,
636+
"--client-key", clientKey,
637+
}
638+
output, exit, err := executeForArgs(args)
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)
646+
})
647+
})
648+
649+
Context("when updating the channel fails", func() {
650+
BeforeEach(func() {
651+
mockChannelManagement.UpdateChannelReturns(types.ChannelInfo{}, types.ErrChannelNotExist)
652+
})
653+
654+
It("returns 405 not allowed", func() {
655+
args := []string{
656+
"channel",
657+
"update",
658+
"--orderer-address", ordererURL,
659+
"--channelID", channelID,
660+
"--config-update-envelope", envelopePath,
661+
"--ca-file", ordererCACert,
662+
"--client-cert", clientCert,
663+
"--client-key", clientKey,
664+
}
665+
output, exit, err := executeForArgs(args)
666+
expectedOutput := types.ErrorResponse{
667+
Error: "cannot update: channel does not exist",
668+
}
669+
checkStatusOutput(output, exit, err, 405, expectedOutput)
670+
})
671+
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+
})
691+
692+
Context("when TLS is disabled", func() {
693+
BeforeEach(func() {
694+
tlsConfig = nil
695+
})
696+
697+
It("uses the channel participation API to join a channel", func() {
698+
args := []string{
699+
"channel",
700+
"update",
701+
"--orderer-address", ordererURL,
702+
"--channelID", channelID,
703+
"--config-update-envelope", envelopePath,
704+
}
705+
output, exit, err := executeForArgs(args)
706+
expectedOutput := types.ChannelInfo{
707+
Name: "apple",
708+
URL: "/participation/v1/channels/apple",
709+
Height: 123,
710+
}
711+
checkStatusOutput(output, exit, err, 201, expectedOutput)
712+
})
713+
})
714+
})
715+
535716
Describe("Flags", func() {
536717
It("accepts short versions of the --orderer-address, --channelID, and --config-block flags", func() {
537718
configBlock := blockWithGroups(
@@ -834,3 +1015,34 @@ func createBlockFile(tempDir string, configBlock *cb.Block) string {
8341015
Expect(err).NotTo(HaveOccurred())
8351016
return blockPath
8361017
}
1018+
1019+
func envelopeUpdateConfigWithGroups(channelID string) *cb.Envelope {
1020+
data := &cb.Envelope{
1021+
Payload: protoutil.MarshalOrPanic(&cb.Payload{
1022+
Data: protoutil.MarshalOrPanic(&cb.ConfigUpdateEnvelope{
1023+
ConfigUpdate: protoutil.MarshalOrPanic(&cb.ConfigUpdate{
1024+
ChannelId: channelID,
1025+
ReadSet: &cb.ConfigGroup{},
1026+
WriteSet: &cb.ConfigGroup{},
1027+
}),
1028+
}),
1029+
Header: &cb.Header{
1030+
ChannelHeader: protoutil.MarshalOrPanic(&cb.ChannelHeader{
1031+
Type: int32(cb.HeaderType_CONFIG_UPDATE),
1032+
ChannelId: channelID,
1033+
}),
1034+
},
1035+
}),
1036+
}
1037+
1038+
return data
1039+
}
1040+
1041+
func createEnvelopeFile(tempDir string, configEnvelope *cb.Envelope) string {
1042+
envelopeBytes, err := proto.Marshal(configEnvelope)
1043+
Expect(err).NotTo(HaveOccurred())
1044+
envelopePath := filepath.Join(tempDir, "envelope.pb")
1045+
err = os.WriteFile(envelopePath, envelopeBytes, 0o644)
1046+
Expect(err).NotTo(HaveOccurred())
1047+
return envelopePath
1048+
}

0 commit comments

Comments
 (0)