blob: 188ae3d46512d61e311a0bea54cbef02db5fbe4a [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"
David K. Bainbridgeb4a9ab02019-09-20 15:12:16 -070024 "github.com/opencord/voltha-go/common/probe"
khenaidoo21d51152019-02-01 13:48:37 -050025 "github.com/opencord/voltha-go/db/model"
William Kurkiandaa6bb22019-03-07 12:26:28 -050026 "github.com/opencord/voltha-protos/go/voltha"
khenaidoo21d51152019-02-01 13:48:37 -050027 "reflect"
28 "sync"
29)
30
31const (
khenaidoo1ce37ad2019-03-24 22:07:24 -040032 SENTINEL_ADAPTER_ID = "adapter_sentinel"
khenaidoo21d51152019-02-01 13:48:37 -050033 SENTINEL_DEVICETYPE_ID = "device_type_sentinel"
khenaidoo21d51152019-02-01 13:48:37 -050034)
35
36type AdapterAgent struct {
khenaidoo1ce37ad2019-03-24 22:07:24 -040037 adapter *voltha.Adapter
khenaidoo21d51152019-02-01 13:48:37 -050038 deviceTypes map[string]*voltha.DeviceType
khenaidoo1ce37ad2019-03-24 22:07:24 -040039 lock sync.RWMutex
khenaidoo21d51152019-02-01 13:48:37 -050040}
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) {
khenaidoo1ce37ad2019-03-24 22:07:24 -040080 aa.lock.Lock()
81 defer aa.lock.Unlock()
khenaidoo21d51152019-02-01 13:48:37 -050082 aa.adapter = adapter
83}
84
khenaidoo1ce37ad2019-03-24 22:07:24 -040085func (aa *AdapterAgent) updateDeviceType(deviceType *voltha.DeviceType) {
86 aa.lock.Lock()
87 defer aa.lock.Unlock()
khenaidoo21d51152019-02-01 13:48:37 -050088 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
khenaidooba6b6c42019-08-02 09:11:56 -040097 deviceMgr *DeviceManager
khenaidoo21d51152019-02-01 13:48:37 -050098 coreInstanceId string
99 exitChannel chan int
100 lockAdaptersMap sync.RWMutex
101 lockdDeviceTypeToAdapterMap sync.RWMutex
102}
103
khenaidooba6b6c42019-08-02 09:11:56 -0400104func newAdapterManager(cdProxy *model.Proxy, coreInstanceId string, deviceMgr *DeviceManager) *AdapterManager {
khenaidoo21d51152019-02-01 13:48:37 -0500105 var adapterMgr AdapterManager
106 adapterMgr.exitChannel = make(chan int, 1)
107 adapterMgr.coreInstanceId = coreInstanceId
108 adapterMgr.clusterDataProxy = cdProxy
109 adapterMgr.adapterAgents = make(map[string]*AdapterAgent)
110 adapterMgr.deviceTypeToAdapterMap = make(map[string]string)
111 adapterMgr.lockAdaptersMap = sync.RWMutex{}
112 adapterMgr.lockdDeviceTypeToAdapterMap = sync.RWMutex{}
khenaidooba6b6c42019-08-02 09:11:56 -0400113 adapterMgr.deviceMgr = deviceMgr
khenaidoo21d51152019-02-01 13:48:37 -0500114 return &adapterMgr
115}
116
khenaidoo1ce37ad2019-03-24 22:07:24 -0400117func (aMgr *AdapterManager) start(ctx context.Context) {
khenaidoo21d51152019-02-01 13:48:37 -0500118 log.Info("starting-adapter-manager")
119
120 // Load the existing adapterAgents and device types - this will also ensure the correct paths have been
121 // created if there are no data in the dB to start
122 aMgr.loadAdaptersAndDevicetypesInMemory()
123
124 //// Create the proxies
Stephane Barbarieef6650d2019-07-18 12:15:09 -0400125 aMgr.adapterProxy = aMgr.clusterDataProxy.CreateProxy(context.Background(), "/adapters", false)
126 aMgr.deviceTypeProxy = aMgr.clusterDataProxy.CreateProxy(context.Background(), "/device_types", false)
khenaidoo21d51152019-02-01 13:48:37 -0500127
128 // Register the callbacks
129 aMgr.adapterProxy.RegisterCallback(model.POST_UPDATE, aMgr.adapterUpdated)
130 aMgr.deviceTypeProxy.RegisterCallback(model.POST_UPDATE, aMgr.deviceTypesUpdated)
David K. Bainbridgeb4a9ab02019-09-20 15:12:16 -0700131 probe.UpdateStatusFromContext(ctx, "adapter-manager", probe.ServiceStatusRunning)
khenaidoo21d51152019-02-01 13:48:37 -0500132 log.Info("adapter-manager-started")
133}
134
135func (aMgr *AdapterManager) stop(ctx context.Context) {
136 log.Info("stopping-device-manager")
137 aMgr.exitChannel <- 1
David K. Bainbridgeb4a9ab02019-09-20 15:12:16 -0700138 probe.UpdateStatusFromContext(ctx, "adapter-manager", probe.ServiceStatusStopped)
khenaidoo21d51152019-02-01 13:48:37 -0500139 log.Info("device-manager-stopped")
140}
141
142//loadAdaptersAndDevicetypesInMemory loads the existing set of adapters and device types in memory
143func (aMgr *AdapterManager) loadAdaptersAndDevicetypesInMemory() {
144 // Load the adapters
Stephane Barbarieef6650d2019-07-18 12:15:09 -0400145 if adaptersIf := aMgr.clusterDataProxy.List(context.Background(), "/adapters", 0, false, ""); adaptersIf != nil {
khenaidoo21d51152019-02-01 13:48:37 -0500146 for _, adapterIf := range adaptersIf.([]interface{}) {
147 if adapter, ok := adapterIf.(*voltha.Adapter); ok {
148 log.Debugw("found-existing-adapter", log.Fields{"adapterId": adapter.Id})
149 aMgr.addAdapter(adapter, false)
150 }
151 }
152 } else {
153 log.Debug("no-existing-adapter-found")
154 // No adapter data. In order to have a proxy setup for that path let's create a fake adapter
155 aMgr.addAdapter(&voltha.Adapter{Id: SENTINEL_ADAPTER_ID}, true)
156 }
157
158 // Load the device types
Stephane Barbarieef6650d2019-07-18 12:15:09 -0400159 if deviceTypesIf := aMgr.clusterDataProxy.List(context.Background(), "/device_types", 0, false, ""); deviceTypesIf != nil {
khenaidoo1ce37ad2019-03-24 22:07:24 -0400160 dTypes := &voltha.DeviceTypes{Items: []*voltha.DeviceType{}}
khenaidoo21d51152019-02-01 13:48:37 -0500161 for _, deviceTypeIf := range deviceTypesIf.([]interface{}) {
162 if dType, ok := deviceTypeIf.(*voltha.DeviceType); ok {
163 log.Debugw("found-existing-device-types", log.Fields{"deviceTypes": dTypes})
164 dTypes.Items = append(dTypes.Items, dType)
165 }
166 }
167 aMgr.addDeviceTypes(dTypes, false)
168 } else {
169 log.Debug("no-existing-device-type-found")
170 // 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 -0400171 aMgr.addDeviceTypes(&voltha.DeviceTypes{Items: []*voltha.DeviceType{{Id: SENTINEL_DEVICETYPE_ID, Adapter: SENTINEL_ADAPTER_ID}}}, true)
khenaidoo21d51152019-02-01 13:48:37 -0500172 }
173}
174
khenaidoo297cd252019-02-07 22:10:23 -0500175//updateAdaptersAndDevicetypesInMemory loads the existing set of adapters and device types in memory
khenaidooba6b6c42019-08-02 09:11:56 -0400176func (aMgr *AdapterManager) updateAdaptersAndDevicetypesInMemory(adapter *voltha.Adapter) {
177 if aMgr.getAdapter(adapter.Id) != nil {
178 // Already registered - Adapter may have restarted. Trigger the reconcile process for that adapter
179 go aMgr.deviceMgr.adapterRestarted(adapter)
180 return
181 }
182
khenaidoo297cd252019-02-07 22:10:23 -0500183 // Update the adapters
Stephane Barbarieef6650d2019-07-18 12:15:09 -0400184 if adaptersIf := aMgr.clusterDataProxy.List(context.Background(), "/adapters", 0, false, ""); adaptersIf != nil {
khenaidoo297cd252019-02-07 22:10:23 -0500185 for _, adapterIf := range adaptersIf.([]interface{}) {
186 if adapter, ok := adapterIf.(*voltha.Adapter); ok {
187 log.Debugw("found-existing-adapter", log.Fields{"adapterId": adapter.Id})
188 aMgr.updateAdapter(adapter)
189 }
190 }
191 }
192 // Update the device types
Stephane Barbarieef6650d2019-07-18 12:15:09 -0400193 if deviceTypesIf := aMgr.clusterDataProxy.List(context.Background(), "/device_types", 0, false, ""); deviceTypesIf != nil {
khenaidoo297cd252019-02-07 22:10:23 -0500194 dTypes := &voltha.DeviceTypes{Items: []*voltha.DeviceType{}}
195 for _, deviceTypeIf := range deviceTypesIf.([]interface{}) {
196 if dType, ok := deviceTypeIf.(*voltha.DeviceType); ok {
197 log.Debugw("found-existing-device-types", log.Fields{"deviceTypes": dTypes})
198 aMgr.updateDeviceType(dType)
199 }
200 }
201 }
202}
203
khenaidoo21d51152019-02-01 13:48:37 -0500204func (aMgr *AdapterManager) addAdapter(adapter *voltha.Adapter, saveToDb bool) {
205 aMgr.lockAdaptersMap.Lock()
206 defer aMgr.lockAdaptersMap.Unlock()
207 log.Debugw("adding-adapter", log.Fields{"adapter": adapter})
208 if _, exist := aMgr.adapterAgents[adapter.Id]; !exist {
209 clonedAdapter := (proto.Clone(adapter)).(*voltha.Adapter)
210 aMgr.adapterAgents[adapter.Id] = newAdapterAgent(clonedAdapter, nil)
211 if saveToDb {
212 // Save the adapter to the KV store - first check if it already exist
Stephane Barbarieef6650d2019-07-18 12:15:09 -0400213 if kvAdapter := aMgr.clusterDataProxy.Get(context.Background(), "/adapters/"+adapter.Id, 0, false, ""); kvAdapter == nil {
214 if added := aMgr.clusterDataProxy.AddWithID(context.Background(), "/adapters", adapter.Id, clonedAdapter, ""); added == nil {
khenaidoo21d51152019-02-01 13:48:37 -0500215 //TODO: Errors when saving to KV would require a separate go routine to be launched and try the saving again
216 log.Errorw("failed-to-save-adapter", log.Fields{"adapter": adapter})
217 } else {
218 log.Debugw("adapter-saved-to-KV-Store", log.Fields{"adapter": adapter})
219 }
220 }
221 }
222 }
223}
224
khenaidoo21d51152019-02-01 13:48:37 -0500225func (aMgr *AdapterManager) addDeviceTypes(deviceTypes *voltha.DeviceTypes, saveToDb bool) {
226 if deviceTypes == nil {
227 return
228 }
229 log.Debugw("adding-device-types", log.Fields{"deviceTypes": deviceTypes})
230 aMgr.lockAdaptersMap.Lock()
231 defer aMgr.lockAdaptersMap.Unlock()
232 aMgr.lockdDeviceTypeToAdapterMap.Lock()
233 defer aMgr.lockdDeviceTypeToAdapterMap.Unlock()
234 for _, deviceType := range deviceTypes.Items {
235 clonedDType := (proto.Clone(deviceType)).(*voltha.DeviceType)
236 if adapterAgent, exist := aMgr.adapterAgents[clonedDType.Adapter]; exist {
237 adapterAgent.updateDeviceType(clonedDType)
238 } else {
239 log.Debugw("adapter-not-exist", log.Fields{"deviceTypes": deviceTypes, "adapterId": clonedDType.Adapter})
khenaidoo1ce37ad2019-03-24 22:07:24 -0400240 aMgr.adapterAgents[clonedDType.Adapter] = newAdapterAgent(&voltha.Adapter{Id: clonedDType.Adapter}, deviceTypes)
khenaidoo21d51152019-02-01 13:48:37 -0500241 }
242 aMgr.deviceTypeToAdapterMap[clonedDType.Id] = clonedDType.Adapter
243 }
244 if saveToDb {
245 // Save the device types to the KV store as well
246 for _, deviceType := range deviceTypes.Items {
Stephane Barbarieef6650d2019-07-18 12:15:09 -0400247 if dType := aMgr.clusterDataProxy.Get(context.Background(), "/device_types/"+deviceType.Id, 0, false, ""); dType == nil {
khenaidoo21d51152019-02-01 13:48:37 -0500248 // Does not exist - save it
249 clonedDType := (proto.Clone(deviceType)).(*voltha.DeviceType)
Stephane Barbarieef6650d2019-07-18 12:15:09 -0400250 if added := aMgr.clusterDataProxy.AddWithID(context.Background(), "/device_types", deviceType.Id, clonedDType, ""); added == nil {
khenaidoo21d51152019-02-01 13:48:37 -0500251 log.Errorw("failed-to-save-deviceType", log.Fields{"deviceType": deviceType})
252 } else {
253 log.Debugw("device-type-saved-to-KV-Store", log.Fields{"deviceType": deviceType})
254 }
255 }
256 }
257 }
258}
259
260func (aMgr *AdapterManager) listAdapters(ctx context.Context) (*voltha.Adapters, error) {
khenaidoo1ce37ad2019-03-24 22:07:24 -0400261 result := &voltha.Adapters{Items: []*voltha.Adapter{}}
262 aMgr.lockAdaptersMap.RLock()
263 defer aMgr.lockAdaptersMap.RUnlock()
khenaidoo21d51152019-02-01 13:48:37 -0500264 for _, adapterAgent := range aMgr.adapterAgents {
265 if a := adapterAgent.getAdapter(); a != nil {
khenaidoo297cd252019-02-07 22:10:23 -0500266 if a.Id != SENTINEL_ADAPTER_ID { // don't report the sentinel
267 result.Items = append(result.Items, (proto.Clone(a)).(*voltha.Adapter))
268 }
khenaidoo21d51152019-02-01 13:48:37 -0500269 }
270 }
271 return result, nil
272}
273
274func (aMgr *AdapterManager) deleteAdapter(adapterId string) {
275 aMgr.lockAdaptersMap.Lock()
276 defer aMgr.lockAdaptersMap.Unlock()
277 delete(aMgr.adapterAgents, adapterId)
278}
279
280func (aMgr *AdapterManager) getAdapter(adapterId string) *voltha.Adapter {
khenaidoo1ce37ad2019-03-24 22:07:24 -0400281 aMgr.lockAdaptersMap.RLock()
282 defer aMgr.lockAdaptersMap.RUnlock()
khenaidoo21d51152019-02-01 13:48:37 -0500283 if adapterAgent, ok := aMgr.adapterAgents[adapterId]; ok {
284 return adapterAgent.getAdapter()
285 }
286 return nil
287}
288
289//updateAdapter updates an adapter if it exist. Otherwise, it creates it.
khenaidoo1ce37ad2019-03-24 22:07:24 -0400290func (aMgr *AdapterManager) updateAdapter(adapter *voltha.Adapter) {
khenaidoo21d51152019-02-01 13:48:37 -0500291 aMgr.lockAdaptersMap.Lock()
292 defer aMgr.lockAdaptersMap.Unlock()
293 if adapterAgent, ok := aMgr.adapterAgents[adapter.Id]; ok {
294 adapterAgent.updateAdapter(adapter)
295 } else {
296 aMgr.adapterAgents[adapter.Id] = newAdapterAgent(adapter, nil)
297 }
298}
299
300//updateDeviceType updates an adapter if it exist. Otherwise, it creates it.
khenaidoo1ce37ad2019-03-24 22:07:24 -0400301func (aMgr *AdapterManager) updateDeviceType(deviceType *voltha.DeviceType) {
khenaidoo21d51152019-02-01 13:48:37 -0500302 aMgr.lockAdaptersMap.Lock()
303 defer aMgr.lockAdaptersMap.Unlock()
304 aMgr.lockdDeviceTypeToAdapterMap.Lock()
305 defer aMgr.lockdDeviceTypeToAdapterMap.Unlock()
khenaidoo297cd252019-02-07 22:10:23 -0500306 if adapterAgent, exist := aMgr.adapterAgents[deviceType.Adapter]; exist {
khenaidoo21d51152019-02-01 13:48:37 -0500307 adapterAgent.updateDeviceType(deviceType)
308 } else {
309 aMgr.adapterAgents[deviceType.Adapter] = newAdapterAgent(&voltha.Adapter{Id: deviceType.Adapter},
khenaidoo1ce37ad2019-03-24 22:07:24 -0400310 &voltha.DeviceTypes{Items: []*voltha.DeviceType{deviceType}})
khenaidoo21d51152019-02-01 13:48:37 -0500311 }
312 aMgr.deviceTypeToAdapterMap[deviceType.Id] = deviceType.Adapter
313}
314
khenaidoo1ce37ad2019-03-24 22:07:24 -0400315func (aMgr *AdapterManager) registerAdapter(adapter *voltha.Adapter, deviceTypes *voltha.DeviceTypes) *voltha.CoreInstance {
khenaidoo21d51152019-02-01 13:48:37 -0500316 log.Debugw("registerAdapter", log.Fields{"adapter": adapter, "deviceTypes": deviceTypes.Items})
317
318 if aMgr.getAdapter(adapter.Id) != nil {
khenaidooba6b6c42019-08-02 09:11:56 -0400319 // Already registered - Adapter may have restarted. Trigger the reconcile process for that adapter
320 go aMgr.deviceMgr.adapterRestarted(adapter)
khenaidoo1ce37ad2019-03-24 22:07:24 -0400321 return &voltha.CoreInstance{InstanceId: aMgr.coreInstanceId}
khenaidoo21d51152019-02-01 13:48:37 -0500322 }
323 // Save the adapter and the device types
324 aMgr.addAdapter(adapter, true)
325 aMgr.addDeviceTypes(deviceTypes, true)
326
327 log.Debugw("adapter-registered", log.Fields{"adapter": adapter.Id})
328
khenaidoo1ce37ad2019-03-24 22:07:24 -0400329 return &voltha.CoreInstance{InstanceId: aMgr.coreInstanceId}
khenaidoo21d51152019-02-01 13:48:37 -0500330}
331
332//getAdapterName returns the name of the device adapter that service this device type
333func (aMgr *AdapterManager) getAdapterName(deviceType string) (string, error) {
334 aMgr.lockdDeviceTypeToAdapterMap.Lock()
335 defer aMgr.lockdDeviceTypeToAdapterMap.Unlock()
336 if adapterId, exist := aMgr.deviceTypeToAdapterMap[deviceType]; exist {
337 return adapterId, nil
338 }
339 return "", errors.New(fmt.Sprintf("Adapter-not-registered-for-device-type %s", deviceType))
340}
341
342// getDeviceType returns the device type proto definition given the name of the device type
khenaidoo1ce37ad2019-03-24 22:07:24 -0400343func (aMgr *AdapterManager) getDeviceType(deviceType string) *voltha.DeviceType {
khenaidoo21d51152019-02-01 13:48:37 -0500344 aMgr.lockdDeviceTypeToAdapterMap.Lock()
345 defer aMgr.lockdDeviceTypeToAdapterMap.Unlock()
346 if adapterId, exist := aMgr.deviceTypeToAdapterMap[deviceType]; exist {
347 if adapterAgent, _ := aMgr.adapterAgents[adapterId]; adapterAgent != nil {
348 return adapterAgent.getDeviceType(deviceType)
349 }
350 }
351 return nil
352}
353
354//adapterUpdated is a callback invoked when an adapter change has been noticed
355func (aMgr *AdapterManager) adapterUpdated(args ...interface{}) interface{} {
356 log.Debugw("updateAdapter-callback", log.Fields{"argsLen": len(args)})
357
358 var previousData *voltha.Adapters
359 var latestData *voltha.Adapters
360
361 var ok bool
362 if previousData, ok = args[0].(*voltha.Adapters); !ok {
363 log.Errorw("invalid-args", log.Fields{"args0": args[0]})
khenaidoo433f54a2019-02-05 14:02:57 -0500364 return nil
khenaidoo21d51152019-02-01 13:48:37 -0500365 }
366 if latestData, ok = args[1].(*voltha.Adapters); !ok {
367 log.Errorw("invalid-args", log.Fields{"args1": args[1]})
khenaidoo21d51152019-02-01 13:48:37 -0500368 return nil
369 }
370
khenaidoo433f54a2019-02-05 14:02:57 -0500371 if previousData != nil && latestData != nil {
372 if reflect.DeepEqual(previousData.Items, latestData.Items) {
373 log.Debug("update-not-required")
374 return nil
375 }
khenaidoo21d51152019-02-01 13:48:37 -0500376 }
khenaidoo433f54a2019-02-05 14:02:57 -0500377
378 if latestData != nil {
379 for _, adapter := range latestData.Items {
380 aMgr.updateAdapter(adapter)
381 }
382 }
383
khenaidoo21d51152019-02-01 13:48:37 -0500384 return nil
385}
386
387//deviceTypesUpdated is a callback invoked when a device type change has been noticed
388func (aMgr *AdapterManager) deviceTypesUpdated(args ...interface{}) interface{} {
389 log.Debugw("deviceTypesUpdated-callback", log.Fields{"argsLen": len(args)})
390
391 var previousData *voltha.DeviceTypes
392 var latestData *voltha.DeviceTypes
393
394 var ok bool
395 if previousData, ok = args[0].(*voltha.DeviceTypes); !ok {
396 log.Errorw("invalid-args", log.Fields{"args0": args[0]})
khenaidoo21d51152019-02-01 13:48:37 -0500397 return nil
398 }
399
khenaidoo433f54a2019-02-05 14:02:57 -0500400 if latestData, ok = args[1].(*voltha.DeviceTypes); !ok {
401 log.Errorw("invalid-args", log.Fields{"args1": args[1]})
402 return nil
403 }
404
405 if previousData != nil && latestData != nil {
406 if reflect.DeepEqual(previousData.Items, latestData.Items) {
407 log.Debug("update-not-required")
408 return nil
409 }
410 }
411
412 if latestData != nil {
413 for _, dType := range latestData.Items {
414 aMgr.updateDeviceType(dType)
415 }
khenaidoo21d51152019-02-01 13:48:37 -0500416 }
417 return nil
khenaidoo1ce37ad2019-03-24 22:07:24 -0400418}