[VOL-5608]:Enable/Disable onu serial number fix

Change-Id: If1d023857f7608827dc6e4cf502c522ef7777f63
Signed-off-by: balaji.nagarajan <balaji.nagarajan@radisys.com>
diff --git a/VERSION b/VERSION
index 7707ee0..82a60c0 100644
--- a/VERSION
+++ b/VERSION
@@ -1 +1 @@
-3.7.19
+3.7.20
diff --git a/rw_core/core/device/agent.go b/rw_core/core/device/agent.go
index 54be97f..5f0f004 100755
--- a/rw_core/core/device/agent.go
+++ b/rw_core/core/device/agent.go
@@ -992,6 +992,14 @@
 			case reflect.Bool:
 				f.SetBool(value.(bool))
 				updated = true
+			default:
+				// Fallback for enums and other user-defined types
+				v := reflect.ValueOf(value)
+				if v.IsValid() && v.Type().AssignableTo(f.Type()) {
+					f.Set(v)
+					updated = true
+				}
+
 			}
 		}
 	}
@@ -1840,43 +1848,52 @@
 	return fmt.Errorf("device-cannot-process-request-%s", agent.deviceID)
 }
 
-func (agent *Agent) disableOnuDevice(ctx context.Context, adapterEndpoint string) error {
+func (agent *Agent) disableOnuDevice(ctx context.Context, onuAgent *Agent) error {
 	var err error
 	var desc string
 	var prevAdminState, currAdminState common.AdminState_Types
 	requestStatus := &common.OperationResp{Code: common.OperationResp_OPERATION_FAILURE}
 
 	defer func() {
-		agent.logDeviceUpdate(ctx, &prevAdminState, &currAdminState, requestStatus, err, desc)
+		onuAgent.logDeviceUpdate(ctx, &prevAdminState, &currAdminState, requestStatus, err, desc)
 	}()
 
 	if err = agent.requestQueue.WaitForGreenLight(ctx); err != nil {
 		desc = "Failed while waiting for green light"
 		return err
 	}
-	logger.Debugw(ctx, "disable-child-device", log.Fields{"device-id": agent.deviceID, "serial-number": agent.device.SerialNumber})
 
-	prevAdminState = agent.device.AdminState
+	defer agent.requestQueue.RequestComplete()
 
-	cloned, desc, err := agent.checkDisableEligibility()
-	if err != nil {
+	parentDevice := agent.getDeviceReadOnlyWithoutLock()
+
+	if parentDevice.ConnectStatus != voltha.ConnectStatus_REACHABLE {
+		err = status.Errorf(codes.FailedPrecondition, "cannot complete operation as device :%s is in operstatus:%s ,connect-status:%s", agent.deviceID, parentDevice.OperStatus, parentDevice.ConnectStatus)
 		agent.requestQueue.RequestComplete()
 		return err
 	}
 
+	logger.Debugw(ctx, "disable-child-device", log.Fields{"device-id": onuAgent.deviceID, "serial-number": onuAgent.device.SerialNumber})
+
+	prevAdminState = onuAgent.device.AdminState
+
+	cloned, desc, err := onuAgent.checkDisableEligibility()
+	if err != nil {
+		return err
+	}
+
 	cloned.AdminState = voltha.AdminState_DISABLED
 
-	client, err := agent.adapterMgr.GetAdapterClient(ctx, adapterEndpoint)
+	client, err := agent.adapterMgr.GetAdapterClient(ctx, agent.adapterEndpoint)
 	if err != nil {
 		logger.Errorw(ctx, "grpc-client-nil",
 			log.Fields{
 				"error":            err,
 				"device-id":        agent.deviceID,
 				"device-type":      agent.deviceType,
-				"adapter-endpoint": adapterEndpoint,
+				"adapter-endpoint": agent.adapterEndpoint,
 			})
-		desc = fmt.Sprintf("failed to get adapter client for endpoint %s", adapterEndpoint)
-		agent.requestQueue.RequestComplete()
+		desc = fmt.Sprintf("failed to get adapter client for endpoint %s", agent.adapterEndpoint)
 		return err
 	}
 
@@ -1903,62 +1920,65 @@
 	select {
 	case resultErr := <-resultCh:
 		if resultErr != nil {
-			agent.requestQueue.RequestComplete()
 			return resultErr
 		}
 	case <-ctx.Done():
 		err = fmt.Errorf("operation cancelled or timed out: %w", ctx.Err())
 		desc = "disable ONU device operation cancelled or timed out"
-		agent.requestQueue.RequestComplete()
 		return err
 	}
 
-	if updateErr := agent.updateDeviceAndReleaseLock(subCtx, cloned); updateErr != nil {
-		desc = "failed to update device after disabling ONU"
-		return fmt.Errorf("update-device-failed: %w", updateErr)
-	}
+	onuAgent.updateDeviceAttribute(subCtx, "AdminState", cloned.AdminState)
 
 	currAdminState = cloned.AdminState
 	return nil
 }
 
-func (agent *Agent) enableOnuDevice(ctx context.Context, adapterEndpoint string) error {
+func (agent *Agent) enableOnuDevice(ctx context.Context, onuAgent *Agent) error {
 	var err error
 	var desc string
 	var prevAdminState, currAdminState common.AdminState_Types
 	requestStatus := &common.OperationResp{Code: common.OperationResp_OPERATION_FAILURE}
 
-	defer func() { agent.logDeviceUpdate(ctx, &prevAdminState, &currAdminState, requestStatus, err, desc) }()
+	defer func() { onuAgent.logDeviceUpdate(ctx, &prevAdminState, &currAdminState, requestStatus, err, desc) }()
 
 	if err = agent.requestQueue.WaitForGreenLight(ctx); err != nil {
 		desc = "Failed while waiting for green light"
 		return err
 	}
-	logger.Debugw(ctx, "enable-child-device", log.Fields{"device-id": agent.deviceID, "serial-number": agent.device.SerialNumber})
 
-	prevAdminState = agent.device.AdminState
+	defer agent.requestQueue.RequestComplete()
+	parentDevice := agent.getDeviceReadOnlyWithoutLock()
 
-	newDevice, desc, err := agent.checkEnableEligibility()
+	if parentDevice.ConnectStatus != voltha.ConnectStatus_REACHABLE {
+		err = status.Errorf(codes.FailedPrecondition, "cannot complete operation as device :%s is in operstatus:%s ,connect-status:%s", agent.deviceID, parentDevice.OperStatus, parentDevice.ConnectStatus)
+		return err
+	}
+
+	logger.Debugw(ctx, "enable-child-device", log.Fields{"device-id": onuAgent.deviceID, "serial-number": onuAgent.device.SerialNumber})
+
+	prevAdminState = onuAgent.device.AdminState
+
+	newDevice, desc, err := onuAgent.checkEnableEligibility()
+
 	if err != nil {
-		agent.requestQueue.RequestComplete()
 		return err
 	}
 
 	// Update the Admin State and set the operational state to activating before sending the request to the Adapters
 	newDevice.AdminState = voltha.AdminState_ENABLED
 
-	client, err := agent.adapterMgr.GetAdapterClient(ctx, adapterEndpoint)
+	client, err := agent.adapterMgr.GetAdapterClient(ctx, agent.adapterEndpoint)
 	if err != nil {
 		logger.Errorw(ctx, "grpc-client-nil",
 			log.Fields{
 				"error":            err,
 				"device-id":        agent.deviceID,
 				"device-type":      agent.deviceType,
-				"adapter-endpoint": adapterEndpoint,
+				"adapter-endpoint": agent.adapterEndpoint,
 			})
 
-		desc = fmt.Sprintf("failed to get adapter client for endpoint %s", adapterEndpoint)
-		agent.requestQueue.RequestComplete()
+		desc = fmt.Sprintf("failed to get adapter client for endpoint %s", agent.adapterEndpoint)
 		return err
 	}
 	subCtx, cancel := context.WithTimeout(coreutils.WithAllMetadataFromContext(ctx), agent.rpcTimeout)
@@ -1986,63 +2006,56 @@
 	select {
 	case resultErr := <-resultCh:
 		if resultErr != nil {
-			agent.requestQueue.RequestComplete()
 			return resultErr
 		}
 	case <-ctx.Done():
 		err = fmt.Errorf("operation cancelled or timed out: %w", ctx.Err())
-		agent.requestQueue.RequestComplete()
 		desc = "enable ONU device operation cancelled or timed out"
 		return err
 	}
 
-	if updateErr := agent.updateDeviceAndReleaseLock(subCtx, newDevice); updateErr != nil {
-		desc = "failed to update device after enabling ONU"
-		return fmt.Errorf("update-device-failed: %w", updateErr)
-	}
+	onuAgent.updateDeviceAttribute(subCtx, "AdminState", newDevice.AdminState)
 
 	currAdminState = newDevice.AdminState
 	return nil
 
 }
 
-func (agent *Agent) disableOnuSerialNumber(ctx context.Context, device *voltha.OnuSerialNumberOnOLTPon, adapterEndpoint string) error {
+func (agent *Agent) disableOnuSerialNumber(ctx context.Context, device *voltha.OnuSerialNumberOnOLTPon) error {
 	var err error
 	var desc string
-	var prevAdminState, currAdminState common.AdminState_Types
 	requestStatus := &common.OperationResp{Code: common.OperationResp_OPERATION_FAILURE}
 
 	defer func() {
-		agent.logDeviceUpdate(ctx, &prevAdminState, &currAdminState, requestStatus, err, desc)
+		agent.logDeviceUpdate(ctx, nil, nil, requestStatus, err, desc)
 	}()
 
 	if err = agent.requestQueue.WaitForGreenLight(ctx); err != nil {
 		desc = "Failed while waiting for green light"
 		return err
 	}
-	logger.Debugw(ctx, "disable-child-serial-number", log.Fields{"device-id": agent.deviceID, "serial-number": agent.device.SerialNumber})
 
-	prevAdminState = agent.device.AdminState
-	cloned, desc, err := agent.checkDisableEligibility()
-	if err != nil {
-		agent.requestQueue.RequestComplete()
+	defer agent.requestQueue.RequestComplete()
+	parentDevice := agent.getDeviceReadOnlyWithoutLock()
+
+	if parentDevice.ConnectStatus != voltha.ConnectStatus_REACHABLE {
+		err = status.Errorf(codes.FailedPrecondition, "cannot complete operation as device :%s is in operstatus:%s ,connect-status:%s", agent.deviceID, parentDevice.OperStatus, parentDevice.ConnectStatus)
 		return err
 	}
 
-	cloned.AdminState = voltha.AdminState_DISABLED
+	logger.Debugw(ctx, "disable-child-serial-number", log.Fields{"device-id": agent.deviceID, "serial-number": agent.device.SerialNumber})
 
-	client, err := agent.adapterMgr.GetAdapterClient(ctx, adapterEndpoint)
+	client, err := agent.adapterMgr.GetAdapterClient(ctx, agent.adapterEndpoint)
 	if err != nil {
 		logger.Errorw(ctx, "grpc-client-nil",
 			log.Fields{
 				"error":            err,
 				"device-id":        agent.deviceID,
 				"device-type":      agent.deviceType,
-				"adapter-endpoint": adapterEndpoint,
+				"adapter-endpoint": agent.adapterEndpoint,
 			})
 
-		desc = fmt.Sprintf("failed to get adapter client for endpoint %s", adapterEndpoint)
-		agent.requestQueue.RequestComplete()
+		desc = fmt.Sprintf("failed to get adapter client for endpoint %s", agent.adapterEndpoint)
 		return err
 	}
 
@@ -2055,11 +2068,11 @@
 	go func() {
 		_, callErr := client.DisableOnuSerialNumber(subCtx, device)
 		if callErr == nil {
-			logger.Infow(subCtx, "disable-child-serial-number-success", log.Fields{"device-id": cloned.Id, "serial-number": device.SerialNumber})
+			logger.Infow(subCtx, "disable-child-serial-number-success", log.Fields{"serial-number": device.SerialNumber})
 			agent.onSuccess(subCtx, nil, nil, true)
 			resultCh <- nil
 		} else {
-			logger.Errorw(subCtx, "disable-child-serial-number-failed", log.Fields{"device-id": cloned.Id, "serial-number": device.SerialNumber, "error": callErr})
+			logger.Errorw(subCtx, "disable-child-serial-number-failed", log.Fields{"serial-number": device.SerialNumber, "error": callErr})
 			agent.onFailure(subCtx, callErr, nil, nil, true)
 			trimmedErr := extractLastRpcError(callErr)
 			desc = fmt.Sprintf("disableOnuSerialNumber call failed: %s", trimmedErr)
@@ -2070,53 +2083,45 @@
 	select {
 	case resultErr := <-resultCh:
 		if resultErr != nil {
-			agent.requestQueue.RequestComplete()
 			return resultErr
 		}
 
 	case <-ctx.Done():
 		err = fmt.Errorf("operation cancelled or timed out: %w", ctx.Err())
-		agent.requestQueue.RequestComplete()
 		desc = "disable ONU serial number operation cancelled or timed out"
 		return err
 	}
 
-	if updateErr := agent.updateDeviceAndReleaseLock(subCtx, cloned); updateErr != nil {
-		desc = "failed to update device after disabling ONU serial number"
-		return fmt.Errorf("update-device-failed: %w", updateErr)
-	}
-	currAdminState = cloned.AdminState
 	return nil
 
 }
 
-func (agent *Agent) enableOnuSerialNumber(ctx context.Context, device *voltha.OnuSerialNumberOnOLTPon, adapterEndpoint string) error {
+func (agent *Agent) enableOnuSerialNumber(ctx context.Context, device *voltha.OnuSerialNumberOnOLTPon) error {
 	var err error
 	var desc string
-	var cloned *voltha.Device
-	var prevAdminState, currAdminState common.AdminState_Types
 	requestStatus := &common.OperationResp{Code: common.OperationResp_OPERATION_FAILURE}
 
 	defer func() {
-		agent.logDeviceUpdate(ctx, &prevAdminState, &currAdminState, requestStatus, err, desc)
+		agent.logDeviceUpdate(ctx, nil, nil, requestStatus, err, desc)
 	}()
 
 	if err = agent.requestQueue.WaitForGreenLight(ctx); err != nil {
 		desc = "Failed while waiting for green light"
 		return err
 	}
+
+	defer agent.requestQueue.RequestComplete()
+
 	logger.Debugw(ctx, "enable-child-serial-number", log.Fields{"serial-number": device.SerialNumber})
 
-	prevAdminState = agent.device.AdminState
-	cloned, desc, err = agent.checkEnableEligibility()
-	if err != nil {
-		agent.requestQueue.RequestComplete()
+	parentDevice := agent.getDeviceReadOnlyWithoutLock()
+
+	if parentDevice.ConnectStatus != voltha.ConnectStatus_REACHABLE {
+		err = status.Errorf(codes.FailedPrecondition, "cannot complete operation as device :%s is in operstatus:%s ,connect-status:%s", agent.deviceID, parentDevice.OperStatus, parentDevice.ConnectStatus)
 		return err
 	}
 
-	cloned.AdminState = voltha.AdminState_ENABLED
-
-	client, err := agent.adapterMgr.GetAdapterClient(ctx, adapterEndpoint)
+	client, err := agent.adapterMgr.GetAdapterClient(ctx, agent.adapterEndpoint)
 	if err != nil {
 		logger.Errorw(ctx, "grpc-client-nil",
 			log.Fields{
@@ -2126,8 +2131,7 @@
 				"adapter-endpoint": agent.adapterEndpoint,
 			})
 
-		desc = fmt.Sprintf("failed to get adapter client for endpoint %s", adapterEndpoint)
-		agent.requestQueue.RequestComplete()
+		desc = fmt.Sprintf("failed to get adapter client for endpoint %s", agent.adapterEndpoint)
 		return err
 	}
 
@@ -2155,22 +2159,15 @@
 	select {
 	case resultErr := <-resultCh:
 		if resultErr != nil {
-			agent.requestQueue.RequestComplete()
 			return resultErr
 		}
 
 	case <-ctx.Done():
 		err = fmt.Errorf("operation cancelled or timed out: %w", ctx.Err())
-		agent.requestQueue.RequestComplete()
 		desc = "enable ONU serial number operation cancelled or timed out"
 		return err
 	}
 
-	if updateErr := agent.updateDeviceAndReleaseLock(subCtx, cloned); updateErr != nil {
-		desc = "failed to update device after enabling ONU serial number"
-		return fmt.Errorf("update-device-failed: %w", updateErr)
-	}
-	currAdminState = cloned.AdminState
 	return nil
 }
 
diff --git a/rw_core/core/device/manager_nbi.go b/rw_core/core/device/manager_nbi.go
index 660f6e6..26bdba6 100644
--- a/rw_core/core/device/manager_nbi.go
+++ b/rw_core/core/device/manager_nbi.go
@@ -970,7 +970,7 @@
 		return nil, status.Errorf(codes.NotFound, "%s", agent.device.ParentId)
 	}
 	logger.Debugw(ctx, "serial-no to be diabled", log.Fields{"serial-number": agent.device.SerialNumber})
-	return &emptypb.Empty{}, agent.disableOnuDevice(ctx, oltAgent.adapterEndpoint)
+	return &emptypb.Empty{}, oltAgent.disableOnuDevice(ctx, agent)
 }
 
 func (dMgr *Manager) EnableOnuDevice(ctx context.Context, id *voltha.ID) (*emptypb.Empty, error) {
@@ -988,7 +988,7 @@
 		return nil, status.Errorf(codes.NotFound, "%s", agent.device.ParentId)
 	}
 	logger.Debugw(ctx, "serial-no to be enabled", log.Fields{"serial-number": agent.device.SerialNumber})
-	return &emptypb.Empty{}, agent.enableOnuDevice(ctx, oltAgent.adapterEndpoint)
+	return &emptypb.Empty{}, oltAgent.enableOnuDevice(ctx, agent)
 }
 
 func (dMgr *Manager) DisableOnuSerialNumber(ctx context.Context, device *voltha.OnuSerialNumberOnOLTPon) (*emptypb.Empty, error) {
@@ -1001,16 +1001,7 @@
 		return nil, status.Errorf(codes.NotFound, "%s", device.OltDeviceId)
 	}
 
-	onuDeviceID, err := dMgr.GetOnuDeviceIdBySerial(ctx, device)
-	if err != nil {
-		return nil, status.Errorf(codes.NotFound, "onu-device-id-not-found-for-serial-number-%s", device.SerialNumber)
-	}
-
-	agent := dMgr.getDeviceAgent(ctx, onuDeviceID)
-	if agent == nil {
-		return nil, status.Errorf(codes.NotFound, "%s", onuDeviceID)
-	}
-	return &emptypb.Empty{}, agent.disableOnuSerialNumber(ctx, device, oltAgent.adapterEndpoint)
+	return &emptypb.Empty{}, oltAgent.disableOnuSerialNumber(ctx, device)
 }
 
 func (dMgr *Manager) EnableOnuSerialNumber(ctx context.Context, device *voltha.OnuSerialNumberOnOLTPon) (*emptypb.Empty, error) {
@@ -1023,17 +1014,7 @@
 		return nil, status.Errorf(codes.NotFound, "%s", device.OltDeviceId)
 	}
 
-	onuDeviceID, err := dMgr.GetOnuDeviceIdBySerial(ctx, device)
-	if err != nil {
-		return nil, status.Errorf(codes.NotFound, "onu-device-id-not-found-for-serial-number-%s", device.SerialNumber)
-	}
-
-	agent := dMgr.getDeviceAgent(ctx, onuDeviceID)
-	if agent == nil {
-		return nil, status.Errorf(codes.NotFound, "%s", onuDeviceID)
-	}
-
-	return &emptypb.Empty{}, agent.enableOnuSerialNumber(ctx, device, oltAgent.adapterEndpoint)
+	return &emptypb.Empty{}, oltAgent.enableOnuSerialNumber(ctx, device)
 }
 
 // UpdateDevice updates the configuration of a device, such as changing the IP address of an OLT device.