[VOL-3834] Avoid ONU service disruption on adapter restart

Change-Id: I21d15b09bdbfe2900edccefac9a72e498d2da9d7
diff --git a/internal/pkg/onuadaptercore/mib_sync.go b/internal/pkg/onuadaptercore/mib_sync.go
index 0c71848..9880cb5 100644
--- a/internal/pkg/onuadaptercore/mib_sync.go
+++ b/internal/pkg/onuadaptercore/mib_sync.go
@@ -128,71 +128,15 @@
 	oo.PDevOmciCC.pLastTxMeInstance = meInstance
 }
 
-func (oo *OnuDeviceEntry) enterGettingMibTemplate(ctx context.Context, e *fsm.Event) {
+func (oo *OnuDeviceEntry) enterGettingMibTemplateState(ctx context.Context, e *fsm.Event) {
 
 	if oo.onuSwImageIndications.activeEntityEntry.valid {
-		oo.activeSwVersion = oo.onuSwImageIndications.activeEntityEntry.version
+		oo.sOnuPersistentData.PersActiveSwVersion = oo.onuSwImageIndications.activeEntityEntry.version
 	} else {
 		logger.Errorw(ctx, "get-mib-template: no active SW version found, working with empty SW version, which might be untrustworthy",
 			log.Fields{"device-id": oo.deviceID})
 	}
-
-	meStoredFromTemplate := false
-	oo.mibTemplatePath = fmt.Sprintf(cSuffixMibTemplateKvStore, oo.vendorID, oo.equipmentID, oo.activeSwVersion)
-	logger.Debugw(ctx, "MibSync FSM - MibTemplate - etcd search string", log.Fields{"path": fmt.Sprintf("%s/%s", cBasePathMibTemplateKvStore, oo.mibTemplatePath)})
-	Value, err := oo.mibTemplateKVStore.Get(log.WithSpanFromContext(context.TODO(), ctx), oo.mibTemplatePath)
-	if err == nil {
-		if Value != nil {
-			logger.Debugf(ctx, "MibSync FSM - MibTemplate read: Key: %s, Value: %s  %s", Value.Key, Value.Value)
-
-			// swap out tokens with specific data
-			mibTmpString, _ := kvstore.ToString(Value.Value)
-			mibTmpString2 := strings.Replace(mibTmpString, "%SERIAL_NUMBER%", oo.serialNumber, -1)
-			mibTmpString = strings.Replace(mibTmpString2, "%MAC_ADDRESS%", oo.macAddress, -1)
-			mibTmpBytes := []byte(mibTmpString)
-			logger.Debugf(ctx, "MibSync FSM - MibTemplate tokens swapped out: %s", mibTmpBytes)
-
-			var firstLevelMap map[string]interface{}
-			if err = json.Unmarshal(mibTmpBytes, &firstLevelMap); err != nil {
-				logger.Errorw(ctx, "MibSync FSM - Failed to unmarshal template", log.Fields{"error": err, "device-id": oo.deviceID})
-			} else {
-				for firstLevelKey, firstLevelValue := range firstLevelMap {
-					//logger.Debugw(ctx, "MibSync FSM - firstLevelKey", log.Fields{"firstLevelKey": firstLevelKey})
-					if uint16ValidNumber, err := strconv.ParseUint(firstLevelKey, 10, 16); err == nil {
-						meClassID := me.ClassID(uint16ValidNumber)
-						//logger.Debugw(ctx, "MibSync FSM - firstLevelKey is a number in uint16-range", log.Fields{"uint16ValidNumber": uint16ValidNumber})
-						if isSupportedClassID(meClassID) {
-							//logger.Debugw(ctx, "MibSync FSM - firstLevelKey is a supported classID", log.Fields{"meClassID": meClassID})
-							secondLevelMap := firstLevelValue.(map[string]interface{})
-							for secondLevelKey, secondLevelValue := range secondLevelMap {
-								//logger.Debugw(ctx, "MibSync FSM - secondLevelKey", log.Fields{"secondLevelKey": secondLevelKey})
-								if uint16ValidNumber, err := strconv.ParseUint(secondLevelKey, 10, 16); err == nil {
-									meEntityID := uint16(uint16ValidNumber)
-									//logger.Debugw(ctx, "MibSync FSM - secondLevelKey is a number and a valid EntityId", log.Fields{"meEntityID": meEntityID})
-									thirdLevelMap := secondLevelValue.(map[string]interface{})
-									for thirdLevelKey, thirdLevelValue := range thirdLevelMap {
-										if thirdLevelKey == "Attributes" {
-											//logger.Debugw(ctx, "MibSync FSM - thirdLevelKey refers to attributes", log.Fields{"thirdLevelKey": thirdLevelKey})
-											attributesMap := thirdLevelValue.(map[string]interface{})
-											//logger.Debugw(ctx, "MibSync FSM - attributesMap", log.Fields{"attributesMap": attributesMap})
-											oo.pOnuDB.PutMe(ctx, meClassID, meEntityID, attributesMap)
-											meStoredFromTemplate = true
-										}
-									}
-								}
-							}
-						}
-					}
-				}
-			}
-		} else {
-			logger.Debugw(ctx, "No MIB template found", log.Fields{"path": oo.mibTemplatePath, "device-id": oo.deviceID})
-		}
-	} else {
-		logger.Errorf(ctx, "Get from kvstore operation failed for path",
-			log.Fields{"path": oo.mibTemplatePath, "device-id": oo.deviceID})
-	}
-	if meStoredFromTemplate {
+	if oo.getMibFromTemplate(ctx) {
 		logger.Debug(ctx, "MibSync FSM - valid MEs stored from template")
 		oo.pOnuDB.logMeDb(ctx)
 		fsmMsg = LoadMibTemplateOk
@@ -248,14 +192,7 @@
 
 func (oo *OnuDeviceEntry) enterExaminingMdsState(ctx context.Context, e *fsm.Event) {
 	logger.Debugw(ctx, "MibSync FSM", log.Fields{"Start GetMds processing in State": e.FSM.Current(), "device-id": oo.deviceID})
-	// TODO: As long as story VOL-3834 "Avoid ONU service distruption on adapter restart" is not finished,
-	// we need a full configuration cycle of the ONU to reconcile all local FSM data.
-	// Therefore we simulate a failed MDS check here to trigger this config
-	//oo.requestMdsValue(ctx)
-	logger.Debugw(ctx, "MibSync FSM - MDS examination failed - new provisioning", log.Fields{"device-id": oo.deviceID})
-	go func() {
-		_ = oo.pMibUploadFsm.pFsm.Event(ulEvMismatch)
-	}()
+	oo.requestMdsValue(ctx)
 }
 
 func (oo *OnuDeviceEntry) enterResynchronizingState(ctx context.Context, e *fsm.Event) {
@@ -268,6 +205,43 @@
 	// VOL-3793 - ONU-reconcile handling after adapter restart based on mib resync
 }
 
+func (oo *OnuDeviceEntry) enterExaminingMdsSuccessState(ctx context.Context, e *fsm.Event) {
+	logger.Debugw(ctx, "MibSync FSM",
+		log.Fields{"Start processing on examining MDS success in State": e.FSM.Current(), "device-id": oo.deviceID})
+
+	if oo.getMibFromTemplate(ctx) {
+		oo.baseDeviceHandler.startReconciling(ctx, true)
+		oo.baseDeviceHandler.addAllUniPorts(ctx)
+		oo.baseDeviceHandler.setDeviceReason(drInitialMibDownloaded)
+		oo.baseDeviceHandler.ReadyForSpecificOmciConfig = true
+		// no need to reconcile additional data for MibDownloadFsm, LockStateFsm, or UnlockStateFsm
+
+		oo.baseDeviceHandler.reconcileDeviceTechProf(ctx)
+		if oo.baseDeviceHandler.isReconciling() {
+			oo.baseDeviceHandler.reconcileDeviceFlowConfig(ctx)
+		}
+		// set admin state independent of reconciling state after tp/flow reconcilement
+		if oo.sOnuPersistentData.PersUniDisableDone {
+			oo.baseDeviceHandler.disableUniPortStateUpdate(ctx)
+			oo.baseDeviceHandler.setDeviceReason(drOmciAdminLock)
+		} else {
+			oo.baseDeviceHandler.enableUniPortStateUpdate(ctx)
+		}
+		oo.baseDeviceHandler.stopReconciling(ctx)
+		go func() {
+			_ = oo.pMibUploadFsm.pFsm.Event(ulEvSuccess)
+		}()
+
+	} else {
+		logger.Debugw(ctx, "MibSync FSM",
+			log.Fields{"Getting MIB from template not successful": e.FSM.Current(), "device-id": oo.deviceID})
+		go func() {
+			//switch to reconciling with OMCI config
+			_ = oo.pMibUploadFsm.pFsm.Event(ulEvMismatch)
+		}()
+	}
+}
+
 func (oo *OnuDeviceEntry) enterAuditingState(ctx context.Context, e *fsm.Event) {
 	logger.Debugw(ctx, "MibSync FSM", log.Fields{"Start MibAudit processing in State": e.FSM.Current(), "device-id": oo.deviceID})
 	if oo.baseDeviceHandler.checkAuditStartCondition(ctx, cUploadFsm) {
@@ -455,25 +429,25 @@
 			logger.Debugf(ctx, "MibSync FSM - GetResponse Data for %s", log.Fields{"device-id": oo.deviceID, "data-fields": msgObj}, meInstance)
 			switch meInstance {
 			case "OnuG":
-				oo.vendorID = trimStringFromInterface(meAttributes["VendorId"])
+				oo.sOnuPersistentData.PersVendorID = trimStringFromInterface(meAttributes["VendorId"])
 				snBytes, _ := me.InterfaceToOctets(meAttributes["SerialNumber"])
 				if onugSerialNumberLen == len(snBytes) {
 					snVendorPart := fmt.Sprintf("%s", snBytes[:4])
 					snNumberPart := hex.EncodeToString(snBytes[4:])
-					oo.serialNumber = snVendorPart + snNumberPart
+					oo.sOnuPersistentData.PersSerialNumber = snVendorPart + snNumberPart
 					logger.Debugw(ctx, "MibSync FSM - GetResponse Data for Onu-G - VendorId/SerialNumber", log.Fields{"device-id": oo.deviceID,
-						"onuDeviceEntry.vendorID": oo.vendorID, "onuDeviceEntry.serialNumber": oo.serialNumber})
+						"onuDeviceEntry.vendorID": oo.sOnuPersistentData.PersVendorID, "onuDeviceEntry.serialNumber": oo.sOnuPersistentData.PersSerialNumber})
 				} else {
 					logger.Infow(ctx, "MibSync FSM - SerialNumber has wrong length - fill serialNumber with zeros", log.Fields{"device-id": oo.deviceID, "length": len(snBytes)})
-					oo.serialNumber = cEmptySerialNumberString
+					oo.sOnuPersistentData.PersSerialNumber = cEmptySerialNumberString
 				}
 				// trigger retrieval of EquipmentId
 				_ = oo.pMibUploadFsm.pFsm.Event(ulEvGetEquipmentID)
 				return nil
 			case "Onu2G":
-				oo.equipmentID = trimStringFromInterface(meAttributes["EquipmentId"])
+				oo.sOnuPersistentData.PersEquipmentID = trimStringFromInterface(meAttributes["EquipmentId"])
 				logger.Debugw(ctx, "MibSync FSM - GetResponse Data for Onu2-G - EquipmentId", log.Fields{"device-id": oo.deviceID,
-					"onuDeviceEntry.equipmentID": oo.equipmentID})
+					"onuDeviceEntry.equipmentID": oo.sOnuPersistentData.PersEquipmentID})
 				// trigger retrieval of 1st SW-image info
 				_ = oo.pMibUploadFsm.pFsm.Event(ulEvGetFirstSwVersion)
 				return nil
@@ -490,12 +464,12 @@
 			case "IpHostConfigData":
 				macBytes, _ := me.InterfaceToOctets(meAttributes["MacAddress"])
 				if omciMacAddressLen == len(macBytes) {
-					oo.macAddress = hex.EncodeToString(macBytes[:])
+					oo.sOnuPersistentData.PersMacAddress = hex.EncodeToString(macBytes[:])
 					logger.Debugw(ctx, "MibSync FSM - GetResponse Data for IpHostConfigData - MacAddress", log.Fields{"device-id": oo.deviceID,
-						"onuDeviceEntry.macAddress": oo.macAddress})
+						"macAddress": oo.sOnuPersistentData.PersMacAddress})
 				} else {
 					logger.Infow(ctx, "MibSync FSM - MacAddress wrong length - fill macAddress with zeros", log.Fields{"device-id": oo.deviceID, "length": len(macBytes)})
-					oo.macAddress = cEmptyMacAddrString
+					oo.sOnuPersistentData.PersMacAddress = cEmptyMacAddrString
 				}
 				// trigger retrieval of mib template
 				_ = oo.pMibUploadFsm.pFsm.Event(ulEvGetMibTemplate)
@@ -523,7 +497,7 @@
 	imageVersion := trimStringFromInterface(meAttributes["Version"])
 	logger.Infow(ctx, "MibSync FSM - GetResponse Data for SoftwareImage",
 		log.Fields{"device-id": oo.deviceID, "entityID": entityID,
-			"version": imageVersion, "isActive": imageIsActive, "isCommitted": imageIsCommitted, "SNR": oo.serialNumber})
+			"version": imageVersion, "isActive": imageIsActive, "isCommitted": imageIsCommitted, "SNR": oo.sOnuPersistentData.PersSerialNumber})
 	if firstSwImageMeID == entityID {
 		//always accept the state of the first image (2nd image info should not yet be available)
 		if imageIsActive == swIsActive {
@@ -614,7 +588,7 @@
 			case "IpHostConfigData":
 				logger.Debugw(ctx, "MibSync FSM - erroneous result for IpHostConfigData received - ONU doesn't support ME - fill macAddress with zeros",
 					log.Fields{"device-id": oo.deviceID, "data-fields": msgObj})
-				oo.macAddress = cEmptyMacAddrString
+				oo.sOnuPersistentData.PersMacAddress = cEmptyMacAddrString
 				// trigger retrieval of mib template
 				_ = oo.pMibUploadFsm.pFsm.Event(ulEvGetMibTemplate)
 				return nil
@@ -743,9 +717,9 @@
 	logger.Debugw(ctx, "MibSync FSM - GetResponse Data for Onu-Data - MibDataSync", log.Fields{"device-id": oo.deviceID,
 		"mibDataSyncOnu": mibDataSyncOnu, "PersMibDataSyncAdpt": oo.sOnuPersistentData.PersMibDataSyncAdpt})
 
-	mdsCheckOk := oo.sOnuPersistentData.PersMibDataSyncAdpt == mibDataSyncOnu
+	mdsValuesAreEqual := oo.sOnuPersistentData.PersMibDataSyncAdpt == mibDataSyncOnu
 	if oo.pMibUploadFsm.pFsm.Is(ulStAuditing) {
-		if mdsCheckOk {
+		if mdsValuesAreEqual {
 			logger.Debugw(ctx, "MibSync FSM - mib audit - MDS check ok", log.Fields{"device-id": oo.deviceID})
 			_ = oo.pMibUploadFsm.pFsm.Event(ulEvSuccess)
 		} else {
@@ -753,7 +727,7 @@
 			_ = oo.pMibUploadFsm.pFsm.Event(ulEvMismatch)
 		}
 	} else if oo.pMibUploadFsm.pFsm.Is(ulStReAuditing) {
-		if mdsCheckOk {
+		if mdsValuesAreEqual {
 			logger.Debugw(ctx, "MibSync FSM - mib reaudit - MDS check ok", log.Fields{"device-id": oo.deviceID})
 			_ = oo.pMibUploadFsm.pFsm.Event(ulEvSuccess)
 		} else {
@@ -762,7 +736,7 @@
 			_ = oo.pMibUploadFsm.pFsm.Event(ulEvMismatch)
 		}
 	} else if oo.pMibUploadFsm.pFsm.Is(ulStExaminingMds) {
-		if mdsCheckOk {
+		if mdsValuesAreEqual && mibDataSyncOnu != 0 {
 			logger.Debugw(ctx, "MibSync FSM - MDS examination ok", log.Fields{"device-id": oo.deviceID})
 			_ = oo.pMibUploadFsm.pFsm.Event(ulEvSuccess)
 		} else {
@@ -801,3 +775,63 @@
 	}
 	return false //all other case are treated as 'nothing to commit
 }
+func (oo *OnuDeviceEntry) getMibFromTemplate(ctx context.Context) bool {
+
+	oo.mibTemplatePath = oo.buildMibTemplatePath()
+	logger.Debugw(ctx, "MibSync FSM - get Mib from template", log.Fields{"path": fmt.Sprintf("%s/%s", cBasePathMibTemplateKvStore, oo.mibTemplatePath)})
+
+	restoredFromMibTemplate := false
+	Value, err := oo.mibTemplateKVStore.Get(log.WithSpanFromContext(context.TODO(), ctx), oo.mibTemplatePath)
+	if err == nil {
+		if Value != nil {
+			logger.Debugf(ctx, "MibSync FSM - Mib template read: Key: %s, Value: %s  %s", Value.Key, Value.Value)
+
+			// swap out tokens with specific data
+			mibTmpString, _ := kvstore.ToString(Value.Value)
+			mibTmpString2 := strings.Replace(mibTmpString, "%SERIAL_NUMBER%", oo.sOnuPersistentData.PersSerialNumber, -1)
+			mibTmpString = strings.Replace(mibTmpString2, "%MAC_ADDRESS%", oo.sOnuPersistentData.PersMacAddress, -1)
+			mibTmpBytes := []byte(mibTmpString)
+			logger.Debugf(ctx, "MibSync FSM - Mib template tokens swapped out: %s", mibTmpBytes)
+
+			var firstLevelMap map[string]interface{}
+			if err = json.Unmarshal(mibTmpBytes, &firstLevelMap); err != nil {
+				logger.Errorw(ctx, "MibSync FSM - Failed to unmarshal template", log.Fields{"error": err, "device-id": oo.deviceID})
+			} else {
+				for firstLevelKey, firstLevelValue := range firstLevelMap {
+					//logger.Debugw(ctx, "MibSync FSM - firstLevelKey", log.Fields{"firstLevelKey": firstLevelKey})
+					if uint16ValidNumber, err := strconv.ParseUint(firstLevelKey, 10, 16); err == nil {
+						meClassID := me.ClassID(uint16ValidNumber)
+						//logger.Debugw(ctx, "MibSync FSM - firstLevelKey is a number in uint16-range", log.Fields{"uint16ValidNumber": uint16ValidNumber})
+						if isSupportedClassID(meClassID) {
+							//logger.Debugw(ctx, "MibSync FSM - firstLevelKey is a supported classID", log.Fields{"meClassID": meClassID})
+							secondLevelMap := firstLevelValue.(map[string]interface{})
+							for secondLevelKey, secondLevelValue := range secondLevelMap {
+								//logger.Debugw(ctx, "MibSync FSM - secondLevelKey", log.Fields{"secondLevelKey": secondLevelKey})
+								if uint16ValidNumber, err := strconv.ParseUint(secondLevelKey, 10, 16); err == nil {
+									meEntityID := uint16(uint16ValidNumber)
+									//logger.Debugw(ctx, "MibSync FSM - secondLevelKey is a number and a valid EntityId", log.Fields{"meEntityID": meEntityID})
+									thirdLevelMap := secondLevelValue.(map[string]interface{})
+									for thirdLevelKey, thirdLevelValue := range thirdLevelMap {
+										if thirdLevelKey == "Attributes" {
+											//logger.Debugw(ctx, "MibSync FSM - thirdLevelKey refers to attributes", log.Fields{"thirdLevelKey": thirdLevelKey})
+											attributesMap := thirdLevelValue.(map[string]interface{})
+											//logger.Debugw(ctx, "MibSync FSM - attributesMap", log.Fields{"attributesMap": attributesMap})
+											oo.pOnuDB.PutMe(ctx, meClassID, meEntityID, attributesMap)
+											restoredFromMibTemplate = true
+										}
+									}
+								}
+							}
+						}
+					}
+				}
+			}
+		} else {
+			logger.Debugw(ctx, "No MIB template found", log.Fields{"path": oo.mibTemplatePath, "device-id": oo.deviceID})
+		}
+	} else {
+		logger.Errorf(ctx, "Get from kvstore operation failed for path",
+			log.Fields{"path": oo.mibTemplatePath, "device-id": oo.deviceID})
+	}
+	return restoredFromMibTemplate
+}