[VOL-3119] Refactoring: Define string constants for all FSM events/states
correction delivery for [VOL-3038] Configuration of tech profiles 1t1gem - Response after processing with possible error indication

Signed-off-by: mpagenko <michael.pagenkopf@adtran.com>
Change-Id: I406b6e373ac7568efd856bf4b6807c6e91d16dc8
diff --git a/internal/pkg/onuadaptercore/device_handler.go b/internal/pkg/onuadaptercore/device_handler.go
index f27e3da..a580530 100644
--- a/internal/pkg/onuadaptercore/device_handler.go
+++ b/internal/pkg/onuadaptercore/device_handler.go
@@ -47,6 +47,23 @@
 )
 */
 
+const (
+	// events of Device FSM
+	devEvDeviceInit       = "devEvDeviceInit"
+	devEvGrpcConnected    = "devEvGrpcConnected"
+	devEvGrpcDisconnected = "devEvGrpcDisconnected"
+	devEvDeviceUpInd      = "devEvDeviceUpInd"
+	devEvDeviceDownInd    = "devEvDeviceDownInd"
+)
+const (
+	// states of Device FSM
+	devStNull      = "devStNull"
+	devStDown      = "devStDown"
+	devStInit      = "devStInit"
+	devStConnected = "devStConnected"
+	devStUp        = "devStUp"
+)
+
 //Event category and subcategory definitions - same as defiend for OLT in eventmgr.go  - should be done more centrally
 const (
 	pon           = voltha.EventSubCategory_PON
@@ -136,23 +153,23 @@
 
 	// Device related state machine
 	dh.pDeviceStateFsm = fsm.NewFSM(
-		"null",
+		devStNull,
 		fsm.Events{
-			{Name: "DeviceInit", Src: []string{"null", "down"}, Dst: "init"},
-			{Name: "GrpcConnected", Src: []string{"init"}, Dst: "connected"},
-			{Name: "GrpcDisconnected", Src: []string{"connected", "down"}, Dst: "init"},
-			{Name: "DeviceUpInd", Src: []string{"connected", "down"}, Dst: "up"},
-			{Name: "DeviceDownInd", Src: []string{"up"}, Dst: "down"},
+			{Name: devEvDeviceInit, Src: []string{devStNull, devStDown}, Dst: devStInit},
+			{Name: devEvGrpcConnected, Src: []string{devStInit}, Dst: devStConnected},
+			{Name: devEvGrpcDisconnected, Src: []string{devStConnected, devStDown}, Dst: devStInit},
+			{Name: devEvDeviceUpInd, Src: []string{devStConnected, devStDown}, Dst: devStUp},
+			{Name: devEvDeviceDownInd, Src: []string{devStUp}, Dst: devStDown},
 		},
 		fsm.Callbacks{
-			"before_event":            func(e *fsm.Event) { dh.logStateChange(e) },
-			"before_DeviceInit":       func(e *fsm.Event) { dh.doStateInit(e) },
-			"after_DeviceInit":        func(e *fsm.Event) { dh.postInit(e) },
-			"before_GrpcConnected":    func(e *fsm.Event) { dh.doStateConnected(e) },
-			"before_GrpcDisconnected": func(e *fsm.Event) { dh.doStateInit(e) },
-			"after_GrpcDisconnected":  func(e *fsm.Event) { dh.postInit(e) },
-			"before_DeviceUpInd":      func(e *fsm.Event) { dh.doStateUp(e) },
-			"before_DeviceDownInd":    func(e *fsm.Event) { dh.doStateDown(e) },
+			"before_event":                      func(e *fsm.Event) { dh.logStateChange(e) },
+			("before_" + devEvDeviceInit):       func(e *fsm.Event) { dh.doStateInit(e) },
+			("after_" + devEvDeviceInit):        func(e *fsm.Event) { dh.postInit(e) },
+			("before_" + devEvGrpcConnected):    func(e *fsm.Event) { dh.doStateConnected(e) },
+			("before_" + devEvGrpcDisconnected): func(e *fsm.Event) { dh.doStateInit(e) },
+			("after_" + devEvGrpcDisconnected):  func(e *fsm.Event) { dh.postInit(e) },
+			("before_" + devEvDeviceUpInd):      func(e *fsm.Event) { dh.doStateUp(e) },
+			("before_" + devEvDeviceDownInd):    func(e *fsm.Event) { dh.doStateDown(e) },
 		},
 	)
 
@@ -180,8 +197,8 @@
 	logger.Debugw("Adopt_device", log.Fields{"deviceID": device.Id, "Address": device.GetHostAndPort()})
 
 	logger.Debugw("Device FSM: ", log.Fields{"state": string(dh.pDeviceStateFsm.Current())})
-	if dh.pDeviceStateFsm.Is("null") {
-		if err := dh.pDeviceStateFsm.Event("DeviceInit"); err != nil {
+	if dh.pDeviceStateFsm.Is(devStNull) {
+		if err := dh.pDeviceStateFsm.Event(devEvDeviceInit); err != nil {
 			logger.Errorw("Device FSM: Can't go to state DeviceInit", log.Fields{"err": err})
 		}
 		logger.Debugw("Device FSM: ", log.Fields{"state": string(dh.pDeviceStateFsm.Current())})
@@ -270,6 +287,11 @@
 					log.Fields{"deviceID": dh.deviceID})
 				return errors.New("TechProfile DLMsg request while onuTechProf instance not setup")
 			}
+			if (dh.deviceReason == "stopping-openomci") || (dh.deviceReason == "omci-admin-lock") {
+				// I've seen cases for this request, where the device was already stopped
+				logger.Warnw("TechProf stopped: device-unreachable", log.Fields{"deviceId": dh.deviceID})
+				return errors.New("device-unreachable")
+			}
 
 			msgBody := msg.GetBody()
 			techProfMsg := &ic.InterAdapterTechProfileDownloadMessage{}
@@ -296,16 +318,20 @@
 				deadline := time.Now().Add(30 * time.Second) //allowed run time to finish before execution
 				dctx, cancel := context.WithDeadline(context.Background(), deadline)
 
+				dh.pOnuTP.resetProcessingErrorIndication()
 				var wg sync.WaitGroup
 				wg.Add(2) // for the 2 go routines to finish
 				// attention: deadline completion check and wg.Done is to be done in both routines
 				go dh.pOnuTP.configureUniTp(dctx, techProfMsg.UniId, techProfMsg.Path, &wg)
 				go dh.pOnuTP.updateOnuTpPathKvStore(dctx, &wg)
 				//the wait.. function is responsible for tpProcMutex.Unlock()
-				go dh.pOnuTP.waitForTpCompletion(cancel, &wg) //let that also run off-line to let the IA messaging return!
-			} else {
-				dh.pOnuTP.unlockTpProcMutex()
+				err := dh.pOnuTP.waitForTpCompletion(cancel, &wg) //wait for background process to finish and collet their result
+				return err
 			}
+			// no change, nothing really to do
+			dh.pOnuTP.unlockTpProcMutex()
+			//return success
+			return nil
 		}
 	case ic.InterAdapterMessageType_DELETE_GEM_PORT_REQUEST:
 		{
@@ -331,12 +357,14 @@
 			deadline := time.Now().Add(10 * time.Second) //allowed run time to finish before execution
 			dctx, cancel := context.WithDeadline(context.Background(), deadline)
 
+			dh.pOnuTP.resetProcessingErrorIndication()
 			var wg sync.WaitGroup
 			wg.Add(1) // for the 1 go routine to finish
 			go dh.pOnuTP.deleteTpResource(dctx, delGemPortMsg.UniId, delGemPortMsg.TpPath,
 				cResourceGemPort, delGemPortMsg.GemPortId, &wg)
 			//the wait.. function is responsible for tpProcMutex.Unlock()
-			go dh.pOnuTP.waitForTpCompletion(cancel, &wg) //let that also run off-line to let the IA messaging return!
+			err := dh.pOnuTP.waitForTpCompletion(cancel, &wg) //let that also run off-line to let the IA messaging return!
+			return err
 		}
 	case ic.InterAdapterMessageType_DELETE_TCONT_REQUEST:
 		{
@@ -362,6 +390,7 @@
 				deadline := time.Now().Add(10 * time.Second) //allowed run time to finish before execution
 				dctx, cancel := context.WithDeadline(context.Background(), deadline)
 
+				dh.pOnuTP.resetProcessingErrorIndication()
 				var wg sync.WaitGroup
 				wg.Add(2) // for the 2 go routines to finish
 				go dh.pOnuTP.deleteTpResource(dctx, delTcontMsg.UniId, delTcontMsg.TpPath,
@@ -369,10 +398,12 @@
 				// Removal of the tcont/alloc id mapping represents the removal of the tech profile
 				go dh.pOnuTP.updateOnuTpPathKvStore(dctx, &wg)
 				//the wait.. function is responsible for tpProcMutex.Unlock()
-				go dh.pOnuTP.waitForTpCompletion(cancel, &wg) //let that also run off-line to let the IA messaging return!
-			} else {
-				dh.pOnuTP.unlockTpProcMutex()
+				err := dh.pOnuTP.waitForTpCompletion(cancel, &wg) //let that also run off-line to let the IA messaging return!
+				return err
 			}
+			dh.pOnuTP.unlockTpProcMutex()
+			//return success
+			return nil
 		}
 	default:
 		{
@@ -866,11 +897,16 @@
 	// PM related heartbeat??? !!!TODO....
 	//self._heartbeat.enabled = True
 
-	//call MibUploadFSM - transition up to state "in_sync"
+	/* Note: Even though FSM calls look 'synchronous' here, FSM is running in background with the effect that possible errors
+	 * 	 within the MibUpload are not notified in the OnuIndication response, this might be acceptable here,
+	 *   as further OltAdapter processing may rely on the deviceReason event 'MibUploadDone' as a result of the FSM processing
+	 *   otherwise some processing synchronisation would be required - cmp. e.g TechProfile processing
+	 */
+	//call MibUploadFSM - transition up to state ulStInSync
 	pMibUlFsm := pDevEntry.pMibUploadFsm.pFsm
 	if pMibUlFsm != nil {
-		if pMibUlFsm.Is("disabled") {
-			if err := pMibUlFsm.Event("start"); err != nil {
+		if pMibUlFsm.Is(ulStDisabled) {
+			if err := pMibUlFsm.Event(ulEvStart); err != nil {
 				logger.Errorw("MibSyncFsm: Can't go to state starting", log.Fields{"err": err})
 				return errors.New("Can't go to state starting")
 			} else {
@@ -878,18 +914,18 @@
 				//Determine ONU status and start/re-start MIB Synchronization tasks
 				//Determine if this ONU has ever synchronized
 				if true { //TODO: insert valid check
-					if err := pMibUlFsm.Event("reset_mib"); err != nil {
+					if err := pMibUlFsm.Event(ulEvResetMib); err != nil {
 						logger.Errorw("MibSyncFsm: Can't go to state resetting_mib", log.Fields{"err": err})
 						return errors.New("Can't go to state resetting_mib")
 					}
 				} else {
-					pMibUlFsm.Event("examine_mds")
+					pMibUlFsm.Event(ulEvExamineMds)
 					logger.Debugw("state of MibSyncFsm", log.Fields{"state": string(pMibUlFsm.Current())})
 					//Examine the MIB Data Sync
 					// callbacks to be handled:
-					// Event("success")
-					// Event("timeout")
-					// Event("mismatch")
+					// Event(ulEvSuccess)
+					// Event(ulEvTimeout)
+					// Event(ulEvMismatch)
 				}
 			}
 		} else {
@@ -919,29 +955,29 @@
 			{ //MIBSync FSM may run
 				pMibUlFsm := pDevEntry.pMibUploadFsm.pFsm
 				if pMibUlFsm != nil {
-					pMibUlFsm.Event("stop") //TODO!! verify if MibSyncFsm stop-processing is sufficient (to allow it again afterwards)
+					pMibUlFsm.Event(ulEvStop) //TODO!! verify if MibSyncFsm stop-processing is sufficient (to allow it again afterwards)
 				}
 			}
 		case "discovery-mibsync-complete":
 			{ //MibDownload may run
 				pMibDlFsm := pDevEntry.pMibDownloadFsm.pFsm
 				if pMibDlFsm != nil {
-					pMibDlFsm.Event("reset")
+					pMibDlFsm.Event(dlEvReset)
 				}
 			}
 		default:
 			{
 				//port lock/unlock FSM's may be active
 				if dh.pUnlockStateFsm != nil {
-					dh.pUnlockStateFsm.pAdaptFsm.pFsm.Event("reset")
+					dh.pUnlockStateFsm.pAdaptFsm.pFsm.Event(uniEvReset)
 				}
 				if dh.pLockStateFsm != nil {
-					dh.pLockStateFsm.pAdaptFsm.pFsm.Event("reset")
+					dh.pLockStateFsm.pAdaptFsm.pFsm.Event(uniEvReset)
 				}
 				//techProfile related PonAniConfigFsm FSM may be active
 				// maybe encapsulated as OnuTP method - perhaps later in context of module splitting
 				if dh.pOnuTP.pAniConfigFsm != nil {
-					dh.pOnuTP.pAniConfigFsm.pAdaptFsm.pFsm.Event("reset")
+					dh.pOnuTP.pAniConfigFsm.pAdaptFsm.pFsm.Event(aniEvReset)
 				}
 			}
 			//TODO!!! care about PM/Alarm processing once started
@@ -1055,14 +1091,14 @@
 			 */
 			pMibDlFsm := pDevEntry.pMibDownloadFsm.pFsm
 			if pMibDlFsm != nil {
-				if pMibDlFsm.Is("disabled") {
-					if err := pMibDlFsm.Event("start"); err != nil {
+				if pMibDlFsm.Is(dlStDisabled) {
+					if err := pMibDlFsm.Event(dlEvStart); err != nil {
 						logger.Errorw("MibDownloadFsm: Can't go to state starting", log.Fields{"err": err})
 						// maybe try a FSM reset and then again ... - TODO!!!
 					} else {
 						logger.Debugw("MibDownloadFsm", log.Fields{"state": string(pMibDlFsm.Current())})
 						// maybe use more specific states here for the specific download steps ...
-						if err := pMibDlFsm.Event("create_gal"); err != nil {
+						if err := pMibDlFsm.Event(dlEvCreateGal); err != nil {
 							logger.Errorw("MibDownloadFsm: Can't start CreateGal", log.Fields{"err": err})
 						} else {
 							logger.Debugw("state of MibDownloadFsm", log.Fields{"state": string(pMibDlFsm.Current())})
@@ -1283,20 +1319,20 @@
 		pLSStatemachine = dh.pLockStateFsm.pAdaptFsm.pFsm
 		//make sure the opposite FSM is not running and if so, terminate it as not relevant anymore
 		if (dh.pUnlockStateFsm != nil) &&
-			(dh.pUnlockStateFsm.pAdaptFsm.pFsm.Current() != "disabled") {
-			dh.pUnlockStateFsm.pAdaptFsm.pFsm.Event("reset")
+			(dh.pUnlockStateFsm.pAdaptFsm.pFsm.Current() != uniStDisabled) {
+			dh.pUnlockStateFsm.pAdaptFsm.pFsm.Event(uniEvReset)
 		}
 	} else {
 		pLSStatemachine = dh.pUnlockStateFsm.pAdaptFsm.pFsm
 		//make sure the opposite FSM is not running and if so, terminate it as not relevant anymore
 		if (dh.pLockStateFsm != nil) &&
-			(dh.pLockStateFsm.pAdaptFsm.pFsm.Current() != "disabled") {
-			dh.pLockStateFsm.pAdaptFsm.pFsm.Event("reset")
+			(dh.pLockStateFsm.pAdaptFsm.pFsm.Current() != uniStDisabled) {
+			dh.pLockStateFsm.pAdaptFsm.pFsm.Event(uniEvReset)
 		}
 	}
 	if pLSStatemachine != nil {
-		if pLSStatemachine.Is("disabled") {
-			if err := pLSStatemachine.Event("start"); err != nil {
+		if pLSStatemachine.Is(uniStDisabled) {
+			if err := pLSStatemachine.Event(uniEvStart); err != nil {
 				logger.Warnw("LockStateFSM: can't start", log.Fields{"err": err})
 				// maybe try a FSM reset and then again ... - TODO!!!
 			} else {