blob: a33765bb2401140688454a7681a61c8d81c25e57 [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 }
Mahir Gunyel92dd1212021-10-22 11:42:56 -0700385 //vol-4275 TST meeting 08/04/2021: Let EnableDevice to be called again if device is in FAILED operational state,
386 //even the admin state is ENABLED.
387 if oldDevice.AdminState == voltha.AdminState_ENABLED && oldDevice.OperStatus != voltha.OperStatus_FAILED {
Kent Hagermanf6db9f12020-07-22 17:16:19 -0400388 logger.Warnw(ctx, "device-already-enabled", log.Fields{"device-id": agent.deviceID})
389 agent.requestQueue.RequestComplete()
khenaidood948f772021-08-11 17:49:24 -0400390 err = status.Errorf(codes.FailedPrecondition, fmt.Sprintf("cannot-enable-an-already-enabled-device: %s", oldDevice.Id))
Matteo Scandolod525ae32020-04-02 17:27:29 -0700391 return err
npujar1d86a522019-11-14 17:11:16 +0530392 }
393
khenaidood948f772021-08-11 17:49:24 -0400394 // Verify whether there is a device type that supports this device type
395 _, err = agent.adapterMgr.GetAdapterType(oldDevice.Type)
396 if err != nil {
397 agent.requestQueue.RequestComplete()
398 return err
399 }
400
401 // 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
402 // 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 -0400403 newDevice := agent.cloneDeviceWithoutLock()
khenaidood948f772021-08-11 17:49:24 -0400404 if newDevice.AdapterEndpoint == "" {
405 if newDevice.AdapterEndpoint, err = agent.adapterMgr.GetAdapterEndpoint(ctx, newDevice.Id, newDevice.Type); err != nil {
406 agent.requestQueue.RequestComplete()
407 return err
408 }
409 agent.adapterEndpoint = newDevice.AdapterEndpoint
410 }
npujar1d86a522019-11-14 17:11:16 +0530411
Kent Hagermanf6db9f12020-07-22 17:16:19 -0400412 // Update the Admin State and set the operational state to activating before sending the request to the Adapters
413 newDevice.AdminState = voltha.AdminState_ENABLED
414 newDevice.OperStatus = voltha.OperStatus_ACTIVATING
Maninder9a1bc0d2020-10-26 11:34:02 +0530415
khenaidoo442e7c72020-03-10 16:13:48 -0400416 // 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 -0400417 client, err := agent.adapterMgr.GetAdapterClient(ctx, agent.adapterEndpoint)
khenaidoo442e7c72020-03-10 16:13:48 -0400418 if err != nil {
khenaidood948f772021-08-11 17:49:24 -0400419 logger.Errorw(ctx, "grpc-client-nil",
420 log.Fields{
421 "error": err,
422 "device-id": agent.deviceID,
423 "device-type": agent.deviceType,
424 "adapter-endpoint": newDevice.AdapterEndpoint,
425 })
426 agent.requestQueue.RequestComplete()
khenaidoo442e7c72020-03-10 16:13:48 -0400427 return err
428 }
khenaidood948f772021-08-11 17:49:24 -0400429 subCtx, cancel := context.WithTimeout(coreutils.WithAllMetadataFromContext(ctx), agent.rpcTimeout)
430 requestStatus.Code = common.OperationResp_OPERATION_IN_PROGRESS
431 go func() {
432 defer cancel()
433 var err error
434 if oldDevice.AdminState == voltha.AdminState_PREPROVISIONED {
435 _, err = client.AdoptDevice(subCtx, newDevice)
436 } else {
437 _, err = client.ReEnableDevice(subCtx, newDevice)
438 }
439 if err == nil {
440 agent.onSuccess(subCtx, nil, nil, true)
441 } else {
442 agent.onFailure(subCtx, err, nil, nil, true)
Himani Chawlab4c25912020-11-12 17:16:38 +0530443 }
444 }()
khenaidood948f772021-08-11 17:49:24 -0400445
446 // Update device
447 if err = agent.updateDeviceAndReleaseLock(ctx, newDevice); err != nil {
448 return err
khenaidoo2c6a0992019-04-29 13:46:56 -0400449 }
khenaidood948f772021-08-11 17:49:24 -0400450 currAdminState = newDevice.AdminState
451 return nil
khenaidoo2c6a0992019-04-29 13:46:56 -0400452}
453
A R Karthick5c28f552019-12-11 22:47:44 -0800454//addFlowsAndGroups adds the "newFlows" and "newGroups" from the existing flows/groups and sends the update to the
455//adapters
Kent Hagerman2b216042020-04-03 18:28:56 -0400456func (agent *Agent) addFlowsAndGroups(ctx context.Context, newFlows []*ofp.OfpFlowStats, newGroups []*ofp.OfpGroupEntry, flowMetadata *voltha.FlowMetadata) error {
Mahir Gunyel03de0d32020-06-03 01:36:59 -0700457 var flwResponse, grpResponse coreutils.Response
458 var err error
459 //if new flow list is empty then the called function returns quickly
460 if flwResponse, err = agent.addFlowsToAdapter(ctx, newFlows, flowMetadata); err != nil {
A R Karthick5c28f552019-12-11 22:47:44 -0800461 return err
462 }
Mahir Gunyel03de0d32020-06-03 01:36:59 -0700463 //if new group list is empty then the called function returns quickly
464 if grpResponse, err = agent.addGroupsToAdapter(ctx, newGroups, flowMetadata); err != nil {
465 return err
466 }
khenaidood948f772021-08-11 17:49:24 -0400467 if errs := coreutils.WaitForNilOrErrorResponses(agent.rpcTimeout, flwResponse, grpResponse); errs != nil {
468 logger.Warnw(ctx, "adapter-response", log.Fields{"device-id": agent.deviceID, "result": errs})
khenaidoo442e7c72020-03-10 16:13:48 -0400469 return status.Errorf(codes.Aborted, "flow-failure-device-%s", agent.deviceID)
khenaidoo0458db62019-06-20 08:50:36 -0400470 }
khenaidoo0458db62019-06-20 08:50:36 -0400471 return nil
472}
473
A R Karthick5c28f552019-12-11 22:47:44 -0800474//deleteFlowsAndGroups removes the "flowsToDel" and "groupsToDel" from the existing flows/groups and sends the update to the
475//adapters
Kent Hagerman2b216042020-04-03 18:28:56 -0400476func (agent *Agent) deleteFlowsAndGroups(ctx context.Context, flowsToDel []*ofp.OfpFlowStats, groupsToDel []*ofp.OfpGroupEntry, flowMetadata *voltha.FlowMetadata) error {
Mahir Gunyel03de0d32020-06-03 01:36:59 -0700477 var flwResponse, grpResponse coreutils.Response
478 var err error
479 if flwResponse, err = agent.deleteFlowsFromAdapter(ctx, flowsToDel, flowMetadata); err != nil {
A R Karthick5c28f552019-12-11 22:47:44 -0800480 return err
481 }
Mahir Gunyel03de0d32020-06-03 01:36:59 -0700482 if grpResponse, err = agent.deleteGroupsFromAdapter(ctx, groupsToDel, flowMetadata); err != nil {
483 return err
484 }
485
khenaidood948f772021-08-11 17:49:24 -0400486 if res := coreutils.WaitForNilOrErrorResponses(agent.rpcTimeout, flwResponse, grpResponse); res != nil {
khenaidoo0458db62019-06-20 08:50:36 -0400487 return status.Errorf(codes.Aborted, "errors-%s", res)
488 }
489 return nil
khenaidoo0458db62019-06-20 08:50:36 -0400490}
491
A R Karthick5c28f552019-12-11 22:47:44 -0800492//updateFlowsAndGroups replaces the existing flows and groups with "updatedFlows" and "updatedGroups" respectively. It
493//also sends the updates to the adapters
Kent Hagerman2b216042020-04-03 18:28:56 -0400494func (agent *Agent) updateFlowsAndGroups(ctx context.Context, updatedFlows []*ofp.OfpFlowStats, updatedGroups []*ofp.OfpGroupEntry, flowMetadata *voltha.FlowMetadata) error {
Mahir Gunyel03de0d32020-06-03 01:36:59 -0700495 var flwResponse, grpResponse coreutils.Response
496 var err error
497 if flwResponse, err = agent.updateFlowsToAdapter(ctx, updatedFlows, flowMetadata); err != nil {
A R Karthick5c28f552019-12-11 22:47:44 -0800498 return err
499 }
Mahir Gunyel03de0d32020-06-03 01:36:59 -0700500 if grpResponse, err = agent.updateGroupsToAdapter(ctx, updatedGroups, flowMetadata); err != nil {
501 return err
502 }
503
khenaidood948f772021-08-11 17:49:24 -0400504 if res := coreutils.WaitForNilOrErrorResponses(agent.rpcTimeout, flwResponse, grpResponse); res != nil {
khenaidoo0458db62019-06-20 08:50:36 -0400505 return status.Errorf(codes.Aborted, "errors-%s", res)
506 }
507 return nil
khenaidoo19d7b632018-10-30 10:49:50 -0400508}
509
khenaidoo4d4802d2018-10-04 21:59:49 -0400510//disableDevice disable a device
Kent Hagerman2b216042020-04-03 18:28:56 -0400511func (agent *Agent) disableDevice(ctx context.Context) error {
khenaidood948f772021-08-11 17:49:24 -0400512 var err error
Maninder9a1bc0d2020-10-26 11:34:02 +0530513 var desc string
khenaidood948f772021-08-11 17:49:24 -0400514 var prevAdminState, currAdminState common.AdminState_Types
515 requestStatus := &common.OperationResp{Code: common.OperationResp_OPERATION_FAILURE}
516 defer func() { agent.logDeviceUpdate(ctx, &prevAdminState, &currAdminState, requestStatus, err, desc) }()
Maninder9a1bc0d2020-10-26 11:34:02 +0530517
khenaidood948f772021-08-11 17:49:24 -0400518 if err = agent.requestQueue.WaitForGreenLight(ctx); err != nil {
khenaidoo442e7c72020-03-10 16:13:48 -0400519 return err
520 }
Himani Chawlab4c25912020-11-12 17:16:38 +0530521 logger.Debugw(ctx, "disable-device", log.Fields{"device-id": agent.deviceID})
khenaidoo6e55d9e2019-12-12 18:26:26 -0500522
Kent Hagermanf6db9f12020-07-22 17:16:19 -0400523 cloned := agent.cloneDeviceWithoutLock()
khenaidood948f772021-08-11 17:49:24 -0400524 prevAdminState = agent.device.AdminState
khenaidoo6e55d9e2019-12-12 18:26:26 -0500525
Maninder2195ccc2021-06-23 20:23:01 +0530526 if !agent.proceedWithRequest(cloned) {
khenaidood948f772021-08-11 17:49:24 -0400527 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 +0530528 agent.requestQueue.RequestComplete()
khenaidood948f772021-08-11 17:49:24 -0400529 return err
Maninder2195ccc2021-06-23 20:23:01 +0530530 }
531
khenaidoo6e55d9e2019-12-12 18:26:26 -0500532 if cloned.AdminState == voltha.AdminState_DISABLED {
Maninder9a1bc0d2020-10-26 11:34:02 +0530533 desc = "device-already-disabled"
Kent Hagermanf6db9f12020-07-22 17:16:19 -0400534 agent.requestQueue.RequestComplete()
npujar1d86a522019-11-14 17:11:16 +0530535 return nil
536 }
Himani Chawla2ba1c9c2020-10-07 13:19:03 +0530537 if cloned.AdminState == voltha.AdminState_PREPROVISIONED {
Kent Hagermanf6db9f12020-07-22 17:16:19 -0400538 agent.requestQueue.RequestComplete()
khenaidood948f772021-08-11 17:49:24 -0400539 err = status.Errorf(codes.FailedPrecondition, "deviceId:%s, invalid-admin-state:%s", agent.deviceID, cloned.AdminState)
540 return err
npujar1d86a522019-11-14 17:11:16 +0530541 }
Maninder0aabf0c2021-03-17 14:55:14 +0530542
npujar1d86a522019-11-14 17:11:16 +0530543 // Update the Admin State and operational state before sending the request out
Kent Hagermanf6db9f12020-07-22 17:16:19 -0400544 cloned.AdminState = voltha.AdminState_DISABLED
545 cloned.OperStatus = voltha.OperStatus_UNKNOWN
Maninder9a1bc0d2020-10-26 11:34:02 +0530546
khenaidood948f772021-08-11 17:49:24 -0400547 client, err := agent.adapterMgr.GetAdapterClient(ctx, agent.adapterEndpoint)
khenaidoo442e7c72020-03-10 16:13:48 -0400548 if err != nil {
khenaidood948f772021-08-11 17:49:24 -0400549 logger.Errorw(ctx, "grpc-client-nil",
550 log.Fields{
551 "error": err,
552 "device-id": agent.deviceID,
553 "device-type": agent.deviceType,
554 "adapter-endpoint": cloned.AdapterEndpoint,
555 })
556 agent.requestQueue.RequestComplete()
npujar1d86a522019-11-14 17:11:16 +0530557 return err
khenaidoo0a822f92019-05-08 15:15:57 -0400558 }
khenaidood948f772021-08-11 17:49:24 -0400559 subCtx, cancel := context.WithTimeout(coreutils.WithAllMetadataFromContext(ctx), agent.rpcTimeout)
560 requestStatus.Code = common.OperationResp_OPERATION_IN_PROGRESS
561 go func() {
562 defer cancel()
563 _, err := client.DisableDevice(subCtx, cloned)
564 if err == nil {
565 agent.onSuccess(subCtx, nil, nil, true)
566 } else {
567 agent.onFailure(subCtx, err, nil, nil, true)
568 }
569 }()
Maninder9a1bc0d2020-10-26 11:34:02 +0530570
khenaidood948f772021-08-11 17:49:24 -0400571 // Update device
572 if err = agent.updateDeviceAndReleaseLock(ctx, cloned); err != nil {
573 return err
574 }
575 currAdminState = cloned.AdminState
khenaidoo0a822f92019-05-08 15:15:57 -0400576
khenaidoo92e62c52018-10-03 14:02:54 -0400577 return nil
578}
579
Kent Hagerman2b216042020-04-03 18:28:56 -0400580func (agent *Agent) rebootDevice(ctx context.Context) error {
Maninder9a1bc0d2020-10-26 11:34:02 +0530581 var desc string
khenaidood948f772021-08-11 17:49:24 -0400582 var err error
583 requestStatus := &common.OperationResp{Code: common.OperationResp_OPERATION_FAILURE}
584 defer func() { agent.logDeviceUpdate(ctx, nil, nil, requestStatus, err, desc) }()
Maninder9a1bc0d2020-10-26 11:34:02 +0530585
khenaidood948f772021-08-11 17:49:24 -0400586 if err = agent.requestQueue.WaitForGreenLight(ctx); err != nil {
Maninder9a1bc0d2020-10-26 11:34:02 +0530587 desc = err.Error()
npujar1d86a522019-11-14 17:11:16 +0530588 return err
khenaidoo4d4802d2018-10-04 21:59:49 -0400589 }
khenaidoo442e7c72020-03-10 16:13:48 -0400590 defer agent.requestQueue.RequestComplete()
Himani Chawlab4c25912020-11-12 17:16:38 +0530591 logger.Debugw(ctx, "reboot-device", log.Fields{"device-id": agent.deviceID})
khenaidoo442e7c72020-03-10 16:13:48 -0400592
Kent Hagermancba2f302020-07-28 13:37:36 -0400593 device := agent.getDeviceReadOnlyWithoutLock()
Maninder2195ccc2021-06-23 20:23:01 +0530594
595 if !agent.proceedWithRequest(device) {
khenaidood948f772021-08-11 17:49:24 -0400596 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 -0400597 return err
598 }
Maninder9a1bc0d2020-10-26 11:34:02 +0530599
khenaidood948f772021-08-11 17:49:24 -0400600 client, err := agent.adapterMgr.GetAdapterClient(ctx, agent.adapterEndpoint)
601 if err != nil {
602 logger.Errorw(ctx, "grpc-client-nil",
603 log.Fields{
604 "error": err,
605 "device-id": agent.deviceID,
606 "device-type": agent.deviceType,
607 "adapter-endpoint": device.AdapterEndpoint,
608 })
609 return err
610 }
611 subCtx, cancel := context.WithTimeout(coreutils.WithAllMetadataFromContext(ctx), agent.rpcTimeout)
612 requestStatus.Code = common.OperationResp_OPERATION_IN_PROGRESS
613 go func() {
614 defer cancel()
615 _, err := client.RebootDevice(subCtx, device)
616 if err == nil {
617 agent.onSuccess(subCtx, nil, nil, true)
618 } else {
619 agent.onFailure(subCtx, err, nil, nil, true)
620 }
621 }()
khenaidoo4d4802d2018-10-04 21:59:49 -0400622 return nil
623}
624
Himani Chawla2ba1c9c2020-10-07 13:19:03 +0530625func (agent *Agent) deleteDeviceForce(ctx context.Context) error {
Himani Chawlab4c25912020-11-12 17:16:38 +0530626 logger.Debugw(ctx, "delete-device-force", log.Fields{"device-id": agent.deviceID})
Maninder9a1bc0d2020-10-26 11:34:02 +0530627
628 var desc string
khenaidood948f772021-08-11 17:49:24 -0400629 var err error
630 requestStatus := &common.OperationResp{Code: common.OperationResp_OPERATION_FAILURE}
631 defer func() { agent.logDeviceUpdate(ctx, nil, nil, requestStatus, err, desc) }()
Maninder9a1bc0d2020-10-26 11:34:02 +0530632
khenaidood948f772021-08-11 17:49:24 -0400633 if err = agent.requestQueue.WaitForGreenLight(ctx); err != nil {
Himani Chawla2ba1c9c2020-10-07 13:19:03 +0530634 return err
635 }
636 // Get the device Transient state, return err if it is DELETING
637 previousDeviceTransientState := agent.getTransientState()
Himani Chawla2ba1c9c2020-10-07 13:19:03 +0530638 device := agent.cloneDeviceWithoutLock()
khenaidood948f772021-08-11 17:49:24 -0400639 if !agent.isForceDeletingAllowed(previousDeviceTransientState, device) {
640 agent.requestQueue.RequestComplete()
641 err = status.Error(codes.FailedPrecondition, fmt.Sprintf("deviceId:%s, force deletion is in progress", agent.deviceID))
Himani Chawla2ba1c9c2020-10-07 13:19:03 +0530642 return err
643 }
Himani Chawlab4c25912020-11-12 17:16:38 +0530644
khenaidood948f772021-08-11 17:49:24 -0400645 previousAdminState := device.AdminState
646 if previousAdminState != common.AdminState_PREPROVISIONED {
647 var client adapter_services.AdapterServiceClient
648 client, err = agent.adapterMgr.GetAdapterClient(ctx, agent.adapterEndpoint)
Himani Chawla2ba1c9c2020-10-07 13:19:03 +0530649 if err != nil {
khenaidood948f772021-08-11 17:49:24 -0400650 logger.Errorw(ctx, "grpc-client-nil",
651 log.Fields{
652 "error": err,
653 "device-id": agent.deviceID,
654 "device-type": agent.deviceType,
655 "adapter-endpoint": device.AdapterEndpoint,
656 })
657 agent.requestQueue.RequestComplete()
Himani Chawla2ba1c9c2020-10-07 13:19:03 +0530658 return err
659 }
khenaidood948f772021-08-11 17:49:24 -0400660 subCtx, cancel := context.WithTimeout(coreutils.WithAllMetadataFromContext(ctx), agent.rpcTimeout)
661 requestStatus.Code = common.OperationResp_OPERATION_IN_PROGRESS
662 go func() {
663 defer cancel()
664 _, err := client.DeleteDevice(subCtx, device)
665 if err == nil {
666 agent.onSuccess(subCtx, nil, nil, true)
667 } else {
668 agent.onFailure(subCtx, err, nil, nil, true)
669 }
670 }()
671 }
672
673 // Update device
674 if err = agent.updateDeviceWithTransientStateAndReleaseLock(ctx, device,
675 core.DeviceTransientState_FORCE_DELETING, previousDeviceTransientState); err != nil {
676 return err
Himani Chawla2ba1c9c2020-10-07 13:19:03 +0530677 }
678 return nil
679}
680
Kent Hagerman2b216042020-04-03 18:28:56 -0400681func (agent *Agent) deleteDevice(ctx context.Context) error {
Himani Chawlab4c25912020-11-12 17:16:38 +0530682 logger.Debugw(ctx, "delete-device", log.Fields{"device-id": agent.deviceID})
Maninder9a1bc0d2020-10-26 11:34:02 +0530683
684 var desc string
khenaidood948f772021-08-11 17:49:24 -0400685 var err error
686 requestStatus := &common.OperationResp{Code: common.OperationResp_OPERATION_FAILURE}
687 defer func() { agent.logDeviceUpdate(ctx, nil, nil, requestStatus, err, desc) }()
Maninder9a1bc0d2020-10-26 11:34:02 +0530688
khenaidood948f772021-08-11 17:49:24 -0400689 if err = agent.requestQueue.WaitForGreenLight(ctx); err != nil {
Maninder9a1bc0d2020-10-26 11:34:02 +0530690 desc = err.Error()
khenaidoo442e7c72020-03-10 16:13:48 -0400691 return err
692 }
Maninder0aabf0c2021-03-17 14:55:14 +0530693
Maninder2195ccc2021-06-23 20:23:01 +0530694 device := agent.cloneDeviceWithoutLock()
695
696 if !agent.proceedWithRequest(device) {
Maninder0aabf0c2021-03-17 14:55:14 +0530697 agent.requestQueue.RequestComplete()
khenaidood948f772021-08-11 17:49:24 -0400698 err = status.Errorf(codes.FailedPrecondition, "cannot complete operation as device deletion is in progress or reconciling is in progress/failed: %s", agent.deviceID)
699 return err
Maninder0aabf0c2021-03-17 14:55:14 +0530700 }
701
Himani Chawla2ba1c9c2020-10-07 13:19:03 +0530702 // Get the device Transient state, return err if it is DELETING
703 previousDeviceTransientState := agent.getTransientState()
khenaidoo6e55d9e2019-12-12 18:26:26 -0500704
Himani Chawla2ba1c9c2020-10-07 13:19:03 +0530705 previousAdminState := device.AdminState
706 // Change the device transient state to DELETING_FROM_ADAPTER state till the device is removed from adapters.
khenaidood948f772021-08-11 17:49:24 -0400707 currentDeviceTransientState := core.DeviceTransientState_DELETING_FROM_ADAPTER
khenaidoo442e7c72020-03-10 16:13:48 -0400708
khenaidood948f772021-08-11 17:49:24 -0400709 if previousAdminState == common.AdminState_PREPROVISIONED {
Himani Chawla2ba1c9c2020-10-07 13:19:03 +0530710 // Change the state to DELETING POST ADAPTER RESPONSE directly as adapters have no info of the device.
khenaidood948f772021-08-11 17:49:24 -0400711 currentDeviceTransientState = core.DeviceTransientState_DELETING_POST_ADAPTER_RESPONSE
Himani Chawla2ba1c9c2020-10-07 13:19:03 +0530712 }
khenaidood948f772021-08-11 17:49:24 -0400713 // If the device was in pre-prov state (only parent device are in that state) then do not send the request to the
714 // adapter
715 if previousAdminState != common.AdminState_PREPROVISIONED {
716 var client adapter_services.AdapterServiceClient
717 client, err = agent.adapterMgr.GetAdapterClient(ctx, agent.adapterEndpoint)
718 if err != nil {
719 logger.Errorw(ctx, "grpc-client-nil",
720 log.Fields{
721 "error": err,
722 "device-id": agent.deviceID,
723 "device-type": agent.deviceType,
724 "adapter-endpoint": device.AdapterEndpoint,
725 })
726 agent.requestQueue.RequestComplete()
727 return err
728 }
729 subCtx, cancel := context.WithTimeout(coreutils.WithAllMetadataFromContext(ctx), agent.rpcTimeout)
730 requestStatus.Code = common.OperationResp_OPERATION_IN_PROGRESS
731 go func() {
732 defer cancel()
733 _, err := client.DeleteDevice(subCtx, device)
734 if err == nil {
735 agent.onDeleteSuccess(subCtx, nil, nil)
736 } else {
737 agent.onDeleteFailure(subCtx, err, nil, nil)
738 }
739 }()
740 }
741
742 // Update device and release lock
743 if err = agent.updateDeviceWithTransientStateAndReleaseLock(ctx, device,
Himani Chawlab4c25912020-11-12 17:16:38 +0530744 currentDeviceTransientState, previousDeviceTransientState); err != nil {
Maninder9a1bc0d2020-10-26 11:34:02 +0530745 desc = err.Error()
npujar1d86a522019-11-14 17:11:16 +0530746 return err
747 }
Himani Chawlab4c25912020-11-12 17:16:38 +0530748
khenaidoo4d4802d2018-10-04 21:59:49 -0400749 return nil
750}
751
Kent Hagerman2b216042020-04-03 18:28:56 -0400752func (agent *Agent) setParentID(ctx context.Context, device *voltha.Device, parentID string) error {
khenaidoo442e7c72020-03-10 16:13:48 -0400753 if err := agent.requestQueue.WaitForGreenLight(ctx); err != nil {
754 return err
755 }
Himani Chawlab4c25912020-11-12 17:16:38 +0530756 logger.Debugw(ctx, "set-parent-id", log.Fields{"device-id": device.Id, "parent-id": parentID})
khenaidoo6e55d9e2019-12-12 18:26:26 -0500757
Kent Hagermanf6db9f12020-07-22 17:16:19 -0400758 cloned := agent.cloneDeviceWithoutLock()
npujar1d86a522019-11-14 17:11:16 +0530759 cloned.ParentId = parentID
Kent Hagermanf6db9f12020-07-22 17:16:19 -0400760 return agent.updateDeviceAndReleaseLock(ctx, cloned)
khenaidooad06fd72019-10-28 12:26:05 -0400761}
762
khenaidoo442e7c72020-03-10 16:13:48 -0400763// getSwitchCapability retrieves the switch capability of a parent device
Kent Hagerman2b216042020-04-03 18:28:56 -0400764func (agent *Agent) getSwitchCapability(ctx context.Context) (*ic.SwitchCapability, error) {
Himani Chawlab4c25912020-11-12 17:16:38 +0530765 logger.Debugw(ctx, "get-switch-capability", log.Fields{"device-id": agent.deviceID})
khenaidoo442e7c72020-03-10 16:13:48 -0400766
Kent Hagermancba2f302020-07-28 13:37:36 -0400767 device, err := agent.getDeviceReadOnly(ctx)
khenaidoo442e7c72020-03-10 16:13:48 -0400768 if err != nil {
khenaidoob9203542018-09-17 22:56:37 -0400769 return nil, err
khenaidoob9203542018-09-17 22:56:37 -0400770 }
khenaidood948f772021-08-11 17:49:24 -0400771
772 // Get the gRPC client
773 client, err := agent.adapterMgr.GetAdapterClient(ctx, agent.adapterEndpoint)
khenaidoo442e7c72020-03-10 16:13:48 -0400774 if err != nil {
775 return nil, err
776 }
777
khenaidood948f772021-08-11 17:49:24 -0400778 return client.GetOfpDeviceInfo(ctx, device)
khenaidoob9203542018-09-17 22:56:37 -0400779}
780
khenaidood948f772021-08-11 17:49:24 -0400781func (agent *Agent) onPacketFailure(ctx context.Context, err error, packet *ofp.OfpPacketOut) {
782 logger.Errorw(ctx, "packet-out-error", log.Fields{
khenaidoo442e7c72020-03-10 16:13:48 -0400783 "device-id": agent.deviceID,
khenaidood948f772021-08-11 17:49:24 -0400784 "error": err.Error(),
785 "packet": hex.EncodeToString(packet.Data),
khenaidoo442e7c72020-03-10 16:13:48 -0400786 })
khenaidood948f772021-08-11 17:49:24 -0400787 rpce := agent.deviceMgr.NewRPCEvent(ctx, agent.deviceID, err.Error(), nil)
788 go agent.deviceMgr.SendRPCEvent(ctx, "RPC_ERROR_RAISE_EVENT", rpce,
789 voltha.EventCategory_COMMUNICATION, nil, time.Now().Unix())
khenaidoo442e7c72020-03-10 16:13:48 -0400790}
791
Kent Hagerman2b216042020-04-03 18:28:56 -0400792func (agent *Agent) packetOut(ctx context.Context, outPort uint32, packet *ofp.OfpPacketOut) error {
Scott Baker80678602019-11-14 16:57:36 -0800793 if agent.deviceType == "" {
npujar467fe752020-01-16 20:17:45 +0530794 agent.reconcileWithKVStore(ctx)
Scott Baker80678602019-11-14 16:57:36 -0800795 }
khenaidoofdbad6e2018-11-06 22:26:38 -0500796 // Send packet to adapter
khenaidood948f772021-08-11 17:49:24 -0400797 client, err := agent.adapterMgr.GetAdapterClient(ctx, agent.adapterEndpoint)
khenaidoo442e7c72020-03-10 16:13:48 -0400798 if err != nil {
khenaidood948f772021-08-11 17:49:24 -0400799 logger.Errorw(ctx, "grpc-client-nil",
800 log.Fields{
801 "error": err,
802 "device-id": agent.deviceID,
803 "device-type": agent.deviceType,
804 })
805 return err
khenaidoofdbad6e2018-11-06 22:26:38 -0500806 }
khenaidood948f772021-08-11 17:49:24 -0400807 subCtx, cancel := context.WithTimeout(coreutils.WithAllMetadataFromContext(ctx), agent.rpcTimeout)
808 go func() {
809 defer cancel()
810 _, err := client.SendPacketOut(subCtx, &ic.PacketOut{
811 DeviceId: agent.deviceID,
812 EgressPortNo: outPort,
813 Packet: packet,
814 })
815 if err == nil {
816 agent.onSuccess(subCtx, nil, nil, false)
817 } else {
818 agent.onPacketFailure(subCtx, err, packet)
819 }
820 }()
khenaidoofdbad6e2018-11-06 22:26:38 -0500821 return nil
822}
823
Kent Hagermanf6db9f12020-07-22 17:16:19 -0400824func (agent *Agent) updateDeviceUsingAdapterData(ctx context.Context, device *voltha.Device) error {
khenaidood948f772021-08-11 17:49:24 -0400825 var err error
826 var desc string
827 requestStatus := &common.OperationResp{Code: common.OperationResp_OPERATION_FAILURE}
828 defer func() { agent.logDeviceUpdate(ctx, nil, nil, requestStatus, err, desc) }()
829
830 if err = agent.requestQueue.WaitForGreenLight(ctx); err != nil {
Kent Hagermanf6db9f12020-07-22 17:16:19 -0400831 return err
832 }
Himani Chawlab4c25912020-11-12 17:16:38 +0530833 logger.Debugw(ctx, "update-device-using-adapter-data", log.Fields{"device-id": device.Id})
Kent Hagermanf6db9f12020-07-22 17:16:19 -0400834
835 cloned := agent.cloneDeviceWithoutLock()
Mahir Gunyel8e2707d2019-07-25 00:36:21 -0700836 cloned.Root = device.Root
837 cloned.Vendor = device.Vendor
838 cloned.Model = device.Model
839 cloned.SerialNumber = device.SerialNumber
840 cloned.MacAddress = device.MacAddress
841 cloned.Vlan = device.Vlan
842 cloned.Reason = device.Reason
Andrea Campanella025667e2021-01-14 11:50:07 +0100843 cloned.ImageDownloads = device.ImageDownloads
khenaidood948f772021-08-11 17:49:24 -0400844 cloned.OperStatus = device.OperStatus
845 cloned.ConnectStatus = device.ConnectStatus
846 if err = agent.updateDeviceAndReleaseLock(ctx, cloned); err == nil {
847 requestStatus.Code = common.OperationResp_OPERATION_SUCCESS
848 }
849 return err
khenaidoo43c82122018-11-22 18:38:28 -0500850}
851
Kent Hagerman2b216042020-04-03 18:28:56 -0400852func (agent *Agent) updateDeviceStatus(ctx context.Context, operStatus voltha.OperStatus_Types, connStatus voltha.ConnectStatus_Types) error {
khenaidood948f772021-08-11 17:49:24 -0400853 var err error
854 var desc string
855 opStatus := &common.OperationResp{Code: common.OperationResp_OPERATION_FAILURE}
856 defer func() { agent.logDeviceUpdate(ctx, nil, nil, opStatus, err, desc) }()
857
858 if err = agent.requestQueue.WaitForGreenLight(ctx); err != nil {
khenaidoo442e7c72020-03-10 16:13:48 -0400859 return err
860 }
khenaidoo6e55d9e2019-12-12 18:26:26 -0500861
Kent Hagermanf6db9f12020-07-22 17:16:19 -0400862 cloned := agent.cloneDeviceWithoutLock()
npujar1d86a522019-11-14 17:11:16 +0530863 // 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 -0400864 if s, ok := voltha.ConnectStatus_Types_name[int32(connStatus)]; ok {
khenaidood948f772021-08-11 17:49:24 -0400865 logger.Debugw(ctx, "update-device-conn-status", log.Fields{"ok": ok, "val": s})
Kent Hagermanf6db9f12020-07-22 17:16:19 -0400866 cloned.ConnectStatus = connStatus
npujar1d86a522019-11-14 17:11:16 +0530867 }
Kent Hagermanf6db9f12020-07-22 17:16:19 -0400868 if s, ok := voltha.OperStatus_Types_name[int32(operStatus)]; ok {
khenaidood948f772021-08-11 17:49:24 -0400869 logger.Debugw(ctx, "update-device-oper-status", log.Fields{"ok": ok, "val": s})
Kent Hagermanf6db9f12020-07-22 17:16:19 -0400870 cloned.OperStatus = operStatus
npujar1d86a522019-11-14 17:11:16 +0530871 }
Himani Chawlab4c25912020-11-12 17:16:38 +0530872 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 +0530873 // Store the device
khenaidood948f772021-08-11 17:49:24 -0400874 if err = agent.updateDeviceAndReleaseLock(ctx, cloned); err == nil {
875 opStatus.Code = common.OperationResp_OPERATION_SUCCESS
876 }
877 return err
khenaidoo92e62c52018-10-03 14:02:54 -0400878}
879
khenaidoob9203542018-09-17 22:56:37 -0400880// TODO: A generic device update by attribute
Kent Hagerman2b216042020-04-03 18:28:56 -0400881func (agent *Agent) updateDeviceAttribute(ctx context.Context, name string, value interface{}) {
khenaidoob9203542018-09-17 22:56:37 -0400882 if value == nil {
883 return
884 }
khenaidoo6e55d9e2019-12-12 18:26:26 -0500885
Kent Hagermanf6db9f12020-07-22 17:16:19 -0400886 if err := agent.requestQueue.WaitForGreenLight(ctx); err != nil {
887 logger.Warnw(ctx, "request-aborted", log.Fields{"device-id": agent.deviceID, "name": name, "error": err})
888 return
889 }
890
891 cloned := agent.cloneDeviceWithoutLock()
khenaidoob9203542018-09-17 22:56:37 -0400892 updated := false
khenaidoo6e55d9e2019-12-12 18:26:26 -0500893 s := reflect.ValueOf(cloned).Elem()
khenaidoob9203542018-09-17 22:56:37 -0400894 if s.Kind() == reflect.Struct {
895 // exported field
896 f := s.FieldByName(name)
897 if f.IsValid() && f.CanSet() {
898 switch f.Kind() {
899 case reflect.String:
900 f.SetString(value.(string))
901 updated = true
902 case reflect.Uint32:
903 f.SetUint(uint64(value.(uint32)))
904 updated = true
905 case reflect.Bool:
906 f.SetBool(value.(bool))
907 updated = true
908 }
909 }
910 }
divyadesaicb8b59d2020-08-18 09:55:47 +0000911 logger.Debugw(ctx, "update-field-status", log.Fields{"device-id": cloned.Id, "name": name, "updated": updated})
khenaidoob9203542018-09-17 22:56:37 -0400912 // Save the data
khenaidoo6e55d9e2019-12-12 18:26:26 -0500913
Kent Hagermanf6db9f12020-07-22 17:16:19 -0400914 if err := agent.updateDeviceAndReleaseLock(ctx, cloned); err != nil {
Rohan Agrawal31f21802020-06-12 05:38:46 +0000915 logger.Warnw(ctx, "attribute-update-failed", log.Fields{"attribute": name, "value": value})
khenaidoob9203542018-09-17 22:56:37 -0400916 }
khenaidoob9203542018-09-17 22:56:37 -0400917}
serkant.uluderya334479d2019-04-10 08:26:15 -0700918
Kent Hagerman45a13e42020-04-13 12:23:50 -0400919func (agent *Agent) simulateAlarm(ctx context.Context, simulateReq *voltha.SimulateAlarmRequest) error {
khenaidood948f772021-08-11 17:49:24 -0400920 var err error
921 var desc string
922 requestStatus := &common.OperationResp{Code: common.OperationResp_OPERATION_FAILURE}
923 defer func() { agent.logDeviceUpdate(ctx, nil, nil, requestStatus, err, desc) }()
924
925 if err = agent.requestQueue.WaitForGreenLight(ctx); err != nil {
khenaidoo442e7c72020-03-10 16:13:48 -0400926 return err
927 }
928 defer agent.requestQueue.RequestComplete()
Himani Chawlab4c25912020-11-12 17:16:38 +0530929 logger.Debugw(ctx, "simulate-alarm", log.Fields{"device-id": agent.deviceID})
khenaidoo6e55d9e2019-12-12 18:26:26 -0500930
Kent Hagermancba2f302020-07-28 13:37:36 -0400931 device := agent.getDeviceReadOnlyWithoutLock()
khenaidoo6e55d9e2019-12-12 18:26:26 -0500932
khenaidood948f772021-08-11 17:49:24 -0400933 client, err := agent.adapterMgr.GetAdapterClient(ctx, agent.adapterEndpoint)
khenaidoo442e7c72020-03-10 16:13:48 -0400934 if err != nil {
khenaidood948f772021-08-11 17:49:24 -0400935 logger.Errorw(ctx, "grpc-client-nil",
936 log.Fields{
937 "error": err,
938 "device-id": agent.deviceID,
939 "device-type": agent.deviceType,
940 "adapter-endpoint": device.AdapterEndpoint,
941 })
npujar1d86a522019-11-14 17:11:16 +0530942 return err
serkant.uluderya334479d2019-04-10 08:26:15 -0700943 }
khenaidood948f772021-08-11 17:49:24 -0400944 subCtx, cancel := context.WithTimeout(coreutils.WithAllMetadataFromContext(ctx), agent.rpcTimeout)
945 requestStatus.Code = common.OperationResp_OPERATION_IN_PROGRESS
946 go func() {
947 defer cancel()
948 _, err := client.SimulateAlarm(subCtx, &ic.SimulateAlarmMessage{Device: device, Request: simulateReq})
949 if err == nil {
950 agent.onSuccess(subCtx, nil, nil, false)
951 } else {
952 agent.onFailure(subCtx, err, nil, nil, false)
953 }
954 }()
serkant.uluderya334479d2019-04-10 08:26:15 -0700955 return nil
956}
Mahir Gunyelb5851672019-07-24 10:46:26 +0300957
Kent Hagermanf6db9f12020-07-22 17:16:19 -0400958// This function updates the device in the DB, releases the device lock, and runs any state transitions.
959// The calling function MUST hold the device lock. The caller MUST NOT modify the device after this is called.
960func (agent *Agent) updateDeviceAndReleaseLock(ctx context.Context, device *voltha.Device) error {
961 // fail early if this agent is no longer valid
Kent Hagerman4f355f52020-03-30 16:01:33 -0400962 if agent.stopped {
Kent Hagermanf6db9f12020-07-22 17:16:19 -0400963 agent.requestQueue.RequestComplete()
Himani Chawla2ba1c9c2020-10-07 13:19:03 +0530964 return errors.New("device-agent-stopped")
Thomas Lee Se5a44012019-11-07 20:32:24 +0530965 }
Kent Hagerman4f355f52020-03-30 16:01:33 -0400966
Kent Hagermanf6db9f12020-07-22 17:16:19 -0400967 // update in db
Kent Hagermanf5a67352020-04-30 15:15:26 -0400968 if err := agent.dbProxy.Set(ctx, agent.deviceID, device); err != nil {
Kent Hagermanf6db9f12020-07-22 17:16:19 -0400969 agent.requestQueue.RequestComplete()
Kent Hagerman4f355f52020-03-30 16:01:33 -0400970 return status.Errorf(codes.Internal, "failed-update-device:%s: %s", agent.deviceID, err)
Mahir Gunyelb5851672019-07-24 10:46:26 +0300971 }
divyadesaicb8b59d2020-08-18 09:55:47 +0000972 logger.Debugw(ctx, "updated-device-in-store", log.Fields{"device-id: ": agent.deviceID})
Mahir Gunyelb5851672019-07-24 10:46:26 +0300973
Kent Hagerman6031aad2020-07-29 16:36:33 -0400974 prevDevice := agent.device
Kent Hagermanf6db9f12020-07-22 17:16:19 -0400975 // update the device
khenaidoo0db4c812020-05-27 15:27:30 -0400976 agent.device = device
Mahir Gunyelb0343bf2021-05-11 14:14:26 -0700977 //If any of the states has chenged, send the change event.
978 if prevDevice.OperStatus != device.OperStatus || prevDevice.ConnectStatus != device.ConnectStatus || prevDevice.AdminState != device.AdminState {
979 _ = agent.deviceMgr.Agent.SendDeviceStateChangeEvent(ctx, prevDevice.OperStatus, prevDevice.ConnectStatus, prevDevice.AdminState, device, time.Now().Unix())
980 }
Maninder0aabf0c2021-03-17 14:55:14 +0530981 deviceTransientState := agent.getTransientState()
982
Kent Hagermanf6db9f12020-07-22 17:16:19 -0400983 // release lock before processing transition
984 agent.requestQueue.RequestComplete()
Himani Chawlab4c25912020-11-12 17:16:38 +0530985 subCtx := coreutils.WithSpanAndRPCMetadataFromContext(ctx)
Kent Hagermanf6db9f12020-07-22 17:16:19 -0400986
Himani Chawlab4c25912020-11-12 17:16:38 +0530987 if err := agent.deviceMgr.stateTransitions.ProcessTransition(subCtx,
Maninder0aabf0c2021-03-17 14:55:14 +0530988 device, prevDevice, deviceTransientState, deviceTransientState); err != nil {
Himani Chawlab4c25912020-11-12 17:16:38 +0530989 logger.Errorw(ctx, "failed-process-transition", log.Fields{"device-id": device.Id, "previous-admin-state": prevDevice.AdminState, "current-admin-state": device.AdminState})
990 // Sending RPC EVENT here
991 rpce := agent.deviceMgr.NewRPCEvent(ctx, agent.deviceID, err.Error(), nil)
Himani Chawla606a4f02021-03-23 19:45:58 +0530992 agent.deviceMgr.SendRPCEvent(ctx, "RPC_ERROR_RAISE_EVENT", rpce, voltha.EventCategory_COMMUNICATION,
993 nil, time.Now().Unix())
Himani Chawlab4c25912020-11-12 17:16:38 +0530994
Kent Hagermanf6db9f12020-07-22 17:16:19 -0400995 }
Mahir Gunyelb5851672019-07-24 10:46:26 +0300996 return nil
997}
Mahir Gunyelfdee9212019-10-16 16:52:21 -0700998
Himani Chawla2ba1c9c2020-10-07 13:19:03 +0530999// This function updates the device transient in the DB through loader, releases the device lock, and runs any state transitions.
1000// The calling function MUST hold the device lock. The caller MUST NOT modify the device after this is called.
1001func (agent *Agent) updateDeviceWithTransientStateAndReleaseLock(ctx context.Context, device *voltha.Device,
khenaidood948f772021-08-11 17:49:24 -04001002 transientState, prevTransientState core.DeviceTransientState_Types) error {
Himani Chawla2ba1c9c2020-10-07 13:19:03 +05301003 // fail early if this agent is no longer valid
1004 if agent.stopped {
1005 agent.requestQueue.RequestComplete()
1006 return errors.New("device-agent-stopped")
1007 }
1008 //update device TransientState
1009 if err := agent.updateTransientState(ctx, transientState); err != nil {
1010 agent.requestQueue.RequestComplete()
1011 return err
1012 }
1013 // update in db
1014 if err := agent.dbProxy.Set(ctx, agent.deviceID, device); err != nil {
1015 //Reverting TransientState update
khenaidood948f772021-08-11 17:49:24 -04001016 if errTransient := agent.updateTransientState(ctx, prevTransientState); errTransient != nil {
1017 logger.Errorw(ctx, "failed-to-revert-transient-state-update-on-error", log.Fields{"device-id": device.Id,
1018 "previous-transient-state": prevTransientState, "current-transient-state": transientState, "error": errTransient})
1019 }
Himani Chawla2ba1c9c2020-10-07 13:19:03 +05301020 agent.requestQueue.RequestComplete()
1021 return status.Errorf(codes.Internal, "failed-update-device:%s: %s", agent.deviceID, err)
1022 }
1023
1024 logger.Debugw(ctx, "updated-device-in-store", log.Fields{"device-id: ": agent.deviceID})
1025
1026 prevDevice := agent.device
1027 // update the device
1028 agent.device = device
Mahir Gunyelb0343bf2021-05-11 14:14:26 -07001029 //If any of the states has chenged, send the change event.
1030 if prevDevice.OperStatus != device.OperStatus || prevDevice.ConnectStatus != device.ConnectStatus || prevDevice.AdminState != device.AdminState {
1031 _ = agent.deviceMgr.Agent.SendDeviceStateChangeEvent(ctx, prevDevice.OperStatus, prevDevice.ConnectStatus, prevDevice.AdminState, device, time.Now().Unix())
1032 }
Himani Chawla2ba1c9c2020-10-07 13:19:03 +05301033
1034 // release lock before processing transition
1035 agent.requestQueue.RequestComplete()
khenaidood948f772021-08-11 17:49:24 -04001036 go func() {
1037 subCtx := coreutils.WithSpanAndRPCMetadataFromContext(ctx)
1038 if err := agent.deviceMgr.stateTransitions.ProcessTransition(subCtx,
1039 device, prevDevice, transientState, prevTransientState); err != nil {
1040 logger.Errorw(ctx, "failed-process-transition", log.Fields{"device-id": device.Id, "previous-admin-state": prevDevice.AdminState, "current-admin-state": device.AdminState})
1041 // Sending RPC EVENT here
1042 rpce := agent.deviceMgr.NewRPCEvent(ctx, agent.deviceID, err.Error(), nil)
1043 agent.deviceMgr.SendRPCEvent(ctx, "RPC_ERROR_RAISE_EVENT", rpce, voltha.EventCategory_COMMUNICATION,
1044 nil, time.Now().Unix())
1045 }
1046 }()
Himani Chawla2ba1c9c2020-10-07 13:19:03 +05301047 return nil
1048}
Kent Hagerman2b216042020-04-03 18:28:56 -04001049func (agent *Agent) updateDeviceReason(ctx context.Context, reason string) error {
khenaidood948f772021-08-11 17:49:24 -04001050 logger.Debugw(ctx, "update-device-reason", log.Fields{"device-id": agent.deviceID, "reason": reason})
1051
1052 var err error
1053 var desc string
1054 requestStatus := &common.OperationResp{Code: common.OperationResp_OPERATION_FAILURE}
1055 defer func() { agent.logDeviceUpdate(ctx, nil, nil, requestStatus, err, desc) }()
1056
1057 if err = agent.requestQueue.WaitForGreenLight(ctx); err != nil {
khenaidoo442e7c72020-03-10 16:13:48 -04001058 return err
1059 }
Maninder9a1bc0d2020-10-26 11:34:02 +05301060
Kent Hagermanf6db9f12020-07-22 17:16:19 -04001061 cloned := agent.cloneDeviceWithoutLock()
npujar1d86a522019-11-14 17:11:16 +05301062 cloned.Reason = reason
khenaidood948f772021-08-11 17:49:24 -04001063 if err = agent.updateDeviceAndReleaseLock(ctx, cloned); err == nil {
1064 requestStatus.Code = common.OperationResp_OPERATION_SUCCESS
Maninder9a1bc0d2020-10-26 11:34:02 +05301065 }
khenaidood948f772021-08-11 17:49:24 -04001066 return err
Mahir Gunyelfdee9212019-10-16 16:52:21 -07001067}
kesavandbc2d1622020-01-21 00:42:01 -05001068
Kent Hagerman2b216042020-04-03 18:28:56 -04001069func (agent *Agent) ChildDeviceLost(ctx context.Context, device *voltha.Device) error {
Himani Chawlab4c25912020-11-12 17:16:38 +05301070 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 -05001071
khenaidood948f772021-08-11 17:49:24 -04001072 var err error
1073 var desc string
1074 requestStatus := &common.OperationResp{Code: common.OperationResp_OPERATION_FAILURE}
1075 defer func() { agent.logDeviceUpdate(ctx, nil, nil, requestStatus, err, desc) }()
1076
Kent Hagerman2a07b862020-06-19 15:23:07 -04001077 // Remove the associated peer ports on the parent device
1078 for portID := range agent.portLoader.ListIDs() {
1079 if portHandle, have := agent.portLoader.Lock(portID); have {
1080 oldPort := portHandle.GetReadOnly()
1081 updatedPeers := make([]*voltha.Port_PeerPort, 0)
1082 for _, peerPort := range oldPort.Peers {
1083 if peerPort.DeviceId != device.Id {
1084 updatedPeers = append(updatedPeers, peerPort)
1085 }
khenaidoo442e7c72020-03-10 16:13:48 -04001086 }
Kent Hagerman2a07b862020-06-19 15:23:07 -04001087 newPort := *oldPort
1088 newPort.Peers = updatedPeers
1089 if err := portHandle.Update(ctx, &newPort); err != nil {
1090 portHandle.Unlock()
1091 return nil
1092 }
1093 portHandle.Unlock()
khenaidoo442e7c72020-03-10 16:13:48 -04001094 }
Chaitrashree G S543df3e2020-02-24 22:36:54 -05001095 }
1096
khenaidoo442e7c72020-03-10 16:13:48 -04001097 //send request to adapter
khenaidood948f772021-08-11 17:49:24 -04001098 client, err := agent.adapterMgr.GetAdapterClient(ctx, agent.adapterEndpoint)
khenaidoo442e7c72020-03-10 16:13:48 -04001099 if err != nil {
khenaidood948f772021-08-11 17:49:24 -04001100 logger.Errorw(ctx, "grpc-client-nil",
1101 log.Fields{
1102 "error": err,
1103 "device-id": agent.deviceID,
1104 "device-type": agent.deviceType,
1105 "adapter-endpoint": device.AdapterEndpoint,
1106 })
khenaidoo442e7c72020-03-10 16:13:48 -04001107 return err
Chaitrashree G S543df3e2020-02-24 22:36:54 -05001108 }
khenaidood948f772021-08-11 17:49:24 -04001109 subCtx, cancel := context.WithTimeout(coreutils.WithAllMetadataFromContext(ctx), agent.rpcTimeout)
1110 requestStatus.Code = common.OperationResp_OPERATION_IN_PROGRESS
1111 go func() {
1112 defer cancel()
1113 _, err := client.ChildDeviceLost(subCtx, device)
1114 if err == nil {
1115 agent.onSuccess(subCtx, nil, nil, true)
1116 } else {
1117 agent.onFailure(subCtx, err, nil, nil, true)
1118 }
1119 }()
Chaitrashree G S543df3e2020-02-24 22:36:54 -05001120 return nil
Chaitrashree G S543df3e2020-02-24 22:36:54 -05001121}
onkarkundargi87285252020-01-27 11:34:52 +05301122
Kent Hagerman2b216042020-04-03 18:28:56 -04001123func (agent *Agent) startOmciTest(ctx context.Context, omcitestrequest *voltha.OmciTestRequest) (*voltha.TestResponse, error) {
khenaidood948f772021-08-11 17:49:24 -04001124 var err error
1125 var desc string
1126 requestStatus := &common.OperationResp{Code: common.OperationResp_OPERATION_FAILURE}
1127 defer func() { agent.logDeviceUpdate(ctx, nil, nil, requestStatus, err, desc) }()
onkarkundargi87285252020-01-27 11:34:52 +05301128
khenaidood948f772021-08-11 17:49:24 -04001129 // OMCI test may be performed on a pre-provisioned device. If a device is in that state both its device type and endpoint
1130 // may not have been set yet.
1131 // First check if we need to update the type or endpoint
1132 cloned, err := agent.getDeviceReadOnly(ctx)
onkarkundargi87285252020-01-27 11:34:52 +05301133 if err != nil {
1134 return nil, err
1135 }
khenaidood948f772021-08-11 17:49:24 -04001136 if cloned.Type == "" || cloned.AdapterEndpoint == "" {
1137 if err = agent.updateDeviceTypeAndEndpoint(ctx); err != nil {
1138 return nil, err
1139 }
1140 cloned, err = agent.getDeviceReadOnly(ctx)
1141 if err != nil {
1142 return nil, err
1143 }
onkarkundargi87285252020-01-27 11:34:52 +05301144 }
1145
khenaidood948f772021-08-11 17:49:24 -04001146 // Send request to the adapter
1147 client, err := agent.adapterMgr.GetAdapterClient(ctx, agent.adapterEndpoint)
1148 if err != nil {
1149 logger.Errorw(ctx, "grpc-client-nil",
1150 log.Fields{
1151 "error": err,
1152 "device-id": agent.deviceID,
1153 "device-type": agent.deviceType,
1154 "adapter-endpoint": cloned.AdapterEndpoint,
1155 })
1156 return nil, err
onkarkundargi87285252020-01-27 11:34:52 +05301157 }
khenaidood948f772021-08-11 17:49:24 -04001158
1159 res, err := client.StartOmciTest(ctx, &ic.OMCITest{
1160 Device: cloned,
1161 Request: omcitestrequest,
1162 })
1163 if err == nil {
1164 requestStatus.Code = common.OperationResp_OPERATION_SUCCESS
1165 }
1166 return res, err
onkarkundargi87285252020-01-27 11:34:52 +05301167}
Dinesh Belwalkarc1129f12020-02-27 10:41:33 -08001168
1169func (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 +05301170 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 -04001171 var err error
1172 var desc string
1173 requestStatus := &common.OperationResp{Code: common.OperationResp_OPERATION_FAILURE}
1174 defer func() { agent.logDeviceUpdate(ctx, nil, nil, requestStatus, err, desc) }()
1175
1176 if err = agent.requestQueue.WaitForGreenLight(ctx); err != nil {
Dinesh Belwalkarc1129f12020-02-27 10:41:33 -08001177 return nil, err
1178 }
1179
khenaidood948f772021-08-11 17:49:24 -04001180 //send request to adapter synchronously
1181 client, err := agent.adapterMgr.GetAdapterClient(ctx, pdevice.AdapterEndpoint)
Dinesh Belwalkarc1129f12020-02-27 10:41:33 -08001182 if err != nil {
khenaidood948f772021-08-11 17:49:24 -04001183 logger.Errorw(ctx, "grpc-client-nil",
1184 log.Fields{
1185 "error": err,
1186 "device-id": agent.deviceID,
1187 "device-type": agent.deviceType,
1188 "adapter-endpoint": pdevice.AdapterEndpoint,
1189 })
1190 agent.requestQueue.RequestComplete()
Dinesh Belwalkarc1129f12020-02-27 10:41:33 -08001191 return nil, err
1192 }
1193
khenaidood948f772021-08-11 17:49:24 -04001194 // Release lock before sending to adapter
1195 agent.requestQueue.RequestComplete()
Dinesh Belwalkarc1129f12020-02-27 10:41:33 -08001196
khenaidood948f772021-08-11 17:49:24 -04001197 retVal, err := client.GetExtValue(ctx, &ic.GetExtValueMessage{
1198 ParentDevice: pdevice,
1199 ChildDevice: cdevice,
1200 ValueType: valueparam.Value,
1201 })
1202 if err == nil {
1203 requestStatus.Code = common.OperationResp_OPERATION_SUCCESS
Dinesh Belwalkarc1129f12020-02-27 10:41:33 -08001204 }
khenaidood948f772021-08-11 17:49:24 -04001205 return retVal, err
Dinesh Belwalkarc1129f12020-02-27 10:41:33 -08001206}
dpaul62686312020-06-23 14:17:36 +05301207
1208func (agent *Agent) setExtValue(ctx context.Context, device *voltha.Device, value *voltha.ValueSet) (*empty.Empty, error) {
Himani Chawlab4c25912020-11-12 17:16:38 +05301209 logger.Debugw(ctx, "set-ext-value", log.Fields{"device-id": value.Id})
khenaidood948f772021-08-11 17:49:24 -04001210
1211 var err error
1212 var desc string
1213 requestStatus := &common.OperationResp{Code: common.OperationResp_OPERATION_FAILURE}
1214 defer func() { agent.logDeviceUpdate(ctx, nil, nil, requestStatus, err, desc) }()
1215
1216 if err = agent.requestQueue.WaitForGreenLight(ctx); err != nil {
dpaul62686312020-06-23 14:17:36 +05301217 return nil, err
1218 }
1219
1220 //send request to adapter
khenaidood948f772021-08-11 17:49:24 -04001221 //send request to adapter synchronously
1222 client, err := agent.adapterMgr.GetAdapterClient(ctx, agent.adapterEndpoint)
dpaul62686312020-06-23 14:17:36 +05301223 if err != nil {
khenaidood948f772021-08-11 17:49:24 -04001224 logger.Errorw(ctx, "grpc-client-nil",
1225 log.Fields{
1226 "error": err,
1227 "device-id": agent.deviceID,
1228 "device-type": agent.deviceType,
1229 "adapter-endpoint": device.AdapterEndpoint,
1230 })
1231 agent.requestQueue.RequestComplete()
dpaul62686312020-06-23 14:17:36 +05301232 return nil, err
1233 }
khenaidood948f772021-08-11 17:49:24 -04001234 // Release lock before sending request to adapter
1235 agent.requestQueue.RequestComplete()
dpaul62686312020-06-23 14:17:36 +05301236
khenaidood948f772021-08-11 17:49:24 -04001237 retVal, err := client.SetExtValue(ctx, &ic.SetExtValueMessage{
1238 Device: device,
1239 Value: value,
1240 })
1241 if err == nil {
1242 requestStatus.Code = common.OperationResp_OPERATION_SUCCESS
dpaul62686312020-06-23 14:17:36 +05301243 }
khenaidood948f772021-08-11 17:49:24 -04001244 return retVal, err
dpaul62686312020-06-23 14:17:36 +05301245}
Salman Siddiqui1cf95042020-11-19 00:42:56 +05301246
1247func (agent *Agent) getSingleValue(ctx context.Context, request *extension.SingleGetValueRequest) (*extension.SingleGetValueResponse, error) {
Himani Chawlab4c25912020-11-12 17:16:38 +05301248 logger.Debugw(ctx, "get-single-value", log.Fields{"device-id": request.TargetId})
Salman Siddiqui1cf95042020-11-19 00:42:56 +05301249
khenaidood948f772021-08-11 17:49:24 -04001250 var err error
1251 var desc string
1252 requestStatus := &common.OperationResp{Code: common.OperationResp_OPERATION_FAILURE}
1253 defer func() { agent.logDeviceUpdate(ctx, nil, nil, requestStatus, err, desc) }()
1254
1255 if err = agent.requestQueue.WaitForGreenLight(ctx); err != nil {
Salman Siddiqui1cf95042020-11-19 00:42:56 +05301256 return nil, err
1257 }
1258
1259 cloned := agent.cloneDeviceWithoutLock()
1260
1261 //send request to adapter
khenaidood948f772021-08-11 17:49:24 -04001262 client, err := agent.adapterMgr.GetAdapterClient(ctx, agent.adapterEndpoint)
Salman Siddiqui1cf95042020-11-19 00:42:56 +05301263 if err != nil {
khenaidood948f772021-08-11 17:49:24 -04001264 logger.Errorw(ctx, "grpc-client-nil",
1265 log.Fields{
1266 "error": err,
1267 "device-id": cloned.Id,
1268 "adapter-endpoint": cloned.AdapterEndpoint,
1269 })
1270 agent.requestQueue.RequestComplete()
Salman Siddiqui1cf95042020-11-19 00:42:56 +05301271 return nil, err
1272 }
khenaidood948f772021-08-11 17:49:24 -04001273 // Release lock before sending request to adapter
1274 agent.requestQueue.RequestComplete()
Salman Siddiqui1cf95042020-11-19 00:42:56 +05301275
khenaidood948f772021-08-11 17:49:24 -04001276 resp, err := client.GetSingleValue(ctx, request)
1277 if err == nil {
1278 requestStatus.Code = common.OperationResp_OPERATION_SUCCESS
Salman Siddiqui1cf95042020-11-19 00:42:56 +05301279 }
khenaidood948f772021-08-11 17:49:24 -04001280 return resp, err
Salman Siddiqui1cf95042020-11-19 00:42:56 +05301281}
1282
1283func (agent *Agent) setSingleValue(ctx context.Context, request *extension.SingleSetValueRequest) (*extension.SingleSetValueResponse, error) {
Himani Chawlab4c25912020-11-12 17:16:38 +05301284 logger.Debugw(ctx, "set-single-value", log.Fields{"device-id": request.TargetId})
Salman Siddiqui1cf95042020-11-19 00:42:56 +05301285
khenaidood948f772021-08-11 17:49:24 -04001286 var err error
1287 var desc string
1288 requestStatus := &common.OperationResp{Code: common.OperationResp_OPERATION_FAILURE}
1289 defer func() { agent.logDeviceUpdate(ctx, nil, nil, requestStatus, err, desc) }()
1290
Salman Siddiqui1cf95042020-11-19 00:42:56 +05301291 if err := agent.requestQueue.WaitForGreenLight(ctx); err != nil {
1292 return nil, err
1293 }
1294
1295 cloned := agent.cloneDeviceWithoutLock()
1296
1297 //send request to adapter
khenaidood948f772021-08-11 17:49:24 -04001298 client, err := agent.adapterMgr.GetAdapterClient(ctx, agent.adapterEndpoint)
Salman Siddiqui1cf95042020-11-19 00:42:56 +05301299 if err != nil {
khenaidood948f772021-08-11 17:49:24 -04001300 logger.Errorw(ctx, "grpc-client-nil",
1301 log.Fields{
1302 "error": err,
1303 "device-id": agent.deviceID,
1304 "device-type": agent.deviceType,
1305 "adapter-endpoint": cloned.AdapterEndpoint,
1306 })
1307 agent.requestQueue.RequestComplete()
Salman Siddiqui1cf95042020-11-19 00:42:56 +05301308 return nil, err
1309 }
khenaidood948f772021-08-11 17:49:24 -04001310 // Release lock before sending request to adapter
1311 agent.requestQueue.RequestComplete()
Salman Siddiqui1cf95042020-11-19 00:42:56 +05301312
khenaidood948f772021-08-11 17:49:24 -04001313 resp, err := client.SetSingleValue(ctx, request)
1314 if err == nil {
1315 requestStatus.Code = common.OperationResp_OPERATION_SUCCESS
Salman Siddiqui1cf95042020-11-19 00:42:56 +05301316 }
khenaidood948f772021-08-11 17:49:24 -04001317 return resp, err
Salman Siddiqui1cf95042020-11-19 00:42:56 +05301318}
Maninder0aabf0c2021-03-17 14:55:14 +05301319
Maninder2195ccc2021-06-23 20:23:01 +05301320func (agent *Agent) proceedWithRequest(device *voltha.Device) bool {
1321 return !agent.isDeletionInProgress() && !agent.isInReconcileState(device)
Maninder0aabf0c2021-03-17 14:55:14 +05301322}
1323
1324func (agent *Agent) stopReconcile() {
1325 agent.stopReconcilingMutex.Lock()
1326 if agent.stopReconciling != nil {
1327 agent.stopReconciling <- 0
1328 }
1329 agent.stopReconcilingMutex.Unlock()
1330}
1331
khenaidood948f772021-08-11 17:49:24 -04001332// abortAllProcessing is invoked when an adapter managing this device is restarted
1333func (agent *Agent) abortAllProcessing(ctx context.Context) error {
1334 logger.Infow(ctx, "aborting-current-running-requests", log.Fields{"device-id": agent.deviceID})
1335 if err := agent.requestQueue.WaitForGreenLight(ctx); err != nil {
1336 return err
1337 }
1338 defer agent.requestQueue.RequestComplete()
1339
1340 // If any reconciling is in progress just abort it. The adapter is gone.
1341 agent.stopReconcile()
1342
1343 // Update the Core device transient state accordingly
1344 var updatedState core.DeviceTransientState_Types
1345 switch agent.getTransientState() {
1346 case core.DeviceTransientState_RECONCILE_IN_PROGRESS:
1347 updatedState = core.DeviceTransientState_NONE
1348 case core.DeviceTransientState_FORCE_DELETING:
1349 updatedState = core.DeviceTransientState_DELETE_FAILED
1350 case core.DeviceTransientState_DELETING_FROM_ADAPTER:
1351 updatedState = core.DeviceTransientState_DELETE_FAILED
1352 default:
1353 updatedState = core.DeviceTransientState_NONE
1354 }
1355 if err := agent.updateTransientState(ctx, updatedState); err != nil {
1356 logger.Errorf(ctx, "transient-state-update-failed", log.Fields{"error": err})
1357 return err
1358 }
1359 return nil
1360}
1361
1362func (agent *Agent) ReconcileDevice(ctx context.Context) {
1363 requestStatus := &common.OperationResp{Code: common.OperationResp_OPERATION_FAILURE}
Maninder0aabf0c2021-03-17 14:55:14 +05301364 var desc string
Maninder0aabf0c2021-03-17 14:55:14 +05301365
1366 if err := agent.requestQueue.WaitForGreenLight(ctx); err != nil {
khenaidood948f772021-08-11 17:49:24 -04001367 agent.logDeviceUpdate(ctx, nil, nil, requestStatus, err, desc)
1368 return
1369 }
1370
1371 device := agent.getDeviceReadOnlyWithoutLock()
1372 if device.AdminState == voltha.AdminState_PREPROVISIONED {
1373 agent.requestQueue.RequestComplete()
1374 logger.Debugw(ctx, "device-in-preprovisioning-state-reconcile-not-needed", log.Fields{"device-id": device.Id})
Maninder0aabf0c2021-03-17 14:55:14 +05301375 return
1376 }
1377
Maninder2195ccc2021-06-23 20:23:01 +05301378 if !agent.proceedWithRequest(device) {
Maninder0aabf0c2021-03-17 14:55:14 +05301379 agent.requestQueue.RequestComplete()
khenaidood948f772021-08-11 17:49:24 -04001380 err := fmt.Errorf("cannot complete operation as device deletion/reconciling is in progress or reconcile failed for device : %s", device.Id)
1381 logger.Errorw(ctx, "reconcile-failed", log.Fields{"error": err})
1382 agent.logDeviceUpdate(ctx, nil, nil, requestStatus, err, desc)
Maninder0aabf0c2021-03-17 14:55:14 +05301383 return
1384 }
1385
1386 //set transient state to RECONCILE IN PROGRESS
khenaidood948f772021-08-11 17:49:24 -04001387 err := agent.updateTransientState(ctx, core.DeviceTransientState_RECONCILE_IN_PROGRESS)
Maninder0aabf0c2021-03-17 14:55:14 +05301388 if err != nil {
1389 agent.requestQueue.RequestComplete()
khenaidood948f772021-08-11 17:49:24 -04001390 logger.Errorw(ctx, "setting-transient-state-failed", log.Fields{"error": err})
1391 agent.logDeviceUpdate(ctx, nil, nil, requestStatus, nil, desc)
Maninder0aabf0c2021-03-17 14:55:14 +05301392 return
1393 }
1394
Maninder0aabf0c2021-03-17 14:55:14 +05301395 reconcilingBackoff := backoff.NewExponentialBackOff()
1396 reconcilingBackoff.InitialInterval = agent.config.BackoffRetryInitialInterval
1397 reconcilingBackoff.MaxElapsedTime = agent.config.BackoffRetryMaxElapsedTime
1398 reconcilingBackoff.MaxInterval = agent.config.BackoffRetryMaxInterval
1399
1400 //making here to keep lifecycle of this channel within the scope of retryReconcile
1401 agent.stopReconcilingMutex.Lock()
1402 agent.stopReconciling = make(chan int)
1403 agent.stopReconcilingMutex.Unlock()
1404
David K. Bainbridge482e4422021-06-30 12:23:42 -07001405 // defined outside the retry loop so it can be cleaned
1406 // up when the loop breaks
1407 var backoffTimer *time.Timer
1408
1409retry:
Maninder0aabf0c2021-03-17 14:55:14 +05301410 for {
David K. Bainbridge482e4422021-06-30 12:23:42 -07001411 // If the operations state of the device is RECONCILING_FAILED then we do not
1412 // want to continue to attempt reconciliation.
1413 deviceRef := agent.getDeviceReadOnlyWithoutLock()
1414 if deviceRef.OperStatus == common.OperStatus_RECONCILING_FAILED {
1415 logger.Warnw(ctx, "reconciling-failed-halting-retries",
1416 log.Fields{"device-id": device.Id})
1417 agent.requestQueue.RequestComplete()
1418 break retry
1419 }
1420
Maninder0aabf0c2021-03-17 14:55:14 +05301421 // Use an exponential back off to prevent getting into a tight loop
1422 duration := reconcilingBackoff.NextBackOff()
1423 //This case should never occur in default case as max elapsed time for backoff is 0(by default) , so it will never return stop
1424 if duration == backoff.Stop {
1425 // If we reach a maximum then warn and reset the backoff
1426 // timer and keep attempting.
1427 logger.Warnw(ctx, "maximum-reconciling-backoff-reached--resetting-backoff-timer",
1428 log.Fields{"max-reconciling-backoff": reconcilingBackoff.MaxElapsedTime,
1429 "device-id": device.Id})
1430 reconcilingBackoff.Reset()
1431 duration = reconcilingBackoff.NextBackOff()
1432 }
1433
David K. Bainbridge482e4422021-06-30 12:23:42 -07001434 backoffTimer = time.NewTimer(duration)
Maninder0aabf0c2021-03-17 14:55:14 +05301435
khenaidood948f772021-08-11 17:49:24 -04001436 logger.Debugw(ctx, "retrying-reconciling", log.Fields{"deviceID": device.Id, "endpoint": device.AdapterEndpoint})
1437 // Release lock before sending request to adapter
Maninder0aabf0c2021-03-17 14:55:14 +05301438 agent.requestQueue.RequestComplete()
khenaidood948f772021-08-11 17:49:24 -04001439
1440 // Send a reconcile request to the adapter.
1441 err := agent.sendReconcileRequestToAdapter(ctx, device)
1442 if errors.Is(err, errContextExpired) || errors.Is(err, errReconcileAborted) {
1443 logger.Errorw(ctx, "reconcile-aborted", log.Fields{"error": err})
1444 requestStatus = &common.OperationResp{Code: common.OperationResp_OperationReturnCode(common.OperStatus_FAILED)}
1445 desc = "aborted"
1446 agent.logDeviceUpdate(ctx, nil, nil, requestStatus, err, desc)
1447 break retry
1448 }
Maninder0aabf0c2021-03-17 14:55:14 +05301449 if err != nil {
khenaidood948f772021-08-11 17:49:24 -04001450 agent.logDeviceUpdate(ctx, nil, nil, requestStatus, err, desc)
Maninder0aabf0c2021-03-17 14:55:14 +05301451 <-backoffTimer.C
1452 // backoffTimer expired continue
1453 // Take lock back before retrying
1454 if err := agent.requestQueue.WaitForGreenLight(ctx); err != nil {
khenaidood948f772021-08-11 17:49:24 -04001455 agent.logDeviceUpdate(ctx, nil, nil, requestStatus, err, desc)
David K. Bainbridge482e4422021-06-30 12:23:42 -07001456 break retry
Maninder0aabf0c2021-03-17 14:55:14 +05301457 }
1458 continue
1459 }
khenaidood948f772021-08-11 17:49:24 -04001460 // Success
1461 requestStatus = &common.OperationResp{Code: common.OperationResp_OPERATION_SUCCESS}
1462 desc = "adapter-response"
1463 agent.logDeviceUpdate(ctx, nil, nil, requestStatus, err, desc)
1464 break retry
David K. Bainbridge482e4422021-06-30 12:23:42 -07001465 }
1466
1467 // Retry loop is broken, so stop any timers and drain the channel
1468 if backoffTimer != nil && !backoffTimer.Stop() {
1469
1470 // As per documentation and stack overflow when a timer is stopped its
1471 // channel should be drained. The issue is that Stop returns false
1472 // either if the timer has already been fired "OR" if the timer can be
1473 // stopped before being fired. This means that in some cases the
1474 // channel has already be emptied so attempting to read from it means
1475 // a blocked thread. To get around this use a select so if the
1476 // channel is already empty the default case hits and we are not
1477 // blocked.
1478 select {
1479 case <-backoffTimer.C:
1480 default:
Maninder0aabf0c2021-03-17 14:55:14 +05301481 }
1482 }
1483}
1484
khenaidood948f772021-08-11 17:49:24 -04001485func (agent *Agent) sendReconcileRequestToAdapter(ctx context.Context, device *voltha.Device) error {
1486 logger.Debugw(ctx, "sending-reconcile-to-adapter", log.Fields{"device-id": device.Id, "endpoint": agent.adapterEndpoint})
1487 client, err := agent.adapterMgr.GetAdapterClient(ctx, agent.adapterEndpoint)
1488 if err != nil {
1489 return err
1490 }
1491 adapterResponse := make(chan error)
1492 go func() {
1493 _, err := client.ReconcileDevice(ctx, device)
1494 adapterResponse <- err
1495 }()
Maninder0aabf0c2021-03-17 14:55:14 +05301496 select {
1497 // wait for response
khenaidood948f772021-08-11 17:49:24 -04001498 case err := <-adapterResponse:
1499 if err != nil {
1500 return err
Maninder0aabf0c2021-03-17 14:55:14 +05301501 }
Maninder0aabf0c2021-03-17 14:55:14 +05301502 //In case of success quit retrying and wait for adapter to reset operation state of device
1503 agent.stopReconcilingMutex.Lock()
1504 agent.stopReconciling = nil
1505 agent.stopReconcilingMutex.Unlock()
1506 return nil
1507
1508 //if reconciling need to be stopped
1509 case _, ok := <-agent.stopReconciling:
1510 agent.stopReconcilingMutex.Lock()
1511 agent.stopReconciling = nil
1512 agent.stopReconcilingMutex.Unlock()
1513 if !ok {
1514 //channel-closed
khenaidood948f772021-08-11 17:49:24 -04001515 return fmt.Errorf("reconcile channel closed:%w", errReconcileAborted)
Maninder0aabf0c2021-03-17 14:55:14 +05301516 }
khenaidood948f772021-08-11 17:49:24 -04001517 return fmt.Errorf("reconciling aborted:%w", errReconcileAborted)
1518 // Context expired
1519 case <-ctx.Done():
1520 return fmt.Errorf("context expired:%s :%w", ctx.Err(), errContextExpired)
Maninder0aabf0c2021-03-17 14:55:14 +05301521 }
Maninder0aabf0c2021-03-17 14:55:14 +05301522}
1523
1524func (agent *Agent) reconcilingCleanup(ctx context.Context) error {
1525 var desc string
khenaidood948f772021-08-11 17:49:24 -04001526 var err error
Maninder0aabf0c2021-03-17 14:55:14 +05301527 operStatus := &common.OperationResp{Code: common.OperationResp_OPERATION_FAILURE}
khenaidood948f772021-08-11 17:49:24 -04001528 defer func() { agent.logDeviceUpdate(ctx, nil, nil, operStatus, err, desc) }()
1529
1530 if err = agent.requestQueue.WaitForGreenLight(ctx); err != nil {
1531 desc = "reconcile-cleanup-failed"
Maninder0aabf0c2021-03-17 14:55:14 +05301532 return err
1533 }
1534 defer agent.requestQueue.RequestComplete()
khenaidood948f772021-08-11 17:49:24 -04001535 err = agent.updateTransientState(ctx, core.DeviceTransientState_NONE)
Maninder0aabf0c2021-03-17 14:55:14 +05301536 if err != nil {
khenaidood948f772021-08-11 17:49:24 -04001537 logger.Errorf(ctx, "transient-state-update-failed", log.Fields{"error": err})
Maninder0aabf0c2021-03-17 14:55:14 +05301538 return err
1539 }
khenaidood948f772021-08-11 17:49:24 -04001540 operStatus.Code = common.OperationResp_OPERATION_SUCCESS
Maninder0aabf0c2021-03-17 14:55:14 +05301541 return nil
1542}
khenaidood948f772021-08-11 17:49:24 -04001543
1544func (agent *Agent) isAdapterConnectionUp(ctx context.Context) bool {
1545 c, err := agent.adapterMgr.GetAdapterClient(ctx, agent.adapterEndpoint)
1546 return c != nil && err == nil
1547}
1548
1549func (agent *Agent) canDeviceRequestProceed(ctx context.Context) error {
1550 if err := agent.requestQueue.WaitForGreenLight(ctx); err != nil {
1551 return err
1552 }
1553 defer agent.requestQueue.RequestComplete()
1554 if agent.proceedWithRequest(agent.device) {
1555 return nil
1556 }
1557 return fmt.Errorf("device-cannot-process-request-%s", agent.deviceID)
1558}