blob: d9dacbc0531165db364c066c461bde33e7a06b1e [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"
khenaidoo92e62c52018-10-03 14:02:54 -040020 "reflect"
21 "sync"
22
khenaidoob9203542018-09-17 22:56:37 -040023 "github.com/gogo/protobuf/proto"
24 "github.com/opencord/voltha-go/common/log"
25 "github.com/opencord/voltha-go/db/model"
26 "github.com/opencord/voltha-go/protos/core_adapter"
27 "github.com/opencord/voltha-go/protos/voltha"
28 "google.golang.org/grpc/codes"
29 "google.golang.org/grpc/status"
khenaidoob9203542018-09-17 22:56:37 -040030)
31
32type DeviceAgent struct {
khenaidoo9a468962018-09-19 15:33:13 -040033 deviceId string
34 lastData *voltha.Device
35 adapterProxy *AdapterProxy
36 deviceMgr *DeviceManager
37 clusterDataProxy *model.Proxy
khenaidoo92e62c52018-10-03 14:02:54 -040038 deviceProxy *model.Proxy
khenaidoo9a468962018-09-19 15:33:13 -040039 exitChannel chan int
khenaidoo92e62c52018-10-03 14:02:54 -040040 lockDevice sync.RWMutex
khenaidoob9203542018-09-17 22:56:37 -040041}
42
khenaidoo9a468962018-09-19 15:33:13 -040043func newDeviceAgent(ap *AdapterProxy, device *voltha.Device, deviceMgr *DeviceManager, cdProxy *model.Proxy) *DeviceAgent {
khenaidoob9203542018-09-17 22:56:37 -040044 var agent DeviceAgent
khenaidoob9203542018-09-17 22:56:37 -040045 agent.adapterProxy = ap
khenaidoo92e62c52018-10-03 14:02:54 -040046 cloned := (proto.Clone(device)).(*voltha.Device)
47 cloned.Id = CreateDeviceId()
48 cloned.AdminState = voltha.AdminState_PREPROVISIONED
49 agent.deviceId = cloned.Id
50 agent.lastData = cloned
khenaidoob9203542018-09-17 22:56:37 -040051 agent.deviceMgr = deviceMgr
52 agent.exitChannel = make(chan int, 1)
khenaidoo9a468962018-09-19 15:33:13 -040053 agent.clusterDataProxy = cdProxy
khenaidoo92e62c52018-10-03 14:02:54 -040054 agent.lockDevice = sync.RWMutex{}
khenaidoob9203542018-09-17 22:56:37 -040055 return &agent
56}
57
58func (agent *DeviceAgent) start(ctx context.Context) {
khenaidoo92e62c52018-10-03 14:02:54 -040059 agent.lockDevice.Lock()
60 defer agent.lockDevice.Unlock()
khenaidoob9203542018-09-17 22:56:37 -040061 log.Debugw("starting-device-agent", log.Fields{"device": agent.lastData})
62 // Add the initial device to the local model
khenaidoo9a468962018-09-19 15:33:13 -040063 if added := agent.clusterDataProxy.Add("/devices", agent.lastData, ""); added == nil {
khenaidoob9203542018-09-17 22:56:37 -040064 log.Errorw("failed-to-add-device", log.Fields{"deviceId": agent.deviceId})
65 }
khenaidoo92e62c52018-10-03 14:02:54 -040066 agent.deviceProxy = agent.clusterDataProxy.Root.GetProxy("/devices/"+agent.deviceId, false)
67 //agent.deviceProxy = agent.clusterDataProxy.Root.Node.GetProxy("/", false)
68 agent.deviceProxy.RegisterCallback(model.POST_UPDATE, agent.processUpdate, nil)
khenaidoob9203542018-09-17 22:56:37 -040069 log.Debug("device-agent-started")
70}
71
72func (agent *DeviceAgent) Stop(ctx context.Context) {
khenaidoo92e62c52018-10-03 14:02:54 -040073 agent.lockDevice.Lock()
74 defer agent.lockDevice.Unlock()
khenaidoob9203542018-09-17 22:56:37 -040075 log.Debug("stopping-device-agent")
76 agent.exitChannel <- 1
77 log.Debug("device-agent-stopped")
78}
79
khenaidoo92e62c52018-10-03 14:02:54 -040080func (agent *DeviceAgent) getDevice() (*voltha.Device, error) {
81 agent.lockDevice.Lock()
82 defer agent.lockDevice.Unlock()
83 if device := agent.clusterDataProxy.Get("/devices/"+agent.deviceId, 1, false, ""); device != nil {
84 if d, ok := device.(*voltha.Device); ok {
85 cloned := proto.Clone(d).(*voltha.Device)
86 return cloned, nil
87 }
88 }
89 return nil, status.Errorf(codes.NotFound, "device-%s", agent.deviceId)
90}
91
92//getDeviceWithoutLock is a helper function to be used ONLY by any device agent function AFTER it has acquired the device lock.
93// This function is meant so that we do not have duplicate code all over the device agent functions
94func (agent *DeviceAgent) getDeviceWithoutLock() (*voltha.Device, error) {
95 if device := agent.clusterDataProxy.Get("/devices/"+agent.deviceId, 1, false, ""); device != nil {
96 if d, ok := device.(*voltha.Device); ok {
97 cloned := proto.Clone(d).(*voltha.Device)
98 return cloned, nil
99 }
100 }
101 return nil, status.Errorf(codes.NotFound, "device-%s", agent.deviceId)
102}
103
khenaidoob9203542018-09-17 22:56:37 -0400104func (agent *DeviceAgent) enableDevice(ctx context.Context) error {
khenaidoo92e62c52018-10-03 14:02:54 -0400105 agent.lockDevice.Lock()
106 defer agent.lockDevice.Unlock()
107 log.Debugw("enableDevice", log.Fields{"id": agent.deviceId})
108 if device, err := agent.getDeviceWithoutLock(); err != nil {
khenaidoob9203542018-09-17 22:56:37 -0400109 return status.Errorf(codes.NotFound, "%s", agent.deviceId)
110 } else {
khenaidoo92e62c52018-10-03 14:02:54 -0400111 if device.AdminState == voltha.AdminState_ENABLED {
112 log.Debugw("device-already-enabled", log.Fields{"id": agent.deviceId})
113 //TODO: Needs customized error message
114 return nil
115 }
116 // Verify whether we need to adopt the device the first time
117 // TODO: A state machine for these state transitions would be better (we just have to handle
118 // a limited set of states now or it may be an overkill)
119 if device.AdminState == voltha.AdminState_PREPROVISIONED {
120 // First send the request to an Adapter and wait for a response
121 if err := agent.adapterProxy.AdoptDevice(ctx, device); err != nil {
122 log.Debugw("adoptDevice-error", log.Fields{"id": agent.lastData.Id, "error": err})
khenaidoob9203542018-09-17 22:56:37 -0400123 return err
124 }
khenaidoo92e62c52018-10-03 14:02:54 -0400125 } else {
126 // First send the request to an Adapter and wait for a response
127 if err := agent.adapterProxy.ReEnableDevice(ctx, device); err != nil {
128 log.Debugw("renableDevice-error", log.Fields{"id": agent.lastData.Id, "error": err})
129 return err
130 }
131 }
132 // Received an Ack (no error found above). Now update the device in the model to the expected state
133 cloned := proto.Clone(device).(*voltha.Device)
134 cloned.AdminState = voltha.AdminState_ENABLED
135 cloned.OperStatus = voltha.OperStatus_ACTIVATING
136 if afterUpdate := agent.clusterDataProxy.Update("/devices/"+agent.deviceId, cloned, false, ""); afterUpdate == nil {
137 return status.Errorf(codes.Internal, "failed-update-device:%s", agent.deviceId)
khenaidoob9203542018-09-17 22:56:37 -0400138 }
139 }
140 return nil
141}
142
khenaidoo92e62c52018-10-03 14:02:54 -0400143func (agent *DeviceAgent) disableDevice(ctx context.Context) error {
144 agent.lockDevice.Lock()
145 //defer agent.lockDevice.Unlock()
146 log.Debugw("disableDevice", log.Fields{"id": agent.deviceId})
147 // Get the most up to date the device info
148 if device, err := agent.getDeviceWithoutLock(); err != nil {
149 return status.Errorf(codes.NotFound, "%s", agent.deviceId)
150 } else {
151 if device.AdminState == voltha.AdminState_DISABLED {
152 log.Debugw("device-already-disabled", log.Fields{"id": agent.deviceId})
153 //TODO: Needs customized error message
154 agent.lockDevice.Unlock()
155 return nil
156 }
157 // First send the request to an Adapter and wait for a response
158 if err := agent.adapterProxy.DisableDevice(ctx, device); err != nil {
159 log.Debugw("disableDevice-error", log.Fields{"id": agent.lastData.Id, "error": err})
160 agent.lockDevice.Unlock()
161 return err
162 }
163 // Received an Ack (no error found above). Now update the device in the model to the expected state
164 cloned := proto.Clone(device).(*voltha.Device)
165 cloned.AdminState = voltha.AdminState_DISABLED
166 // Set the state of all ports on that device to disable
167 for _, port := range cloned.Ports {
168 port.AdminState = voltha.AdminState_DISABLED
169 port.OperStatus = voltha.OperStatus_UNKNOWN
170 }
171 if afterUpdate := agent.clusterDataProxy.Update("/devices/"+agent.deviceId, cloned, false, ""); afterUpdate == nil {
172 agent.lockDevice.Unlock()
173 return status.Errorf(codes.Internal, "failed-update-device:%s", agent.deviceId)
174 }
175 agent.lockDevice.Unlock()
176 //TODO: callback will be invoked to handle this state change
177 //For now force the state transition to happen
178 if err := agent.deviceMgr.processTransition(device, cloned); err != nil {
179 log.Warnw("process-transition-error", log.Fields{"deviceid": device.Id, "error": err})
180 return err
181 }
182 }
183 return nil
184}
185
186func (agent *DeviceAgent) getPorts(ctx context.Context, portType voltha.Port_PortType) *voltha.Ports {
187 log.Debugw("getPorts", log.Fields{"id": agent.deviceId, "portType": portType})
khenaidoob9203542018-09-17 22:56:37 -0400188 ports := &voltha.Ports{}
189 if device, _ := agent.deviceMgr.getDevice(agent.deviceId); device != nil {
190 for _, port := range device.Ports {
khenaidoo92e62c52018-10-03 14:02:54 -0400191 if port.Type == portType {
khenaidoob9203542018-09-17 22:56:37 -0400192 ports.Items = append(ports.Items, port)
193 }
194 }
195 }
196 return ports
197}
198
199func (agent *DeviceAgent) getSwitchCapability(ctx context.Context) (*core_adapter.SwitchCapability, error) {
200 log.Debugw("getSwitchCapability", log.Fields{"deviceId": agent.deviceId})
201 if device, err := agent.deviceMgr.getDevice(agent.deviceId); device == nil {
202 return nil, err
203 } else {
204 var switchCap *core_adapter.SwitchCapability
205 var err error
206 if switchCap, err = agent.adapterProxy.GetOfpDeviceInfo(ctx, device); err != nil {
207 log.Debugw("getSwitchCapability-error", log.Fields{"id": device.Id, "error": err})
208 return nil, err
209 }
210 return switchCap, nil
211 }
212}
213
214func (agent *DeviceAgent) getPortCapability(ctx context.Context, portNo uint32) (*core_adapter.PortCapability, error) {
215 log.Debugw("getPortCapability", log.Fields{"deviceId": agent.deviceId})
216 if device, err := agent.deviceMgr.getDevice(agent.deviceId); device == nil {
217 return nil, err
218 } else {
219 var portCap *core_adapter.PortCapability
220 var err error
221 if portCap, err = agent.adapterProxy.GetOfpPortInfo(ctx, device, portNo); err != nil {
222 log.Debugw("getPortCapability-error", log.Fields{"id": device.Id, "error": err})
223 return nil, err
224 }
225 return portCap, nil
226 }
227}
228
khenaidoo92e62c52018-10-03 14:02:54 -0400229func (agent *DeviceAgent) processUpdate(args ...interface{}) interface{} {
230 log.Debug("!!!!!!!!!!!!!!!!!!!!!!!!!")
231 log.Debugw("processUpdate", log.Fields{"deviceId": agent.deviceId, "args": args})
232 return nil
233}
234
khenaidoob9203542018-09-17 22:56:37 -0400235func (agent *DeviceAgent) updateDevice(device *voltha.Device) error {
khenaidoo92e62c52018-10-03 14:02:54 -0400236 agent.lockDevice.Lock()
237 //defer agent.lockDevice.Unlock()
khenaidoob9203542018-09-17 22:56:37 -0400238 log.Debugw("updateDevice", log.Fields{"deviceId": device.Id})
239 // Get the dev info from the model
khenaidoo92e62c52018-10-03 14:02:54 -0400240 if storedData, err := agent.getDeviceWithoutLock(); err != nil {
241 agent.lockDevice.Unlock()
khenaidoob9203542018-09-17 22:56:37 -0400242 return status.Errorf(codes.NotFound, "%s", device.Id)
243 } else {
244 // store the changed data
khenaidoo92e62c52018-10-03 14:02:54 -0400245 cloned := proto.Clone(device).(*voltha.Device)
khenaidoo9a468962018-09-19 15:33:13 -0400246 afterUpdate := agent.clusterDataProxy.Update("/devices/"+device.Id, cloned, false, "")
khenaidoo92e62c52018-10-03 14:02:54 -0400247 agent.lockDevice.Unlock()
khenaidoob9203542018-09-17 22:56:37 -0400248 if afterUpdate == nil {
249 return status.Errorf(codes.Internal, "%s", device.Id)
250 }
251 // Perform the state transition
252 if err := agent.deviceMgr.processTransition(storedData, cloned); err != nil {
253 log.Warnw("process-transition-error", log.Fields{"deviceid": device.Id, "error": err})
254 return err
255 }
256 return nil
257 }
258}
259
khenaidoo92e62c52018-10-03 14:02:54 -0400260func (agent *DeviceAgent) updateDeviceStatus(operStatus voltha.OperStatus_OperStatus, connStatus voltha.ConnectStatus_ConnectStatus) error {
261 agent.lockDevice.Lock()
262 //defer agent.lockDevice.Unlock()
khenaidoob9203542018-09-17 22:56:37 -0400263 // Work only on latest data
khenaidoo92e62c52018-10-03 14:02:54 -0400264 if storeDevice, err := agent.getDeviceWithoutLock(); err != nil {
265 agent.lockDevice.Unlock()
khenaidoob9203542018-09-17 22:56:37 -0400266 return status.Errorf(codes.NotFound, "%s", agent.deviceId)
267 } else {
268 // clone the device
khenaidoo92e62c52018-10-03 14:02:54 -0400269 cloned := proto.Clone(storeDevice).(*voltha.Device)
270 // Ensure the enums passed in are valid - they will be invalid if they are not set when this function is invoked
271 if s, ok := voltha.ConnectStatus_ConnectStatus_value[connStatus.String()]; ok {
272 log.Debugw("updateDeviceStatus-conn", log.Fields{"ok": ok, "val": s})
273 cloned.ConnectStatus = connStatus
khenaidoob9203542018-09-17 22:56:37 -0400274 }
khenaidoo92e62c52018-10-03 14:02:54 -0400275 if s, ok := voltha.OperStatus_OperStatus_value[operStatus.String()]; ok {
276 log.Debugw("updateDeviceStatus-oper", log.Fields{"ok": ok, "val": s})
277 cloned.OperStatus = operStatus
khenaidoob9203542018-09-17 22:56:37 -0400278 }
khenaidoo92e62c52018-10-03 14:02:54 -0400279 log.Debugw("updateDeviceStatus", log.Fields{"deviceId": cloned.Id, "operStatus": cloned.OperStatus, "connectStatus": cloned.ConnectStatus})
khenaidoob9203542018-09-17 22:56:37 -0400280 // Store the device
khenaidoo92e62c52018-10-03 14:02:54 -0400281 if afterUpdate := agent.clusterDataProxy.Update("/devices/"+agent.deviceId, cloned, false, ""); afterUpdate == nil {
282 agent.lockDevice.Unlock()
khenaidoob9203542018-09-17 22:56:37 -0400283 return status.Errorf(codes.Internal, "%s", agent.deviceId)
284 }
khenaidoo92e62c52018-10-03 14:02:54 -0400285 agent.lockDevice.Unlock()
khenaidoob9203542018-09-17 22:56:37 -0400286 // Perform the state transition
khenaidoo92e62c52018-10-03 14:02:54 -0400287 if err := agent.deviceMgr.processTransition(storeDevice, cloned); err != nil {
288 log.Warnw("process-transition-error", log.Fields{"deviceid": agent.deviceId, "error": err})
289 return err
290 }
291 return nil
292 }
293}
294
295func (agent *DeviceAgent) updatePortState(portType voltha.Port_PortType, portNo uint32, operStatus voltha.OperStatus_OperStatus) error {
296 agent.lockDevice.Lock()
297 //defer agent.lockDevice.Unlock()
298 // Work only on latest data
299 // TODO: Get list of ports from device directly instead of the entire device
300 if storeDevice, err := agent.getDeviceWithoutLock(); err != nil {
301 agent.lockDevice.Unlock()
302 return status.Errorf(codes.NotFound, "%s", agent.deviceId)
303 } else {
304 // clone the device
305 cloned := proto.Clone(storeDevice).(*voltha.Device)
306 // Ensure the enums passed in are valid - they will be invalid if they are not set when this function is invoked
307 if _, ok := voltha.Port_PortType_value[portType.String()]; !ok {
308 agent.lockDevice.Unlock()
309 return status.Errorf(codes.InvalidArgument, "%s", portType)
310 }
311 for _, port := range cloned.Ports {
312 if port.Type == portType && port.PortNo == portNo {
313 port.OperStatus = operStatus
314 // Set the admin status to ENABLED if the operational status is ACTIVE
315 // TODO: Set by northbound system?
316 if operStatus == voltha.OperStatus_ACTIVE {
317 port.AdminState = voltha.AdminState_ENABLED
318 }
319 break
320 }
321 }
322 log.Debugw("portStatusUpdate", log.Fields{"deviceId": cloned.Id})
323 // Store the device
324 if afterUpdate := agent.clusterDataProxy.Update("/devices/"+agent.deviceId, cloned, false, ""); afterUpdate == nil {
325 agent.lockDevice.Unlock()
326 return status.Errorf(codes.Internal, "%s", agent.deviceId)
327 }
328 agent.lockDevice.Unlock()
329 // Perform the state transition
330 if err := agent.deviceMgr.processTransition(storeDevice, cloned); err != nil {
khenaidoob9203542018-09-17 22:56:37 -0400331 log.Warnw("process-transition-error", log.Fields{"deviceid": agent.deviceId, "error": err})
332 return err
333 }
334 return nil
335 }
336}
337
338func (agent *DeviceAgent) updatePmConfigs(pmConfigs *voltha.PmConfigs) error {
khenaidoo92e62c52018-10-03 14:02:54 -0400339 agent.lockDevice.Lock()
340 defer agent.lockDevice.Unlock()
khenaidoob9203542018-09-17 22:56:37 -0400341 log.Debug("updatePmConfigs")
342 // Work only on latest data
khenaidoo92e62c52018-10-03 14:02:54 -0400343 if storeDevice, err := agent.getDeviceWithoutLock(); err != nil {
khenaidoob9203542018-09-17 22:56:37 -0400344 return status.Errorf(codes.NotFound, "%s", agent.deviceId)
345 } else {
346 // clone the device
khenaidoo92e62c52018-10-03 14:02:54 -0400347 cloned := proto.Clone(storeDevice).(*voltha.Device)
348 cloned.PmConfigs = proto.Clone(pmConfigs).(*voltha.PmConfigs)
khenaidoob9203542018-09-17 22:56:37 -0400349 // Store the device
khenaidoo92e62c52018-10-03 14:02:54 -0400350 afterUpdate := agent.clusterDataProxy.Update("/devices/"+agent.deviceId, cloned, false, "")
khenaidoob9203542018-09-17 22:56:37 -0400351 if afterUpdate == nil {
352 return status.Errorf(codes.Internal, "%s", agent.deviceId)
353 }
354 return nil
355 }
356}
357
358func (agent *DeviceAgent) addPort(port *voltha.Port) error {
khenaidoo92e62c52018-10-03 14:02:54 -0400359 agent.lockDevice.Lock()
360 defer agent.lockDevice.Unlock()
361 log.Debugw("addPort", log.Fields{"deviceId": agent.deviceId})
khenaidoob9203542018-09-17 22:56:37 -0400362 // Work only on latest data
khenaidoo92e62c52018-10-03 14:02:54 -0400363 if storeDevice, err := agent.getDeviceWithoutLock(); err != nil {
khenaidoob9203542018-09-17 22:56:37 -0400364 return status.Errorf(codes.NotFound, "%s", agent.deviceId)
365 } else {
366 // clone the device
khenaidoo92e62c52018-10-03 14:02:54 -0400367 cloned := proto.Clone(storeDevice).(*voltha.Device)
khenaidoob9203542018-09-17 22:56:37 -0400368 if cloned.Ports == nil {
369 // First port
khenaidoo92e62c52018-10-03 14:02:54 -0400370 log.Debugw("addPort-first-port-to-add", log.Fields{"deviceId": agent.deviceId})
khenaidoob9203542018-09-17 22:56:37 -0400371 cloned.Ports = make([]*voltha.Port, 0)
372 }
khenaidoo92e62c52018-10-03 14:02:54 -0400373 cp := proto.Clone(port).(*voltha.Port)
374 // Set the admin state of the port to ENABLE if the operational state is ACTIVE
375 // TODO: Set by northbound system?
376 if cp.OperStatus == voltha.OperStatus_ACTIVE {
377 cp.AdminState = voltha.AdminState_ENABLED
378 }
379 cloned.Ports = append(cloned.Ports, cp)
khenaidoob9203542018-09-17 22:56:37 -0400380 // Store the device
khenaidoo92e62c52018-10-03 14:02:54 -0400381 afterUpdate := agent.clusterDataProxy.Update("/devices/"+agent.deviceId, cloned, false, "")
382 if afterUpdate == nil {
383 return status.Errorf(codes.Internal, "%s", agent.deviceId)
384 }
385 return nil
386 }
387}
388
389func (agent *DeviceAgent) addPeerPort(port *voltha.Port_PeerPort) error {
390 agent.lockDevice.Lock()
391 defer agent.lockDevice.Unlock()
392 log.Debug("addPeerPort")
393 // Work only on latest data
394 if storeDevice, err := agent.getDeviceWithoutLock(); err != nil {
395 return status.Errorf(codes.NotFound, "%s", agent.deviceId)
396 } else {
397 // clone the device
398 cloned := proto.Clone(storeDevice).(*voltha.Device)
399 // Get the peer port on the device based on the port no
400 for _, peerPort := range cloned.Ports {
401 if peerPort.PortNo == port.PortNo { // found port
402 cp := proto.Clone(port).(*voltha.Port_PeerPort)
403 peerPort.Peers = append(peerPort.Peers, cp)
404 log.Debugw("found-peer", log.Fields{"portNo": port.PortNo, "deviceId": agent.deviceId})
405 break
406 }
407 }
408 // Store the device
409 afterUpdate := agent.clusterDataProxy.Update("/devices/"+agent.deviceId, cloned, false, "")
khenaidoob9203542018-09-17 22:56:37 -0400410 if afterUpdate == nil {
411 return status.Errorf(codes.Internal, "%s", agent.deviceId)
412 }
413 return nil
414 }
415}
416
417// TODO: A generic device update by attribute
418func (agent *DeviceAgent) updateDeviceAttribute(name string, value interface{}) {
khenaidoo92e62c52018-10-03 14:02:54 -0400419 agent.lockDevice.Lock()
420 defer agent.lockDevice.Unlock()
khenaidoob9203542018-09-17 22:56:37 -0400421 if value == nil {
422 return
423 }
424 var storeDevice *voltha.Device
425 var err error
khenaidoo92e62c52018-10-03 14:02:54 -0400426 if storeDevice, err = agent.getDeviceWithoutLock(); err != nil {
khenaidoob9203542018-09-17 22:56:37 -0400427 return
428 }
429 updated := false
430 s := reflect.ValueOf(storeDevice).Elem()
431 if s.Kind() == reflect.Struct {
432 // exported field
433 f := s.FieldByName(name)
434 if f.IsValid() && f.CanSet() {
435 switch f.Kind() {
436 case reflect.String:
437 f.SetString(value.(string))
438 updated = true
439 case reflect.Uint32:
440 f.SetUint(uint64(value.(uint32)))
441 updated = true
442 case reflect.Bool:
443 f.SetBool(value.(bool))
444 updated = true
445 }
446 }
447 }
khenaidoo92e62c52018-10-03 14:02:54 -0400448 log.Debugw("update-field-status", log.Fields{"deviceId": storeDevice.Id, "name": name, "updated": updated})
khenaidoob9203542018-09-17 22:56:37 -0400449 // Save the data
khenaidoo92e62c52018-10-03 14:02:54 -0400450 cloned := proto.Clone(storeDevice).(*voltha.Device)
451 if afterUpdate := agent.clusterDataProxy.Update("/devices/"+agent.deviceId, cloned, false, ""); afterUpdate == nil {
khenaidoob9203542018-09-17 22:56:37 -0400452 log.Warnw("attribute-update-failed", log.Fields{"attribute": name, "value": value})
453 }
454 return
455}