VOL-1845 : Support for delete device in openolt adapter

           This commit is for the handling of delete device.

           The changes are done to handle the request for delete
           device. This includes the clearing of all data related
           to the device in KV store and reboot of device to reset
           the device.

           This commit has dependency in voltha-go so that needs to
           be merged first. Please refer this review link
           https://gerrit.opencord.org/#/c/15084/

           Updated to dep ensure above voltha-go patch set.  Also typo
           and make lint/sca fixes.

Change-Id: I53f16022c6902d498dad30e9b7d0ff50bf156347
diff --git a/adaptercore/device_handler.go b/adaptercore/device_handler.go
index 287f927..52e4afd 100644
--- a/adaptercore/device_handler.go
+++ b/adaptercore/device_handler.go
@@ -275,6 +275,10 @@
 		}
 		if err != nil {
 			log.Infow("Failed to read from indications", log.Fields{"err": err})
+			if dh.adminState == "deleted" {
+				log.Debug("Device deleted stoping the read indication thread")
+				break
+			}
 			dh.transitionMap.Handle(DeviceDownInd)
 			dh.transitionMap.Handle(DeviceInit)
 			break
@@ -1055,6 +1059,113 @@
 	return nil
 }
 
+func (dh *DeviceHandler) clearUNIData(onu *OnuDevice, uniPorts []*voltha.Port) error {
+	var uniID uint32
+	var err error
+	for _, port := range uniPorts {
+		if port.Type == voltha.Port_ETHERNET_UNI {
+			uniID = UniIDFromPortNum(port.PortNo)
+			/* Delete tech-profile instance from the KV store */
+			if err = dh.flowMgr.DeleteTechProfileInstance(onu.intfID, onu.onuID, uniID, onu.serialNumber); err != nil {
+				log.Debugw("Failed-to-remove-tech-profile-instance-for-onu", log.Fields{"onu-id": onu.onuID})
+			}
+			log.Debugw("Deleted-tech-profile-instance-for-onu", log.Fields{"onu-id": onu.onuID})
+			flowIDs := dh.resourceMgr.GetCurrentFlowIDsForOnu(onu.intfID, onu.onuID, uniID)
+			for _, flowID := range flowIDs {
+				dh.resourceMgr.FreeFlowID(onu.intfID, int32(onu.onuID), int32(uniID), flowID)
+			}
+			dh.resourceMgr.FreePONResourcesForONU(onu.intfID, onu.onuID, uniID)
+			if err = dh.resourceMgr.RemoveTechProfileIDForOnu(onu.intfID, onu.onuID, uniID); err != nil {
+				log.Debugw("Failed-to-remove-tech-profile-id-for-onu", log.Fields{"onu-id": onu.onuID})
+			}
+			log.Debugw("Removed-tech-profile-id-for-onu", log.Fields{"onu-id": onu.onuID})
+			if err = dh.resourceMgr.RemoveMeterIDForOnu("upstream", onu.intfID, onu.onuID, uniID); err != nil {
+				log.Debugw("Failed-to-remove-meter-id-for-onu-upstream", log.Fields{"onu-id": onu.onuID})
+			}
+			log.Debugw("Removed-meter-id-for-onu-upstream", log.Fields{"onu-id": onu.onuID})
+			if err = dh.resourceMgr.RemoveMeterIDForOnu("downstream", onu.intfID, onu.onuID, uniID); err != nil {
+				log.Debugw("Failed-to-remove-meter-id-for-onu-downstream", log.Fields{"onu-id": onu.onuID})
+			}
+			log.Debugw("Removed-meter-id-for-onu-downstream", log.Fields{"onu-id": onu.onuID})
+		}
+	}
+	return nil
+}
+
+func (dh *DeviceHandler) clearNNIData() error {
+	nniUniID := -1
+	nniOnuID := -1
+	flowIDs := dh.resourceMgr.GetCurrentFlowIDsForOnu(uint32(dh.nniIntfID), uint32(nniOnuID), uint32(nniUniID))
+	log.Debugw("Current flow ids for nni", log.Fields{"flow-ids": flowIDs})
+	for _, flowID := range flowIDs {
+		dh.resourceMgr.FreeFlowID(uint32(dh.nniIntfID), -1, -1, uint32(flowID))
+	}
+	//Free the flow-ids for the NNI port
+	dh.resourceMgr.FreePONResourcesForONU(uint32(dh.nniIntfID), uint32(nniOnuID), uint32(nniUniID))
+	/* Free ONU IDs for each pon port
+	   intfIDToONUIds is a map of intf-id: [onu-ids]*/
+	intfIDToONUIds := make(map[uint32][]uint32)
+	for _, onu := range dh.onus {
+		intfIDToONUIds[onu.intfID] = append(intfIDToONUIds[onu.intfID], onu.onuID)
+	}
+	for intfID, onuIds := range intfIDToONUIds {
+		dh.resourceMgr.FreeonuID(intfID, onuIds)
+	}
+	return nil
+}
+
+// DeleteDevice deletes the device instance from openolt handler array.  Also clears allocated resource manager resources.  Also reboots the OLT hardware!
+func (dh *DeviceHandler) DeleteDevice(device *voltha.Device) error {
+	log.Debug("Function entry delete device")
+	dh.lockDevice.Lock()
+	dh.adminState = "deleted"
+	dh.lockDevice.Unlock()
+	/* Clear the KV store data associated with the all the UNI ports
+	   This clears up flow data and also resource map data for various
+	   other pon resources like alloc_id and gemport_id
+	*/
+	for _, onu := range dh.onus {
+		childDevice, err := dh.coreProxy.GetDevice(nil, dh.deviceID, onu.deviceID)
+		if err != nil {
+			log.Debug("Failed to get onu device")
+			continue
+		}
+		uniPorts := childDevice.Ports
+		log.Debugw("onu-uni-ports", log.Fields{"onu-ports": uniPorts})
+		if err := dh.clearUNIData(onu, uniPorts); err != nil {
+			log.Debugw("Failed to clear data for onu", log.Fields{"onu-device": onu})
+		}
+	}
+	/* Clear the flows from KV store associated with NNI port.
+	   There are mostly trap rules from NNI port (like LLDP)
+	*/
+	if err := dh.clearNNIData(); err != nil {
+		log.Debugw("Failed to clear data for NNI port", log.Fields{"device-id": dh.deviceID})
+	}
+	/* Clear the resource pool for each PON port*/
+	if err := dh.resourceMgr.Delete(); err != nil {
+		log.Debug("Failed-to-remove-device-from-Resource-mananger-KV-store")
+	}
+	/*Delete ONU map for the device*/
+	for onu := range dh.onus {
+		delete(dh.onus, onu)
+	}
+	log.Debug("Removed-device-from-Resource-manager-KV-store")
+	//Reset the state
+	if _, err := dh.Client.Reboot(context.Background(), new(oop.Empty)); err != nil {
+		log.Errorw("Failed-to-reboot-olt ", log.Fields{"err": err})
+		return err
+	}
+	cloned := proto.Clone(device).(*voltha.Device)
+	cloned.OperStatus = voltha.OperStatus_UNKNOWN
+	cloned.ConnectStatus = voltha.ConnectStatus_UNREACHABLE
+	if err := dh.coreProxy.DeviceStateUpdate(context.TODO(), cloned.Id, cloned.ConnectStatus, cloned.OperStatus); err != nil {
+		log.Errorw("error-updating-device-state", log.Fields{"deviceID": device.Id, "error": err})
+		return err
+	}
+	return nil
+}
+
 //RebootDevice reboots the given device
 func (dh *DeviceHandler) RebootDevice(device *voltha.Device) error {
 	if _, err := dh.Client.Reboot(context.Background(), new(oop.Empty)); err != nil {
diff --git a/adaptercore/openolt.go b/adaptercore/openolt.go
index 3d10a6f..0da66ff 100644
--- a/adaptercore/openolt.go
+++ b/adaptercore/openolt.go
@@ -240,7 +240,16 @@
 
 //Delete_device unimplemented
 func (oo *OpenOLT) Delete_device(device *voltha.Device) error {
-	return errors.New("unImplemented")
+	log.Infow("delete-device", log.Fields{"deviceId": device.Id})
+	if handler := oo.getDeviceHandler(device.Id); handler != nil {
+		if err := handler.DeleteDevice(device); err != nil {
+			log.Errorw("failed-to-handle-delete-device", log.Fields{"device-id": device.Id})
+		}
+		oo.deleteDeviceHandlerToMap(handler)
+		return nil
+	}
+	log.Errorw("device-handler-not-set", log.Fields{"deviceId": device.Id})
+	return errors.New("device-handler-not-found")
 }
 
 //Get_device_details unimplemented
diff --git a/adaptercore/openolt_flowmgr.go b/adaptercore/openolt_flowmgr.go
index 4b3be6a..55fd1df 100644
--- a/adaptercore/openolt_flowmgr.go
+++ b/adaptercore/openolt_flowmgr.go
@@ -889,6 +889,17 @@
 	return f.techprofile[intfID].GetTechProfileInstanceKVPath(TpID, uni)
 }
 
+// DeleteTechProfileInstance removes the tech profile instance from persistent storage
+func (f *OpenOltFlowMgr) DeleteTechProfileInstance(intfID uint32, onuID uint32, uniID uint32, sn string) error {
+	tpID := f.resourceMgr.GetTechProfileIDForOnu(intfID, onuID, uniID)
+	uniPortName := fmt.Sprintf("pon-{%d}/onu-{%d}/uni-{%d}", intfID, onuID, uniID)
+	if err := f.techprofile[intfID].DeleteTechProfileInstance(tpID, uniPortName); err != nil {
+		log.Debugw("Failed-to-delete-tp-instance-from-kv-store", log.Fields{"tp-id": tpID, "uni-port-name": uniPortName})
+		return err
+	}
+	return nil
+}
+
 func getFlowStoreCookie(classifier map[string]interface{}, gemPortID uint32) uint64 {
 	if len(classifier) == 0 { // should never happen
 		log.Error("Invalid classfier object")
@@ -994,7 +1005,7 @@
 
 	if err != nil {
 		log.Errorw("Failed to Add flow to device", log.Fields{"err": err, "deviceFlow": deviceFlow})
-		f.resourceMgr.FreeFlowID(intfID, uint32(deviceFlow.OnuId), uint32(deviceFlow.UniId), deviceFlow.FlowId)
+		f.resourceMgr.FreeFlowID(intfID, deviceFlow.OnuId, deviceFlow.UniId, deviceFlow.FlowId)
 		return false
 	}
 	log.Debugw("Flow added to device successfully ", log.Fields{"flow": *deviceFlow})
@@ -1109,7 +1120,7 @@
 		f.updateFlowInfoToKVStore(int32(ponIntf), int32(onuID), int32(uniID), flowID, &updatedFlows)
 		if len(updatedFlows) == 0 {
 			log.Debugw("Releasing flow Id to resource manager", log.Fields{"ponIntf": ponIntf, "onuId": onuID, "uniId": uniID, "flowId": flowID})
-			f.resourceMgr.FreeFlowID(ponIntf, onuID, uniID, flowID)
+			f.resourceMgr.FreeFlowID(ponIntf, int32(onuID), int32(uniID), flowID)
 		}
 	}
 	flowIds := f.resourceMgr.GetCurrentFlowIDsForOnu(ponIntf, onuID, uniID)
diff --git a/adaptercore/resourcemanager/resourcemanager.go b/adaptercore/resourcemanager/resourcemanager.go
index bb78ebd..4b0220b 100755
--- a/adaptercore/resourcemanager/resourcemanager.go
+++ b/adaptercore/resourcemanager/resourcemanager.go
@@ -336,27 +336,38 @@
 	ponRMgr.UpdateRanges(ponrmgr.UNI_ID_START_IDX, 0, ponrmgr.UNI_ID_END_IDX /* TODO =OpenOltPlatform.MAX_UNIS_PER_ONU-1*/, 1, "", 0, nil)
 }
 
-/* TODO
-def __del__(self):
-        self.log.info("clearing-device-resource-pool")
-        for key, resource_mgr in self.resource_mgrs.iteritems():
-            resource_mgr.clear_device_resource_pool()
+// Delete clears used resources for the particular olt device being deleted
+func (RsrcMgr *OpenOltResourceMgr) Delete() error {
+	/* TODO
+	   def __del__(self):
+	           self.log.info("clearing-device-resource-pool")
+	           for key, resource_mgr in self.resource_mgrs.iteritems():
+	               resource_mgr.clear_device_resource_pool()
 
-    def assert_pon_id_limit(self, pon_intf_id):
-        assert pon_intf_id in self.resource_mgrs
+	       def assert_pon_id_limit(self, pon_intf_id):
+	           assert pon_intf_id in self.resource_mgrs
 
-    def assert_onu_id_limit(self, pon_intf_id, onu_id):
-        self.assert_pon_id_limit(pon_intf_id)
-        self.resource_mgrs[pon_intf_id].assert_resource_limits(onu_id, PONResourceManager.ONU_ID)
+	       def assert_onu_id_limit(self, pon_intf_id, onu_id):
+	           self.assert_pon_id_limit(pon_intf_id)
+	           self.resource_mgrs[pon_intf_id].assert_resource_limits(onu_id, PONResourceManager.ONU_ID)
 
-    @property
-    def max_uni_id_per_onu(self):
-        return 0 #OpenOltPlatform.MAX_UNIS_PER_ONU-1, zero-based indexing Uncomment or override to make default multi-uni
+	       @property
+	       def max_uni_id_per_onu(self):
+	           return 0 #OpenOltPlatform.MAX_UNIS_PER_ONU-1, zero-based indexing Uncomment or override to make default multi-uni
 
-    def assert_uni_id_limit(self, pon_intf_id, onu_id, uni_id):
-        self.assert_onu_id_limit(pon_intf_id, onu_id)
-        self.resource_mgrs[pon_intf_id].assert_resource_limits(uni_id, PONResourceManager.UNI_ID)
-*/
+	       def assert_uni_id_limit(self, pon_intf_id, onu_id, uni_id):
+	           self.assert_onu_id_limit(pon_intf_id, onu_id)
+	           self.resource_mgrs[pon_intf_id].assert_resource_limits(uni_id, PONResourceManager.UNI_ID)
+	*/
+	for _, rsrcMgr := range RsrcMgr.ResourceMgrs {
+		if err := rsrcMgr.ClearDeviceResourcePool(); err != nil {
+			log.Debug("Failed to clear device resource pool")
+			return err
+		}
+	}
+	log.Debug("Cleared device resource pool")
+	return nil
+}
 
 // GetONUID returns the available OnuID for the given pon-port
 func (RsrcMgr *OpenOltResourceMgr) GetONUID(ponIntfID uint32) (uint32, error) {
@@ -374,7 +385,7 @@
 		return ONUID[0], err
 	}
 	if ONUID != nil {
-		RsrcMgr.ResourceMgrs[ponIntfID].InitResourceMap(fmt.Sprintf("%d,%d", ponIntfID, ONUID))
+		RsrcMgr.ResourceMgrs[ponIntfID].InitResourceMap(fmt.Sprintf("%d,%d", ponIntfID, ONUID[0]))
 		return ONUID[0], err
 	}
 
@@ -603,8 +614,8 @@
 }
 
 // FreeFlowID returns the free flow id for a given interface, onu id and uni id
-func (RsrcMgr *OpenOltResourceMgr) FreeFlowID(IntfID uint32, onuID uint32,
-	uniID uint32, FlowID uint32) {
+func (RsrcMgr *OpenOltResourceMgr) FreeFlowID(IntfID uint32, onuID int32,
+	uniID int32, FlowID uint32) {
 	var IntfONUID string
 	var err error
 	IntfONUID = fmt.Sprintf("%d,%d,%d", IntfID, onuID, uniID)
@@ -656,10 +667,11 @@
 	RsrcMgr.ResourceMgrs[intfID].FreeResourceID(intfID,
 		ponrmgr.FLOW_ID,
 		FlowIDs)
-	RsrcMgr.ResourceMgrs[intfID].FreeResourceID(intfID,
-		ponrmgr.ONU_ID,
-		onuIDs)
-
+	if int32(onuID) >= 0 {
+		RsrcMgr.ResourceMgrs[intfID].FreeResourceID(intfID,
+			ponrmgr.ONU_ID,
+			onuIDs)
+	}
 	// Clear resource map associated with (pon_intf_id, gemport_id) tuple.
 	RsrcMgr.ResourceMgrs[intfID].RemoveResourceMap(IntfOnuIDUniID)