SEBA-941 updated apis to  poweron/shutdown all ONUs in PON/OLT

Change-Id: I6923cbcc51a4391f70ff08d266c274e1f34ca3ca
diff --git a/internal/bbsim/api/onus_handler.go b/internal/bbsim/api/onus_handler.go
index 0f898e8..330621a 100644
--- a/internal/bbsim/api/onus_handler.go
+++ b/internal/bbsim/api/onus_handler.go
@@ -74,6 +74,7 @@
 	return &res, nil
 }
 
+// ShutdownONU sends DyingGasp indication for specified ONUs and mark ONUs as disabled.
 func (s BBSimServer) ShutdownONU(ctx context.Context, req *bbsim.ONURequest) (*bbsim.Response, error) {
 	// NOTE this method is now sending a Dying Gasp and then disabling the device (operState: down, adminState: up),
 	// is this the only way to do? Should we address other cases?
@@ -81,82 +82,70 @@
 	// - a fiber is pulled
 	// - ONU malfunction
 	// - ONU shutdown
-	res := &bbsim.Response{}
-
 	logger.WithFields(log.Fields{
 		"OnuSn": req.SerialNumber,
 	}).Infof("Received request to shutdown ONU")
 
+	res := &bbsim.Response{}
 	olt := devices.GetOLT()
 
 	onu, err := olt.FindOnuBySn(req.SerialNumber)
-
 	if err != nil {
 		res.StatusCode = int32(codes.NotFound)
 		res.Message = err.Error()
 		return res, err
 	}
 
-	dyingGasp := bbsim.ONUAlarmRequest{
-		AlarmType:    "DyingGasp",
-		SerialNumber: onu.Sn(),
-		Status:       "on",
-	}
+	return handleShutdownONU(onu)
+}
 
-	if err := alarmsim.SimulateOnuAlarm(context.TODO(), &dyingGasp, olt); err != nil {
-		logger.WithFields(log.Fields{
-			"OnuId":  onu.ID,
-			"IntfId": onu.PonPortID,
-			"OnuSn":  onu.Sn(),
-		}).Errorf("Cannot send Dying Gasp: %s", err.Error())
-		res.StatusCode = int32(codes.FailedPrecondition)
-		res.Message = err.Error()
-		return res, err
-	}
+// ShutdownONUsOnPON sends DyingGasp indication for all ONUs under specified PON port
+func (s BBSimServer) ShutdownONUsOnPON(ctx context.Context, req *bbsim.PONRequest) (*bbsim.Response, error) {
+	logger.WithFields(log.Fields{
+		"IntfId": req.PonPortId,
+	}).Infof("Received request to shutdown all ONUs on PON")
 
-	losReq := bbsim.ONUAlarmRequest{
-		AlarmType:    "LossOfSignal",
-		SerialNumber: onu.Sn(),
-		Status:       "on",
-	}
+	res := &bbsim.Response{}
+	olt := devices.GetOLT()
+	pon, _ := olt.GetPonById(req.PonPortId)
 
-	if err := alarmsim.SimulateOnuAlarm(context.TODO(), &losReq, olt); err != nil {
-		logger.WithFields(log.Fields{
-			"OnuId":  onu.ID,
-			"IntfId": onu.PonPortID,
-			"OnuSn":  onu.Sn(),
-		}).Errorf("Cannot send LOS: %s", err.Error())
-		res.StatusCode = int32(codes.FailedPrecondition)
-		res.Message = err.Error()
-		return res, err
-	}
-
-	// TODO if it's the last ONU on the PON, then send a PON LOS
-
-	if err := onu.InternalState.Event("disable"); err != nil {
-		logger.WithFields(log.Fields{
-			"OnuId":  onu.ID,
-			"IntfId": onu.PonPortID,
-			"OnuSn":  onu.Sn(),
-		}).Errorf("Cannot shutdown ONU: %s", err.Error())
-		res.StatusCode = int32(codes.FailedPrecondition)
-		res.Message = err.Error()
-		return res, err
-	}
-
+	go func() {
+		for _, onu := range pon.Onus {
+			res, _ = handleShutdownONU(onu)
+		}
+	}()
 	res.StatusCode = int32(codes.OK)
-	res.Message = fmt.Sprintf("ONU %s successfully shut down.", onu.Sn())
+	res.Message = fmt.Sprintf("Request accepted for shutdown all ONUs on PON port %d", pon.ID)
 
 	return res, nil
 }
 
-func (s BBSimServer) PoweronONU(ctx context.Context, req *bbsim.ONURequest) (*bbsim.Response, error) {
+// ShutdownAllONUs sends DyingGasp indication for all ONUs and mark ONUs as disabled.
+func (s BBSimServer) ShutdownAllONUs(context.Context, *bbsim.Empty) (*bbsim.Response, error) {
+	logger.Infof("Received request to shutdown all ONUs")
 	res := &bbsim.Response{}
+	olt := devices.GetOLT()
 
+	go func() {
+		for _, pon := range olt.Pons {
+			for _, onu := range pon.Onus {
+				res, _ = handleShutdownONU(onu)
+			}
+		}
+	}()
+	res.StatusCode = int32(codes.OK)
+	res.Message = fmt.Sprintf("Request Accepted for shutdown all ONUs in OLT %d", olt.ID)
+
+	return res, nil
+}
+
+// PoweronONU simulates ONU power on and start sending discovery indications to VOLTHA
+func (s BBSimServer) PoweronONU(ctx context.Context, req *bbsim.ONURequest) (*bbsim.Response, error) {
 	logger.WithFields(log.Fields{
 		"OnuSn": req.SerialNumber,
 	}).Infof("Received request to poweron ONU")
 
+	res := &bbsim.Response{}
 	olt := devices.GetOLT()
 
 	onu, err := olt.FindOnuBySn(req.SerialNumber)
@@ -180,60 +169,59 @@
 		return res, err
 	}
 
-	if onu.InternalState.Current() == "created" || onu.InternalState.Current() == "disabled" {
-		if err := onu.InternalState.Event("initialize"); err != nil {
-			logger.WithFields(log.Fields{
-				"OnuId":  onu.ID,
-				"IntfId": onu.PonPortID,
-				"OnuSn":  onu.Sn(),
-			}).Errorf("Cannot poweron ONU: %s", err.Error())
-			res.StatusCode = int32(codes.FailedPrecondition)
-			res.Message = err.Error()
-			return res, err
+	return handlePoweronONU(onu)
+}
+
+// PoweronONUsOnPON simulates ONU power on for all ONUs under specified PON port
+func (s BBSimServer) PoweronONUsOnPON(ctx context.Context, req *bbsim.PONRequest) (*bbsim.Response, error) {
+	logger.WithFields(log.Fields{
+		"IntfId": req.PonPortId,
+	}).Infof("Received request to poweron all ONUs on PON")
+
+	res := &bbsim.Response{}
+	olt := devices.GetOLT()
+
+	pon, _ := olt.GetPonById(req.PonPortId)
+	if pon.InternalState.Current() != "enabled" {
+		err := fmt.Errorf("PON port %d not enabled", pon.ID)
+		logger.WithFields(log.Fields{
+			"IntfId": pon.ID,
+		}).Errorf("Cannot poweron ONUs on PON: %s", err.Error())
+
+		res.StatusCode = int32(codes.FailedPrecondition)
+		res.Message = err.Error()
+		return res, err
+	}
+
+	go func() {
+		for _, onu := range pon.Onus {
+			res, _ = handlePoweronONU(onu)
 		}
-	}
-
-	losReq := bbsim.ONUAlarmRequest{
-		AlarmType:    "LossOfSignal",
-		SerialNumber: onu.Sn(),
-		Status:       "off",
-	}
-
-	if err := alarmsim.SimulateOnuAlarm(context.TODO(), &losReq, olt); err != nil {
-		logger.WithFields(log.Fields{
-			"OnuId":  onu.ID,
-			"IntfId": onu.PonPortID,
-			"OnuSn":  onu.Sn(),
-		}).Errorf("Cannot send LOS: %s", err.Error())
-		res.StatusCode = int32(codes.FailedPrecondition)
-		res.Message = err.Error()
-		return res, err
-	}
-
-	if err := onu.InternalState.Event("discover"); err != nil {
-		logger.WithFields(log.Fields{
-			"OnuId":  onu.ID,
-			"IntfId": onu.PonPortID,
-			"OnuSn":  onu.Sn(),
-		}).Errorf("Cannot poweron ONU: %s", err.Error())
-		res.StatusCode = int32(codes.FailedPrecondition)
-		res.Message = err.Error()
-		return res, err
-	}
-
-	if err := onu.InternalState.Event("enable"); err != nil {
-		logger.WithFields(log.Fields{
-			"OnuId":  onu.ID,
-			"IntfId": onu.PonPortID,
-			"OnuSn":  onu.Sn(),
-		}).Errorf("Cannot enable ONU: %s", err.Error())
-		res.StatusCode = int32(codes.FailedPrecondition)
-		res.Message = err.Error()
-		return res, err
-	}
-
+	}()
 	res.StatusCode = int32(codes.OK)
-	res.Message = fmt.Sprintf("ONU %s successfully powered on.", onu.Sn())
+	res.Message = fmt.Sprintf("Request Accepted for power on all ONUs on PON port %d", pon.ID)
+
+	return res, nil
+}
+
+// PoweronAllONUs simulates ONU power on for all ONUs on all PON ports
+func (s BBSimServer) PoweronAllONUs(context.Context, *bbsim.Empty) (*bbsim.Response, error) {
+	logger.Infof("Received request to poweron all ONUs")
+
+	res := &bbsim.Response{}
+	olt := devices.GetOLT()
+
+	go func() {
+		for _, pon := range olt.Pons {
+			if pon.InternalState.Current() == "enabled" {
+				for _, onu := range pon.Onus {
+					res, _ = handlePoweronONU(onu)
+				}
+			}
+		}
+	}()
+	res.StatusCode = int32(codes.OK)
+	res.Message = fmt.Sprintf("Request Accepted for power on all ONUs in OLT %d", olt.ID)
 
 	return res, nil
 }
@@ -397,3 +385,126 @@
 		return &ts, nil
 	}
 }
+
+func handlePoweronONU(onu *devices.Onu) (*bbsim.Response, error) {
+	res := &bbsim.Response{}
+	olt := devices.GetOLT()
+	intitalState := onu.InternalState.Current()
+	if onu.InternalState.Current() == "created" || onu.InternalState.Current() == "disabled" {
+		if err := onu.InternalState.Event("initialize"); err != nil {
+			logger.WithFields(log.Fields{
+				"OnuId":  onu.ID,
+				"IntfId": onu.PonPortID,
+				"OnuSn":  onu.Sn(),
+			}).Errorf("Cannot poweron ONU: %s", err.Error())
+			res.StatusCode = int32(codes.FailedPrecondition)
+			res.Message = err.Error()
+			return res, err
+		}
+	}
+
+	losReq := bbsim.ONUAlarmRequest{
+		AlarmType:    "LossOfSignal",
+		SerialNumber: onu.Sn(),
+		Status:       "off",
+	}
+
+	if err := alarmsim.SimulateOnuAlarm(context.TODO(), &losReq, olt); err != nil {
+		logger.WithFields(log.Fields{
+			"OnuId":  onu.ID,
+			"IntfId": onu.PonPortID,
+			"OnuSn":  onu.Sn(),
+		}).Errorf("Cannot send LOS: %s", err.Error())
+		res.StatusCode = int32(codes.FailedPrecondition)
+		res.Message = err.Error()
+		return res, err
+	}
+
+	if err := onu.InternalState.Event("discover"); err != nil {
+		logger.WithFields(log.Fields{
+			"OnuId":  onu.ID,
+			"IntfId": onu.PonPortID,
+			"OnuSn":  onu.Sn(),
+		}).Errorf("Cannot poweron ONU: %s", err.Error())
+		res.StatusCode = int32(codes.FailedPrecondition)
+		res.Message = err.Error()
+		return res, err
+	}
+	// move onu directly to enable state only when its a powercycle case
+	// in case of first time onu poweron onu will be moved to enable on
+	// receiving ActivateOnu request from openolt adapter
+	if intitalState == "disabled" {
+		if err := onu.InternalState.Event("enable"); err != nil {
+			logger.WithFields(log.Fields{
+				"OnuId":  onu.ID,
+				"IntfId": onu.PonPortID,
+				"OnuSn":  onu.Sn(),
+			}).Errorf("Cannot enable ONU: %s", err.Error())
+			res.StatusCode = int32(codes.FailedPrecondition)
+			res.Message = err.Error()
+			return res, err
+		}
+	}
+
+	res.StatusCode = int32(codes.OK)
+	res.Message = fmt.Sprintf("ONU %s successfully powered on.", onu.Sn())
+
+	return res, nil
+}
+
+func handleShutdownONU(onu *devices.Onu) (*bbsim.Response, error) {
+	res := &bbsim.Response{}
+	olt := devices.GetOLT()
+
+	dyingGasp := bbsim.ONUAlarmRequest{
+		AlarmType:    "DyingGasp",
+		SerialNumber: onu.Sn(),
+		Status:       "on",
+	}
+
+	if err := alarmsim.SimulateOnuAlarm(context.TODO(), &dyingGasp, olt); err != nil {
+		logger.WithFields(log.Fields{
+			"OnuId":  onu.ID,
+			"IntfId": onu.PonPortID,
+			"OnuSn":  onu.Sn(),
+		}).Errorf("Cannot send Dying Gasp: %s", err.Error())
+		res.StatusCode = int32(codes.FailedPrecondition)
+		res.Message = err.Error()
+		return res, err
+	}
+
+	losReq := bbsim.ONUAlarmRequest{
+		AlarmType:    "LossOfSignal",
+		SerialNumber: onu.Sn(),
+		Status:       "on",
+	}
+
+	if err := alarmsim.SimulateOnuAlarm(context.TODO(), &losReq, olt); err != nil {
+		logger.WithFields(log.Fields{
+			"OnuId":  onu.ID,
+			"IntfId": onu.PonPortID,
+			"OnuSn":  onu.Sn(),
+		}).Errorf("Cannot send LOS: %s", err.Error())
+		res.StatusCode = int32(codes.FailedPrecondition)
+		res.Message = err.Error()
+		return res, err
+	}
+
+	// TODO if it's the last ONU on the PON, then send a PON LOS
+
+	if err := onu.InternalState.Event("disable"); err != nil {
+		logger.WithFields(log.Fields{
+			"OnuId":  onu.ID,
+			"IntfId": onu.PonPortID,
+			"OnuSn":  onu.Sn(),
+		}).Errorf("Cannot shutdown ONU: %s", err.Error())
+		res.StatusCode = int32(codes.FailedPrecondition)
+		res.Message = err.Error()
+		return res, err
+	}
+
+	res.StatusCode = int32(codes.OK)
+	res.Message = fmt.Sprintf("ONU %s successfully shut down.", onu.Sn())
+
+	return res, nil
+}