[VOL-2573] Delete all logical ports on OLT Delete

Change-Id: Id809e176fe3a902aabea8cbce573fbf9710d9b10
diff --git a/rw_core/core/device_manager.go b/rw_core/core/device_manager.go
index 950819e..fab90ee 100755
--- a/rw_core/core/device_manager.go
+++ b/rw_core/core/device_manager.go
@@ -1274,6 +1274,15 @@
 	return nil
 }
 
+//DeleteAllUNILogicalPorts is invoked as a callback when the parent device is deleted
+func (dMgr *DeviceManager) DeleteAllUNILogicalPorts(ctx context.Context, parentDevice *voltha.Device) error {
+	log.Debugw("delete-all-uni-logical-ports", log.Fields{"parent-device-id": parentDevice.Id})
+	if err := dMgr.logicalDeviceMgr.deleteAllUNILogicalPorts(ctx, parentDevice); err != nil {
+		return err
+	}
+	return nil
+}
+
 //getAllChildDeviceIds is a helper method to get all the child device IDs from the device passed as parameter
 func (dMgr *DeviceManager) getAllChildDeviceIds(parentDevice *voltha.Device) ([]string, error) {
 	log.Debugw("getAllChildDeviceIds", log.Fields{"parentDeviceId": parentDevice.Id})
diff --git a/rw_core/core/device_state_transitions.go b/rw_core/core/device_state_transitions.go
index 0a6264b..9b4acf3 100644
--- a/rw_core/core/device_state_transitions.go
+++ b/rw_core/core/device_state_transitions.go
@@ -90,7 +90,7 @@
 			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},
-			handlers:      []TransitionHandler{dMgr.DisableAllChildDevices, dMgr.DeleteAllChildDevices, dMgr.DeleteLogicalDevice, dMgr.RunPostDeviceDelete}})
+			handlers:      []TransitionHandler{dMgr.DisableAllChildDevices, dMgr.DeleteAllUNILogicalPorts, dMgr.DeleteAllChildDevices, dMgr.DeleteLogicalDevice, dMgr.RunPostDeviceDelete}})
 	transitionMap.transitions = append(transitionMap.transitions,
 		Transition{
 			deviceType:    child,
diff --git a/rw_core/core/device_state_transitions_test.go b/rw_core/core/device_state_transitions_test.go
index 4df728f..15d72f3 100644
--- a/rw_core/core/device_state_transitions_test.go
+++ b/rw_core/core/device_state_transitions_test.go
@@ -172,29 +172,32 @@
 	from = getDevice(true, voltha.AdminState_DISABLED, voltha.ConnectStatus_UNKNOWN, voltha.OperStatus_UNKNOWN)
 	to = getDevice(true, voltha.AdminState_DELETED, voltha.ConnectStatus_UNKNOWN, voltha.OperStatus_UNKNOWN)
 	handlers = transitionMap.GetTransitionHandler(from, to)
-	assert.Equal(t, 4, len(handlers))
+	assert.Equal(t, 5, len(handlers))
 	assert.True(t, reflect.ValueOf(tdm.DisableAllChildDevices).Pointer() == reflect.ValueOf(handlers[0]).Pointer())
-	assert.True(t, reflect.ValueOf(tdm.DeleteAllChildDevices).Pointer() == reflect.ValueOf(handlers[1]).Pointer())
-	assert.True(t, reflect.ValueOf(tdm.DeleteLogicalDevice).Pointer() == reflect.ValueOf(handlers[2]).Pointer())
-	assert.True(t, reflect.ValueOf(tdm.RunPostDeviceDelete).Pointer() == reflect.ValueOf(handlers[3]).Pointer())
+	assert.True(t, reflect.ValueOf(tdm.DeleteAllUNILogicalPorts).Pointer() == reflect.ValueOf(handlers[1]).Pointer())
+	assert.True(t, reflect.ValueOf(tdm.DeleteAllChildDevices).Pointer() == reflect.ValueOf(handlers[2]).Pointer())
+	assert.True(t, reflect.ValueOf(tdm.DeleteLogicalDevice).Pointer() == reflect.ValueOf(handlers[3]).Pointer())
+	assert.True(t, reflect.ValueOf(tdm.RunPostDeviceDelete).Pointer() == reflect.ValueOf(handlers[4]).Pointer())
 
 	from = getDevice(true, voltha.AdminState_DISABLED, voltha.ConnectStatus_REACHABLE, voltha.OperStatus_UNKNOWN)
 	to = getDevice(true, voltha.AdminState_DELETED, voltha.ConnectStatus_UNREACHABLE, voltha.OperStatus_UNKNOWN)
 	handlers = transitionMap.GetTransitionHandler(from, to)
-	assert.Equal(t, 4, len(handlers))
+	assert.Equal(t, 5, len(handlers))
 	assert.True(t, reflect.ValueOf(tdm.DisableAllChildDevices).Pointer() == reflect.ValueOf(handlers[0]).Pointer())
-	assert.True(t, reflect.ValueOf(tdm.DeleteAllChildDevices).Pointer() == reflect.ValueOf(handlers[1]).Pointer())
-	assert.True(t, reflect.ValueOf(tdm.DeleteLogicalDevice).Pointer() == reflect.ValueOf(handlers[2]).Pointer())
-	assert.True(t, reflect.ValueOf(tdm.RunPostDeviceDelete).Pointer() == reflect.ValueOf(handlers[3]).Pointer())
+	assert.True(t, reflect.ValueOf(tdm.DeleteAllUNILogicalPorts).Pointer() == reflect.ValueOf(handlers[1]).Pointer())
+	assert.True(t, reflect.ValueOf(tdm.DeleteAllChildDevices).Pointer() == reflect.ValueOf(handlers[2]).Pointer())
+	assert.True(t, reflect.ValueOf(tdm.DeleteLogicalDevice).Pointer() == reflect.ValueOf(handlers[3]).Pointer())
+	assert.True(t, reflect.ValueOf(tdm.RunPostDeviceDelete).Pointer() == reflect.ValueOf(handlers[4]).Pointer())
 
 	from = getDevice(true, voltha.AdminState_DISABLED, voltha.ConnectStatus_UNREACHABLE, voltha.OperStatus_UNKNOWN)
 	to = getDevice(true, voltha.AdminState_DELETED, voltha.ConnectStatus_UNREACHABLE, voltha.OperStatus_FAILED)
 	handlers = transitionMap.GetTransitionHandler(from, to)
-	assert.Equal(t, 4, len(handlers))
+	assert.Equal(t, 5, len(handlers))
 	assert.True(t, reflect.ValueOf(tdm.DisableAllChildDevices).Pointer() == reflect.ValueOf(handlers[0]).Pointer())
-	assert.True(t, reflect.ValueOf(tdm.DeleteAllChildDevices).Pointer() == reflect.ValueOf(handlers[1]).Pointer())
-	assert.True(t, reflect.ValueOf(tdm.DeleteLogicalDevice).Pointer() == reflect.ValueOf(handlers[2]).Pointer())
-	assert.True(t, reflect.ValueOf(tdm.RunPostDeviceDelete).Pointer() == reflect.ValueOf(handlers[3]).Pointer())
+	assert.True(t, reflect.ValueOf(tdm.DeleteAllUNILogicalPorts).Pointer() == reflect.ValueOf(handlers[1]).Pointer())
+	assert.True(t, reflect.ValueOf(tdm.DeleteAllChildDevices).Pointer() == reflect.ValueOf(handlers[2]).Pointer())
+	assert.True(t, reflect.ValueOf(tdm.DeleteLogicalDevice).Pointer() == reflect.ValueOf(handlers[3]).Pointer())
+	assert.True(t, reflect.ValueOf(tdm.RunPostDeviceDelete).Pointer() == reflect.ValueOf(handlers[4]).Pointer())
 
 	from = getDevice(false, voltha.AdminState_DISABLED, voltha.ConnectStatus_UNKNOWN, voltha.OperStatus_UNKNOWN)
 	to = getDevice(false, voltha.AdminState_DELETED, voltha.ConnectStatus_UNKNOWN, voltha.OperStatus_UNKNOWN)
diff --git a/rw_core/core/logical_device_agent.go b/rw_core/core/logical_device_agent.go
index fc9dd92..25a073a 100644
--- a/rw_core/core/logical_device_agent.go
+++ b/rw_core/core/logical_device_agent.go
@@ -519,6 +519,34 @@
 	return nil
 }
 
+// deleteAllUNILogicalPorts deletes all UNI logical ports associated with this parent device
+func (agent *LogicalDeviceAgent) deleteAllUNILogicalPorts(ctx context.Context, parentDevice *voltha.Device) error {
+	log.Debugw("delete-all-uni-logical-ports", log.Fields{"logical-device-id": agent.logicalDeviceID})
+	agent.lockLogicalDevice.Lock()
+	defer agent.lockLogicalDevice.Unlock()
+	// Get the latest logical device info
+	ld := agent.getLogicalDeviceWithoutLock()
+
+	cloned := (proto.Clone(ld)).(*voltha.LogicalDevice)
+	updateLogicalPorts := []*voltha.LogicalPort{}
+	for _, lport := range cloned.Ports {
+		// Save NNI ports only
+		if agent.isNNIPort(lport.DevicePortNo) {
+			updateLogicalPorts = append(updateLogicalPorts, lport)
+		}
+	}
+	if len(updateLogicalPorts) < len(cloned.Ports) {
+		cloned.Ports = updateLogicalPorts
+		// Updating the logical device will trigger the port change events to be populated to the controller
+		if err := agent.updateLogicalDeviceWithoutLock(ctx, cloned); err != nil {
+			return err
+		}
+	} else {
+		log.Debugw("no-change-required", log.Fields{"logical-device-id": agent.logicalDeviceID})
+	}
+	return nil
+}
+
 //updateLogicalDeviceWithoutLock updates the model with the logical device.  It clones the logicaldevice before saving it
 func (agent *LogicalDeviceAgent) updateLogicalDeviceWithoutLock(ctx context.Context, logicalDevice *voltha.LogicalDevice) error {
 	updateCtx := context.WithValue(ctx, model.RequestTimestamp, time.Now().UnixNano())
diff --git a/rw_core/core/logical_device_manager.go b/rw_core/core/logical_device_manager.go
index 853404e..e6b8fe0 100644
--- a/rw_core/core/logical_device_manager.go
+++ b/rw_core/core/logical_device_manager.go
@@ -503,6 +503,24 @@
 	}
 	return nil
 }
+
+func (ldMgr *LogicalDeviceManager) deleteAllUNILogicalPorts(ctx context.Context, parentDevice *voltha.Device) error {
+	log.Debugw("delete-all-uni-logical-ports", log.Fields{"parent-device-id": parentDevice.Id})
+
+	var ldID *string
+	var err error
+	//Get the logical device Id for this device
+	if ldID, err = ldMgr.getLogicalDeviceID(ctx, parentDevice); err != nil {
+		return err
+	}
+	if agent := ldMgr.getLogicalDeviceAgent(ctx, *ldID); agent != nil {
+		if err := agent.deleteAllUNILogicalPorts(ctx, parentDevice); err != nil {
+			return err
+		}
+	}
+	return nil
+}
+
 func (ldMgr *LogicalDeviceManager) updatePortState(ctx context.Context, deviceID string, portNo uint32, state voltha.OperStatus_Types) error {
 	log.Debugw("updatePortState", log.Fields{"deviceId": deviceID, "state": state, "portNo": portNo})
 
diff --git a/rw_core/coreif/device_manager_if.go b/rw_core/coreif/device_manager_if.go
index 7a9e64d..60da009 100644
--- a/rw_core/coreif/device_manager_if.go
+++ b/rw_core/coreif/device_manager_if.go
@@ -39,4 +39,5 @@
 	DeleteAllChildDevices(context.Context, *voltha.Device) error
 	RunPostDeviceDelete(context.Context, *voltha.Device) error
 	ChildDeviceLost(context.Context, *voltha.Device) error
+	DeleteAllUNILogicalPorts(context.Context, *voltha.Device) error
 }
diff --git a/rw_core/mocks/device_manager.go b/rw_core/mocks/device_manager.go
index 6edfdc9..45e5af5 100644
--- a/rw_core/mocks/device_manager.go
+++ b/rw_core/mocks/device_manager.go
@@ -76,6 +76,11 @@
 	return nil
 }
 
+// DeleteAllUNILogicalPorts -
+func (dm *DeviceManager) DeleteAllUNILogicalPorts(ctx context.Context, cDevice *voltha.Device) error {
+	return nil
+}
+
 // RunPostDeviceDelete -
 func (dm *DeviceManager) RunPostDeviceDelete(ctx context.Context, cDevice *voltha.Device) error {
 	return nil