[VOL-3767] Removing device flows during deletion of device and completing deletion regardless of devices not found
Change-Id: I803003d42ecfce98240efe22559c28ca2180e9ca
diff --git a/rw_core/core/device/logical_agent_flow.go b/rw_core/core/device/logical_agent_flow.go
index fa1a19a..eda4fa6 100644
--- a/rw_core/core/device/logical_agent_flow.go
+++ b/rw_core/core/device/logical_agent_flow.go
@@ -356,9 +356,20 @@
devicesInFlows = []string{agent.rootDeviceID}
}
- if err := agent.deviceMgr.canMultipleAdapterRequestProceed(ctx, devicesInFlows); err != nil {
- logger.Warnw(ctx, "adapters-not-ready", log.Fields{"logical-device-id": agent.logicalDeviceID, "flow": toDelete, "error": err})
- return err
+ for _, deviceID := range devicesInFlows {
+ if err := agent.deviceMgr.canAdapterRequestProceed(ctx, deviceID); err != nil {
+ //If the error has code.NotFound the device is not there anymore, there is no need to delete flows, just ignore it
+ if status.Code(err) != codes.NotFound {
+ logger.Warnw(ctx, "adapters-not-ready", log.Fields{"logical-device-id": agent.logicalDeviceID, "flow": toDelete, "error": err})
+ return err
+ } else {
+ logger.Debugw(ctx, "flow-delete-for-nil-device-proceeding-deletion", log.Fields{"deviceID": deviceID})
+ if deviceRules != nil {
+ deviceRules.RemoveRule(deviceID)
+ partialRoute = true
+ }
+ }
+ }
}
// Update the devices
@@ -456,9 +467,20 @@
devicesInFlows = []string{agent.rootDeviceID}
}
- if err := agent.deviceMgr.canMultipleAdapterRequestProceed(ctx, devicesInFlows); err != nil {
- logger.Warnw(ctx, "adapters-not-ready", log.Fields{"logical-device-id": agent.logicalDeviceID, "flow": flowsToDelete, "error": err})
- return err
+ for _, deviceID := range devicesInFlows {
+ if err := agent.deviceMgr.canAdapterRequestProceed(ctx, deviceID); err != nil {
+ //If the error has code.NotFound the device is not there anymore, there is no need to delete flows, just ignore it
+ if status.Code(err) != codes.NotFound {
+ logger.Warnw(ctx, "adapters-not-ready", log.Fields{"logical-device-id": agent.logicalDeviceID, "flow": flowsToDelete, "error": err})
+ return err
+ } else {
+ logger.Debugw(ctx, "flow-delete-strict-for-nil-device-proceeding-deletion", log.Fields{"deviceID": deviceID})
+ if deviceRules != nil {
+ deviceRules.RemoveRule(deviceID)
+ partialRoute = true
+ }
+ }
+ }
}
// Update the devices
diff --git a/rw_core/core/device/manager.go b/rw_core/core/device/manager.go
index 07e92d0..c1148b5 100755
--- a/rw_core/core/device/manager.go
+++ b/rw_core/core/device/manager.go
@@ -465,37 +465,44 @@
return status.Errorf(codes.NotFound, "%s", deviceID)
}
-func (dMgr *Manager) canMultipleAdapterRequestProceed(ctx context.Context, deviceIDs []string) error {
- ready := len(deviceIDs) > 0
- for _, deviceID := range deviceIDs {
- agent := dMgr.getDeviceAgent(ctx, deviceID)
- if agent == nil {
- logger.Errorw(ctx, "adapter-nil", log.Fields{"device-id": deviceID})
- return status.Errorf(codes.Unavailable, "adapter-nil-for-%s", deviceID)
+func (dMgr *Manager) canAdapterRequestProceed(ctx context.Context, deviceID string) error {
+ agent := dMgr.getDeviceAgent(ctx, deviceID)
+ if agent == nil {
+ logger.Errorw(ctx, "device-nil", log.Fields{"device-id": deviceID})
+ return status.Errorf(codes.NotFound, "device-nil-for-%s", deviceID)
+ }
+ if !agent.isAdapterConnectionUp(ctx) {
+ return status.Errorf(codes.Unavailable, "adapter-connection-down-for-%s", deviceID)
+ }
+ if err := agent.canDeviceRequestProceed(ctx); err != nil {
+ return err
+ }
+ // Perform the same checks for parent device
+ if !agent.isRootDevice {
+ parentDeviceAgent := dMgr.getDeviceAgent(ctx, agent.parentID)
+ if parentDeviceAgent == nil {
+ logger.Errorw(ctx, "parent-device-adapter-nil", log.Fields{"parent-id": agent.parentID})
+ return status.Errorf(codes.NotFound, "parent-device-adapter-nil-for-%s", deviceID)
}
- ready = ready && agent.isAdapterConnectionUp(ctx)
- if !ready {
- return status.Errorf(codes.Unavailable, "adapter-connection-down-for-%s", deviceID)
- }
- if err := agent.canDeviceRequestProceed(ctx); err != nil {
+ if err := parentDeviceAgent.canDeviceRequestProceed(ctx); err != nil {
return err
}
- // Perform the same checks for parent device
- if !agent.isRootDevice {
- parentDeviceAgent := dMgr.getDeviceAgent(ctx, agent.parentID)
- if parentDeviceAgent == nil {
- logger.Errorw(ctx, "parent-device-adapter-nil", log.Fields{"parent-id": agent.parentID})
- return status.Errorf(codes.Unavailable, "parent-device-adapter-nil-for-%s", deviceID)
- }
- if err := parentDeviceAgent.canDeviceRequestProceed(ctx); err != nil {
- return err
- }
- }
-
}
- if !ready {
+
+ return nil
+}
+
+func (dMgr *Manager) canMultipleAdapterRequestProceed(ctx context.Context, deviceIDs []string) error {
+ if len(deviceIDs) == 0 {
return status.Error(codes.Unavailable, "adapter(s)-not-ready")
}
+
+ for _, deviceID := range deviceIDs {
+ if err := dMgr.canAdapterRequestProceed(ctx, deviceID); err != nil {
+ return err
+ }
+ }
+
return nil
}
diff --git a/rw_core/core/device/state/transitions.go b/rw_core/core/device/state/transitions.go
index ed0a59d..b8e429c 100644
--- a/rw_core/core/device/state/transitions.go
+++ b/rw_core/core/device/state/transitions.go
@@ -201,13 +201,13 @@
deviceType: child,
previousState: deviceState{Admin: voltha.AdminState_UNKNOWN, Connection: voltha.ConnectStatus_UNKNOWN, Operational: voltha.OperStatus_UNKNOWN, Transient: core.DeviceTransientState_ANY},
currentState: deviceState{Admin: voltha.AdminState_UNKNOWN, Connection: voltha.ConnectStatus_UNKNOWN, Operational: voltha.OperStatus_UNKNOWN, Transient: core.DeviceTransientState_FORCE_DELETING},
- handlers: []transitionHandler{dMgr.ChildDeviceLost, dMgr.DeleteLogicalPorts, dMgr.RunPostDeviceDelete}})
+ handlers: []transitionHandler{dMgr.DeleteAllDeviceFlows, dMgr.ChildDeviceLost, dMgr.DeleteLogicalPorts, dMgr.RunPostDeviceDelete}})
transitionMap.transitions = append(transitionMap.transitions,
transition{ //DELETE after adapter response case
deviceType: child,
previousState: deviceState{Admin: voltha.AdminState_UNKNOWN, Connection: voltha.ConnectStatus_UNKNOWN, Operational: voltha.OperStatus_UNKNOWN, Transient: core.DeviceTransientState_ANY},
currentState: deviceState{Admin: voltha.AdminState_UNKNOWN, Connection: voltha.ConnectStatus_UNKNOWN, Operational: voltha.OperStatus_UNKNOWN, Transient: core.DeviceTransientState_DELETING_POST_ADAPTER_RESPONSE},
- handlers: []transitionHandler{dMgr.ChildDeviceLost, dMgr.DeleteLogicalPorts, dMgr.RunPostDeviceDelete}})
+ handlers: []transitionHandler{dMgr.DeleteAllDeviceFlows, dMgr.ChildDeviceLost, dMgr.DeleteLogicalPorts, dMgr.RunPostDeviceDelete}})
transitionMap.transitions = append(transitionMap.transitions,
transition{ //DELETE wait for adapter response(no operation)
deviceType: child,
diff --git a/rw_core/core/device/state/transitions_test.go b/rw_core/core/device/state/transitions_test.go
index cef7af9..d503efa 100644
--- a/rw_core/core/device/state/transitions_test.go
+++ b/rw_core/core/device/state/transitions_test.go
@@ -199,10 +199,11 @@
device = getDevice(false, voltha.AdminState_ENABLED, voltha.ConnectStatus_UNKNOWN, voltha.OperStatus_FAILED)
handlers = transitionMap.getTransitionHandler(ctx, device, previousDevice, core.DeviceTransientState_FORCE_DELETING,
core.DeviceTransientState_ANY)
- assert.Equal(t, 3, len(handlers))
- assert.True(t, reflect.ValueOf(tdm.ChildDeviceLost).Pointer() == reflect.ValueOf(handlers[0]).Pointer())
- assert.True(t, reflect.ValueOf(tdm.DeleteLogicalPorts).Pointer() == reflect.ValueOf(handlers[1]).Pointer())
- assert.True(t, reflect.ValueOf(tdm.RunPostDeviceDelete).Pointer() == reflect.ValueOf(handlers[2]).Pointer())
+ assert.Equal(t, 4, len(handlers))
+ assert.True(t, reflect.ValueOf(tdm.DeleteAllDeviceFlows).Pointer() == reflect.ValueOf(handlers[0]).Pointer())
+ assert.True(t, reflect.ValueOf(tdm.ChildDeviceLost).Pointer() == reflect.ValueOf(handlers[1]).Pointer())
+ assert.True(t, reflect.ValueOf(tdm.DeleteLogicalPorts).Pointer() == reflect.ValueOf(handlers[2]).Pointer())
+ assert.True(t, reflect.ValueOf(tdm.RunPostDeviceDelete).Pointer() == reflect.ValueOf(handlers[3]).Pointer())
previousDevice = getDevice(true, voltha.AdminState_ENABLED, voltha.ConnectStatus_REACHABLE, voltha.OperStatus_ACTIVE)
device = getDevice(true, voltha.AdminState_ENABLED, voltha.ConnectStatus_UNREACHABLE, voltha.OperStatus_UNKNOWN)
@@ -337,6 +338,7 @@
tdm.RunPostDeviceDelete,
},
expectedChildHandlers: []transitionHandler{
+ tdm.DeleteAllDeviceFlows,
tdm.ChildDeviceLost,
tdm.DeleteLogicalPorts,
tdm.RunPostDeviceDelete,
@@ -365,7 +367,7 @@
t.Run(testName, func(t *testing.T) {
handlers = transitionMap.getTransitionHandler(ctx, device, previousDevice, core.DeviceTransientState_FORCE_DELETING,
core.DeviceTransientState_ANY)
- assert.Equal(t, 3, len(handlers))
+ assert.Equal(t, 4, len(handlers))
for idx, expHandler := range deleteDeviceTest.expectedChildHandlers {
assert.True(t, reflect.ValueOf(expHandler).Pointer() == reflect.ValueOf(handlers[idx]).Pointer())
}