[VOL-1658] Address disable/delete of a device in Pre-prov state
This commit addresses the case where a user wants to disable a
preprovisioned device and also delete it. It addresses part of the
issue raised by VOL-1658.
Change-Id: Iac8adf45070a234c5505ed800f77150d8ed85156
diff --git a/rw_core/core/device_agent.go b/rw_core/core/device_agent.go
index 4e31ff8..4a88779 100755
--- a/rw_core/core/device_agent.go
+++ b/rw_core/core/device_agent.go
@@ -116,7 +116,7 @@
log.Debug("stopping-device-agent")
// Remove the device from the KV store
if removed := agent.clusterDataProxy.Remove("/devices/"+agent.deviceId, ""); removed == nil {
- log.Errorw("failed-removing-device", log.Fields{"id": agent.deviceId})
+ log.Debugw("device-already-removed", log.Fields{"id": agent.deviceId})
}
agent.exitChannel <- 1
log.Debug("device-agent-stopped")
@@ -348,6 +348,12 @@
log.Debugw("device-already-disabled", log.Fields{"id": agent.deviceId})
return nil
}
+ if device.AdminState == voltha.AdminState_PREPROVISIONED ||
+ device.AdminState == voltha.AdminState_DELETED {
+ log.Debugw("device-not-enabled", log.Fields{"id": agent.deviceId})
+ return status.Errorf(codes.FailedPrecondition, "deviceId:%s, invalid-admin-state:%s", agent.deviceId, device.AdminState)
+ }
+
// First send the request to an Adapter and wait for a response
if err := agent.adapterProxy.DisableDevice(ctx, device); err != nil {
log.Debugw("disableDevice-error", log.Fields{"id": agent.lastData.Id, "error": err})
@@ -422,12 +428,13 @@
//TODO: Needs customized error message
return status.Errorf(codes.FailedPrecondition, "deviceId:%s, expected-admin-state:%s", agent.deviceId, voltha.AdminState_DISABLED)
}
- // Send the request to an Adapter and wait for a response
- if err := agent.adapterProxy.DeleteDevice(ctx, device); err != nil {
- log.Debugw("deleteDevice-error", log.Fields{"id": agent.lastData.Id, "error": err})
- return err
+ if device.AdminState != voltha.AdminState_PREPROVISIONED {
+ // Send the request to an Adapter only if the device is not in poreporovision state and wait for a response
+ if err := agent.adapterProxy.DeleteDevice(ctx, device); err != nil {
+ log.Debugw("deleteDevice-error", log.Fields{"id": agent.lastData.Id, "error": err})
+ return err
+ }
}
-
// Set the state to deleted - this will trigger some background process to clean up the device as well
// as its association with the logical device
cloned := proto.Clone(device).(*voltha.Device)
diff --git a/rw_core/core/device_ownership.go b/rw_core/core/device_ownership.go
index e746444..49d860a 100644
--- a/rw_core/core/device_ownership.go
+++ b/rw_core/core/device_ownership.go
@@ -50,6 +50,7 @@
deviceMapLock *sync.RWMutex
deviceToKeyMap map[string]string
deviceToKeyMapLock *sync.RWMutex
+ ownershipLock *sync.RWMutex
}
func NewDeviceOwnership(id string, kvClient kvstore.Client, deviceMgr *DeviceManager, logicalDeviceMgr *LogicalDeviceManager, ownershipPrefix string, reservationTimeout int64) *DeviceOwnership {
@@ -65,6 +66,7 @@
deviceOwnership.deviceMapLock = &sync.RWMutex{}
deviceOwnership.deviceToKeyMap = make(map[string]string)
deviceOwnership.deviceToKeyMapLock = &sync.RWMutex{}
+ deviceOwnership.ownershipLock = &sync.RWMutex{}
return &deviceOwnership
}
@@ -109,21 +111,23 @@
}
func (da *DeviceOwnership) MonitorOwnership(id string, chnl chan int) {
+ log.Debugw("start-device-monitoring", log.Fields{"id": id})
op := "starting"
exit := false
ticker := time.NewTicker(time.Duration(da.reservationTimeout) / 3 * time.Second)
for {
select {
case <-da.exitChannel:
- log.Infow("closing-monitoring", log.Fields{"Id": id})
+ log.Debugw("closing-monitoring", log.Fields{"Id": id})
exit = true
case <-ticker.C:
log.Debugw(fmt.Sprintf("%s-reservation", op), log.Fields{"Id": id})
case <-chnl:
- log.Infow("closing-device-monitoring", log.Fields{"Id": id})
+ log.Debugw("closing-device-monitoring", log.Fields{"Id": id})
exit = true
}
if exit {
+ log.Infow("exiting-device-monitoring", log.Fields{"Id": id})
ticker.Stop()
break
}
@@ -144,6 +148,7 @@
}
}
}
+ log.Debugw("device-monitoring-stopped", log.Fields{"id": id})
}
func (da *DeviceOwnership) getOwnership(id string) (bool, bool) {
@@ -188,6 +193,12 @@
da.deviceToKeyMapLock.Unlock()
}
+ // Add a lock to prevent creation of two separate monitoring routines for the same device. When a NB request for a
+ // device not in memory is received this results in this function being called in rapid succession, once when
+ // loading the device and once when handling the NB request.
+ da.ownershipLock.Lock()
+ defer da.ownershipLock.Unlock()
+
deviceOwned, ownedByMe := da.getOwnership(ownershipKey)
if deviceOwned {
log.Debugw("ownership", log.Fields{"Id": ownershipKey, "owned": ownedByMe})
diff --git a/rw_core/core/device_state_transitions.go b/rw_core/core/device_state_transitions.go
index 5c52a8f..906c4e7 100644
--- a/rw_core/core/device_state_transitions.go
+++ b/rw_core/core/device_state_transitions.go
@@ -163,6 +163,12 @@
handlers: []TransitionHandler{dMgr.NotifyInvalidTransition}})
transitionMap.transitions = append(transitionMap.transitions,
Transition{
+ deviceType: any,
+ previousState: DeviceState{Admin: voltha.AdminState_PREPROVISIONED, Connection: voltha.ConnectStatus_UNKNOWN, Operational: voltha.OperStatus_UNKNOWN},
+ currentState: DeviceState{Admin: voltha.AdminState_DELETED, Connection: voltha.ConnectStatus_UNKNOWN, Operational: voltha.OperStatus_UNKNOWN},
+ handlers: []TransitionHandler{dMgr.RunPostDeviceDelete}})
+ transitionMap.transitions = append(transitionMap.transitions,
+ Transition{
deviceType: parent,
previousState: DeviceState{Admin: voltha.AdminState_DISABLED, Connection: voltha.ConnectStatus_UNKNOWN, Operational: voltha.OperStatus_UNKNOWN},
currentState: DeviceState{Admin: voltha.AdminState_DELETED, Connection: voltha.ConnectStatus_UNKNOWN, Operational: voltha.OperStatus_UNKNOWN},