blob: c0ec1e9fbc9ea0e8b7428808de47d692e9269964 [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
142 if adaptersIf := aMgr.clusterDataProxy.Get("/adapters", 0, false, ""); adaptersIf != nil {
143 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
156 if deviceTypesIf := aMgr.clusterDataProxy.Get("/device_types", 0, false, ""); deviceTypesIf != nil {
157 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
172func (aMgr *AdapterManager) addAdapter(adapter *voltha.Adapter, saveToDb bool) {
173 aMgr.lockAdaptersMap.Lock()
174 defer aMgr.lockAdaptersMap.Unlock()
175 log.Debugw("adding-adapter", log.Fields{"adapter": adapter})
176 if _, exist := aMgr.adapterAgents[adapter.Id]; !exist {
177 clonedAdapter := (proto.Clone(adapter)).(*voltha.Adapter)
178 aMgr.adapterAgents[adapter.Id] = newAdapterAgent(clonedAdapter, nil)
179 if saveToDb {
180 // Save the adapter to the KV store - first check if it already exist
181 if kvAdapter := aMgr.clusterDataProxy.Get("/adapters/"+adapter.Id, 0, false, ""); kvAdapter == nil {
182 if added := aMgr.clusterDataProxy.AddWithID("/adapters", adapter.Id, clonedAdapter, ""); added == nil {
183 //TODO: Errors when saving to KV would require a separate go routine to be launched and try the saving again
184 log.Errorw("failed-to-save-adapter", log.Fields{"adapter": adapter})
185 } else {
186 log.Debugw("adapter-saved-to-KV-Store", log.Fields{"adapter": adapter})
187 }
188 }
189 }
190 }
191}
192
193
194func (aMgr *AdapterManager) addDeviceTypes(deviceTypes *voltha.DeviceTypes, saveToDb bool) {
195 if deviceTypes == nil {
196 return
197 }
198 log.Debugw("adding-device-types", log.Fields{"deviceTypes": deviceTypes})
199 aMgr.lockAdaptersMap.Lock()
200 defer aMgr.lockAdaptersMap.Unlock()
201 aMgr.lockdDeviceTypeToAdapterMap.Lock()
202 defer aMgr.lockdDeviceTypeToAdapterMap.Unlock()
203 for _, deviceType := range deviceTypes.Items {
204 clonedDType := (proto.Clone(deviceType)).(*voltha.DeviceType)
205 if adapterAgent, exist := aMgr.adapterAgents[clonedDType.Adapter]; exist {
206 adapterAgent.updateDeviceType(clonedDType)
207 } else {
208 log.Debugw("adapter-not-exist", log.Fields{"deviceTypes": deviceTypes, "adapterId": clonedDType.Adapter})
209 aMgr.adapterAgents[clonedDType.Adapter] = newAdapterAgent(&voltha.Adapter{Id:clonedDType.Adapter}, deviceTypes)
210 }
211 aMgr.deviceTypeToAdapterMap[clonedDType.Id] = clonedDType.Adapter
212 }
213 if saveToDb {
214 // Save the device types to the KV store as well
215 for _, deviceType := range deviceTypes.Items {
216 if dType := aMgr.clusterDataProxy.Get("/device_types/"+deviceType.Id, 0, false, ""); dType == nil {
217 // Does not exist - save it
218 clonedDType := (proto.Clone(deviceType)).(*voltha.DeviceType)
219 if added := aMgr.clusterDataProxy.AddWithID("/device_types", deviceType.Id, clonedDType, ""); added == nil {
220 log.Errorw("failed-to-save-deviceType", log.Fields{"deviceType": deviceType})
221 } else {
222 log.Debugw("device-type-saved-to-KV-Store", log.Fields{"deviceType": deviceType})
223 }
224 }
225 }
226 }
227}
228
229func (aMgr *AdapterManager) listAdapters(ctx context.Context) (*voltha.Adapters, error) {
230 result := &voltha.Adapters{Items:[]*voltha.Adapter{}}
231 aMgr.lockAdaptersMap.Lock()
232 defer aMgr.lockAdaptersMap.Unlock()
233 for _, adapterAgent := range aMgr.adapterAgents {
234 if a := adapterAgent.getAdapter(); a != nil {
235 result.Items = append(result.Items, (proto.Clone(a)).(*voltha.Adapter))
236 }
237 }
238 return result, nil
239}
240
241func (aMgr *AdapterManager) deleteAdapter(adapterId string) {
242 aMgr.lockAdaptersMap.Lock()
243 defer aMgr.lockAdaptersMap.Unlock()
244 delete(aMgr.adapterAgents, adapterId)
245}
246
247func (aMgr *AdapterManager) getAdapter(adapterId string) *voltha.Adapter {
248 aMgr.lockAdaptersMap.Lock()
249 defer aMgr.lockAdaptersMap.Unlock()
250 if adapterAgent, ok := aMgr.adapterAgents[adapterId]; ok {
251 return adapterAgent.getAdapter()
252 }
253 return nil
254}
255
256//updateAdapter updates an adapter if it exist. Otherwise, it creates it.
257func (aMgr *AdapterManager) updateAdapter(adapter *voltha.Adapter) {
258 aMgr.lockAdaptersMap.Lock()
259 defer aMgr.lockAdaptersMap.Unlock()
260 if adapterAgent, ok := aMgr.adapterAgents[adapter.Id]; ok {
261 adapterAgent.updateAdapter(adapter)
262 } else {
263 aMgr.adapterAgents[adapter.Id] = newAdapterAgent(adapter, nil)
264 }
265}
266
267//updateDeviceType updates an adapter if it exist. Otherwise, it creates it.
268func (aMgr *AdapterManager) updateDeviceType(deviceType *voltha.DeviceType) {
269 aMgr.lockAdaptersMap.Lock()
270 defer aMgr.lockAdaptersMap.Unlock()
271 aMgr.lockdDeviceTypeToAdapterMap.Lock()
272 defer aMgr.lockdDeviceTypeToAdapterMap.Unlock()
273 if adapterAgent, exist := aMgr.adapterAgents[deviceType.Adapter]; !exist {
274 adapterAgent.updateDeviceType(deviceType)
275 } else {
276 aMgr.adapterAgents[deviceType.Adapter] = newAdapterAgent(&voltha.Adapter{Id: deviceType.Adapter},
277 &voltha.DeviceTypes{Items:[]*voltha.DeviceType{deviceType}})
278 }
279 aMgr.deviceTypeToAdapterMap[deviceType.Id] = deviceType.Adapter
280}
281
282func (aMgr *AdapterManager) registerAdapter(adapter *voltha.Adapter, deviceTypes *voltha.DeviceTypes) *voltha.CoreInstance {
283 log.Debugw("registerAdapter", log.Fields{"adapter": adapter, "deviceTypes": deviceTypes.Items})
284
285 if aMgr.getAdapter(adapter.Id) != nil {
286 // Already registered
287 return &voltha.CoreInstance{InstanceId:aMgr.coreInstanceId}
288 }
289 // Save the adapter and the device types
290 aMgr.addAdapter(adapter, true)
291 aMgr.addDeviceTypes(deviceTypes, true)
292
293 log.Debugw("adapter-registered", log.Fields{"adapter": adapter.Id})
294
295 return &voltha.CoreInstance{InstanceId:aMgr.coreInstanceId}
296}
297
298//getAdapterName returns the name of the device adapter that service this device type
299func (aMgr *AdapterManager) getAdapterName(deviceType string) (string, error) {
300 aMgr.lockdDeviceTypeToAdapterMap.Lock()
301 defer aMgr.lockdDeviceTypeToAdapterMap.Unlock()
302 if adapterId, exist := aMgr.deviceTypeToAdapterMap[deviceType]; exist {
303 return adapterId, nil
304 }
305 return "", errors.New(fmt.Sprintf("Adapter-not-registered-for-device-type %s", deviceType))
306}
307
308// getDeviceType returns the device type proto definition given the name of the device type
309func (aMgr *AdapterManager) getDeviceType(deviceType string) *voltha.DeviceType {
310 aMgr.lockdDeviceTypeToAdapterMap.Lock()
311 defer aMgr.lockdDeviceTypeToAdapterMap.Unlock()
312 if adapterId, exist := aMgr.deviceTypeToAdapterMap[deviceType]; exist {
313 if adapterAgent, _ := aMgr.adapterAgents[adapterId]; adapterAgent != nil {
314 return adapterAgent.getDeviceType(deviceType)
315 }
316 }
317 return nil
318}
319
320//adapterUpdated is a callback invoked when an adapter change has been noticed
321func (aMgr *AdapterManager) adapterUpdated(args ...interface{}) interface{} {
322 log.Debugw("updateAdapter-callback", log.Fields{"argsLen": len(args)})
323
324 var previousData *voltha.Adapters
325 var latestData *voltha.Adapters
326
327 var ok bool
328 if previousData, ok = args[0].(*voltha.Adapters); !ok {
329 log.Errorw("invalid-args", log.Fields{"args0": args[0]})
330 }
331 if latestData, ok = args[1].(*voltha.Adapters); !ok {
332 log.Errorw("invalid-args", log.Fields{"args1": args[1]})
333 }
334
335 if reflect.DeepEqual(previousData.Items, latestData.Items) {
336 log.Debug("update-not-required")
337 return nil
338 }
339
340 for _, adapter := range latestData.Items {
341 aMgr.updateAdapter(adapter)
342 }
343 return nil
344}
345
346//deviceTypesUpdated is a callback invoked when a device type change has been noticed
347func (aMgr *AdapterManager) deviceTypesUpdated(args ...interface{}) interface{} {
348 log.Debugw("deviceTypesUpdated-callback", log.Fields{"argsLen": len(args)})
349
350 var previousData *voltha.DeviceTypes
351 var latestData *voltha.DeviceTypes
352
353 var ok bool
354 if previousData, ok = args[0].(*voltha.DeviceTypes); !ok {
355 log.Errorw("invalid-args", log.Fields{"args0": args[0]})
356 }
357 if latestData, ok = args[1].(*voltha.DeviceTypes); !ok {
358 log.Errorw("invalid-args", log.Fields{"args1": args[1]})
359 }
360
361 if reflect.DeepEqual(previousData.Items, latestData.Items) {
362 log.Debug("update-not-required")
363 return nil
364 }
365
366 for _, dType := range latestData.Items {
367 aMgr.updateDeviceType(dType)
368 }
369 return nil
370}