diff --git a/controller/controller.go b/controller/controller.go index 7e2414e7664a96fe10b7f1911ddd0f7c5bdcef25..3eb2c153ffd24231834769eecf0d23788404f8be 100644 --- a/controller/controller.go +++ b/controller/controller.go @@ -146,7 +146,7 @@ func initialize() error { } c.networkElementWatcher = nucleus.NewNetworkElementWatcher(c.mneService, c.eventService) - c.networkElementWatcher.SubscribeToNetworkElements(config.GetGnmiSubscriptionPaths(), nil) + c.networkElementWatcher.SubscribeToNetworkElements(nil) if err := ensureDefaultRoleExists(); err != nil { return err diff --git a/controller/northbound/server/networkElement.go b/controller/northbound/server/networkElement.go index 7f33994dadbc8023dcea02616994030163952961..95816707b8982d46c0be75e6145e3d246e7146cb 100644 --- a/controller/northbound/server/networkElement.go +++ b/controller/northbound/server/networkElement.go @@ -9,7 +9,6 @@ import ( mnepb "code.fbi.h-da.de/danet/gosdn/api/go/gosdn/networkelement" ppb "code.fbi.h-da.de/danet/gosdn/api/go/gosdn/pnd" tpb "code.fbi.h-da.de/danet/gosdn/api/go/gosdn/transport" - "code.fbi.h-da.de/danet/gosdn/controller/config" "code.fbi.h-da.de/danet/gosdn/controller/conflict" "code.fbi.h-da.de/danet/gosdn/controller/customerrs" "code.fbi.h-da.de/danet/gosdn/controller/interfaces/change" @@ -629,7 +628,7 @@ func (n *NetworkElementServer) addMne(ctx context.Context, return uuid.Nil, err } - n.networkElementWatchter.SubscribeToNetworkElement(mne, config.GetGnmiSubscriptionPaths(), nil) + n.networkElementWatchter.SubscribeToNetworkElement(mne, nil) } else { err = fmt.Errorf("invalid transport data provided") return uuid.Nil, err diff --git a/controller/nucleus/networkElementWatcher.go b/controller/nucleus/networkElementWatcher.go index 48d6bc39567e1c570ffe213e5968b84346a5787b..21b910e977f91989ff09fdbc2a06f4d554c64fc4 100644 --- a/controller/nucleus/networkElementWatcher.go +++ b/controller/nucleus/networkElementWatcher.go @@ -3,8 +3,10 @@ package nucleus import ( "context" "fmt" + "sort" "strconv" + "code.fbi.h-da.de/danet/gosdn/controller/config" "code.fbi.h-da.de/danet/gosdn/controller/customerrs" "code.fbi.h-da.de/danet/gosdn/controller/event" eventInterfaces "code.fbi.h-da.de/danet/gosdn/controller/interfaces/event" @@ -14,6 +16,7 @@ import ( "code.fbi.h-da.de/danet/gosdn/forks/goarista/gnmi" "github.com/google/uuid" gpb "github.com/openconfig/gnmi/proto/gnmi" + ygotutil "github.com/openconfig/ygot/util" "github.com/openconfig/ygot/ygot" log "github.com/sirupsen/logrus" ) @@ -51,14 +54,12 @@ func NewNetworkElementWatcher(mneService networkelement.Service, eventService ev } // SubscribeToNetworkElements subscribes to every available network element in each network domain according to provided SubscribeOptions. -// Paths should be provided in the following format [][]string{{"system", "config", "hostname"}} // SubscribeOptions can be nil. Use nil for a fixed, pre-defined set of gNMI subscription options (streaming in sample mode each second). -func (n *NetworkElementWatcher) SubscribeToNetworkElements(paths [][]string, opts *gnmi.SubscribeOptions) { +func (n *NetworkElementWatcher) SubscribeToNetworkElements(opts *gnmi.SubscribeOptions) { if opts == nil { opts = &gnmi.SubscribeOptions{ Mode: gNMISubscribeMode, StreamMode: gNMIStreamMode, - Paths: paths, SampleInterval: subscribeSampleInterval, } } @@ -75,14 +76,12 @@ func (n *NetworkElementWatcher) SubscribeToNetworkElements(paths [][]string, opt } // SubscribeToNetworkElement subscribes to the provided network element according to provided SubscribeOptions. -// Paths should be provided in the following format [][]string{{"system", "config", "hostname"}} // SubscribeOptions can be nil. Use nil for a fixed, pre-defined set of gNMI subscription options (streaming in sample mode each second). -func (n *NetworkElementWatcher) SubscribeToNetworkElement(mne networkelement.NetworkElement, paths [][]string, opts *gnmi.SubscribeOptions) { +func (n *NetworkElementWatcher) SubscribeToNetworkElement(mne networkelement.NetworkElement, opts *gnmi.SubscribeOptions) { if opts == nil { opts = &gnmi.SubscribeOptions{ Mode: gNMISubscribeMode, StreamMode: gNMIStreamMode, - Paths: paths, SampleInterval: subscribeSampleInterval, } } @@ -98,14 +97,14 @@ func (n *NetworkElementWatcher) subscribeToNetworkElement(mne networkelement.Net stopFunc: cancel, }) + opts.Paths = n.mergeGnmiSubscriptions(mne.GetGnmiSubscriptionPaths(), config.GetGnmiSubscriptionPaths()) + go n.callSubscribe(stopContext, mne, opts) } // callSubscribe spawns a worker pool to handle gNMI subscription updates for each individual subscription // and then sets up the gNMI subscription listener. func (n *NetworkElementWatcher) callSubscribe(stopContext context.Context, mne networkelement.NetworkElement, opts *gnmi.SubscribeOptions) { - opts.Paths = mne.GetGnmiSubscriptionPaths() - gNMIOptionsCtx := context.Background() gNMIOptionsCtx = context.WithValue(gNMIOptionsCtx, types.CtxKeyOpts, opts) @@ -212,21 +211,38 @@ func (n *NetworkElementWatcher) handleSubscribeResponseUpdate(resp *gpb.Subscrib } } -// TODO(faseid): implement path join! -// func (n *NetworkElementWatcher) joinGnmiSubscriptions(gNMISusbcriptionPathsFromMne, gNMISusbcriptionPathsFromConfig [][]string) [][]string { -// var joinedPaths = gNMISusbcriptionPathsFromMne - -// for i, _ := range gNMISusbcriptionPathsFromMne { +// mergeGnmiSubscriptions takes paths for gNMI Subscriptions from two sources (the MNE and a config file) +// and merges them to one set of subscription paths without duplicates. +// Paths should be provided in the following format [][]string{{"system", "config", "hostname"}}. +func (n *NetworkElementWatcher) mergeGnmiSubscriptions(gNMISusbcriptionPathsFromMne, gNMISusbcriptionPathsFromConfig [][]string) [][]string { + // create slice with all elements + var tempJoinedPaths = gNMISusbcriptionPathsFromMne -// } + for _, configPath := range gNMISusbcriptionPathsFromConfig { + tempJoinedPaths = append(tempJoinedPaths, configPath) + } -// for _, mnePath := range joinedPaths { -// for _, configPath := range gNMISusbcriptionPathsFromConfig { -// if mnePath != configPath { + // sort slice + sort.Slice(tempJoinedPaths[:], func(i, j int) bool { + for elem := range tempJoinedPaths[i] { + if tempJoinedPaths[i][elem] == tempJoinedPaths[j][elem] { + continue + } + return tempJoinedPaths[i][elem] < tempJoinedPaths[j][elem] + } + return false + }) -// } -// } -// } + // remove duplicates + inResult := make(map[string]bool) + var joinedPaths [][]string + for _, pathSlice := range tempJoinedPaths { + path := ygotutil.SlicePathToString(pathSlice) + if _, ok := inResult[path]; !ok { + inResult[path] = true + joinedPaths = append(joinedPaths, pathSlice) + } + } -// return joinedPaths -// } + return joinedPaths +}