diff --git a/application-framework/registration/registration.go b/application-framework/registration/registration.go index 97acc4e3dfb40f6bdc9348a23e6d4766ed6c4fb8..2c3571b5e9e4ba9950d0e4ac378b00fbf2b7db54 100644 --- a/application-framework/registration/registration.go +++ b/application-framework/registration/registration.go @@ -2,6 +2,7 @@ package registration import ( "context" + "fmt" "time" "code.fbi.h-da.de/danet/gosdn/api/go/gosdn/app" @@ -15,6 +16,12 @@ func Register(ctx context.Context, gosdnAddress, name, token string) (string, er if err != nil { return "", err } + defer func() { + if ferr := conn.Close(); ferr != nil { + fErrString := ferr.Error() + err = fmt.Errorf("InternalError=%w DeferError=%+s", err, fErrString) + } + }() appService := app.NewAppServiceClient(conn) diff --git a/controller/northbound/client/app.go b/controller/northbound/client/app.go index 48195078acf9907c2702c1687615da8420959575..1ba7188c185fe3bb853eb9506c004ed845cedd1f 100644 --- a/controller/northbound/client/app.go +++ b/controller/northbound/client/app.go @@ -5,13 +5,19 @@ import ( "google.golang.org/grpc" ) +var appClientConnection *grpc.ClientConn + // AppClient returns a client for the gRPC App service. It takes // the address of the gRPC endpoint and optional grpc.DialOption // as argument. func AppClient(addr string, opts ...grpc.DialOption) (apb.AppServiceClient, error) { - conn, err := grpc.NewClient(addr, opts...) - if err != nil { - return nil, err + var err error + + if appClientConnection == nil { + appClientConnection, err = grpc.NewClient(addr, opts...) + if err != nil { + return nil, err + } } - return apb.NewAppServiceClient(conn), nil + return apb.NewAppServiceClient(appClientConnection), nil } diff --git a/controller/northbound/client/configurationManagement.go b/controller/northbound/client/configurationManagement.go index a88cae6d72e87cb21bb04d322bce1a4fdb5dbe53..bb8972b74a640e2747f007c1609ee96f1768d1df 100644 --- a/controller/northbound/client/configurationManagement.go +++ b/controller/northbound/client/configurationManagement.go @@ -5,13 +5,20 @@ import ( "google.golang.org/grpc" ) +var configurationManagementClientConnection *grpc.ClientConn + // ConfigurationManagementClient returns a client for the gRPC ConfigurationManagement service. It takes // the address of the gRPC endpoint and optional grpc.DialOption // as argument. func ConfigurationManagementClient(addr string, opts ...grpc.DialOption) (cpb.ConfigurationManagementServiceClient, error) { - conn, err := grpc.NewClient(addr, opts...) - if err != nil { - return nil, err + var err error + + if configurationManagementClientConnection == nil { + configurationManagementClientConnection, err = grpc.NewClient(addr, opts...) + if err != nil { + return nil, err + } } - return cpb.NewConfigurationManagementServiceClient(conn), nil + + return cpb.NewConfigurationManagementServiceClient(configurationManagementClientConnection), nil } diff --git a/controller/northbound/client/networkElement.go b/controller/northbound/client/networkElement.go index b3b71cf078ad8f44036ea6534809454fac7ae8bb..2a85e98f4f06fdd67d3e8096cc57cdfd1cfbbc24 100644 --- a/controller/northbound/client/networkElement.go +++ b/controller/northbound/client/networkElement.go @@ -5,13 +5,20 @@ import ( "google.golang.org/grpc" ) +var networkElementServiceClientConnection *grpc.ClientConn + // NetworkElementClient returns a client for the gRPC NetworkElement service. It takes // the address of the gRPC endpoint and optional grpc.DialOption // as argument. func NetworkElementClient(addr string, opts ...grpc.DialOption) (mnepb.NetworkElementServiceClient, error) { - conn, err := grpc.NewClient(addr, opts...) - if err != nil { - return nil, err + var err error + + if networkElementServiceClientConnection == nil { + networkElementServiceClientConnection, err = grpc.NewClient(addr, opts...) + if err != nil { + return nil, err + } } - return mnepb.NewNetworkElementServiceClient(conn), nil + + return mnepb.NewNetworkElementServiceClient(networkElementServiceClientConnection), nil } diff --git a/controller/northbound/client/plugin.go b/controller/northbound/client/plugin.go index e9adcdd42268b43f4bec98983b9d21a6db29e8bb..96bef09dcc8cfc9bab0ebc127efd0cdd0a27bcdf 100644 --- a/controller/northbound/client/plugin.go +++ b/controller/northbound/client/plugin.go @@ -5,10 +5,16 @@ import ( "google.golang.org/grpc" ) +var pluginClientConnection *grpc.ClientConn + func PluginClient(addr string, opts ...grpc.DialOption) (pipb.PluginInternalServiceClient, error) { - conn, err := grpc.NewClient(addr, opts...) - if err != nil { - return nil, err + var err error + + if pluginClientConnection == nil { + pluginClientConnection, err = grpc.NewClient(addr, opts...) + if err != nil { + return nil, err + } } - return pipb.NewPluginInternalServiceClient(conn), nil + return pipb.NewPluginInternalServiceClient(pluginClientConnection), nil } diff --git a/controller/northbound/client/pnd.go b/controller/northbound/client/pnd.go index c239c6c695b3c9b7d7b6df464fe04d1cc458ab82..ad16efc50d4599ff8bb4825bec63ae70cec50dff 100644 --- a/controller/northbound/client/pnd.go +++ b/controller/northbound/client/pnd.go @@ -5,13 +5,20 @@ import ( "google.golang.org/grpc" ) +var pndClientConnection *grpc.ClientConn + // PndClient returns a client for the gRPC PND service. It takes // the address of the gRPC endpoint and optional grpc.DialOption // as argument. func PndClient(addr string, opts ...grpc.DialOption) (ppb.PndServiceClient, error) { - conn, err := grpc.NewClient(addr, opts...) - if err != nil { - return nil, err + var err error + + if pndClientConnection == nil { + pndClientConnection, err = grpc.NewClient(addr, opts...) + if err != nil { + return nil, err + } } - return ppb.NewPndServiceClient(conn), nil + + return ppb.NewPndServiceClient(pndClientConnection), nil } diff --git a/controller/northbound/client/rbac.go b/controller/northbound/client/rbac.go index 1c3443f4b49281060c65e21c2e33e59c1018d031..01c59622d96422d88864c24f32aae8b6dcc5fc8c 100644 --- a/controller/northbound/client/rbac.go +++ b/controller/northbound/client/rbac.go @@ -5,35 +5,51 @@ import ( "google.golang.org/grpc" ) +var authClientConnection *grpc.ClientConn +var userClientConnection *grpc.ClientConn +var roleClientConnection *grpc.ClientConn + // AuthClient returns a client for the gRPC Auth service. It takes // the address of the gRPC endpoint and optional grpc.DialOption // as argument. func AuthClient(addr string, opts ...grpc.DialOption) (apb.AuthServiceClient, error) { - conn, err := grpc.NewClient(addr, opts...) - if err != nil { - return nil, err + var err error + + if authClientConnection == nil { + authClientConnection, err = grpc.NewClient(addr, opts...) + if err != nil { + return nil, err + } } - return apb.NewAuthServiceClient(conn), nil + return apb.NewAuthServiceClient(authClientConnection), nil } // UserClient returns a client for the gRPC User service. It takes // the address of the gRPC endpoint and optional grpc.DialOption // as argument. func UserClient(addr string, opts ...grpc.DialOption) (apb.UserServiceClient, error) { - conn, err := grpc.NewClient(addr, opts...) - if err != nil { - return nil, err + var err error + + if userClientConnection == nil { + userClientConnection, err = grpc.NewClient(addr, opts...) + if err != nil { + return nil, err + } } - return apb.NewUserServiceClient(conn), nil + return apb.NewUserServiceClient(userClientConnection), nil } // RoleClient returns a client for the gRPC Role service. It takes // the address of the gRPC endpoint and optional grpc.DialOption // as argument. func RoleClient(addr string, opts ...grpc.DialOption) (apb.RoleServiceClient, error) { - conn, err := grpc.NewClient(addr, opts...) - if err != nil { - return nil, err + var err error + + if roleClientConnection == nil { + roleClientConnection, err = grpc.NewClient(addr, opts...) + if err != nil { + return nil, err + } } - return apb.NewRoleServiceClient(conn), nil + return apb.NewRoleServiceClient(roleClientConnection), nil } diff --git a/controller/northbound/client/sbi.go b/controller/northbound/client/sbi.go index a07128b89d325af489ab486055368703af6b857a..8795ce1cf3e9fd242f839a7bb450805a78b01df1 100644 --- a/controller/northbound/client/sbi.go +++ b/controller/northbound/client/sbi.go @@ -5,13 +5,20 @@ import ( "google.golang.org/grpc" ) +var sbiClientConnection *grpc.ClientConn + // SbiClient returns a client for the gRPC SBI service. It takes // the address of the gRPC endpoint and optional grpc.DialOption // as argument. func SbiClient(addr string, opts ...grpc.DialOption) (spb.SbiServiceClient, error) { - conn, err := grpc.NewClient(addr, opts...) - if err != nil { - return nil, err + var err error + + if sbiClientConnection == nil { + sbiClientConnection, err = grpc.NewClient(addr, opts...) + if err != nil { + return nil, err + } } - return spb.NewSbiServiceClient(conn), nil + + return spb.NewSbiServiceClient(sbiClientConnection), nil } diff --git a/controller/northbound/client/submanagement.go b/controller/northbound/client/submanagement.go index c8774a2e036175a807a688560209c99ac330ec64..6526cce1265033934a9c8935456f5345ed653ccd 100644 --- a/controller/northbound/client/submanagement.go +++ b/controller/northbound/client/submanagement.go @@ -5,13 +5,20 @@ import ( "google.golang.org/grpc" ) +var subManagementClientConnection *grpc.ClientConn + // SubManagementClient returns a client for the gRPC SubscriptionManagement service. It takes // the address of the gRPC endpoint and optional grpc.DialOption // as argument. func SubManagementClient(addr string, opts ...grpc.DialOption) (subpb.SubscriptionManagementServiceClient, error) { - conn, err := grpc.NewClient(addr, opts...) - if err != nil { - return nil, err + var err error + + if subManagementClientConnection == nil { + subManagementClientConnection, err = grpc.NewClient(addr, opts...) + if err != nil { + return nil, err + } } - return subpb.NewSubscriptionManagementServiceClient(conn), nil + + return subpb.NewSubscriptionManagementServiceClient(subManagementClientConnection), nil } diff --git a/controller/nucleus/databaseNetworkElementStore.go b/controller/nucleus/databaseNetworkElementStore.go index a5bc5cb0746246b4b53ea472f20ea635a2577110..77e7e5975dc3d7d08809aa01e5cdd09216fb6021 100644 --- a/controller/nucleus/databaseNetworkElementStore.go +++ b/controller/nucleus/databaseNetworkElementStore.go @@ -6,7 +6,6 @@ import ( "code.fbi.h-da.de/danet/gosdn/controller/customerrs" "code.fbi.h-da.de/danet/gosdn/controller/interfaces/networkelement" - "code.fbi.h-da.de/danet/gosdn/controller/nucleus/database" "code.fbi.h-da.de/danet/gosdn/controller/store" "go.mongodb.org/mongo-driver/bson" "go.mongodb.org/mongo-driver/bson/primitive" @@ -122,15 +121,10 @@ func (s *DatabaseNetworkElementStore) Add(ctx context.Context, networkElementToA func (s *DatabaseNetworkElementStore) Update(ctx context.Context, networkElementToUpdate networkelement.NetworkElement) (err error) { var updatedLoadedNetworkElement networkelement.LoadedNetworkElement - db, err := database.GetDatabaseConnection() - if err != nil { - return err - } - wc := writeconcern.Majority() txnOptions := options.Transaction().SetWriteConcern(wc) // Starts a session on the client - session, err := db.Client().StartSession() + session, err := s.collection.Database().Client().StartSession() if err != nil { return err } diff --git a/controller/nucleus/gnmi_transport.go b/controller/nucleus/gnmi_transport.go index a51770d764f2abd12b28941000cacd2860c9e8fe..f25f8c0093e828916bb5c0fe88defcb3b22cd6f1 100644 --- a/controller/nucleus/gnmi_transport.go +++ b/controller/nucleus/gnmi_transport.go @@ -20,6 +20,8 @@ import ( tpb "code.fbi.h-da.de/danet/gosdn/api/go/gosdn/transport" ) +var gnmiClients = make(map[string]gpb.GNMIClient, 0) + // Gnmi implements the Transport interface and provides an SBI with the // possibility to access a gNMI endpoint. type Gnmi struct { @@ -64,9 +66,14 @@ func newGnmiTransport(opts *tpb.TransportOption, model shared.DeviceModel) (*Gnm } } - c, err := gnmi.Dial(gnmiConfig) - if err != nil { - return nil, err + var err error + c, ok := gnmiClients[opts.GetAddress()] + if !ok { + c, err = gnmi.Dial(gnmiConfig) + if err != nil { + return nil, err + } + gnmiClients[opts.GetAddress()] = c } log.WithFields(log.Fields{ diff --git a/controller/nucleus/plugin.go b/controller/nucleus/plugin.go index b409e6252ea0476fcaff8de5d385f172609d09be..96a0e00ebd28a5402a5405d73840e2215528baee 100644 --- a/controller/nucleus/plugin.go +++ b/controller/nucleus/plugin.go @@ -16,6 +16,13 @@ import ( "go.mongodb.org/mongo-driver/bson" ) +type pluginConnection struct { + client *hcplugin.Client + model shared.DeviceModel +} + +var pluginClients = make(map[uuid.UUID]pluginConnection, 0) + // Plugin is the controllers internal representation of a plugin. type Plugin struct { UUID uuid.UUID @@ -66,6 +73,11 @@ func NewPlugin(id uuid.UUID, execPath string) (*Plugin, error) { } } + pluginClients[id] = pluginConnection{ + client: client, + model: model, + } + return &Plugin{ UUID: id, client: client, @@ -78,43 +90,52 @@ func NewPlugin(id uuid.UUID, execPath string) (*Plugin, error) { // NewPluginThroughReattachConfig creates a new Plugin through a reattach config. func NewPluginThroughReattachConfig(loadedPlugin plugin.LoadedPlugin) (plugin.Plugin, error) { - client := hcplugin.NewClient(&hcplugin.ClientConfig{ - HandshakeConfig: shared.Handshake, - Plugins: shared.PluginMap, - Reattach: &loadedPlugin.ReattachConfig, - AllowedProtocols: []hcplugin.Protocol{hcplugin.ProtocolGRPC}, - }) - - // create a client that is within the AllowedProtocols. In this case this - // returns a gRPCClient. Allows to connect through gRPC. - gRPCClient, err := client.Client() + //client := hcplugin.NewClient(&hcplugin.ClientConfig{ + // HandshakeConfig: shared.Handshake, + // Plugins: shared.PluginMap, + // Reattach: &loadedPlugin.ReattachConfig, + // AllowedProtocols: []hcplugin.Protocol{hcplugin.ProtocolGRPC}, + //}) + + //// create a client that is within the AllowedProtocols. In this case this + //// returns a gRPCClient. Allows to connect through gRPC. + //gRPCClient, err := client.Client() + //if err != nil { + // return nil, err + //} + + //// Request the plugin. This returns the gRPC client from the + //// DeviceModelPlugin. This can then be casted to the interface that we are + //// exposing through the plugin (in this case "DeviceModel"). + //raw, err := gRPCClient.Dispense("deviceModel") + //if err != nil { + // return nil, err + //} + + //// cast the raw plugin to the DeviceModel interface. This allows to call + //// methods on the plugin as if it were a normal DeviceModel instance but + //// actually they are executed on the plugin sent through gRPC. + //model, ok := raw.(shared.DeviceModel) + //if !ok { + // return nil, customerrs.InvalidTypeAssertionError{ + // Value: model, + // Type: (*shared.DeviceModel)(nil), + // } + //} + pluginId, err := uuid.Parse(loadedPlugin.ID) if err != nil { return nil, err } - // Request the plugin. This returns the gRPC client from the - // DeviceModelPlugin. This can then be casted to the interface that we are - // exposing through the plugin (in this case "DeviceModel"). - raw, err := gRPCClient.Dispense("deviceModel") - if err != nil { - return nil, err - } - - // cast the raw plugin to the DeviceModel interface. This allows to call - // methods on the plugin as if it were a normal DeviceModel instance but - // actually they are executed on the plugin sent through gRPC. - model, ok := raw.(shared.DeviceModel) + pc, ok := pluginClients[pluginId] if !ok { - return nil, customerrs.InvalidTypeAssertionError{ - Value: model, - Type: (*shared.DeviceModel)(nil), - } + return nil, fmt.Errorf("plugin not found") } return &Plugin{ UUID: uuid.MustParse(loadedPlugin.ID), - client: client, - DeviceModel: model, + client: pc.client, + DeviceModel: pc.model, manifest: &loadedPlugin.Manifest, state: plugin.INITIALIZED, }, nil diff --git a/controller/rbac/databaseUserStore.go b/controller/rbac/databaseUserStore.go index cfa592de9761195c56f1c7e8185160d286213acc..c3b4400e9d576e4f6034d595b6385fc82805d2ad 100644 --- a/controller/rbac/databaseUserStore.go +++ b/controller/rbac/databaseUserStore.go @@ -6,7 +6,6 @@ import ( "code.fbi.h-da.de/danet/gosdn/controller/customerrs" "code.fbi.h-da.de/danet/gosdn/controller/interfaces/rbac" - "code.fbi.h-da.de/danet/gosdn/controller/nucleus/database" "code.fbi.h-da.de/danet/gosdn/controller/store" "github.com/google/uuid" log "github.com/sirupsen/logrus" @@ -134,15 +133,10 @@ func (s *DatabaseUserStore) GetAll(ctx context.Context) (loadedUsers []rbac.Load func (s *DatabaseUserStore) Update(ctx context.Context, userToUpdate rbac.User) (err error) { var updatedLoadedUser rbac.LoadedUser - db, err := database.GetDatabaseConnection() - if err != nil { - return err - } - wc := writeconcern.Majority() txnOptions := options.Transaction().SetWriteConcern(wc) // Starts a session on the client - session, err := db.Client().StartSession() + session, err := s.collection.Database().Client().StartSession() if err != nil { return err } diff --git a/controller/topology/nodes/databaseNodeStore.go b/controller/topology/nodes/databaseNodeStore.go index b0389082c7dcd44055f3c160c834ddea9bb49a4c..9c575cb6f74b71806ff13a907384230899f05ab3 100644 --- a/controller/topology/nodes/databaseNodeStore.go +++ b/controller/topology/nodes/databaseNodeStore.go @@ -6,7 +6,6 @@ import ( "time" "code.fbi.h-da.de/danet/gosdn/controller/customerrs" - "code.fbi.h-da.de/danet/gosdn/controller/nucleus/database" query "code.fbi.h-da.de/danet/gosdn/controller/store" "github.com/google/uuid" @@ -133,15 +132,10 @@ func (s *DatabaseNodeStore) Add(ctx context.Context, node Node) (err error) { func (s *DatabaseNodeStore) Update(ctx context.Context, node Node) (err error) { var updatedLoadedNodes Node - db, err := database.GetDatabaseConnection() - if err != nil { - return err - } - wc := writeconcern.Majority() txnOptions := options.Transaction().SetWriteConcern(wc) // Starts a session on the client - session, err := db.Client().StartSession() + session, err := s.collection.Database().Client().StartSession() if err != nil { return err }