[VOL-5452]: Onu Disable/Enable Olt adapter

Change-Id: I681ff5fc407b90ab7cf75a2386a82f8e996e488b
Signed-off-by: balaji.nagarajan <balaji.nagarajan@radisys.com>
diff --git a/internal/pkg/core/device_handler.go b/internal/pkg/core/device_handler.go
index 9f9b187..2664391 100755
--- a/internal/pkg/core/device_handler.go
+++ b/internal/pkg/core/device_handler.go
@@ -659,6 +659,65 @@
 	return nil
 }
 
+func (dh *DeviceHandler) handleOnuDisableIndication(ctx context.Context, onuIndication *oop.OnuDisabledIndication) error {
+	logger.Infow(ctx, "handleOnuDisableIndication", log.Fields{"device-id": dh.device.Id, "onuInd": onuIndication})
+	sn := dh.stringifySerialNumber(onuIndication.SerialNumber)
+	intfID := onuIndication.GetIntfId()
+	ponPort := plt.IntfIDToPortNo(intfID, voltha.Port_PON_OLT)
+	onuDev := dh.getChildDevice(ctx, sn, ponPort)
+	if onuDev == nil {
+		logger.Warnw(ctx, "handleOnuDisableIndication onu-device-fetch-failed", log.Fields{"device-id": dh.device.Id, "onuInd": onuIndication})
+		onuDev = &OnuDevice{
+			serialNumber: sn,
+		}
+	}
+	dh.discOnus.Delete(sn)
+
+	raisedTs := time.Now().Unix()
+	if err := dh.eventMgr.onuDisableIndication(ctx, onuIndication, dh.device.Id, onuDev, raisedTs); err != nil {
+		return olterrors.NewErrAdapter("failed-indication", log.Fields{
+			"device-id":  dh.device.Id,
+			"indication": onuIndication,
+			"timestamp":  raisedTs}, err)
+	}
+	OnuIndication := generateOnuIndication(onuDev.intfID, onuDev.onuID, "down", "down")
+	err := dh.sendOnuIndicationToChildAdapter(ctx, onuDev.adapterEndpoint, &ia.OnuIndicationMessage{
+		DeviceId:      onuDev.deviceID,
+		OnuIndication: OnuIndication.GetOnuInd(),
+	})
+	if err != nil {
+		return olterrors.NewErrCommunication("inter-adapter-send-failed", log.Fields{
+			"onu-indicator": OnuIndication.GetOnuInd(),
+			"source":        dh.openOLT.config.AdapterEndpoint,
+			"device-type":   onuDev.deviceType,
+			"device-id":     onuDev.deviceID}, err)
+	}
+	return nil
+}
+
+func (dh *DeviceHandler) handleOnuEnableIndication(ctx context.Context, onuIndication *oop.OnuEnabledIndication) error {
+	logger.Infow(ctx, "handleOnuEnableIndication", log.Fields{"device-id": dh.device.Id, "onuInd": onuIndication})
+	sn := dh.stringifySerialNumber(onuIndication.SerialNumber)
+	intfID := onuIndication.GetIntfId()
+	ponPort := plt.IntfIDToPortNo(intfID, voltha.Port_PON_OLT)
+	onuDev := dh.getChildDevice(ctx, sn, ponPort)
+	if onuDev == nil {
+		logger.Warnw(ctx, "handleOnuEnableIndication onu-device-fetch-failed", log.Fields{"device-id": dh.device.Id, "onuInd": onuIndication})
+		onuDev = &OnuDevice{
+			serialNumber: sn,
+		}
+	}
+	raisedTs := time.Now().Unix()
+
+	if err := dh.eventMgr.onuEnableIndication(ctx, onuIndication, dh.device.Id, onuDev, raisedTs); err != nil {
+		return olterrors.NewErrAdapter("failed-indication", log.Fields{
+			"device-id":  dh.device.Id,
+			"indication": onuIndication,
+			"timestamp":  raisedTs}, err)
+	}
+	return nil
+}
+
 // nolint: gocyclo,govet
 func (dh *DeviceHandler) handleIndication(ctx context.Context, indication *oop.Indication) {
 	raisedTs := time.Now().Unix()
@@ -780,6 +839,20 @@
 		alarmInd := indication.GetAlarmInd()
 		logger.Infow(ctx, "received-alarm-indication", log.Fields{"AlarmInd": alarmInd, "device-id": dh.device.Id})
 		go dh.eventMgr.ProcessEvents(ctx, alarmInd, dh.device.Id, raisedTs)
+	case *oop.Indication_OnuDisabledInd:
+		span, ctx := log.CreateChildSpan(ctx, "onu-disable-indication", log.Fields{"device-id": dh.device.Id})
+		defer span.Finish()
+		logger.Infow(ctx, "received onu-disable-indication", log.Fields{"device-id": dh.device.Id, "onu-ind": indication.GetOnuInd()})
+		if err := dh.handleOnuDisableIndication(ctx, indication.GetOnuDisabledInd()); err != nil {
+			_ = olterrors.NewErrAdapter("handle-indication-error", log.Fields{"type": "olt", "device-id": dh.device.Id, "onu-ind": indication.GetOnuInd()}, err).Log()
+		}
+	case *oop.Indication_OnuEnabledInd:
+		span, ctx := log.CreateChildSpan(ctx, "onu-enable-indication", log.Fields{"device-id": dh.device.Id})
+		defer span.Finish()
+		logger.Infow(ctx, "received onu-enable-indication", log.Fields{"device-id": dh.device.Id, "onu-ind": indication.GetOnuInd()})
+		if err := dh.handleOnuEnableIndication(ctx, indication.GetOnuEnabledInd()); err != nil {
+			_ = olterrors.NewErrAdapter("handle-indication-error", log.Fields{"type": "olt", "device-id": dh.device.Id, "onu-ind": indication.GetOnuInd()}, err).Log()
+		}
 	}
 }
 
@@ -3038,6 +3111,145 @@
 	dh.transitionMap.Handle(ctx, DeviceInit)
 }
 
+// EnableOnuSerialNumber to enable onu serial number
+func (dh *DeviceHandler) EnableOnuSerialNumber(ctx context.Context, device *voltha.OnuSerialNumberOnOLTPon) error {
+	logger.Debugw(ctx, "enable-onu-serial-number", log.Fields{"Device": dh.device, "onu-serial-number": device.SerialNumber, "port": device.Port.PortNo})
+	onuSerialNumber := device.SerialNumber
+
+	// fetch interfaceid from PortNo
+	ponID := plt.PortNoToIntfID(device.Port.GetPortNo(), voltha.Port_PON_OLT)
+
+	sn, err := dh.deStringifySerialNumber(onuSerialNumber)
+	if err != nil {
+		return olterrors.NewErrAdapter("failed-to-destringify-serial-number",
+			log.Fields{
+				"devicer-id":    dh.device.Id,
+				"serial-number": onuSerialNumber}, err).Log()
+	}
+
+	onuIntf := &oop.InterfaceOnuSerialNumber{
+		IntfId:          ponID,
+		OnuSerialNumber: sn,
+	}
+	_, err = dh.Client.EnableOnuSerialNumber(ctx, onuIntf)
+
+	if err != nil {
+		logger.Errorw(ctx, "failed to enable onu serial number", log.Fields{"onudev": onuSerialNumber, "error": err})
+		return olterrors.NewErrAdapter("onu-serial-number-enable-failed", log.Fields{
+			"device-id":         dh.device.Id,
+			"onu-serial-number": onuSerialNumber}, err)
+	}
+	return nil
+}
+
+// DisableOnuSerialNumber to disable onu serial number
+func (dh *DeviceHandler) DisableOnuSerialNumber(ctx context.Context, device *voltha.OnuSerialNumberOnOLTPon) error {
+	logger.Debugw(ctx, "disable-onu-serial-number", log.Fields{"Device": dh.device, "onu-serial-number": device.SerialNumber, "port": device.Port.PortNo})
+	onuSerialNumber := device.SerialNumber
+	ponID := plt.PortNoToIntfID(device.Port.GetPortNo(), voltha.Port_PON_OLT)
+	sn, err := dh.deStringifySerialNumber(onuSerialNumber)
+	if err != nil {
+		return olterrors.NewErrAdapter("failed-to-destringify-serial-number",
+			log.Fields{
+				"devicer-id":    dh.device.Id,
+				"serial-number": onuSerialNumber}, err).Log()
+	}
+
+	onuIntf := &oop.InterfaceOnuSerialNumber{
+		OnuSerialNumber: sn,
+		IntfId:          ponID,
+	}
+	_, err = dh.Client.DisableOnuSerialNumber(ctx, onuIntf)
+
+	if err != nil {
+		logger.Errorw(ctx, "failed to disable onu serial number", log.Fields{"onudev": onuSerialNumber, "error": err})
+		return olterrors.NewErrAdapter("onu-serial-number-disable-failed", log.Fields{
+			"device-id":         dh.device.Id,
+			"onu-serial-number": onuSerialNumber}, err)
+	}
+	return nil
+}
+
+// EnableOnu to enable onu
+func (dh *DeviceHandler) EnableOnu(ctx context.Context, device *voltha.Device) error {
+	logger.Debugw(ctx, "enable-onu", log.Fields{"Device": dh.device, "onu-serial-number": device.SerialNumber})
+	onuSerialNumber := device.SerialNumber
+	InCacheOnuDev := dh.getChildDevice(ctx, onuSerialNumber, dh.device.ParentPortNo)
+	if InCacheOnuDev == nil {
+		logger.Errorw(ctx, "failed to get child device from cache", log.Fields{"onudev": onuSerialNumber})
+		return olterrors.NewErrAdapter("failed to get child device from cache", log.Fields{
+			"device-id":         dh.device.Id,
+			"onu-serial-number": onuSerialNumber}, nil)
+	}
+	logger.Debugw(ctx, "successfully-received-child-device-from-cache", log.Fields{"child-device-intfid": InCacheOnuDev.intfID, "child-device-sn": InCacheOnuDev.serialNumber, "child-onuid": InCacheOnuDev.onuID})
+
+	sn, err := dh.deStringifySerialNumber(onuSerialNumber)
+	if err != nil {
+		return olterrors.NewErrAdapter("failed-to-destringify-serial-number",
+			log.Fields{
+				"device-id":     dh.device.Id,
+				"serial-number": onuSerialNumber}, err).Log()
+	}
+
+	onuIntf := &oop.InterfaceOnuSerialNumber{
+		OnuSerialNumber: sn,
+		IntfId:          InCacheOnuDev.intfID,
+	}
+	onuIntfReq := &oop.InterfaceOnuSerialNumberOnuId{
+		OnuId:           InCacheOnuDev.onuID,
+		IntfIdSerialNum: onuIntf,
+	}
+	_, err = dh.Client.EnableOnu(ctx, onuIntfReq)
+
+	if err != nil {
+		logger.Errorw(ctx, "failed to enable onu ", log.Fields{"onudev": onuSerialNumber, "error": err})
+		return olterrors.NewErrAdapter("onu-enable-failed", log.Fields{
+			"olt-device-id":     dh.device.Id,
+			"onu-serial-number": onuSerialNumber}, err)
+	}
+	return nil
+}
+
+// DisableOnu to disable onu
+func (dh *DeviceHandler) DisableOnu(ctx context.Context, device *voltha.Device) error {
+	logger.Debugw(ctx, "disable-onu", log.Fields{"Device": dh.device, "onu-serial-number": device.SerialNumber})
+	onuSerialNumber := device.SerialNumber
+	InCacheOnuDev := dh.getChildDevice(ctx, onuSerialNumber, dh.device.ParentPortNo)
+	if InCacheOnuDev == nil {
+		logger.Errorw(ctx, "failed to get child device from cache", log.Fields{"onudev": onuSerialNumber})
+		return olterrors.NewErrAdapter("failed to get child device from cache", log.Fields{
+			"device-id":         dh.device.Id,
+			"onu-serial-number": onuSerialNumber}, nil)
+	}
+	logger.Debugw(ctx, "successfully-received-child-device-from-cache", log.Fields{"child-device-intfid": InCacheOnuDev.intfID, "child-device-sn": InCacheOnuDev.serialNumber, "child-onuid": InCacheOnuDev.onuID})
+
+	sn, err := dh.deStringifySerialNumber(onuSerialNumber)
+	if err != nil {
+		return olterrors.NewErrAdapter("failed-to-destringify-serial-number",
+			log.Fields{
+				"device-id":     dh.device.Id,
+				"serial-number": onuSerialNumber}, err).Log()
+	}
+
+	onuIntf := &oop.InterfaceOnuSerialNumber{
+		OnuSerialNumber: sn,
+		IntfId:          InCacheOnuDev.intfID,
+	}
+	onuIntfReq := &oop.InterfaceOnuSerialNumberOnuId{
+		OnuId:           InCacheOnuDev.onuID,
+		IntfIdSerialNum: onuIntf,
+	}
+	_, err = dh.Client.DisableOnu(ctx, onuIntfReq)
+
+	if err != nil {
+		logger.Errorw(ctx, "failed to disable onu ", log.Fields{"onudev": onuSerialNumber, "error": err})
+		return olterrors.NewErrAdapter("onu-disable-failed", log.Fields{
+			"olt-device-id":     dh.device.Id,
+			"onu-serial-number": onuSerialNumber}, err)
+	}
+	return nil
+}
+
 // EnablePort to enable Pon interface
 func (dh *DeviceHandler) EnablePort(ctx context.Context, port *voltha.Port) error {
 	logger.Debugw(ctx, "enable-port", log.Fields{"Device": dh.device, "port": port})
diff --git a/internal/pkg/core/openolt.go b/internal/pkg/core/openolt.go
index 0df5140..cc11caa 100644
--- a/internal/pkg/core/openolt.go
+++ b/internal/pkg/core/openolt.go
@@ -336,6 +336,101 @@
 	return nil, olterrors.NewErrNotFound("device-handler", log.Fields{"device-id": packet.DeviceId}, nil)
 }
 
+// EnableOnuSerialNumber to Enable onu serial number
+func (oo *OpenOLT) EnableOnuSerialNumber(ctx context.Context, device *voltha.OnuSerialNumberOnOLTPon) (*empty.Empty, error) {
+	logger.Infow(ctx, "enable_onu_serial_number", log.Fields{"olt_device_id": device.OltDeviceId, "onu_serial_number": device.SerialNumber})
+	if err := oo.enableDisableOnuSerialNumber(log.WithSpanFromContext(context.Background(), ctx), device, true); err != nil {
+		return nil, err
+	}
+	return &empty.Empty{}, nil
+}
+
+// DisableOnuSerialNumber to Disable onu serial number
+func (oo *OpenOLT) DisableOnuSerialNumber(ctx context.Context, device *voltha.OnuSerialNumberOnOLTPon) (*empty.Empty, error) {
+	logger.Infow(ctx, "disable_onu_serial_number", log.Fields{"olt_device_id": device.OltDeviceId, "onu_serial_number": device.SerialNumber})
+	if err := oo.enableDisableOnuSerialNumber(log.WithSpanFromContext(context.Background(), ctx), device, false); err != nil {
+		return nil, err
+	}
+	return &empty.Empty{}, nil
+}
+
+// enableDisableOnuSerialNumber to Disable onu or Enable onu
+func (oo *OpenOLT) enableDisableOnuSerialNumber(ctx context.Context, device *voltha.OnuSerialNumberOnOLTPon, enable bool) error {
+	if device.OltDeviceId == nil {
+		return olterrors.NewErrInvalidValue(log.Fields{
+			"reason": "olt device id is required",
+		}, nil)
+	}
+	if device.SerialNumber == "" {
+		return olterrors.NewErrInvalidValue(log.Fields{
+			"reason": "onu_serial_number cannot be empty",
+		}, nil)
+	}
+	if device.Port == nil {
+		return olterrors.NewErrInvalidValue(log.Fields{
+			"reason": "pon port cannot be empty",
+		}, nil)
+	}
+	if handler := oo.getDeviceHandler(device.OltDeviceId.Id); handler != nil {
+		if enable {
+			if err := handler.EnableOnuSerialNumber(ctx, device); err != nil {
+				return olterrors.NewErrAdapter("error-occurred-during-enable-onu-serial-number", log.Fields{"device-id": device.OltDeviceId.Id, "sn": device.SerialNumber}, err)
+			}
+		} else {
+			if err := handler.DisableOnuSerialNumber(ctx, device); err != nil {
+				return olterrors.NewErrAdapter("error-occurred-during-disable-onu-serial-number", log.Fields{"device-id": device.OltDeviceId.Id, "sn": device.SerialNumber}, err)
+			}
+		}
+		return nil
+	}
+	return olterrors.NewErrNotFound("device-handler", log.Fields{"device-id": device.OltDeviceId.Id}, nil)
+}
+
+// EnableOnuDevice to Enable onu
+func (oo *OpenOLT) EnableOnuDevice(ctx context.Context, device *voltha.Device) (*empty.Empty, error) {
+	logger.Infow(ctx, "enable_onu", log.Fields{"onu_device_id": device.Id, "onu_serial_number": device.SerialNumber})
+	if err := oo.enableDisableOnuDevice(log.WithSpanFromContext(context.Background(), ctx), device, true); err != nil {
+		return nil, err
+	}
+	return &empty.Empty{}, nil
+}
+
+// DisableOnuDevice to Disable onu
+func (oo *OpenOLT) DisableOnuDevice(ctx context.Context, device *voltha.Device) (*empty.Empty, error) {
+	logger.Infow(ctx, "disable_onu", log.Fields{"onu_device_id": device.Id, "onu_serial_number": device.SerialNumber})
+	if err := oo.enableDisableOnuDevice(log.WithSpanFromContext(context.Background(), ctx), device, false); err != nil {
+		return nil, err
+	}
+	return &empty.Empty{}, nil
+}
+
+// enableDisableOnuDevice to Disable onu or Enable onu
+func (oo *OpenOLT) enableDisableOnuDevice(ctx context.Context, device *voltha.Device, enable bool) error {
+	if device.ParentId == "" {
+		return olterrors.NewErrInvalidValue(log.Fields{
+			"reason": "olt device id is required",
+		}, nil)
+	}
+	if device.SerialNumber == "" {
+		return olterrors.NewErrInvalidValue(log.Fields{
+			"reason": "onu_serial_number cannot be empty",
+		}, nil)
+	}
+	if handler := oo.getDeviceHandler(device.ParentId); handler != nil {
+		if enable {
+			if err := handler.EnableOnu(ctx, device); err != nil {
+				return olterrors.NewErrAdapter("error-occurred-during-enable-onu", log.Fields{"device-id": device.ParentId, "sn": device.SerialNumber}, err)
+			}
+		} else {
+			if err := handler.DisableOnu(ctx, device); err != nil {
+				return olterrors.NewErrAdapter("error-occurred-during-disable-onu", log.Fields{"device-id": device.ParentId, "sn": device.SerialNumber}, err)
+			}
+		}
+		return nil
+	}
+	return olterrors.NewErrNotFound("device-handler", log.Fields{"device-id": device.ParentId}, nil)
+}
+
 // EnablePort to Enable PON/NNI interface
 func (oo *OpenOLT) EnablePort(ctx context.Context, port *voltha.Port) (*empty.Empty, error) {
 	logger.Infow(ctx, "enable_port", log.Fields{"device-id": port.DeviceId, "port": port})
diff --git a/internal/pkg/core/openolt_eventmgr.go b/internal/pkg/core/openolt_eventmgr.go
index c2c5b5e..888957f 100644
--- a/internal/pkg/core/openolt_eventmgr.go
+++ b/internal/pkg/core/openolt_eventmgr.go
@@ -54,6 +54,8 @@
 	onuLossOfKeySyncEvent               = "ONU_LOSS_OF_KEY_SYNC"
 	onuLossOfFrameEvent                 = "ONU_LOSS_OF_FRAME"
 	onuLossOfPloamEvent                 = "ONU_LOSS_OF_PLOAM"
+	onuDisableEvent                     = "ONU_DISABLE"
+	onuEnableEvent                      = "ONU_ENABLE"
 	ponIntfDownIndiction                = "OLT_PON_INTERFACE_DOWN"
 	onuDeactivationFailureEvent         = "ONU_DEACTIVATION_FAILURE"
 	onuRemoteDefectIndication           = "ONU_REMOTE_DEFECT"
@@ -374,6 +376,50 @@
 	return onuDeviceID
 }
 
+func (em *OpenOltEventMgr) onuDisableIndication(ctx context.Context, onui *oop.OnuDisabledIndication, parentDeviceID string, onuDev *OnuDevice, raisedTs int64) error {
+	var de voltha.DeviceEvent
+	context := make(map[string]string)
+	/* Populating event context */
+	onuDeviceID := em.populateContextWithSerialDeviceID(context, onui.IntfId, onui.OnuId)
+
+	context[ContextOnuPonIntfID] = strconv.FormatUint(uint64(onui.IntfId), base10)
+	context[ContextOnuOnuID] = strconv.FormatUint(uint64(onui.OnuId), base10)
+	context[ContextDeviceID] = onuDev.deviceID
+	context[ContextOnuSerialNumber] = onuDev.serialNumber
+	/* Populating device event body */
+	de.Context = context
+	de.ResourceId = parentDeviceID
+	de.DeviceEventName = onuDisableEvent
+	/* Send event to KAFKA */
+	if err := em.eventProxy.SendDeviceEventWithKey(ctx, &de, voltha.EventCategory_COMMUNICATION, voltha.EventSubCategory_ONU, raisedTs, onuDeviceID); err != nil {
+		return err
+	}
+	logger.Debugw(ctx, "onu-disabled-event-sent-to-kafka", log.Fields{"intf-id": onui.IntfId, "onu_id": onui.OnuId})
+	return nil
+}
+
+func (em *OpenOltEventMgr) onuEnableIndication(ctx context.Context, onui *oop.OnuEnabledIndication, deviceID string, onuDev *OnuDevice, raisedTs int64) error {
+	var de voltha.DeviceEvent
+	context := make(map[string]string)
+	/* Populating event context */
+	onuDeviceID := em.populateContextWithSerialDeviceID(context, onui.IntfId, onui.OnuId)
+
+	context[ContextOnuPonIntfID] = strconv.FormatUint(uint64(onui.IntfId), base10)
+	context[ContextOnuOnuID] = strconv.FormatUint(uint64(onui.OnuId), base10)
+	context[ContextDeviceID] = onuDev.deviceID
+	context[ContextOnuSerialNumber] = onuDev.serialNumber
+	/* Populating device event body */
+	de.Context = context
+	de.ResourceId = deviceID
+	de.DeviceEventName = onuEnableEvent
+	/* Send event to KAFKA */
+	if err := em.eventProxy.SendDeviceEventWithKey(ctx, &de, voltha.EventCategory_COMMUNICATION, voltha.EventSubCategory_ONU, raisedTs, onuDeviceID); err != nil {
+		return err
+	}
+	logger.Debugw(ctx, "onu-enabled-event-sent-to-kafka", log.Fields{"intf-id": onui.IntfId, "onu_id": onui.OnuId})
+	return nil
+}
+
 func (em *OpenOltEventMgr) onuDyingGaspIndication(ctx context.Context, dgi *oop.DyingGaspIndication, deviceID string, raisedTs int64) error {
 	var de voltha.DeviceEvent
 	context := make(map[string]string)