Newer
Older
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
package nucleus
import (
"fmt"
spb "code.fbi.h-da.de/danet/gosdn/api/go/gosdn/southbound"
"code.fbi.h-da.de/danet/gosdn/controller/event"
eventInterfaces "code.fbi.h-da.de/danet/gosdn/controller/interfaces/event"
"code.fbi.h-da.de/danet/gosdn/controller/interfaces/networkelement"
"code.fbi.h-da.de/danet/gosdn/controller/interfaces/southbound"
"code.fbi.h-da.de/danet/gosdn/controller/store"
"github.com/google/uuid"
"github.com/openconfig/ygot/ygot"
tpb "code.fbi.h-da.de/danet/gosdn/api/go/gosdn/transport"
log "github.com/sirupsen/logrus"
)
const (
// NetworkElementEventTopic is the used topic for network element related entity changes.
NetworkElementEventTopic = "managedNetworkElement"
)
// NetworkElementService provides a network element service implementation.
// This services provides abstraction between the user (e.g a PND) and the matching store (e.g. networkElementStore).
type NetworkElementService struct {
networkElementStore networkelement.Store
sbiService southbound.Service
eventService eventInterfaces.Service
}
// NewNetworkElementService creates a network element service.
func NewNetworkElementService(
networkElementStore networkelement.Store,
sbiService southbound.Service,
eventService eventInterfaces.Service,
) networkelement.Service {
return &NetworkElementService{
networkElementStore: networkElementStore,
sbiService: sbiService,
eventService: eventService,
}
}
// Get takes a network element's UUID or name and returns the network element.
func (s *NetworkElementService) Get(query store.Query) (networkelement.NetworkElement, error) {
loadedNetworkElement, err := s.networkElementStore.Get(query)
if err != nil {
return nil, err
}
mne, err := s.createNetworkElementFromStore(loadedNetworkElement)
if err != nil {
return nil, err
}
return mne, nil
}
// GetAll returns all stored network elements.
func (s *NetworkElementService) GetAll() ([]networkelement.NetworkElement, error) {
var mnes []networkelement.NetworkElement
loadedNetworkElements, err := s.networkElementStore.GetAll()
if err != nil {
return nil, err
}
for _, loadedNetworkElement := range loadedNetworkElements {
mne, err := s.createNetworkElementFromStore(loadedNetworkElement)
if err != nil {
return nil, err
}
mnes = append(mnes, mne)
}
return mnes, nil
}
// GetAllAsLoaded returns all stored network elements as LoadedNetworkElement.
// This method should be used if there is no need for a networkelement.NetworkElement, since
// requesting network element information through this method is a lot faster than the
// usual `GetAll` method.
func (s *NetworkElementService) GetAllAsLoaded() ([]networkelement.LoadedNetworkElement, error) {
loadedNetworkElements, err := s.networkElementStore.GetAll()
if err != nil {
return nil, err
}
return loadedNetworkElements, nil
}
// Add adds a network element to the network element store.
func (s *NetworkElementService) Add(networkElementToAdd networkelement.NetworkElement) error {
err := s.networkElementStore.Add(networkElementToAdd)
if err != nil {
return err
}
Fabian Seidl
committed
pubEvent := event.NewAddEvent(networkElementToAdd.ID())
if err := s.eventService.PublishEvent(NetworkElementEventTopic, pubEvent); err != nil {
go func() {
s.eventService.Reconnect()
retryErr := s.eventService.RetryPublish(NetworkElementEventTopic, pubEvent)
if retryErr != nil {
log.Error(retryErr)
}
}()
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
}
return nil
}
// UpdateModel updates a existing network element with a new model provided as string.
func (s *NetworkElementService) UpdateModel(networkElementToUpdate networkelement.NetworkElement, modelAsString string) error {
exisitingNetworkElement, err := s.Get(store.Query{ID: networkElementToUpdate.ID()})
if err != nil {
return err
}
// Create 'root' path to be able to load the whole model from the store.
path, err := ygot.StringToPath("/", ygot.StructuredPath)
if err != nil {
return err
}
// Use unmarshall from the network elements SBI to unmarshall ygot json in go struct.
err = exisitingNetworkElement.SBI().Unmarshal([]byte(modelAsString), path, exisitingNetworkElement.GetModel())
if err != nil {
return err
}
err = s.networkElementStore.Update(exisitingNetworkElement)
if err != nil {
return err
}
// TODO (faseid): check if we want to add the paths with values here instead of empty map!
pubEvent := event.NewMneUpdateEvent(networkElementToUpdate.ID(), map[string]string{})
Fabian Seidl
committed
if err := s.eventService.PublishEvent(NetworkElementEventTopic, pubEvent); err != nil {
go func() {
s.eventService.Reconnect()
retryErr := s.eventService.RetryPublish(NetworkElementEventTopic, pubEvent)
if retryErr != nil {
log.Error(retryErr)
}
}()
}
return nil
}
// Update updates a existing network element.
func (s *NetworkElementService) Update(networkElementToUpdate networkelement.NetworkElement) error {
err := s.networkElementStore.Update(networkElementToUpdate)
if err != nil {
return err
}
// TODO (faseid): check if we want to add the paths with values here instead of empty map!
pubEvent := event.NewMneUpdateEvent(networkElementToUpdate.ID(), map[string]string{})
Fabian Seidl
committed
if err := s.eventService.PublishEvent(NetworkElementEventTopic, pubEvent); err != nil {
go func() {
s.eventService.Reconnect()
retryErr := s.eventService.RetryPublish(NetworkElementEventTopic, pubEvent)
if retryErr != nil {
log.Error(retryErr)
}
}()
}
return nil
}
// Delete deletes a network element from the network element store.
func (s *NetworkElementService) Delete(networkElementToDelete networkelement.NetworkElement) error {
err := s.networkElementStore.Delete(networkElementToDelete)
if err != nil {
return err
}
if networkElementToDelete.SBI().Type() == spb.Type_TYPE_PLUGIN {
err = s.sbiService.Delete(networkElementToDelete.SBI())
if err != nil {
return err
}
}
Fabian Seidl
committed
pubEvent := event.NewDeleteEvent(networkElementToDelete.ID())
if err := s.eventService.PublishEvent(NetworkElementEventTopic, pubEvent); err != nil {
go func() {
s.eventService.Reconnect()
retryErr := s.eventService.RetryPublish(NetworkElementEventTopic, pubEvent)
if retryErr != nil {
log.Error(retryErr)
}
}()
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
}
return nil
}
func (s *NetworkElementService) createNetworkElementFromStore(loadedNetworkElement networkelement.LoadedNetworkElement) (networkelement.NetworkElement, error) {
if loadedNetworkElement.SBI == "" {
return nil, fmt.Errorf("no sbi found for network element")
}
sbiForNetworkElement, err := s.sbiService.Get(store.Query{ID: uuid.MustParse(loadedNetworkElement.SBI)})
if err != nil {
return nil, err
}
mne, err := NewNetworkElement(
loadedNetworkElement.Name,
uuid.MustParse(loadedNetworkElement.ID),
&tpb.TransportOption{
Address: loadedNetworkElement.TransportAddress,
Username: loadedNetworkElement.TransportUsername,
Password: loadedNetworkElement.TransportPassword,
TransportOption: &tpb.TransportOption_GnmiTransportOption{
GnmiTransportOption: &tpb.GnmiTransportOption{},
},
Type: spb.Type_TYPE_OPENCONFIG,
},
sbiForNetworkElement,
loadedNetworkElement.Metadata,
)
if err != nil {
return nil, err
}
// Create 'root' path to be able to load the whole model from the store.
path, err := ygot.StringToPath("/", ygot.StructuredPath)
if err != nil {
return nil, err
}
// Use unmarshall from the network elements SBI to unmarshall ygot json in go struct.
err = mne.SBI().Unmarshal([]byte(loadedNetworkElement.Model), path, mne.GetModel())
if err != nil {
return nil, err
}
return mne, nil
}