blob: 0ce1828aa39acf11add9e941d69e5dacb907163d [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
khenaidooba6b6c42019-08-02 09:11:56 -040096 deviceMgr *DeviceManager
khenaidoo21d51152019-02-01 13:48:37 -050097 coreInstanceId string
98 exitChannel chan int
99 lockAdaptersMap sync.RWMutex
100 lockdDeviceTypeToAdapterMap sync.RWMutex
101}
102
khenaidooba6b6c42019-08-02 09:11:56 -0400103func newAdapterManager(cdProxy *model.Proxy, coreInstanceId string, deviceMgr *DeviceManager) *AdapterManager {
khenaidoo21d51152019-02-01 13:48:37 -0500104 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{}
khenaidooba6b6c42019-08-02 09:11:56 -0400112 adapterMgr.deviceMgr = deviceMgr
khenaidoo21d51152019-02-01 13:48:37 -0500113 return &adapterMgr
114}
115
khenaidoo1ce37ad2019-03-24 22:07:24 -0400116func (aMgr *AdapterManager) start(ctx context.Context) {
khenaidoo21d51152019-02-01 13:48:37 -0500117 log.Info("starting-adapter-manager")
118
119 // Load the existing adapterAgents and device types - this will also ensure the correct paths have been
120 // created if there are no data in the dB to start
121 aMgr.loadAdaptersAndDevicetypesInMemory()
122
123 //// Create the proxies
Stephane Barbarieef6650d2019-07-18 12:15:09 -0400124 aMgr.adapterProxy = aMgr.clusterDataProxy.CreateProxy(context.Background(), "/adapters", false)
125 aMgr.deviceTypeProxy = aMgr.clusterDataProxy.CreateProxy(context.Background(), "/device_types", false)
khenaidoo21d51152019-02-01 13:48:37 -0500126
127 // Register the callbacks
128 aMgr.adapterProxy.RegisterCallback(model.POST_UPDATE, aMgr.adapterUpdated)
129 aMgr.deviceTypeProxy.RegisterCallback(model.POST_UPDATE, aMgr.deviceTypesUpdated)
130
131 log.Info("adapter-manager-started")
132}
133
134func (aMgr *AdapterManager) stop(ctx context.Context) {
135 log.Info("stopping-device-manager")
136 aMgr.exitChannel <- 1
137 log.Info("device-manager-stopped")
138}
139
140//loadAdaptersAndDevicetypesInMemory loads the existing set of adapters and device types in memory
141func (aMgr *AdapterManager) loadAdaptersAndDevicetypesInMemory() {
142 // Load the adapters
Stephane Barbarieef6650d2019-07-18 12:15:09 -0400143 if adaptersIf := aMgr.clusterDataProxy.List(context.Background(), "/adapters", 0, false, ""); adaptersIf != nil {
khenaidoo21d51152019-02-01 13:48:37 -0500144 for _, adapterIf := range adaptersIf.([]interface{}) {
145 if adapter, ok := adapterIf.(*voltha.Adapter); ok {
146 log.Debugw("found-existing-adapter", log.Fields{"adapterId": adapter.Id})
147 aMgr.addAdapter(adapter, false)
148 }
149 }
150 } else {
151 log.Debug("no-existing-adapter-found")
152 // No adapter data. In order to have a proxy setup for that path let's create a fake adapter
153 aMgr.addAdapter(&voltha.Adapter{Id: SENTINEL_ADAPTER_ID}, true)
154 }
155
156 // Load the device types
Stephane Barbarieef6650d2019-07-18 12:15:09 -0400157 if deviceTypesIf := aMgr.clusterDataProxy.List(context.Background(), "/device_types", 0, false, ""); deviceTypesIf != nil {
khenaidoo1ce37ad2019-03-24 22:07:24 -0400158 dTypes := &voltha.DeviceTypes{Items: []*voltha.DeviceType{}}
khenaidoo21d51152019-02-01 13:48:37 -0500159 for _, deviceTypeIf := range deviceTypesIf.([]interface{}) {
160 if dType, ok := deviceTypeIf.(*voltha.DeviceType); ok {
161 log.Debugw("found-existing-device-types", log.Fields{"deviceTypes": dTypes})
162 dTypes.Items = append(dTypes.Items, dType)
163 }
164 }
165 aMgr.addDeviceTypes(dTypes, false)
166 } else {
167 log.Debug("no-existing-device-type-found")
168 // No device types data. In order to have a proxy setup for that path let's create a fake device type
khenaidoo2c6a0992019-04-29 13:46:56 -0400169 aMgr.addDeviceTypes(&voltha.DeviceTypes{Items: []*voltha.DeviceType{{Id: SENTINEL_DEVICETYPE_ID, Adapter: SENTINEL_ADAPTER_ID}}}, true)
khenaidoo21d51152019-02-01 13:48:37 -0500170 }
171}
172
khenaidoo297cd252019-02-07 22:10:23 -0500173//updateAdaptersAndDevicetypesInMemory loads the existing set of adapters and device types in memory
khenaidooba6b6c42019-08-02 09:11:56 -0400174func (aMgr *AdapterManager) updateAdaptersAndDevicetypesInMemory(adapter *voltha.Adapter) {
175 if aMgr.getAdapter(adapter.Id) != nil {
176 // Already registered - Adapter may have restarted. Trigger the reconcile process for that adapter
177 go aMgr.deviceMgr.adapterRestarted(adapter)
178 return
179 }
180
khenaidoo297cd252019-02-07 22:10:23 -0500181 // Update the adapters
Stephane Barbarieef6650d2019-07-18 12:15:09 -0400182 if adaptersIf := aMgr.clusterDataProxy.List(context.Background(), "/adapters", 0, false, ""); adaptersIf != nil {
khenaidoo297cd252019-02-07 22:10:23 -0500183 for _, adapterIf := range adaptersIf.([]interface{}) {
184 if adapter, ok := adapterIf.(*voltha.Adapter); ok {
185 log.Debugw("found-existing-adapter", log.Fields{"adapterId": adapter.Id})
186 aMgr.updateAdapter(adapter)
187 }
188 }
189 }
190 // Update the device types
Stephane Barbarieef6650d2019-07-18 12:15:09 -0400191 if deviceTypesIf := aMgr.clusterDataProxy.List(context.Background(), "/device_types", 0, false, ""); deviceTypesIf != nil {
khenaidoo297cd252019-02-07 22:10:23 -0500192 dTypes := &voltha.DeviceTypes{Items: []*voltha.DeviceType{}}
193 for _, deviceTypeIf := range deviceTypesIf.([]interface{}) {
194 if dType, ok := deviceTypeIf.(*voltha.DeviceType); ok {
195 log.Debugw("found-existing-device-types", log.Fields{"deviceTypes": dTypes})
196 aMgr.updateDeviceType(dType)
197 }
198 }
199 }
200}
201
khenaidoo21d51152019-02-01 13:48:37 -0500202func (aMgr *AdapterManager) addAdapter(adapter *voltha.Adapter, saveToDb bool) {
203 aMgr.lockAdaptersMap.Lock()
204 defer aMgr.lockAdaptersMap.Unlock()
205 log.Debugw("adding-adapter", log.Fields{"adapter": adapter})
206 if _, exist := aMgr.adapterAgents[adapter.Id]; !exist {
207 clonedAdapter := (proto.Clone(adapter)).(*voltha.Adapter)
208 aMgr.adapterAgents[adapter.Id] = newAdapterAgent(clonedAdapter, nil)
209 if saveToDb {
210 // Save the adapter to the KV store - first check if it already exist
Stephane Barbarieef6650d2019-07-18 12:15:09 -0400211 if kvAdapter := aMgr.clusterDataProxy.Get(context.Background(), "/adapters/"+adapter.Id, 0, false, ""); kvAdapter == nil {
212 if added := aMgr.clusterDataProxy.AddWithID(context.Background(), "/adapters", adapter.Id, clonedAdapter, ""); added == nil {
khenaidoo21d51152019-02-01 13:48:37 -0500213 //TODO: Errors when saving to KV would require a separate go routine to be launched and try the saving again
214 log.Errorw("failed-to-save-adapter", log.Fields{"adapter": adapter})
215 } else {
216 log.Debugw("adapter-saved-to-KV-Store", log.Fields{"adapter": adapter})
217 }
218 }
219 }
220 }
221}
222
khenaidoo21d51152019-02-01 13:48:37 -0500223func (aMgr *AdapterManager) addDeviceTypes(deviceTypes *voltha.DeviceTypes, saveToDb bool) {
224 if deviceTypes == nil {
225 return
226 }
227 log.Debugw("adding-device-types", log.Fields{"deviceTypes": deviceTypes})
228 aMgr.lockAdaptersMap.Lock()
229 defer aMgr.lockAdaptersMap.Unlock()
230 aMgr.lockdDeviceTypeToAdapterMap.Lock()
231 defer aMgr.lockdDeviceTypeToAdapterMap.Unlock()
232 for _, deviceType := range deviceTypes.Items {
233 clonedDType := (proto.Clone(deviceType)).(*voltha.DeviceType)
234 if adapterAgent, exist := aMgr.adapterAgents[clonedDType.Adapter]; exist {
235 adapterAgent.updateDeviceType(clonedDType)
236 } else {
237 log.Debugw("adapter-not-exist", log.Fields{"deviceTypes": deviceTypes, "adapterId": clonedDType.Adapter})
khenaidoo1ce37ad2019-03-24 22:07:24 -0400238 aMgr.adapterAgents[clonedDType.Adapter] = newAdapterAgent(&voltha.Adapter{Id: clonedDType.Adapter}, deviceTypes)
khenaidoo21d51152019-02-01 13:48:37 -0500239 }
240 aMgr.deviceTypeToAdapterMap[clonedDType.Id] = clonedDType.Adapter
241 }
242 if saveToDb {
243 // Save the device types to the KV store as well
244 for _, deviceType := range deviceTypes.Items {
Stephane Barbarieef6650d2019-07-18 12:15:09 -0400245 if dType := aMgr.clusterDataProxy.Get(context.Background(), "/device_types/"+deviceType.Id, 0, false, ""); dType == nil {
khenaidoo21d51152019-02-01 13:48:37 -0500246 // Does not exist - save it
247 clonedDType := (proto.Clone(deviceType)).(*voltha.DeviceType)
Stephane Barbarieef6650d2019-07-18 12:15:09 -0400248 if added := aMgr.clusterDataProxy.AddWithID(context.Background(), "/device_types", deviceType.Id, clonedDType, ""); added == nil {
khenaidoo21d51152019-02-01 13:48:37 -0500249 log.Errorw("failed-to-save-deviceType", log.Fields{"deviceType": deviceType})
250 } else {
251 log.Debugw("device-type-saved-to-KV-Store", log.Fields{"deviceType": deviceType})
252 }
253 }
254 }
255 }
256}
257
258func (aMgr *AdapterManager) listAdapters(ctx context.Context) (*voltha.Adapters, error) {
khenaidoo1ce37ad2019-03-24 22:07:24 -0400259 result := &voltha.Adapters{Items: []*voltha.Adapter{}}
260 aMgr.lockAdaptersMap.RLock()
261 defer aMgr.lockAdaptersMap.RUnlock()
khenaidoo21d51152019-02-01 13:48:37 -0500262 for _, adapterAgent := range aMgr.adapterAgents {
263 if a := adapterAgent.getAdapter(); a != nil {
khenaidoo297cd252019-02-07 22:10:23 -0500264 if a.Id != SENTINEL_ADAPTER_ID { // don't report the sentinel
265 result.Items = append(result.Items, (proto.Clone(a)).(*voltha.Adapter))
266 }
khenaidoo21d51152019-02-01 13:48:37 -0500267 }
268 }
269 return result, nil
270}
271
272func (aMgr *AdapterManager) deleteAdapter(adapterId string) {
273 aMgr.lockAdaptersMap.Lock()
274 defer aMgr.lockAdaptersMap.Unlock()
275 delete(aMgr.adapterAgents, adapterId)
276}
277
278func (aMgr *AdapterManager) getAdapter(adapterId string) *voltha.Adapter {
khenaidoo1ce37ad2019-03-24 22:07:24 -0400279 aMgr.lockAdaptersMap.RLock()
280 defer aMgr.lockAdaptersMap.RUnlock()
khenaidoo21d51152019-02-01 13:48:37 -0500281 if adapterAgent, ok := aMgr.adapterAgents[adapterId]; ok {
282 return adapterAgent.getAdapter()
283 }
284 return nil
285}
286
287//updateAdapter updates an adapter if it exist. Otherwise, it creates it.
khenaidoo1ce37ad2019-03-24 22:07:24 -0400288func (aMgr *AdapterManager) updateAdapter(adapter *voltha.Adapter) {
khenaidoo21d51152019-02-01 13:48:37 -0500289 aMgr.lockAdaptersMap.Lock()
290 defer aMgr.lockAdaptersMap.Unlock()
291 if adapterAgent, ok := aMgr.adapterAgents[adapter.Id]; ok {
292 adapterAgent.updateAdapter(adapter)
293 } else {
294 aMgr.adapterAgents[adapter.Id] = newAdapterAgent(adapter, nil)
295 }
296}
297
298//updateDeviceType updates an adapter if it exist. Otherwise, it creates it.
khenaidoo1ce37ad2019-03-24 22:07:24 -0400299func (aMgr *AdapterManager) updateDeviceType(deviceType *voltha.DeviceType) {
khenaidoo21d51152019-02-01 13:48:37 -0500300 aMgr.lockAdaptersMap.Lock()
301 defer aMgr.lockAdaptersMap.Unlock()
302 aMgr.lockdDeviceTypeToAdapterMap.Lock()
303 defer aMgr.lockdDeviceTypeToAdapterMap.Unlock()
khenaidoo297cd252019-02-07 22:10:23 -0500304 if adapterAgent, exist := aMgr.adapterAgents[deviceType.Adapter]; exist {
khenaidoo21d51152019-02-01 13:48:37 -0500305 adapterAgent.updateDeviceType(deviceType)
306 } else {
307 aMgr.adapterAgents[deviceType.Adapter] = newAdapterAgent(&voltha.Adapter{Id: deviceType.Adapter},
khenaidoo1ce37ad2019-03-24 22:07:24 -0400308 &voltha.DeviceTypes{Items: []*voltha.DeviceType{deviceType}})
khenaidoo21d51152019-02-01 13:48:37 -0500309 }
310 aMgr.deviceTypeToAdapterMap[deviceType.Id] = deviceType.Adapter
311}
312
khenaidoo1ce37ad2019-03-24 22:07:24 -0400313func (aMgr *AdapterManager) registerAdapter(adapter *voltha.Adapter, deviceTypes *voltha.DeviceTypes) *voltha.CoreInstance {
khenaidoo21d51152019-02-01 13:48:37 -0500314 log.Debugw("registerAdapter", log.Fields{"adapter": adapter, "deviceTypes": deviceTypes.Items})
315
316 if aMgr.getAdapter(adapter.Id) != nil {
khenaidooba6b6c42019-08-02 09:11:56 -0400317 // Already registered - Adapter may have restarted. Trigger the reconcile process for that adapter
318 go aMgr.deviceMgr.adapterRestarted(adapter)
khenaidoo1ce37ad2019-03-24 22:07:24 -0400319 return &voltha.CoreInstance{InstanceId: aMgr.coreInstanceId}
khenaidoo21d51152019-02-01 13:48:37 -0500320 }
321 // Save the adapter and the device types
322 aMgr.addAdapter(adapter, true)
323 aMgr.addDeviceTypes(deviceTypes, true)
324
325 log.Debugw("adapter-registered", log.Fields{"adapter": adapter.Id})
326
khenaidoo1ce37ad2019-03-24 22:07:24 -0400327 return &voltha.CoreInstance{InstanceId: aMgr.coreInstanceId}
khenaidoo21d51152019-02-01 13:48:37 -0500328}
329
330//getAdapterName returns the name of the device adapter that service this device type
331func (aMgr *AdapterManager) getAdapterName(deviceType string) (string, error) {
332 aMgr.lockdDeviceTypeToAdapterMap.Lock()
333 defer aMgr.lockdDeviceTypeToAdapterMap.Unlock()
334 if adapterId, exist := aMgr.deviceTypeToAdapterMap[deviceType]; exist {
335 return adapterId, nil
336 }
337 return "", errors.New(fmt.Sprintf("Adapter-not-registered-for-device-type %s", deviceType))
338}
339
340// getDeviceType returns the device type proto definition given the name of the device type
khenaidoo1ce37ad2019-03-24 22:07:24 -0400341func (aMgr *AdapterManager) getDeviceType(deviceType string) *voltha.DeviceType {
khenaidoo21d51152019-02-01 13:48:37 -0500342 aMgr.lockdDeviceTypeToAdapterMap.Lock()
343 defer aMgr.lockdDeviceTypeToAdapterMap.Unlock()
344 if adapterId, exist := aMgr.deviceTypeToAdapterMap[deviceType]; exist {
345 if adapterAgent, _ := aMgr.adapterAgents[adapterId]; adapterAgent != nil {
346 return adapterAgent.getDeviceType(deviceType)
347 }
348 }
349 return nil
350}
351
352//adapterUpdated is a callback invoked when an adapter change has been noticed
353func (aMgr *AdapterManager) adapterUpdated(args ...interface{}) interface{} {
354 log.Debugw("updateAdapter-callback", log.Fields{"argsLen": len(args)})
355
356 var previousData *voltha.Adapters
357 var latestData *voltha.Adapters
358
359 var ok bool
360 if previousData, ok = args[0].(*voltha.Adapters); !ok {
361 log.Errorw("invalid-args", log.Fields{"args0": args[0]})
khenaidoo433f54a2019-02-05 14:02:57 -0500362 return nil
khenaidoo21d51152019-02-01 13:48:37 -0500363 }
364 if latestData, ok = args[1].(*voltha.Adapters); !ok {
365 log.Errorw("invalid-args", log.Fields{"args1": args[1]})
khenaidoo21d51152019-02-01 13:48:37 -0500366 return nil
367 }
368
khenaidoo433f54a2019-02-05 14:02:57 -0500369 if previousData != nil && latestData != nil {
370 if reflect.DeepEqual(previousData.Items, latestData.Items) {
371 log.Debug("update-not-required")
372 return nil
373 }
khenaidoo21d51152019-02-01 13:48:37 -0500374 }
khenaidoo433f54a2019-02-05 14:02:57 -0500375
376 if latestData != nil {
377 for _, adapter := range latestData.Items {
378 aMgr.updateAdapter(adapter)
379 }
380 }
381
khenaidoo21d51152019-02-01 13:48:37 -0500382 return nil
383}
384
385//deviceTypesUpdated is a callback invoked when a device type change has been noticed
386func (aMgr *AdapterManager) deviceTypesUpdated(args ...interface{}) interface{} {
387 log.Debugw("deviceTypesUpdated-callback", log.Fields{"argsLen": len(args)})
388
389 var previousData *voltha.DeviceTypes
390 var latestData *voltha.DeviceTypes
391
392 var ok bool
393 if previousData, ok = args[0].(*voltha.DeviceTypes); !ok {
394 log.Errorw("invalid-args", log.Fields{"args0": args[0]})
khenaidoo21d51152019-02-01 13:48:37 -0500395 return nil
396 }
397
khenaidoo433f54a2019-02-05 14:02:57 -0500398 if latestData, ok = args[1].(*voltha.DeviceTypes); !ok {
399 log.Errorw("invalid-args", log.Fields{"args1": args[1]})
400 return nil
401 }
402
403 if previousData != nil && latestData != nil {
404 if reflect.DeepEqual(previousData.Items, latestData.Items) {
405 log.Debug("update-not-required")
406 return nil
407 }
408 }
409
410 if latestData != nil {
411 for _, dType := range latestData.Items {
412 aMgr.updateDeviceType(dType)
413 }
khenaidoo21d51152019-02-01 13:48:37 -0500414 }
415 return nil
khenaidoo1ce37ad2019-03-24 22:07:24 -0400416}