VOL-4147
Add support of setting operation state to RECONCILE_FAILED from adapters

Change-Id: I2fb7e8ef2227d8c31a6612b92d1fd8bcabe6fdaa
diff --git a/internal/pkg/onuadaptercore/device_handler.go b/internal/pkg/onuadaptercore/device_handler.go
index 96e0ca7..59d3236 100644
--- a/internal/pkg/onuadaptercore/device_handler.go
+++ b/internal/pkg/onuadaptercore/device_handler.go
@@ -135,6 +135,9 @@
 	drRebooting                        = 10
 	drOmciFlowsDeleted                 = 11
 	drTechProfileConfigDeleteSuccess   = 12
+	drReconcileFailed                  = 13
+	drReconcileMaxTimeout              = 14
+	drReconcileCanceled                = 15
 )
 
 var deviceReasonMap = map[uint8]string{
@@ -151,6 +154,9 @@
 	drRebooting:                        "rebooting",
 	drOmciFlowsDeleted:                 "omci-flows-deleted",
 	drTechProfileConfigDeleteSuccess:   "tech-profile-config-delete-success",
+	drReconcileFailed:                  "reconcile-failed",
+	drReconcileMaxTimeout:              "reconcile-max-timeout",
+	drReconcileCanceled:                "reconciling-canceled",
 }
 
 const (
@@ -3530,6 +3536,9 @@
 func (dh *deviceHandler) startReconciling(ctx context.Context, skipOnuConfig bool) {
 	logger.Debugw(ctx, "start reconciling", log.Fields{"skipOnuConfig": skipOnuConfig, "device-id": dh.deviceID})
 
+	connectStatus := voltha.ConnectStatus_UNREACHABLE
+	operState := voltha.OperStatus_UNKNOWN
+
 	if !dh.isReconciling() {
 		go func() {
 			logger.Debugw(ctx, "wait for channel signal or timeout",
@@ -3541,8 +3550,6 @@
 						logger.Errorw(ctx, "No valid OnuDevice - aborting Core DeviceStateUpdate",
 							log.Fields{"device-id": dh.deviceID})
 					} else {
-						connectStatus := voltha.ConnectStatus_UNREACHABLE
-						operState := voltha.OperStatus_UNKNOWN
 						if onuDevEntry.sOnuPersistentData.PersOperState == "up" {
 							connectStatus = voltha.ConnectStatus_REACHABLE
 							if !onuDevEntry.sOnuPersistentData.PersUniDisableDone {
@@ -3559,21 +3566,39 @@
 						}
 
 						logger.Debugw(ctx, "Core DeviceStateUpdate", log.Fields{"connectStatus": connectStatus, "operState": operState})
-						if err := dh.coreProxy.DeviceStateUpdate(ctx, dh.deviceID, connectStatus, operState); err != nil {
-							logger.Errorw(ctx, "unable to update device state to core",
-								log.Fields{"OperState": onuDevEntry.sOnuPersistentData.PersOperState, "Err": err})
-						}
 					}
 					logger.Debugw(ctx, "reconciling has been finished in time",
 						log.Fields{"device-id": dh.deviceID})
+					if err := dh.coreProxy.DeviceStateUpdate(ctx, dh.deviceID, connectStatus, operState); err != nil {
+						logger.Errorw(ctx, "unable to update device state to core",
+							log.Fields{"device-id": dh.deviceID, "Err": err})
+					}
 				} else {
 					logger.Errorw(ctx, "wait for reconciling aborted",
 						log.Fields{"device-id": dh.deviceID})
+
+					if onuDevEntry := dh.getOnuDeviceEntry(ctx, true); onuDevEntry == nil {
+						logger.Errorw(ctx, "No valid OnuDevice",
+							log.Fields{"device-id": dh.deviceID})
+					} else if onuDevEntry.sOnuPersistentData.PersOperState == "up" {
+						connectStatus = voltha.ConnectStatus_REACHABLE
+					}
+
+					dh.deviceReconcileFailedUpdate(ctx, drReconcileCanceled, connectStatus)
 				}
 			case <-time.After(dh.pOpenOnuAc.maxTimeoutReconciling):
-				//TODO: handle notification to core if reconciling timed out
 				logger.Errorw(ctx, "timeout waiting for reconciling to be finished!",
 					log.Fields{"device-id": dh.deviceID})
+
+				if onuDevEntry := dh.getOnuDeviceEntry(ctx, true); onuDevEntry == nil {
+					logger.Errorw(ctx, "No valid OnuDevice",
+						log.Fields{"device-id": dh.deviceID})
+				} else if onuDevEntry.sOnuPersistentData.PersOperState == "up" {
+					connectStatus = voltha.ConnectStatus_REACHABLE
+				}
+
+				dh.deviceReconcileFailedUpdate(ctx, drReconcileMaxTimeout, connectStatus)
+
 			}
 			dh.mutexReconcilingFlag.Lock()
 			dh.reconciling = cNoReconciling
@@ -3651,3 +3676,16 @@
 	dh.mutexReadyForOmciConfig.RUnlock()
 	return flagValue
 }
+
+func (dh *deviceHandler) deviceReconcileFailedUpdate(ctx context.Context, deviceReason uint8, connectStatus voltha.ConnectStatus_Types) {
+	if err := dh.deviceReasonUpdate(ctx, deviceReason, true); err != nil {
+		logger.Errorw(ctx, "unable to update device reason to core",
+			log.Fields{"device-id": dh.deviceID, "Err": err})
+	}
+
+	logger.Debugw(ctx, "Core DeviceStateUpdate", log.Fields{"connectStatus": connectStatus, "operState": voltha.OperStatus_RECONCILING_FAILED})
+	if err := dh.coreProxy.DeviceStateUpdate(ctx, dh.deviceID, connectStatus, voltha.OperStatus_RECONCILING_FAILED); err != nil {
+		logger.Errorw(ctx, "unable to update device state to core",
+			log.Fields{"device-id": dh.deviceID, "Err": err})
+	}
+}