From 39332d4193f1654d54f781a75293325982c4fe2e Mon Sep 17 00:00:00 2001 From: David Moore <4121492+davemooreuws@users.noreply.github.com> Date: Mon, 8 Jul 2024 15:09:19 +1000 Subject: [PATCH] fix: refactor all resources to use shared register methods (#89) --- nitric/api.go | 31 ++++++++--------------- nitric/bucket.go | 56 ++++++++++++++++++---------------------- nitric/keyvalue.go | 62 ++++++++++++++++++++------------------------- nitric/manager.go | 55 +++++++++++++++++++--------------------- nitric/oidc.go | 19 +++----------- nitric/queue.go | 61 ++++++++++++++++++++------------------------ nitric/schedule.go | 6 +---- nitric/secret.go | 60 ++++++++++++++++++++----------------------- nitric/topic.go | 11 ++++---- nitric/websocket.go | 55 ++++++++-------------------------------- 10 files changed, 163 insertions(+), 253 deletions(-) diff --git a/nitric/api.go b/nitric/api.go index cc72e67..5c2b84f 100644 --- a/nitric/api.go +++ b/nitric/api.go @@ -15,7 +15,6 @@ package nitric import ( - "context" "net/http" "path" "strings" @@ -42,7 +41,7 @@ type route struct { path string api *api middleware handler.HttpMiddleware - manager *manager + manager Manager } func composeRouteMiddleware(apiMiddleware handler.HttpMiddleware, routeMiddleware []handler.HttpMiddleware) handler.HttpMiddleware { @@ -179,23 +178,21 @@ type ApiDetails struct { type api struct { name string routes map[string]Route - manager *manager + manager Manager securityRules map[string]interface{} security []OidcOptions path string middleware handler.HttpMiddleware } -func (m *manager) newApi(name string, opts ...ApiOption) (Api, error) { - rsc, err := m.resourceServiceClient() - if err != nil { - return nil, err - } - +// NewApi Registers a new API Resource. +// +// The returned API object can be used to register Routes and Methods, with Handlers. +func NewApi(name string, opts ...ApiOption) (Api, error) { a := &api{ name: name, routes: map[string]Route{}, - manager: m, + manager: defaultManager, } // Apply options @@ -218,9 +215,8 @@ func (m *manager) newApi(name string, opts ...ApiOption) (Api, error) { } } } - // declare resource - _, err = rsc.Declare(context.TODO(), &resourcev1.ResourceDeclareRequest{ + result := <-defaultManager.registerResource(&resourcev1.ResourceDeclareRequest{ Id: &resourcev1.ResourceIdentifier{ Name: name, Type: resourcev1.ResourceType_Api, @@ -229,20 +225,13 @@ func (m *manager) newApi(name string, opts ...ApiOption) (Api, error) { Api: apiResource, }, }) - if err != nil { - return nil, err + if result.Err != nil { + return nil, result.Err } return a, nil } -// NewApi Registers a new API Resource. -// -// The returned API object can be used to register Routes and Methods, with Handlers. -func NewApi(name string, opts ...ApiOption) (Api, error) { - return defaultManager.newApi(name, opts...) -} - // Get adds a Get method handler to the path with any specified opts. // Note: to chain middleware use handler.ComposeHttpMiddlware() func (a *api) Get(match string, handler handler.HttpMiddleware, opts ...MethodOption) { diff --git a/nitric/bucket.go b/nitric/bucket.go index 889e0d5..d67baf1 100644 --- a/nitric/bucket.go +++ b/nitric/bucket.go @@ -15,7 +15,6 @@ package nitric import ( - "context" "fmt" "strings" @@ -29,8 +28,9 @@ import ( type BucketPermission string type bucket struct { - name string - manager Manager + name string + manager Manager + registerChan <-chan RegisterResult } type Bucket interface { @@ -49,42 +49,29 @@ var BucketEverything []BucketPermission = []BucketPermission{BucketRead, BucketW // NewBucket register this bucket as a required resource for the calling function/container and // register the permissions required by the currently scoped function for this resource. func NewBucket(name string) Bucket { - return &bucket{ + bucket := &bucket{ name: name, manager: defaultManager, } -} - -func (b *bucket) Allow(permission BucketPermission, permissions ...BucketPermission) (storage.Bucket, error) { - allPerms := append([]BucketPermission{permission}, permissions...) - - return defaultManager.newBucket(b.name, allPerms...) -} - -func (m *manager) newBucket(name string, permissions ...BucketPermission) (storage.Bucket, error) { - rsc, err := m.resourceServiceClient() - if err != nil { - return nil, err - } - - res := &v1.ResourceIdentifier{ - Type: v1.ResourceType_Bucket, - Name: name, - } - dr := &v1.ResourceDeclareRequest{ - Id: res, + bucket.registerChan = defaultManager.registerResource(&v1.ResourceDeclareRequest{ + Id: &v1.ResourceIdentifier{ + Type: v1.ResourceType_Bucket, + Name: name, + }, Config: &v1.ResourceDeclareRequest_Bucket{ Bucket: &v1.BucketResource{}, }, - } - _, err = rsc.Declare(context.Background(), dr) - if err != nil { - return nil, err - } + }) + + return bucket +} + +func (b *bucket) Allow(permission BucketPermission, permissions ...BucketPermission) (storage.Bucket, error) { + allPerms := append([]BucketPermission{permission}, permissions...) actions := []v1.Action{} - for _, perm := range permissions { + for _, perm := range allPerms { switch perm { case BucketRead: actions = append(actions, v1.Action_BucketFileGet, v1.Action_BucketFileList) @@ -97,7 +84,12 @@ func (m *manager) newBucket(name string, permissions ...BucketPermission) (stora } } - _, err = rsc.Declare(context.Background(), functionResourceDeclareRequest(res, actions)) + registerResult := <-b.registerChan + if registerResult.Err != nil { + return nil, registerResult.Err + } + + m, err := b.manager.registerPolicy(registerResult.Identifier, actions...) if err != nil { return nil, err } @@ -109,7 +101,7 @@ func (m *manager) newBucket(name string, permissions ...BucketPermission) (stora } } - return m.storage.Bucket(name), nil + return m.storage.Bucket(b.name), nil } func (b *bucket) On(notificationType handler.BlobEventType, notificationPrefixFilter string, middleware ...handler.BlobEventMiddleware) { diff --git a/nitric/keyvalue.go b/nitric/keyvalue.go index 3c344fa..4ddffce 100644 --- a/nitric/keyvalue.go +++ b/nitric/keyvalue.go @@ -15,7 +15,6 @@ package nitric import ( - "context" "fmt" "github.com/nitrictech/go-sdk/api/keyvalue" @@ -37,48 +36,37 @@ type KvStore interface { } type kvstore struct { - name string - manager Manager + name string + manager Manager + registerChan <-chan RegisterResult } func NewKv(name string) *kvstore { - return &kvstore{ - name: name, - manager: defaultManager, + kvstore := &kvstore{ + name: name, + manager: defaultManager, + registerChan: make(chan RegisterResult), } + + kvstore.registerChan = defaultManager.registerResource(&v1.ResourceDeclareRequest{ + Id: &v1.ResourceIdentifier{ + Type: v1.ResourceType_KeyValueStore, + Name: name, + }, + Config: &v1.ResourceDeclareRequest_KeyValueStore{ + KeyValueStore: &v1.KeyValueStoreResource{}, + }, + }) + + return kvstore } // NewQueue registers this queue as a required resource for the calling function/container. func (k *kvstore) Allow(permission KvStorePermission, permissions ...KvStorePermission) (keyvalue.Store, error) { allPerms := append([]KvStorePermission{permission}, permissions...) - return defaultManager.newKv(k.name, allPerms...) -} - -func (m *manager) newKv(name string, permissions ...KvStorePermission) (keyvalue.Store, error) { - rsc, err := m.resourceServiceClient() - if err != nil { - return nil, err - } - - colRes := &v1.ResourceIdentifier{ - Type: v1.ResourceType_KeyValueStore, - Name: name, - } - - dr := &v1.ResourceDeclareRequest{ - Id: colRes, - Config: &v1.ResourceDeclareRequest_KeyValueStore{ - KeyValueStore: &v1.KeyValueStoreResource{}, - }, - } - _, err = rsc.Declare(context.Background(), dr) - if err != nil { - return nil, err - } - actions := []v1.Action{} - for _, perm := range permissions { + for _, perm := range allPerms { switch perm { case KvStoreGet: actions = append(actions, v1.Action_KeyValueStoreRead) @@ -91,7 +79,13 @@ func (m *manager) newKv(name string, permissions ...KvStorePermission) (keyvalue } } - _, err = rsc.Declare(context.Background(), functionResourceDeclareRequest(colRes, actions)) + registerResult := <-k.registerChan + + if registerResult.Err != nil { + return nil, registerResult.Err + } + + m, err := k.manager.registerPolicy(registerResult.Identifier, actions...) if err != nil { return nil, err } @@ -103,5 +97,5 @@ func (m *manager) newKv(name string, permissions ...KvStorePermission) (keyvalue } } - return m.kvstores.Store(name), nil + return m.kvstores.Store(k.name), nil } diff --git a/nitric/manager.go b/nitric/manager.go index 4274fd6..d906655 100644 --- a/nitric/manager.go +++ b/nitric/manager.go @@ -41,17 +41,8 @@ type Manager interface { Run() error addWorker(name string, s workers.Worker) resourceServiceClient() (v1.ResourcesClient, error) - registerResource(request *v1.ResourceDeclareRequest, registerResourceChan chan RegisterResult) + registerResource(request *v1.ResourceDeclareRequest) <-chan RegisterResult registerPolicy(res *v1.ResourceIdentifier, actions ...v1.Action) (*manager, error) - - newApi(name string, opts ...ApiOption) (Api, error) - newBucket(name string, permissions ...BucketPermission) (storage.Bucket, error) - newSecret(name string, permissions ...SecretPermission) (secrets.SecretRef, error) - newQueue(name string, permissions ...QueuePermission) (queues.Queue, error) - newSchedule(name string) Schedule - newWebsocket(socket string) (Websocket, error) - newKv(name string, permissions ...KvStorePermission) (keyvalue.Store, error) - newOidcSecurityDefinition(apiName string, options OidcOptions) (OidcSecurityDefinition, error) } type RegisterResult struct { @@ -110,31 +101,37 @@ func (m *manager) resourceServiceClient() (v1.ResourcesClient, error) { return m.rsc, nil } -func (m *manager) registerResource(request *v1.ResourceDeclareRequest, registerResourceChan chan RegisterResult) { - rsc, err := m.resourceServiceClient() - if err != nil { - registerResourceChan <- RegisterResult{ - Err: err, - Identifier: nil, +func (m *manager) registerResource(request *v1.ResourceDeclareRequest) <-chan RegisterResult { + registerResourceChan := make(chan RegisterResult) + + go func() { + rsc, err := m.resourceServiceClient() + if err != nil { + registerResourceChan <- RegisterResult{ + Err: err, + Identifier: nil, + } + + return } - return - } + _, err = rsc.Declare(context.Background(), request) + if err != nil { + registerResourceChan <- RegisterResult{ + Err: err, + Identifier: nil, + } - _, err = rsc.Declare(context.Background(), request) - if err != nil { - registerResourceChan <- RegisterResult{ - Err: err, - Identifier: nil, + return } - return - } + registerResourceChan <- RegisterResult{ + Err: nil, + Identifier: request.Id, + } + }() - registerResourceChan <- RegisterResult{ - Err: nil, - Identifier: request.Id, - } + return registerResourceChan } func (m *manager) registerPolicy(res *v1.ResourceIdentifier, actions ...v1.Action) (*manager, error) { diff --git a/nitric/oidc.go b/nitric/oidc.go index c5b4eb2..8edea02 100644 --- a/nitric/oidc.go +++ b/nitric/oidc.go @@ -15,8 +15,6 @@ package nitric import ( - "context" - v1 "github.com/nitrictech/nitric/core/pkg/proto/resources/v1" ) @@ -51,25 +49,16 @@ type oidcSecurityDefinition struct { } func NewOidcSecurityDefinition(apiName string, options OidcOptions) (OidcSecurityDefinition, error) { - return defaultManager.newOidcSecurityDefinition(apiName, options) -} - -func (m *manager) newOidcSecurityDefinition(apiName string, options OidcOptions) (OidcSecurityDefinition, error) { - rsc, err := m.resourceServiceClient() - if err != nil { - return nil, err - } - o := &oidcSecurityDefinition{ ApiName: apiName, RuleName: options.Name, Issuer: options.Issuer, Audiences: options.Audiences, - manager: m, + manager: defaultManager, } // declare resource - _, err = rsc.Declare(context.TODO(), &v1.ResourceDeclareRequest{ + registerResult := <-defaultManager.registerResource(&v1.ResourceDeclareRequest{ Id: &v1.ResourceIdentifier{ Name: options.Name, Type: v1.ResourceType_ApiSecurityDefinition, @@ -86,8 +75,8 @@ func (m *manager) newOidcSecurityDefinition(apiName string, options OidcOptions) }, }, }) - if err != nil { - return nil, err + if registerResult.Err != nil { + return nil, registerResult.Err } return o, nil diff --git a/nitric/queue.go b/nitric/queue.go index 2a3621c..c96ad76 100644 --- a/nitric/queue.go +++ b/nitric/queue.go @@ -15,7 +15,6 @@ package nitric import ( - "context" "fmt" "github.com/nitrictech/go-sdk/api/queues" @@ -36,48 +35,37 @@ type Queue interface { } type queue struct { - name string - manager Manager + name string + manager Manager + registerChan <-chan RegisterResult } func NewQueue(name string) *queue { - return &queue{ - name: name, - manager: defaultManager, + queue := &queue{ + name: name, + manager: defaultManager, + registerChan: make(chan RegisterResult), } + + queue.registerChan = defaultManager.registerResource(&v1.ResourceDeclareRequest{ + Id: &v1.ResourceIdentifier{ + Type: v1.ResourceType_Queue, + Name: name, + }, + Config: &v1.ResourceDeclareRequest_Queue{ + Queue: &v1.QueueResource{}, + }, + }) + + return queue } // NewQueue registers this queue as a required resource for the calling function/container. func (q *queue) Allow(permission QueuePermission, permissions ...QueuePermission) (queues.Queue, error) { allPerms := append([]QueuePermission{permission}, permissions...) - return defaultManager.newQueue(q.name, allPerms...) -} - -func (m *manager) newQueue(name string, permissions ...QueuePermission) (queues.Queue, error) { - rsc, err := m.resourceServiceClient() - if err != nil { - return nil, err - } - - colRes := &v1.ResourceIdentifier{ - Type: v1.ResourceType_Queue, - Name: name, - } - - dr := &v1.ResourceDeclareRequest{ - Id: colRes, - Config: &v1.ResourceDeclareRequest_Queue{ - Queue: &v1.QueueResource{}, - }, - } - _, err = rsc.Declare(context.Background(), dr) - if err != nil { - return nil, err - } - actions := []v1.Action{} - for _, perm := range permissions { + for _, perm := range allPerms { switch perm { case QueueDequeue: actions = append(actions, v1.Action_QueueDequeue) @@ -88,7 +76,12 @@ func (m *manager) newQueue(name string, permissions ...QueuePermission) (queues. } } - _, err = rsc.Declare(context.Background(), functionResourceDeclareRequest(colRes, actions)) + registerResult := <-q.registerChan + if registerResult.Err != nil { + return nil, registerResult.Err + } + + m, err := q.manager.registerPolicy(registerResult.Identifier, actions...) if err != nil { return nil, err } @@ -100,5 +93,5 @@ func (m *manager) newQueue(name string, permissions ...QueuePermission) (queues. } } - return m.queues.Queue(name), nil + return m.queues.Queue(q.name), nil } diff --git a/nitric/schedule.go b/nitric/schedule.go index 5777be2..6dfd516 100644 --- a/nitric/schedule.go +++ b/nitric/schedule.go @@ -36,13 +36,9 @@ type schedule struct { // NewSchedule provides a new schedule, which can be configured with a rate/cron and a callback to run on the schedule. func NewSchedule(name string) Schedule { - return defaultManager.newSchedule(name) -} - -func (m *manager) newSchedule(name string) Schedule { return &schedule{ name: name, - manager: m, + manager: defaultManager, } } diff --git a/nitric/secret.go b/nitric/secret.go index 4208520..a1c80c5 100644 --- a/nitric/secret.go +++ b/nitric/secret.go @@ -15,7 +15,6 @@ package nitric import ( - "context" "fmt" "github.com/nitrictech/go-sdk/api/secrets" @@ -31,50 +30,40 @@ const ( var SecretEverything []SecretPermission = []SecretPermission{SecretAccess, SecretPut} -type Secret interface{} +type Secret interface { + Allow(SecretPermission, ...SecretPermission) (secrets.SecretRef, error) +} type secret struct { - name string - manager Manager + name string + manager Manager + registerChan <-chan RegisterResult } func NewSecret(name string) *secret { - return &secret{ + secret := &secret{ name: name, manager: defaultManager, } -} - -func (s *secret) Allow(permission SecretPermission, permissions ...SecretPermission) (secrets.SecretRef, error) { - allPerms := append([]SecretPermission{permission}, permissions...) - - return defaultManager.newSecret(s.name, allPerms...) -} - -func (m *manager) newSecret(name string, permissions ...SecretPermission) (secrets.SecretRef, error) { - rsc, err := m.resourceServiceClient() - if err != nil { - return nil, err - } - - colRes := &v1.ResourceIdentifier{ - Type: v1.ResourceType_Secret, - Name: name, - } - dr := &v1.ResourceDeclareRequest{ - Id: colRes, + secret.registerChan = defaultManager.registerResource(&v1.ResourceDeclareRequest{ + Id: &v1.ResourceIdentifier{ + Type: v1.ResourceType_Secret, + Name: name, + }, Config: &v1.ResourceDeclareRequest_Secret{ Secret: &v1.SecretResource{}, }, - } - _, err = rsc.Declare(context.Background(), dr) - if err != nil { - return nil, err - } + }) + + return secret +} + +func (s *secret) Allow(permission SecretPermission, permissions ...SecretPermission) (secrets.SecretRef, error) { + allPerms := append([]SecretPermission{permission}, permissions...) actions := []v1.Action{} - for _, perm := range permissions { + for _, perm := range allPerms { switch perm { case SecretAccess: actions = append(actions, v1.Action_SecretAccess) @@ -85,7 +74,12 @@ func (m *manager) newSecret(name string, permissions ...SecretPermission) (secre } } - _, err = rsc.Declare(context.Background(), functionResourceDeclareRequest(colRes, actions)) + registerResult := <-s.registerChan + if registerResult.Err != nil { + return nil, registerResult.Err + } + + m, err := s.manager.registerPolicy(registerResult.Identifier, actions...) if err != nil { return nil, err } @@ -97,5 +91,5 @@ func (m *manager) newSecret(name string, permissions ...SecretPermission) (secre } } - return m.secrets.Secret(name), nil + return m.secrets.Secret(s.name), nil } diff --git a/nitric/topic.go b/nitric/topic.go index ac3bd5d..0bd9431 100644 --- a/nitric/topic.go +++ b/nitric/topic.go @@ -53,18 +53,17 @@ type topic struct { type subscribableTopic struct { name string manager Manager - registerChan chan RegisterResult + registerChan <-chan RegisterResult } // NewTopic creates a new Topic with the give permissions. func NewTopic(name string) SubscribableTopic { topic := &subscribableTopic{ - name: name, - manager: defaultManager, - registerChan: make(chan RegisterResult), + name: name, + manager: defaultManager, } - go defaultManager.registerResource(&v1.ResourceDeclareRequest{ + topic.registerChan = defaultManager.registerResource(&v1.ResourceDeclareRequest{ Id: &v1.ResourceIdentifier{ Type: v1.ResourceType_Topic, Name: name, @@ -72,7 +71,7 @@ func NewTopic(name string) SubscribableTopic { Config: &v1.ResourceDeclareRequest_Topic{ Topic: &v1.TopicResource{}, }, - }, topic.registerChan) + }) return topic } diff --git a/nitric/websocket.go b/nitric/websocket.go index d598020..944ae96 100644 --- a/nitric/websocket.go +++ b/nitric/websocket.go @@ -18,11 +18,6 @@ import ( "context" "strings" - "google.golang.org/grpc" - - "github.com/nitrictech/go-sdk/api/errors" - "github.com/nitrictech/go-sdk/api/errors/codes" - "github.com/nitrictech/go-sdk/constants" "github.com/nitrictech/go-sdk/handler" "github.com/nitrictech/go-sdk/workers" resourcesv1 "github.com/nitrictech/nitric/core/pkg/proto/resources/v1" @@ -46,55 +41,27 @@ type websocket struct { // NewCollection register this collection as a required resource for the calling function/container. func NewWebsocket(name string) (Websocket, error) { - return defaultManager.newWebsocket(name) -} - -func (m *manager) newWebsocket(name string) (Websocket, error) { - ctx, _ := context.WithTimeout(context.Background(), constants.NitricDialTimeout()) - - conn, err := grpc.DialContext( - ctx, - constants.NitricAddress(), - constants.DefaultOptions()..., - ) - if err != nil { - return nil, errors.NewWithCause( - codes.Unavailable, - "Websocket.New: Unable to reach WebsocketServiceServer", - err, - ) - } - - rsc, err := m.resourceServiceClient() - if err != nil { - return nil, err - } - - res := &resourcesv1.ResourceIdentifier{ - Type: resourcesv1.ResourceType_Websocket, - Name: name, - } - - dr := &resourcesv1.ResourceDeclareRequest{ - Id: res, - } - - _, err = rsc.Declare(context.Background(), dr) - if err != nil { - return nil, err + registerResult := <-defaultManager.registerResource(&resourcesv1.ResourceDeclareRequest{ + Id: &resourcesv1.ResourceIdentifier{ + Type: resourcesv1.ResourceType_Websocket, + Name: name, + }, + }) + if registerResult.Err != nil { + return nil, registerResult.Err } actions := []resourcesv1.Action{resourcesv1.Action_WebsocketManage} - _, err = rsc.Declare(context.Background(), functionResourceDeclareRequest(res, actions)) + m, err := defaultManager.registerPolicy(registerResult.Identifier, actions...) if err != nil { return nil, err } - wClient := websocketsv1.NewWebsocketClient(conn) + wClient := websocketsv1.NewWebsocketClient(m.conn) return &websocket{ - manager: m, + manager: defaultManager, client: wClient, name: name, }, nil