Skip to content

Commit 43de890

Browse files
authored
Merge pull request #1158 from kaleido-io/backport
Backport crash fixes to release-1.1 branch
2 parents 057a7af + d6b37be commit 43de890

File tree

10 files changed

+124
-64
lines changed

10 files changed

+124
-64
lines changed

internal/apiserver/route_get_namespace_test.go

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@ package apiserver
1818

1919
import (
2020
"context"
21+
"fmt"
2122
"net/http/httptest"
2223
"testing"
2324

@@ -48,8 +49,8 @@ func TestGetNamespaceInvalid(t *testing.T) {
4849
req.Header.Set("Content-Type", "application/json; charset=utf-8")
4950
res := httptest.NewRecorder()
5051

51-
mgr.On("Orchestrator", "BAD").Return(nil, nil)
52+
mgr.On("Orchestrator", mock.Anything, "BAD").Return(nil, fmt.Errorf("pop"))
5253
r.ServeHTTP(res, req)
5354

54-
assert.Equal(t, 404, res.Result().StatusCode)
55+
assert.Equal(t, 500, res.Result().StatusCode)
5556
}

internal/apiserver/server.go

Lines changed: 8 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
// Copyright © 2022 Kaleido, Inc.
1+
// Copyright © 2023 Kaleido, Inc.
22
//
33
// SPDX-License-Identifier: Apache-2.0
44
//
@@ -210,9 +210,9 @@ func (as *apiServer) swaggerGenerator(routes []*ffapi.Route, apiBaseURL string)
210210
func (as *apiServer) contractSwaggerGenerator(mgr namespace.Manager, apiBaseURL string) func(req *http.Request) (*openapi3.T, error) {
211211
return func(req *http.Request) (*openapi3.T, error) {
212212
vars := mux.Vars(req)
213-
or := mgr.Orchestrator(vars["ns"])
214-
if or == nil {
215-
return nil, i18n.NewError(req.Context(), coremsgs.MsgNamespaceDoesNotExist)
213+
or, err := mgr.Orchestrator(req.Context(), vars["ns"])
214+
if err != nil {
215+
return nil, err
216216
}
217217
cm := or.Contracts()
218218
api, err := cm.GetContractAPI(req.Context(), apiBaseURL, vars["apiName"])
@@ -235,19 +235,16 @@ func (as *apiServer) contractSwaggerGenerator(mgr namespace.Manager, apiBaseURL
235235
func getOrchestrator(ctx context.Context, mgr namespace.Manager, tag string, r *ffapi.APIRequest) (or orchestrator.Orchestrator, err error) {
236236
switch tag {
237237
case routeTagDefaultNamespace:
238-
or = mgr.Orchestrator(config.GetString(coreconfig.NamespacesDefault))
238+
return mgr.Orchestrator(ctx, config.GetString(coreconfig.NamespacesDefault))
239239
case routeTagNonDefaultNamespace:
240240
vars := mux.Vars(r.Req)
241241
if ns, ok := vars["ns"]; ok {
242-
or = mgr.Orchestrator(ns)
242+
return mgr.Orchestrator(ctx, ns)
243243
}
244-
default:
244+
case routeTagGlobal:
245245
return nil, nil
246246
}
247-
if or == nil {
248-
return nil, i18n.NewError(ctx, coremsgs.MsgNamespaceDoesNotExist)
249-
}
250-
return or, nil
247+
return nil, i18n.NewError(ctx, coremsgs.MsgMissingNamespace)
251248
}
252249

253250
func (as *apiServer) routeHandler(hf *ffapi.HandlerFactory, mgr namespace.Manager, apiBaseURL string, route *ffapi.Route) http.HandlerFunc {

internal/apiserver/server_test.go

Lines changed: 12 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,7 @@ import (
3535
"github.com/hyperledger/firefly-common/pkg/httpserver"
3636
"github.com/hyperledger/firefly-common/pkg/i18n"
3737
"github.com/hyperledger/firefly/internal/coreconfig"
38+
"github.com/hyperledger/firefly/internal/coremsgs"
3839
"github.com/hyperledger/firefly/internal/metrics"
3940
"github.com/hyperledger/firefly/mocks/apiservermocks"
4041
"github.com/hyperledger/firefly/mocks/contractmocks"
@@ -56,6 +57,9 @@ func newTestServer() (*namespacemocks.Manager, *orchestratormocks.Orchestrator,
5657
mgr.On("Orchestrator", "default").Return(o).Maybe()
5758
mgr.On("Orchestrator", "mynamespace").Return(o).Maybe()
5859
mgr.On("Orchestrator", "ns1").Return(o).Maybe()
60+
mgr.On("Orchestrator", mock.Anything, "default").Return(o, nil).Maybe()
61+
mgr.On("Orchestrator", mock.Anything, "mynamespace").Return(o, nil).Maybe()
62+
mgr.On("Orchestrator", mock.Anything, "ns1").Return(o, nil).Maybe()
5963
as := &apiServer{
6064
apiTimeout: 5 * time.Second,
6165
maxFilterLimit: 100,
@@ -369,7 +373,7 @@ func TestContractAPISwaggerJSONBadNamespace(t *testing.T) {
369373
s := httptest.NewServer(r)
370374
defer s.Close()
371375

372-
mgr.On("Orchestrator", "BAD").Return(nil)
376+
mgr.On("Orchestrator", mock.Anything, "BAD").Return(nil, i18n.NewError(context.Background(), coremsgs.MsgUnknownNamespace))
373377

374378
res, err := http.Get(fmt.Sprintf("http://%s/api/v1/namespaces/BAD/apis/my-api/api/swagger.json", s.Listener.Addr()))
375379
assert.NoError(t, err)
@@ -395,7 +399,7 @@ func TestJSONBadNamespace(t *testing.T) {
395399
s := httptest.NewServer(r)
396400
defer s.Close()
397401

398-
mgr.On("Orchestrator", "BAD").Return(nil)
402+
mgr.On("Orchestrator", mock.Anything, "BAD").Return(nil, i18n.NewError(context.Background(), coremsgs.MsgUnknownNamespace))
399403

400404
var b bytes.Buffer
401405
req := httptest.NewRequest("GET", "/api/v1/namespaces/BAD/apis", &b)
@@ -413,7 +417,7 @@ func TestFormDataBadNamespace(t *testing.T) {
413417
s := httptest.NewServer(r)
414418
defer s.Close()
415419

416-
mgr.On("Orchestrator", "BAD").Return(nil)
420+
mgr.On("Orchestrator", mock.Anything, "BAD").Return(nil, i18n.NewError(context.Background(), coremsgs.MsgUnknownNamespace))
417421

418422
var b bytes.Buffer
419423
w := multipart.NewWriter(&b)
@@ -471,3 +475,8 @@ func TestFormDataDisabledRoute(t *testing.T) {
471475

472476
assert.Equal(t, 400, res.Result().StatusCode)
473477
}
478+
479+
func TestGetOrchestratorMissingTag(t *testing.T) {
480+
_, err := getOrchestrator(context.Background(), &namespacemocks.Manager{}, "", nil)
481+
assert.Regexp(t, "FF10436", err)
482+
}

internal/apiserver/spi_routes.go

Lines changed: 7 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
// Copyright © 2022 Kaleido, Inc.
1+
// Copyright © 2023 Kaleido, Inc.
22
//
33
// SPDX-License-Identifier: Apache-2.0
44
//
@@ -20,11 +20,14 @@ import "github.com/hyperledger/firefly-common/pkg/ffapi"
2020

2121
// The Service Provider Interface (SPI) allows external microservices (such as the FireFly Transaction Manager)
2222
// to act as augmented components to the core.
23-
var spiRoutes = []*ffapi.Route{
23+
var spiRoutes = append(globalRoutes([]*ffapi.Route{
2424
spiGetNamespaceByName,
2525
spiGetNamespaces,
2626
spiGetOpByID,
27-
spiGetOps,
2827
spiPatchOpByID,
2928
spiPostReset,
30-
}
29+
}),
30+
namespacedRoutes([]*ffapi.Route{
31+
spiGetOps,
32+
})...,
33+
)

internal/coremsgs/en_error_messages.go

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
// Copyright © 2022 Kaleido, Inc.
1+
// Copyright © 2023 Kaleido, Inc.
22
//
33
// SPDX-License-Identifier: Apache-2.0
44
//
@@ -271,4 +271,8 @@ var (
271271
MsgIdempotencyKeyDuplicateMessage = ffe("FF10430", "Idempotency key '%s' already used for message '%s'", 409)
272272
MsgIdempotencyKeyDuplicateTransaction = ffe("FF10431", "Idempotency key '%s' already used for transaction '%s'", 409)
273273
MsgNonIdempotencyKeyConflictTxInsert = ffe("FF10432", "Conflict on insert of transaction '%s'. No existing transaction matching idempotency key '%s' found", 409)
274+
MsgErrorNameMustBeSet = ffe("FF10433", "The name of the error must be set", 400)
275+
MsgContractErrorsResolveError = ffe("FF10434", "Unable to resolve contract errors: %s", 400)
276+
MsgUnknownNamespace = ffe("FF10435", "Unknown namespace '%s'", 404)
277+
MsgMissingNamespace = ffe("FF10436", "Missing namespace in request", 400)
274278
)

internal/events/webhooks/webhooks.go

Lines changed: 8 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -211,18 +211,19 @@ func (wh *WebHooks) attemptRequest(sub *core.Subscription, event *core.EventDeli
211211

212212
if req.method == http.MethodPost || req.method == http.MethodPatch || req.method == http.MethodPut {
213213
switch {
214-
case !withData:
215-
// We are just sending the event itself
216-
req.r.SetBody(event)
217214
case req.body != nil:
218215
// We might have been told to extract a body from the first data record
219216
req.r.SetBody(req.body)
220217
case len(allData) > 1:
221218
// We've got an array of data to POST
222219
req.r.SetBody(allData)
223-
default:
224-
// Otherwise just send the first object directly
220+
case len(allData) == 1:
221+
// Just send the first object directly
225222
req.r.SetBody(firstData)
223+
default:
224+
// Just send the event itself
225+
req.r.SetBody(event)
226+
226227
}
227228
}
228229

@@ -292,7 +293,7 @@ func (wh *WebHooks) doDelivery(connID string, reply bool, sub *core.Subscription
292293
log.L(wh.ctx).Tracef("Webhook response: %s", string(b))
293294

294295
// Emit the response
295-
if reply {
296+
if reply && event.Message != nil {
296297
txType := fftypes.FFEnum(strings.ToLower(sub.Options.TransportOptions().GetString("replytx")))
297298
if req != nil && req.replyTx != "" {
298299
txType = fftypes.FFEnum(strings.ToLower(req.replyTx))
@@ -333,13 +334,8 @@ func (wh *WebHooks) doDelivery(connID string, reply bool, sub *core.Subscription
333334
}
334335

335336
func (wh *WebHooks) DeliveryRequest(connID string, sub *core.Subscription, event *core.EventDelivery, data core.DataArray) error {
336-
if event.Message == nil && sub.Options.WithData != nil && *sub.Options.WithData {
337-
log.L(wh.ctx).Debugf("Webhook withData=true subscription called with non-message event '%s'", event.ID)
338-
return nil
339-
}
340-
341337
reply := sub.Options.TransportOptions().GetBool("reply")
342-
if reply && event.Message.Header.CID != nil {
338+
if reply && event.Message != nil && event.Message.Header.CID != nil {
343339
// We cowardly refuse to dispatch a message that is itself a reply, as it's hard for users to
344340
// avoid loops - and there's no way for us to detect here if a user has configured correctly
345341
// to avoid a loop.

internal/events/webhooks/webhooks_test.go

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -703,6 +703,8 @@ func TestWebhookFailFastAsk(t *testing.T) {
703703
func TestDeliveryRequestNilMessage(t *testing.T) {
704704
wh, cancel := newTestWebHooks(t)
705705
defer cancel()
706+
mcb := wh.callbacks["ns1"].(*eventsmocks.Callbacks)
707+
mcb.On("DeliveryResponse", mock.Anything, mock.Anything).Return("", &core.EventDelivery{})
706708

707709
yes := true
708710
sub := &core.Subscription{
@@ -729,6 +731,7 @@ func TestDeliveryRequestNilMessage(t *testing.T) {
729731

730732
err := wh.DeliveryRequest(mock.Anything, sub, event, nil)
731733
assert.NoError(t, err)
734+
mcb.AssertExpectations(t)
732735
}
733736

734737
func TestDeliveryRequestReplyToReply(t *testing.T) {

internal/namespace/manager.go

Lines changed: 28 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
// Copyright © 2022 Kaleido, Inc.
1+
// Copyright © 2023 Kaleido, Inc.
22
//
33
// SPDX-License-Identifier: Apache-2.0
44
//
@@ -77,7 +77,8 @@ type Manager interface {
7777
WaitStop()
7878
Reset(ctx context.Context)
7979

80-
Orchestrator(ns string) orchestrator.Orchestrator
80+
Orchestrator(ctx context.Context, ns string) (orchestrator.Orchestrator, error)
81+
MustOrchestrator(ns string) orchestrator.Orchestrator
8182
SPIEvents() spievents.Manager
8283
GetNamespaces(ctx context.Context) ([]*core.Namespace, error)
8384
GetOperationByNamespacedID(ctx context.Context, nsOpID string) (*core.Operation, error)
@@ -1039,13 +1040,22 @@ func (nm *namespaceManager) SPIEvents() spievents.Manager {
10391040
return nm.adminEvents
10401041
}
10411042

1042-
func (nm *namespaceManager) Orchestrator(ns string) orchestrator.Orchestrator {
1043+
func (nm *namespaceManager) Orchestrator(ctx context.Context, ns string) (orchestrator.Orchestrator, error) {
10431044
nm.nsMux.Lock()
10441045
defer nm.nsMux.Unlock()
1045-
if namespace, ok := nm.namespaces[ns]; ok {
1046-
return namespace.orchestrator
1046+
if namespace, ok := nm.namespaces[ns]; ok && namespace != nil {
1047+
return namespace.orchestrator, nil
10471048
}
1048-
return nil
1049+
return nil, i18n.NewError(ctx, coremsgs.MsgUnknownNamespace, ns)
1050+
}
1051+
1052+
// MustOrchestrator must only be called by code that is absolutely sure the orchestrator exists
1053+
func (nm *namespaceManager) MustOrchestrator(ns string) orchestrator.Orchestrator {
1054+
or, err := nm.Orchestrator(context.Background(), ns)
1055+
if err != nil {
1056+
panic(err)
1057+
}
1058+
return or
10491059
}
10501060

10511061
func (nm *namespaceManager) GetNamespaces(ctx context.Context) ([]*core.Namespace, error) {
@@ -1063,9 +1073,9 @@ func (nm *namespaceManager) GetOperationByNamespacedID(ctx context.Context, nsOp
10631073
if err != nil {
10641074
return nil, err
10651075
}
1066-
or := nm.Orchestrator(ns)
1067-
if or == nil {
1068-
return nil, i18n.NewError(ctx, coremsgs.Msg404NotFound)
1076+
or, err := nm.Orchestrator(ctx, ns)
1077+
if err != nil {
1078+
return nil, err
10691079
}
10701080
return or.GetOperationByID(ctx, u.String())
10711081
}
@@ -1075,10 +1085,11 @@ func (nm *namespaceManager) ResolveOperationByNamespacedID(ctx context.Context,
10751085
if err != nil {
10761086
return err
10771087
}
1078-
or := nm.Orchestrator(ns)
1079-
if or == nil {
1080-
return i18n.NewError(ctx, coremsgs.Msg404NotFound)
1088+
or, err := nm.Orchestrator(ctx, ns)
1089+
if err != nil {
1090+
return err
10811091
}
1092+
10821093
return or.Operations().ResolveOperationByID(ctx, u, op)
10831094
}
10841095

@@ -1133,5 +1144,9 @@ func (nm *namespaceManager) getAuthPlugin(ctx context.Context) (plugins map[stri
11331144
}
11341145

11351146
func (nm *namespaceManager) Authorize(ctx context.Context, authReq *fftypes.AuthReq) error {
1136-
return nm.Orchestrator(authReq.Namespace).Authorize(ctx, authReq)
1147+
or, err := nm.Orchestrator(ctx, authReq.Namespace)
1148+
if err != nil {
1149+
return err
1150+
}
1151+
return or.Authorize(ctx, authReq)
11371152
}

0 commit comments

Comments
 (0)