package api import ( "context" "errors" "io" "time" mnepb "code.fbi.h-da.de/danet/gosdn/api/go/gosdn/networkelement" pipb "code.fbi.h-da.de/danet/gosdn/api/go/gosdn/plugin-internal" spb "code.fbi.h-da.de/danet/gosdn/api/go/gosdn/southbound" tpb "code.fbi.h-da.de/danet/gosdn/api/go/gosdn/transport" nbi "code.fbi.h-da.de/danet/gosdn/controller/northbound/client" "github.com/google/uuid" "github.com/openconfig/goyang/pkg/yang" "github.com/openconfig/ygot/ygot" log "github.com/sirupsen/logrus" ) // AddNetworkElement adds a new network element to the controller. The network element name is optional. // If no name is provided a name will be generated upon network element creation. func AddNetworkElement(ctx context.Context, addr, mneName string, opt *tpb.TransportOption, pluginID, pid uuid.UUID) (*mnepb.AddListResponse, error) { client, err := nbi.NetworkElementClient(addr, dialOptions...) if err != nil { return nil, err } req := &mnepb.AddListRequest{ Timestamp: time.Now().UnixNano(), Mne: []*mnepb.SetMne{ { Address: opt.GetAddress(), MneName: mneName, PluginId: pluginID.String(), Pid: pid.String(), TransportOption: opt, }, }, Pid: pid.String(), } switch t := opt.Type; t { case spb.Type_TYPE_CONTAINERISED, spb.Type_TYPE_PLUGIN: req.Mne[0].TransportOption.Type = t default: } return client.AddList(ctx, req) } // GetNetworkElement requests one network element belonging to a given // PrincipalNetworkDomain from the controller. If no network element identifier // is provided, an error is thrown. func GetNetworkElement(ctx context.Context, addr, pid string, mneid string) (*mnepb.GetResponse, error) { client, err := nbi.NetworkElementClient(addr, dialOptions...) if err != nil { return nil, err } if len(mneid) == 0 { return nil, err } req := &mnepb.GetRequest{ Timestamp: time.Now().UnixNano(), Mneid: mneid, Pid: pid, } return client.Get(ctx, req) } // GetPluginSchemaTree gets the schema tree for a plugin. func GetPluginSchemaTree(ctx context.Context, addr string, pluginID uuid.UUID) (map[string]*yang.Entry, error) { pluginClient, err := nbi.PluginClient(addr, dialOptions...) if err != nil { return map[string]*yang.Entry{}, err } req := &pipb.GetPluginSchemaRequest{ Timestamp: time.Now().UnixNano(), Pid: pluginID.String(), } ctx, cancel := context.WithTimeout(ctx, time.Minute*10) defer cancel() sClient, err := pluginClient.GetPluginSchema(ctx, req) if err != nil { return map[string]*yang.Entry{}, err } sTreeBytes := []byte{} for { payload, err := sClient.Recv() if err != nil { if errors.Is(err, io.EOF) { break } log.Error(err) closeErr := sClient.CloseSend() if closeErr != nil { return nil, err } return map[string]*yang.Entry{}, err } sTreeBytes = append(sTreeBytes, payload.Chunk...) } sTreeMap, err := ygot.GzipToSchema(sTreeBytes) if err != nil { return map[string]*yang.Entry{}, err } return sTreeMap, nil } // GetFlattenedNetworkElement requests a network elements belonging to a given // PrincipalNetworkDomain from the controller. func GetFlattenedNetworkElement(ctx context.Context, addr, pid string, mneid string) (*mnepb.GetFlattenedResponse, error) { client, err := nbi.NetworkElementClient(addr, dialOptions...) if err != nil { return nil, err } req := &mnepb.GetFlattenedRequest{ Timestamp: time.Now().UnixNano(), Mneid: mneid, Pid: pid, } return client.GetFlattened(ctx, req) } // GetFlattenedNetworkElements requests all network elements belonging to a given // PrincipalNetworkDomain from the controller. func GetFlattenedNetworkElements(ctx context.Context, addr, pid string) (*mnepb.GetAllFlattenedResponse, error) { client, err := nbi.NetworkElementClient(addr, dialOptions...) if err != nil { return nil, err } req := &mnepb.GetAllFlattenedRequest{ Timestamp: time.Now().UnixNano(), Pid: pid, } return client.GetAllFlattened(ctx, req) } // GetPath requests a specific path. func GetPath(ctx context.Context, addr, pid, mneid, path string) (*mnepb.GetPathResponse, error) { client, err := nbi.NetworkElementClient(addr, dialOptions...) if err != nil { return nil, err } req := &mnepb.GetPathRequest{ Timestamp: time.Now().UnixNano(), Mneid: mneid, Pid: pid, Path: path, } return client.GetPath(ctx, req) } func GetIntendedPath(ctx context.Context, addr, pid, mneid, intendedPath string) (*mnepb.GetIntendedPathResponse, error) { client, err := nbi.NetworkElementClient(addr, dialOptions...) if err != nil { return nil, err } req := &mnepb.GetIntendedPathRequest{ Timestamp: time.Now().UnixNano(), Mneid: mneid, Pid: pid, IntendedPath: intendedPath, } return client.GetIntendedPath(ctx, req) } // SubscribePath subscribes to paths on a network element. func SubscribePath(ctx context.Context, addr, pid, mneid string, slist *mnepb.SubscriptionList) (mnepb.NetworkElementService_SubscribePathClient, error) { log.Println("subscribePath called") client, err := nbi.NetworkElementClient(addr, dialOptions...) if err != nil { return nil, err } req := &mnepb.SubscribePathRequest{ Timestamp: time.Now().UnixNano(), Mneid: mneid, Pid: pid, Sublist: slist, } return client.SubscribePath(ctx, req) } // DeleteNetworkElement deletes a network element. func DeleteNetworkElement(ctx context.Context, addr, pid, mneid string) (*mnepb.DeleteResponse, error) { client, err := nbi.NetworkElementClient(addr, dialOptions...) if err != nil { return nil, err } req := &mnepb.DeleteRequest{ Timestamp: time.Now().UnixNano(), Mneid: mneid, Pid: pid, } return client.Delete(ctx, req) }