blob: 1a83cb261e8982e8dec2698968e482202a5e95bf [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 */
npujar1d86a522019-11-14 17:11:16 +053016
Kent Hagerman2b216042020-04-03 18:28:56 -040017package device
khenaidoob9203542018-09-17 22:56:37 -040018
19import (
20 "context"
Matteo Scandolo360605d2019-11-05 18:29:17 -080021 "encoding/hex"
Kent Hagerman4f355f52020-03-30 16:01:33 -040022 "errors"
khenaidoo3ab34882019-05-02 21:33:30 -040023 "fmt"
Mahir Gunyelb0343bf2021-05-11 14:14:26 -070024 "reflect"
25 "sync"
26 "time"
27
khenaidood948f772021-08-11 17:49:24 -040028 "github.com/opencord/voltha-protos/v5/go/adapter_services"
29 "github.com/opencord/voltha-protos/v5/go/core"
30
Maninder0aabf0c2021-03-17 14:55:14 +053031 "github.com/cenkalti/backoff/v3"
Maninder9a1bc0d2020-10-26 11:34:02 +053032 "github.com/gogo/protobuf/proto"
Maninder9a1bc0d2020-10-26 11:34:02 +053033 "github.com/golang/protobuf/ptypes/empty"
Maninder0aabf0c2021-03-17 14:55:14 +053034 "github.com/opencord/voltha-go/rw_core/config"
Maninder9a1bc0d2020-10-26 11:34:02 +053035 "google.golang.org/grpc/codes"
36 "google.golang.org/grpc/status"
Mahir Gunyeladdb66a2020-04-29 18:08:50 -070037
Himani Chawla2ba1c9c2020-10-07 13:19:03 +053038 "github.com/opencord/voltha-go/db/model"
Kent Hagerman2b216042020-04-03 18:28:56 -040039 "github.com/opencord/voltha-go/rw_core/core/adapter"
Mahir Gunyel03de0d32020-06-03 01:36:59 -070040 "github.com/opencord/voltha-go/rw_core/core/device/flow"
41 "github.com/opencord/voltha-go/rw_core/core/device/group"
Kent Hagerman2a07b862020-06-19 15:23:07 -040042 "github.com/opencord/voltha-go/rw_core/core/device/port"
Himani Chawla2ba1c9c2020-10-07 13:19:03 +053043 "github.com/opencord/voltha-go/rw_core/core/device/transientstate"
Scott Bakerb671a862019-10-24 10:53:40 -070044 coreutils "github.com/opencord/voltha-go/rw_core/utils"
khenaidood948f772021-08-11 17:49:24 -040045 "github.com/opencord/voltha-lib-go/v7/pkg/log"
46 "github.com/opencord/voltha-protos/v5/go/common"
47 "github.com/opencord/voltha-protos/v5/go/extension"
48 ic "github.com/opencord/voltha-protos/v5/go/inter_container"
49 ofp "github.com/opencord/voltha-protos/v5/go/openflow_13"
50 "github.com/opencord/voltha-protos/v5/go/voltha"
khenaidoob9203542018-09-17 22:56:37 -040051)
52
khenaidood948f772021-08-11 17:49:24 -040053var errReconcileAborted = errors.New("reconcile aborted")
54var errContextExpired = errors.New("context expired")
55
Kent Hagerman2b216042020-04-03 18:28:56 -040056// Agent represents device agent attributes
57type Agent struct {
Maninder0aabf0c2021-03-17 14:55:14 +053058 deviceID string
59 parentID string
60 deviceType string
khenaidood948f772021-08-11 17:49:24 -040061 adapterEndpoint string
Maninder0aabf0c2021-03-17 14:55:14 +053062 isRootDevice bool
Maninder0aabf0c2021-03-17 14:55:14 +053063 adapterMgr *adapter.Manager
64 deviceMgr *Manager
65 dbProxy *model.Proxy
66 exitChannel chan int
67 device *voltha.Device
68 requestQueue *coreutils.RequestQueue
khenaidood948f772021-08-11 17:49:24 -040069 internalTimeout time.Duration
70 rpcTimeout time.Duration
Maninder0aabf0c2021-03-17 14:55:14 +053071 startOnce sync.Once
72 stopOnce sync.Once
73 stopped bool
74 stopReconciling chan int
75 stopReconcilingMutex sync.RWMutex
76 config *config.RWCoreFlags
Mahir Gunyel03de0d32020-06-03 01:36:59 -070077
khenaidoo7585a962021-06-10 16:15:38 -040078 flowCache *flow.Cache
79 groupCache *group.Cache
Himani Chawla2ba1c9c2020-10-07 13:19:03 +053080 portLoader *port.Loader
81 transientStateLoader *transientstate.Loader
khenaidoob9203542018-09-17 22:56:37 -040082}
83
Kent Hagerman2b216042020-04-03 18:28:56 -040084//newAgent creates a new device agent. The device will be initialized when start() is called.
khenaidood948f772021-08-11 17:49:24 -040085func newAgent(device *voltha.Device, deviceMgr *Manager, dbPath *model.Path, deviceProxy *model.Proxy, internalTimeout, rpcTimeout time.Duration) *Agent {
Kent Hagerman2a07b862020-06-19 15:23:07 -040086 deviceID := device.Id
87 if deviceID == "" {
88 deviceID = coreutils.CreateDeviceID()
Stephane Barbarie1ab43272018-12-08 21:42:13 -050089 }
Scott Baker80678602019-11-14 16:57:36 -080090
Kent Hagerman2a07b862020-06-19 15:23:07 -040091 return &Agent{
Himani Chawla2ba1c9c2020-10-07 13:19:03 +053092 deviceID: deviceID,
Himani Chawla2ba1c9c2020-10-07 13:19:03 +053093 isRootDevice: device.Root,
94 parentID: device.ParentId,
95 deviceType: device.Type,
khenaidood948f772021-08-11 17:49:24 -040096 adapterEndpoint: device.AdapterEndpoint,
Himani Chawla2ba1c9c2020-10-07 13:19:03 +053097 deviceMgr: deviceMgr,
98 adapterMgr: deviceMgr.adapterMgr,
99 exitChannel: make(chan int, 1),
100 dbProxy: deviceProxy,
khenaidood948f772021-08-11 17:49:24 -0400101 internalTimeout: internalTimeout,
102 rpcTimeout: rpcTimeout,
Himani Chawla2ba1c9c2020-10-07 13:19:03 +0530103 device: proto.Clone(device).(*voltha.Device),
104 requestQueue: coreutils.NewRequestQueue(),
Maninder0aabf0c2021-03-17 14:55:14 +0530105 config: deviceMgr.config,
khenaidoo7585a962021-06-10 16:15:38 -0400106 flowCache: flow.NewCache(),
107 groupCache: group.NewCache(),
Himani Chawla2ba1c9c2020-10-07 13:19:03 +0530108 portLoader: port.NewLoader(dbPath.SubPath("ports").Proxy(deviceID)),
109 transientStateLoader: transientstate.NewLoader(dbPath.SubPath("core").Proxy("transientstate"), deviceID),
Kent Hagerman2a07b862020-06-19 15:23:07 -0400110 }
khenaidoob9203542018-09-17 22:56:37 -0400111}
112
khenaidoo442e7c72020-03-10 16:13:48 -0400113// start() saves the device to the data model and registers for callbacks on that device if deviceToCreate!=nil.
114// Otherwise, it will load the data from the dB and setup the necessary callbacks and proxies. Returns the device that
Scott Baker80678602019-11-14 16:57:36 -0800115// was started.
khenaidoo7585a962021-06-10 16:15:38 -0400116func (agent *Agent) start(ctx context.Context, deviceExist bool, deviceToCreate *voltha.Device) (*voltha.Device, error) {
khenaidoo442e7c72020-03-10 16:13:48 -0400117 needToStart := false
118 if agent.startOnce.Do(func() { needToStart = true }); !needToStart {
Kent Hagermancba2f302020-07-28 13:37:36 -0400119 return agent.getDeviceReadOnly(ctx)
khenaidoo442e7c72020-03-10 16:13:48 -0400120 }
121 var startSucceeded bool
122 defer func() {
123 if !startSucceeded {
124 if err := agent.stop(ctx); err != nil {
Rohan Agrawal31f21802020-06-12 05:38:46 +0000125 logger.Errorw(ctx, "failed-to-cleanup-after-unsuccessful-start", log.Fields{"device-id": agent.deviceID, "error": err})
khenaidoo442e7c72020-03-10 16:13:48 -0400126 }
127 }
128 }()
khenaidoo7585a962021-06-10 16:15:38 -0400129 if deviceExist {
130 device := deviceToCreate
131 if device == nil {
132 // Load from dB
133 device = &voltha.Device{}
134 have, err := agent.dbProxy.Get(ctx, agent.deviceID, device)
135 if err != nil {
136 return nil, err
137 } else if !have {
138 return nil, status.Errorf(codes.NotFound, "device-%s", agent.deviceID)
139 }
khenaidood948f772021-08-11 17:49:24 -0400140 logger.Infow(ctx, "device-loaded-from-db", log.Fields{"device-id": agent.deviceID, "adapter-endpoint": device.AdapterEndpoint, "type": device.Type})
Thomas Lee Se5a44012019-11-07 20:32:24 +0530141 }
khenaidood948f772021-08-11 17:49:24 -0400142 agent.deviceType = device.Type
143 agent.adapterEndpoint = device.AdapterEndpoint
Kent Hagerman4f355f52020-03-30 16:01:33 -0400144 agent.device = proto.Clone(device).(*voltha.Device)
khenaidoo7585a962021-06-10 16:15:38 -0400145 // load the ports from KV to cache
Kent Hagerman2a07b862020-06-19 15:23:07 -0400146 agent.portLoader.Load(ctx)
Himani Chawla2ba1c9c2020-10-07 13:19:03 +0530147 agent.transientStateLoader.Load(ctx)
khenaidoo297cd252019-02-07 22:10:23 -0500148 } else {
Scott Baker80678602019-11-14 16:57:36 -0800149 // Create a new device
Maninder9a1bc0d2020-10-26 11:34:02 +0530150 var desc string
khenaidood948f772021-08-11 17:49:24 -0400151 var err error
Maninder9a1bc0d2020-10-26 11:34:02 +0530152 prevState := common.AdminState_UNKNOWN
153 currState := common.AdminState_UNKNOWN
khenaidood948f772021-08-11 17:49:24 -0400154 requestStatus := &common.OperationResp{Code: common.OperationResp_OPERATION_FAILURE}
Maninder9a1bc0d2020-10-26 11:34:02 +0530155
khenaidood948f772021-08-11 17:49:24 -0400156 defer func() { agent.logDeviceUpdate(ctx, &prevState, &currState, requestStatus, err, desc) }()
Maninder9a1bc0d2020-10-26 11:34:02 +0530157
Kent Hagermanf5a67352020-04-30 15:15:26 -0400158 // Assumption is that AdminState, FlowGroups, and Flows are uninitialized since this
159 // is a new device, so populate them here before passing the device to ldProxy.Set.
Kent Hagerman2b216042020-04-03 18:28:56 -0400160 // agent.deviceId will also have been set during newAgent().
khenaidoo7585a962021-06-10 16:15:38 -0400161 device := (proto.Clone(deviceToCreate)).(*voltha.Device)
npujar1d86a522019-11-14 17:11:16 +0530162 device.Id = agent.deviceID
Scott Baker80678602019-11-14 16:57:36 -0800163 device.AdminState = voltha.AdminState_PREPROVISIONED
Maninder9a1bc0d2020-10-26 11:34:02 +0530164 currState = device.AdminState
Scott Baker80678602019-11-14 16:57:36 -0800165 if !deviceToCreate.GetRoot() && deviceToCreate.ProxyAddress != nil {
166 // Set the default vlan ID to the one specified by the parent adapter. It can be
167 // overwritten by the child adapter during a device update request
168 device.Vlan = deviceToCreate.ProxyAddress.ChannelId
169 }
170
khenaidood948f772021-08-11 17:49:24 -0400171 // Save the device to the model
172 if err = agent.dbProxy.Set(ctx, agent.deviceID, device); err != nil {
173 err = status.Errorf(codes.Aborted, "failed-adding-device-%s: %s", agent.deviceID, err)
174 return nil, err
khenaidoo297cd252019-02-07 22:10:23 -0500175 }
Mahir Gunyelb0343bf2021-05-11 14:14:26 -0700176 _ = agent.deviceMgr.Agent.SendDeviceStateChangeEvent(ctx, device.OperStatus, device.ConnectStatus, prevState, device, time.Now().Unix())
khenaidood948f772021-08-11 17:49:24 -0400177 requestStatus.Code = common.OperationResp_OPERATION_SUCCESS
khenaidoo442e7c72020-03-10 16:13:48 -0400178 agent.device = device
khenaidoob9203542018-09-17 22:56:37 -0400179 }
khenaidoo442e7c72020-03-10 16:13:48 -0400180 startSucceeded = true
Rohan Agrawalcf12f202020-08-03 04:42:01 +0000181 log.EnrichSpan(ctx, log.Fields{"device-id": agent.deviceID})
Rohan Agrawal31f21802020-06-12 05:38:46 +0000182 logger.Debugw(ctx, "device-agent-started", log.Fields{"device-id": agent.deviceID})
khenaidoo442e7c72020-03-10 16:13:48 -0400183
Kent Hagermancba2f302020-07-28 13:37:36 -0400184 return agent.getDeviceReadOnly(ctx)
khenaidoob9203542018-09-17 22:56:37 -0400185}
186
khenaidoo4d4802d2018-10-04 21:59:49 -0400187// stop stops the device agent. Not much to do for now
Kent Hagerman2b216042020-04-03 18:28:56 -0400188func (agent *Agent) stop(ctx context.Context) error {
khenaidoo442e7c72020-03-10 16:13:48 -0400189 needToStop := false
190 if agent.stopOnce.Do(func() { needToStop = true }); !needToStop {
191 return nil
192 }
193 if err := agent.requestQueue.WaitForGreenLight(ctx); err != nil {
194 return err
195 }
196 defer agent.requestQueue.RequestComplete()
khenaidoo49085352020-01-13 19:15:43 -0500197
Himani Chawlab4c25912020-11-12 17:16:38 +0530198 logger.Infow(ctx, "stopping-device-agent", log.Fields{"device-id": agent.deviceID, "parent-id": agent.parentID})
Himani Chawla2ba1c9c2020-10-07 13:19:03 +0530199 // Remove the device transient loader
200 if err := agent.deleteTransientState(ctx); err != nil {
201 return err
202 }
khenaidoo0a822f92019-05-08 15:15:57 -0400203 // Remove the device from the KV store
Kent Hagermanf5a67352020-04-30 15:15:26 -0400204 if err := agent.dbProxy.Remove(ctx, agent.deviceID); err != nil {
khenaidoo442e7c72020-03-10 16:13:48 -0400205 return err
Thomas Lee Se5a44012019-11-07 20:32:24 +0530206 }
khenaidoo442e7c72020-03-10 16:13:48 -0400207
khenaidoo442e7c72020-03-10 16:13:48 -0400208 close(agent.exitChannel)
209
210 agent.stopped = true
211
Rohan Agrawal31f21802020-06-12 05:38:46 +0000212 logger.Infow(ctx, "device-agent-stopped", log.Fields{"device-id": agent.deviceID, "parent-id": agent.parentID})
khenaidoo442e7c72020-03-10 16:13:48 -0400213
214 return nil
khenaidoob9203542018-09-17 22:56:37 -0400215}
216
Scott Baker80678602019-11-14 16:57:36 -0800217// Load the most recent state from the KVStore for the device.
Kent Hagerman2b216042020-04-03 18:28:56 -0400218func (agent *Agent) reconcileWithKVStore(ctx context.Context) {
khenaidoo442e7c72020-03-10 16:13:48 -0400219 if err := agent.requestQueue.WaitForGreenLight(ctx); err != nil {
Rohan Agrawal31f21802020-06-12 05:38:46 +0000220 logger.Warnw(ctx, "request-aborted", log.Fields{"device-id": agent.deviceID, "error": err})
khenaidoo442e7c72020-03-10 16:13:48 -0400221 return
222 }
223 defer agent.requestQueue.RequestComplete()
Rohan Agrawal31f21802020-06-12 05:38:46 +0000224 logger.Debug(ctx, "reconciling-device-agent-devicetype")
Scott Baker80678602019-11-14 16:57:36 -0800225 // TODO: context timeout
Kent Hagerman4f355f52020-03-30 16:01:33 -0400226 device := &voltha.Device{}
Kent Hagermanf5a67352020-04-30 15:15:26 -0400227 if have, err := agent.dbProxy.Get(ctx, agent.deviceID, device); err != nil {
Rohan Agrawal31f21802020-06-12 05:38:46 +0000228 logger.Errorw(ctx, "kv-get-failed", log.Fields{"device-id": agent.deviceID, "error": err})
Thomas Lee Se5a44012019-11-07 20:32:24 +0530229 return
Kent Hagerman4f355f52020-03-30 16:01:33 -0400230 } else if !have {
231 return // not found in kv
Thomas Lee Se5a44012019-11-07 20:32:24 +0530232 }
Kent Hagerman4f355f52020-03-30 16:01:33 -0400233
khenaidood948f772021-08-11 17:49:24 -0400234 agent.deviceType = device.Type
Kent Hagerman4f355f52020-03-30 16:01:33 -0400235 agent.device = device
khenaidood948f772021-08-11 17:49:24 -0400236 agent.adapterEndpoint = device.AdapterEndpoint
Kent Hagerman2a07b862020-06-19 15:23:07 -0400237 agent.portLoader.Load(ctx)
Himani Chawla2ba1c9c2020-10-07 13:19:03 +0530238 agent.transientStateLoader.Load(ctx)
239
Rohan Agrawal31f21802020-06-12 05:38:46 +0000240 logger.Debugw(ctx, "reconciled-device-agent-devicetype", log.Fields{"device-id": agent.deviceID, "type": agent.deviceType})
Scott Baker80678602019-11-14 16:57:36 -0800241}
242
khenaidoo442e7c72020-03-10 16:13:48 -0400243// onSuccess is a common callback for scenarios where we receive a nil response following a request to an adapter
khenaidood948f772021-08-11 17:49:24 -0400244func (agent *Agent) onSuccess(ctx context.Context, prevState, currState *common.AdminState_Types, deviceUpdateLog bool) {
245 if deviceUpdateLog {
246 requestStatus := &common.OperationResp{Code: common.OperationResp_OPERATION_SUCCESS}
247 desc := "adapter-response"
248 agent.logDeviceUpdate(ctx, prevState, currState, requestStatus, nil, desc)
249 return
250 }
251 logger.Debugw(ctx, "successful-operation", log.Fields{"device-id": agent.deviceID, "rpc": coreutils.GetRPCMetadataFromContext(ctx)})
khenaidoo442e7c72020-03-10 16:13:48 -0400252}
253
254// onFailure is a common callback for scenarios where we receive an error response following a request to an adapter
255// and the only action required is to publish the failed result on kafka
khenaidood948f772021-08-11 17:49:24 -0400256func (agent *Agent) onFailure(ctx context.Context, err error, prevState, currState *common.AdminState_Types, deviceUpdateLog bool) {
257 // Send an event on kafka
258 rpce := agent.deviceMgr.NewRPCEvent(ctx, agent.deviceID, err.Error(), nil)
259 go agent.deviceMgr.SendRPCEvent(ctx, "RPC_ERROR_RAISE_EVENT", rpce,
260 voltha.EventCategory_COMMUNICATION, nil, time.Now().Unix())
khenaidoo442e7c72020-03-10 16:13:48 -0400261
khenaidood948f772021-08-11 17:49:24 -0400262 // Log the device update event
263 if deviceUpdateLog {
264 requestStatus := &common.OperationResp{Code: common.OperationResp_OPERATION_FAILURE}
265 desc := "adapter-response"
266 agent.logDeviceUpdate(ctx, prevState, currState, requestStatus, err, desc)
267 return
khenaidoo442e7c72020-03-10 16:13:48 -0400268 }
khenaidood948f772021-08-11 17:49:24 -0400269 logger.Errorw(ctx, "failed-operation", log.Fields{"error": err, "device-id": agent.deviceID, "rpc": coreutils.GetRPCMetadataFromContext(ctx)})
khenaidoo442e7c72020-03-10 16:13:48 -0400270}
271
Himani Chawla2ba1c9c2020-10-07 13:19:03 +0530272// onDeleteSuccess is a common callback for scenarios where we receive a nil response following a delete request
273// to an adapter.
khenaidood948f772021-08-11 17:49:24 -0400274func (agent *Agent) onDeleteSuccess(ctx context.Context, prevState, currState *common.AdminState_Types) {
Himani Chawla2ba1c9c2020-10-07 13:19:03 +0530275 if err := agent.requestQueue.WaitForGreenLight(ctx); err != nil {
khenaidood948f772021-08-11 17:49:24 -0400276 logger.Errorw(ctx, "delete-device-failure", log.Fields{"device-id": agent.deviceID, "error": err})
Himani Chawla2ba1c9c2020-10-07 13:19:03 +0530277 }
278 previousDeviceTransientState := agent.getTransientState()
279 newDevice := agent.cloneDeviceWithoutLock()
280 if err := agent.updateDeviceWithTransientStateAndReleaseLock(ctx, newDevice,
khenaidood948f772021-08-11 17:49:24 -0400281 core.DeviceTransientState_DELETING_POST_ADAPTER_RESPONSE, previousDeviceTransientState); err != nil {
282 logger.Errorw(ctx, "delete-device-failure", log.Fields{"device-id": agent.deviceID, "error": err})
Himani Chawla2ba1c9c2020-10-07 13:19:03 +0530283 }
khenaidood948f772021-08-11 17:49:24 -0400284 requestStatus := &common.OperationResp{Code: common.OperationResp_OPERATION_SUCCESS}
285 desc := "adapter-response"
286 agent.logDeviceUpdate(ctx, prevState, currState, requestStatus, nil, desc)
Himani Chawla2ba1c9c2020-10-07 13:19:03 +0530287}
288
289// onDeleteFailure is a common callback for scenarios where we receive an error response following a delete request
290// to an adapter and the only action required is to return the error response.
khenaidood948f772021-08-11 17:49:24 -0400291func (agent *Agent) onDeleteFailure(ctx context.Context, err error, prevState, currState *common.AdminState_Types) {
292 logger.Errorw(ctx, "rpc-failed", log.Fields{"rpc": coreutils.GetRPCMetadataFromContext(ctx), "device-id": agent.deviceID, "error": err})
293
Himani Chawla2ba1c9c2020-10-07 13:19:03 +0530294 //Only updating of transient state is required, no transition.
khenaidood948f772021-08-11 17:49:24 -0400295 if er := agent.updateTransientState(ctx, core.DeviceTransientState_DELETE_FAILED); er != nil {
296 logger.Errorw(ctx, "failed-to-update-transient-state-as-delete-failed", log.Fields{"device-id": agent.deviceID, "error": er})
Himani Chawla2ba1c9c2020-10-07 13:19:03 +0530297 }
khenaidood948f772021-08-11 17:49:24 -0400298 rpce := agent.deviceMgr.NewRPCEvent(ctx, agent.deviceID, err.Error(), nil)
299 go agent.deviceMgr.SendRPCEvent(ctx, "RPC_ERROR_RAISE_EVENT", rpce,
300 voltha.EventCategory_COMMUNICATION, nil, time.Now().Unix())
Himani Chawla2ba1c9c2020-10-07 13:19:03 +0530301
khenaidood948f772021-08-11 17:49:24 -0400302 // Log the device update event
303 requestStatus := &common.OperationResp{Code: common.OperationResp_OPERATION_FAILURE}
304 desc := "adapter-response"
305 agent.logDeviceUpdate(ctx, prevState, currState, requestStatus, err, desc)
Maninder9a1bc0d2020-10-26 11:34:02 +0530306}
307
Kent Hagermancba2f302020-07-28 13:37:36 -0400308// getDeviceReadOnly returns a device which MUST NOT be modified, but is safe to keep forever.
309func (agent *Agent) getDeviceReadOnly(ctx context.Context) (*voltha.Device, error) {
khenaidoo442e7c72020-03-10 16:13:48 -0400310 if err := agent.requestQueue.WaitForGreenLight(ctx); err != nil {
311 return nil, err
312 }
313 defer agent.requestQueue.RequestComplete()
Kent Hagermancba2f302020-07-28 13:37:36 -0400314 return agent.device, nil
khenaidoo92e62c52018-10-03 14:02:54 -0400315}
316
Kent Hagermancba2f302020-07-28 13:37:36 -0400317// getDeviceReadOnlyWithoutLock returns a device which MUST NOT be modified, but is safe to keep forever. This is very efficient.
Kent Hagermanf6db9f12020-07-22 17:16:19 -0400318// The device lock MUST be held by the caller.
Kent Hagermancba2f302020-07-28 13:37:36 -0400319func (agent *Agent) getDeviceReadOnlyWithoutLock() *voltha.Device {
khenaidoo0db4c812020-05-27 15:27:30 -0400320 return agent.device
khenaidoo92e62c52018-10-03 14:02:54 -0400321}
322
Kent Hagermanf6db9f12020-07-22 17:16:19 -0400323// cloneDeviceWithoutLock returns a copy of the device which is safe to modify.
324// The device lock MUST be held by the caller.
325func (agent *Agent) cloneDeviceWithoutLock() *voltha.Device {
326 return proto.Clone(agent.device).(*voltha.Device)
327}
328
khenaidood948f772021-08-11 17:49:24 -0400329func (agent *Agent) updateDeviceTypeAndEndpoint(ctx context.Context) error {
330 if err := agent.requestQueue.WaitForGreenLight(ctx); err != nil {
331 return err
332 }
333 changed := false
334 cloned := agent.cloneDeviceWithoutLock()
335 if cloned.Type == "" {
336 adapterType, err := agent.adapterMgr.GetAdapterType(cloned.Type)
337 if err != nil {
338 agent.requestQueue.RequestComplete()
339 return err
340 }
341 cloned.Type = adapterType
342 changed = true
343 }
344
345 if cloned.AdapterEndpoint == "" {
346 var err error
347 if cloned.AdapterEndpoint, err = agent.adapterMgr.GetAdapterEndpoint(ctx, cloned.Id, cloned.Type); err != nil {
348 agent.requestQueue.RequestComplete()
349 return err
350 }
351 agent.adapterEndpoint = cloned.AdapterEndpoint
352 changed = true
353 }
354
355 if changed {
356 return agent.updateDeviceAndReleaseLock(ctx, cloned)
357 }
358 agent.requestQueue.RequestComplete()
359 return nil
360}
361
khenaidoo3ab34882019-05-02 21:33:30 -0400362// enableDevice activates a preprovisioned or a disable device
Kent Hagerman2b216042020-04-03 18:28:56 -0400363func (agent *Agent) enableDevice(ctx context.Context) error {
Maninder9a1bc0d2020-10-26 11:34:02 +0530364 //To preserve and use oldDevice state as prev state in new device
khenaidood948f772021-08-11 17:49:24 -0400365 var err error
Maninder9a1bc0d2020-10-26 11:34:02 +0530366 var desc string
khenaidood948f772021-08-11 17:49:24 -0400367 var prevAdminState, currAdminState common.AdminState_Types
368 requestStatus := &common.OperationResp{Code: common.OperationResp_OPERATION_FAILURE}
Maninder9a1bc0d2020-10-26 11:34:02 +0530369
khenaidood948f772021-08-11 17:49:24 -0400370 defer func() { agent.logDeviceUpdate(ctx, &prevAdminState, &currAdminState, requestStatus, err, desc) }()
Maninder9a1bc0d2020-10-26 11:34:02 +0530371
khenaidood948f772021-08-11 17:49:24 -0400372 if err = agent.requestQueue.WaitForGreenLight(ctx); err != nil {
khenaidoo442e7c72020-03-10 16:13:48 -0400373 return err
374 }
Himani Chawlab4c25912020-11-12 17:16:38 +0530375 logger.Debugw(ctx, "enable-device", log.Fields{"device-id": agent.deviceID})
khenaidoo21d51152019-02-01 13:48:37 -0500376
Kent Hagermancba2f302020-07-28 13:37:36 -0400377 oldDevice := agent.getDeviceReadOnlyWithoutLock()
khenaidood948f772021-08-11 17:49:24 -0400378 prevAdminState = oldDevice.AdminState
Maninder9a1bc0d2020-10-26 11:34:02 +0530379
Maninder2195ccc2021-06-23 20:23:01 +0530380 if !agent.proceedWithRequest(oldDevice) {
381 agent.requestQueue.RequestComplete()
khenaidood948f772021-08-11 17:49:24 -0400382 err = status.Errorf(codes.FailedPrecondition, "cannot complete operation as device deletion is in progress or reconciling is in progress/failed: %s", agent.deviceID)
383 return err
Maninder2195ccc2021-06-23 20:23:01 +0530384 }
385
Kent Hagermanf6db9f12020-07-22 17:16:19 -0400386 if oldDevice.AdminState == voltha.AdminState_ENABLED {
387 logger.Warnw(ctx, "device-already-enabled", log.Fields{"device-id": agent.deviceID})
388 agent.requestQueue.RequestComplete()
khenaidood948f772021-08-11 17:49:24 -0400389 err = status.Errorf(codes.FailedPrecondition, fmt.Sprintf("cannot-enable-an-already-enabled-device: %s", oldDevice.Id))
Matteo Scandolod525ae32020-04-02 17:27:29 -0700390 return err
npujar1d86a522019-11-14 17:11:16 +0530391 }
392
khenaidood948f772021-08-11 17:49:24 -0400393 // Verify whether there is a device type that supports this device type
394 _, err = agent.adapterMgr.GetAdapterType(oldDevice.Type)
395 if err != nil {
396 agent.requestQueue.RequestComplete()
397 return err
398 }
399
400 // Update device adapter endpoint if not set. This is set once by the Core and use as is by the adapters. E.g if this is a
401 // child device then the parent adapter will use this device's adapter endpoint (set here) to communicate with it.
Kent Hagermanf6db9f12020-07-22 17:16:19 -0400402 newDevice := agent.cloneDeviceWithoutLock()
khenaidood948f772021-08-11 17:49:24 -0400403 if newDevice.AdapterEndpoint == "" {
404 if newDevice.AdapterEndpoint, err = agent.adapterMgr.GetAdapterEndpoint(ctx, newDevice.Id, newDevice.Type); err != nil {
405 agent.requestQueue.RequestComplete()
406 return err
407 }
408 agent.adapterEndpoint = newDevice.AdapterEndpoint
409 }
npujar1d86a522019-11-14 17:11:16 +0530410
Kent Hagermanf6db9f12020-07-22 17:16:19 -0400411 // Update the Admin State and set the operational state to activating before sending the request to the Adapters
412 newDevice.AdminState = voltha.AdminState_ENABLED
413 newDevice.OperStatus = voltha.OperStatus_ACTIVATING
Maninder9a1bc0d2020-10-26 11:34:02 +0530414
khenaidoo442e7c72020-03-10 16:13:48 -0400415 // Adopt the device if it was in pre-provision state. In all other cases, try to re-enable it.
khenaidood948f772021-08-11 17:49:24 -0400416 client, err := agent.adapterMgr.GetAdapterClient(ctx, agent.adapterEndpoint)
khenaidoo442e7c72020-03-10 16:13:48 -0400417 if err != nil {
khenaidood948f772021-08-11 17:49:24 -0400418 logger.Errorw(ctx, "grpc-client-nil",
419 log.Fields{
420 "error": err,
421 "device-id": agent.deviceID,
422 "device-type": agent.deviceType,
423 "adapter-endpoint": newDevice.AdapterEndpoint,
424 })
425 agent.requestQueue.RequestComplete()
khenaidoo442e7c72020-03-10 16:13:48 -0400426 return err
427 }
khenaidood948f772021-08-11 17:49:24 -0400428 subCtx, cancel := context.WithTimeout(coreutils.WithAllMetadataFromContext(ctx), agent.rpcTimeout)
429 requestStatus.Code = common.OperationResp_OPERATION_IN_PROGRESS
430 go func() {
431 defer cancel()
432 var err error
433 if oldDevice.AdminState == voltha.AdminState_PREPROVISIONED {
434 _, err = client.AdoptDevice(subCtx, newDevice)
435 } else {
436 _, err = client.ReEnableDevice(subCtx, newDevice)
437 }
438 if err == nil {
439 agent.onSuccess(subCtx, nil, nil, true)
440 } else {
441 agent.onFailure(subCtx, err, nil, nil, true)
Himani Chawlab4c25912020-11-12 17:16:38 +0530442 }
443 }()
khenaidood948f772021-08-11 17:49:24 -0400444
445 // Update device
446 if err = agent.updateDeviceAndReleaseLock(ctx, newDevice); err != nil {
447 return err
khenaidoo2c6a0992019-04-29 13:46:56 -0400448 }
khenaidood948f772021-08-11 17:49:24 -0400449 currAdminState = newDevice.AdminState
450 return nil
khenaidoo2c6a0992019-04-29 13:46:56 -0400451}
452
A R Karthick5c28f552019-12-11 22:47:44 -0800453//addFlowsAndGroups adds the "newFlows" and "newGroups" from the existing flows/groups and sends the update to the
454//adapters
Kent Hagerman2b216042020-04-03 18:28:56 -0400455func (agent *Agent) addFlowsAndGroups(ctx context.Context, newFlows []*ofp.OfpFlowStats, newGroups []*ofp.OfpGroupEntry, flowMetadata *voltha.FlowMetadata) error {
Mahir Gunyel03de0d32020-06-03 01:36:59 -0700456 var flwResponse, grpResponse coreutils.Response
457 var err error
458 //if new flow list is empty then the called function returns quickly
459 if flwResponse, err = agent.addFlowsToAdapter(ctx, newFlows, flowMetadata); err != nil {
A R Karthick5c28f552019-12-11 22:47:44 -0800460 return err
461 }
Mahir Gunyel03de0d32020-06-03 01:36:59 -0700462 //if new group list is empty then the called function returns quickly
463 if grpResponse, err = agent.addGroupsToAdapter(ctx, newGroups, flowMetadata); err != nil {
464 return err
465 }
khenaidood948f772021-08-11 17:49:24 -0400466 if errs := coreutils.WaitForNilOrErrorResponses(agent.rpcTimeout, flwResponse, grpResponse); errs != nil {
467 logger.Warnw(ctx, "adapter-response", log.Fields{"device-id": agent.deviceID, "result": errs})
khenaidoo442e7c72020-03-10 16:13:48 -0400468 return status.Errorf(codes.Aborted, "flow-failure-device-%s", agent.deviceID)
khenaidoo0458db62019-06-20 08:50:36 -0400469 }
khenaidoo0458db62019-06-20 08:50:36 -0400470 return nil
471}
472
A R Karthick5c28f552019-12-11 22:47:44 -0800473//deleteFlowsAndGroups removes the "flowsToDel" and "groupsToDel" from the existing flows/groups and sends the update to the
474//adapters
Kent Hagerman2b216042020-04-03 18:28:56 -0400475func (agent *Agent) deleteFlowsAndGroups(ctx context.Context, flowsToDel []*ofp.OfpFlowStats, groupsToDel []*ofp.OfpGroupEntry, flowMetadata *voltha.FlowMetadata) error {
Mahir Gunyel03de0d32020-06-03 01:36:59 -0700476 var flwResponse, grpResponse coreutils.Response
477 var err error
478 if flwResponse, err = agent.deleteFlowsFromAdapter(ctx, flowsToDel, flowMetadata); err != nil {
A R Karthick5c28f552019-12-11 22:47:44 -0800479 return err
480 }
Mahir Gunyel03de0d32020-06-03 01:36:59 -0700481 if grpResponse, err = agent.deleteGroupsFromAdapter(ctx, groupsToDel, flowMetadata); err != nil {
482 return err
483 }
484
khenaidood948f772021-08-11 17:49:24 -0400485 if res := coreutils.WaitForNilOrErrorResponses(agent.rpcTimeout, flwResponse, grpResponse); res != nil {
khenaidoo0458db62019-06-20 08:50:36 -0400486 return status.Errorf(codes.Aborted, "errors-%s", res)
487 }
488 return nil
khenaidoo0458db62019-06-20 08:50:36 -0400489}
490
A R Karthick5c28f552019-12-11 22:47:44 -0800491//updateFlowsAndGroups replaces the existing flows and groups with "updatedFlows" and "updatedGroups" respectively. It
492//also sends the updates to the adapters
Kent Hagerman2b216042020-04-03 18:28:56 -0400493func (agent *Agent) updateFlowsAndGroups(ctx context.Context, updatedFlows []*ofp.OfpFlowStats, updatedGroups []*ofp.OfpGroupEntry, flowMetadata *voltha.FlowMetadata) error {
Mahir Gunyel03de0d32020-06-03 01:36:59 -0700494 var flwResponse, grpResponse coreutils.Response
495 var err error
496 if flwResponse, err = agent.updateFlowsToAdapter(ctx, updatedFlows, flowMetadata); err != nil {
A R Karthick5c28f552019-12-11 22:47:44 -0800497 return err
498 }
Mahir Gunyel03de0d32020-06-03 01:36:59 -0700499 if grpResponse, err = agent.updateGroupsToAdapter(ctx, updatedGroups, flowMetadata); err != nil {
500 return err
501 }
502
khenaidood948f772021-08-11 17:49:24 -0400503 if res := coreutils.WaitForNilOrErrorResponses(agent.rpcTimeout, flwResponse, grpResponse); res != nil {
khenaidoo0458db62019-06-20 08:50:36 -0400504 return status.Errorf(codes.Aborted, "errors-%s", res)
505 }
506 return nil
khenaidoo19d7b632018-10-30 10:49:50 -0400507}
508
khenaidoo4d4802d2018-10-04 21:59:49 -0400509//disableDevice disable a device
Kent Hagerman2b216042020-04-03 18:28:56 -0400510func (agent *Agent) disableDevice(ctx context.Context) error {
khenaidood948f772021-08-11 17:49:24 -0400511 var err error
Maninder9a1bc0d2020-10-26 11:34:02 +0530512 var desc string
khenaidood948f772021-08-11 17:49:24 -0400513 var prevAdminState, currAdminState common.AdminState_Types
514 requestStatus := &common.OperationResp{Code: common.OperationResp_OPERATION_FAILURE}
515 defer func() { agent.logDeviceUpdate(ctx, &prevAdminState, &currAdminState, requestStatus, err, desc) }()
Maninder9a1bc0d2020-10-26 11:34:02 +0530516
khenaidood948f772021-08-11 17:49:24 -0400517 if err = agent.requestQueue.WaitForGreenLight(ctx); err != nil {
khenaidoo442e7c72020-03-10 16:13:48 -0400518 return err
519 }
Himani Chawlab4c25912020-11-12 17:16:38 +0530520 logger.Debugw(ctx, "disable-device", log.Fields{"device-id": agent.deviceID})
khenaidoo6e55d9e2019-12-12 18:26:26 -0500521
Kent Hagermanf6db9f12020-07-22 17:16:19 -0400522 cloned := agent.cloneDeviceWithoutLock()
khenaidood948f772021-08-11 17:49:24 -0400523 prevAdminState = agent.device.AdminState
khenaidoo6e55d9e2019-12-12 18:26:26 -0500524
Maninder2195ccc2021-06-23 20:23:01 +0530525 if !agent.proceedWithRequest(cloned) {
khenaidood948f772021-08-11 17:49:24 -0400526 err = status.Errorf(codes.FailedPrecondition, "cannot complete operation as device deletion is in progress or reconciling is in progress/failed: %s", agent.deviceID)
Maninder2195ccc2021-06-23 20:23:01 +0530527 agent.requestQueue.RequestComplete()
khenaidood948f772021-08-11 17:49:24 -0400528 return err
Maninder2195ccc2021-06-23 20:23:01 +0530529 }
530
khenaidoo6e55d9e2019-12-12 18:26:26 -0500531 if cloned.AdminState == voltha.AdminState_DISABLED {
Maninder9a1bc0d2020-10-26 11:34:02 +0530532 desc = "device-already-disabled"
Kent Hagermanf6db9f12020-07-22 17:16:19 -0400533 agent.requestQueue.RequestComplete()
npujar1d86a522019-11-14 17:11:16 +0530534 return nil
535 }
Himani Chawla2ba1c9c2020-10-07 13:19:03 +0530536 if cloned.AdminState == voltha.AdminState_PREPROVISIONED {
Kent Hagermanf6db9f12020-07-22 17:16:19 -0400537 agent.requestQueue.RequestComplete()
khenaidood948f772021-08-11 17:49:24 -0400538 err = status.Errorf(codes.FailedPrecondition, "deviceId:%s, invalid-admin-state:%s", agent.deviceID, cloned.AdminState)
539 return err
npujar1d86a522019-11-14 17:11:16 +0530540 }
Maninder0aabf0c2021-03-17 14:55:14 +0530541
npujar1d86a522019-11-14 17:11:16 +0530542 // Update the Admin State and operational state before sending the request out
Kent Hagermanf6db9f12020-07-22 17:16:19 -0400543 cloned.AdminState = voltha.AdminState_DISABLED
544 cloned.OperStatus = voltha.OperStatus_UNKNOWN
Maninder9a1bc0d2020-10-26 11:34:02 +0530545
khenaidood948f772021-08-11 17:49:24 -0400546 client, err := agent.adapterMgr.GetAdapterClient(ctx, agent.adapterEndpoint)
khenaidoo442e7c72020-03-10 16:13:48 -0400547 if err != nil {
khenaidood948f772021-08-11 17:49:24 -0400548 logger.Errorw(ctx, "grpc-client-nil",
549 log.Fields{
550 "error": err,
551 "device-id": agent.deviceID,
552 "device-type": agent.deviceType,
553 "adapter-endpoint": cloned.AdapterEndpoint,
554 })
555 agent.requestQueue.RequestComplete()
npujar1d86a522019-11-14 17:11:16 +0530556 return err
khenaidoo0a822f92019-05-08 15:15:57 -0400557 }
khenaidood948f772021-08-11 17:49:24 -0400558 subCtx, cancel := context.WithTimeout(coreutils.WithAllMetadataFromContext(ctx), agent.rpcTimeout)
559 requestStatus.Code = common.OperationResp_OPERATION_IN_PROGRESS
560 go func() {
561 defer cancel()
562 _, err := client.DisableDevice(subCtx, cloned)
563 if err == nil {
564 agent.onSuccess(subCtx, nil, nil, true)
565 } else {
566 agent.onFailure(subCtx, err, nil, nil, true)
567 }
568 }()
Maninder9a1bc0d2020-10-26 11:34:02 +0530569
khenaidood948f772021-08-11 17:49:24 -0400570 // Update device
571 if err = agent.updateDeviceAndReleaseLock(ctx, cloned); err != nil {
572 return err
573 }
574 currAdminState = cloned.AdminState
khenaidoo0a822f92019-05-08 15:15:57 -0400575
khenaidoo92e62c52018-10-03 14:02:54 -0400576 return nil
577}
578
Kent Hagerman2b216042020-04-03 18:28:56 -0400579func (agent *Agent) rebootDevice(ctx context.Context) error {
Maninder9a1bc0d2020-10-26 11:34:02 +0530580 var desc string
khenaidood948f772021-08-11 17:49:24 -0400581 var err error
582 requestStatus := &common.OperationResp{Code: common.OperationResp_OPERATION_FAILURE}
583 defer func() { agent.logDeviceUpdate(ctx, nil, nil, requestStatus, err, desc) }()
Maninder9a1bc0d2020-10-26 11:34:02 +0530584
khenaidood948f772021-08-11 17:49:24 -0400585 if err = agent.requestQueue.WaitForGreenLight(ctx); err != nil {
Maninder9a1bc0d2020-10-26 11:34:02 +0530586 desc = err.Error()
npujar1d86a522019-11-14 17:11:16 +0530587 return err
khenaidoo4d4802d2018-10-04 21:59:49 -0400588 }
khenaidoo442e7c72020-03-10 16:13:48 -0400589 defer agent.requestQueue.RequestComplete()
Himani Chawlab4c25912020-11-12 17:16:38 +0530590 logger.Debugw(ctx, "reboot-device", log.Fields{"device-id": agent.deviceID})
khenaidoo442e7c72020-03-10 16:13:48 -0400591
Kent Hagermancba2f302020-07-28 13:37:36 -0400592 device := agent.getDeviceReadOnlyWithoutLock()
Maninder2195ccc2021-06-23 20:23:01 +0530593
594 if !agent.proceedWithRequest(device) {
khenaidood948f772021-08-11 17:49:24 -0400595 err = status.Errorf(codes.FailedPrecondition, "cannot complete operation as device deletion is in progress or reconciling is in progress/failed:%s", agent.deviceID)
khenaidoo442e7c72020-03-10 16:13:48 -0400596 return err
597 }
Maninder9a1bc0d2020-10-26 11:34:02 +0530598
khenaidood948f772021-08-11 17:49:24 -0400599 client, err := agent.adapterMgr.GetAdapterClient(ctx, agent.adapterEndpoint)
600 if err != nil {
601 logger.Errorw(ctx, "grpc-client-nil",
602 log.Fields{
603 "error": err,
604 "device-id": agent.deviceID,
605 "device-type": agent.deviceType,
606 "adapter-endpoint": device.AdapterEndpoint,
607 })
608 return err
609 }
610 subCtx, cancel := context.WithTimeout(coreutils.WithAllMetadataFromContext(ctx), agent.rpcTimeout)
611 requestStatus.Code = common.OperationResp_OPERATION_IN_PROGRESS
612 go func() {
613 defer cancel()
614 _, err := client.RebootDevice(subCtx, device)
615 if err == nil {
616 agent.onSuccess(subCtx, nil, nil, true)
617 } else {
618 agent.onFailure(subCtx, err, nil, nil, true)
619 }
620 }()
khenaidoo4d4802d2018-10-04 21:59:49 -0400621 return nil
622}
623
Himani Chawla2ba1c9c2020-10-07 13:19:03 +0530624func (agent *Agent) deleteDeviceForce(ctx context.Context) error {
Himani Chawlab4c25912020-11-12 17:16:38 +0530625 logger.Debugw(ctx, "delete-device-force", log.Fields{"device-id": agent.deviceID})
Maninder9a1bc0d2020-10-26 11:34:02 +0530626
627 var desc string
khenaidood948f772021-08-11 17:49:24 -0400628 var err error
629 requestStatus := &common.OperationResp{Code: common.OperationResp_OPERATION_FAILURE}
630 defer func() { agent.logDeviceUpdate(ctx, nil, nil, requestStatus, err, desc) }()
Maninder9a1bc0d2020-10-26 11:34:02 +0530631
khenaidood948f772021-08-11 17:49:24 -0400632 if err = agent.requestQueue.WaitForGreenLight(ctx); err != nil {
Himani Chawla2ba1c9c2020-10-07 13:19:03 +0530633 return err
634 }
635 // Get the device Transient state, return err if it is DELETING
636 previousDeviceTransientState := agent.getTransientState()
Himani Chawla2ba1c9c2020-10-07 13:19:03 +0530637 device := agent.cloneDeviceWithoutLock()
khenaidood948f772021-08-11 17:49:24 -0400638 if !agent.isForceDeletingAllowed(previousDeviceTransientState, device) {
639 agent.requestQueue.RequestComplete()
640 err = status.Error(codes.FailedPrecondition, fmt.Sprintf("deviceId:%s, force deletion is in progress", agent.deviceID))
Himani Chawla2ba1c9c2020-10-07 13:19:03 +0530641 return err
642 }
Himani Chawlab4c25912020-11-12 17:16:38 +0530643
khenaidood948f772021-08-11 17:49:24 -0400644 previousAdminState := device.AdminState
645 if previousAdminState != common.AdminState_PREPROVISIONED {
646 var client adapter_services.AdapterServiceClient
647 client, err = agent.adapterMgr.GetAdapterClient(ctx, agent.adapterEndpoint)
Himani Chawla2ba1c9c2020-10-07 13:19:03 +0530648 if err != nil {
khenaidood948f772021-08-11 17:49:24 -0400649 logger.Errorw(ctx, "grpc-client-nil",
650 log.Fields{
651 "error": err,
652 "device-id": agent.deviceID,
653 "device-type": agent.deviceType,
654 "adapter-endpoint": device.AdapterEndpoint,
655 })
656 agent.requestQueue.RequestComplete()
Himani Chawla2ba1c9c2020-10-07 13:19:03 +0530657 return err
658 }
khenaidood948f772021-08-11 17:49:24 -0400659 subCtx, cancel := context.WithTimeout(coreutils.WithAllMetadataFromContext(ctx), agent.rpcTimeout)
660 requestStatus.Code = common.OperationResp_OPERATION_IN_PROGRESS
661 go func() {
662 defer cancel()
663 _, err := client.DeleteDevice(subCtx, device)
664 if err == nil {
665 agent.onSuccess(subCtx, nil, nil, true)
666 } else {
667 agent.onFailure(subCtx, err, nil, nil, true)
668 }
669 }()
670 }
671
672 // Update device
673 if err = agent.updateDeviceWithTransientStateAndReleaseLock(ctx, device,
674 core.DeviceTransientState_FORCE_DELETING, previousDeviceTransientState); err != nil {
675 return err
Himani Chawla2ba1c9c2020-10-07 13:19:03 +0530676 }
677 return nil
678}
679
Kent Hagerman2b216042020-04-03 18:28:56 -0400680func (agent *Agent) deleteDevice(ctx context.Context) error {
Himani Chawlab4c25912020-11-12 17:16:38 +0530681 logger.Debugw(ctx, "delete-device", log.Fields{"device-id": agent.deviceID})
Maninder9a1bc0d2020-10-26 11:34:02 +0530682
683 var desc string
khenaidood948f772021-08-11 17:49:24 -0400684 var err error
685 requestStatus := &common.OperationResp{Code: common.OperationResp_OPERATION_FAILURE}
686 defer func() { agent.logDeviceUpdate(ctx, nil, nil, requestStatus, err, desc) }()
Maninder9a1bc0d2020-10-26 11:34:02 +0530687
khenaidood948f772021-08-11 17:49:24 -0400688 if err = agent.requestQueue.WaitForGreenLight(ctx); err != nil {
Maninder9a1bc0d2020-10-26 11:34:02 +0530689 desc = err.Error()
khenaidoo442e7c72020-03-10 16:13:48 -0400690 return err
691 }
Maninder0aabf0c2021-03-17 14:55:14 +0530692
Maninder2195ccc2021-06-23 20:23:01 +0530693 device := agent.cloneDeviceWithoutLock()
694
695 if !agent.proceedWithRequest(device) {
Maninder0aabf0c2021-03-17 14:55:14 +0530696 agent.requestQueue.RequestComplete()
khenaidood948f772021-08-11 17:49:24 -0400697 err = status.Errorf(codes.FailedPrecondition, "cannot complete operation as device deletion is in progress or reconciling is in progress/failed: %s", agent.deviceID)
698 return err
Maninder0aabf0c2021-03-17 14:55:14 +0530699 }
700
Himani Chawla2ba1c9c2020-10-07 13:19:03 +0530701 // Get the device Transient state, return err if it is DELETING
702 previousDeviceTransientState := agent.getTransientState()
khenaidoo6e55d9e2019-12-12 18:26:26 -0500703
Himani Chawla2ba1c9c2020-10-07 13:19:03 +0530704 previousAdminState := device.AdminState
705 // Change the device transient state to DELETING_FROM_ADAPTER state till the device is removed from adapters.
khenaidood948f772021-08-11 17:49:24 -0400706 currentDeviceTransientState := core.DeviceTransientState_DELETING_FROM_ADAPTER
khenaidoo442e7c72020-03-10 16:13:48 -0400707
khenaidood948f772021-08-11 17:49:24 -0400708 if previousAdminState == common.AdminState_PREPROVISIONED {
Himani Chawla2ba1c9c2020-10-07 13:19:03 +0530709 // Change the state to DELETING POST ADAPTER RESPONSE directly as adapters have no info of the device.
khenaidood948f772021-08-11 17:49:24 -0400710 currentDeviceTransientState = core.DeviceTransientState_DELETING_POST_ADAPTER_RESPONSE
Himani Chawla2ba1c9c2020-10-07 13:19:03 +0530711 }
khenaidood948f772021-08-11 17:49:24 -0400712 // If the device was in pre-prov state (only parent device are in that state) then do not send the request to the
713 // adapter
714 if previousAdminState != common.AdminState_PREPROVISIONED {
715 var client adapter_services.AdapterServiceClient
716 client, err = agent.adapterMgr.GetAdapterClient(ctx, agent.adapterEndpoint)
717 if err != nil {
718 logger.Errorw(ctx, "grpc-client-nil",
719 log.Fields{
720 "error": err,
721 "device-id": agent.deviceID,
722 "device-type": agent.deviceType,
723 "adapter-endpoint": device.AdapterEndpoint,
724 })
725 agent.requestQueue.RequestComplete()
726 return err
727 }
728 subCtx, cancel := context.WithTimeout(coreutils.WithAllMetadataFromContext(ctx), agent.rpcTimeout)
729 requestStatus.Code = common.OperationResp_OPERATION_IN_PROGRESS
730 go func() {
731 defer cancel()
732 _, err := client.DeleteDevice(subCtx, device)
733 if err == nil {
734 agent.onDeleteSuccess(subCtx, nil, nil)
735 } else {
736 agent.onDeleteFailure(subCtx, err, nil, nil)
737 }
738 }()
739 }
740
741 // Update device and release lock
742 if err = agent.updateDeviceWithTransientStateAndReleaseLock(ctx, device,
Himani Chawlab4c25912020-11-12 17:16:38 +0530743 currentDeviceTransientState, previousDeviceTransientState); err != nil {
Maninder9a1bc0d2020-10-26 11:34:02 +0530744 desc = err.Error()
npujar1d86a522019-11-14 17:11:16 +0530745 return err
746 }
Himani Chawlab4c25912020-11-12 17:16:38 +0530747
khenaidoo4d4802d2018-10-04 21:59:49 -0400748 return nil
749}
750
Kent Hagerman2b216042020-04-03 18:28:56 -0400751func (agent *Agent) setParentID(ctx context.Context, device *voltha.Device, parentID string) error {
khenaidoo442e7c72020-03-10 16:13:48 -0400752 if err := agent.requestQueue.WaitForGreenLight(ctx); err != nil {
753 return err
754 }
Himani Chawlab4c25912020-11-12 17:16:38 +0530755 logger.Debugw(ctx, "set-parent-id", log.Fields{"device-id": device.Id, "parent-id": parentID})
khenaidoo6e55d9e2019-12-12 18:26:26 -0500756
Kent Hagermanf6db9f12020-07-22 17:16:19 -0400757 cloned := agent.cloneDeviceWithoutLock()
npujar1d86a522019-11-14 17:11:16 +0530758 cloned.ParentId = parentID
Kent Hagermanf6db9f12020-07-22 17:16:19 -0400759 return agent.updateDeviceAndReleaseLock(ctx, cloned)
khenaidooad06fd72019-10-28 12:26:05 -0400760}
761
khenaidoo442e7c72020-03-10 16:13:48 -0400762// getSwitchCapability retrieves the switch capability of a parent device
Kent Hagerman2b216042020-04-03 18:28:56 -0400763func (agent *Agent) getSwitchCapability(ctx context.Context) (*ic.SwitchCapability, error) {
Himani Chawlab4c25912020-11-12 17:16:38 +0530764 logger.Debugw(ctx, "get-switch-capability", log.Fields{"device-id": agent.deviceID})
khenaidoo442e7c72020-03-10 16:13:48 -0400765
Kent Hagermancba2f302020-07-28 13:37:36 -0400766 device, err := agent.getDeviceReadOnly(ctx)
khenaidoo442e7c72020-03-10 16:13:48 -0400767 if err != nil {
khenaidoob9203542018-09-17 22:56:37 -0400768 return nil, err
khenaidoob9203542018-09-17 22:56:37 -0400769 }
khenaidood948f772021-08-11 17:49:24 -0400770
771 // Get the gRPC client
772 client, err := agent.adapterMgr.GetAdapterClient(ctx, agent.adapterEndpoint)
khenaidoo442e7c72020-03-10 16:13:48 -0400773 if err != nil {
774 return nil, err
775 }
776
khenaidood948f772021-08-11 17:49:24 -0400777 return client.GetOfpDeviceInfo(ctx, device)
khenaidoob9203542018-09-17 22:56:37 -0400778}
779
khenaidood948f772021-08-11 17:49:24 -0400780func (agent *Agent) onPacketFailure(ctx context.Context, err error, packet *ofp.OfpPacketOut) {
781 logger.Errorw(ctx, "packet-out-error", log.Fields{
khenaidoo442e7c72020-03-10 16:13:48 -0400782 "device-id": agent.deviceID,
khenaidood948f772021-08-11 17:49:24 -0400783 "error": err.Error(),
784 "packet": hex.EncodeToString(packet.Data),
khenaidoo442e7c72020-03-10 16:13:48 -0400785 })
khenaidood948f772021-08-11 17:49:24 -0400786 rpce := agent.deviceMgr.NewRPCEvent(ctx, agent.deviceID, err.Error(), nil)
787 go agent.deviceMgr.SendRPCEvent(ctx, "RPC_ERROR_RAISE_EVENT", rpce,
788 voltha.EventCategory_COMMUNICATION, nil, time.Now().Unix())
khenaidoo442e7c72020-03-10 16:13:48 -0400789}
790
Kent Hagerman2b216042020-04-03 18:28:56 -0400791func (agent *Agent) packetOut(ctx context.Context, outPort uint32, packet *ofp.OfpPacketOut) error {
Scott Baker80678602019-11-14 16:57:36 -0800792 if agent.deviceType == "" {
npujar467fe752020-01-16 20:17:45 +0530793 agent.reconcileWithKVStore(ctx)
Scott Baker80678602019-11-14 16:57:36 -0800794 }
khenaidoofdbad6e2018-11-06 22:26:38 -0500795 // Send packet to adapter
khenaidood948f772021-08-11 17:49:24 -0400796 client, err := agent.adapterMgr.GetAdapterClient(ctx, agent.adapterEndpoint)
khenaidoo442e7c72020-03-10 16:13:48 -0400797 if err != nil {
khenaidood948f772021-08-11 17:49:24 -0400798 logger.Errorw(ctx, "grpc-client-nil",
799 log.Fields{
800 "error": err,
801 "device-id": agent.deviceID,
802 "device-type": agent.deviceType,
803 })
804 return err
khenaidoofdbad6e2018-11-06 22:26:38 -0500805 }
khenaidood948f772021-08-11 17:49:24 -0400806 subCtx, cancel := context.WithTimeout(coreutils.WithAllMetadataFromContext(ctx), agent.rpcTimeout)
807 go func() {
808 defer cancel()
809 _, err := client.SendPacketOut(subCtx, &ic.PacketOut{
810 DeviceId: agent.deviceID,
811 EgressPortNo: outPort,
812 Packet: packet,
813 })
814 if err == nil {
815 agent.onSuccess(subCtx, nil, nil, false)
816 } else {
817 agent.onPacketFailure(subCtx, err, packet)
818 }
819 }()
khenaidoofdbad6e2018-11-06 22:26:38 -0500820 return nil
821}
822
Kent Hagermanf6db9f12020-07-22 17:16:19 -0400823func (agent *Agent) updateDeviceUsingAdapterData(ctx context.Context, device *voltha.Device) error {
khenaidood948f772021-08-11 17:49:24 -0400824 var err error
825 var desc string
826 requestStatus := &common.OperationResp{Code: common.OperationResp_OPERATION_FAILURE}
827 defer func() { agent.logDeviceUpdate(ctx, nil, nil, requestStatus, err, desc) }()
828
829 if err = agent.requestQueue.WaitForGreenLight(ctx); err != nil {
Kent Hagermanf6db9f12020-07-22 17:16:19 -0400830 return err
831 }
Himani Chawlab4c25912020-11-12 17:16:38 +0530832 logger.Debugw(ctx, "update-device-using-adapter-data", log.Fields{"device-id": device.Id})
Kent Hagermanf6db9f12020-07-22 17:16:19 -0400833
834 cloned := agent.cloneDeviceWithoutLock()
Mahir Gunyel8e2707d2019-07-25 00:36:21 -0700835 cloned.Root = device.Root
836 cloned.Vendor = device.Vendor
837 cloned.Model = device.Model
838 cloned.SerialNumber = device.SerialNumber
839 cloned.MacAddress = device.MacAddress
840 cloned.Vlan = device.Vlan
841 cloned.Reason = device.Reason
Andrea Campanella025667e2021-01-14 11:50:07 +0100842 cloned.ImageDownloads = device.ImageDownloads
khenaidood948f772021-08-11 17:49:24 -0400843 cloned.OperStatus = device.OperStatus
844 cloned.ConnectStatus = device.ConnectStatus
845 if err = agent.updateDeviceAndReleaseLock(ctx, cloned); err == nil {
846 requestStatus.Code = common.OperationResp_OPERATION_SUCCESS
847 }
848 return err
khenaidoo43c82122018-11-22 18:38:28 -0500849}
850
Kent Hagerman2b216042020-04-03 18:28:56 -0400851func (agent *Agent) updateDeviceStatus(ctx context.Context, operStatus voltha.OperStatus_Types, connStatus voltha.ConnectStatus_Types) error {
khenaidood948f772021-08-11 17:49:24 -0400852 var err error
853 var desc string
854 opStatus := &common.OperationResp{Code: common.OperationResp_OPERATION_FAILURE}
855 defer func() { agent.logDeviceUpdate(ctx, nil, nil, opStatus, err, desc) }()
856
857 if err = agent.requestQueue.WaitForGreenLight(ctx); err != nil {
khenaidoo442e7c72020-03-10 16:13:48 -0400858 return err
859 }
khenaidoo6e55d9e2019-12-12 18:26:26 -0500860
Kent Hagermanf6db9f12020-07-22 17:16:19 -0400861 cloned := agent.cloneDeviceWithoutLock()
npujar1d86a522019-11-14 17:11:16 +0530862 // Ensure the enums passed in are valid - they will be invalid if they are not set when this function is invoked
Kent Hagermanf6db9f12020-07-22 17:16:19 -0400863 if s, ok := voltha.ConnectStatus_Types_name[int32(connStatus)]; ok {
khenaidood948f772021-08-11 17:49:24 -0400864 logger.Debugw(ctx, "update-device-conn-status", log.Fields{"ok": ok, "val": s})
Kent Hagermanf6db9f12020-07-22 17:16:19 -0400865 cloned.ConnectStatus = connStatus
npujar1d86a522019-11-14 17:11:16 +0530866 }
Kent Hagermanf6db9f12020-07-22 17:16:19 -0400867 if s, ok := voltha.OperStatus_Types_name[int32(operStatus)]; ok {
khenaidood948f772021-08-11 17:49:24 -0400868 logger.Debugw(ctx, "update-device-oper-status", log.Fields{"ok": ok, "val": s})
Kent Hagermanf6db9f12020-07-22 17:16:19 -0400869 cloned.OperStatus = operStatus
npujar1d86a522019-11-14 17:11:16 +0530870 }
Himani Chawlab4c25912020-11-12 17:16:38 +0530871 logger.Debugw(ctx, "update-device-status", log.Fields{"device-id": cloned.Id, "oper-status": cloned.OperStatus, "connect-status": cloned.ConnectStatus})
npujar1d86a522019-11-14 17:11:16 +0530872 // Store the device
khenaidood948f772021-08-11 17:49:24 -0400873 if err = agent.updateDeviceAndReleaseLock(ctx, cloned); err == nil {
874 opStatus.Code = common.OperationResp_OPERATION_SUCCESS
875 }
876 return err
khenaidoo92e62c52018-10-03 14:02:54 -0400877}
878
khenaidoob9203542018-09-17 22:56:37 -0400879// TODO: A generic device update by attribute
Kent Hagerman2b216042020-04-03 18:28:56 -0400880func (agent *Agent) updateDeviceAttribute(ctx context.Context, name string, value interface{}) {
khenaidoob9203542018-09-17 22:56:37 -0400881 if value == nil {
882 return
883 }
khenaidoo6e55d9e2019-12-12 18:26:26 -0500884
Kent Hagermanf6db9f12020-07-22 17:16:19 -0400885 if err := agent.requestQueue.WaitForGreenLight(ctx); err != nil {
886 logger.Warnw(ctx, "request-aborted", log.Fields{"device-id": agent.deviceID, "name": name, "error": err})
887 return
888 }
889
890 cloned := agent.cloneDeviceWithoutLock()
khenaidoob9203542018-09-17 22:56:37 -0400891 updated := false
khenaidoo6e55d9e2019-12-12 18:26:26 -0500892 s := reflect.ValueOf(cloned).Elem()
khenaidoob9203542018-09-17 22:56:37 -0400893 if s.Kind() == reflect.Struct {
894 // exported field
895 f := s.FieldByName(name)
896 if f.IsValid() && f.CanSet() {
897 switch f.Kind() {
898 case reflect.String:
899 f.SetString(value.(string))
900 updated = true
901 case reflect.Uint32:
902 f.SetUint(uint64(value.(uint32)))
903 updated = true
904 case reflect.Bool:
905 f.SetBool(value.(bool))
906 updated = true
907 }
908 }
909 }
divyadesaicb8b59d2020-08-18 09:55:47 +0000910 logger.Debugw(ctx, "update-field-status", log.Fields{"device-id": cloned.Id, "name": name, "updated": updated})
khenaidoob9203542018-09-17 22:56:37 -0400911 // Save the data
khenaidoo6e55d9e2019-12-12 18:26:26 -0500912
Kent Hagermanf6db9f12020-07-22 17:16:19 -0400913 if err := agent.updateDeviceAndReleaseLock(ctx, cloned); err != nil {
Rohan Agrawal31f21802020-06-12 05:38:46 +0000914 logger.Warnw(ctx, "attribute-update-failed", log.Fields{"attribute": name, "value": value})
khenaidoob9203542018-09-17 22:56:37 -0400915 }
khenaidoob9203542018-09-17 22:56:37 -0400916}
serkant.uluderya334479d2019-04-10 08:26:15 -0700917
Kent Hagerman45a13e42020-04-13 12:23:50 -0400918func (agent *Agent) simulateAlarm(ctx context.Context, simulateReq *voltha.SimulateAlarmRequest) error {
khenaidood948f772021-08-11 17:49:24 -0400919 var err error
920 var desc string
921 requestStatus := &common.OperationResp{Code: common.OperationResp_OPERATION_FAILURE}
922 defer func() { agent.logDeviceUpdate(ctx, nil, nil, requestStatus, err, desc) }()
923
924 if err = agent.requestQueue.WaitForGreenLight(ctx); err != nil {
khenaidoo442e7c72020-03-10 16:13:48 -0400925 return err
926 }
927 defer agent.requestQueue.RequestComplete()
Himani Chawlab4c25912020-11-12 17:16:38 +0530928 logger.Debugw(ctx, "simulate-alarm", log.Fields{"device-id": agent.deviceID})
khenaidoo6e55d9e2019-12-12 18:26:26 -0500929
Kent Hagermancba2f302020-07-28 13:37:36 -0400930 device := agent.getDeviceReadOnlyWithoutLock()
khenaidoo6e55d9e2019-12-12 18:26:26 -0500931
khenaidood948f772021-08-11 17:49:24 -0400932 client, err := agent.adapterMgr.GetAdapterClient(ctx, agent.adapterEndpoint)
khenaidoo442e7c72020-03-10 16:13:48 -0400933 if err != nil {
khenaidood948f772021-08-11 17:49:24 -0400934 logger.Errorw(ctx, "grpc-client-nil",
935 log.Fields{
936 "error": err,
937 "device-id": agent.deviceID,
938 "device-type": agent.deviceType,
939 "adapter-endpoint": device.AdapterEndpoint,
940 })
npujar1d86a522019-11-14 17:11:16 +0530941 return err
serkant.uluderya334479d2019-04-10 08:26:15 -0700942 }
khenaidood948f772021-08-11 17:49:24 -0400943 subCtx, cancel := context.WithTimeout(coreutils.WithAllMetadataFromContext(ctx), agent.rpcTimeout)
944 requestStatus.Code = common.OperationResp_OPERATION_IN_PROGRESS
945 go func() {
946 defer cancel()
947 _, err := client.SimulateAlarm(subCtx, &ic.SimulateAlarmMessage{Device: device, Request: simulateReq})
948 if err == nil {
949 agent.onSuccess(subCtx, nil, nil, false)
950 } else {
951 agent.onFailure(subCtx, err, nil, nil, false)
952 }
953 }()
serkant.uluderya334479d2019-04-10 08:26:15 -0700954 return nil
955}
Mahir Gunyelb5851672019-07-24 10:46:26 +0300956
Kent Hagermanf6db9f12020-07-22 17:16:19 -0400957// This function updates the device in the DB, releases the device lock, and runs any state transitions.
958// The calling function MUST hold the device lock. The caller MUST NOT modify the device after this is called.
959func (agent *Agent) updateDeviceAndReleaseLock(ctx context.Context, device *voltha.Device) error {
960 // fail early if this agent is no longer valid
Kent Hagerman4f355f52020-03-30 16:01:33 -0400961 if agent.stopped {
Kent Hagermanf6db9f12020-07-22 17:16:19 -0400962 agent.requestQueue.RequestComplete()
Himani Chawla2ba1c9c2020-10-07 13:19:03 +0530963 return errors.New("device-agent-stopped")
Thomas Lee Se5a44012019-11-07 20:32:24 +0530964 }
Kent Hagerman4f355f52020-03-30 16:01:33 -0400965
Kent Hagermanf6db9f12020-07-22 17:16:19 -0400966 // update in db
Kent Hagermanf5a67352020-04-30 15:15:26 -0400967 if err := agent.dbProxy.Set(ctx, agent.deviceID, device); err != nil {
Kent Hagermanf6db9f12020-07-22 17:16:19 -0400968 agent.requestQueue.RequestComplete()
Kent Hagerman4f355f52020-03-30 16:01:33 -0400969 return status.Errorf(codes.Internal, "failed-update-device:%s: %s", agent.deviceID, err)
Mahir Gunyelb5851672019-07-24 10:46:26 +0300970 }
divyadesaicb8b59d2020-08-18 09:55:47 +0000971 logger.Debugw(ctx, "updated-device-in-store", log.Fields{"device-id: ": agent.deviceID})
Mahir Gunyelb5851672019-07-24 10:46:26 +0300972
Kent Hagerman6031aad2020-07-29 16:36:33 -0400973 prevDevice := agent.device
Kent Hagermanf6db9f12020-07-22 17:16:19 -0400974 // update the device
khenaidoo0db4c812020-05-27 15:27:30 -0400975 agent.device = device
Mahir Gunyelb0343bf2021-05-11 14:14:26 -0700976 //If any of the states has chenged, send the change event.
977 if prevDevice.OperStatus != device.OperStatus || prevDevice.ConnectStatus != device.ConnectStatus || prevDevice.AdminState != device.AdminState {
978 _ = agent.deviceMgr.Agent.SendDeviceStateChangeEvent(ctx, prevDevice.OperStatus, prevDevice.ConnectStatus, prevDevice.AdminState, device, time.Now().Unix())
979 }
Maninder0aabf0c2021-03-17 14:55:14 +0530980 deviceTransientState := agent.getTransientState()
981
Kent Hagermanf6db9f12020-07-22 17:16:19 -0400982 // release lock before processing transition
983 agent.requestQueue.RequestComplete()
Himani Chawlab4c25912020-11-12 17:16:38 +0530984 subCtx := coreutils.WithSpanAndRPCMetadataFromContext(ctx)
Kent Hagermanf6db9f12020-07-22 17:16:19 -0400985
Himani Chawlab4c25912020-11-12 17:16:38 +0530986 if err := agent.deviceMgr.stateTransitions.ProcessTransition(subCtx,
Maninder0aabf0c2021-03-17 14:55:14 +0530987 device, prevDevice, deviceTransientState, deviceTransientState); err != nil {
Himani Chawlab4c25912020-11-12 17:16:38 +0530988 logger.Errorw(ctx, "failed-process-transition", log.Fields{"device-id": device.Id, "previous-admin-state": prevDevice.AdminState, "current-admin-state": device.AdminState})
989 // Sending RPC EVENT here
990 rpce := agent.deviceMgr.NewRPCEvent(ctx, agent.deviceID, err.Error(), nil)
Himani Chawla606a4f02021-03-23 19:45:58 +0530991 agent.deviceMgr.SendRPCEvent(ctx, "RPC_ERROR_RAISE_EVENT", rpce, voltha.EventCategory_COMMUNICATION,
992 nil, time.Now().Unix())
Himani Chawlab4c25912020-11-12 17:16:38 +0530993
Kent Hagermanf6db9f12020-07-22 17:16:19 -0400994 }
Mahir Gunyelb5851672019-07-24 10:46:26 +0300995 return nil
996}
Mahir Gunyelfdee9212019-10-16 16:52:21 -0700997
Himani Chawla2ba1c9c2020-10-07 13:19:03 +0530998// This function updates the device transient in the DB through loader, releases the device lock, and runs any state transitions.
999// The calling function MUST hold the device lock. The caller MUST NOT modify the device after this is called.
1000func (agent *Agent) updateDeviceWithTransientStateAndReleaseLock(ctx context.Context, device *voltha.Device,
khenaidood948f772021-08-11 17:49:24 -04001001 transientState, prevTransientState core.DeviceTransientState_Types) error {
Himani Chawla2ba1c9c2020-10-07 13:19:03 +05301002 // fail early if this agent is no longer valid
1003 if agent.stopped {
1004 agent.requestQueue.RequestComplete()
1005 return errors.New("device-agent-stopped")
1006 }
1007 //update device TransientState
1008 if err := agent.updateTransientState(ctx, transientState); err != nil {
1009 agent.requestQueue.RequestComplete()
1010 return err
1011 }
1012 // update in db
1013 if err := agent.dbProxy.Set(ctx, agent.deviceID, device); err != nil {
1014 //Reverting TransientState update
khenaidood948f772021-08-11 17:49:24 -04001015 if errTransient := agent.updateTransientState(ctx, prevTransientState); errTransient != nil {
1016 logger.Errorw(ctx, "failed-to-revert-transient-state-update-on-error", log.Fields{"device-id": device.Id,
1017 "previous-transient-state": prevTransientState, "current-transient-state": transientState, "error": errTransient})
1018 }
Himani Chawla2ba1c9c2020-10-07 13:19:03 +05301019 agent.requestQueue.RequestComplete()
1020 return status.Errorf(codes.Internal, "failed-update-device:%s: %s", agent.deviceID, err)
1021 }
1022
1023 logger.Debugw(ctx, "updated-device-in-store", log.Fields{"device-id: ": agent.deviceID})
1024
1025 prevDevice := agent.device
1026 // update the device
1027 agent.device = device
Mahir Gunyelb0343bf2021-05-11 14:14:26 -07001028 //If any of the states has chenged, send the change event.
1029 if prevDevice.OperStatus != device.OperStatus || prevDevice.ConnectStatus != device.ConnectStatus || prevDevice.AdminState != device.AdminState {
1030 _ = agent.deviceMgr.Agent.SendDeviceStateChangeEvent(ctx, prevDevice.OperStatus, prevDevice.ConnectStatus, prevDevice.AdminState, device, time.Now().Unix())
1031 }
Himani Chawla2ba1c9c2020-10-07 13:19:03 +05301032
1033 // release lock before processing transition
1034 agent.requestQueue.RequestComplete()
khenaidood948f772021-08-11 17:49:24 -04001035 go func() {
1036 subCtx := coreutils.WithSpanAndRPCMetadataFromContext(ctx)
1037 if err := agent.deviceMgr.stateTransitions.ProcessTransition(subCtx,
1038 device, prevDevice, transientState, prevTransientState); err != nil {
1039 logger.Errorw(ctx, "failed-process-transition", log.Fields{"device-id": device.Id, "previous-admin-state": prevDevice.AdminState, "current-admin-state": device.AdminState})
1040 // Sending RPC EVENT here
1041 rpce := agent.deviceMgr.NewRPCEvent(ctx, agent.deviceID, err.Error(), nil)
1042 agent.deviceMgr.SendRPCEvent(ctx, "RPC_ERROR_RAISE_EVENT", rpce, voltha.EventCategory_COMMUNICATION,
1043 nil, time.Now().Unix())
1044 }
1045 }()
Himani Chawla2ba1c9c2020-10-07 13:19:03 +05301046 return nil
1047}
Kent Hagerman2b216042020-04-03 18:28:56 -04001048func (agent *Agent) updateDeviceReason(ctx context.Context, reason string) error {
khenaidood948f772021-08-11 17:49:24 -04001049 logger.Debugw(ctx, "update-device-reason", log.Fields{"device-id": agent.deviceID, "reason": reason})
1050
1051 var err error
1052 var desc string
1053 requestStatus := &common.OperationResp{Code: common.OperationResp_OPERATION_FAILURE}
1054 defer func() { agent.logDeviceUpdate(ctx, nil, nil, requestStatus, err, desc) }()
1055
1056 if err = agent.requestQueue.WaitForGreenLight(ctx); err != nil {
khenaidoo442e7c72020-03-10 16:13:48 -04001057 return err
1058 }
Maninder9a1bc0d2020-10-26 11:34:02 +05301059
Kent Hagermanf6db9f12020-07-22 17:16:19 -04001060 cloned := agent.cloneDeviceWithoutLock()
npujar1d86a522019-11-14 17:11:16 +05301061 cloned.Reason = reason
khenaidood948f772021-08-11 17:49:24 -04001062 if err = agent.updateDeviceAndReleaseLock(ctx, cloned); err == nil {
1063 requestStatus.Code = common.OperationResp_OPERATION_SUCCESS
Maninder9a1bc0d2020-10-26 11:34:02 +05301064 }
khenaidood948f772021-08-11 17:49:24 -04001065 return err
Mahir Gunyelfdee9212019-10-16 16:52:21 -07001066}
kesavandbc2d1622020-01-21 00:42:01 -05001067
Kent Hagerman2b216042020-04-03 18:28:56 -04001068func (agent *Agent) ChildDeviceLost(ctx context.Context, device *voltha.Device) error {
Himani Chawlab4c25912020-11-12 17:16:38 +05301069 logger.Debugw(ctx, "child-device-lost", log.Fields{"child-device-id": device.Id, "parent-device-id": agent.deviceID})
Chaitrashree G S543df3e2020-02-24 22:36:54 -05001070
khenaidood948f772021-08-11 17:49:24 -04001071 var err error
1072 var desc string
1073 requestStatus := &common.OperationResp{Code: common.OperationResp_OPERATION_FAILURE}
1074 defer func() { agent.logDeviceUpdate(ctx, nil, nil, requestStatus, err, desc) }()
1075
Kent Hagerman2a07b862020-06-19 15:23:07 -04001076 // Remove the associated peer ports on the parent device
1077 for portID := range agent.portLoader.ListIDs() {
1078 if portHandle, have := agent.portLoader.Lock(portID); have {
1079 oldPort := portHandle.GetReadOnly()
1080 updatedPeers := make([]*voltha.Port_PeerPort, 0)
1081 for _, peerPort := range oldPort.Peers {
1082 if peerPort.DeviceId != device.Id {
1083 updatedPeers = append(updatedPeers, peerPort)
1084 }
khenaidoo442e7c72020-03-10 16:13:48 -04001085 }
Kent Hagerman2a07b862020-06-19 15:23:07 -04001086 newPort := *oldPort
1087 newPort.Peers = updatedPeers
1088 if err := portHandle.Update(ctx, &newPort); err != nil {
1089 portHandle.Unlock()
1090 return nil
1091 }
1092 portHandle.Unlock()
khenaidoo442e7c72020-03-10 16:13:48 -04001093 }
Chaitrashree G S543df3e2020-02-24 22:36:54 -05001094 }
1095
khenaidoo442e7c72020-03-10 16:13:48 -04001096 //send request to adapter
khenaidood948f772021-08-11 17:49:24 -04001097 client, err := agent.adapterMgr.GetAdapterClient(ctx, agent.adapterEndpoint)
khenaidoo442e7c72020-03-10 16:13:48 -04001098 if err != nil {
khenaidood948f772021-08-11 17:49:24 -04001099 logger.Errorw(ctx, "grpc-client-nil",
1100 log.Fields{
1101 "error": err,
1102 "device-id": agent.deviceID,
1103 "device-type": agent.deviceType,
1104 "adapter-endpoint": device.AdapterEndpoint,
1105 })
khenaidoo442e7c72020-03-10 16:13:48 -04001106 return err
Chaitrashree G S543df3e2020-02-24 22:36:54 -05001107 }
khenaidood948f772021-08-11 17:49:24 -04001108 subCtx, cancel := context.WithTimeout(coreutils.WithAllMetadataFromContext(ctx), agent.rpcTimeout)
1109 requestStatus.Code = common.OperationResp_OPERATION_IN_PROGRESS
1110 go func() {
1111 defer cancel()
1112 _, err := client.ChildDeviceLost(subCtx, device)
1113 if err == nil {
1114 agent.onSuccess(subCtx, nil, nil, true)
1115 } else {
1116 agent.onFailure(subCtx, err, nil, nil, true)
1117 }
1118 }()
Chaitrashree G S543df3e2020-02-24 22:36:54 -05001119 return nil
Chaitrashree G S543df3e2020-02-24 22:36:54 -05001120}
onkarkundargi87285252020-01-27 11:34:52 +05301121
Kent Hagerman2b216042020-04-03 18:28:56 -04001122func (agent *Agent) startOmciTest(ctx context.Context, omcitestrequest *voltha.OmciTestRequest) (*voltha.TestResponse, error) {
khenaidood948f772021-08-11 17:49:24 -04001123 var err error
1124 var desc string
1125 requestStatus := &common.OperationResp{Code: common.OperationResp_OPERATION_FAILURE}
1126 defer func() { agent.logDeviceUpdate(ctx, nil, nil, requestStatus, err, desc) }()
onkarkundargi87285252020-01-27 11:34:52 +05301127
khenaidood948f772021-08-11 17:49:24 -04001128 // OMCI test may be performed on a pre-provisioned device. If a device is in that state both its device type and endpoint
1129 // may not have been set yet.
1130 // First check if we need to update the type or endpoint
1131 cloned, err := agent.getDeviceReadOnly(ctx)
onkarkundargi87285252020-01-27 11:34:52 +05301132 if err != nil {
1133 return nil, err
1134 }
khenaidood948f772021-08-11 17:49:24 -04001135 if cloned.Type == "" || cloned.AdapterEndpoint == "" {
1136 if err = agent.updateDeviceTypeAndEndpoint(ctx); err != nil {
1137 return nil, err
1138 }
1139 cloned, err = agent.getDeviceReadOnly(ctx)
1140 if err != nil {
1141 return nil, err
1142 }
onkarkundargi87285252020-01-27 11:34:52 +05301143 }
1144
khenaidood948f772021-08-11 17:49:24 -04001145 // Send request to the adapter
1146 client, err := agent.adapterMgr.GetAdapterClient(ctx, agent.adapterEndpoint)
1147 if err != nil {
1148 logger.Errorw(ctx, "grpc-client-nil",
1149 log.Fields{
1150 "error": err,
1151 "device-id": agent.deviceID,
1152 "device-type": agent.deviceType,
1153 "adapter-endpoint": cloned.AdapterEndpoint,
1154 })
1155 return nil, err
onkarkundargi87285252020-01-27 11:34:52 +05301156 }
khenaidood948f772021-08-11 17:49:24 -04001157
1158 res, err := client.StartOmciTest(ctx, &ic.OMCITest{
1159 Device: cloned,
1160 Request: omcitestrequest,
1161 })
1162 if err == nil {
1163 requestStatus.Code = common.OperationResp_OPERATION_SUCCESS
1164 }
1165 return res, err
onkarkundargi87285252020-01-27 11:34:52 +05301166}
Dinesh Belwalkarc1129f12020-02-27 10:41:33 -08001167
1168func (agent *Agent) getExtValue(ctx context.Context, pdevice *voltha.Device, cdevice *voltha.Device, valueparam *voltha.ValueSpecifier) (*voltha.ReturnValues, error) {
Himani Chawlab4c25912020-11-12 17:16:38 +05301169 logger.Debugw(ctx, "get-ext-value", log.Fields{"device-id": agent.deviceID, "onu-id": valueparam.Id, "value-type": valueparam.Value})
khenaidood948f772021-08-11 17:49:24 -04001170 var err error
1171 var desc string
1172 requestStatus := &common.OperationResp{Code: common.OperationResp_OPERATION_FAILURE}
1173 defer func() { agent.logDeviceUpdate(ctx, nil, nil, requestStatus, err, desc) }()
1174
1175 if err = agent.requestQueue.WaitForGreenLight(ctx); err != nil {
Dinesh Belwalkarc1129f12020-02-27 10:41:33 -08001176 return nil, err
1177 }
1178
khenaidood948f772021-08-11 17:49:24 -04001179 //send request to adapter synchronously
1180 client, err := agent.adapterMgr.GetAdapterClient(ctx, pdevice.AdapterEndpoint)
Dinesh Belwalkarc1129f12020-02-27 10:41:33 -08001181 if err != nil {
khenaidood948f772021-08-11 17:49:24 -04001182 logger.Errorw(ctx, "grpc-client-nil",
1183 log.Fields{
1184 "error": err,
1185 "device-id": agent.deviceID,
1186 "device-type": agent.deviceType,
1187 "adapter-endpoint": pdevice.AdapterEndpoint,
1188 })
1189 agent.requestQueue.RequestComplete()
Dinesh Belwalkarc1129f12020-02-27 10:41:33 -08001190 return nil, err
1191 }
1192
khenaidood948f772021-08-11 17:49:24 -04001193 // Release lock before sending to adapter
1194 agent.requestQueue.RequestComplete()
Dinesh Belwalkarc1129f12020-02-27 10:41:33 -08001195
khenaidood948f772021-08-11 17:49:24 -04001196 retVal, err := client.GetExtValue(ctx, &ic.GetExtValueMessage{
1197 ParentDevice: pdevice,
1198 ChildDevice: cdevice,
1199 ValueType: valueparam.Value,
1200 })
1201 if err == nil {
1202 requestStatus.Code = common.OperationResp_OPERATION_SUCCESS
Dinesh Belwalkarc1129f12020-02-27 10:41:33 -08001203 }
khenaidood948f772021-08-11 17:49:24 -04001204 return retVal, err
Dinesh Belwalkarc1129f12020-02-27 10:41:33 -08001205}
dpaul62686312020-06-23 14:17:36 +05301206
1207func (agent *Agent) setExtValue(ctx context.Context, device *voltha.Device, value *voltha.ValueSet) (*empty.Empty, error) {
Himani Chawlab4c25912020-11-12 17:16:38 +05301208 logger.Debugw(ctx, "set-ext-value", log.Fields{"device-id": value.Id})
khenaidood948f772021-08-11 17:49:24 -04001209
1210 var err error
1211 var desc string
1212 requestStatus := &common.OperationResp{Code: common.OperationResp_OPERATION_FAILURE}
1213 defer func() { agent.logDeviceUpdate(ctx, nil, nil, requestStatus, err, desc) }()
1214
1215 if err = agent.requestQueue.WaitForGreenLight(ctx); err != nil {
dpaul62686312020-06-23 14:17:36 +05301216 return nil, err
1217 }
1218
1219 //send request to adapter
khenaidood948f772021-08-11 17:49:24 -04001220 //send request to adapter synchronously
1221 client, err := agent.adapterMgr.GetAdapterClient(ctx, agent.adapterEndpoint)
dpaul62686312020-06-23 14:17:36 +05301222 if err != nil {
khenaidood948f772021-08-11 17:49:24 -04001223 logger.Errorw(ctx, "grpc-client-nil",
1224 log.Fields{
1225 "error": err,
1226 "device-id": agent.deviceID,
1227 "device-type": agent.deviceType,
1228 "adapter-endpoint": device.AdapterEndpoint,
1229 })
1230 agent.requestQueue.RequestComplete()
dpaul62686312020-06-23 14:17:36 +05301231 return nil, err
1232 }
khenaidood948f772021-08-11 17:49:24 -04001233 // Release lock before sending request to adapter
1234 agent.requestQueue.RequestComplete()
dpaul62686312020-06-23 14:17:36 +05301235
khenaidood948f772021-08-11 17:49:24 -04001236 retVal, err := client.SetExtValue(ctx, &ic.SetExtValueMessage{
1237 Device: device,
1238 Value: value,
1239 })
1240 if err == nil {
1241 requestStatus.Code = common.OperationResp_OPERATION_SUCCESS
dpaul62686312020-06-23 14:17:36 +05301242 }
khenaidood948f772021-08-11 17:49:24 -04001243 return retVal, err
dpaul62686312020-06-23 14:17:36 +05301244}
Salman Siddiqui1cf95042020-11-19 00:42:56 +05301245
1246func (agent *Agent) getSingleValue(ctx context.Context, request *extension.SingleGetValueRequest) (*extension.SingleGetValueResponse, error) {
Himani Chawlab4c25912020-11-12 17:16:38 +05301247 logger.Debugw(ctx, "get-single-value", log.Fields{"device-id": request.TargetId})
Salman Siddiqui1cf95042020-11-19 00:42:56 +05301248
khenaidood948f772021-08-11 17:49:24 -04001249 var err error
1250 var desc string
1251 requestStatus := &common.OperationResp{Code: common.OperationResp_OPERATION_FAILURE}
1252 defer func() { agent.logDeviceUpdate(ctx, nil, nil, requestStatus, err, desc) }()
1253
1254 if err = agent.requestQueue.WaitForGreenLight(ctx); err != nil {
Salman Siddiqui1cf95042020-11-19 00:42:56 +05301255 return nil, err
1256 }
1257
1258 cloned := agent.cloneDeviceWithoutLock()
1259
1260 //send request to adapter
khenaidood948f772021-08-11 17:49:24 -04001261 client, err := agent.adapterMgr.GetAdapterClient(ctx, agent.adapterEndpoint)
Salman Siddiqui1cf95042020-11-19 00:42:56 +05301262 if err != nil {
khenaidood948f772021-08-11 17:49:24 -04001263 logger.Errorw(ctx, "grpc-client-nil",
1264 log.Fields{
1265 "error": err,
1266 "device-id": cloned.Id,
1267 "adapter-endpoint": cloned.AdapterEndpoint,
1268 })
1269 agent.requestQueue.RequestComplete()
Salman Siddiqui1cf95042020-11-19 00:42:56 +05301270 return nil, err
1271 }
khenaidood948f772021-08-11 17:49:24 -04001272 // Release lock before sending request to adapter
1273 agent.requestQueue.RequestComplete()
Salman Siddiqui1cf95042020-11-19 00:42:56 +05301274
khenaidood948f772021-08-11 17:49:24 -04001275 resp, err := client.GetSingleValue(ctx, request)
1276 if err == nil {
1277 requestStatus.Code = common.OperationResp_OPERATION_SUCCESS
Salman Siddiqui1cf95042020-11-19 00:42:56 +05301278 }
khenaidood948f772021-08-11 17:49:24 -04001279 return resp, err
Salman Siddiqui1cf95042020-11-19 00:42:56 +05301280}
1281
1282func (agent *Agent) setSingleValue(ctx context.Context, request *extension.SingleSetValueRequest) (*extension.SingleSetValueResponse, error) {
Himani Chawlab4c25912020-11-12 17:16:38 +05301283 logger.Debugw(ctx, "set-single-value", log.Fields{"device-id": request.TargetId})
Salman Siddiqui1cf95042020-11-19 00:42:56 +05301284
khenaidood948f772021-08-11 17:49:24 -04001285 var err error
1286 var desc string
1287 requestStatus := &common.OperationResp{Code: common.OperationResp_OPERATION_FAILURE}
1288 defer func() { agent.logDeviceUpdate(ctx, nil, nil, requestStatus, err, desc) }()
1289
Salman Siddiqui1cf95042020-11-19 00:42:56 +05301290 if err := agent.requestQueue.WaitForGreenLight(ctx); err != nil {
1291 return nil, err
1292 }
1293
1294 cloned := agent.cloneDeviceWithoutLock()
1295
1296 //send request to adapter
khenaidood948f772021-08-11 17:49:24 -04001297 client, err := agent.adapterMgr.GetAdapterClient(ctx, agent.adapterEndpoint)
Salman Siddiqui1cf95042020-11-19 00:42:56 +05301298 if err != nil {
khenaidood948f772021-08-11 17:49:24 -04001299 logger.Errorw(ctx, "grpc-client-nil",
1300 log.Fields{
1301 "error": err,
1302 "device-id": agent.deviceID,
1303 "device-type": agent.deviceType,
1304 "adapter-endpoint": cloned.AdapterEndpoint,
1305 })
1306 agent.requestQueue.RequestComplete()
Salman Siddiqui1cf95042020-11-19 00:42:56 +05301307 return nil, err
1308 }
khenaidood948f772021-08-11 17:49:24 -04001309 // Release lock before sending request to adapter
1310 agent.requestQueue.RequestComplete()
Salman Siddiqui1cf95042020-11-19 00:42:56 +05301311
khenaidood948f772021-08-11 17:49:24 -04001312 resp, err := client.SetSingleValue(ctx, request)
1313 if err == nil {
1314 requestStatus.Code = common.OperationResp_OPERATION_SUCCESS
Salman Siddiqui1cf95042020-11-19 00:42:56 +05301315 }
khenaidood948f772021-08-11 17:49:24 -04001316 return resp, err
Salman Siddiqui1cf95042020-11-19 00:42:56 +05301317}
Maninder0aabf0c2021-03-17 14:55:14 +05301318
Maninder2195ccc2021-06-23 20:23:01 +05301319func (agent *Agent) proceedWithRequest(device *voltha.Device) bool {
1320 return !agent.isDeletionInProgress() && !agent.isInReconcileState(device)
Maninder0aabf0c2021-03-17 14:55:14 +05301321}
1322
1323func (agent *Agent) stopReconcile() {
1324 agent.stopReconcilingMutex.Lock()
1325 if agent.stopReconciling != nil {
1326 agent.stopReconciling <- 0
1327 }
1328 agent.stopReconcilingMutex.Unlock()
1329}
1330
khenaidood948f772021-08-11 17:49:24 -04001331// abortAllProcessing is invoked when an adapter managing this device is restarted
1332func (agent *Agent) abortAllProcessing(ctx context.Context) error {
1333 logger.Infow(ctx, "aborting-current-running-requests", log.Fields{"device-id": agent.deviceID})
1334 if err := agent.requestQueue.WaitForGreenLight(ctx); err != nil {
1335 return err
1336 }
1337 defer agent.requestQueue.RequestComplete()
1338
1339 // If any reconciling is in progress just abort it. The adapter is gone.
1340 agent.stopReconcile()
1341
1342 // Update the Core device transient state accordingly
1343 var updatedState core.DeviceTransientState_Types
1344 switch agent.getTransientState() {
1345 case core.DeviceTransientState_RECONCILE_IN_PROGRESS:
1346 updatedState = core.DeviceTransientState_NONE
1347 case core.DeviceTransientState_FORCE_DELETING:
1348 updatedState = core.DeviceTransientState_DELETE_FAILED
1349 case core.DeviceTransientState_DELETING_FROM_ADAPTER:
1350 updatedState = core.DeviceTransientState_DELETE_FAILED
1351 default:
1352 updatedState = core.DeviceTransientState_NONE
1353 }
1354 if err := agent.updateTransientState(ctx, updatedState); err != nil {
1355 logger.Errorf(ctx, "transient-state-update-failed", log.Fields{"error": err})
1356 return err
1357 }
1358 return nil
1359}
1360
1361func (agent *Agent) ReconcileDevice(ctx context.Context) {
1362 requestStatus := &common.OperationResp{Code: common.OperationResp_OPERATION_FAILURE}
Maninder0aabf0c2021-03-17 14:55:14 +05301363 var desc string
Maninder0aabf0c2021-03-17 14:55:14 +05301364
1365 if err := agent.requestQueue.WaitForGreenLight(ctx); err != nil {
khenaidood948f772021-08-11 17:49:24 -04001366 agent.logDeviceUpdate(ctx, nil, nil, requestStatus, err, desc)
1367 return
1368 }
1369
1370 device := agent.getDeviceReadOnlyWithoutLock()
1371 if device.AdminState == voltha.AdminState_PREPROVISIONED {
1372 agent.requestQueue.RequestComplete()
1373 logger.Debugw(ctx, "device-in-preprovisioning-state-reconcile-not-needed", log.Fields{"device-id": device.Id})
Maninder0aabf0c2021-03-17 14:55:14 +05301374 return
1375 }
1376
Maninder2195ccc2021-06-23 20:23:01 +05301377 if !agent.proceedWithRequest(device) {
Maninder0aabf0c2021-03-17 14:55:14 +05301378 agent.requestQueue.RequestComplete()
khenaidood948f772021-08-11 17:49:24 -04001379 err := fmt.Errorf("cannot complete operation as device deletion/reconciling is in progress or reconcile failed for device : %s", device.Id)
1380 logger.Errorw(ctx, "reconcile-failed", log.Fields{"error": err})
1381 agent.logDeviceUpdate(ctx, nil, nil, requestStatus, err, desc)
Maninder0aabf0c2021-03-17 14:55:14 +05301382 return
1383 }
1384
1385 //set transient state to RECONCILE IN PROGRESS
khenaidood948f772021-08-11 17:49:24 -04001386 err := agent.updateTransientState(ctx, core.DeviceTransientState_RECONCILE_IN_PROGRESS)
Maninder0aabf0c2021-03-17 14:55:14 +05301387 if err != nil {
1388 agent.requestQueue.RequestComplete()
khenaidood948f772021-08-11 17:49:24 -04001389 logger.Errorw(ctx, "setting-transient-state-failed", log.Fields{"error": err})
1390 agent.logDeviceUpdate(ctx, nil, nil, requestStatus, nil, desc)
Maninder0aabf0c2021-03-17 14:55:14 +05301391 return
1392 }
1393
Maninder0aabf0c2021-03-17 14:55:14 +05301394 reconcilingBackoff := backoff.NewExponentialBackOff()
1395 reconcilingBackoff.InitialInterval = agent.config.BackoffRetryInitialInterval
1396 reconcilingBackoff.MaxElapsedTime = agent.config.BackoffRetryMaxElapsedTime
1397 reconcilingBackoff.MaxInterval = agent.config.BackoffRetryMaxInterval
1398
1399 //making here to keep lifecycle of this channel within the scope of retryReconcile
1400 agent.stopReconcilingMutex.Lock()
1401 agent.stopReconciling = make(chan int)
1402 agent.stopReconcilingMutex.Unlock()
1403
David K. Bainbridge482e4422021-06-30 12:23:42 -07001404 // defined outside the retry loop so it can be cleaned
1405 // up when the loop breaks
1406 var backoffTimer *time.Timer
1407
1408retry:
Maninder0aabf0c2021-03-17 14:55:14 +05301409 for {
David K. Bainbridge482e4422021-06-30 12:23:42 -07001410 // If the operations state of the device is RECONCILING_FAILED then we do not
1411 // want to continue to attempt reconciliation.
1412 deviceRef := agent.getDeviceReadOnlyWithoutLock()
1413 if deviceRef.OperStatus == common.OperStatus_RECONCILING_FAILED {
1414 logger.Warnw(ctx, "reconciling-failed-halting-retries",
1415 log.Fields{"device-id": device.Id})
1416 agent.requestQueue.RequestComplete()
1417 break retry
1418 }
1419
Maninder0aabf0c2021-03-17 14:55:14 +05301420 // Use an exponential back off to prevent getting into a tight loop
1421 duration := reconcilingBackoff.NextBackOff()
1422 //This case should never occur in default case as max elapsed time for backoff is 0(by default) , so it will never return stop
1423 if duration == backoff.Stop {
1424 // If we reach a maximum then warn and reset the backoff
1425 // timer and keep attempting.
1426 logger.Warnw(ctx, "maximum-reconciling-backoff-reached--resetting-backoff-timer",
1427 log.Fields{"max-reconciling-backoff": reconcilingBackoff.MaxElapsedTime,
1428 "device-id": device.Id})
1429 reconcilingBackoff.Reset()
1430 duration = reconcilingBackoff.NextBackOff()
1431 }
1432
David K. Bainbridge482e4422021-06-30 12:23:42 -07001433 backoffTimer = time.NewTimer(duration)
Maninder0aabf0c2021-03-17 14:55:14 +05301434
khenaidood948f772021-08-11 17:49:24 -04001435 logger.Debugw(ctx, "retrying-reconciling", log.Fields{"deviceID": device.Id, "endpoint": device.AdapterEndpoint})
1436 // Release lock before sending request to adapter
Maninder0aabf0c2021-03-17 14:55:14 +05301437 agent.requestQueue.RequestComplete()
khenaidood948f772021-08-11 17:49:24 -04001438
1439 // Send a reconcile request to the adapter.
1440 err := agent.sendReconcileRequestToAdapter(ctx, device)
1441 if errors.Is(err, errContextExpired) || errors.Is(err, errReconcileAborted) {
1442 logger.Errorw(ctx, "reconcile-aborted", log.Fields{"error": err})
1443 requestStatus = &common.OperationResp{Code: common.OperationResp_OperationReturnCode(common.OperStatus_FAILED)}
1444 desc = "aborted"
1445 agent.logDeviceUpdate(ctx, nil, nil, requestStatus, err, desc)
1446 break retry
1447 }
Maninder0aabf0c2021-03-17 14:55:14 +05301448 if err != nil {
khenaidood948f772021-08-11 17:49:24 -04001449 agent.logDeviceUpdate(ctx, nil, nil, requestStatus, err, desc)
Maninder0aabf0c2021-03-17 14:55:14 +05301450 <-backoffTimer.C
1451 // backoffTimer expired continue
1452 // Take lock back before retrying
1453 if err := agent.requestQueue.WaitForGreenLight(ctx); err != nil {
khenaidood948f772021-08-11 17:49:24 -04001454 agent.logDeviceUpdate(ctx, nil, nil, requestStatus, err, desc)
David K. Bainbridge482e4422021-06-30 12:23:42 -07001455 break retry
Maninder0aabf0c2021-03-17 14:55:14 +05301456 }
1457 continue
1458 }
khenaidood948f772021-08-11 17:49:24 -04001459 // Success
1460 requestStatus = &common.OperationResp{Code: common.OperationResp_OPERATION_SUCCESS}
1461 desc = "adapter-response"
1462 agent.logDeviceUpdate(ctx, nil, nil, requestStatus, err, desc)
1463 break retry
David K. Bainbridge482e4422021-06-30 12:23:42 -07001464 }
1465
1466 // Retry loop is broken, so stop any timers and drain the channel
1467 if backoffTimer != nil && !backoffTimer.Stop() {
1468
1469 // As per documentation and stack overflow when a timer is stopped its
1470 // channel should be drained. The issue is that Stop returns false
1471 // either if the timer has already been fired "OR" if the timer can be
1472 // stopped before being fired. This means that in some cases the
1473 // channel has already be emptied so attempting to read from it means
1474 // a blocked thread. To get around this use a select so if the
1475 // channel is already empty the default case hits and we are not
1476 // blocked.
1477 select {
1478 case <-backoffTimer.C:
1479 default:
Maninder0aabf0c2021-03-17 14:55:14 +05301480 }
1481 }
1482}
1483
khenaidood948f772021-08-11 17:49:24 -04001484func (agent *Agent) sendReconcileRequestToAdapter(ctx context.Context, device *voltha.Device) error {
1485 logger.Debugw(ctx, "sending-reconcile-to-adapter", log.Fields{"device-id": device.Id, "endpoint": agent.adapterEndpoint})
1486 client, err := agent.adapterMgr.GetAdapterClient(ctx, agent.adapterEndpoint)
1487 if err != nil {
1488 return err
1489 }
1490 adapterResponse := make(chan error)
1491 go func() {
1492 _, err := client.ReconcileDevice(ctx, device)
1493 adapterResponse <- err
1494 }()
Maninder0aabf0c2021-03-17 14:55:14 +05301495 select {
1496 // wait for response
khenaidood948f772021-08-11 17:49:24 -04001497 case err := <-adapterResponse:
1498 if err != nil {
1499 return err
Maninder0aabf0c2021-03-17 14:55:14 +05301500 }
Maninder0aabf0c2021-03-17 14:55:14 +05301501 //In case of success quit retrying and wait for adapter to reset operation state of device
1502 agent.stopReconcilingMutex.Lock()
1503 agent.stopReconciling = nil
1504 agent.stopReconcilingMutex.Unlock()
1505 return nil
1506
1507 //if reconciling need to be stopped
1508 case _, ok := <-agent.stopReconciling:
1509 agent.stopReconcilingMutex.Lock()
1510 agent.stopReconciling = nil
1511 agent.stopReconcilingMutex.Unlock()
1512 if !ok {
1513 //channel-closed
khenaidood948f772021-08-11 17:49:24 -04001514 return fmt.Errorf("reconcile channel closed:%w", errReconcileAborted)
Maninder0aabf0c2021-03-17 14:55:14 +05301515 }
khenaidood948f772021-08-11 17:49:24 -04001516 return fmt.Errorf("reconciling aborted:%w", errReconcileAborted)
1517 // Context expired
1518 case <-ctx.Done():
1519 return fmt.Errorf("context expired:%s :%w", ctx.Err(), errContextExpired)
Maninder0aabf0c2021-03-17 14:55:14 +05301520 }
Maninder0aabf0c2021-03-17 14:55:14 +05301521}
1522
1523func (agent *Agent) reconcilingCleanup(ctx context.Context) error {
1524 var desc string
khenaidood948f772021-08-11 17:49:24 -04001525 var err error
Maninder0aabf0c2021-03-17 14:55:14 +05301526 operStatus := &common.OperationResp{Code: common.OperationResp_OPERATION_FAILURE}
khenaidood948f772021-08-11 17:49:24 -04001527 defer func() { agent.logDeviceUpdate(ctx, nil, nil, operStatus, err, desc) }()
1528
1529 if err = agent.requestQueue.WaitForGreenLight(ctx); err != nil {
1530 desc = "reconcile-cleanup-failed"
Maninder0aabf0c2021-03-17 14:55:14 +05301531 return err
1532 }
1533 defer agent.requestQueue.RequestComplete()
khenaidood948f772021-08-11 17:49:24 -04001534 err = agent.updateTransientState(ctx, core.DeviceTransientState_NONE)
Maninder0aabf0c2021-03-17 14:55:14 +05301535 if err != nil {
khenaidood948f772021-08-11 17:49:24 -04001536 logger.Errorf(ctx, "transient-state-update-failed", log.Fields{"error": err})
Maninder0aabf0c2021-03-17 14:55:14 +05301537 return err
1538 }
khenaidood948f772021-08-11 17:49:24 -04001539 operStatus.Code = common.OperationResp_OPERATION_SUCCESS
Maninder0aabf0c2021-03-17 14:55:14 +05301540 return nil
1541}
khenaidood948f772021-08-11 17:49:24 -04001542
1543func (agent *Agent) isAdapterConnectionUp(ctx context.Context) bool {
1544 c, err := agent.adapterMgr.GetAdapterClient(ctx, agent.adapterEndpoint)
1545 return c != nil && err == nil
1546}
1547
1548func (agent *Agent) canDeviceRequestProceed(ctx context.Context) error {
1549 if err := agent.requestQueue.WaitForGreenLight(ctx); err != nil {
1550 return err
1551 }
1552 defer agent.requestQueue.RequestComplete()
1553 if agent.proceedWithRequest(agent.device) {
1554 return nil
1555 }
1556 return fmt.Errorf("device-cannot-process-request-%s", agent.deviceID)
1557}