blob: be5b589a65e4f7e074a262f6e1492dabc92d1894 [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"
William Kurkiandaa6bb22019-03-07 12:26:28 -050025 "github.com/opencord/voltha-protos/go/voltha"
khenaidoo21d51152019-02-01 13:48:37 -050026 "reflect"
27 "sync"
28)
29
30const (
khenaidoo1ce37ad2019-03-24 22:07:24 -040031 SENTINEL_ADAPTER_ID = "adapter_sentinel"
khenaidoo21d51152019-02-01 13:48:37 -050032 SENTINEL_DEVICETYPE_ID = "device_type_sentinel"
khenaidoo21d51152019-02-01 13:48:37 -050033)
34
35type AdapterAgent struct {
khenaidoo1ce37ad2019-03-24 22:07:24 -040036 adapter *voltha.Adapter
khenaidoo21d51152019-02-01 13:48:37 -050037 deviceTypes map[string]*voltha.DeviceType
khenaidoo1ce37ad2019-03-24 22:07:24 -040038 lock sync.RWMutex
khenaidoo21d51152019-02-01 13:48:37 -050039}
40
41func newAdapterAgent(adapter *voltha.Adapter, deviceTypes *voltha.DeviceTypes) *AdapterAgent {
42 var adapterAgent AdapterAgent
43 adapterAgent.adapter = adapter
44 adapterAgent.lock = sync.RWMutex{}
45 adapterAgent.deviceTypes = make(map[string]*voltha.DeviceType)
46 if deviceTypes != nil {
47 for _, dType := range deviceTypes.Items {
48 adapterAgent.deviceTypes[dType.Id] = dType
49 }
50 }
51 return &adapterAgent
52}
53
54// Returns true if this device agent can handle this device Type
55func (aa *AdapterAgent) handlesDeviceType(deviceType string) bool {
56 aa.lock.RLock()
57 defer aa.lock.RUnlock()
58 _, exist := aa.deviceTypes[deviceType]
59 return exist
60}
61
62func (aa *AdapterAgent) getDeviceType(deviceType string) *voltha.DeviceType {
63 aa.lock.RLock()
64 defer aa.lock.RUnlock()
65 if _, exist := aa.deviceTypes[deviceType]; exist {
66 return aa.deviceTypes[deviceType]
67 }
68 return nil
69}
70
71func (aa *AdapterAgent) getAdapter() *voltha.Adapter {
72 aa.lock.RLock()
73 defer aa.lock.RUnlock()
74 log.Debugw("getAdapter", log.Fields{"adapter": aa.adapter})
75 return aa.adapter
76}
77
78func (aa *AdapterAgent) updateAdapter(adapter *voltha.Adapter) {
khenaidoo1ce37ad2019-03-24 22:07:24 -040079 aa.lock.Lock()
80 defer aa.lock.Unlock()
khenaidoo21d51152019-02-01 13:48:37 -050081 aa.adapter = adapter
82}
83
khenaidoo1ce37ad2019-03-24 22:07:24 -040084func (aa *AdapterAgent) updateDeviceType(deviceType *voltha.DeviceType) {
85 aa.lock.Lock()
86 defer aa.lock.Unlock()
khenaidoo21d51152019-02-01 13:48:37 -050087 aa.deviceTypes[deviceType.Id] = deviceType
88}
89
90type AdapterManager struct {
91 adapterAgents map[string]*AdapterAgent
92 deviceTypeToAdapterMap map[string]string
93 clusterDataProxy *model.Proxy
94 adapterProxy *model.Proxy
95 deviceTypeProxy *model.Proxy
96 coreInstanceId string
97 exitChannel chan int
98 lockAdaptersMap sync.RWMutex
99 lockdDeviceTypeToAdapterMap sync.RWMutex
100}
101
102func newAdapterManager(cdProxy *model.Proxy, coreInstanceId string) *AdapterManager {
103 var adapterMgr AdapterManager
104 adapterMgr.exitChannel = make(chan int, 1)
105 adapterMgr.coreInstanceId = coreInstanceId
106 adapterMgr.clusterDataProxy = cdProxy
107 adapterMgr.adapterAgents = make(map[string]*AdapterAgent)
108 adapterMgr.deviceTypeToAdapterMap = make(map[string]string)
109 adapterMgr.lockAdaptersMap = sync.RWMutex{}
110 adapterMgr.lockdDeviceTypeToAdapterMap = sync.RWMutex{}
111 return &adapterMgr
112}
113
khenaidoo1ce37ad2019-03-24 22:07:24 -0400114func (aMgr *AdapterManager) start(ctx context.Context) {
khenaidoo21d51152019-02-01 13:48:37 -0500115 log.Info("starting-adapter-manager")
116
117 // Load the existing adapterAgents and device types - this will also ensure the correct paths have been
118 // created if there are no data in the dB to start
119 aMgr.loadAdaptersAndDevicetypesInMemory()
120
121 //// Create the proxies
122 aMgr.adapterProxy = aMgr.clusterDataProxy.Root.CreateProxy("/adapters", false)
123 aMgr.deviceTypeProxy = aMgr.clusterDataProxy.Root.CreateProxy("/device_types", false)
124
125 // Register the callbacks
126 aMgr.adapterProxy.RegisterCallback(model.POST_UPDATE, aMgr.adapterUpdated)
127 aMgr.deviceTypeProxy.RegisterCallback(model.POST_UPDATE, aMgr.deviceTypesUpdated)
128
129 log.Info("adapter-manager-started")
130}
131
132func (aMgr *AdapterManager) stop(ctx context.Context) {
133 log.Info("stopping-device-manager")
134 aMgr.exitChannel <- 1
135 log.Info("device-manager-stopped")
136}
137
138//loadAdaptersAndDevicetypesInMemory loads the existing set of adapters and device types in memory
139func (aMgr *AdapterManager) loadAdaptersAndDevicetypesInMemory() {
140 // Load the adapters
khenaidoo297cd252019-02-07 22:10:23 -0500141 if adaptersIf := aMgr.clusterDataProxy.List("/adapters", 0, false, ""); adaptersIf != nil {
khenaidoo21d51152019-02-01 13:48:37 -0500142 for _, adapterIf := range adaptersIf.([]interface{}) {
143 if adapter, ok := adapterIf.(*voltha.Adapter); ok {
144 log.Debugw("found-existing-adapter", log.Fields{"adapterId": adapter.Id})
145 aMgr.addAdapter(adapter, false)
146 }
147 }
148 } else {
149 log.Debug("no-existing-adapter-found")
150 // No adapter data. In order to have a proxy setup for that path let's create a fake adapter
151 aMgr.addAdapter(&voltha.Adapter{Id: SENTINEL_ADAPTER_ID}, true)
152 }
153
154 // Load the device types
khenaidoo297cd252019-02-07 22:10:23 -0500155 if deviceTypesIf := aMgr.clusterDataProxy.List("/device_types", 0, false, ""); deviceTypesIf != nil {
khenaidoo1ce37ad2019-03-24 22:07:24 -0400156 dTypes := &voltha.DeviceTypes{Items: []*voltha.DeviceType{}}
khenaidoo21d51152019-02-01 13:48:37 -0500157 for _, deviceTypeIf := range deviceTypesIf.([]interface{}) {
158 if dType, ok := deviceTypeIf.(*voltha.DeviceType); ok {
159 log.Debugw("found-existing-device-types", log.Fields{"deviceTypes": dTypes})
160 dTypes.Items = append(dTypes.Items, dType)
161 }
162 }
163 aMgr.addDeviceTypes(dTypes, false)
164 } else {
165 log.Debug("no-existing-device-type-found")
166 // No device types data. In order to have a proxy setup for that path let's create a fake device type
khenaidoo1ce37ad2019-03-24 22:07:24 -0400167 aMgr.addDeviceTypes(&voltha.DeviceTypes{Items: []*voltha.DeviceType{&voltha.DeviceType{Id: SENTINEL_DEVICETYPE_ID, Adapter: SENTINEL_ADAPTER_ID}}}, true)
khenaidoo21d51152019-02-01 13:48:37 -0500168 }
169}
170
khenaidoo297cd252019-02-07 22:10:23 -0500171//updateAdaptersAndDevicetypesInMemory loads the existing set of adapters and device types in memory
172func (aMgr *AdapterManager) updateAdaptersAndDevicetypesInMemory() {
173 // Update the adapters
174 if adaptersIf := aMgr.clusterDataProxy.List("/adapters", 0, false, ""); adaptersIf != nil {
175 for _, adapterIf := range adaptersIf.([]interface{}) {
176 if adapter, ok := adapterIf.(*voltha.Adapter); ok {
177 log.Debugw("found-existing-adapter", log.Fields{"adapterId": adapter.Id})
178 aMgr.updateAdapter(adapter)
179 }
180 }
181 }
182 // Update the device types
183 if deviceTypesIf := aMgr.clusterDataProxy.List("/device_types", 0, false, ""); deviceTypesIf != nil {
184 dTypes := &voltha.DeviceTypes{Items: []*voltha.DeviceType{}}
185 for _, deviceTypeIf := range deviceTypesIf.([]interface{}) {
186 if dType, ok := deviceTypeIf.(*voltha.DeviceType); ok {
187 log.Debugw("found-existing-device-types", log.Fields{"deviceTypes": dTypes})
188 aMgr.updateDeviceType(dType)
189 }
190 }
191 }
192}
193
khenaidoo21d51152019-02-01 13:48:37 -0500194func (aMgr *AdapterManager) addAdapter(adapter *voltha.Adapter, saveToDb bool) {
195 aMgr.lockAdaptersMap.Lock()
196 defer aMgr.lockAdaptersMap.Unlock()
197 log.Debugw("adding-adapter", log.Fields{"adapter": adapter})
198 if _, exist := aMgr.adapterAgents[adapter.Id]; !exist {
199 clonedAdapter := (proto.Clone(adapter)).(*voltha.Adapter)
200 aMgr.adapterAgents[adapter.Id] = newAdapterAgent(clonedAdapter, nil)
201 if saveToDb {
202 // Save the adapter to the KV store - first check if it already exist
203 if kvAdapter := aMgr.clusterDataProxy.Get("/adapters/"+adapter.Id, 0, false, ""); kvAdapter == nil {
204 if added := aMgr.clusterDataProxy.AddWithID("/adapters", adapter.Id, clonedAdapter, ""); added == nil {
205 //TODO: Errors when saving to KV would require a separate go routine to be launched and try the saving again
206 log.Errorw("failed-to-save-adapter", log.Fields{"adapter": adapter})
207 } else {
208 log.Debugw("adapter-saved-to-KV-Store", log.Fields{"adapter": adapter})
209 }
210 }
211 }
212 }
213}
214
khenaidoo21d51152019-02-01 13:48:37 -0500215func (aMgr *AdapterManager) addDeviceTypes(deviceTypes *voltha.DeviceTypes, saveToDb bool) {
216 if deviceTypes == nil {
217 return
218 }
219 log.Debugw("adding-device-types", log.Fields{"deviceTypes": deviceTypes})
220 aMgr.lockAdaptersMap.Lock()
221 defer aMgr.lockAdaptersMap.Unlock()
222 aMgr.lockdDeviceTypeToAdapterMap.Lock()
223 defer aMgr.lockdDeviceTypeToAdapterMap.Unlock()
224 for _, deviceType := range deviceTypes.Items {
225 clonedDType := (proto.Clone(deviceType)).(*voltha.DeviceType)
226 if adapterAgent, exist := aMgr.adapterAgents[clonedDType.Adapter]; exist {
227 adapterAgent.updateDeviceType(clonedDType)
228 } else {
229 log.Debugw("adapter-not-exist", log.Fields{"deviceTypes": deviceTypes, "adapterId": clonedDType.Adapter})
khenaidoo1ce37ad2019-03-24 22:07:24 -0400230 aMgr.adapterAgents[clonedDType.Adapter] = newAdapterAgent(&voltha.Adapter{Id: clonedDType.Adapter}, deviceTypes)
khenaidoo21d51152019-02-01 13:48:37 -0500231 }
232 aMgr.deviceTypeToAdapterMap[clonedDType.Id] = clonedDType.Adapter
233 }
234 if saveToDb {
235 // Save the device types to the KV store as well
236 for _, deviceType := range deviceTypes.Items {
237 if dType := aMgr.clusterDataProxy.Get("/device_types/"+deviceType.Id, 0, false, ""); dType == nil {
238 // Does not exist - save it
239 clonedDType := (proto.Clone(deviceType)).(*voltha.DeviceType)
240 if added := aMgr.clusterDataProxy.AddWithID("/device_types", deviceType.Id, clonedDType, ""); added == nil {
241 log.Errorw("failed-to-save-deviceType", log.Fields{"deviceType": deviceType})
242 } else {
243 log.Debugw("device-type-saved-to-KV-Store", log.Fields{"deviceType": deviceType})
244 }
245 }
246 }
247 }
248}
249
250func (aMgr *AdapterManager) listAdapters(ctx context.Context) (*voltha.Adapters, error) {
khenaidoo1ce37ad2019-03-24 22:07:24 -0400251 result := &voltha.Adapters{Items: []*voltha.Adapter{}}
252 aMgr.lockAdaptersMap.RLock()
253 defer aMgr.lockAdaptersMap.RUnlock()
khenaidoo21d51152019-02-01 13:48:37 -0500254 for _, adapterAgent := range aMgr.adapterAgents {
255 if a := adapterAgent.getAdapter(); a != nil {
khenaidoo297cd252019-02-07 22:10:23 -0500256 if a.Id != SENTINEL_ADAPTER_ID { // don't report the sentinel
257 result.Items = append(result.Items, (proto.Clone(a)).(*voltha.Adapter))
258 }
khenaidoo21d51152019-02-01 13:48:37 -0500259 }
260 }
261 return result, nil
262}
263
264func (aMgr *AdapterManager) deleteAdapter(adapterId string) {
265 aMgr.lockAdaptersMap.Lock()
266 defer aMgr.lockAdaptersMap.Unlock()
267 delete(aMgr.adapterAgents, adapterId)
268}
269
270func (aMgr *AdapterManager) getAdapter(adapterId string) *voltha.Adapter {
khenaidoo1ce37ad2019-03-24 22:07:24 -0400271 aMgr.lockAdaptersMap.RLock()
272 defer aMgr.lockAdaptersMap.RUnlock()
khenaidoo21d51152019-02-01 13:48:37 -0500273 if adapterAgent, ok := aMgr.adapterAgents[adapterId]; ok {
274 return adapterAgent.getAdapter()
275 }
276 return nil
277}
278
279//updateAdapter updates an adapter if it exist. Otherwise, it creates it.
khenaidoo1ce37ad2019-03-24 22:07:24 -0400280func (aMgr *AdapterManager) updateAdapter(adapter *voltha.Adapter) {
khenaidoo21d51152019-02-01 13:48:37 -0500281 aMgr.lockAdaptersMap.Lock()
282 defer aMgr.lockAdaptersMap.Unlock()
283 if adapterAgent, ok := aMgr.adapterAgents[adapter.Id]; ok {
284 adapterAgent.updateAdapter(adapter)
285 } else {
286 aMgr.adapterAgents[adapter.Id] = newAdapterAgent(adapter, nil)
287 }
288}
289
290//updateDeviceType updates an adapter if it exist. Otherwise, it creates it.
khenaidoo1ce37ad2019-03-24 22:07:24 -0400291func (aMgr *AdapterManager) updateDeviceType(deviceType *voltha.DeviceType) {
khenaidoo21d51152019-02-01 13:48:37 -0500292 aMgr.lockAdaptersMap.Lock()
293 defer aMgr.lockAdaptersMap.Unlock()
294 aMgr.lockdDeviceTypeToAdapterMap.Lock()
295 defer aMgr.lockdDeviceTypeToAdapterMap.Unlock()
khenaidoo297cd252019-02-07 22:10:23 -0500296 if adapterAgent, exist := aMgr.adapterAgents[deviceType.Adapter]; exist {
khenaidoo21d51152019-02-01 13:48:37 -0500297 adapterAgent.updateDeviceType(deviceType)
298 } else {
299 aMgr.adapterAgents[deviceType.Adapter] = newAdapterAgent(&voltha.Adapter{Id: deviceType.Adapter},
khenaidoo1ce37ad2019-03-24 22:07:24 -0400300 &voltha.DeviceTypes{Items: []*voltha.DeviceType{deviceType}})
khenaidoo21d51152019-02-01 13:48:37 -0500301 }
302 aMgr.deviceTypeToAdapterMap[deviceType.Id] = deviceType.Adapter
303}
304
khenaidoo1ce37ad2019-03-24 22:07:24 -0400305func (aMgr *AdapterManager) registerAdapter(adapter *voltha.Adapter, deviceTypes *voltha.DeviceTypes) *voltha.CoreInstance {
khenaidoo21d51152019-02-01 13:48:37 -0500306 log.Debugw("registerAdapter", log.Fields{"adapter": adapter, "deviceTypes": deviceTypes.Items})
307
308 if aMgr.getAdapter(adapter.Id) != nil {
309 // Already registered
khenaidoo1ce37ad2019-03-24 22:07:24 -0400310 return &voltha.CoreInstance{InstanceId: aMgr.coreInstanceId}
khenaidoo21d51152019-02-01 13:48:37 -0500311 }
312 // Save the adapter and the device types
313 aMgr.addAdapter(adapter, true)
314 aMgr.addDeviceTypes(deviceTypes, true)
315
316 log.Debugw("adapter-registered", log.Fields{"adapter": adapter.Id})
317
khenaidoo1ce37ad2019-03-24 22:07:24 -0400318 return &voltha.CoreInstance{InstanceId: aMgr.coreInstanceId}
khenaidoo21d51152019-02-01 13:48:37 -0500319}
320
321//getAdapterName returns the name of the device adapter that service this device type
322func (aMgr *AdapterManager) getAdapterName(deviceType string) (string, error) {
323 aMgr.lockdDeviceTypeToAdapterMap.Lock()
324 defer aMgr.lockdDeviceTypeToAdapterMap.Unlock()
325 if adapterId, exist := aMgr.deviceTypeToAdapterMap[deviceType]; exist {
326 return adapterId, nil
327 }
328 return "", errors.New(fmt.Sprintf("Adapter-not-registered-for-device-type %s", deviceType))
329}
330
331// getDeviceType returns the device type proto definition given the name of the device type
khenaidoo1ce37ad2019-03-24 22:07:24 -0400332func (aMgr *AdapterManager) getDeviceType(deviceType string) *voltha.DeviceType {
khenaidoo21d51152019-02-01 13:48:37 -0500333 aMgr.lockdDeviceTypeToAdapterMap.Lock()
334 defer aMgr.lockdDeviceTypeToAdapterMap.Unlock()
335 if adapterId, exist := aMgr.deviceTypeToAdapterMap[deviceType]; exist {
336 if adapterAgent, _ := aMgr.adapterAgents[adapterId]; adapterAgent != nil {
337 return adapterAgent.getDeviceType(deviceType)
338 }
339 }
340 return nil
341}
342
343//adapterUpdated is a callback invoked when an adapter change has been noticed
344func (aMgr *AdapterManager) adapterUpdated(args ...interface{}) interface{} {
345 log.Debugw("updateAdapter-callback", log.Fields{"argsLen": len(args)})
346
347 var previousData *voltha.Adapters
348 var latestData *voltha.Adapters
349
350 var ok bool
351 if previousData, ok = args[0].(*voltha.Adapters); !ok {
352 log.Errorw("invalid-args", log.Fields{"args0": args[0]})
khenaidoo433f54a2019-02-05 14:02:57 -0500353 return nil
khenaidoo21d51152019-02-01 13:48:37 -0500354 }
355 if latestData, ok = args[1].(*voltha.Adapters); !ok {
356 log.Errorw("invalid-args", log.Fields{"args1": args[1]})
khenaidoo21d51152019-02-01 13:48:37 -0500357 return nil
358 }
359
khenaidoo433f54a2019-02-05 14:02:57 -0500360 if previousData != nil && latestData != nil {
361 if reflect.DeepEqual(previousData.Items, latestData.Items) {
362 log.Debug("update-not-required")
363 return nil
364 }
khenaidoo21d51152019-02-01 13:48:37 -0500365 }
khenaidoo433f54a2019-02-05 14:02:57 -0500366
367 if latestData != nil {
368 for _, adapter := range latestData.Items {
369 aMgr.updateAdapter(adapter)
370 }
371 }
372
khenaidoo21d51152019-02-01 13:48:37 -0500373 return nil
374}
375
376//deviceTypesUpdated is a callback invoked when a device type change has been noticed
377func (aMgr *AdapterManager) deviceTypesUpdated(args ...interface{}) interface{} {
378 log.Debugw("deviceTypesUpdated-callback", log.Fields{"argsLen": len(args)})
379
380 var previousData *voltha.DeviceTypes
381 var latestData *voltha.DeviceTypes
382
383 var ok bool
384 if previousData, ok = args[0].(*voltha.DeviceTypes); !ok {
385 log.Errorw("invalid-args", log.Fields{"args0": args[0]})
khenaidoo21d51152019-02-01 13:48:37 -0500386 return nil
387 }
388
khenaidoo433f54a2019-02-05 14:02:57 -0500389 if latestData, ok = args[1].(*voltha.DeviceTypes); !ok {
390 log.Errorw("invalid-args", log.Fields{"args1": args[1]})
391 return nil
392 }
393
394 if previousData != nil && latestData != nil {
395 if reflect.DeepEqual(previousData.Items, latestData.Items) {
396 log.Debug("update-not-required")
397 return nil
398 }
399 }
400
401 if latestData != nil {
402 for _, dType := range latestData.Items {
403 aMgr.updateDeviceType(dType)
404 }
khenaidoo21d51152019-02-01 13:48:37 -0500405 }
406 return nil
khenaidoo1ce37ad2019-03-24 22:07:24 -0400407}