blob: 634566cf237ea22f35a529818e0cb9db920d4bde [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"
Scott Baker807addd2019-10-24 15:16:21 -070024 "github.com/opencord/voltha-lib-go/v2/pkg/log"
25 "github.com/opencord/voltha-lib-go/v2/pkg/probe"
Scott Baker555307d2019-11-04 08:58:01 -080026 "github.com/opencord/voltha-protos/v2/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{}
Stephane Barbarieef6650d2019-07-18 12:15:09 -0400135 if devices := dMgr.clusterDataProxy.List(context.Background(), "/devices", 0, false, ""); devices != nil {
Stephane Barbariea75791c2019-01-24 10:58:06 -0500136 for _, device := range devices.([]interface{}) {
Stephane Barbarie1e28f3e2019-02-08 15:45:20 -0500137 // If device is not in memory then set it up
138 if !dMgr.IsDeviceInCache(device.(*voltha.Device).Id) {
139 agent := newDeviceAgent(device.(*voltha.Device), dMgr, dMgr.clusterDataProxy)
npujar03b018e2019-11-13 15:29:36 +0530140 if err := agent.start(context.TODO(), true); err != nil {
141 log.Warnw("failure-starting-agent", log.Fields{"deviceID": device.(*voltha.Device).Id})
142 agent.stop(context.TODO())
Stephane Barbarie1e28f3e2019-02-08 15:45:20 -0500143 } else {
144 dMgr.addDeviceAgentToMap(agent)
145 }
Stephane Barbariea75791c2019-01-24 10:58:06 -0500146 }
147 result.Items = append(result.Items, device.(*voltha.Device))
148 }
149 }
150 return result, nil
151}
152
npujar03b018e2019-11-13 15:29:36 +0530153// loadDevice loads the deviceID in memory, if not present
154func (dMgr *DeviceManager) loadDevice(deviceID string) (*DeviceAgent, error) {
155 log.Debugw("loading-device", log.Fields{"deviceID": deviceID})
Stephane Barbarie1e28f3e2019-02-08 15:45:20 -0500156 // Sanity check
npujar03b018e2019-11-13 15:29:36 +0530157 if deviceID == "" {
158 return nil, status.Error(codes.InvalidArgument, "deviceID empty")
Stephane Barbarie1e28f3e2019-02-08 15:45:20 -0500159 }
npujar03b018e2019-11-13 15:29:36 +0530160 if !dMgr.IsDeviceInCache(deviceID) {
161 agent := newDeviceAgent(&voltha.Device{Id: deviceID}, dMgr, dMgr.clusterDataProxy)
162 if err := agent.start(context.TODO(), true); err != nil {
163 agent.stop(context.TODO())
Stephane Barbarie1e28f3e2019-02-08 15:45:20 -0500164 return nil, err
165 }
166 dMgr.addDeviceAgentToMap(agent)
167 }
npujar03b018e2019-11-13 15:29:36 +0530168 if agent := dMgr.getDeviceAgent(deviceID); agent != nil {
Stephane Barbarie1e28f3e2019-02-08 15:45:20 -0500169 return agent, nil
170 }
npujar03b018e2019-11-13 15:29:36 +0530171 return nil, status.Error(codes.NotFound, deviceID) // This should nto happen
Stephane Barbarie1e28f3e2019-02-08 15:45:20 -0500172}
173
174// loadRootDeviceParentAndChildren loads the children and parents of a root device in memory
175func (dMgr *DeviceManager) loadRootDeviceParentAndChildren(device *voltha.Device) error {
npujar03b018e2019-11-13 15:29:36 +0530176 log.Debugw("loading-parent-and-children", log.Fields{"deviceID": device.Id})
Stephane Barbarie1e28f3e2019-02-08 15:45:20 -0500177 if device.Root {
178 // Scenario A
179 if device.ParentId != "" {
180 // Load logical device if needed.
181 if err := dMgr.logicalDeviceMgr.load(device.ParentId); err != nil {
npujar03b018e2019-11-13 15:29:36 +0530182 log.Warnw("failure-loading-logical-device", log.Fields{"lDeviceID": device.ParentId})
Stephane Barbarie1e28f3e2019-02-08 15:45:20 -0500183 }
184 } else {
npujar03b018e2019-11-13 15:29:36 +0530185 log.Debugw("no-parent-to-load", log.Fields{"deviceID": device.Id})
Stephane Barbarie1e28f3e2019-02-08 15:45:20 -0500186 }
187 // Load all child devices, if needed
npujar03b018e2019-11-13 15:29:36 +0530188 if childDeviceIDs, err := dMgr.getAllChildDeviceIDs(device); err == nil {
189 for _, childDeviceID := range childDeviceIDs {
190 if _, err := dMgr.loadDevice(childDeviceID); err != nil {
191 log.Warnw("failure-loading-device", log.Fields{"deviceID": childDeviceID})
Stephane Barbarie1e28f3e2019-02-08 15:45:20 -0500192 return err
193 }
194 }
npujar03b018e2019-11-13 15:29:36 +0530195 log.Debugw("loaded-children", log.Fields{"deviceID": device.Id, "numChildren": len(childDeviceIDs)})
Stephane Barbarie1e28f3e2019-02-08 15:45:20 -0500196 } else {
npujar03b018e2019-11-13 15:29:36 +0530197 log.Debugw("no-child-to-load", log.Fields{"deviceID": device.Id})
Stephane Barbarie1e28f3e2019-02-08 15:45:20 -0500198 }
199 }
200 return nil
201}
202
npujar03b018e2019-11-13 15:29:36 +0530203// 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 -0500204// in memory is for improved performance. It is not imperative that a device needs to be in memory when a request
205// acting on the device is received by the core. In such a scenario, the Core will load the device in memory first
206// and the proceed with the request.
npujar03b018e2019-11-13 15:29:36 +0530207func (dMgr *DeviceManager) load(deviceID string) error {
Stephane Barbarie1e28f3e2019-02-08 15:45:20 -0500208 log.Debug("load...")
209 // First load the device - this may fail in case the device was deleted intentionally by the other core
210 var dAgent *DeviceAgent
211 var err error
npujar03b018e2019-11-13 15:29:36 +0530212 if dAgent, err = dMgr.loadDevice(deviceID); err != nil {
213 log.Warnw("failure-loading-device", log.Fields{"deviceID": deviceID})
Stephane Barbarie1e28f3e2019-02-08 15:45:20 -0500214 return err
215 }
216 // Get the loaded device details
217 var device *voltha.Device
218 if device, err = dAgent.getDevice(); err != nil {
219 return err
220 }
221
222 // If the device is in Pre-provisioning or deleted state stop here
223 if device.AdminState == voltha.AdminState_PREPROVISIONED || device.AdminState == voltha.AdminState_DELETED {
224 return nil
225 }
226
227 // Now we face two scenarios
228 if device.Root {
229 // Load all children as well as the parent of this device (logical_device)
230 if err := dMgr.loadRootDeviceParentAndChildren(device); err != nil {
npujar03b018e2019-11-13 15:29:36 +0530231 log.Warnw("failure-loading-device-parent-and-children", log.Fields{"deviceID": deviceID})
Stephane Barbarie1e28f3e2019-02-08 15:45:20 -0500232 return err
233 }
npujar03b018e2019-11-13 15:29:36 +0530234 log.Debugw("successfully-loaded-parent-and-children", log.Fields{"deviceID": deviceID})
Stephane Barbarie1e28f3e2019-02-08 15:45:20 -0500235 } else {
npujar03b018e2019-11-13 15:29:36 +0530236 // Scenario B - use the parentID of that device (root device) to trigger the loading
Stephane Barbarie1e28f3e2019-02-08 15:45:20 -0500237 if device.ParentId != "" {
238 return dMgr.load(device.ParentId)
239 }
240 }
241 return nil
242}
243
npujar03b018e2019-11-13 15:29:36 +0530244// ListDeviceIDs retrieves the latest device IDs information from the data model (memory data only)
245func (dMgr *DeviceManager) ListDeviceIDs() (*voltha.IDs, error) {
Stephane Barbariea75791c2019-01-24 10:58:06 -0500246 log.Debug("ListDeviceIDs")
247 // Report only device IDs that are in the device agent map
npujar03b018e2019-11-13 15:29:36 +0530248 return dMgr.listDeviceIDsFromMap(), nil
Stephane Barbariea75791c2019-01-24 10:58:06 -0500249}
250
251//ReconcileDevices is a request to a voltha core to managed a list of devices based on their IDs
252func (dMgr *DeviceManager) ReconcileDevices(ctx context.Context, ids *voltha.IDs, ch chan interface{}) {
253 log.Debug("ReconcileDevices")
254 var res interface{}
255 if ids != nil {
256 toReconcile := len(ids.Items)
257 reconciled := 0
258 for _, id := range ids.Items {
259 // Act on the device only if its not present in the agent map
Stephane Barbarie1e28f3e2019-02-08 15:45:20 -0500260 if !dMgr.IsDeviceInCache(id.Id) {
npujar03b018e2019-11-13 15:29:36 +0530261 // Device ID not in memory
Stephane Barbariea75791c2019-01-24 10:58:06 -0500262 log.Debugw("reconciling-device", log.Fields{"id": id.Id})
Stephane Barbarie1e28f3e2019-02-08 15:45:20 -0500263 // Load device from dB
264 agent := newDeviceAgent(&voltha.Device{Id: id.Id}, dMgr, dMgr.clusterDataProxy)
npujar03b018e2019-11-13 15:29:36 +0530265 if err := agent.start(context.TODO(), true); err != nil {
266 log.Warnw("failure-loading-device", log.Fields{"deviceID": id.Id})
267 agent.stop(context.TODO())
Stephane Barbariea75791c2019-01-24 10:58:06 -0500268 } else {
Stephane Barbarie1e28f3e2019-02-08 15:45:20 -0500269 dMgr.addDeviceAgentToMap(agent)
npujar03b018e2019-11-13 15:29:36 +0530270 reconciled++
Stephane Barbariea75791c2019-01-24 10:58:06 -0500271 }
272 } else {
npujar03b018e2019-11-13 15:29:36 +0530273 reconciled++
Stephane Barbariea75791c2019-01-24 10:58:06 -0500274 }
275 }
276 if toReconcile != reconciled {
277 res = status.Errorf(codes.DataLoss, "less-device-reconciled:%d/%d", reconciled, toReconcile)
278 }
279 } else {
280 res = status.Errorf(codes.InvalidArgument, "empty-list-of-ids")
281 }
282 sendResponse(ctx, ch, res)
283}
284
npujar03b018e2019-11-13 15:29:36 +0530285// ListDevicePorts returns ports details for a specific device
286func (dMgr *DeviceManager) ListDevicePorts(ctx context.Context, deviceID string) (*voltha.Ports, error) {
287 log.Debugw("ListDevicePorts", log.Fields{"deviceid": deviceID})
288 if agent := dMgr.getDeviceAgent(deviceID); agent != nil {
Stephane Barbariea75791c2019-01-24 10:58:06 -0500289 return agent.ListDevicePorts(ctx)
290 }
npujar03b018e2019-11-13 15:29:36 +0530291 return nil, status.Errorf(codes.NotFound, "%s", deviceID)
Stephane Barbariea75791c2019-01-24 10:58:06 -0500292
293}
294
npujar03b018e2019-11-13 15:29:36 +0530295// ListDevicePmConfigs returns PM config details for a specific device
296func (dMgr *DeviceManager) ListDevicePmConfigs(ctx context.Context, deviceID string) (*voltha.PmConfigs, error) {
297 log.Debugw("ListDevicePmConfigs", log.Fields{"deviceid": deviceID})
298 if agent := dMgr.getDeviceAgent(deviceID); agent != nil {
Stephane Barbariea75791c2019-01-24 10:58:06 -0500299 return agent.ListDevicePmConfigs(ctx)
300 }
npujar03b018e2019-11-13 15:29:36 +0530301 return nil, status.Errorf(codes.NotFound, "%s", deviceID)
Stephane Barbariea75791c2019-01-24 10:58:06 -0500302
303}
304
npujar03b018e2019-11-13 15:29:36 +0530305// ListDeviceFlows returns flow details for a specific device
306func (dMgr *DeviceManager) ListDeviceFlows(ctx context.Context, deviceID string) (*voltha.Flows, error) {
307 log.Debugw("ListDeviceFlows", log.Fields{"deviceid": deviceID})
308 if agent := dMgr.getDeviceAgent(deviceID); agent != nil {
Stephane Barbariea75791c2019-01-24 10:58:06 -0500309 return agent.ListDeviceFlows(ctx)
310 }
npujar03b018e2019-11-13 15:29:36 +0530311 return nil, status.Errorf(codes.NotFound, "%s", deviceID)
Stephane Barbariea75791c2019-01-24 10:58:06 -0500312}
313
npujar03b018e2019-11-13 15:29:36 +0530314// ListDeviceFlowGroups returns flow group details for a specific device
315func (dMgr *DeviceManager) ListDeviceFlowGroups(ctx context.Context, deviceID string) (*voltha.FlowGroups, error) {
316 log.Debugw("ListDeviceFlowGroups", log.Fields{"deviceid": deviceID})
317 if agent := dMgr.getDeviceAgent(deviceID); agent != nil {
Stephane Barbariea75791c2019-01-24 10:58:06 -0500318 return agent.ListDeviceFlowGroups(ctx)
319 }
npujar03b018e2019-11-13 15:29:36 +0530320 return nil, status.Errorf(codes.NotFound, "%s", deviceID)
Stephane Barbariea75791c2019-01-24 10:58:06 -0500321
322}
323
npujar03b018e2019-11-13 15:29:36 +0530324// GetImageDownloadStatus returns the download status of an image of a particular device
325func (dMgr *DeviceManager) GetImageDownloadStatus(ctx context.Context, deviceID string, imageName string) (*voltha.ImageDownload, error) {
326 log.Debugw("GetImageDownloadStatus", log.Fields{"deviceid": deviceID, "imagename": imageName})
327 if agent := dMgr.getDeviceAgent(deviceID); agent != nil {
Stephane Barbariea75791c2019-01-24 10:58:06 -0500328 return agent.GetImageDownloadStatus(ctx, imageName)
329 }
npujar03b018e2019-11-13 15:29:36 +0530330 return nil, status.Errorf(codes.NotFound, "%s", deviceID)
Stephane Barbariea75791c2019-01-24 10:58:06 -0500331
332}
333
npujar03b018e2019-11-13 15:29:36 +0530334// GetImageDownload return the download details for a specific image entry
335func (dMgr *DeviceManager) GetImageDownload(ctx context.Context, deviceID string, imageName string) (*voltha.ImageDownload, error) {
336 log.Debugw("GetImageDownload", log.Fields{"deviceid": deviceID, "imagename": imageName})
337 if agent := dMgr.getDeviceAgent(deviceID); agent != nil {
Stephane Barbariea75791c2019-01-24 10:58:06 -0500338 return agent.GetImageDownload(ctx, imageName)
339 }
npujar03b018e2019-11-13 15:29:36 +0530340 return nil, status.Errorf(codes.NotFound, "%s", deviceID)
Stephane Barbariea75791c2019-01-24 10:58:06 -0500341
342}
343
npujar03b018e2019-11-13 15:29:36 +0530344// ListImageDownloads returns all image downloads known to the system
345func (dMgr *DeviceManager) ListImageDownloads(ctx context.Context, deviceID string) (*voltha.ImageDownloads, error) {
346 log.Debugw("ListImageDownloads", log.Fields{"deviceid": deviceID})
347 if agent := dMgr.getDeviceAgent(deviceID); agent != nil {
Stephane Barbariea75791c2019-01-24 10:58:06 -0500348 return agent.ListImageDownloads(ctx)
349 }
npujar03b018e2019-11-13 15:29:36 +0530350 return nil, status.Errorf(codes.NotFound, "%s", deviceID)
Stephane Barbariea75791c2019-01-24 10:58:06 -0500351
352}
353
npujar03b018e2019-11-13 15:29:36 +0530354// GetImages returns all images for a specific device entry
355func (dMgr *DeviceManager) GetImages(ctx context.Context, deviceID string) (*voltha.Images, error) {
356 log.Debugw("GetImages", log.Fields{"deviceid": deviceID})
357 if agent := dMgr.getDeviceAgent(deviceID); agent != nil {
Stephane Barbariea75791c2019-01-24 10:58:06 -0500358 return agent.GetImages(ctx)
359 }
npujar03b018e2019-11-13 15:29:36 +0530360 return nil, status.Errorf(codes.NotFound, "%s", deviceID)
Stephane Barbariea75791c2019-01-24 10:58:06 -0500361
362}
363
364func (dMgr *DeviceManager) getParentDevice(childDevice *voltha.Device) *voltha.Device {
365 // Sanity check
366 if childDevice.Root {
367 // childDevice is the parent device
368 return childDevice
369 }
370 parentDevice, _ := dMgr.GetDevice(childDevice.ParentId)
371 return parentDevice
372}
Stephane Barbarie1e28f3e2019-02-08 15:45:20 -0500373
npujar03b018e2019-11-13 15:29:36 +0530374//getAllChildDeviceIDs is a helper method to get all the child device IDs from the device passed as parameter
375func (dMgr *DeviceManager) getAllChildDeviceIDs(parentDevice *voltha.Device) ([]string, error) {
376 log.Debugw("getAllChildDeviceIDs", log.Fields{"parentDeviceID": parentDevice.Id})
377 childDeviceIDs := make([]string, 0)
Stephane Barbarie1e28f3e2019-02-08 15:45:20 -0500378 if parentDevice != nil {
379 for _, port := range parentDevice.Ports {
380 for _, peer := range port.Peers {
npujar03b018e2019-11-13 15:29:36 +0530381 childDeviceIDs = append(childDeviceIDs, peer.DeviceId)
Stephane Barbarie1e28f3e2019-02-08 15:45:20 -0500382 }
383 }
384 }
npujar03b018e2019-11-13 15:29:36 +0530385 return childDeviceIDs, nil
Stephane Barbarie1e28f3e2019-02-08 15:45:20 -0500386}