blob: 818b9764c8ed47df6e1bcd0d5f64dd043b008ab9 [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
khenaidoo9beaaf12021-10-19 17:32:01 -040028 "github.com/opencord/voltha-protos/v5/go/adapter_service"
khenaidood948f772021-08-11 17:49:24 -040029 "github.com/opencord/voltha-protos/v5/go/core"
khenaidoo9beaaf12021-10-19 17:32:01 -040030 "github.com/opencord/voltha-protos/v5/go/omci"
khenaidood948f772021-08-11 17:49:24 -040031
Maninder0aabf0c2021-03-17 14:55:14 +053032 "github.com/cenkalti/backoff/v3"
Maninder9a1bc0d2020-10-26 11:34:02 +053033 "github.com/gogo/protobuf/proto"
Maninder9a1bc0d2020-10-26 11:34:02 +053034 "github.com/golang/protobuf/ptypes/empty"
Maninder0aabf0c2021-03-17 14:55:14 +053035 "github.com/opencord/voltha-go/rw_core/config"
Maninder9a1bc0d2020-10-26 11:34:02 +053036 "google.golang.org/grpc/codes"
37 "google.golang.org/grpc/status"
Mahir Gunyeladdb66a2020-04-29 18:08:50 -070038
Himani Chawla2ba1c9c2020-10-07 13:19:03 +053039 "github.com/opencord/voltha-go/db/model"
Kent Hagerman2b216042020-04-03 18:28:56 -040040 "github.com/opencord/voltha-go/rw_core/core/adapter"
Mahir Gunyel03de0d32020-06-03 01:36:59 -070041 "github.com/opencord/voltha-go/rw_core/core/device/flow"
42 "github.com/opencord/voltha-go/rw_core/core/device/group"
Kent Hagerman2a07b862020-06-19 15:23:07 -040043 "github.com/opencord/voltha-go/rw_core/core/device/port"
Himani Chawla2ba1c9c2020-10-07 13:19:03 +053044 "github.com/opencord/voltha-go/rw_core/core/device/transientstate"
Scott Bakerb671a862019-10-24 10:53:40 -070045 coreutils "github.com/opencord/voltha-go/rw_core/utils"
khenaidood948f772021-08-11 17:49:24 -040046 "github.com/opencord/voltha-lib-go/v7/pkg/log"
47 "github.com/opencord/voltha-protos/v5/go/common"
khenaidoo9beaaf12021-10-19 17:32:01 -040048 ca "github.com/opencord/voltha-protos/v5/go/core_adapter"
khenaidood948f772021-08-11 17:49:24 -040049 "github.com/opencord/voltha-protos/v5/go/extension"
khenaidood948f772021-08-11 17:49:24 -040050 ofp "github.com/opencord/voltha-protos/v5/go/openflow_13"
51 "github.com/opencord/voltha-protos/v5/go/voltha"
khenaidoob9203542018-09-17 22:56:37 -040052)
53
khenaidood948f772021-08-11 17:49:24 -040054var errReconcileAborted = errors.New("reconcile aborted")
55var errContextExpired = errors.New("context expired")
56
Kent Hagerman2b216042020-04-03 18:28:56 -040057// Agent represents device agent attributes
58type Agent struct {
Maninder0aabf0c2021-03-17 14:55:14 +053059 deviceID string
60 parentID string
61 deviceType string
khenaidood948f772021-08-11 17:49:24 -040062 adapterEndpoint string
Maninder0aabf0c2021-03-17 14:55:14 +053063 isRootDevice bool
Maninder0aabf0c2021-03-17 14:55:14 +053064 adapterMgr *adapter.Manager
65 deviceMgr *Manager
66 dbProxy *model.Proxy
67 exitChannel chan int
68 device *voltha.Device
69 requestQueue *coreutils.RequestQueue
khenaidood948f772021-08-11 17:49:24 -040070 internalTimeout time.Duration
71 rpcTimeout time.Duration
Himani Chawla4b4bd252021-11-08 15:59:40 +053072 flowTimeout time.Duration
Maninder0aabf0c2021-03-17 14:55:14 +053073 startOnce sync.Once
74 stopOnce sync.Once
75 stopped bool
76 stopReconciling chan int
77 stopReconcilingMutex sync.RWMutex
78 config *config.RWCoreFlags
Mahir Gunyel03de0d32020-06-03 01:36:59 -070079
khenaidoo7585a962021-06-10 16:15:38 -040080 flowCache *flow.Cache
81 groupCache *group.Cache
Himani Chawla2ba1c9c2020-10-07 13:19:03 +053082 portLoader *port.Loader
83 transientStateLoader *transientstate.Loader
khenaidoob9203542018-09-17 22:56:37 -040084}
85
Kent Hagerman2b216042020-04-03 18:28:56 -040086//newAgent creates a new device agent. The device will be initialized when start() is called.
Himani Chawla4b4bd252021-11-08 15:59:40 +053087func newAgent(device *voltha.Device, deviceMgr *Manager, dbPath *model.Path, deviceProxy *model.Proxy, internalTimeout, rpcTimeout, flowTimeout time.Duration) *Agent {
Kent Hagerman2a07b862020-06-19 15:23:07 -040088 deviceID := device.Id
89 if deviceID == "" {
90 deviceID = coreutils.CreateDeviceID()
Stephane Barbarie1ab43272018-12-08 21:42:13 -050091 }
Scott Baker80678602019-11-14 16:57:36 -080092
Kent Hagerman2a07b862020-06-19 15:23:07 -040093 return &Agent{
Himani Chawla2ba1c9c2020-10-07 13:19:03 +053094 deviceID: deviceID,
Himani Chawla2ba1c9c2020-10-07 13:19:03 +053095 isRootDevice: device.Root,
96 parentID: device.ParentId,
97 deviceType: device.Type,
khenaidood948f772021-08-11 17:49:24 -040098 adapterEndpoint: device.AdapterEndpoint,
Himani Chawla2ba1c9c2020-10-07 13:19:03 +053099 deviceMgr: deviceMgr,
100 adapterMgr: deviceMgr.adapterMgr,
101 exitChannel: make(chan int, 1),
102 dbProxy: deviceProxy,
khenaidood948f772021-08-11 17:49:24 -0400103 internalTimeout: internalTimeout,
104 rpcTimeout: rpcTimeout,
Himani Chawla4b4bd252021-11-08 15:59:40 +0530105 flowTimeout: flowTimeout,
Himani Chawla2ba1c9c2020-10-07 13:19:03 +0530106 device: proto.Clone(device).(*voltha.Device),
107 requestQueue: coreutils.NewRequestQueue(),
Maninder0aabf0c2021-03-17 14:55:14 +0530108 config: deviceMgr.config,
khenaidoo7585a962021-06-10 16:15:38 -0400109 flowCache: flow.NewCache(),
110 groupCache: group.NewCache(),
Himani Chawla2ba1c9c2020-10-07 13:19:03 +0530111 portLoader: port.NewLoader(dbPath.SubPath("ports").Proxy(deviceID)),
112 transientStateLoader: transientstate.NewLoader(dbPath.SubPath("core").Proxy("transientstate"), deviceID),
Kent Hagerman2a07b862020-06-19 15:23:07 -0400113 }
khenaidoob9203542018-09-17 22:56:37 -0400114}
115
khenaidoo442e7c72020-03-10 16:13:48 -0400116// start() saves the device to the data model and registers for callbacks on that device if deviceToCreate!=nil.
117// 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 -0800118// was started.
khenaidoo7585a962021-06-10 16:15:38 -0400119func (agent *Agent) start(ctx context.Context, deviceExist bool, deviceToCreate *voltha.Device) (*voltha.Device, error) {
khenaidoo442e7c72020-03-10 16:13:48 -0400120 needToStart := false
121 if agent.startOnce.Do(func() { needToStart = true }); !needToStart {
Kent Hagermancba2f302020-07-28 13:37:36 -0400122 return agent.getDeviceReadOnly(ctx)
khenaidoo442e7c72020-03-10 16:13:48 -0400123 }
124 var startSucceeded bool
125 defer func() {
126 if !startSucceeded {
127 if err := agent.stop(ctx); err != nil {
Rohan Agrawal31f21802020-06-12 05:38:46 +0000128 logger.Errorw(ctx, "failed-to-cleanup-after-unsuccessful-start", log.Fields{"device-id": agent.deviceID, "error": err})
khenaidoo442e7c72020-03-10 16:13:48 -0400129 }
130 }
131 }()
khenaidoo7585a962021-06-10 16:15:38 -0400132 if deviceExist {
133 device := deviceToCreate
134 if device == nil {
135 // Load from dB
136 device = &voltha.Device{}
137 have, err := agent.dbProxy.Get(ctx, agent.deviceID, device)
138 if err != nil {
139 return nil, err
140 } else if !have {
141 return nil, status.Errorf(codes.NotFound, "device-%s", agent.deviceID)
142 }
khenaidood948f772021-08-11 17:49:24 -0400143 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 +0530144 }
khenaidood948f772021-08-11 17:49:24 -0400145 agent.deviceType = device.Type
146 agent.adapterEndpoint = device.AdapterEndpoint
Kent Hagerman4f355f52020-03-30 16:01:33 -0400147 agent.device = proto.Clone(device).(*voltha.Device)
khenaidoo7585a962021-06-10 16:15:38 -0400148 // load the ports from KV to cache
Kent Hagerman2a07b862020-06-19 15:23:07 -0400149 agent.portLoader.Load(ctx)
Himani Chawla2ba1c9c2020-10-07 13:19:03 +0530150 agent.transientStateLoader.Load(ctx)
khenaidoo297cd252019-02-07 22:10:23 -0500151 } else {
Scott Baker80678602019-11-14 16:57:36 -0800152 // Create a new device
Maninder9a1bc0d2020-10-26 11:34:02 +0530153 var desc string
khenaidood948f772021-08-11 17:49:24 -0400154 var err error
Maninder9a1bc0d2020-10-26 11:34:02 +0530155 prevState := common.AdminState_UNKNOWN
156 currState := common.AdminState_UNKNOWN
khenaidood948f772021-08-11 17:49:24 -0400157 requestStatus := &common.OperationResp{Code: common.OperationResp_OPERATION_FAILURE}
Maninder9a1bc0d2020-10-26 11:34:02 +0530158
khenaidood948f772021-08-11 17:49:24 -0400159 defer func() { agent.logDeviceUpdate(ctx, &prevState, &currState, requestStatus, err, desc) }()
Maninder9a1bc0d2020-10-26 11:34:02 +0530160
Kent Hagermanf5a67352020-04-30 15:15:26 -0400161 // Assumption is that AdminState, FlowGroups, and Flows are uninitialized since this
162 // is a new device, so populate them here before passing the device to ldProxy.Set.
Kent Hagerman2b216042020-04-03 18:28:56 -0400163 // agent.deviceId will also have been set during newAgent().
khenaidoo7585a962021-06-10 16:15:38 -0400164 device := (proto.Clone(deviceToCreate)).(*voltha.Device)
npujar1d86a522019-11-14 17:11:16 +0530165 device.Id = agent.deviceID
Scott Baker80678602019-11-14 16:57:36 -0800166 device.AdminState = voltha.AdminState_PREPROVISIONED
Maninder9a1bc0d2020-10-26 11:34:02 +0530167 currState = device.AdminState
Scott Baker80678602019-11-14 16:57:36 -0800168 if !deviceToCreate.GetRoot() && deviceToCreate.ProxyAddress != nil {
169 // Set the default vlan ID to the one specified by the parent adapter. It can be
170 // overwritten by the child adapter during a device update request
171 device.Vlan = deviceToCreate.ProxyAddress.ChannelId
172 }
173
khenaidood948f772021-08-11 17:49:24 -0400174 // Save the device to the model
175 if err = agent.dbProxy.Set(ctx, agent.deviceID, device); err != nil {
176 err = status.Errorf(codes.Aborted, "failed-adding-device-%s: %s", agent.deviceID, err)
177 return nil, err
khenaidoo297cd252019-02-07 22:10:23 -0500178 }
Mahir Gunyelb0343bf2021-05-11 14:14:26 -0700179 _ = agent.deviceMgr.Agent.SendDeviceStateChangeEvent(ctx, device.OperStatus, device.ConnectStatus, prevState, device, time.Now().Unix())
khenaidood948f772021-08-11 17:49:24 -0400180 requestStatus.Code = common.OperationResp_OPERATION_SUCCESS
khenaidoo442e7c72020-03-10 16:13:48 -0400181 agent.device = device
khenaidoob9203542018-09-17 22:56:37 -0400182 }
khenaidoo442e7c72020-03-10 16:13:48 -0400183 startSucceeded = true
Rohan Agrawalcf12f202020-08-03 04:42:01 +0000184 log.EnrichSpan(ctx, log.Fields{"device-id": agent.deviceID})
Rohan Agrawal31f21802020-06-12 05:38:46 +0000185 logger.Debugw(ctx, "device-agent-started", log.Fields{"device-id": agent.deviceID})
khenaidoo442e7c72020-03-10 16:13:48 -0400186
Kent Hagermancba2f302020-07-28 13:37:36 -0400187 return agent.getDeviceReadOnly(ctx)
khenaidoob9203542018-09-17 22:56:37 -0400188}
189
khenaidoo4d4802d2018-10-04 21:59:49 -0400190// stop stops the device agent. Not much to do for now
Kent Hagerman2b216042020-04-03 18:28:56 -0400191func (agent *Agent) stop(ctx context.Context) error {
khenaidoo442e7c72020-03-10 16:13:48 -0400192 needToStop := false
193 if agent.stopOnce.Do(func() { needToStop = true }); !needToStop {
194 return nil
195 }
196 if err := agent.requestQueue.WaitForGreenLight(ctx); err != nil {
197 return err
198 }
199 defer agent.requestQueue.RequestComplete()
khenaidoo49085352020-01-13 19:15:43 -0500200
Himani Chawlab4c25912020-11-12 17:16:38 +0530201 logger.Infow(ctx, "stopping-device-agent", log.Fields{"device-id": agent.deviceID, "parent-id": agent.parentID})
Himani Chawla2ba1c9c2020-10-07 13:19:03 +0530202 // Remove the device transient loader
203 if err := agent.deleteTransientState(ctx); err != nil {
204 return err
205 }
khenaidoo0a822f92019-05-08 15:15:57 -0400206 // Remove the device from the KV store
Kent Hagermanf5a67352020-04-30 15:15:26 -0400207 if err := agent.dbProxy.Remove(ctx, agent.deviceID); err != nil {
khenaidoo442e7c72020-03-10 16:13:48 -0400208 return err
Thomas Lee Se5a44012019-11-07 20:32:24 +0530209 }
khenaidoo442e7c72020-03-10 16:13:48 -0400210
khenaidoo442e7c72020-03-10 16:13:48 -0400211 close(agent.exitChannel)
212
213 agent.stopped = true
214
Rohan Agrawal31f21802020-06-12 05:38:46 +0000215 logger.Infow(ctx, "device-agent-stopped", log.Fields{"device-id": agent.deviceID, "parent-id": agent.parentID})
khenaidoo442e7c72020-03-10 16:13:48 -0400216
217 return nil
khenaidoob9203542018-09-17 22:56:37 -0400218}
219
Scott Baker80678602019-11-14 16:57:36 -0800220// Load the most recent state from the KVStore for the device.
Kent Hagerman2b216042020-04-03 18:28:56 -0400221func (agent *Agent) reconcileWithKVStore(ctx context.Context) {
khenaidoo442e7c72020-03-10 16:13:48 -0400222 if err := agent.requestQueue.WaitForGreenLight(ctx); err != nil {
Rohan Agrawal31f21802020-06-12 05:38:46 +0000223 logger.Warnw(ctx, "request-aborted", log.Fields{"device-id": agent.deviceID, "error": err})
khenaidoo442e7c72020-03-10 16:13:48 -0400224 return
225 }
226 defer agent.requestQueue.RequestComplete()
Rohan Agrawal31f21802020-06-12 05:38:46 +0000227 logger.Debug(ctx, "reconciling-device-agent-devicetype")
Scott Baker80678602019-11-14 16:57:36 -0800228 // TODO: context timeout
Kent Hagerman4f355f52020-03-30 16:01:33 -0400229 device := &voltha.Device{}
Kent Hagermanf5a67352020-04-30 15:15:26 -0400230 if have, err := agent.dbProxy.Get(ctx, agent.deviceID, device); err != nil {
Rohan Agrawal31f21802020-06-12 05:38:46 +0000231 logger.Errorw(ctx, "kv-get-failed", log.Fields{"device-id": agent.deviceID, "error": err})
Thomas Lee Se5a44012019-11-07 20:32:24 +0530232 return
Kent Hagerman4f355f52020-03-30 16:01:33 -0400233 } else if !have {
234 return // not found in kv
Thomas Lee Se5a44012019-11-07 20:32:24 +0530235 }
Kent Hagerman4f355f52020-03-30 16:01:33 -0400236
khenaidood948f772021-08-11 17:49:24 -0400237 agent.deviceType = device.Type
Kent Hagerman4f355f52020-03-30 16:01:33 -0400238 agent.device = device
khenaidood948f772021-08-11 17:49:24 -0400239 agent.adapterEndpoint = device.AdapterEndpoint
Kent Hagerman2a07b862020-06-19 15:23:07 -0400240 agent.portLoader.Load(ctx)
Himani Chawla2ba1c9c2020-10-07 13:19:03 +0530241 agent.transientStateLoader.Load(ctx)
242
Rohan Agrawal31f21802020-06-12 05:38:46 +0000243 logger.Debugw(ctx, "reconciled-device-agent-devicetype", log.Fields{"device-id": agent.deviceID, "type": agent.deviceType})
Scott Baker80678602019-11-14 16:57:36 -0800244}
245
khenaidoo442e7c72020-03-10 16:13:48 -0400246// 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 -0400247func (agent *Agent) onSuccess(ctx context.Context, prevState, currState *common.AdminState_Types, deviceUpdateLog bool) {
248 if deviceUpdateLog {
249 requestStatus := &common.OperationResp{Code: common.OperationResp_OPERATION_SUCCESS}
250 desc := "adapter-response"
251 agent.logDeviceUpdate(ctx, prevState, currState, requestStatus, nil, desc)
252 return
253 }
254 logger.Debugw(ctx, "successful-operation", log.Fields{"device-id": agent.deviceID, "rpc": coreutils.GetRPCMetadataFromContext(ctx)})
khenaidoo442e7c72020-03-10 16:13:48 -0400255}
256
257// onFailure is a common callback for scenarios where we receive an error response following a request to an adapter
258// and the only action required is to publish the failed result on kafka
khenaidood948f772021-08-11 17:49:24 -0400259func (agent *Agent) onFailure(ctx context.Context, err error, prevState, currState *common.AdminState_Types, deviceUpdateLog bool) {
260 // Send an event on kafka
261 rpce := agent.deviceMgr.NewRPCEvent(ctx, agent.deviceID, err.Error(), nil)
262 go agent.deviceMgr.SendRPCEvent(ctx, "RPC_ERROR_RAISE_EVENT", rpce,
263 voltha.EventCategory_COMMUNICATION, nil, time.Now().Unix())
khenaidoo442e7c72020-03-10 16:13:48 -0400264
khenaidood948f772021-08-11 17:49:24 -0400265 // Log the device update event
266 if deviceUpdateLog {
267 requestStatus := &common.OperationResp{Code: common.OperationResp_OPERATION_FAILURE}
268 desc := "adapter-response"
269 agent.logDeviceUpdate(ctx, prevState, currState, requestStatus, err, desc)
270 return
khenaidoo442e7c72020-03-10 16:13:48 -0400271 }
khenaidood948f772021-08-11 17:49:24 -0400272 logger.Errorw(ctx, "failed-operation", log.Fields{"error": err, "device-id": agent.deviceID, "rpc": coreutils.GetRPCMetadataFromContext(ctx)})
khenaidoo442e7c72020-03-10 16:13:48 -0400273}
274
Himani Chawla2ba1c9c2020-10-07 13:19:03 +0530275// onDeleteSuccess is a common callback for scenarios where we receive a nil response following a delete request
276// to an adapter.
khenaidood948f772021-08-11 17:49:24 -0400277func (agent *Agent) onDeleteSuccess(ctx context.Context, prevState, currState *common.AdminState_Types) {
Himani Chawla2ba1c9c2020-10-07 13:19:03 +0530278 if err := agent.requestQueue.WaitForGreenLight(ctx); err != nil {
khenaidood948f772021-08-11 17:49:24 -0400279 logger.Errorw(ctx, "delete-device-failure", log.Fields{"device-id": agent.deviceID, "error": err})
Himani Chawla2ba1c9c2020-10-07 13:19:03 +0530280 }
281 previousDeviceTransientState := agent.getTransientState()
282 newDevice := agent.cloneDeviceWithoutLock()
283 if err := agent.updateDeviceWithTransientStateAndReleaseLock(ctx, newDevice,
khenaidood948f772021-08-11 17:49:24 -0400284 core.DeviceTransientState_DELETING_POST_ADAPTER_RESPONSE, previousDeviceTransientState); err != nil {
285 logger.Errorw(ctx, "delete-device-failure", log.Fields{"device-id": agent.deviceID, "error": err})
Himani Chawla2ba1c9c2020-10-07 13:19:03 +0530286 }
khenaidood948f772021-08-11 17:49:24 -0400287 requestStatus := &common.OperationResp{Code: common.OperationResp_OPERATION_SUCCESS}
288 desc := "adapter-response"
289 agent.logDeviceUpdate(ctx, prevState, currState, requestStatus, nil, desc)
Himani Chawla2ba1c9c2020-10-07 13:19:03 +0530290}
291
292// onDeleteFailure is a common callback for scenarios where we receive an error response following a delete request
293// to an adapter and the only action required is to return the error response.
khenaidood948f772021-08-11 17:49:24 -0400294func (agent *Agent) onDeleteFailure(ctx context.Context, err error, prevState, currState *common.AdminState_Types) {
295 logger.Errorw(ctx, "rpc-failed", log.Fields{"rpc": coreutils.GetRPCMetadataFromContext(ctx), "device-id": agent.deviceID, "error": err})
296
Himani Chawla2ba1c9c2020-10-07 13:19:03 +0530297 //Only updating of transient state is required, no transition.
khenaidood948f772021-08-11 17:49:24 -0400298 if er := agent.updateTransientState(ctx, core.DeviceTransientState_DELETE_FAILED); er != nil {
299 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 +0530300 }
khenaidood948f772021-08-11 17:49:24 -0400301 rpce := agent.deviceMgr.NewRPCEvent(ctx, agent.deviceID, err.Error(), nil)
302 go agent.deviceMgr.SendRPCEvent(ctx, "RPC_ERROR_RAISE_EVENT", rpce,
303 voltha.EventCategory_COMMUNICATION, nil, time.Now().Unix())
Himani Chawla2ba1c9c2020-10-07 13:19:03 +0530304
khenaidood948f772021-08-11 17:49:24 -0400305 // Log the device update event
306 requestStatus := &common.OperationResp{Code: common.OperationResp_OPERATION_FAILURE}
307 desc := "adapter-response"
308 agent.logDeviceUpdate(ctx, prevState, currState, requestStatus, err, desc)
Maninder9a1bc0d2020-10-26 11:34:02 +0530309}
310
Kent Hagermancba2f302020-07-28 13:37:36 -0400311// getDeviceReadOnly returns a device which MUST NOT be modified, but is safe to keep forever.
312func (agent *Agent) getDeviceReadOnly(ctx context.Context) (*voltha.Device, error) {
khenaidoo442e7c72020-03-10 16:13:48 -0400313 if err := agent.requestQueue.WaitForGreenLight(ctx); err != nil {
314 return nil, err
315 }
316 defer agent.requestQueue.RequestComplete()
Kent Hagermancba2f302020-07-28 13:37:36 -0400317 return agent.device, nil
khenaidoo92e62c52018-10-03 14:02:54 -0400318}
319
Kent Hagermancba2f302020-07-28 13:37:36 -0400320// 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 -0400321// The device lock MUST be held by the caller.
Kent Hagermancba2f302020-07-28 13:37:36 -0400322func (agent *Agent) getDeviceReadOnlyWithoutLock() *voltha.Device {
khenaidoo0db4c812020-05-27 15:27:30 -0400323 return agent.device
khenaidoo92e62c52018-10-03 14:02:54 -0400324}
325
Kent Hagermanf6db9f12020-07-22 17:16:19 -0400326// cloneDeviceWithoutLock returns a copy of the device which is safe to modify.
327// The device lock MUST be held by the caller.
328func (agent *Agent) cloneDeviceWithoutLock() *voltha.Device {
329 return proto.Clone(agent.device).(*voltha.Device)
330}
331
khenaidood948f772021-08-11 17:49:24 -0400332func (agent *Agent) updateDeviceTypeAndEndpoint(ctx context.Context) error {
333 if err := agent.requestQueue.WaitForGreenLight(ctx); err != nil {
334 return err
335 }
336 changed := false
337 cloned := agent.cloneDeviceWithoutLock()
338 if cloned.Type == "" {
339 adapterType, err := agent.adapterMgr.GetAdapterType(cloned.Type)
340 if err != nil {
341 agent.requestQueue.RequestComplete()
342 return err
343 }
344 cloned.Type = adapterType
345 changed = true
346 }
347
348 if cloned.AdapterEndpoint == "" {
349 var err error
350 if cloned.AdapterEndpoint, err = agent.adapterMgr.GetAdapterEndpoint(ctx, cloned.Id, cloned.Type); err != nil {
351 agent.requestQueue.RequestComplete()
352 return err
353 }
354 agent.adapterEndpoint = cloned.AdapterEndpoint
355 changed = true
356 }
357
358 if changed {
359 return agent.updateDeviceAndReleaseLock(ctx, cloned)
360 }
361 agent.requestQueue.RequestComplete()
362 return nil
363}
364
khenaidoo3ab34882019-05-02 21:33:30 -0400365// enableDevice activates a preprovisioned or a disable device
Kent Hagerman2b216042020-04-03 18:28:56 -0400366func (agent *Agent) enableDevice(ctx context.Context) error {
Maninder9a1bc0d2020-10-26 11:34:02 +0530367 //To preserve and use oldDevice state as prev state in new device
khenaidood948f772021-08-11 17:49:24 -0400368 var err error
Maninder9a1bc0d2020-10-26 11:34:02 +0530369 var desc string
khenaidood948f772021-08-11 17:49:24 -0400370 var prevAdminState, currAdminState common.AdminState_Types
371 requestStatus := &common.OperationResp{Code: common.OperationResp_OPERATION_FAILURE}
Maninder9a1bc0d2020-10-26 11:34:02 +0530372
khenaidood948f772021-08-11 17:49:24 -0400373 defer func() { agent.logDeviceUpdate(ctx, &prevAdminState, &currAdminState, requestStatus, err, desc) }()
Maninder9a1bc0d2020-10-26 11:34:02 +0530374
khenaidood948f772021-08-11 17:49:24 -0400375 if err = agent.requestQueue.WaitForGreenLight(ctx); err != nil {
khenaidoo442e7c72020-03-10 16:13:48 -0400376 return err
377 }
Himani Chawlab4c25912020-11-12 17:16:38 +0530378 logger.Debugw(ctx, "enable-device", log.Fields{"device-id": agent.deviceID})
khenaidoo21d51152019-02-01 13:48:37 -0500379
Kent Hagermancba2f302020-07-28 13:37:36 -0400380 oldDevice := agent.getDeviceReadOnlyWithoutLock()
khenaidood948f772021-08-11 17:49:24 -0400381 prevAdminState = oldDevice.AdminState
Maninder9a1bc0d2020-10-26 11:34:02 +0530382
Maninder2195ccc2021-06-23 20:23:01 +0530383 if !agent.proceedWithRequest(oldDevice) {
384 agent.requestQueue.RequestComplete()
khenaidood948f772021-08-11 17:49:24 -0400385 err = status.Errorf(codes.FailedPrecondition, "cannot complete operation as device deletion is in progress or reconciling is in progress/failed: %s", agent.deviceID)
386 return err
Maninder2195ccc2021-06-23 20:23:01 +0530387 }
Mahir Gunyel92dd1212021-10-22 11:42:56 -0700388 //vol-4275 TST meeting 08/04/2021: Let EnableDevice to be called again if device is in FAILED operational state,
389 //even the admin state is ENABLED.
390 if oldDevice.AdminState == voltha.AdminState_ENABLED && oldDevice.OperStatus != voltha.OperStatus_FAILED {
Kent Hagermanf6db9f12020-07-22 17:16:19 -0400391 logger.Warnw(ctx, "device-already-enabled", log.Fields{"device-id": agent.deviceID})
392 agent.requestQueue.RequestComplete()
khenaidood948f772021-08-11 17:49:24 -0400393 err = status.Errorf(codes.FailedPrecondition, fmt.Sprintf("cannot-enable-an-already-enabled-device: %s", oldDevice.Id))
Matteo Scandolod525ae32020-04-02 17:27:29 -0700394 return err
npujar1d86a522019-11-14 17:11:16 +0530395 }
396
khenaidood948f772021-08-11 17:49:24 -0400397 // Verify whether there is a device type that supports this device type
398 _, err = agent.adapterMgr.GetAdapterType(oldDevice.Type)
399 if err != nil {
400 agent.requestQueue.RequestComplete()
401 return err
402 }
403
404 // 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
405 // 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 -0400406 newDevice := agent.cloneDeviceWithoutLock()
khenaidood948f772021-08-11 17:49:24 -0400407 if newDevice.AdapterEndpoint == "" {
408 if newDevice.AdapterEndpoint, err = agent.adapterMgr.GetAdapterEndpoint(ctx, newDevice.Id, newDevice.Type); err != nil {
409 agent.requestQueue.RequestComplete()
410 return err
411 }
412 agent.adapterEndpoint = newDevice.AdapterEndpoint
413 }
npujar1d86a522019-11-14 17:11:16 +0530414
Kent Hagermanf6db9f12020-07-22 17:16:19 -0400415 // Update the Admin State and set the operational state to activating before sending the request to the Adapters
416 newDevice.AdminState = voltha.AdminState_ENABLED
417 newDevice.OperStatus = voltha.OperStatus_ACTIVATING
Maninder9a1bc0d2020-10-26 11:34:02 +0530418
khenaidoo442e7c72020-03-10 16:13:48 -0400419 // 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 -0400420 client, err := agent.adapterMgr.GetAdapterClient(ctx, agent.adapterEndpoint)
khenaidoo442e7c72020-03-10 16:13:48 -0400421 if err != nil {
khenaidood948f772021-08-11 17:49:24 -0400422 logger.Errorw(ctx, "grpc-client-nil",
423 log.Fields{
424 "error": err,
425 "device-id": agent.deviceID,
426 "device-type": agent.deviceType,
427 "adapter-endpoint": newDevice.AdapterEndpoint,
428 })
429 agent.requestQueue.RequestComplete()
khenaidoo442e7c72020-03-10 16:13:48 -0400430 return err
431 }
khenaidood948f772021-08-11 17:49:24 -0400432 subCtx, cancel := context.WithTimeout(coreutils.WithAllMetadataFromContext(ctx), agent.rpcTimeout)
433 requestStatus.Code = common.OperationResp_OPERATION_IN_PROGRESS
434 go func() {
435 defer cancel()
436 var err error
437 if oldDevice.AdminState == voltha.AdminState_PREPROVISIONED {
438 _, err = client.AdoptDevice(subCtx, newDevice)
439 } else {
440 _, err = client.ReEnableDevice(subCtx, newDevice)
441 }
442 if err == nil {
443 agent.onSuccess(subCtx, nil, nil, true)
444 } else {
445 agent.onFailure(subCtx, err, nil, nil, true)
Himani Chawlab4c25912020-11-12 17:16:38 +0530446 }
447 }()
khenaidood948f772021-08-11 17:49:24 -0400448
449 // Update device
450 if err = agent.updateDeviceAndReleaseLock(ctx, newDevice); err != nil {
451 return err
khenaidoo2c6a0992019-04-29 13:46:56 -0400452 }
khenaidood948f772021-08-11 17:49:24 -0400453 currAdminState = newDevice.AdminState
454 return nil
khenaidoo2c6a0992019-04-29 13:46:56 -0400455}
456
A R Karthick5c28f552019-12-11 22:47:44 -0800457//addFlowsAndGroups adds the "newFlows" and "newGroups" from the existing flows/groups and sends the update to the
458//adapters
khenaidoo9beaaf12021-10-19 17:32:01 -0400459func (agent *Agent) addFlowsAndGroups(ctx context.Context, newFlows []*ofp.OfpFlowStats, newGroups []*ofp.OfpGroupEntry, flowMetadata *ofp.FlowMetadata) error {
Mahir Gunyel03de0d32020-06-03 01:36:59 -0700460 var flwResponse, grpResponse coreutils.Response
461 var err error
462 //if new flow list is empty then the called function returns quickly
463 if flwResponse, err = agent.addFlowsToAdapter(ctx, newFlows, flowMetadata); err != nil {
A R Karthick5c28f552019-12-11 22:47:44 -0800464 return err
465 }
Mahir Gunyel03de0d32020-06-03 01:36:59 -0700466 //if new group list is empty then the called function returns quickly
467 if grpResponse, err = agent.addGroupsToAdapter(ctx, newGroups, flowMetadata); err != nil {
468 return err
469 }
Himani Chawla4b4bd252021-11-08 15:59:40 +0530470 if errs := coreutils.WaitForNilOrErrorResponses(agent.flowTimeout, flwResponse, grpResponse); errs != nil {
khenaidood948f772021-08-11 17:49:24 -0400471 logger.Warnw(ctx, "adapter-response", log.Fields{"device-id": agent.deviceID, "result": errs})
khenaidoo442e7c72020-03-10 16:13:48 -0400472 return status.Errorf(codes.Aborted, "flow-failure-device-%s", agent.deviceID)
khenaidoo0458db62019-06-20 08:50:36 -0400473 }
khenaidoo0458db62019-06-20 08:50:36 -0400474 return nil
475}
476
A R Karthick5c28f552019-12-11 22:47:44 -0800477//deleteFlowsAndGroups removes the "flowsToDel" and "groupsToDel" from the existing flows/groups and sends the update to the
478//adapters
khenaidoo9beaaf12021-10-19 17:32:01 -0400479func (agent *Agent) deleteFlowsAndGroups(ctx context.Context, flowsToDel []*ofp.OfpFlowStats, groupsToDel []*ofp.OfpGroupEntry, flowMetadata *ofp.FlowMetadata) error {
Mahir Gunyel03de0d32020-06-03 01:36:59 -0700480 var flwResponse, grpResponse coreutils.Response
481 var err error
482 if flwResponse, err = agent.deleteFlowsFromAdapter(ctx, flowsToDel, flowMetadata); err != nil {
A R Karthick5c28f552019-12-11 22:47:44 -0800483 return err
484 }
Mahir Gunyel03de0d32020-06-03 01:36:59 -0700485 if grpResponse, err = agent.deleteGroupsFromAdapter(ctx, groupsToDel, flowMetadata); err != nil {
486 return err
487 }
488
Himani Chawla4b4bd252021-11-08 15:59:40 +0530489 if res := coreutils.WaitForNilOrErrorResponses(agent.flowTimeout, flwResponse, grpResponse); res != nil {
khenaidoo0458db62019-06-20 08:50:36 -0400490 return status.Errorf(codes.Aborted, "errors-%s", res)
491 }
492 return nil
khenaidoo0458db62019-06-20 08:50:36 -0400493}
494
A R Karthick5c28f552019-12-11 22:47:44 -0800495//updateFlowsAndGroups replaces the existing flows and groups with "updatedFlows" and "updatedGroups" respectively. It
496//also sends the updates to the adapters
khenaidoo9beaaf12021-10-19 17:32:01 -0400497func (agent *Agent) updateFlowsAndGroups(ctx context.Context, updatedFlows []*ofp.OfpFlowStats, updatedGroups []*ofp.OfpGroupEntry, flowMetadata *ofp.FlowMetadata) error {
Mahir Gunyel03de0d32020-06-03 01:36:59 -0700498 var flwResponse, grpResponse coreutils.Response
499 var err error
500 if flwResponse, err = agent.updateFlowsToAdapter(ctx, updatedFlows, flowMetadata); err != nil {
A R Karthick5c28f552019-12-11 22:47:44 -0800501 return err
502 }
Mahir Gunyel03de0d32020-06-03 01:36:59 -0700503 if grpResponse, err = agent.updateGroupsToAdapter(ctx, updatedGroups, flowMetadata); err != nil {
504 return err
505 }
506
Himani Chawla4b4bd252021-11-08 15:59:40 +0530507 if res := coreutils.WaitForNilOrErrorResponses(agent.flowTimeout, flwResponse, grpResponse); res != nil {
khenaidoo0458db62019-06-20 08:50:36 -0400508 return status.Errorf(codes.Aborted, "errors-%s", res)
509 }
510 return nil
khenaidoo19d7b632018-10-30 10:49:50 -0400511}
512
khenaidoo4d4802d2018-10-04 21:59:49 -0400513//disableDevice disable a device
Kent Hagerman2b216042020-04-03 18:28:56 -0400514func (agent *Agent) disableDevice(ctx context.Context) error {
khenaidood948f772021-08-11 17:49:24 -0400515 var err error
Maninder9a1bc0d2020-10-26 11:34:02 +0530516 var desc string
khenaidood948f772021-08-11 17:49:24 -0400517 var prevAdminState, currAdminState common.AdminState_Types
518 requestStatus := &common.OperationResp{Code: common.OperationResp_OPERATION_FAILURE}
519 defer func() { agent.logDeviceUpdate(ctx, &prevAdminState, &currAdminState, requestStatus, err, desc) }()
Maninder9a1bc0d2020-10-26 11:34:02 +0530520
khenaidood948f772021-08-11 17:49:24 -0400521 if err = agent.requestQueue.WaitForGreenLight(ctx); err != nil {
khenaidoo442e7c72020-03-10 16:13:48 -0400522 return err
523 }
Himani Chawlab4c25912020-11-12 17:16:38 +0530524 logger.Debugw(ctx, "disable-device", log.Fields{"device-id": agent.deviceID})
khenaidoo6e55d9e2019-12-12 18:26:26 -0500525
Kent Hagermanf6db9f12020-07-22 17:16:19 -0400526 cloned := agent.cloneDeviceWithoutLock()
khenaidood948f772021-08-11 17:49:24 -0400527 prevAdminState = agent.device.AdminState
khenaidoo6e55d9e2019-12-12 18:26:26 -0500528
Maninder2195ccc2021-06-23 20:23:01 +0530529 if !agent.proceedWithRequest(cloned) {
khenaidood948f772021-08-11 17:49:24 -0400530 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 +0530531 agent.requestQueue.RequestComplete()
khenaidood948f772021-08-11 17:49:24 -0400532 return err
Maninder2195ccc2021-06-23 20:23:01 +0530533 }
534
khenaidoo6e55d9e2019-12-12 18:26:26 -0500535 if cloned.AdminState == voltha.AdminState_DISABLED {
Maninder9a1bc0d2020-10-26 11:34:02 +0530536 desc = "device-already-disabled"
Kent Hagermanf6db9f12020-07-22 17:16:19 -0400537 agent.requestQueue.RequestComplete()
npujar1d86a522019-11-14 17:11:16 +0530538 return nil
539 }
Himani Chawla2ba1c9c2020-10-07 13:19:03 +0530540 if cloned.AdminState == voltha.AdminState_PREPROVISIONED {
Kent Hagermanf6db9f12020-07-22 17:16:19 -0400541 agent.requestQueue.RequestComplete()
khenaidood948f772021-08-11 17:49:24 -0400542 err = status.Errorf(codes.FailedPrecondition, "deviceId:%s, invalid-admin-state:%s", agent.deviceID, cloned.AdminState)
543 return err
npujar1d86a522019-11-14 17:11:16 +0530544 }
Maninder0aabf0c2021-03-17 14:55:14 +0530545
npujar1d86a522019-11-14 17:11:16 +0530546 // Update the Admin State and operational state before sending the request out
Kent Hagermanf6db9f12020-07-22 17:16:19 -0400547 cloned.AdminState = voltha.AdminState_DISABLED
548 cloned.OperStatus = voltha.OperStatus_UNKNOWN
Maninder9a1bc0d2020-10-26 11:34:02 +0530549
khenaidood948f772021-08-11 17:49:24 -0400550 client, err := agent.adapterMgr.GetAdapterClient(ctx, agent.adapterEndpoint)
khenaidoo442e7c72020-03-10 16:13:48 -0400551 if err != nil {
khenaidood948f772021-08-11 17:49:24 -0400552 logger.Errorw(ctx, "grpc-client-nil",
553 log.Fields{
554 "error": err,
555 "device-id": agent.deviceID,
556 "device-type": agent.deviceType,
557 "adapter-endpoint": cloned.AdapterEndpoint,
558 })
559 agent.requestQueue.RequestComplete()
npujar1d86a522019-11-14 17:11:16 +0530560 return err
khenaidoo0a822f92019-05-08 15:15:57 -0400561 }
khenaidood948f772021-08-11 17:49:24 -0400562 subCtx, cancel := context.WithTimeout(coreutils.WithAllMetadataFromContext(ctx), agent.rpcTimeout)
563 requestStatus.Code = common.OperationResp_OPERATION_IN_PROGRESS
564 go func() {
565 defer cancel()
566 _, err := client.DisableDevice(subCtx, cloned)
567 if err == nil {
568 agent.onSuccess(subCtx, nil, nil, true)
569 } else {
570 agent.onFailure(subCtx, err, nil, nil, true)
571 }
572 }()
Maninder9a1bc0d2020-10-26 11:34:02 +0530573
khenaidood948f772021-08-11 17:49:24 -0400574 // Update device
575 if err = agent.updateDeviceAndReleaseLock(ctx, cloned); err != nil {
576 return err
577 }
578 currAdminState = cloned.AdminState
khenaidoo0a822f92019-05-08 15:15:57 -0400579
khenaidoo92e62c52018-10-03 14:02:54 -0400580 return nil
581}
582
Kent Hagerman2b216042020-04-03 18:28:56 -0400583func (agent *Agent) rebootDevice(ctx context.Context) error {
Maninder9a1bc0d2020-10-26 11:34:02 +0530584 var desc string
khenaidood948f772021-08-11 17:49:24 -0400585 var err error
586 requestStatus := &common.OperationResp{Code: common.OperationResp_OPERATION_FAILURE}
587 defer func() { agent.logDeviceUpdate(ctx, nil, nil, requestStatus, err, desc) }()
Maninder9a1bc0d2020-10-26 11:34:02 +0530588
khenaidood948f772021-08-11 17:49:24 -0400589 if err = agent.requestQueue.WaitForGreenLight(ctx); err != nil {
Maninder9a1bc0d2020-10-26 11:34:02 +0530590 desc = err.Error()
npujar1d86a522019-11-14 17:11:16 +0530591 return err
khenaidoo4d4802d2018-10-04 21:59:49 -0400592 }
khenaidoo442e7c72020-03-10 16:13:48 -0400593 defer agent.requestQueue.RequestComplete()
Himani Chawlab4c25912020-11-12 17:16:38 +0530594 logger.Debugw(ctx, "reboot-device", log.Fields{"device-id": agent.deviceID})
khenaidoo442e7c72020-03-10 16:13:48 -0400595
Kent Hagermancba2f302020-07-28 13:37:36 -0400596 device := agent.getDeviceReadOnlyWithoutLock()
Maninder2195ccc2021-06-23 20:23:01 +0530597
598 if !agent.proceedWithRequest(device) {
khenaidood948f772021-08-11 17:49:24 -0400599 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 -0400600 return err
601 }
Maninder9a1bc0d2020-10-26 11:34:02 +0530602
khenaidood948f772021-08-11 17:49:24 -0400603 client, err := agent.adapterMgr.GetAdapterClient(ctx, agent.adapterEndpoint)
604 if err != nil {
605 logger.Errorw(ctx, "grpc-client-nil",
606 log.Fields{
607 "error": err,
608 "device-id": agent.deviceID,
609 "device-type": agent.deviceType,
610 "adapter-endpoint": device.AdapterEndpoint,
611 })
612 return err
613 }
614 subCtx, cancel := context.WithTimeout(coreutils.WithAllMetadataFromContext(ctx), agent.rpcTimeout)
615 requestStatus.Code = common.OperationResp_OPERATION_IN_PROGRESS
616 go func() {
617 defer cancel()
618 _, err := client.RebootDevice(subCtx, device)
619 if err == nil {
620 agent.onSuccess(subCtx, nil, nil, true)
621 } else {
622 agent.onFailure(subCtx, err, nil, nil, true)
623 }
624 }()
khenaidoo4d4802d2018-10-04 21:59:49 -0400625 return nil
626}
627
Himani Chawla2ba1c9c2020-10-07 13:19:03 +0530628func (agent *Agent) deleteDeviceForce(ctx context.Context) error {
Himani Chawlab4c25912020-11-12 17:16:38 +0530629 logger.Debugw(ctx, "delete-device-force", log.Fields{"device-id": agent.deviceID})
Maninder9a1bc0d2020-10-26 11:34:02 +0530630
631 var desc string
khenaidood948f772021-08-11 17:49:24 -0400632 var err error
633 requestStatus := &common.OperationResp{Code: common.OperationResp_OPERATION_FAILURE}
634 defer func() { agent.logDeviceUpdate(ctx, nil, nil, requestStatus, err, desc) }()
Maninder9a1bc0d2020-10-26 11:34:02 +0530635
khenaidood948f772021-08-11 17:49:24 -0400636 if err = agent.requestQueue.WaitForGreenLight(ctx); err != nil {
Himani Chawla2ba1c9c2020-10-07 13:19:03 +0530637 return err
638 }
639 // Get the device Transient state, return err if it is DELETING
640 previousDeviceTransientState := agent.getTransientState()
Himani Chawla2ba1c9c2020-10-07 13:19:03 +0530641 device := agent.cloneDeviceWithoutLock()
khenaidood948f772021-08-11 17:49:24 -0400642 if !agent.isForceDeletingAllowed(previousDeviceTransientState, device) {
643 agent.requestQueue.RequestComplete()
644 err = status.Error(codes.FailedPrecondition, fmt.Sprintf("deviceId:%s, force deletion is in progress", agent.deviceID))
Himani Chawla2ba1c9c2020-10-07 13:19:03 +0530645 return err
646 }
Himani Chawlab4c25912020-11-12 17:16:38 +0530647
khenaidood948f772021-08-11 17:49:24 -0400648 previousAdminState := device.AdminState
649 if previousAdminState != common.AdminState_PREPROVISIONED {
khenaidoo9beaaf12021-10-19 17:32:01 -0400650 var client adapter_service.AdapterServiceClient
khenaidood948f772021-08-11 17:49:24 -0400651 client, err = agent.adapterMgr.GetAdapterClient(ctx, agent.adapterEndpoint)
Himani Chawla2ba1c9c2020-10-07 13:19:03 +0530652 if err != nil {
khenaidood948f772021-08-11 17:49:24 -0400653 logger.Errorw(ctx, "grpc-client-nil",
654 log.Fields{
655 "error": err,
656 "device-id": agent.deviceID,
657 "device-type": agent.deviceType,
658 "adapter-endpoint": device.AdapterEndpoint,
659 })
660 agent.requestQueue.RequestComplete()
Himani Chawla2ba1c9c2020-10-07 13:19:03 +0530661 return err
662 }
khenaidood948f772021-08-11 17:49:24 -0400663 subCtx, cancel := context.WithTimeout(coreutils.WithAllMetadataFromContext(ctx), agent.rpcTimeout)
664 requestStatus.Code = common.OperationResp_OPERATION_IN_PROGRESS
665 go func() {
666 defer cancel()
667 _, err := client.DeleteDevice(subCtx, device)
668 if err == nil {
669 agent.onSuccess(subCtx, nil, nil, true)
670 } else {
671 agent.onFailure(subCtx, err, nil, nil, true)
672 }
673 }()
674 }
675
676 // Update device
677 if err = agent.updateDeviceWithTransientStateAndReleaseLock(ctx, device,
678 core.DeviceTransientState_FORCE_DELETING, previousDeviceTransientState); err != nil {
679 return err
Himani Chawla2ba1c9c2020-10-07 13:19:03 +0530680 }
681 return nil
682}
683
Kent Hagerman2b216042020-04-03 18:28:56 -0400684func (agent *Agent) deleteDevice(ctx context.Context) error {
Himani Chawlab4c25912020-11-12 17:16:38 +0530685 logger.Debugw(ctx, "delete-device", log.Fields{"device-id": agent.deviceID})
Maninder9a1bc0d2020-10-26 11:34:02 +0530686
687 var desc string
khenaidood948f772021-08-11 17:49:24 -0400688 var err error
689 requestStatus := &common.OperationResp{Code: common.OperationResp_OPERATION_FAILURE}
690 defer func() { agent.logDeviceUpdate(ctx, nil, nil, requestStatus, err, desc) }()
Maninder9a1bc0d2020-10-26 11:34:02 +0530691
khenaidood948f772021-08-11 17:49:24 -0400692 if err = agent.requestQueue.WaitForGreenLight(ctx); err != nil {
Maninder9a1bc0d2020-10-26 11:34:02 +0530693 desc = err.Error()
khenaidoo442e7c72020-03-10 16:13:48 -0400694 return err
695 }
Maninder0aabf0c2021-03-17 14:55:14 +0530696
Maninder2195ccc2021-06-23 20:23:01 +0530697 device := agent.cloneDeviceWithoutLock()
698
699 if !agent.proceedWithRequest(device) {
Maninder0aabf0c2021-03-17 14:55:14 +0530700 agent.requestQueue.RequestComplete()
khenaidood948f772021-08-11 17:49:24 -0400701 err = status.Errorf(codes.FailedPrecondition, "cannot complete operation as device deletion is in progress or reconciling is in progress/failed: %s", agent.deviceID)
702 return err
Maninder0aabf0c2021-03-17 14:55:14 +0530703 }
704
Himani Chawla2ba1c9c2020-10-07 13:19:03 +0530705 // Get the device Transient state, return err if it is DELETING
706 previousDeviceTransientState := agent.getTransientState()
khenaidoo6e55d9e2019-12-12 18:26:26 -0500707
Himani Chawla2ba1c9c2020-10-07 13:19:03 +0530708 previousAdminState := device.AdminState
709 // Change the device transient state to DELETING_FROM_ADAPTER state till the device is removed from adapters.
khenaidood948f772021-08-11 17:49:24 -0400710 currentDeviceTransientState := core.DeviceTransientState_DELETING_FROM_ADAPTER
khenaidoo442e7c72020-03-10 16:13:48 -0400711
khenaidood948f772021-08-11 17:49:24 -0400712 if previousAdminState == common.AdminState_PREPROVISIONED {
Himani Chawla2ba1c9c2020-10-07 13:19:03 +0530713 // Change the state to DELETING POST ADAPTER RESPONSE directly as adapters have no info of the device.
khenaidood948f772021-08-11 17:49:24 -0400714 currentDeviceTransientState = core.DeviceTransientState_DELETING_POST_ADAPTER_RESPONSE
Himani Chawla2ba1c9c2020-10-07 13:19:03 +0530715 }
khenaidood948f772021-08-11 17:49:24 -0400716 // If the device was in pre-prov state (only parent device are in that state) then do not send the request to the
717 // adapter
718 if previousAdminState != common.AdminState_PREPROVISIONED {
khenaidoo9beaaf12021-10-19 17:32:01 -0400719 var client adapter_service.AdapterServiceClient
khenaidood948f772021-08-11 17:49:24 -0400720 client, err = agent.adapterMgr.GetAdapterClient(ctx, agent.adapterEndpoint)
721 if err != nil {
722 logger.Errorw(ctx, "grpc-client-nil",
723 log.Fields{
724 "error": err,
725 "device-id": agent.deviceID,
726 "device-type": agent.deviceType,
727 "adapter-endpoint": device.AdapterEndpoint,
728 })
729 agent.requestQueue.RequestComplete()
730 return err
731 }
732 subCtx, cancel := context.WithTimeout(coreutils.WithAllMetadataFromContext(ctx), agent.rpcTimeout)
733 requestStatus.Code = common.OperationResp_OPERATION_IN_PROGRESS
734 go func() {
735 defer cancel()
736 _, err := client.DeleteDevice(subCtx, device)
737 if err == nil {
738 agent.onDeleteSuccess(subCtx, nil, nil)
739 } else {
740 agent.onDeleteFailure(subCtx, err, nil, nil)
741 }
742 }()
743 }
744
745 // Update device and release lock
746 if err = agent.updateDeviceWithTransientStateAndReleaseLock(ctx, device,
Himani Chawlab4c25912020-11-12 17:16:38 +0530747 currentDeviceTransientState, previousDeviceTransientState); err != nil {
Maninder9a1bc0d2020-10-26 11:34:02 +0530748 desc = err.Error()
npujar1d86a522019-11-14 17:11:16 +0530749 return err
750 }
Himani Chawlab4c25912020-11-12 17:16:38 +0530751
khenaidoo4d4802d2018-10-04 21:59:49 -0400752 return nil
753}
754
Kent Hagerman2b216042020-04-03 18:28:56 -0400755func (agent *Agent) setParentID(ctx context.Context, device *voltha.Device, parentID string) error {
khenaidoo442e7c72020-03-10 16:13:48 -0400756 if err := agent.requestQueue.WaitForGreenLight(ctx); err != nil {
757 return err
758 }
Himani Chawlab4c25912020-11-12 17:16:38 +0530759 logger.Debugw(ctx, "set-parent-id", log.Fields{"device-id": device.Id, "parent-id": parentID})
khenaidoo6e55d9e2019-12-12 18:26:26 -0500760
Kent Hagermanf6db9f12020-07-22 17:16:19 -0400761 cloned := agent.cloneDeviceWithoutLock()
npujar1d86a522019-11-14 17:11:16 +0530762 cloned.ParentId = parentID
Kent Hagermanf6db9f12020-07-22 17:16:19 -0400763 return agent.updateDeviceAndReleaseLock(ctx, cloned)
khenaidooad06fd72019-10-28 12:26:05 -0400764}
765
khenaidoo442e7c72020-03-10 16:13:48 -0400766// getSwitchCapability retrieves the switch capability of a parent device
khenaidoo9beaaf12021-10-19 17:32:01 -0400767func (agent *Agent) getSwitchCapability(ctx context.Context) (*ca.SwitchCapability, error) {
Himani Chawlab4c25912020-11-12 17:16:38 +0530768 logger.Debugw(ctx, "get-switch-capability", log.Fields{"device-id": agent.deviceID})
khenaidoo442e7c72020-03-10 16:13:48 -0400769
Kent Hagermancba2f302020-07-28 13:37:36 -0400770 device, err := agent.getDeviceReadOnly(ctx)
khenaidoo442e7c72020-03-10 16:13:48 -0400771 if err != nil {
khenaidoob9203542018-09-17 22:56:37 -0400772 return nil, err
khenaidoob9203542018-09-17 22:56:37 -0400773 }
khenaidood948f772021-08-11 17:49:24 -0400774
775 // Get the gRPC client
776 client, err := agent.adapterMgr.GetAdapterClient(ctx, agent.adapterEndpoint)
khenaidoo442e7c72020-03-10 16:13:48 -0400777 if err != nil {
778 return nil, err
779 }
780
khenaidood948f772021-08-11 17:49:24 -0400781 return client.GetOfpDeviceInfo(ctx, device)
khenaidoob9203542018-09-17 22:56:37 -0400782}
783
khenaidood948f772021-08-11 17:49:24 -0400784func (agent *Agent) onPacketFailure(ctx context.Context, err error, packet *ofp.OfpPacketOut) {
785 logger.Errorw(ctx, "packet-out-error", log.Fields{
khenaidoo442e7c72020-03-10 16:13:48 -0400786 "device-id": agent.deviceID,
khenaidood948f772021-08-11 17:49:24 -0400787 "error": err.Error(),
788 "packet": hex.EncodeToString(packet.Data),
khenaidoo442e7c72020-03-10 16:13:48 -0400789 })
khenaidood948f772021-08-11 17:49:24 -0400790 rpce := agent.deviceMgr.NewRPCEvent(ctx, agent.deviceID, err.Error(), nil)
791 go agent.deviceMgr.SendRPCEvent(ctx, "RPC_ERROR_RAISE_EVENT", rpce,
792 voltha.EventCategory_COMMUNICATION, nil, time.Now().Unix())
khenaidoo442e7c72020-03-10 16:13:48 -0400793}
794
Kent Hagerman2b216042020-04-03 18:28:56 -0400795func (agent *Agent) packetOut(ctx context.Context, outPort uint32, packet *ofp.OfpPacketOut) error {
Scott Baker80678602019-11-14 16:57:36 -0800796 if agent.deviceType == "" {
npujar467fe752020-01-16 20:17:45 +0530797 agent.reconcileWithKVStore(ctx)
Scott Baker80678602019-11-14 16:57:36 -0800798 }
khenaidoofdbad6e2018-11-06 22:26:38 -0500799 // Send packet to adapter
khenaidood948f772021-08-11 17:49:24 -0400800 client, err := agent.adapterMgr.GetAdapterClient(ctx, agent.adapterEndpoint)
khenaidoo442e7c72020-03-10 16:13:48 -0400801 if err != nil {
khenaidood948f772021-08-11 17:49:24 -0400802 logger.Errorw(ctx, "grpc-client-nil",
803 log.Fields{
804 "error": err,
805 "device-id": agent.deviceID,
806 "device-type": agent.deviceType,
807 })
808 return err
khenaidoofdbad6e2018-11-06 22:26:38 -0500809 }
khenaidood948f772021-08-11 17:49:24 -0400810 subCtx, cancel := context.WithTimeout(coreutils.WithAllMetadataFromContext(ctx), agent.rpcTimeout)
811 go func() {
812 defer cancel()
khenaidoo9beaaf12021-10-19 17:32:01 -0400813 _, err := client.SendPacketOut(subCtx, &ca.PacketOut{
khenaidood948f772021-08-11 17:49:24 -0400814 DeviceId: agent.deviceID,
815 EgressPortNo: outPort,
816 Packet: packet,
817 })
818 if err == nil {
819 agent.onSuccess(subCtx, nil, nil, false)
820 } else {
821 agent.onPacketFailure(subCtx, err, packet)
822 }
823 }()
khenaidoofdbad6e2018-11-06 22:26:38 -0500824 return nil
825}
826
Kent Hagermanf6db9f12020-07-22 17:16:19 -0400827func (agent *Agent) updateDeviceUsingAdapterData(ctx context.Context, device *voltha.Device) error {
khenaidood948f772021-08-11 17:49:24 -0400828 var err error
829 var desc string
830 requestStatus := &common.OperationResp{Code: common.OperationResp_OPERATION_FAILURE}
831 defer func() { agent.logDeviceUpdate(ctx, nil, nil, requestStatus, err, desc) }()
832
833 if err = agent.requestQueue.WaitForGreenLight(ctx); err != nil {
Kent Hagermanf6db9f12020-07-22 17:16:19 -0400834 return err
835 }
Himani Chawlab4c25912020-11-12 17:16:38 +0530836 logger.Debugw(ctx, "update-device-using-adapter-data", log.Fields{"device-id": device.Id})
Kent Hagermanf6db9f12020-07-22 17:16:19 -0400837
838 cloned := agent.cloneDeviceWithoutLock()
Mahir Gunyel8e2707d2019-07-25 00:36:21 -0700839 cloned.Root = device.Root
840 cloned.Vendor = device.Vendor
841 cloned.Model = device.Model
842 cloned.SerialNumber = device.SerialNumber
843 cloned.MacAddress = device.MacAddress
844 cloned.Vlan = device.Vlan
845 cloned.Reason = device.Reason
Andrea Campanella025667e2021-01-14 11:50:07 +0100846 cloned.ImageDownloads = device.ImageDownloads
khenaidood948f772021-08-11 17:49:24 -0400847 cloned.OperStatus = device.OperStatus
848 cloned.ConnectStatus = device.ConnectStatus
849 if err = agent.updateDeviceAndReleaseLock(ctx, cloned); err == nil {
850 requestStatus.Code = common.OperationResp_OPERATION_SUCCESS
851 }
852 return err
khenaidoo43c82122018-11-22 18:38:28 -0500853}
854
Kent Hagerman2b216042020-04-03 18:28:56 -0400855func (agent *Agent) updateDeviceStatus(ctx context.Context, operStatus voltha.OperStatus_Types, connStatus voltha.ConnectStatus_Types) error {
khenaidood948f772021-08-11 17:49:24 -0400856 var err error
857 var desc string
858 opStatus := &common.OperationResp{Code: common.OperationResp_OPERATION_FAILURE}
859 defer func() { agent.logDeviceUpdate(ctx, nil, nil, opStatus, err, desc) }()
860
861 if err = agent.requestQueue.WaitForGreenLight(ctx); err != nil {
khenaidoo442e7c72020-03-10 16:13:48 -0400862 return err
863 }
khenaidoo6e55d9e2019-12-12 18:26:26 -0500864
Kent Hagermanf6db9f12020-07-22 17:16:19 -0400865 cloned := agent.cloneDeviceWithoutLock()
npujar1d86a522019-11-14 17:11:16 +0530866 // 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 -0400867 if s, ok := voltha.ConnectStatus_Types_name[int32(connStatus)]; ok {
khenaidood948f772021-08-11 17:49:24 -0400868 logger.Debugw(ctx, "update-device-conn-status", log.Fields{"ok": ok, "val": s})
Kent Hagermanf6db9f12020-07-22 17:16:19 -0400869 cloned.ConnectStatus = connStatus
npujar1d86a522019-11-14 17:11:16 +0530870 }
Kent Hagermanf6db9f12020-07-22 17:16:19 -0400871 if s, ok := voltha.OperStatus_Types_name[int32(operStatus)]; ok {
khenaidood948f772021-08-11 17:49:24 -0400872 logger.Debugw(ctx, "update-device-oper-status", log.Fields{"ok": ok, "val": s})
Kent Hagermanf6db9f12020-07-22 17:16:19 -0400873 cloned.OperStatus = operStatus
npujar1d86a522019-11-14 17:11:16 +0530874 }
Himani Chawlab4c25912020-11-12 17:16:38 +0530875 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 +0530876 // Store the device
khenaidood948f772021-08-11 17:49:24 -0400877 if err = agent.updateDeviceAndReleaseLock(ctx, cloned); err == nil {
878 opStatus.Code = common.OperationResp_OPERATION_SUCCESS
879 }
880 return err
khenaidoo92e62c52018-10-03 14:02:54 -0400881}
882
khenaidoob9203542018-09-17 22:56:37 -0400883// TODO: A generic device update by attribute
Kent Hagerman2b216042020-04-03 18:28:56 -0400884func (agent *Agent) updateDeviceAttribute(ctx context.Context, name string, value interface{}) {
khenaidoob9203542018-09-17 22:56:37 -0400885 if value == nil {
886 return
887 }
khenaidoo6e55d9e2019-12-12 18:26:26 -0500888
Kent Hagermanf6db9f12020-07-22 17:16:19 -0400889 if err := agent.requestQueue.WaitForGreenLight(ctx); err != nil {
890 logger.Warnw(ctx, "request-aborted", log.Fields{"device-id": agent.deviceID, "name": name, "error": err})
891 return
892 }
893
894 cloned := agent.cloneDeviceWithoutLock()
khenaidoob9203542018-09-17 22:56:37 -0400895 updated := false
khenaidoo6e55d9e2019-12-12 18:26:26 -0500896 s := reflect.ValueOf(cloned).Elem()
khenaidoob9203542018-09-17 22:56:37 -0400897 if s.Kind() == reflect.Struct {
898 // exported field
899 f := s.FieldByName(name)
900 if f.IsValid() && f.CanSet() {
901 switch f.Kind() {
902 case reflect.String:
903 f.SetString(value.(string))
904 updated = true
905 case reflect.Uint32:
906 f.SetUint(uint64(value.(uint32)))
907 updated = true
908 case reflect.Bool:
909 f.SetBool(value.(bool))
910 updated = true
911 }
912 }
913 }
divyadesaicb8b59d2020-08-18 09:55:47 +0000914 logger.Debugw(ctx, "update-field-status", log.Fields{"device-id": cloned.Id, "name": name, "updated": updated})
khenaidoob9203542018-09-17 22:56:37 -0400915 // Save the data
khenaidoo6e55d9e2019-12-12 18:26:26 -0500916
Kent Hagermanf6db9f12020-07-22 17:16:19 -0400917 if err := agent.updateDeviceAndReleaseLock(ctx, cloned); err != nil {
Rohan Agrawal31f21802020-06-12 05:38:46 +0000918 logger.Warnw(ctx, "attribute-update-failed", log.Fields{"attribute": name, "value": value})
khenaidoob9203542018-09-17 22:56:37 -0400919 }
khenaidoob9203542018-09-17 22:56:37 -0400920}
serkant.uluderya334479d2019-04-10 08:26:15 -0700921
Kent Hagerman45a13e42020-04-13 12:23:50 -0400922func (agent *Agent) simulateAlarm(ctx context.Context, simulateReq *voltha.SimulateAlarmRequest) error {
khenaidood948f772021-08-11 17:49:24 -0400923 var err error
924 var desc string
925 requestStatus := &common.OperationResp{Code: common.OperationResp_OPERATION_FAILURE}
926 defer func() { agent.logDeviceUpdate(ctx, nil, nil, requestStatus, err, desc) }()
927
928 if err = agent.requestQueue.WaitForGreenLight(ctx); err != nil {
khenaidoo442e7c72020-03-10 16:13:48 -0400929 return err
930 }
931 defer agent.requestQueue.RequestComplete()
Himani Chawlab4c25912020-11-12 17:16:38 +0530932 logger.Debugw(ctx, "simulate-alarm", log.Fields{"device-id": agent.deviceID})
khenaidoo6e55d9e2019-12-12 18:26:26 -0500933
Kent Hagermancba2f302020-07-28 13:37:36 -0400934 device := agent.getDeviceReadOnlyWithoutLock()
khenaidoo6e55d9e2019-12-12 18:26:26 -0500935
khenaidood948f772021-08-11 17:49:24 -0400936 client, err := agent.adapterMgr.GetAdapterClient(ctx, agent.adapterEndpoint)
khenaidoo442e7c72020-03-10 16:13:48 -0400937 if err != nil {
khenaidood948f772021-08-11 17:49:24 -0400938 logger.Errorw(ctx, "grpc-client-nil",
939 log.Fields{
940 "error": err,
941 "device-id": agent.deviceID,
942 "device-type": agent.deviceType,
943 "adapter-endpoint": device.AdapterEndpoint,
944 })
npujar1d86a522019-11-14 17:11:16 +0530945 return err
serkant.uluderya334479d2019-04-10 08:26:15 -0700946 }
khenaidood948f772021-08-11 17:49:24 -0400947 subCtx, cancel := context.WithTimeout(coreutils.WithAllMetadataFromContext(ctx), agent.rpcTimeout)
948 requestStatus.Code = common.OperationResp_OPERATION_IN_PROGRESS
949 go func() {
950 defer cancel()
khenaidoo9beaaf12021-10-19 17:32:01 -0400951 _, err := client.SimulateAlarm(subCtx, &ca.SimulateAlarmMessage{Device: device, Request: simulateReq})
khenaidood948f772021-08-11 17:49:24 -0400952 if err == nil {
953 agent.onSuccess(subCtx, nil, nil, false)
954 } else {
955 agent.onFailure(subCtx, err, nil, nil, false)
956 }
957 }()
serkant.uluderya334479d2019-04-10 08:26:15 -0700958 return nil
959}
Mahir Gunyelb5851672019-07-24 10:46:26 +0300960
Kent Hagermanf6db9f12020-07-22 17:16:19 -0400961// This function updates the device in the DB, releases the device lock, and runs any state transitions.
962// The calling function MUST hold the device lock. The caller MUST NOT modify the device after this is called.
963func (agent *Agent) updateDeviceAndReleaseLock(ctx context.Context, device *voltha.Device) error {
964 // fail early if this agent is no longer valid
Kent Hagerman4f355f52020-03-30 16:01:33 -0400965 if agent.stopped {
Kent Hagermanf6db9f12020-07-22 17:16:19 -0400966 agent.requestQueue.RequestComplete()
Himani Chawla2ba1c9c2020-10-07 13:19:03 +0530967 return errors.New("device-agent-stopped")
Thomas Lee Se5a44012019-11-07 20:32:24 +0530968 }
Kent Hagerman4f355f52020-03-30 16:01:33 -0400969
Kent Hagermanf6db9f12020-07-22 17:16:19 -0400970 // update in db
Kent Hagermanf5a67352020-04-30 15:15:26 -0400971 if err := agent.dbProxy.Set(ctx, agent.deviceID, device); err != nil {
Kent Hagermanf6db9f12020-07-22 17:16:19 -0400972 agent.requestQueue.RequestComplete()
Kent Hagerman4f355f52020-03-30 16:01:33 -0400973 return status.Errorf(codes.Internal, "failed-update-device:%s: %s", agent.deviceID, err)
Mahir Gunyelb5851672019-07-24 10:46:26 +0300974 }
divyadesaicb8b59d2020-08-18 09:55:47 +0000975 logger.Debugw(ctx, "updated-device-in-store", log.Fields{"device-id: ": agent.deviceID})
Mahir Gunyelb5851672019-07-24 10:46:26 +0300976
Kent Hagerman6031aad2020-07-29 16:36:33 -0400977 prevDevice := agent.device
Kent Hagermanf6db9f12020-07-22 17:16:19 -0400978 // update the device
khenaidoo0db4c812020-05-27 15:27:30 -0400979 agent.device = device
Mahir Gunyelb0343bf2021-05-11 14:14:26 -0700980 //If any of the states has chenged, send the change event.
981 if prevDevice.OperStatus != device.OperStatus || prevDevice.ConnectStatus != device.ConnectStatus || prevDevice.AdminState != device.AdminState {
982 _ = agent.deviceMgr.Agent.SendDeviceStateChangeEvent(ctx, prevDevice.OperStatus, prevDevice.ConnectStatus, prevDevice.AdminState, device, time.Now().Unix())
983 }
Maninder0aabf0c2021-03-17 14:55:14 +0530984 deviceTransientState := agent.getTransientState()
985
Kent Hagermanf6db9f12020-07-22 17:16:19 -0400986 // release lock before processing transition
987 agent.requestQueue.RequestComplete()
Himani Chawlab4c25912020-11-12 17:16:38 +0530988 subCtx := coreutils.WithSpanAndRPCMetadataFromContext(ctx)
Kent Hagermanf6db9f12020-07-22 17:16:19 -0400989
Himani Chawlab4c25912020-11-12 17:16:38 +0530990 if err := agent.deviceMgr.stateTransitions.ProcessTransition(subCtx,
Maninder0aabf0c2021-03-17 14:55:14 +0530991 device, prevDevice, deviceTransientState, deviceTransientState); err != nil {
Himani Chawlab4c25912020-11-12 17:16:38 +0530992 logger.Errorw(ctx, "failed-process-transition", log.Fields{"device-id": device.Id, "previous-admin-state": prevDevice.AdminState, "current-admin-state": device.AdminState})
993 // Sending RPC EVENT here
994 rpce := agent.deviceMgr.NewRPCEvent(ctx, agent.deviceID, err.Error(), nil)
Himani Chawla606a4f02021-03-23 19:45:58 +0530995 agent.deviceMgr.SendRPCEvent(ctx, "RPC_ERROR_RAISE_EVENT", rpce, voltha.EventCategory_COMMUNICATION,
996 nil, time.Now().Unix())
Himani Chawlab4c25912020-11-12 17:16:38 +0530997
Kent Hagermanf6db9f12020-07-22 17:16:19 -0400998 }
Mahir Gunyelb5851672019-07-24 10:46:26 +0300999 return nil
1000}
Mahir Gunyelfdee9212019-10-16 16:52:21 -07001001
Himani Chawla2ba1c9c2020-10-07 13:19:03 +05301002// This function updates the device transient in the DB through loader, releases the device lock, and runs any state transitions.
1003// The calling function MUST hold the device lock. The caller MUST NOT modify the device after this is called.
1004func (agent *Agent) updateDeviceWithTransientStateAndReleaseLock(ctx context.Context, device *voltha.Device,
khenaidood948f772021-08-11 17:49:24 -04001005 transientState, prevTransientState core.DeviceTransientState_Types) error {
Himani Chawla2ba1c9c2020-10-07 13:19:03 +05301006 // fail early if this agent is no longer valid
1007 if agent.stopped {
1008 agent.requestQueue.RequestComplete()
1009 return errors.New("device-agent-stopped")
1010 }
1011 //update device TransientState
1012 if err := agent.updateTransientState(ctx, transientState); err != nil {
1013 agent.requestQueue.RequestComplete()
1014 return err
1015 }
1016 // update in db
1017 if err := agent.dbProxy.Set(ctx, agent.deviceID, device); err != nil {
1018 //Reverting TransientState update
khenaidood948f772021-08-11 17:49:24 -04001019 if errTransient := agent.updateTransientState(ctx, prevTransientState); errTransient != nil {
1020 logger.Errorw(ctx, "failed-to-revert-transient-state-update-on-error", log.Fields{"device-id": device.Id,
1021 "previous-transient-state": prevTransientState, "current-transient-state": transientState, "error": errTransient})
1022 }
Himani Chawla2ba1c9c2020-10-07 13:19:03 +05301023 agent.requestQueue.RequestComplete()
1024 return status.Errorf(codes.Internal, "failed-update-device:%s: %s", agent.deviceID, err)
1025 }
1026
1027 logger.Debugw(ctx, "updated-device-in-store", log.Fields{"device-id: ": agent.deviceID})
1028
1029 prevDevice := agent.device
1030 // update the device
1031 agent.device = device
Mahir Gunyelb0343bf2021-05-11 14:14:26 -07001032 //If any of the states has chenged, send the change event.
1033 if prevDevice.OperStatus != device.OperStatus || prevDevice.ConnectStatus != device.ConnectStatus || prevDevice.AdminState != device.AdminState {
1034 _ = agent.deviceMgr.Agent.SendDeviceStateChangeEvent(ctx, prevDevice.OperStatus, prevDevice.ConnectStatus, prevDevice.AdminState, device, time.Now().Unix())
1035 }
Himani Chawla2ba1c9c2020-10-07 13:19:03 +05301036
1037 // release lock before processing transition
1038 agent.requestQueue.RequestComplete()
khenaidood948f772021-08-11 17:49:24 -04001039 go func() {
1040 subCtx := coreutils.WithSpanAndRPCMetadataFromContext(ctx)
1041 if err := agent.deviceMgr.stateTransitions.ProcessTransition(subCtx,
1042 device, prevDevice, transientState, prevTransientState); err != nil {
1043 logger.Errorw(ctx, "failed-process-transition", log.Fields{"device-id": device.Id, "previous-admin-state": prevDevice.AdminState, "current-admin-state": device.AdminState})
1044 // Sending RPC EVENT here
1045 rpce := agent.deviceMgr.NewRPCEvent(ctx, agent.deviceID, err.Error(), nil)
1046 agent.deviceMgr.SendRPCEvent(ctx, "RPC_ERROR_RAISE_EVENT", rpce, voltha.EventCategory_COMMUNICATION,
1047 nil, time.Now().Unix())
1048 }
1049 }()
Himani Chawla2ba1c9c2020-10-07 13:19:03 +05301050 return nil
1051}
Kent Hagerman2b216042020-04-03 18:28:56 -04001052func (agent *Agent) updateDeviceReason(ctx context.Context, reason string) error {
khenaidood948f772021-08-11 17:49:24 -04001053 logger.Debugw(ctx, "update-device-reason", log.Fields{"device-id": agent.deviceID, "reason": reason})
1054
1055 var err error
1056 var desc string
1057 requestStatus := &common.OperationResp{Code: common.OperationResp_OPERATION_FAILURE}
1058 defer func() { agent.logDeviceUpdate(ctx, nil, nil, requestStatus, err, desc) }()
1059
1060 if err = agent.requestQueue.WaitForGreenLight(ctx); err != nil {
khenaidoo442e7c72020-03-10 16:13:48 -04001061 return err
1062 }
Maninder9a1bc0d2020-10-26 11:34:02 +05301063
Kent Hagermanf6db9f12020-07-22 17:16:19 -04001064 cloned := agent.cloneDeviceWithoutLock()
npujar1d86a522019-11-14 17:11:16 +05301065 cloned.Reason = reason
khenaidood948f772021-08-11 17:49:24 -04001066 if err = agent.updateDeviceAndReleaseLock(ctx, cloned); err == nil {
1067 requestStatus.Code = common.OperationResp_OPERATION_SUCCESS
Maninder9a1bc0d2020-10-26 11:34:02 +05301068 }
khenaidood948f772021-08-11 17:49:24 -04001069 return err
Mahir Gunyelfdee9212019-10-16 16:52:21 -07001070}
kesavandbc2d1622020-01-21 00:42:01 -05001071
Kent Hagerman2b216042020-04-03 18:28:56 -04001072func (agent *Agent) ChildDeviceLost(ctx context.Context, device *voltha.Device) error {
Himani Chawlab4c25912020-11-12 17:16:38 +05301073 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 -05001074
khenaidood948f772021-08-11 17:49:24 -04001075 var err error
1076 var desc string
1077 requestStatus := &common.OperationResp{Code: common.OperationResp_OPERATION_FAILURE}
1078 defer func() { agent.logDeviceUpdate(ctx, nil, nil, requestStatus, err, desc) }()
1079
Kent Hagerman2a07b862020-06-19 15:23:07 -04001080 // Remove the associated peer ports on the parent device
1081 for portID := range agent.portLoader.ListIDs() {
1082 if portHandle, have := agent.portLoader.Lock(portID); have {
1083 oldPort := portHandle.GetReadOnly()
1084 updatedPeers := make([]*voltha.Port_PeerPort, 0)
1085 for _, peerPort := range oldPort.Peers {
1086 if peerPort.DeviceId != device.Id {
1087 updatedPeers = append(updatedPeers, peerPort)
1088 }
khenaidoo442e7c72020-03-10 16:13:48 -04001089 }
Kent Hagerman2a07b862020-06-19 15:23:07 -04001090 newPort := *oldPort
1091 newPort.Peers = updatedPeers
1092 if err := portHandle.Update(ctx, &newPort); err != nil {
1093 portHandle.Unlock()
1094 return nil
1095 }
1096 portHandle.Unlock()
khenaidoo442e7c72020-03-10 16:13:48 -04001097 }
Chaitrashree G S543df3e2020-02-24 22:36:54 -05001098 }
1099
khenaidoo442e7c72020-03-10 16:13:48 -04001100 //send request to adapter
khenaidood948f772021-08-11 17:49:24 -04001101 client, err := agent.adapterMgr.GetAdapterClient(ctx, agent.adapterEndpoint)
khenaidoo442e7c72020-03-10 16:13:48 -04001102 if err != nil {
khenaidood948f772021-08-11 17:49:24 -04001103 logger.Errorw(ctx, "grpc-client-nil",
1104 log.Fields{
1105 "error": err,
1106 "device-id": agent.deviceID,
1107 "device-type": agent.deviceType,
1108 "adapter-endpoint": device.AdapterEndpoint,
1109 })
khenaidoo442e7c72020-03-10 16:13:48 -04001110 return err
Chaitrashree G S543df3e2020-02-24 22:36:54 -05001111 }
khenaidood948f772021-08-11 17:49:24 -04001112 subCtx, cancel := context.WithTimeout(coreutils.WithAllMetadataFromContext(ctx), agent.rpcTimeout)
1113 requestStatus.Code = common.OperationResp_OPERATION_IN_PROGRESS
1114 go func() {
1115 defer cancel()
1116 _, err := client.ChildDeviceLost(subCtx, device)
1117 if err == nil {
1118 agent.onSuccess(subCtx, nil, nil, true)
1119 } else {
1120 agent.onFailure(subCtx, err, nil, nil, true)
1121 }
1122 }()
Chaitrashree G S543df3e2020-02-24 22:36:54 -05001123 return nil
Chaitrashree G S543df3e2020-02-24 22:36:54 -05001124}
onkarkundargi87285252020-01-27 11:34:52 +05301125
khenaidoo9beaaf12021-10-19 17:32:01 -04001126func (agent *Agent) startOmciTest(ctx context.Context, omcitestrequest *omci.OmciTestRequest) (*omci.TestResponse, error) {
khenaidood948f772021-08-11 17:49:24 -04001127 var err error
1128 var desc string
1129 requestStatus := &common.OperationResp{Code: common.OperationResp_OPERATION_FAILURE}
1130 defer func() { agent.logDeviceUpdate(ctx, nil, nil, requestStatus, err, desc) }()
onkarkundargi87285252020-01-27 11:34:52 +05301131
khenaidood948f772021-08-11 17:49:24 -04001132 // OMCI test may be performed on a pre-provisioned device. If a device is in that state both its device type and endpoint
1133 // may not have been set yet.
1134 // First check if we need to update the type or endpoint
1135 cloned, err := agent.getDeviceReadOnly(ctx)
onkarkundargi87285252020-01-27 11:34:52 +05301136 if err != nil {
1137 return nil, err
1138 }
khenaidood948f772021-08-11 17:49:24 -04001139 if cloned.Type == "" || cloned.AdapterEndpoint == "" {
1140 if err = agent.updateDeviceTypeAndEndpoint(ctx); err != nil {
1141 return nil, err
1142 }
1143 cloned, err = agent.getDeviceReadOnly(ctx)
1144 if err != nil {
1145 return nil, err
1146 }
onkarkundargi87285252020-01-27 11:34:52 +05301147 }
1148
khenaidood948f772021-08-11 17:49:24 -04001149 // Send request to the adapter
1150 client, err := agent.adapterMgr.GetAdapterClient(ctx, agent.adapterEndpoint)
1151 if err != nil {
1152 logger.Errorw(ctx, "grpc-client-nil",
1153 log.Fields{
1154 "error": err,
1155 "device-id": agent.deviceID,
1156 "device-type": agent.deviceType,
1157 "adapter-endpoint": cloned.AdapterEndpoint,
1158 })
1159 return nil, err
onkarkundargi87285252020-01-27 11:34:52 +05301160 }
khenaidood948f772021-08-11 17:49:24 -04001161
khenaidoo9beaaf12021-10-19 17:32:01 -04001162 res, err := client.StartOmciTest(ctx, &ca.OMCITest{
khenaidood948f772021-08-11 17:49:24 -04001163 Device: cloned,
1164 Request: omcitestrequest,
1165 })
1166 if err == nil {
1167 requestStatus.Code = common.OperationResp_OPERATION_SUCCESS
1168 }
1169 return res, err
onkarkundargi87285252020-01-27 11:34:52 +05301170}
Dinesh Belwalkarc1129f12020-02-27 10:41:33 -08001171
khenaidoo9beaaf12021-10-19 17:32:01 -04001172func (agent *Agent) getExtValue(ctx context.Context, pdevice *voltha.Device, cdevice *voltha.Device, valueparam *extension.ValueSpecifier) (*extension.ReturnValues, error) {
Himani Chawlab4c25912020-11-12 17:16:38 +05301173 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 -04001174 var err error
1175 var desc string
1176 requestStatus := &common.OperationResp{Code: common.OperationResp_OPERATION_FAILURE}
1177 defer func() { agent.logDeviceUpdate(ctx, nil, nil, requestStatus, err, desc) }()
1178
1179 if err = agent.requestQueue.WaitForGreenLight(ctx); err != nil {
Dinesh Belwalkarc1129f12020-02-27 10:41:33 -08001180 return nil, err
1181 }
1182
khenaidood948f772021-08-11 17:49:24 -04001183 //send request to adapter synchronously
1184 client, err := agent.adapterMgr.GetAdapterClient(ctx, pdevice.AdapterEndpoint)
Dinesh Belwalkarc1129f12020-02-27 10:41:33 -08001185 if err != nil {
khenaidood948f772021-08-11 17:49:24 -04001186 logger.Errorw(ctx, "grpc-client-nil",
1187 log.Fields{
1188 "error": err,
1189 "device-id": agent.deviceID,
1190 "device-type": agent.deviceType,
1191 "adapter-endpoint": pdevice.AdapterEndpoint,
1192 })
1193 agent.requestQueue.RequestComplete()
Dinesh Belwalkarc1129f12020-02-27 10:41:33 -08001194 return nil, err
1195 }
1196
khenaidood948f772021-08-11 17:49:24 -04001197 // Release lock before sending to adapter
1198 agent.requestQueue.RequestComplete()
Dinesh Belwalkarc1129f12020-02-27 10:41:33 -08001199
khenaidoo9beaaf12021-10-19 17:32:01 -04001200 retVal, err := client.GetExtValue(ctx, &ca.GetExtValueMessage{
khenaidood948f772021-08-11 17:49:24 -04001201 ParentDevice: pdevice,
1202 ChildDevice: cdevice,
1203 ValueType: valueparam.Value,
1204 })
1205 if err == nil {
1206 requestStatus.Code = common.OperationResp_OPERATION_SUCCESS
Dinesh Belwalkarc1129f12020-02-27 10:41:33 -08001207 }
khenaidood948f772021-08-11 17:49:24 -04001208 return retVal, err
Dinesh Belwalkarc1129f12020-02-27 10:41:33 -08001209}
dpaul62686312020-06-23 14:17:36 +05301210
khenaidoo9beaaf12021-10-19 17:32:01 -04001211func (agent *Agent) setExtValue(ctx context.Context, device *voltha.Device, value *extension.ValueSet) (*empty.Empty, error) {
Himani Chawlab4c25912020-11-12 17:16:38 +05301212 logger.Debugw(ctx, "set-ext-value", log.Fields{"device-id": value.Id})
khenaidood948f772021-08-11 17:49:24 -04001213
1214 var err error
1215 var desc string
1216 requestStatus := &common.OperationResp{Code: common.OperationResp_OPERATION_FAILURE}
1217 defer func() { agent.logDeviceUpdate(ctx, nil, nil, requestStatus, err, desc) }()
1218
1219 if err = agent.requestQueue.WaitForGreenLight(ctx); err != nil {
dpaul62686312020-06-23 14:17:36 +05301220 return nil, err
1221 }
1222
1223 //send request to adapter
khenaidood948f772021-08-11 17:49:24 -04001224 //send request to adapter synchronously
1225 client, err := agent.adapterMgr.GetAdapterClient(ctx, agent.adapterEndpoint)
dpaul62686312020-06-23 14:17:36 +05301226 if err != nil {
khenaidood948f772021-08-11 17:49:24 -04001227 logger.Errorw(ctx, "grpc-client-nil",
1228 log.Fields{
1229 "error": err,
1230 "device-id": agent.deviceID,
1231 "device-type": agent.deviceType,
1232 "adapter-endpoint": device.AdapterEndpoint,
1233 })
1234 agent.requestQueue.RequestComplete()
dpaul62686312020-06-23 14:17:36 +05301235 return nil, err
1236 }
khenaidood948f772021-08-11 17:49:24 -04001237 // Release lock before sending request to adapter
1238 agent.requestQueue.RequestComplete()
dpaul62686312020-06-23 14:17:36 +05301239
khenaidoo9beaaf12021-10-19 17:32:01 -04001240 retVal, err := client.SetExtValue(ctx, &ca.SetExtValueMessage{
khenaidood948f772021-08-11 17:49:24 -04001241 Device: device,
1242 Value: value,
1243 })
1244 if err == nil {
1245 requestStatus.Code = common.OperationResp_OPERATION_SUCCESS
dpaul62686312020-06-23 14:17:36 +05301246 }
khenaidood948f772021-08-11 17:49:24 -04001247 return retVal, err
dpaul62686312020-06-23 14:17:36 +05301248}
Salman Siddiqui1cf95042020-11-19 00:42:56 +05301249
1250func (agent *Agent) getSingleValue(ctx context.Context, request *extension.SingleGetValueRequest) (*extension.SingleGetValueResponse, error) {
Himani Chawlab4c25912020-11-12 17:16:38 +05301251 logger.Debugw(ctx, "get-single-value", log.Fields{"device-id": request.TargetId})
Salman Siddiqui1cf95042020-11-19 00:42:56 +05301252
khenaidood948f772021-08-11 17:49:24 -04001253 var err error
1254 var desc string
1255 requestStatus := &common.OperationResp{Code: common.OperationResp_OPERATION_FAILURE}
1256 defer func() { agent.logDeviceUpdate(ctx, nil, nil, requestStatus, err, desc) }()
1257
1258 if err = agent.requestQueue.WaitForGreenLight(ctx); err != nil {
Salman Siddiqui1cf95042020-11-19 00:42:56 +05301259 return nil, err
1260 }
1261
1262 cloned := agent.cloneDeviceWithoutLock()
1263
1264 //send request to adapter
khenaidood948f772021-08-11 17:49:24 -04001265 client, err := agent.adapterMgr.GetAdapterClient(ctx, agent.adapterEndpoint)
Salman Siddiqui1cf95042020-11-19 00:42:56 +05301266 if err != nil {
khenaidood948f772021-08-11 17:49:24 -04001267 logger.Errorw(ctx, "grpc-client-nil",
1268 log.Fields{
1269 "error": err,
1270 "device-id": cloned.Id,
1271 "adapter-endpoint": cloned.AdapterEndpoint,
1272 })
1273 agent.requestQueue.RequestComplete()
Salman Siddiqui1cf95042020-11-19 00:42:56 +05301274 return nil, err
1275 }
khenaidood948f772021-08-11 17:49:24 -04001276 // Release lock before sending request to adapter
1277 agent.requestQueue.RequestComplete()
Salman Siddiqui1cf95042020-11-19 00:42:56 +05301278
khenaidood948f772021-08-11 17:49:24 -04001279 resp, err := client.GetSingleValue(ctx, request)
1280 if err == nil {
1281 requestStatus.Code = common.OperationResp_OPERATION_SUCCESS
Salman Siddiqui1cf95042020-11-19 00:42:56 +05301282 }
khenaidood948f772021-08-11 17:49:24 -04001283 return resp, err
Salman Siddiqui1cf95042020-11-19 00:42:56 +05301284}
1285
1286func (agent *Agent) setSingleValue(ctx context.Context, request *extension.SingleSetValueRequest) (*extension.SingleSetValueResponse, error) {
Himani Chawlab4c25912020-11-12 17:16:38 +05301287 logger.Debugw(ctx, "set-single-value", log.Fields{"device-id": request.TargetId})
Salman Siddiqui1cf95042020-11-19 00:42:56 +05301288
khenaidood948f772021-08-11 17:49:24 -04001289 var err error
1290 var desc string
1291 requestStatus := &common.OperationResp{Code: common.OperationResp_OPERATION_FAILURE}
1292 defer func() { agent.logDeviceUpdate(ctx, nil, nil, requestStatus, err, desc) }()
1293
Salman Siddiqui1cf95042020-11-19 00:42:56 +05301294 if err := agent.requestQueue.WaitForGreenLight(ctx); err != nil {
1295 return nil, err
1296 }
1297
1298 cloned := agent.cloneDeviceWithoutLock()
1299
1300 //send request to adapter
khenaidood948f772021-08-11 17:49:24 -04001301 client, err := agent.adapterMgr.GetAdapterClient(ctx, agent.adapterEndpoint)
Salman Siddiqui1cf95042020-11-19 00:42:56 +05301302 if err != nil {
khenaidood948f772021-08-11 17:49:24 -04001303 logger.Errorw(ctx, "grpc-client-nil",
1304 log.Fields{
1305 "error": err,
1306 "device-id": agent.deviceID,
1307 "device-type": agent.deviceType,
1308 "adapter-endpoint": cloned.AdapterEndpoint,
1309 })
1310 agent.requestQueue.RequestComplete()
Salman Siddiqui1cf95042020-11-19 00:42:56 +05301311 return nil, err
1312 }
khenaidood948f772021-08-11 17:49:24 -04001313 // Release lock before sending request to adapter
1314 agent.requestQueue.RequestComplete()
Salman Siddiqui1cf95042020-11-19 00:42:56 +05301315
khenaidood948f772021-08-11 17:49:24 -04001316 resp, err := client.SetSingleValue(ctx, request)
1317 if err == nil {
1318 requestStatus.Code = common.OperationResp_OPERATION_SUCCESS
Salman Siddiqui1cf95042020-11-19 00:42:56 +05301319 }
khenaidood948f772021-08-11 17:49:24 -04001320 return resp, err
Salman Siddiqui1cf95042020-11-19 00:42:56 +05301321}
Maninder0aabf0c2021-03-17 14:55:14 +05301322
Maninder2195ccc2021-06-23 20:23:01 +05301323func (agent *Agent) proceedWithRequest(device *voltha.Device) bool {
1324 return !agent.isDeletionInProgress() && !agent.isInReconcileState(device)
Maninder0aabf0c2021-03-17 14:55:14 +05301325}
1326
1327func (agent *Agent) stopReconcile() {
1328 agent.stopReconcilingMutex.Lock()
1329 if agent.stopReconciling != nil {
1330 agent.stopReconciling <- 0
1331 }
1332 agent.stopReconcilingMutex.Unlock()
1333}
1334
khenaidood948f772021-08-11 17:49:24 -04001335// abortAllProcessing is invoked when an adapter managing this device is restarted
1336func (agent *Agent) abortAllProcessing(ctx context.Context) error {
1337 logger.Infow(ctx, "aborting-current-running-requests", log.Fields{"device-id": agent.deviceID})
1338 if err := agent.requestQueue.WaitForGreenLight(ctx); err != nil {
1339 return err
1340 }
1341 defer agent.requestQueue.RequestComplete()
1342
1343 // If any reconciling is in progress just abort it. The adapter is gone.
1344 agent.stopReconcile()
1345
1346 // Update the Core device transient state accordingly
1347 var updatedState core.DeviceTransientState_Types
1348 switch agent.getTransientState() {
1349 case core.DeviceTransientState_RECONCILE_IN_PROGRESS:
1350 updatedState = core.DeviceTransientState_NONE
1351 case core.DeviceTransientState_FORCE_DELETING:
1352 updatedState = core.DeviceTransientState_DELETE_FAILED
1353 case core.DeviceTransientState_DELETING_FROM_ADAPTER:
1354 updatedState = core.DeviceTransientState_DELETE_FAILED
1355 default:
1356 updatedState = core.DeviceTransientState_NONE
1357 }
1358 if err := agent.updateTransientState(ctx, updatedState); err != nil {
1359 logger.Errorf(ctx, "transient-state-update-failed", log.Fields{"error": err})
1360 return err
1361 }
1362 return nil
1363}
1364
1365func (agent *Agent) ReconcileDevice(ctx context.Context) {
1366 requestStatus := &common.OperationResp{Code: common.OperationResp_OPERATION_FAILURE}
Maninder0aabf0c2021-03-17 14:55:14 +05301367 var desc string
Maninder0aabf0c2021-03-17 14:55:14 +05301368
1369 if err := agent.requestQueue.WaitForGreenLight(ctx); err != nil {
khenaidood948f772021-08-11 17:49:24 -04001370 agent.logDeviceUpdate(ctx, nil, nil, requestStatus, err, desc)
1371 return
1372 }
1373
1374 device := agent.getDeviceReadOnlyWithoutLock()
1375 if device.AdminState == voltha.AdminState_PREPROVISIONED {
1376 agent.requestQueue.RequestComplete()
1377 logger.Debugw(ctx, "device-in-preprovisioning-state-reconcile-not-needed", log.Fields{"device-id": device.Id})
Maninder0aabf0c2021-03-17 14:55:14 +05301378 return
1379 }
1380
Maninder2195ccc2021-06-23 20:23:01 +05301381 if !agent.proceedWithRequest(device) {
Maninder0aabf0c2021-03-17 14:55:14 +05301382 agent.requestQueue.RequestComplete()
khenaidood948f772021-08-11 17:49:24 -04001383 err := fmt.Errorf("cannot complete operation as device deletion/reconciling is in progress or reconcile failed for device : %s", device.Id)
1384 logger.Errorw(ctx, "reconcile-failed", log.Fields{"error": err})
1385 agent.logDeviceUpdate(ctx, nil, nil, requestStatus, err, desc)
Maninder0aabf0c2021-03-17 14:55:14 +05301386 return
1387 }
1388
1389 //set transient state to RECONCILE IN PROGRESS
khenaidood948f772021-08-11 17:49:24 -04001390 err := agent.updateTransientState(ctx, core.DeviceTransientState_RECONCILE_IN_PROGRESS)
Maninder0aabf0c2021-03-17 14:55:14 +05301391 if err != nil {
1392 agent.requestQueue.RequestComplete()
khenaidood948f772021-08-11 17:49:24 -04001393 logger.Errorw(ctx, "setting-transient-state-failed", log.Fields{"error": err})
1394 agent.logDeviceUpdate(ctx, nil, nil, requestStatus, nil, desc)
Maninder0aabf0c2021-03-17 14:55:14 +05301395 return
1396 }
1397
Maninder0aabf0c2021-03-17 14:55:14 +05301398 reconcilingBackoff := backoff.NewExponentialBackOff()
1399 reconcilingBackoff.InitialInterval = agent.config.BackoffRetryInitialInterval
1400 reconcilingBackoff.MaxElapsedTime = agent.config.BackoffRetryMaxElapsedTime
1401 reconcilingBackoff.MaxInterval = agent.config.BackoffRetryMaxInterval
1402
1403 //making here to keep lifecycle of this channel within the scope of retryReconcile
1404 agent.stopReconcilingMutex.Lock()
1405 agent.stopReconciling = make(chan int)
1406 agent.stopReconcilingMutex.Unlock()
1407
David K. Bainbridge482e4422021-06-30 12:23:42 -07001408 // defined outside the retry loop so it can be cleaned
1409 // up when the loop breaks
1410 var backoffTimer *time.Timer
1411
1412retry:
Maninder0aabf0c2021-03-17 14:55:14 +05301413 for {
David K. Bainbridge482e4422021-06-30 12:23:42 -07001414 // If the operations state of the device is RECONCILING_FAILED then we do not
1415 // want to continue to attempt reconciliation.
1416 deviceRef := agent.getDeviceReadOnlyWithoutLock()
1417 if deviceRef.OperStatus == common.OperStatus_RECONCILING_FAILED {
1418 logger.Warnw(ctx, "reconciling-failed-halting-retries",
1419 log.Fields{"device-id": device.Id})
1420 agent.requestQueue.RequestComplete()
1421 break retry
1422 }
1423
Maninder0aabf0c2021-03-17 14:55:14 +05301424 // Use an exponential back off to prevent getting into a tight loop
1425 duration := reconcilingBackoff.NextBackOff()
1426 //This case should never occur in default case as max elapsed time for backoff is 0(by default) , so it will never return stop
1427 if duration == backoff.Stop {
1428 // If we reach a maximum then warn and reset the backoff
1429 // timer and keep attempting.
1430 logger.Warnw(ctx, "maximum-reconciling-backoff-reached--resetting-backoff-timer",
1431 log.Fields{"max-reconciling-backoff": reconcilingBackoff.MaxElapsedTime,
1432 "device-id": device.Id})
1433 reconcilingBackoff.Reset()
1434 duration = reconcilingBackoff.NextBackOff()
1435 }
1436
David K. Bainbridge482e4422021-06-30 12:23:42 -07001437 backoffTimer = time.NewTimer(duration)
Maninder0aabf0c2021-03-17 14:55:14 +05301438
khenaidood948f772021-08-11 17:49:24 -04001439 logger.Debugw(ctx, "retrying-reconciling", log.Fields{"deviceID": device.Id, "endpoint": device.AdapterEndpoint})
1440 // Release lock before sending request to adapter
Maninder0aabf0c2021-03-17 14:55:14 +05301441 agent.requestQueue.RequestComplete()
khenaidood948f772021-08-11 17:49:24 -04001442
1443 // Send a reconcile request to the adapter.
1444 err := agent.sendReconcileRequestToAdapter(ctx, device)
1445 if errors.Is(err, errContextExpired) || errors.Is(err, errReconcileAborted) {
1446 logger.Errorw(ctx, "reconcile-aborted", log.Fields{"error": err})
1447 requestStatus = &common.OperationResp{Code: common.OperationResp_OperationReturnCode(common.OperStatus_FAILED)}
1448 desc = "aborted"
1449 agent.logDeviceUpdate(ctx, nil, nil, requestStatus, err, desc)
1450 break retry
1451 }
Maninder0aabf0c2021-03-17 14:55:14 +05301452 if err != nil {
khenaidood948f772021-08-11 17:49:24 -04001453 agent.logDeviceUpdate(ctx, nil, nil, requestStatus, err, desc)
Maninder0aabf0c2021-03-17 14:55:14 +05301454 <-backoffTimer.C
1455 // backoffTimer expired continue
1456 // Take lock back before retrying
1457 if err := agent.requestQueue.WaitForGreenLight(ctx); err != nil {
khenaidood948f772021-08-11 17:49:24 -04001458 agent.logDeviceUpdate(ctx, nil, nil, requestStatus, err, desc)
David K. Bainbridge482e4422021-06-30 12:23:42 -07001459 break retry
Maninder0aabf0c2021-03-17 14:55:14 +05301460 }
1461 continue
1462 }
khenaidood948f772021-08-11 17:49:24 -04001463 // Success
1464 requestStatus = &common.OperationResp{Code: common.OperationResp_OPERATION_SUCCESS}
1465 desc = "adapter-response"
1466 agent.logDeviceUpdate(ctx, nil, nil, requestStatus, err, desc)
1467 break retry
David K. Bainbridge482e4422021-06-30 12:23:42 -07001468 }
1469
1470 // Retry loop is broken, so stop any timers and drain the channel
1471 if backoffTimer != nil && !backoffTimer.Stop() {
1472
1473 // As per documentation and stack overflow when a timer is stopped its
1474 // channel should be drained. The issue is that Stop returns false
1475 // either if the timer has already been fired "OR" if the timer can be
1476 // stopped before being fired. This means that in some cases the
1477 // channel has already be emptied so attempting to read from it means
1478 // a blocked thread. To get around this use a select so if the
1479 // channel is already empty the default case hits and we are not
1480 // blocked.
1481 select {
1482 case <-backoffTimer.C:
1483 default:
Maninder0aabf0c2021-03-17 14:55:14 +05301484 }
1485 }
1486}
1487
khenaidood948f772021-08-11 17:49:24 -04001488func (agent *Agent) sendReconcileRequestToAdapter(ctx context.Context, device *voltha.Device) error {
1489 logger.Debugw(ctx, "sending-reconcile-to-adapter", log.Fields{"device-id": device.Id, "endpoint": agent.adapterEndpoint})
1490 client, err := agent.adapterMgr.GetAdapterClient(ctx, agent.adapterEndpoint)
1491 if err != nil {
1492 return err
1493 }
1494 adapterResponse := make(chan error)
1495 go func() {
1496 _, err := client.ReconcileDevice(ctx, device)
1497 adapterResponse <- err
1498 }()
Maninder0aabf0c2021-03-17 14:55:14 +05301499 select {
1500 // wait for response
khenaidood948f772021-08-11 17:49:24 -04001501 case err := <-adapterResponse:
1502 if err != nil {
1503 return err
Maninder0aabf0c2021-03-17 14:55:14 +05301504 }
Maninder0aabf0c2021-03-17 14:55:14 +05301505 //In case of success quit retrying and wait for adapter to reset operation state of device
1506 agent.stopReconcilingMutex.Lock()
1507 agent.stopReconciling = nil
1508 agent.stopReconcilingMutex.Unlock()
1509 return nil
1510
1511 //if reconciling need to be stopped
1512 case _, ok := <-agent.stopReconciling:
1513 agent.stopReconcilingMutex.Lock()
1514 agent.stopReconciling = nil
1515 agent.stopReconcilingMutex.Unlock()
1516 if !ok {
1517 //channel-closed
khenaidood948f772021-08-11 17:49:24 -04001518 return fmt.Errorf("reconcile channel closed:%w", errReconcileAborted)
Maninder0aabf0c2021-03-17 14:55:14 +05301519 }
khenaidood948f772021-08-11 17:49:24 -04001520 return fmt.Errorf("reconciling aborted:%w", errReconcileAborted)
1521 // Context expired
1522 case <-ctx.Done():
1523 return fmt.Errorf("context expired:%s :%w", ctx.Err(), errContextExpired)
Maninder0aabf0c2021-03-17 14:55:14 +05301524 }
Maninder0aabf0c2021-03-17 14:55:14 +05301525}
1526
1527func (agent *Agent) reconcilingCleanup(ctx context.Context) error {
1528 var desc string
khenaidood948f772021-08-11 17:49:24 -04001529 var err error
Maninder0aabf0c2021-03-17 14:55:14 +05301530 operStatus := &common.OperationResp{Code: common.OperationResp_OPERATION_FAILURE}
khenaidood948f772021-08-11 17:49:24 -04001531 defer func() { agent.logDeviceUpdate(ctx, nil, nil, operStatus, err, desc) }()
1532
1533 if err = agent.requestQueue.WaitForGreenLight(ctx); err != nil {
1534 desc = "reconcile-cleanup-failed"
Maninder0aabf0c2021-03-17 14:55:14 +05301535 return err
1536 }
1537 defer agent.requestQueue.RequestComplete()
khenaidood948f772021-08-11 17:49:24 -04001538 err = agent.updateTransientState(ctx, core.DeviceTransientState_NONE)
Maninder0aabf0c2021-03-17 14:55:14 +05301539 if err != nil {
khenaidood948f772021-08-11 17:49:24 -04001540 logger.Errorf(ctx, "transient-state-update-failed", log.Fields{"error": err})
Maninder0aabf0c2021-03-17 14:55:14 +05301541 return err
1542 }
khenaidood948f772021-08-11 17:49:24 -04001543 operStatus.Code = common.OperationResp_OPERATION_SUCCESS
Maninder0aabf0c2021-03-17 14:55:14 +05301544 return nil
1545}
khenaidood948f772021-08-11 17:49:24 -04001546
1547func (agent *Agent) isAdapterConnectionUp(ctx context.Context) bool {
1548 c, err := agent.adapterMgr.GetAdapterClient(ctx, agent.adapterEndpoint)
1549 return c != nil && err == nil
1550}
1551
1552func (agent *Agent) canDeviceRequestProceed(ctx context.Context) error {
1553 if err := agent.requestQueue.WaitForGreenLight(ctx); err != nil {
1554 return err
1555 }
1556 defer agent.requestQueue.RequestComplete()
1557 if agent.proceedWithRequest(agent.device) {
1558 return nil
1559 }
1560 return fmt.Errorf("device-cannot-process-request-%s", agent.deviceID)
1561}