blob: 88b0c7dd01082dca897607089f7cabaa88e1ff31 [file] [log] [blame]
khenaidoob9203542018-09-17 22:56:37 -04001/*
2 * Copyright 2018-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 "github.com/opencord/voltha-go/common/log"
22 "github.com/opencord/voltha-go/db/model"
23 "github.com/opencord/voltha-go/kafka"
khenaidoo79232702018-12-04 11:00:41 -050024 ic "github.com/opencord/voltha-go/protos/inter_container"
khenaidoo19d7b632018-10-30 10:49:50 -040025 ofp "github.com/opencord/voltha-go/protos/openflow_13"
khenaidoob9203542018-09-17 22:56:37 -040026 "github.com/opencord/voltha-go/protos/voltha"
27 "google.golang.org/grpc/codes"
28 "google.golang.org/grpc/status"
29 "reflect"
30 "runtime"
31 "sync"
32)
33
34type DeviceManager struct {
35 deviceAgents map[string]*DeviceAgent
36 adapterProxy *AdapterProxy
khenaidoo297cd252019-02-07 22:10:23 -050037 adapterMgr *AdapterManager
khenaidoob9203542018-09-17 22:56:37 -040038 logicalDeviceMgr *LogicalDeviceManager
khenaidoo43c82122018-11-22 18:38:28 -050039 kafkaICProxy *kafka.InterContainerProxy
khenaidoob9203542018-09-17 22:56:37 -040040 stateTransitions *TransitionMap
khenaidoo9a468962018-09-19 15:33:13 -040041 clusterDataProxy *model.Proxy
khenaidood2b6df92018-12-13 16:37:20 -050042 coreInstanceId string
khenaidoob9203542018-09-17 22:56:37 -040043 exitChannel chan int
44 lockDeviceAgentsMap sync.RWMutex
45}
46
khenaidoo21d51152019-02-01 13:48:37 -050047func newDeviceManager(kafkaICProxy *kafka.InterContainerProxy, cdProxy *model.Proxy, adapterMgr *AdapterManager, coreInstanceId string) *DeviceManager {
khenaidoob9203542018-09-17 22:56:37 -040048 var deviceMgr DeviceManager
49 deviceMgr.exitChannel = make(chan int, 1)
50 deviceMgr.deviceAgents = make(map[string]*DeviceAgent)
khenaidoo43c82122018-11-22 18:38:28 -050051 deviceMgr.adapterProxy = NewAdapterProxy(kafkaICProxy)
52 deviceMgr.kafkaICProxy = kafkaICProxy
khenaidoo19374072018-12-11 11:05:15 -050053 deviceMgr.coreInstanceId = coreInstanceId
khenaidoo9a468962018-09-19 15:33:13 -040054 deviceMgr.clusterDataProxy = cdProxy
khenaidoo297cd252019-02-07 22:10:23 -050055 deviceMgr.adapterMgr = adapterMgr
khenaidoob9203542018-09-17 22:56:37 -040056 deviceMgr.lockDeviceAgentsMap = sync.RWMutex{}
57 return &deviceMgr
58}
59
khenaidoo4d4802d2018-10-04 21:59:49 -040060func (dMgr *DeviceManager) start(ctx context.Context, logicalDeviceMgr *LogicalDeviceManager) {
khenaidoob9203542018-09-17 22:56:37 -040061 log.Info("starting-device-manager")
62 dMgr.logicalDeviceMgr = logicalDeviceMgr
63 dMgr.stateTransitions = NewTransitionMap(dMgr)
64 log.Info("device-manager-started")
65}
66
khenaidoo4d4802d2018-10-04 21:59:49 -040067func (dMgr *DeviceManager) stop(ctx context.Context) {
khenaidoob9203542018-09-17 22:56:37 -040068 log.Info("stopping-device-manager")
69 dMgr.exitChannel <- 1
70 log.Info("device-manager-stopped")
71}
72
73func sendResponse(ctx context.Context, ch chan interface{}, result interface{}) {
74 if ctx.Err() == nil {
75 // Returned response only of the ctx has not been cancelled/timeout/etc
76 // Channel is automatically closed when a context is Done
77 ch <- result
78 log.Debugw("sendResponse", log.Fields{"result": result})
79 } else {
80 // Should the transaction be reverted back?
81 log.Debugw("sendResponse-context-error", log.Fields{"context-error": ctx.Err()})
82 }
83}
84
85func (dMgr *DeviceManager) addDeviceAgentToMap(agent *DeviceAgent) {
86 dMgr.lockDeviceAgentsMap.Lock()
87 defer dMgr.lockDeviceAgentsMap.Unlock()
88 if _, exist := dMgr.deviceAgents[agent.deviceId]; !exist {
89 dMgr.deviceAgents[agent.deviceId] = agent
90 }
91}
92
khenaidoo4d4802d2018-10-04 21:59:49 -040093func (dMgr *DeviceManager) deleteDeviceAgentToMap(agent *DeviceAgent) {
94 dMgr.lockDeviceAgentsMap.Lock()
95 defer dMgr.lockDeviceAgentsMap.Unlock()
96 delete(dMgr.deviceAgents, agent.deviceId)
97}
98
khenaidoo297cd252019-02-07 22:10:23 -050099// getDeviceAgent returns the agent managing the device. If the device is not in memory, it will loads it, if it exists
khenaidoob9203542018-09-17 22:56:37 -0400100func (dMgr *DeviceManager) getDeviceAgent(deviceId string) *DeviceAgent {
101 dMgr.lockDeviceAgentsMap.Lock()
khenaidoob9203542018-09-17 22:56:37 -0400102 if agent, ok := dMgr.deviceAgents[deviceId]; ok {
khenaidoo297cd252019-02-07 22:10:23 -0500103 dMgr.lockDeviceAgentsMap.Unlock()
khenaidoob9203542018-09-17 22:56:37 -0400104 return agent
khenaidoo297cd252019-02-07 22:10:23 -0500105 } else {
106 // Try to load into memory - loading will also create the device agent
107 dMgr.lockDeviceAgentsMap.Unlock()
108 if err := dMgr.load(deviceId); err == nil {
109 dMgr.lockDeviceAgentsMap.Lock()
110 defer dMgr.lockDeviceAgentsMap.Unlock()
111 if agent, ok = dMgr.deviceAgents[deviceId]; ok {
112 return agent
113 }
114 }
khenaidoob9203542018-09-17 22:56:37 -0400115 }
116 return nil
117}
118
khenaidoo297cd252019-02-07 22:10:23 -0500119// listDeviceIdsFromMap returns the list of device IDs that are in memory
khenaidoo7ccedd52018-12-14 16:48:54 -0500120func (dMgr *DeviceManager) listDeviceIdsFromMap() *voltha.IDs {
121 dMgr.lockDeviceAgentsMap.Lock()
122 defer dMgr.lockDeviceAgentsMap.Unlock()
123 result := &voltha.IDs{Items: make([]*voltha.ID, 0)}
124 for key, _ := range dMgr.deviceAgents {
125 result.Items = append(result.Items, &voltha.ID{Id: key})
126 }
127 return result
128}
129
khenaidoob9203542018-09-17 22:56:37 -0400130func (dMgr *DeviceManager) createDevice(ctx context.Context, device *voltha.Device, ch chan interface{}) {
khenaidoo92e62c52018-10-03 14:02:54 -0400131 log.Debugw("createDevice", log.Fields{"device": device, "aproxy": dMgr.adapterProxy})
khenaidoob9203542018-09-17 22:56:37 -0400132
133 // Create and start a device agent for that device
khenaidoo9a468962018-09-19 15:33:13 -0400134 agent := newDeviceAgent(dMgr.adapterProxy, device, dMgr, dMgr.clusterDataProxy)
khenaidoob9203542018-09-17 22:56:37 -0400135 dMgr.addDeviceAgentToMap(agent)
khenaidoo297cd252019-02-07 22:10:23 -0500136 agent.start(ctx, false)
khenaidoob9203542018-09-17 22:56:37 -0400137
khenaidoo92e62c52018-10-03 14:02:54 -0400138 sendResponse(ctx, ch, agent.lastData)
khenaidoob9203542018-09-17 22:56:37 -0400139}
140
141func (dMgr *DeviceManager) enableDevice(ctx context.Context, id *voltha.ID, ch chan interface{}) {
khenaidoo92e62c52018-10-03 14:02:54 -0400142 log.Debugw("enableDevice", log.Fields{"deviceid": id})
khenaidoob9203542018-09-17 22:56:37 -0400143 var res interface{}
144 if agent := dMgr.getDeviceAgent(id.Id); agent != nil {
145 res = agent.enableDevice(ctx)
146 log.Debugw("EnableDevice-result", log.Fields{"result": res})
khenaidoob9203542018-09-17 22:56:37 -0400147 }
148
149 sendResponse(ctx, ch, res)
150}
151
khenaidoo92e62c52018-10-03 14:02:54 -0400152func (dMgr *DeviceManager) disableDevice(ctx context.Context, id *voltha.ID, ch chan interface{}) {
153 log.Debugw("disableDevice", log.Fields{"deviceid": id})
khenaidoo92e62c52018-10-03 14:02:54 -0400154 var res interface{}
155 if agent := dMgr.getDeviceAgent(id.Id); agent != nil {
156 res = agent.disableDevice(ctx)
157 log.Debugw("disableDevice-result", log.Fields{"result": res})
khenaidoob9203542018-09-17 22:56:37 -0400158 } else {
khenaidoo92e62c52018-10-03 14:02:54 -0400159 res = status.Errorf(codes.NotFound, "%s", id.Id)
khenaidoob9203542018-09-17 22:56:37 -0400160 }
khenaidoo92e62c52018-10-03 14:02:54 -0400161
162 sendResponse(ctx, ch, res)
163}
164
khenaidoo4d4802d2018-10-04 21:59:49 -0400165func (dMgr *DeviceManager) rebootDevice(ctx context.Context, id *voltha.ID, ch chan interface{}) {
166 log.Debugw("rebootDevice", log.Fields{"deviceid": id})
167 var res interface{}
168 if agent := dMgr.getDeviceAgent(id.Id); agent != nil {
169 res = agent.rebootDevice(ctx)
170 log.Debugw("rebootDevice-result", log.Fields{"result": res})
171 } else {
172 res = status.Errorf(codes.NotFound, "%s", id.Id)
173 }
174 sendResponse(ctx, ch, res)
175}
176
177func (dMgr *DeviceManager) deleteDevice(ctx context.Context, id *voltha.ID, ch chan interface{}) {
178 log.Debugw("deleteDevice", log.Fields{"deviceid": id})
179 var res interface{}
180 if agent := dMgr.getDeviceAgent(id.Id); agent != nil {
181 res = agent.deleteDevice(ctx)
182 if res == nil { //Success
183 agent.stop(ctx)
184 dMgr.deleteDeviceAgentToMap(agent)
185 }
186 log.Debugw("deleteDevice-result", log.Fields{"result": res})
187 } else {
188 res = status.Errorf(codes.NotFound, "%s", id.Id)
189 }
190 sendResponse(ctx, ch, res)
191}
192
khenaidoo297cd252019-02-07 22:10:23 -0500193// GetDevice will returns a device, either from memory or from the dB, if present
khenaidoo19d7b632018-10-30 10:49:50 -0400194func (dMgr *DeviceManager) GetDevice(id string) (*voltha.Device, error) {
195 log.Debugw("GetDevice", log.Fields{"deviceid": id})
khenaidoo92e62c52018-10-03 14:02:54 -0400196 if agent := dMgr.getDeviceAgent(id); agent != nil {
197 return agent.getDevice()
198 }
199 return nil, status.Errorf(codes.NotFound, "%s", id)
khenaidoob9203542018-09-17 22:56:37 -0400200}
201
khenaidoo297cd252019-02-07 22:10:23 -0500202func (dMgr *DeviceManager) IsDeviceInCache(id string) bool {
203 dMgr.lockDeviceAgentsMap.Lock()
204 defer dMgr.lockDeviceAgentsMap.Unlock()
205 _, exist := dMgr.deviceAgents[id]
206 return exist
207}
208
khenaidoo19d7b632018-10-30 10:49:50 -0400209func (dMgr *DeviceManager) IsRootDevice(id string) (bool, error) {
210 device, err := dMgr.GetDevice(id)
211 if err != nil {
212 return false, err
213 }
214 return device.Root, nil
215}
216
Stephane Barbarieaa467942019-02-06 14:09:44 -0500217// ListDevices retrieves the latest devices from the data model
khenaidoob9203542018-09-17 22:56:37 -0400218func (dMgr *DeviceManager) ListDevices() (*voltha.Devices, error) {
khenaidoo92e62c52018-10-03 14:02:54 -0400219 log.Debug("ListDevices")
khenaidoob9203542018-09-17 22:56:37 -0400220 result := &voltha.Devices{}
Stephane Barbarieaa467942019-02-06 14:09:44 -0500221 if devices := dMgr.clusterDataProxy.List("/devices", 0, false, ""); devices != nil {
Stephane Barbarie1ab43272018-12-08 21:42:13 -0500222 for _, device := range devices.([]interface{}) {
khenaidoo297cd252019-02-07 22:10:23 -0500223 // If device is not in memory then set it up
224 if !dMgr.IsDeviceInCache(device.(*voltha.Device).Id) {
225 agent := newDeviceAgent(dMgr.adapterProxy, device.(*voltha.Device), dMgr, dMgr.clusterDataProxy)
226 if err := agent.start(nil, true); err != nil {
227 log.Warnw("failure-starting-agent", log.Fields{"deviceId": device.(*voltha.Device).Id})
228 agent.stop(nil)
229 } else {
230 dMgr.addDeviceAgentToMap(agent)
231 }
Stephane Barbarie1ab43272018-12-08 21:42:13 -0500232 }
233 result.Items = append(result.Items, device.(*voltha.Device))
khenaidoob9203542018-09-17 22:56:37 -0400234 }
235 }
236 return result, nil
237}
238
khenaidoo297cd252019-02-07 22:10:23 -0500239// loadDevice loads the deviceId in memory, if not present
240func (dMgr *DeviceManager) loadDevice(deviceId string) (*DeviceAgent, error) {
241 log.Debugw("loading-device", log.Fields{"deviceId": deviceId})
242 // Sanity check
243 if deviceId == "" {
244 return nil, status.Error(codes.InvalidArgument, "deviceId empty")
245 }
246 if !dMgr.IsDeviceInCache(deviceId) {
247 agent := newDeviceAgent(dMgr.adapterProxy, &voltha.Device{Id: deviceId}, dMgr, dMgr.clusterDataProxy)
248 if err := agent.start(nil, true); err != nil {
249 agent.stop(nil)
250 return nil, err
251 }
252 dMgr.addDeviceAgentToMap(agent)
253 }
254 if agent := dMgr.getDeviceAgent(deviceId); agent != nil {
255 return agent, nil
256 }
257 return nil, status.Error(codes.NotFound, deviceId) // This should nto happen
258}
259
260// loadRootDeviceParentAndChildren loads the children and parents of a root device in memory
261func (dMgr *DeviceManager) loadRootDeviceParentAndChildren(device *voltha.Device) error {
262 log.Debugw("loading-parent-and-children", log.Fields{"deviceId": device.Id})
263 if device.Root {
264 // Scenario A
265 if device.ParentId != "" {
266 // Load logical device if needed.
267 if err := dMgr.logicalDeviceMgr.load(device.ParentId); err != nil {
268 log.Warnw("failure-loading-logical-device", log.Fields{"lDeviceId": device.ParentId})
269 }
270 } else {
271 log.Debugw("no-parent-to-load", log.Fields{"deviceId": device.Id})
272 }
273 // Load all child devices, if needed
274 if childDeviceIds, err := dMgr.getAllChildDeviceIds(device); err == nil {
275 for _, childDeviceId := range childDeviceIds {
276 if _, err := dMgr.loadDevice(childDeviceId); err != nil {
277 log.Warnw("failure-loading-device", log.Fields{"deviceId": childDeviceId})
278 return err
279 }
280 }
281 log.Debugw("loaded-children", log.Fields{"deviceId": device.Id, "numChildren": len(childDeviceIds)})
282 } else {
283 log.Debugw("no-child-to-load", log.Fields{"deviceId": device.Id})
284 }
285 }
286 return nil
287}
288
289// load loads the deviceId in memory, if not present, and also loads its accompanying parents and children. Loading
290// in memory is for improved performance. It is not imperative that a device needs to be in memory when a request
291// acting on the device is received by the core. In such a scenario, the Core will load the device in memory first
292// and the proceed with the request.
293func (dMgr *DeviceManager) load(deviceId string) error {
294 log.Debug("load...")
295 // First load the device - this may fail in case the device was deleted intentionally by the other core
296 var dAgent *DeviceAgent
297 var err error
298 if dAgent, err = dMgr.loadDevice(deviceId); err != nil {
299 log.Warnw("failure-loading-device", log.Fields{"deviceId": deviceId})
300 return err
301 }
302 // Get the loaded device details
303 var device *voltha.Device
304 if device, err = dAgent.getDevice(); err != nil {
305 return err
306 }
307
308 // If the device is in Pre-provisioning or deleted state stop here
309 if device.AdminState == voltha.AdminState_PREPROVISIONED || device.AdminState == voltha.AdminState_DELETED {
310 return nil
311 }
312
313 // Now we face two scenarios
314 if device.Root {
315 // Load all children as well as the parent of this device (logical_device)
316 if err := dMgr.loadRootDeviceParentAndChildren(device); err != nil {
317 log.Warnw("failure-loading-device-parent-and-children", log.Fields{"deviceId": deviceId})
318 return err
319 }
320 log.Debugw("successfully-loaded-parent-and-children", log.Fields{"deviceId": deviceId})
321 } else {
322 // Scenario B - use the parentId of that device (root device) to trigger the loading
323 if device.ParentId != "" {
324 return dMgr.load(device.ParentId)
325 }
326 }
327 return nil
328}
329
khenaidoo7ccedd52018-12-14 16:48:54 -0500330// ListDeviceIds retrieves the latest device IDs information from the data model (memory data only)
331func (dMgr *DeviceManager) ListDeviceIds() (*voltha.IDs, error) {
332 log.Debug("ListDeviceIDs")
333 // Report only device IDs that are in the device agent map
334 return dMgr.listDeviceIdsFromMap(), nil
335}
336
337//ReconcileDevices is a request to a voltha core to managed a list of devices based on their IDs
338func (dMgr *DeviceManager) ReconcileDevices(ctx context.Context, ids *voltha.IDs, ch chan interface{}) {
339 log.Debug("ReconcileDevices")
340 var res interface{}
341 if ids != nil {
342 toReconcile := len(ids.Items)
343 reconciled := 0
344 for _, id := range ids.Items {
345 // Act on the device only if its not present in the agent map
khenaidoo297cd252019-02-07 22:10:23 -0500346 if !dMgr.IsDeviceInCache(id.Id) {
khenaidoo7ccedd52018-12-14 16:48:54 -0500347 // Device Id not in memory
348 log.Debugw("reconciling-device", log.Fields{"id": id.Id})
khenaidoo297cd252019-02-07 22:10:23 -0500349 // Load device from dB
350 agent := newDeviceAgent(dMgr.adapterProxy, &voltha.Device{Id:id.Id}, dMgr, dMgr.clusterDataProxy)
351 if err := agent.start(nil, true); err != nil {
352 log.Warnw("failure-loading-device", log.Fields{"deviceId": id.Id})
353 agent.stop(nil)
khenaidoo7ccedd52018-12-14 16:48:54 -0500354 } else {
khenaidoo297cd252019-02-07 22:10:23 -0500355 dMgr.addDeviceAgentToMap(agent)
356 reconciled += 1
khenaidoo7ccedd52018-12-14 16:48:54 -0500357 }
358 } else {
359 reconciled += 1
360 }
361 }
362 if toReconcile != reconciled {
363 res = status.Errorf(codes.DataLoss, "less-device-reconciled:%d/%d", reconciled, toReconcile)
364 }
365 } else {
366 res = status.Errorf(codes.InvalidArgument, "empty-list-of-ids")
367 }
368 sendResponse(ctx, ch, res)
369}
Stephane Barbarie1ab43272018-12-08 21:42:13 -0500370
khenaidoob9203542018-09-17 22:56:37 -0400371func (dMgr *DeviceManager) updateDevice(device *voltha.Device) error {
khenaidoo92e62c52018-10-03 14:02:54 -0400372 log.Debugw("updateDevice", log.Fields{"deviceid": device.Id, "device": device})
khenaidoob9203542018-09-17 22:56:37 -0400373 if agent := dMgr.getDeviceAgent(device.Id); agent != nil {
374 return agent.updateDevice(device)
375 }
376 return status.Errorf(codes.NotFound, "%s", device.Id)
377}
378
379func (dMgr *DeviceManager) addPort(deviceId string, port *voltha.Port) error {
380 if agent := dMgr.getDeviceAgent(deviceId); agent != nil {
khenaidoo92e62c52018-10-03 14:02:54 -0400381 if err := agent.addPort(port); err != nil {
382 return err
383 }
384 // Setup peer ports
385 meAsPeer := &voltha.Port_PeerPort{DeviceId: deviceId, PortNo: port.PortNo}
386 for _, peerPort := range port.Peers {
387 if agent := dMgr.getDeviceAgent(peerPort.DeviceId); agent != nil {
388 if err := agent.addPeerPort(meAsPeer); err != nil {
389 log.Errorw("failed-to-add-peer", log.Fields{"peer-device-id": peerPort.DeviceId})
390 return err
391 }
392 }
393 }
394 return nil
395 } else {
396 return status.Errorf(codes.NotFound, "%s", deviceId)
khenaidoob9203542018-09-17 22:56:37 -0400397 }
khenaidoob9203542018-09-17 22:56:37 -0400398}
399
khenaidoo19d7b632018-10-30 10:49:50 -0400400func (dMgr *DeviceManager) updateFlows(deviceId string, flows []*ofp.OfpFlowStats) error {
401 log.Debugw("updateFlows", log.Fields{"deviceid": deviceId})
402 if agent := dMgr.getDeviceAgent(deviceId); agent != nil {
403 return agent.updateFlows(flows)
404 }
405 return status.Errorf(codes.NotFound, "%s", deviceId)
406}
407
408func (dMgr *DeviceManager) updateGroups(deviceId string, groups []*ofp.OfpGroupEntry) error {
409 if agent := dMgr.getDeviceAgent(deviceId); agent != nil {
410 return agent.updateGroups(groups)
411 }
412 return status.Errorf(codes.NotFound, "%s", deviceId)
413}
414
khenaidoob9203542018-09-17 22:56:37 -0400415func (dMgr *DeviceManager) updatePmConfigs(deviceId string, pmConfigs *voltha.PmConfigs) error {
416 if agent := dMgr.getDeviceAgent(deviceId); agent != nil {
417 return agent.updatePmConfigs(pmConfigs)
418 }
419 return status.Errorf(codes.NotFound, "%s", deviceId)
420}
421
khenaidoo79232702018-12-04 11:00:41 -0500422func (dMgr *DeviceManager) getSwitchCapability(ctx context.Context, deviceId string) (*ic.SwitchCapability, error) {
khenaidoo92e62c52018-10-03 14:02:54 -0400423 log.Debugw("getSwitchCapability", log.Fields{"deviceid": deviceId})
khenaidoob9203542018-09-17 22:56:37 -0400424 if agent := dMgr.getDeviceAgent(deviceId); agent != nil {
425 return agent.getSwitchCapability(ctx)
426 }
427 return nil, status.Errorf(codes.NotFound, "%s", deviceId)
428}
429
khenaidoo92e62c52018-10-03 14:02:54 -0400430func (dMgr *DeviceManager) getPorts(ctx context.Context, deviceId string, portType voltha.Port_PortType) (*voltha.Ports, error) {
431 log.Debugw("getPorts", log.Fields{"deviceid": deviceId, "portType": portType})
khenaidoob9203542018-09-17 22:56:37 -0400432 if agent := dMgr.getDeviceAgent(deviceId); agent != nil {
khenaidoo92e62c52018-10-03 14:02:54 -0400433 return agent.getPorts(ctx, portType), nil
khenaidoob9203542018-09-17 22:56:37 -0400434 }
435 return nil, status.Errorf(codes.NotFound, "%s", deviceId)
khenaidoo92e62c52018-10-03 14:02:54 -0400436
khenaidoob9203542018-09-17 22:56:37 -0400437}
438
khenaidoo79232702018-12-04 11:00:41 -0500439func (dMgr *DeviceManager) getPortCapability(ctx context.Context, deviceId string, portNo uint32) (*ic.PortCapability, error) {
khenaidoo92e62c52018-10-03 14:02:54 -0400440 log.Debugw("getPortCapability", log.Fields{"deviceid": deviceId})
khenaidoob9203542018-09-17 22:56:37 -0400441 if agent := dMgr.getDeviceAgent(deviceId); agent != nil {
442 return agent.getPortCapability(ctx, portNo)
443 }
444 return nil, status.Errorf(codes.NotFound, "%s", deviceId)
445}
446
khenaidoo92e62c52018-10-03 14:02:54 -0400447func (dMgr *DeviceManager) updateDeviceStatus(deviceId string, operStatus voltha.OperStatus_OperStatus, connStatus voltha.ConnectStatus_ConnectStatus) error {
448 log.Debugw("updateDeviceStatus", log.Fields{"deviceid": deviceId, "operStatus": operStatus, "connStatus": connStatus})
khenaidoob9203542018-09-17 22:56:37 -0400449 if agent := dMgr.getDeviceAgent(deviceId); agent != nil {
khenaidoo92e62c52018-10-03 14:02:54 -0400450 return agent.updateDeviceStatus(operStatus, connStatus)
451 }
452 return status.Errorf(codes.NotFound, "%s", deviceId)
453}
454
khenaidoo4d4802d2018-10-04 21:59:49 -0400455func (dMgr *DeviceManager) updateChildrenStatus(deviceId string, operStatus voltha.OperStatus_OperStatus, connStatus voltha.ConnectStatus_ConnectStatus) error {
456 log.Debugw("updateChildrenStatus", log.Fields{"parentDeviceid": deviceId, "operStatus": operStatus, "connStatus": connStatus})
457 var parentDevice *voltha.Device
458 var err error
khenaidoo19d7b632018-10-30 10:49:50 -0400459 if parentDevice, err = dMgr.GetDevice(deviceId); err != nil {
khenaidoo4d4802d2018-10-04 21:59:49 -0400460 return status.Errorf(codes.Aborted, "%s", err.Error())
461 }
462 var childDeviceIds []string
463 if childDeviceIds, err = dMgr.getAllChildDeviceIds(parentDevice); err != nil {
464 return status.Errorf(codes.Aborted, "%s", err.Error())
465 }
466 if len(childDeviceIds) == 0 {
467 log.Debugw("no-child-device", log.Fields{"parentDeviceId": parentDevice.Id})
468 }
469 for _, childDeviceId := range childDeviceIds {
470 if agent := dMgr.getDeviceAgent(childDeviceId); agent != nil {
471 if err = agent.updateDeviceStatus(operStatus, connStatus); err != nil {
472 return status.Errorf(codes.Aborted, "childDevice:%s, error:%s", childDeviceId, err.Error())
473 }
474 }
475 }
476 return nil
477}
478
khenaidoo92e62c52018-10-03 14:02:54 -0400479func (dMgr *DeviceManager) updatePortState(deviceId string, portType voltha.Port_PortType, portNo uint32, operStatus voltha.OperStatus_OperStatus) error {
480 log.Debugw("updatePortState", log.Fields{"deviceid": deviceId, "portType": portType, "portNo": portNo, "operStatus": operStatus})
481 if agent := dMgr.getDeviceAgent(deviceId); agent != nil {
482 return agent.updatePortState(portType, portNo, operStatus)
khenaidoob9203542018-09-17 22:56:37 -0400483 }
484 return status.Errorf(codes.NotFound, "%s", deviceId)
485}
486
487func (dMgr *DeviceManager) childDeviceDetected(parentDeviceId string, parentPortNo int64, deviceType string, channelId int64) error {
khenaidoo92e62c52018-10-03 14:02:54 -0400488 log.Debugw("childDeviceDetected", log.Fields{"parentDeviceId": parentDeviceId})
khenaidoob9203542018-09-17 22:56:37 -0400489
490 // Create the ONU device
491 childDevice := &voltha.Device{}
khenaidoob9203542018-09-17 22:56:37 -0400492 childDevice.Type = deviceType
493 childDevice.ParentId = parentDeviceId
494 childDevice.ParentPortNo = uint32(parentPortNo)
495 childDevice.Root = false
khenaidoo6fdf0ba2018-11-02 14:38:33 -0400496
497 //Get parent device type
498 parent, err := dMgr.GetDevice(parentDeviceId)
499 if err != nil {
khenaidoo43c82122018-11-22 18:38:28 -0500500 log.Error("no-parent-found", log.Fields{"parentId": parentDeviceId})
khenaidoo6fdf0ba2018-11-02 14:38:33 -0400501 return status.Errorf(codes.NotFound, "%s", parentDeviceId)
502 }
503
504 childDevice.ProxyAddress = &voltha.Device_ProxyAddress{DeviceId: parentDeviceId, DeviceType: parent.Type, ChannelId: uint32(channelId)}
khenaidoob9203542018-09-17 22:56:37 -0400505
506 // Create and start a device agent for that device
khenaidoo9a468962018-09-19 15:33:13 -0400507 agent := newDeviceAgent(dMgr.adapterProxy, childDevice, dMgr, dMgr.clusterDataProxy)
khenaidoob9203542018-09-17 22:56:37 -0400508 dMgr.addDeviceAgentToMap(agent)
khenaidoo297cd252019-02-07 22:10:23 -0500509 agent.start(nil, false)
khenaidoob9203542018-09-17 22:56:37 -0400510
511 // Activate the child device
khenaidoo92e62c52018-10-03 14:02:54 -0400512 if agent := dMgr.getDeviceAgent(agent.deviceId); agent != nil {
khenaidoo79232702018-12-04 11:00:41 -0500513 go agent.enableDevice(nil)
khenaidoob9203542018-09-17 22:56:37 -0400514 }
515
khenaidoo79232702018-12-04 11:00:41 -0500516 // Publish on the messaging bus that we have discovered new devices
khenaidoo19374072018-12-11 11:05:15 -0500517 go dMgr.kafkaICProxy.DeviceDiscovered(agent.deviceId, deviceType, parentDeviceId, dMgr.coreInstanceId)
khenaidoo79232702018-12-04 11:00:41 -0500518
khenaidoob9203542018-09-17 22:56:37 -0400519 return nil
520}
521
522func (dMgr *DeviceManager) processTransition(previous *voltha.Device, current *voltha.Device) error {
523 // This will be triggered on every update to the device.
khenaidoo92e62c52018-10-03 14:02:54 -0400524 handlers := dMgr.stateTransitions.GetTransitionHandler(previous, current)
525 if handlers == nil {
khenaidoo43c82122018-11-22 18:38:28 -0500526 log.Debugw("no-op-transition", log.Fields{"deviceId": current.Id})
khenaidoo92e62c52018-10-03 14:02:54 -0400527 return nil
khenaidoob9203542018-09-17 22:56:37 -0400528 }
khenaidoo92e62c52018-10-03 14:02:54 -0400529 for _, handler := range handlers {
530 log.Debugw("running-handler", log.Fields{"handler": funcName(handler)})
531 if err := handler(current); err != nil {
532 return err
533 }
534 }
khenaidoob9203542018-09-17 22:56:37 -0400535 return nil
536}
537
khenaidoofdbad6e2018-11-06 22:26:38 -0500538func (dMgr *DeviceManager) packetOut(deviceId string, outPort uint32, packet *ofp.OfpPacketOut) error {
539 log.Debugw("packetOut", log.Fields{"deviceId": deviceId, "outPort": outPort})
540 if agent := dMgr.getDeviceAgent(deviceId); agent != nil {
541 return agent.packetOut(outPort, packet)
542 }
543 return status.Errorf(codes.NotFound, "%s", deviceId)
544}
545
khenaidoo297cd252019-02-07 22:10:23 -0500546func (dMgr *DeviceManager) PacketIn(deviceId string, port uint32, transactionId string, packet []byte) error {
khenaidoofdbad6e2018-11-06 22:26:38 -0500547 log.Debugw("PacketIn", log.Fields{"deviceId": deviceId, "port": port})
548 // Get the logical device Id based on the deviceId
549 var device *voltha.Device
550 var err error
551 if device, err = dMgr.GetDevice(deviceId); err != nil {
552 log.Errorw("device-not-found", log.Fields{"deviceId": deviceId})
553 return err
554 }
khenaidoo43c82122018-11-22 18:38:28 -0500555 if !device.Root {
khenaidoofdbad6e2018-11-06 22:26:38 -0500556 log.Errorw("device-not-root", log.Fields{"deviceId": deviceId})
557 return status.Errorf(codes.FailedPrecondition, "%s", deviceId)
558 }
559
khenaidoo297cd252019-02-07 22:10:23 -0500560 if err := dMgr.logicalDeviceMgr.packetIn(device.ParentId, port, transactionId, packet); err != nil {
khenaidoofdbad6e2018-11-06 22:26:38 -0500561 return err
562 }
563 return nil
564}
565
khenaidoo92e62c52018-10-03 14:02:54 -0400566func (dMgr *DeviceManager) createLogicalDevice(cDevice *voltha.Device) error {
khenaidoob9203542018-09-17 22:56:37 -0400567 log.Info("createLogicalDevice")
568 var logicalId *string
569 var err error
khenaidoo4d4802d2018-10-04 21:59:49 -0400570 if logicalId, err = dMgr.logicalDeviceMgr.createLogicalDevice(nil, cDevice); err != nil {
khenaidoob9203542018-09-17 22:56:37 -0400571 log.Warnw("createlogical-device-error", log.Fields{"device": cDevice})
572 return err
573 }
574 // Update the parent device with the logical id
575 dMgr.UpdateDeviceAttribute(cDevice.Id, "ParentId", *logicalId)
576 return nil
577}
578
khenaidoo92e62c52018-10-03 14:02:54 -0400579func (dMgr *DeviceManager) deleteLogicalDevice(cDevice *voltha.Device) error {
580 log.Info("deleteLogicalDevice")
581 var err error
khenaidoo4d4802d2018-10-04 21:59:49 -0400582 if err = dMgr.logicalDeviceMgr.deleteLogicalDevice(nil, cDevice); err != nil {
khenaidoo92e62c52018-10-03 14:02:54 -0400583 log.Warnw("deleteLogical-device-error", log.Fields{"deviceId": cDevice.Id})
584 return err
585 }
586 // Remove the logical device Id from the parent device
587 logicalId := ""
588 dMgr.UpdateDeviceAttribute(cDevice.Id, "ParentId", logicalId)
589 return nil
590}
591
khenaidoo19d7b632018-10-30 10:49:50 -0400592func (dMgr *DeviceManager) deleteLogicalPort(device *voltha.Device) error {
khenaidoo92e62c52018-10-03 14:02:54 -0400593 log.Info("deleteLogicalPort")
594 var err error
khenaidoo19d7b632018-10-30 10:49:50 -0400595 // Get the logical port associated with this device
596 var lPortId *voltha.LogicalPortId
597 if lPortId, err = dMgr.logicalDeviceMgr.getLogicalPortId(device); err != nil {
khenaidoo6fdf0ba2018-11-02 14:38:33 -0400598 log.Warnw("getLogical-port-error", log.Fields{"deviceId": device.Id, "error": err})
khenaidoo19d7b632018-10-30 10:49:50 -0400599 return err
600 }
601 if err = dMgr.logicalDeviceMgr.deleteLogicalPort(nil, lPortId); err != nil {
602 log.Warnw("deleteLogical-port-error", log.Fields{"deviceId": device.Id})
khenaidoo92e62c52018-10-03 14:02:54 -0400603 return err
604 }
khenaidoo92e62c52018-10-03 14:02:54 -0400605 return nil
606}
607
608func (dMgr *DeviceManager) getParentDevice(childDevice *voltha.Device) *voltha.Device {
609 // Sanity check
610 if childDevice.Root {
611 // childDevice is the parent device
612 return childDevice
613 }
khenaidoo19d7b632018-10-30 10:49:50 -0400614 parentDevice, _ := dMgr.GetDevice(childDevice.ParentId)
khenaidoo92e62c52018-10-03 14:02:54 -0400615 return parentDevice
616}
617
khenaidoo4d4802d2018-10-04 21:59:49 -0400618/*
619All the functions below are callback functions where they are invoked with the latest and previous data. We can
620therefore use the data as is without trying to get the latest from the model.
621*/
622
623//disableAllChildDevices is invoked as a callback when the parent device is disabled
624func (dMgr *DeviceManager) disableAllChildDevices(parentDevice *voltha.Device) error {
khenaidoo92e62c52018-10-03 14:02:54 -0400625 log.Debug("disableAllChildDevices")
626 var childDeviceIds []string
627 var err error
khenaidoo4d4802d2018-10-04 21:59:49 -0400628 if childDeviceIds, err = dMgr.getAllChildDeviceIds(parentDevice); err != nil {
629 return status.Errorf(codes.NotFound, "%s", parentDevice.Id)
khenaidoo92e62c52018-10-03 14:02:54 -0400630 }
631 if len(childDeviceIds) == 0 {
khenaidoo4d4802d2018-10-04 21:59:49 -0400632 log.Debugw("no-child-device", log.Fields{"parentDeviceId": parentDevice.Id})
khenaidoo92e62c52018-10-03 14:02:54 -0400633 }
khenaidoo4d4802d2018-10-04 21:59:49 -0400634 allChildDisable := true
khenaidoo92e62c52018-10-03 14:02:54 -0400635 for _, childDeviceId := range childDeviceIds {
636 if agent := dMgr.getDeviceAgent(childDeviceId); agent != nil {
637 if err = agent.disableDevice(nil); err != nil {
638 log.Errorw("failure-disable-device", log.Fields{"deviceId": childDeviceId, "error": err.Error()})
khenaidoo4d4802d2018-10-04 21:59:49 -0400639 allChildDisable = false
khenaidoo92e62c52018-10-03 14:02:54 -0400640 }
641 }
642 }
khenaidoo4d4802d2018-10-04 21:59:49 -0400643 if !allChildDisable {
644 return err
645 }
khenaidoo92e62c52018-10-03 14:02:54 -0400646 return nil
647}
648
khenaidoo4d4802d2018-10-04 21:59:49 -0400649//deleteAllChildDevices is invoked as a callback when the parent device is deleted
650func (dMgr *DeviceManager) deleteAllChildDevices(parentDevice *voltha.Device) error {
651 log.Debug("deleteAllChildDevices")
652 var childDeviceIds []string
khenaidoo92e62c52018-10-03 14:02:54 -0400653 var err error
khenaidoo4d4802d2018-10-04 21:59:49 -0400654 if childDeviceIds, err = dMgr.getAllChildDeviceIds(parentDevice); err != nil {
655 return status.Errorf(codes.NotFound, "%s", parentDevice.Id)
khenaidoo92e62c52018-10-03 14:02:54 -0400656 }
khenaidoo4d4802d2018-10-04 21:59:49 -0400657 if len(childDeviceIds) == 0 {
658 log.Debugw("no-child-device", log.Fields{"parentDeviceId": parentDevice.Id})
659 }
660 allChildDeleted := true
661 for _, childDeviceId := range childDeviceIds {
662 if agent := dMgr.getDeviceAgent(childDeviceId); agent != nil {
663 if err = agent.deleteDevice(nil); err != nil {
664 log.Errorw("failure-delete-device", log.Fields{"deviceId": childDeviceId, "error": err.Error()})
665 allChildDeleted = false
666 } else {
667 agent.stop(nil)
668 dMgr.deleteDeviceAgentToMap(agent)
669 }
670 }
671 }
672 if !allChildDeleted {
673 return err
674 }
675 return nil
676}
677
678//getAllChildDeviceIds is a helper method to get all the child device IDs from the device passed as parameter
679func (dMgr *DeviceManager) getAllChildDeviceIds(parentDevice *voltha.Device) ([]string, error) {
680 log.Debugw("getAllChildDeviceIds", log.Fields{"parentDeviceId": parentDevice.Id})
khenaidoo92e62c52018-10-03 14:02:54 -0400681 childDeviceIds := make([]string, 0)
khenaidoo4d4802d2018-10-04 21:59:49 -0400682 if parentDevice != nil {
683 for _, port := range parentDevice.Ports {
684 for _, peer := range port.Peers {
685 childDeviceIds = append(childDeviceIds, peer.DeviceId)
686 }
khenaidoo92e62c52018-10-03 14:02:54 -0400687 }
688 }
689 return childDeviceIds, nil
690}
691
khenaidoo297cd252019-02-07 22:10:23 -0500692//getAllChildDevices is a helper method to get all the child device IDs from the device passed as parameter
693func (dMgr *DeviceManager) getAllChildDevices(parentDeviceId string) (*voltha.Devices, error) {
694 log.Debugw("getAllChildDevices", log.Fields{"parentDeviceId": parentDeviceId})
695 if parentDevice, err := dMgr.GetDevice(parentDeviceId); err == nil {
696 childDevices := make([]*voltha.Device, 0)
697 if childDeviceIds, er := dMgr.getAllChildDeviceIds(parentDevice); er == nil {
698 for _, deviceId := range childDeviceIds {
699 if d, e := dMgr.GetDevice(deviceId); e == nil && d != nil {
700 childDevices = append(childDevices, d)
701 }
702 }
703 }
704 return &voltha.Devices{Items: childDevices}, nil
705 }
706 return nil, status.Errorf(codes.NotFound, "%s", parentDeviceId)
707}
708
khenaidoo92e62c52018-10-03 14:02:54 -0400709func (dMgr *DeviceManager) addUNILogicalPort(cDevice *voltha.Device) error {
khenaidoob9203542018-09-17 22:56:37 -0400710 log.Info("addUNILogicalPort")
khenaidoo4d4802d2018-10-04 21:59:49 -0400711 if err := dMgr.logicalDeviceMgr.addUNILogicalPort(nil, cDevice); err != nil {
khenaidoob9203542018-09-17 22:56:37 -0400712 log.Warnw("addUNILogicalPort-error", log.Fields{"device": cDevice, "err": err})
713 return err
714 }
715 return nil
716}
717
khenaidoof5a5bfa2019-01-23 22:20:29 -0500718func (dMgr *DeviceManager) downloadImage(ctx context.Context, img *voltha.ImageDownload, ch chan interface{}) {
719 log.Debugw("downloadImage", log.Fields{"deviceid": img.Id, "imageName": img.Name})
720 var res interface{}
721 var err error
722 if agent := dMgr.getDeviceAgent(img.Id); agent != nil {
723 if res, err = agent.downloadImage(ctx, img); err != nil {
724 log.Debugw("downloadImage-failed", log.Fields{"err": err, "imageName": img.Name})
725 res = err
726 }
727 } else {
728 res = status.Errorf(codes.NotFound, "%s", img.Id)
729 }
730 sendResponse(ctx, ch, res)
731}
732
733func (dMgr *DeviceManager) cancelImageDownload(ctx context.Context, img *voltha.ImageDownload, ch chan interface{}) {
734 log.Debugw("cancelImageDownload", log.Fields{"deviceid": img.Id, "imageName": img.Name})
735 var res interface{}
736 var err error
737 if agent := dMgr.getDeviceAgent(img.Id); agent != nil {
738 if res, err = agent.cancelImageDownload(ctx, img); err != nil {
739 log.Debugw("cancelImageDownload-failed", log.Fields{"err": err, "imageName": img.Name})
740 res = err
741 }
742 } else {
743 res = status.Errorf(codes.NotFound, "%s", img.Id)
744 }
745 sendResponse(ctx, ch, res)
746}
747
748func (dMgr *DeviceManager) activateImage(ctx context.Context, img *voltha.ImageDownload, ch chan interface{}) {
749 log.Debugw("activateImage", log.Fields{"deviceid": img.Id, "imageName": img.Name})
750 var res interface{}
751 var err error
752 if agent := dMgr.getDeviceAgent(img.Id); agent != nil {
753 if res, err = agent.activateImage(ctx, img); err != nil {
754 log.Debugw("activateImage-failed", log.Fields{"err": err, "imageName": img.Name})
755 res = err
756 }
757 } else {
758 res = status.Errorf(codes.NotFound, "%s", img.Id)
759 }
760 sendResponse(ctx, ch, res)
761}
762
763func (dMgr *DeviceManager) revertImage(ctx context.Context, img *voltha.ImageDownload, ch chan interface{}) {
764 log.Debugw("revertImage", log.Fields{"deviceid": img.Id, "imageName": img.Name})
765 var res interface{}
766 var err error
767 if agent := dMgr.getDeviceAgent(img.Id); agent != nil {
768 if res, err = agent.revertImage(ctx, img); err != nil {
769 log.Debugw("revertImage-failed", log.Fields{"err": err, "imageName": img.Name})
770 res = err
771 }
772 } else {
773 res = status.Errorf(codes.NotFound, "%s", img.Id)
774 }
775 sendResponse(ctx, ch, res)
776}
777
778func (dMgr *DeviceManager) getImageDownloadStatus(ctx context.Context, img *voltha.ImageDownload, ch chan interface{}) {
779 log.Debugw("getImageDownloadStatus", log.Fields{"deviceid": img.Id, "imageName": img.Name})
780 var res interface{}
781 var err error
782 if agent := dMgr.getDeviceAgent(img.Id); agent != nil {
783 if res, err = agent.getImageDownloadStatus(ctx, img); err != nil {
784 log.Debugw("getImageDownloadStatus-failed", log.Fields{"err": err, "imageName": img.Name})
785 res = err
786 }
787 } else {
788 res = status.Errorf(codes.NotFound, "%s", img.Id)
789 }
790 sendResponse(ctx, ch, res)
791}
792
khenaidoof5a5bfa2019-01-23 22:20:29 -0500793func (dMgr *DeviceManager) updateImageDownload(deviceId string, img *voltha.ImageDownload) error {
794 log.Debugw("updateImageDownload", log.Fields{"deviceid": img.Id, "imageName": img.Name})
795 if agent := dMgr.getDeviceAgent(deviceId); agent != nil {
796 if err := agent.updateImageDownload(img); err != nil {
797 log.Debugw("updateImageDownload-failed", log.Fields{"err": err, "imageName": img.Name})
798 return err
799 }
800 } else {
801 return status.Errorf(codes.NotFound, "%s", img.Id)
802 }
803 return nil
804}
805
806func (dMgr *DeviceManager) getImageDownload(ctx context.Context, img *voltha.ImageDownload) (*voltha.ImageDownload, error) {
807 log.Debugw("getImageDownload", log.Fields{"deviceid": img.Id, "imageName": img.Name})
808 if agent := dMgr.getDeviceAgent(img.Id); agent != nil {
809 return agent.getImageDownload(ctx, img)
810 }
811 return nil, status.Errorf(codes.NotFound, "%s", img.Id)
812}
813
814func (dMgr *DeviceManager) listImageDownloads(ctx context.Context, deviceId string) (*voltha.ImageDownloads, error) {
815 log.Debugw("listImageDownloads", log.Fields{"deviceId": deviceId})
816 if agent := dMgr.getDeviceAgent(deviceId); agent != nil {
817 return agent.listImageDownloads(ctx, deviceId)
818 }
819 return nil, status.Errorf(codes.NotFound, "%s", deviceId)
820}
821
khenaidoo92e62c52018-10-03 14:02:54 -0400822func (dMgr *DeviceManager) activateDevice(cDevice *voltha.Device) error {
khenaidoob9203542018-09-17 22:56:37 -0400823 log.Info("activateDevice")
824 return nil
825}
826
khenaidoo92e62c52018-10-03 14:02:54 -0400827func (dMgr *DeviceManager) disableDeviceHandler(cDevice *voltha.Device) error {
828 log.Info("disableDevice-donothing")
khenaidoob9203542018-09-17 22:56:37 -0400829 return nil
830}
831
khenaidoo92e62c52018-10-03 14:02:54 -0400832func (dMgr *DeviceManager) abandonDevice(cDevice *voltha.Device) error {
khenaidoob9203542018-09-17 22:56:37 -0400833 log.Info("abandonDevice")
834 return nil
835}
836
khenaidoo92e62c52018-10-03 14:02:54 -0400837func (dMgr *DeviceManager) reEnableDevice(cDevice *voltha.Device) error {
khenaidoob9203542018-09-17 22:56:37 -0400838 log.Info("reEnableDevice")
839 return nil
840}
841
khenaidoo92e62c52018-10-03 14:02:54 -0400842func (dMgr *DeviceManager) noOp(cDevice *voltha.Device) error {
khenaidoob9203542018-09-17 22:56:37 -0400843 log.Info("noOp")
844 return nil
845}
846
khenaidoo92e62c52018-10-03 14:02:54 -0400847func (dMgr *DeviceManager) notAllowed(pcDevice *voltha.Device) error {
khenaidoob9203542018-09-17 22:56:37 -0400848 log.Info("notAllowed")
849 return errors.New("Transition-not-allowed")
850}
851
852func funcName(f interface{}) string {
853 p := reflect.ValueOf(f).Pointer()
854 rf := runtime.FuncForPC(p)
855 return rf.Name()
856}
857
858func (dMgr *DeviceManager) UpdateDeviceAttribute(deviceId string, attribute string, value interface{}) {
859 if agent, ok := dMgr.deviceAgents[deviceId]; ok {
860 agent.updateDeviceAttribute(attribute, value)
861 }
862}
863
864func (dMgr *DeviceManager) GetParentDeviceId(deviceId string) *string {
khenaidoo19d7b632018-10-30 10:49:50 -0400865 if device, _ := dMgr.GetDevice(deviceId); device != nil {
khenaidoo92e62c52018-10-03 14:02:54 -0400866 log.Infow("GetParentDeviceId", log.Fields{"deviceId": device.Id, "parentId": device.ParentId})
khenaidoob9203542018-09-17 22:56:37 -0400867 return &device.ParentId
868 }
869 return nil
870}