blob: 0be4e1200d4c31cda8efaf1dbb0f0a55382864af [file] [log] [blame]
khenaidoo21d51152019-02-01 13:48:37 -05001/*
2 * Copyright 2019-present Open Networking Foundation
3
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7
8 * http://www.apache.org/licenses/LICENSE-2.0
9
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16package core
17
18import (
19 "context"
20 "errors"
21 "fmt"
22 "github.com/gogo/protobuf/proto"
23 "github.com/opencord/voltha-go/common/log"
24 "github.com/opencord/voltha-go/db/model"
25 "github.com/opencord/voltha-go/protos/voltha"
26 "reflect"
27 "sync"
28)
29
30const (
31 SENTINEL_ADAPTER_ID = "adapter_sentinel"
32 SENTINEL_DEVICETYPE_ID = "device_type_sentinel"
33
34)
35
36type AdapterAgent struct {
37 adapter *voltha.Adapter
38 deviceTypes map[string]*voltha.DeviceType
39 lock sync.RWMutex
40}
41
42func newAdapterAgent(adapter *voltha.Adapter, deviceTypes *voltha.DeviceTypes) *AdapterAgent {
43 var adapterAgent AdapterAgent
44 adapterAgent.adapter = adapter
45 adapterAgent.lock = sync.RWMutex{}
46 adapterAgent.deviceTypes = make(map[string]*voltha.DeviceType)
47 if deviceTypes != nil {
48 for _, dType := range deviceTypes.Items {
49 adapterAgent.deviceTypes[dType.Id] = dType
50 }
51 }
52 return &adapterAgent
53}
54
55// Returns true if this device agent can handle this device Type
56func (aa *AdapterAgent) handlesDeviceType(deviceType string) bool {
57 aa.lock.RLock()
58 defer aa.lock.RUnlock()
59 _, exist := aa.deviceTypes[deviceType]
60 return exist
61}
62
63func (aa *AdapterAgent) getDeviceType(deviceType string) *voltha.DeviceType {
64 aa.lock.RLock()
65 defer aa.lock.RUnlock()
66 if _, exist := aa.deviceTypes[deviceType]; exist {
67 return aa.deviceTypes[deviceType]
68 }
69 return nil
70}
71
72func (aa *AdapterAgent) getAdapter() *voltha.Adapter {
73 aa.lock.RLock()
74 defer aa.lock.RUnlock()
75 log.Debugw("getAdapter", log.Fields{"adapter": aa.adapter})
76 return aa.adapter
77}
78
79func (aa *AdapterAgent) updateAdapter(adapter *voltha.Adapter) {
80 aa.lock.RLock()
81 defer aa.lock.RUnlock()
82 aa.adapter = adapter
83}
84
85func (aa *AdapterAgent) updateDeviceType(deviceType *voltha.DeviceType) {
86 aa.lock.RLock()
87 defer aa.lock.RUnlock()
88 aa.deviceTypes[deviceType.Id] = deviceType
89}
90
91type AdapterManager struct {
92 adapterAgents map[string]*AdapterAgent
93 deviceTypeToAdapterMap map[string]string
94 clusterDataProxy *model.Proxy
95 adapterProxy *model.Proxy
96 deviceTypeProxy *model.Proxy
97 coreInstanceId string
98 exitChannel chan int
99 lockAdaptersMap sync.RWMutex
100 lockdDeviceTypeToAdapterMap sync.RWMutex
101}
102
103func newAdapterManager(cdProxy *model.Proxy, coreInstanceId string) *AdapterManager {
104 var adapterMgr AdapterManager
105 adapterMgr.exitChannel = make(chan int, 1)
106 adapterMgr.coreInstanceId = coreInstanceId
107 adapterMgr.clusterDataProxy = cdProxy
108 adapterMgr.adapterAgents = make(map[string]*AdapterAgent)
109 adapterMgr.deviceTypeToAdapterMap = make(map[string]string)
110 adapterMgr.lockAdaptersMap = sync.RWMutex{}
111 adapterMgr.lockdDeviceTypeToAdapterMap = sync.RWMutex{}
112 return &adapterMgr
113}
114
115func (aMgr *AdapterManager) start(ctx context.Context) {
116 log.Info("starting-adapter-manager")
117
118 // Load the existing adapterAgents and device types - this will also ensure the correct paths have been
119 // created if there are no data in the dB to start
120 aMgr.loadAdaptersAndDevicetypesInMemory()
121
122 //// Create the proxies
123 aMgr.adapterProxy = aMgr.clusterDataProxy.Root.CreateProxy("/adapters", false)
124 aMgr.deviceTypeProxy = aMgr.clusterDataProxy.Root.CreateProxy("/device_types", false)
125
126 // Register the callbacks
127 aMgr.adapterProxy.RegisterCallback(model.POST_UPDATE, aMgr.adapterUpdated)
128 aMgr.deviceTypeProxy.RegisterCallback(model.POST_UPDATE, aMgr.deviceTypesUpdated)
129
130 log.Info("adapter-manager-started")
131}
132
133func (aMgr *AdapterManager) stop(ctx context.Context) {
134 log.Info("stopping-device-manager")
135 aMgr.exitChannel <- 1
136 log.Info("device-manager-stopped")
137}
138
139//loadAdaptersAndDevicetypesInMemory loads the existing set of adapters and device types in memory
140func (aMgr *AdapterManager) loadAdaptersAndDevicetypesInMemory() {
141 // Load the adapters
khenaidoo297cd252019-02-07 22:10:23 -0500142 if adaptersIf := aMgr.clusterDataProxy.List("/adapters", 0, false, ""); adaptersIf != nil {
khenaidoo21d51152019-02-01 13:48:37 -0500143 for _, adapterIf := range adaptersIf.([]interface{}) {
144 if adapter, ok := adapterIf.(*voltha.Adapter); ok {
145 log.Debugw("found-existing-adapter", log.Fields{"adapterId": adapter.Id})
146 aMgr.addAdapter(adapter, false)
147 }
148 }
149 } else {
150 log.Debug("no-existing-adapter-found")
151 // No adapter data. In order to have a proxy setup for that path let's create a fake adapter
152 aMgr.addAdapter(&voltha.Adapter{Id: SENTINEL_ADAPTER_ID}, true)
153 }
154
155 // Load the device types
khenaidoo297cd252019-02-07 22:10:23 -0500156 if deviceTypesIf := aMgr.clusterDataProxy.List("/device_types", 0, false, ""); deviceTypesIf != nil {
khenaidoo21d51152019-02-01 13:48:37 -0500157 dTypes := &voltha.DeviceTypes{Items:[]*voltha.DeviceType{}}
158 for _, deviceTypeIf := range deviceTypesIf.([]interface{}) {
159 if dType, ok := deviceTypeIf.(*voltha.DeviceType); ok {
160 log.Debugw("found-existing-device-types", log.Fields{"deviceTypes": dTypes})
161 dTypes.Items = append(dTypes.Items, dType)
162 }
163 }
164 aMgr.addDeviceTypes(dTypes, false)
165 } else {
166 log.Debug("no-existing-device-type-found")
167 // No device types data. In order to have a proxy setup for that path let's create a fake device type
168 aMgr.addDeviceTypes(&voltha.DeviceTypes{Items:[]*voltha.DeviceType{&voltha.DeviceType{Id:SENTINEL_DEVICETYPE_ID, Adapter:SENTINEL_ADAPTER_ID}}}, true)
169 }
170}
171
khenaidoo297cd252019-02-07 22:10:23 -0500172
173//updateAdaptersAndDevicetypesInMemory loads the existing set of adapters and device types in memory
174func (aMgr *AdapterManager) updateAdaptersAndDevicetypesInMemory() {
175 // Update the adapters
176 if adaptersIf := aMgr.clusterDataProxy.List("/adapters", 0, false, ""); adaptersIf != nil {
177 for _, adapterIf := range adaptersIf.([]interface{}) {
178 if adapter, ok := adapterIf.(*voltha.Adapter); ok {
179 log.Debugw("found-existing-adapter", log.Fields{"adapterId": adapter.Id})
180 aMgr.updateAdapter(adapter)
181 }
182 }
183 }
184 // Update the device types
185 if deviceTypesIf := aMgr.clusterDataProxy.List("/device_types", 0, false, ""); deviceTypesIf != nil {
186 dTypes := &voltha.DeviceTypes{Items: []*voltha.DeviceType{}}
187 for _, deviceTypeIf := range deviceTypesIf.([]interface{}) {
188 if dType, ok := deviceTypeIf.(*voltha.DeviceType); ok {
189 log.Debugw("found-existing-device-types", log.Fields{"deviceTypes": dTypes})
190 aMgr.updateDeviceType(dType)
191 }
192 }
193 }
194}
195
196
khenaidoo21d51152019-02-01 13:48:37 -0500197func (aMgr *AdapterManager) addAdapter(adapter *voltha.Adapter, saveToDb bool) {
198 aMgr.lockAdaptersMap.Lock()
199 defer aMgr.lockAdaptersMap.Unlock()
200 log.Debugw("adding-adapter", log.Fields{"adapter": adapter})
201 if _, exist := aMgr.adapterAgents[adapter.Id]; !exist {
202 clonedAdapter := (proto.Clone(adapter)).(*voltha.Adapter)
203 aMgr.adapterAgents[adapter.Id] = newAdapterAgent(clonedAdapter, nil)
204 if saveToDb {
205 // Save the adapter to the KV store - first check if it already exist
206 if kvAdapter := aMgr.clusterDataProxy.Get("/adapters/"+adapter.Id, 0, false, ""); kvAdapter == nil {
207 if added := aMgr.clusterDataProxy.AddWithID("/adapters", adapter.Id, clonedAdapter, ""); added == nil {
208 //TODO: Errors when saving to KV would require a separate go routine to be launched and try the saving again
209 log.Errorw("failed-to-save-adapter", log.Fields{"adapter": adapter})
210 } else {
211 log.Debugw("adapter-saved-to-KV-Store", log.Fields{"adapter": adapter})
212 }
213 }
214 }
215 }
216}
217
218
219func (aMgr *AdapterManager) addDeviceTypes(deviceTypes *voltha.DeviceTypes, saveToDb bool) {
220 if deviceTypes == nil {
221 return
222 }
223 log.Debugw("adding-device-types", log.Fields{"deviceTypes": deviceTypes})
224 aMgr.lockAdaptersMap.Lock()
225 defer aMgr.lockAdaptersMap.Unlock()
226 aMgr.lockdDeviceTypeToAdapterMap.Lock()
227 defer aMgr.lockdDeviceTypeToAdapterMap.Unlock()
228 for _, deviceType := range deviceTypes.Items {
229 clonedDType := (proto.Clone(deviceType)).(*voltha.DeviceType)
230 if adapterAgent, exist := aMgr.adapterAgents[clonedDType.Adapter]; exist {
231 adapterAgent.updateDeviceType(clonedDType)
232 } else {
233 log.Debugw("adapter-not-exist", log.Fields{"deviceTypes": deviceTypes, "adapterId": clonedDType.Adapter})
234 aMgr.adapterAgents[clonedDType.Adapter] = newAdapterAgent(&voltha.Adapter{Id:clonedDType.Adapter}, deviceTypes)
235 }
236 aMgr.deviceTypeToAdapterMap[clonedDType.Id] = clonedDType.Adapter
237 }
238 if saveToDb {
239 // Save the device types to the KV store as well
240 for _, deviceType := range deviceTypes.Items {
241 if dType := aMgr.clusterDataProxy.Get("/device_types/"+deviceType.Id, 0, false, ""); dType == nil {
242 // Does not exist - save it
243 clonedDType := (proto.Clone(deviceType)).(*voltha.DeviceType)
244 if added := aMgr.clusterDataProxy.AddWithID("/device_types", deviceType.Id, clonedDType, ""); added == nil {
245 log.Errorw("failed-to-save-deviceType", log.Fields{"deviceType": deviceType})
246 } else {
247 log.Debugw("device-type-saved-to-KV-Store", log.Fields{"deviceType": deviceType})
248 }
249 }
250 }
251 }
252}
253
254func (aMgr *AdapterManager) listAdapters(ctx context.Context) (*voltha.Adapters, error) {
255 result := &voltha.Adapters{Items:[]*voltha.Adapter{}}
256 aMgr.lockAdaptersMap.Lock()
257 defer aMgr.lockAdaptersMap.Unlock()
258 for _, adapterAgent := range aMgr.adapterAgents {
259 if a := adapterAgent.getAdapter(); a != nil {
khenaidoo297cd252019-02-07 22:10:23 -0500260 if a.Id != SENTINEL_ADAPTER_ID { // don't report the sentinel
261 result.Items = append(result.Items, (proto.Clone(a)).(*voltha.Adapter))
262 }
khenaidoo21d51152019-02-01 13:48:37 -0500263 }
264 }
265 return result, nil
266}
267
268func (aMgr *AdapterManager) deleteAdapter(adapterId string) {
269 aMgr.lockAdaptersMap.Lock()
270 defer aMgr.lockAdaptersMap.Unlock()
271 delete(aMgr.adapterAgents, adapterId)
272}
273
274func (aMgr *AdapterManager) getAdapter(adapterId string) *voltha.Adapter {
275 aMgr.lockAdaptersMap.Lock()
276 defer aMgr.lockAdaptersMap.Unlock()
277 if adapterAgent, ok := aMgr.adapterAgents[adapterId]; ok {
278 return adapterAgent.getAdapter()
279 }
280 return nil
281}
282
283//updateAdapter updates an adapter if it exist. Otherwise, it creates it.
284func (aMgr *AdapterManager) updateAdapter(adapter *voltha.Adapter) {
285 aMgr.lockAdaptersMap.Lock()
286 defer aMgr.lockAdaptersMap.Unlock()
287 if adapterAgent, ok := aMgr.adapterAgents[adapter.Id]; ok {
288 adapterAgent.updateAdapter(adapter)
289 } else {
290 aMgr.adapterAgents[adapter.Id] = newAdapterAgent(adapter, nil)
291 }
292}
293
294//updateDeviceType updates an adapter if it exist. Otherwise, it creates it.
295func (aMgr *AdapterManager) updateDeviceType(deviceType *voltha.DeviceType) {
296 aMgr.lockAdaptersMap.Lock()
297 defer aMgr.lockAdaptersMap.Unlock()
298 aMgr.lockdDeviceTypeToAdapterMap.Lock()
299 defer aMgr.lockdDeviceTypeToAdapterMap.Unlock()
khenaidoo297cd252019-02-07 22:10:23 -0500300 if adapterAgent, exist := aMgr.adapterAgents[deviceType.Adapter]; exist {
khenaidoo21d51152019-02-01 13:48:37 -0500301 adapterAgent.updateDeviceType(deviceType)
302 } else {
303 aMgr.adapterAgents[deviceType.Adapter] = newAdapterAgent(&voltha.Adapter{Id: deviceType.Adapter},
304 &voltha.DeviceTypes{Items:[]*voltha.DeviceType{deviceType}})
305 }
306 aMgr.deviceTypeToAdapterMap[deviceType.Id] = deviceType.Adapter
307}
308
309func (aMgr *AdapterManager) registerAdapter(adapter *voltha.Adapter, deviceTypes *voltha.DeviceTypes) *voltha.CoreInstance {
310 log.Debugw("registerAdapter", log.Fields{"adapter": adapter, "deviceTypes": deviceTypes.Items})
311
312 if aMgr.getAdapter(adapter.Id) != nil {
313 // Already registered
314 return &voltha.CoreInstance{InstanceId:aMgr.coreInstanceId}
315 }
316 // Save the adapter and the device types
317 aMgr.addAdapter(adapter, true)
318 aMgr.addDeviceTypes(deviceTypes, true)
319
320 log.Debugw("adapter-registered", log.Fields{"adapter": adapter.Id})
321
322 return &voltha.CoreInstance{InstanceId:aMgr.coreInstanceId}
323}
324
325//getAdapterName returns the name of the device adapter that service this device type
326func (aMgr *AdapterManager) getAdapterName(deviceType string) (string, error) {
327 aMgr.lockdDeviceTypeToAdapterMap.Lock()
328 defer aMgr.lockdDeviceTypeToAdapterMap.Unlock()
329 if adapterId, exist := aMgr.deviceTypeToAdapterMap[deviceType]; exist {
330 return adapterId, nil
331 }
332 return "", errors.New(fmt.Sprintf("Adapter-not-registered-for-device-type %s", deviceType))
333}
334
335// getDeviceType returns the device type proto definition given the name of the device type
336func (aMgr *AdapterManager) getDeviceType(deviceType string) *voltha.DeviceType {
337 aMgr.lockdDeviceTypeToAdapterMap.Lock()
338 defer aMgr.lockdDeviceTypeToAdapterMap.Unlock()
339 if adapterId, exist := aMgr.deviceTypeToAdapterMap[deviceType]; exist {
340 if adapterAgent, _ := aMgr.adapterAgents[adapterId]; adapterAgent != nil {
341 return adapterAgent.getDeviceType(deviceType)
342 }
343 }
344 return nil
345}
346
347//adapterUpdated is a callback invoked when an adapter change has been noticed
348func (aMgr *AdapterManager) adapterUpdated(args ...interface{}) interface{} {
349 log.Debugw("updateAdapter-callback", log.Fields{"argsLen": len(args)})
350
351 var previousData *voltha.Adapters
352 var latestData *voltha.Adapters
353
354 var ok bool
355 if previousData, ok = args[0].(*voltha.Adapters); !ok {
356 log.Errorw("invalid-args", log.Fields{"args0": args[0]})
khenaidoo433f54a2019-02-05 14:02:57 -0500357 return nil
khenaidoo21d51152019-02-01 13:48:37 -0500358 }
359 if latestData, ok = args[1].(*voltha.Adapters); !ok {
360 log.Errorw("invalid-args", log.Fields{"args1": args[1]})
khenaidoo21d51152019-02-01 13:48:37 -0500361 return nil
362 }
363
khenaidoo433f54a2019-02-05 14:02:57 -0500364 if previousData != nil && latestData != nil {
365 if reflect.DeepEqual(previousData.Items, latestData.Items) {
366 log.Debug("update-not-required")
367 return nil
368 }
khenaidoo21d51152019-02-01 13:48:37 -0500369 }
khenaidoo433f54a2019-02-05 14:02:57 -0500370
371 if latestData != nil {
372 for _, adapter := range latestData.Items {
373 aMgr.updateAdapter(adapter)
374 }
375 }
376
khenaidoo21d51152019-02-01 13:48:37 -0500377 return nil
378}
379
380//deviceTypesUpdated is a callback invoked when a device type change has been noticed
381func (aMgr *AdapterManager) deviceTypesUpdated(args ...interface{}) interface{} {
382 log.Debugw("deviceTypesUpdated-callback", log.Fields{"argsLen": len(args)})
383
384 var previousData *voltha.DeviceTypes
385 var latestData *voltha.DeviceTypes
386
387 var ok bool
388 if previousData, ok = args[0].(*voltha.DeviceTypes); !ok {
389 log.Errorw("invalid-args", log.Fields{"args0": args[0]})
khenaidoo21d51152019-02-01 13:48:37 -0500390 return nil
391 }
392
khenaidoo433f54a2019-02-05 14:02:57 -0500393 if latestData, ok = args[1].(*voltha.DeviceTypes); !ok {
394 log.Errorw("invalid-args", log.Fields{"args1": args[1]})
395 return nil
396 }
397
398 if previousData != nil && latestData != nil {
399 if reflect.DeepEqual(previousData.Items, latestData.Items) {
400 log.Debug("update-not-required")
401 return nil
402 }
403 }
404
405 if latestData != nil {
406 for _, dType := range latestData.Items {
407 aMgr.updateDeviceType(dType)
408 }
khenaidoo21d51152019-02-01 13:48:37 -0500409 }
410 return nil
411}