blob: aaa4a7392c31b1fdd268c4af223f0aba2abb6a2d [file] [log] [blame]
Stephane Barbariea75791c2019-01-24 10:58:06 -05001/*
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 */
npujar03b018e2019-11-13 15:29:36 +053016
Stephane Barbariea75791c2019-01-24 10:58:06 -050017package core
18
19import (
20 "context"
npujar03b018e2019-11-13 15:29:36 +053021 "sync"
22
sbarbari17d7e222019-11-05 10:02:29 -050023 "github.com/opencord/voltha-go/db/model"
serkant.uluderya2ae470f2020-01-21 11:13:09 -080024 "github.com/opencord/voltha-lib-go/v3/pkg/log"
25 "github.com/opencord/voltha-lib-go/v3/pkg/probe"
26 "github.com/opencord/voltha-protos/v3/go/voltha"
Stephane Barbariea75791c2019-01-24 10:58:06 -050027 "google.golang.org/grpc/codes"
28 "google.golang.org/grpc/status"
Stephane Barbariea75791c2019-01-24 10:58:06 -050029)
30
npujar03b018e2019-11-13 15:29:36 +053031// DeviceManager represents device manager related information
Stephane Barbariea75791c2019-01-24 10:58:06 -050032type DeviceManager struct {
Stephane Barbarieef6650d2019-07-18 12:15:09 -040033 deviceAgents sync.Map
34 logicalDeviceMgr *LogicalDeviceManager
35 clusterDataProxy *model.Proxy
npujar03b018e2019-11-13 15:29:36 +053036 coreInstanceID string
Stephane Barbarieef6650d2019-07-18 12:15:09 -040037 exitChannel chan int
Stephane Barbariea75791c2019-01-24 10:58:06 -050038}
39
npujar03b018e2019-11-13 15:29:36 +053040func newDeviceManager(cdProxy *model.Proxy, coreInstanceID string) *DeviceManager {
Stephane Barbariea75791c2019-01-24 10:58:06 -050041 var deviceMgr DeviceManager
42 deviceMgr.exitChannel = make(chan int, 1)
npujar03b018e2019-11-13 15:29:36 +053043 deviceMgr.coreInstanceID = coreInstanceID
Stephane Barbariea75791c2019-01-24 10:58:06 -050044 deviceMgr.clusterDataProxy = cdProxy
Stephane Barbariea75791c2019-01-24 10:58:06 -050045 return &deviceMgr
46}
47
48func (dMgr *DeviceManager) start(ctx context.Context, logicalDeviceMgr *LogicalDeviceManager) {
49 log.Info("starting-device-manager")
50 dMgr.logicalDeviceMgr = logicalDeviceMgr
Hardik Windlassdc63dde2019-09-30 07:15:13 +000051 probe.UpdateStatusFromContext(ctx, "device-manager", probe.ServiceStatusRunning)
Stephane Barbariea75791c2019-01-24 10:58:06 -050052 log.Info("device-manager-started")
53}
54
55func (dMgr *DeviceManager) stop(ctx context.Context) {
56 log.Info("stopping-device-manager")
57 dMgr.exitChannel <- 1
Hardik Windlassdc63dde2019-09-30 07:15:13 +000058 probe.UpdateStatusFromContext(ctx, "device-manager", probe.ServiceStatusStopped)
Stephane Barbariea75791c2019-01-24 10:58:06 -050059 log.Info("device-manager-stopped")
60}
61
62func sendResponse(ctx context.Context, ch chan interface{}, result interface{}) {
63 if ctx.Err() == nil {
64 // Returned response only of the ctx has not been cancelled/timeout/etc
65 // Channel is automatically closed when a context is Done
66 ch <- result
67 log.Debugw("sendResponse", log.Fields{"result": result})
68 } else {
69 // Should the transaction be reverted back?
70 log.Debugw("sendResponse-context-error", log.Fields{"context-error": ctx.Err()})
71 }
72}
73
74func (dMgr *DeviceManager) addDeviceAgentToMap(agent *DeviceAgent) {
npujar03b018e2019-11-13 15:29:36 +053075 if _, exist := dMgr.deviceAgents.Load(agent.deviceID); !exist {
76 dMgr.deviceAgents.Store(agent.deviceID, agent)
Stephane Barbariea75791c2019-01-24 10:58:06 -050077 }
78}
79
80func (dMgr *DeviceManager) deleteDeviceAgentToMap(agent *DeviceAgent) {
npujar03b018e2019-11-13 15:29:36 +053081 dMgr.deviceAgents.Delete(agent.deviceID)
Stephane Barbariea75791c2019-01-24 10:58:06 -050082}
83
npujar03b018e2019-11-13 15:29:36 +053084func (dMgr *DeviceManager) getDeviceAgent(deviceID string) *DeviceAgent {
85 if agent, ok := dMgr.deviceAgents.Load(deviceID); ok {
Stephane Barbarieef6650d2019-07-18 12:15:09 -040086 return agent.(*DeviceAgent)
npujar03b018e2019-11-13 15:29:36 +053087 }
88 // Try to load into memory - loading will also create the device agent
89 if err := dMgr.load(deviceID); err == nil {
90 if agent, ok := dMgr.deviceAgents.Load(deviceID); ok {
91 return agent.(*DeviceAgent)
Stephane Barbarie1e28f3e2019-02-08 15:45:20 -050092 }
Stephane Barbariea75791c2019-01-24 10:58:06 -050093 }
94 return nil
95}
96
npujar03b018e2019-11-13 15:29:36 +053097// listDeviceIDsFromMap returns the list of device IDs that are in memory
98func (dMgr *DeviceManager) listDeviceIDsFromMap() *voltha.IDs {
Stephane Barbariea75791c2019-01-24 10:58:06 -050099 result := &voltha.IDs{Items: make([]*voltha.ID, 0)}
Stephane Barbarieef6650d2019-07-18 12:15:09 -0400100 dMgr.deviceAgents.Range(func(key, value interface{}) bool {
101 result.Items = append(result.Items, &voltha.ID{Id: key.(string)})
102 return true
103 })
Stephane Barbariea75791c2019-01-24 10:58:06 -0500104 return result
105}
106
Stephane Barbarie1e28f3e2019-02-08 15:45:20 -0500107// GetDevice will returns a device, either from memory or from the dB, if present
Stephane Barbariea75791c2019-01-24 10:58:06 -0500108func (dMgr *DeviceManager) GetDevice(id string) (*voltha.Device, error) {
109 log.Debugw("GetDevice", log.Fields{"deviceid": id})
110 if agent := dMgr.getDeviceAgent(id); agent != nil {
111 return agent.getDevice()
112 }
113 return nil, status.Errorf(codes.NotFound, "%s", id)
114}
115
npujar03b018e2019-11-13 15:29:36 +0530116// IsDeviceInCache returns true if device exists in cache
Stephane Barbarie1e28f3e2019-02-08 15:45:20 -0500117func (dMgr *DeviceManager) IsDeviceInCache(id string) bool {
Stephane Barbarieef6650d2019-07-18 12:15:09 -0400118 _, exist := dMgr.deviceAgents.Load(id)
Stephane Barbarie1e28f3e2019-02-08 15:45:20 -0500119 return exist
120}
121
npujar03b018e2019-11-13 15:29:36 +0530122// IsRootDevice returns true if root device is present in either memory or db
Stephane Barbariea75791c2019-01-24 10:58:06 -0500123func (dMgr *DeviceManager) IsRootDevice(id string) (bool, error) {
124 device, err := dMgr.GetDevice(id)
125 if err != nil {
126 return false, err
127 }
128 return device.Root, nil
129}
130
Stephane Barbarieaa467942019-02-06 14:09:44 -0500131// ListDevices retrieves the latest devices from the data model
Stephane Barbariea75791c2019-01-24 10:58:06 -0500132func (dMgr *DeviceManager) ListDevices() (*voltha.Devices, error) {
133 log.Debug("ListDevices")
134 result := &voltha.Devices{}
Thomas Lee Se5a44012019-11-07 20:32:24 +0530135 if devices, err := dMgr.clusterDataProxy.List(context.Background(), "/devices", 0, false, ""); err != nil {
136 log.Errorw("failed-to-list-devices", log.Fields{"error": err})
137 return nil, err
138 } else if devices != nil {
Stephane Barbariea75791c2019-01-24 10:58:06 -0500139 for _, device := range devices.([]interface{}) {
Stephane Barbarie1e28f3e2019-02-08 15:45:20 -0500140 // If device is not in memory then set it up
141 if !dMgr.IsDeviceInCache(device.(*voltha.Device).Id) {
142 agent := newDeviceAgent(device.(*voltha.Device), dMgr, dMgr.clusterDataProxy)
npujar03b018e2019-11-13 15:29:36 +0530143 if err := agent.start(context.TODO(), true); err != nil {
144 log.Warnw("failure-starting-agent", log.Fields{"deviceID": device.(*voltha.Device).Id})
145 agent.stop(context.TODO())
Stephane Barbarie1e28f3e2019-02-08 15:45:20 -0500146 } else {
147 dMgr.addDeviceAgentToMap(agent)
148 }
Stephane Barbariea75791c2019-01-24 10:58:06 -0500149 }
150 result.Items = append(result.Items, device.(*voltha.Device))
151 }
152 }
153 return result, nil
154}
155
npujar03b018e2019-11-13 15:29:36 +0530156// loadDevice loads the deviceID in memory, if not present
157func (dMgr *DeviceManager) loadDevice(deviceID string) (*DeviceAgent, error) {
158 log.Debugw("loading-device", log.Fields{"deviceID": deviceID})
Stephane Barbarie1e28f3e2019-02-08 15:45:20 -0500159 // Sanity check
npujar03b018e2019-11-13 15:29:36 +0530160 if deviceID == "" {
161 return nil, status.Error(codes.InvalidArgument, "deviceID empty")
Stephane Barbarie1e28f3e2019-02-08 15:45:20 -0500162 }
npujar03b018e2019-11-13 15:29:36 +0530163 if !dMgr.IsDeviceInCache(deviceID) {
164 agent := newDeviceAgent(&voltha.Device{Id: deviceID}, dMgr, dMgr.clusterDataProxy)
165 if err := agent.start(context.TODO(), true); err != nil {
166 agent.stop(context.TODO())
Stephane Barbarie1e28f3e2019-02-08 15:45:20 -0500167 return nil, err
168 }
169 dMgr.addDeviceAgentToMap(agent)
170 }
npujar03b018e2019-11-13 15:29:36 +0530171 if agent := dMgr.getDeviceAgent(deviceID); agent != nil {
Stephane Barbarie1e28f3e2019-02-08 15:45:20 -0500172 return agent, nil
173 }
npujar03b018e2019-11-13 15:29:36 +0530174 return nil, status.Error(codes.NotFound, deviceID) // This should nto happen
Stephane Barbarie1e28f3e2019-02-08 15:45:20 -0500175}
176
177// loadRootDeviceParentAndChildren loads the children and parents of a root device in memory
178func (dMgr *DeviceManager) loadRootDeviceParentAndChildren(device *voltha.Device) error {
npujar03b018e2019-11-13 15:29:36 +0530179 log.Debugw("loading-parent-and-children", log.Fields{"deviceID": device.Id})
Stephane Barbarie1e28f3e2019-02-08 15:45:20 -0500180 if device.Root {
181 // Scenario A
182 if device.ParentId != "" {
183 // Load logical device if needed.
184 if err := dMgr.logicalDeviceMgr.load(device.ParentId); err != nil {
npujar03b018e2019-11-13 15:29:36 +0530185 log.Warnw("failure-loading-logical-device", log.Fields{"lDeviceID": device.ParentId})
Stephane Barbarie1e28f3e2019-02-08 15:45:20 -0500186 }
187 } else {
npujar03b018e2019-11-13 15:29:36 +0530188 log.Debugw("no-parent-to-load", log.Fields{"deviceID": device.Id})
Stephane Barbarie1e28f3e2019-02-08 15:45:20 -0500189 }
190 // Load all child devices, if needed
npujar03b018e2019-11-13 15:29:36 +0530191 if childDeviceIDs, err := dMgr.getAllChildDeviceIDs(device); err == nil {
192 for _, childDeviceID := range childDeviceIDs {
193 if _, err := dMgr.loadDevice(childDeviceID); err != nil {
194 log.Warnw("failure-loading-device", log.Fields{"deviceID": childDeviceID})
Stephane Barbarie1e28f3e2019-02-08 15:45:20 -0500195 return err
196 }
197 }
npujar03b018e2019-11-13 15:29:36 +0530198 log.Debugw("loaded-children", log.Fields{"deviceID": device.Id, "numChildren": len(childDeviceIDs)})
Stephane Barbarie1e28f3e2019-02-08 15:45:20 -0500199 } else {
npujar03b018e2019-11-13 15:29:36 +0530200 log.Debugw("no-child-to-load", log.Fields{"deviceID": device.Id})
Stephane Barbarie1e28f3e2019-02-08 15:45:20 -0500201 }
202 }
203 return nil
204}
205
npujar03b018e2019-11-13 15:29:36 +0530206// load loads the deviceID in memory, if not present, and also loads its accompanying parents and children. Loading
Stephane Barbarie1e28f3e2019-02-08 15:45:20 -0500207// in memory is for improved performance. It is not imperative that a device needs to be in memory when a request
208// acting on the device is received by the core. In such a scenario, the Core will load the device in memory first
209// and the proceed with the request.
npujar03b018e2019-11-13 15:29:36 +0530210func (dMgr *DeviceManager) load(deviceID string) error {
Stephane Barbarie1e28f3e2019-02-08 15:45:20 -0500211 log.Debug("load...")
212 // First load the device - this may fail in case the device was deleted intentionally by the other core
213 var dAgent *DeviceAgent
214 var err error
npujar03b018e2019-11-13 15:29:36 +0530215 if dAgent, err = dMgr.loadDevice(deviceID); err != nil {
216 log.Warnw("failure-loading-device", log.Fields{"deviceID": deviceID})
Stephane Barbarie1e28f3e2019-02-08 15:45:20 -0500217 return err
218 }
219 // Get the loaded device details
220 var device *voltha.Device
221 if device, err = dAgent.getDevice(); err != nil {
222 return err
223 }
224
225 // If the device is in Pre-provisioning or deleted state stop here
226 if device.AdminState == voltha.AdminState_PREPROVISIONED || device.AdminState == voltha.AdminState_DELETED {
227 return nil
228 }
229
230 // Now we face two scenarios
231 if device.Root {
232 // Load all children as well as the parent of this device (logical_device)
233 if err := dMgr.loadRootDeviceParentAndChildren(device); err != nil {
npujar03b018e2019-11-13 15:29:36 +0530234 log.Warnw("failure-loading-device-parent-and-children", log.Fields{"deviceID": deviceID})
Stephane Barbarie1e28f3e2019-02-08 15:45:20 -0500235 return err
236 }
npujar03b018e2019-11-13 15:29:36 +0530237 log.Debugw("successfully-loaded-parent-and-children", log.Fields{"deviceID": deviceID})
Stephane Barbarie1e28f3e2019-02-08 15:45:20 -0500238 } else {
npujar03b018e2019-11-13 15:29:36 +0530239 // Scenario B - use the parentID of that device (root device) to trigger the loading
Stephane Barbarie1e28f3e2019-02-08 15:45:20 -0500240 if device.ParentId != "" {
241 return dMgr.load(device.ParentId)
242 }
243 }
244 return nil
245}
246
npujar03b018e2019-11-13 15:29:36 +0530247// ListDeviceIDs retrieves the latest device IDs information from the data model (memory data only)
248func (dMgr *DeviceManager) ListDeviceIDs() (*voltha.IDs, error) {
Stephane Barbariea75791c2019-01-24 10:58:06 -0500249 log.Debug("ListDeviceIDs")
250 // Report only device IDs that are in the device agent map
npujar03b018e2019-11-13 15:29:36 +0530251 return dMgr.listDeviceIDsFromMap(), nil
Stephane Barbariea75791c2019-01-24 10:58:06 -0500252}
253
254//ReconcileDevices is a request to a voltha core to managed a list of devices based on their IDs
255func (dMgr *DeviceManager) ReconcileDevices(ctx context.Context, ids *voltha.IDs, ch chan interface{}) {
256 log.Debug("ReconcileDevices")
257 var res interface{}
258 if ids != nil {
259 toReconcile := len(ids.Items)
260 reconciled := 0
261 for _, id := range ids.Items {
262 // Act on the device only if its not present in the agent map
Stephane Barbarie1e28f3e2019-02-08 15:45:20 -0500263 if !dMgr.IsDeviceInCache(id.Id) {
npujar03b018e2019-11-13 15:29:36 +0530264 // Device ID not in memory
Stephane Barbariea75791c2019-01-24 10:58:06 -0500265 log.Debugw("reconciling-device", log.Fields{"id": id.Id})
Stephane Barbarie1e28f3e2019-02-08 15:45:20 -0500266 // Load device from dB
267 agent := newDeviceAgent(&voltha.Device{Id: id.Id}, dMgr, dMgr.clusterDataProxy)
npujar03b018e2019-11-13 15:29:36 +0530268 if err := agent.start(context.TODO(), true); err != nil {
269 log.Warnw("failure-loading-device", log.Fields{"deviceID": id.Id})
270 agent.stop(context.TODO())
Stephane Barbariea75791c2019-01-24 10:58:06 -0500271 } else {
Stephane Barbarie1e28f3e2019-02-08 15:45:20 -0500272 dMgr.addDeviceAgentToMap(agent)
npujar03b018e2019-11-13 15:29:36 +0530273 reconciled++
Stephane Barbariea75791c2019-01-24 10:58:06 -0500274 }
275 } else {
npujar03b018e2019-11-13 15:29:36 +0530276 reconciled++
Stephane Barbariea75791c2019-01-24 10:58:06 -0500277 }
278 }
279 if toReconcile != reconciled {
280 res = status.Errorf(codes.DataLoss, "less-device-reconciled:%d/%d", reconciled, toReconcile)
281 }
282 } else {
283 res = status.Errorf(codes.InvalidArgument, "empty-list-of-ids")
284 }
285 sendResponse(ctx, ch, res)
286}
287
npujar03b018e2019-11-13 15:29:36 +0530288// ListDevicePorts returns ports details for a specific device
289func (dMgr *DeviceManager) ListDevicePorts(ctx context.Context, deviceID string) (*voltha.Ports, error) {
290 log.Debugw("ListDevicePorts", log.Fields{"deviceid": deviceID})
291 if agent := dMgr.getDeviceAgent(deviceID); agent != nil {
Stephane Barbariea75791c2019-01-24 10:58:06 -0500292 return agent.ListDevicePorts(ctx)
293 }
npujar03b018e2019-11-13 15:29:36 +0530294 return nil, status.Errorf(codes.NotFound, "%s", deviceID)
Stephane Barbariea75791c2019-01-24 10:58:06 -0500295
296}
297
npujar03b018e2019-11-13 15:29:36 +0530298// ListDevicePmConfigs returns PM config details for a specific device
299func (dMgr *DeviceManager) ListDevicePmConfigs(ctx context.Context, deviceID string) (*voltha.PmConfigs, error) {
300 log.Debugw("ListDevicePmConfigs", log.Fields{"deviceid": deviceID})
301 if agent := dMgr.getDeviceAgent(deviceID); agent != nil {
Stephane Barbariea75791c2019-01-24 10:58:06 -0500302 return agent.ListDevicePmConfigs(ctx)
303 }
npujar03b018e2019-11-13 15:29:36 +0530304 return nil, status.Errorf(codes.NotFound, "%s", deviceID)
Stephane Barbariea75791c2019-01-24 10:58:06 -0500305
306}
307
npujar03b018e2019-11-13 15:29:36 +0530308// ListDeviceFlows returns flow details for a specific device
309func (dMgr *DeviceManager) ListDeviceFlows(ctx context.Context, deviceID string) (*voltha.Flows, error) {
310 log.Debugw("ListDeviceFlows", log.Fields{"deviceid": deviceID})
311 if agent := dMgr.getDeviceAgent(deviceID); agent != nil {
Stephane Barbariea75791c2019-01-24 10:58:06 -0500312 return agent.ListDeviceFlows(ctx)
313 }
npujar03b018e2019-11-13 15:29:36 +0530314 return nil, status.Errorf(codes.NotFound, "%s", deviceID)
Stephane Barbariea75791c2019-01-24 10:58:06 -0500315}
316
npujar03b018e2019-11-13 15:29:36 +0530317// ListDeviceFlowGroups returns flow group details for a specific device
318func (dMgr *DeviceManager) ListDeviceFlowGroups(ctx context.Context, deviceID string) (*voltha.FlowGroups, error) {
319 log.Debugw("ListDeviceFlowGroups", log.Fields{"deviceid": deviceID})
320 if agent := dMgr.getDeviceAgent(deviceID); agent != nil {
Stephane Barbariea75791c2019-01-24 10:58:06 -0500321 return agent.ListDeviceFlowGroups(ctx)
322 }
npujar03b018e2019-11-13 15:29:36 +0530323 return nil, status.Errorf(codes.NotFound, "%s", deviceID)
Stephane Barbariea75791c2019-01-24 10:58:06 -0500324
325}
326
npujar03b018e2019-11-13 15:29:36 +0530327// GetImageDownloadStatus returns the download status of an image of a particular device
328func (dMgr *DeviceManager) GetImageDownloadStatus(ctx context.Context, deviceID string, imageName string) (*voltha.ImageDownload, error) {
329 log.Debugw("GetImageDownloadStatus", log.Fields{"deviceid": deviceID, "imagename": imageName})
330 if agent := dMgr.getDeviceAgent(deviceID); agent != nil {
Stephane Barbariea75791c2019-01-24 10:58:06 -0500331 return agent.GetImageDownloadStatus(ctx, imageName)
332 }
npujar03b018e2019-11-13 15:29:36 +0530333 return nil, status.Errorf(codes.NotFound, "%s", deviceID)
Stephane Barbariea75791c2019-01-24 10:58:06 -0500334
335}
336
npujar03b018e2019-11-13 15:29:36 +0530337// GetImageDownload return the download details for a specific image entry
338func (dMgr *DeviceManager) GetImageDownload(ctx context.Context, deviceID string, imageName string) (*voltha.ImageDownload, error) {
339 log.Debugw("GetImageDownload", log.Fields{"deviceid": deviceID, "imagename": imageName})
340 if agent := dMgr.getDeviceAgent(deviceID); agent != nil {
Stephane Barbariea75791c2019-01-24 10:58:06 -0500341 return agent.GetImageDownload(ctx, imageName)
342 }
npujar03b018e2019-11-13 15:29:36 +0530343 return nil, status.Errorf(codes.NotFound, "%s", deviceID)
Stephane Barbariea75791c2019-01-24 10:58:06 -0500344
345}
346
npujar03b018e2019-11-13 15:29:36 +0530347// ListImageDownloads returns all image downloads known to the system
348func (dMgr *DeviceManager) ListImageDownloads(ctx context.Context, deviceID string) (*voltha.ImageDownloads, error) {
349 log.Debugw("ListImageDownloads", log.Fields{"deviceid": deviceID})
350 if agent := dMgr.getDeviceAgent(deviceID); agent != nil {
Stephane Barbariea75791c2019-01-24 10:58:06 -0500351 return agent.ListImageDownloads(ctx)
352 }
npujar03b018e2019-11-13 15:29:36 +0530353 return nil, status.Errorf(codes.NotFound, "%s", deviceID)
Stephane Barbariea75791c2019-01-24 10:58:06 -0500354
355}
356
npujar03b018e2019-11-13 15:29:36 +0530357// GetImages returns all images for a specific device entry
358func (dMgr *DeviceManager) GetImages(ctx context.Context, deviceID string) (*voltha.Images, error) {
359 log.Debugw("GetImages", log.Fields{"deviceid": deviceID})
360 if agent := dMgr.getDeviceAgent(deviceID); agent != nil {
Stephane Barbariea75791c2019-01-24 10:58:06 -0500361 return agent.GetImages(ctx)
362 }
npujar03b018e2019-11-13 15:29:36 +0530363 return nil, status.Errorf(codes.NotFound, "%s", deviceID)
Stephane Barbariea75791c2019-01-24 10:58:06 -0500364
365}
366
367func (dMgr *DeviceManager) getParentDevice(childDevice *voltha.Device) *voltha.Device {
368 // Sanity check
369 if childDevice.Root {
370 // childDevice is the parent device
371 return childDevice
372 }
373 parentDevice, _ := dMgr.GetDevice(childDevice.ParentId)
374 return parentDevice
375}
Stephane Barbarie1e28f3e2019-02-08 15:45:20 -0500376
npujar03b018e2019-11-13 15:29:36 +0530377//getAllChildDeviceIDs is a helper method to get all the child device IDs from the device passed as parameter
378func (dMgr *DeviceManager) getAllChildDeviceIDs(parentDevice *voltha.Device) ([]string, error) {
379 log.Debugw("getAllChildDeviceIDs", log.Fields{"parentDeviceID": parentDevice.Id})
380 childDeviceIDs := make([]string, 0)
Stephane Barbarie1e28f3e2019-02-08 15:45:20 -0500381 if parentDevice != nil {
382 for _, port := range parentDevice.Ports {
383 for _, peer := range port.Peers {
npujar03b018e2019-11-13 15:29:36 +0530384 childDeviceIDs = append(childDeviceIDs, peer.DeviceId)
Stephane Barbarie1e28f3e2019-02-08 15:45:20 -0500385 }
386 }
387 }
npujar03b018e2019-11-13 15:29:36 +0530388 return childDeviceIDs, nil
Stephane Barbarie1e28f3e2019-02-08 15:45:20 -0500389}