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
+}
diff --git a/internal/bbsimctl/commands/olt.go b/internal/bbsimctl/commands/olt.go
index 3ea004c..a16edef 100644
--- a/internal/bbsimctl/commands/olt.go
+++ b/internal/bbsimctl/commands/olt.go
@@ -51,15 +51,21 @@
 
 type OltFlows struct{}
 
+type OltPoweronAllOnus struct{}
+
+type OltShutdownAllOnus struct{}
+
 type oltOptions struct {
-	Get      OltGet          `command:"get"`
-	NNI      OltNNIs         `command:"nnis"`
-	PON      OltPONs         `command:"pons"`
-	Shutdown OltShutdown     `command:"shutdown"`
-	Poweron  OltPoweron      `command:"poweron"`
-	Reboot   OltReboot       `command:"reboot"`
-	Alarms   OltAlarmOptions `command:"alarms"`
-	Flows    OltFlows        `command:"flows"`
+	Get             OltGet             `command:"get"`
+	NNI             OltNNIs            `command:"nnis"`
+	PON             OltPONs            `command:"pons"`
+	Shutdown        OltShutdown        `command:"shutdown"`
+	Poweron         OltPoweron         `command:"poweron"`
+	Reboot          OltReboot          `command:"reboot"`
+	Alarms          OltAlarmOptions    `command:"alarms"`
+	Flows           OltFlows           `command:"flows"`
+	PoweronAllOnus  OltPoweronAllOnus  `command:"poweronAllONUs"`
+	ShutdownAllOnus OltShutdownAllOnus `command:"shutdownAllONUs"`
 }
 
 func RegisterOltCommands(parser *flags.Parser) {
@@ -243,3 +249,39 @@
 	tableFlow.SetNewLine("")
 	return nil
 }
+
+func (o *OltPoweronAllOnus) Execute(args []string) error {
+	client, conn := connect()
+	defer conn.Close()
+
+	ctx, cancel := context.WithTimeout(context.Background(), config.GlobalConfig.Grpc.Timeout)
+	defer cancel()
+
+	res, err := client.PoweronAllONUs(ctx, &pb.Empty{})
+
+	if err != nil {
+		log.Errorf("Cannot poweron all ONUs: %v", err)
+		return err
+	}
+
+	fmt.Println(fmt.Sprintf("[Status: %d] %s", res.StatusCode, res.Message))
+	return nil
+}
+
+func (o *OltShutdownAllOnus) Execute(args []string) error {
+	client, conn := connect()
+	defer conn.Close()
+
+	ctx, cancel := context.WithTimeout(context.Background(), config.GlobalConfig.Grpc.Timeout)
+	defer cancel()
+
+	res, err := client.ShutdownAllONUs(ctx, &pb.Empty{})
+
+	if err != nil {
+		log.Errorf("Cannot shutdown all ONUs: %v", err)
+		return err
+	}
+
+	fmt.Println(fmt.Sprintf("[Status: %d] %s", res.StatusCode, res.Message))
+	return nil
+}
diff --git a/internal/bbsimctl/commands/pon.go b/internal/bbsimctl/commands/pon.go
new file mode 100644
index 0000000..885fb75
--- /dev/null
+++ b/internal/bbsimctl/commands/pon.go
@@ -0,0 +1,91 @@
+/*
+ * Portions copyright 2019-present Open Networking Foundation
+ * Original copyright 2019-present Ciena Corporation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package commands
+
+import (
+	"context"
+	"fmt"
+
+	"github.com/jessevdk/go-flags"
+	pb "github.com/opencord/bbsim/api/bbsim"
+	"github.com/opencord/bbsim/internal/bbsimctl/config"
+	log "github.com/sirupsen/logrus"
+)
+
+type PonPoweronAllOnus struct {
+	Args struct {
+		IntfID OltInterfaceID
+	} `positional-args:"yes" required:"yes"`
+}
+
+type PonShutdownAllOnus struct {
+	Args struct {
+		IntfID OltInterfaceID
+	} `positional-args:"yes" required:"yes"`
+}
+
+type PONOptions struct {
+	PoweronAllOnus  PonPoweronAllOnus  `command:"poweronAllONUs"`
+	ShutdownAllOnus PonShutdownAllOnus `command:"shutdownAllONUs"`
+}
+
+func RegisterPonCommands(parser *flags.Parser) {
+	parser.AddCommand("pon", "PON Commands", "Commands to query and manipulate the PON port", &PONOptions{})
+}
+
+func (pon *PonPoweronAllOnus) Execute(args []string) error {
+	client, conn := connect()
+	defer conn.Close()
+
+	ctx, cancel := context.WithTimeout(context.Background(), config.GlobalConfig.Grpc.Timeout)
+	defer cancel()
+
+	req := pb.PONRequest{
+		PonPortId: uint32(pon.Args.IntfID),
+	}
+
+	res, err := client.PoweronONUsOnPON(ctx, &req)
+	if err != nil {
+		log.Errorf("Cannot poweron all ONUs on PON port: %v", err)
+		return err
+	}
+
+	fmt.Println(fmt.Sprintf("[Status: %d] %s", res.StatusCode, res.Message))
+	return nil
+}
+
+func (pon *PonShutdownAllOnus) Execute(args []string) error {
+	client, conn := connect()
+	defer conn.Close()
+
+	ctx, cancel := context.WithTimeout(context.Background(), config.GlobalConfig.Grpc.Timeout)
+	defer cancel()
+
+	req := pb.PONRequest{
+		PonPortId: uint32(pon.Args.IntfID),
+	}
+
+	res, err := client.ShutdownONUsOnPON(ctx, &req)
+	if err != nil {
+		log.Errorf("Cannot shutdown all ONUs on PON port: %v", err)
+		return err
+	}
+
+	fmt.Println(fmt.Sprintf("[Status: %d] %s", res.StatusCode, res.Message))
+	return nil
+}