blob: 74754847d3ce43909f269a3ea1dbe65878328507 [file] [log] [blame]
/*
* Copyright 2018-present Open Networking Foundation
* 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 core
import (
"context"
"net"
"net/http"
"sync"
"github.com/grpc-ecosystem/grpc-gateway/runtime"
pb "github.com/opencord/voltha-bbsim/api"
"github.com/opencord/voltha-bbsim/common/logger"
"github.com/opencord/voltha-bbsim/device"
"google.golang.org/grpc"
"google.golang.org/grpc/codes"
"google.golang.org/grpc/status"
)
// Response Constants
const (
RequestAccepted = "API request accepted"
OLTNotEnabled = "OLT not enabled"
RequestFailed = "API request failed"
SoftReboot = "soft-reboot"
HardReboot = "hard-reboot"
DeviceTypeOlt = "olt"
DeviceTypeOnu = "onu"
)
// OLTStatus method returns OLT status.
func (s *Server) OLTStatus(ctx context.Context, in *pb.Empty) (*pb.OLTStatusResponse, error) {
logger.Debug("OLTStatus request received")
oltInfo := &pb.OLTStatusResponse{
Olt: &pb.OLTInfo{
OltId: int64(s.Olt.ID),
OltSerial: s.Olt.SerialNumber,
OltIp: getOltIP().String(),
OltState: s.Olt.OperState,
OltVendor: s.Olt.Manufacture,
},
}
for _, nniPort := range s.Olt.NniIntfs {
nniPortInfo, _ := s.fetchPortDetail(nniPort.IntfID, nniPort.Type)
oltInfo.Ports = append(oltInfo.Ports, nniPortInfo)
}
for _, ponPort := range s.Olt.PonIntfs {
ponPortInfo, _ := s.fetchPortDetail(ponPort.IntfID, ponPort.Type)
oltInfo.Ports = append(oltInfo.Ports, ponPortInfo)
}
logger.Info("OLT Info: %v\n", oltInfo)
return oltInfo, nil
}
// PortStatus method returns Port status.
func (s *Server) PortStatus(ctx context.Context, in *pb.PortInfo) (*pb.Ports, error) {
portInfo := &pb.Ports{}
logger.Debug("PortStatus() invoked")
if in.PortType == device.IntfNni {
for _, nniPort := range s.Olt.NniIntfs {
nniPortInfo, _ := s.fetchPortDetail(nniPort.IntfID, nniPort.Type)
portInfo.Ports = append(portInfo.Ports, nniPortInfo)
}
} else if in.PortType == device.IntfPon {
for _, ponPort := range s.Olt.PonIntfs {
ponPortInfo, _ := s.fetchPortDetail(ponPort.IntfID, ponPort.Type)
portInfo.Ports = append(portInfo.Ports, ponPortInfo)
}
} else {
return &pb.Ports{}, status.Errorf(codes.InvalidArgument, "Invalid port type")
}
return portInfo, nil
}
// ONUStatus method returns ONU status.
func (s *Server) ONUStatus(ctx context.Context, in *pb.ONURequest) (*pb.ONUs, error) {
logger.Debug("ONUStatus request received")
if in.GetOnu() != nil {
logger.Debug("Received single ONU: %+v, %d\n", in.GetOnu(), in.GetOnu().PonPortId)
return s.handleONUStatusRequest(in.GetOnu())
}
logger.Debug("Received bulk ONUs status request")
onuInfo := &pb.ONUs{}
for intfid := range s.Onumap {
for _, onu := range s.Onumap[intfid] {
if onu.InternalState != device.ONU_FREE {
onuInfo.Onus = append(onuInfo.Onus, copyONUInfo(onu))
}
}
}
return onuInfo, nil
}
// ONUActivate method handles ONU activate requests from user.
func (s *Server) ONUActivate(ctx context.Context, in *pb.ONURequest) (*pb.BBSimResponse, error) {
logger.Info("ONUActivate request received")
logger.Debug("Received values: %+v\n", in)
var onuInfo = []*pb.ONUInfo{}
// Activate single ONU
if in.GetOnu() != nil {
logger.Debug("Received single ONU: %+v\n", in.GetOnu())
onuInfo = append(onuInfo, in.GetOnu())
} else if len(in.GetOnusBatch().GetOnus()) != 0 { // Activate multiple ONUs
logger.Debug("Received multiple ONUs")
onuInfo = in.GetOnusBatch().GetOnus()
} else {
logger.Debug("Received empty request body")
return &pb.BBSimResponse{}, status.Errorf(codes.InvalidArgument, RequestFailed)
}
resp, err := s.handleONUActivate(onuInfo)
return resp, err
}
// ONUDeactivate method handles ONU deactivation request.
func (s *Server) ONUDeactivate(ctx context.Context, in *pb.ONURequest) (*pb.BBSimResponse, error) {
logger.Info("ONUDeactivate request received")
// deactivate single ONU
if in.GetOnu() != nil {
logger.Debug("Received single ONU: %+v\n", in.GetOnu())
err := s.handleONUDeactivate(in.GetOnu())
if err != nil {
return &pb.BBSimResponse{}, status.Errorf(codes.Aborted, RequestFailed)
}
} else if len(in.GetOnusBatch().GetOnus()) != 0 { // bulk deactivate
logger.Debug("Received multiple ONUs")
for _, onuinfo := range in.GetOnusBatch().GetOnus() {
logger.Debug("ONU values: %+v\n", onuinfo)
err := s.handleONUDeactivate(onuinfo)
if err != nil {
return &pb.BBSimResponse{}, status.Errorf(codes.Aborted, RequestFailed)
}
}
} else {
// Empty request body is passed, delete all ONUs from all PON ports
for intfID := range s.Onumap {
if err := s.DeactivateAllOnuByIntfID(intfID); err != nil {
logger.Error("Failed in ONUDeactivate: %v", err)
return &pb.BBSimResponse{}, status.Errorf(codes.Aborted, RequestFailed)
}
}
}
return &pb.BBSimResponse{StatusMsg: RequestAccepted}, nil
}
// GenerateONUAlarm RPC generates alarm for the onu
func (s *Server) GenerateONUAlarm(ctx context.Context, in *pb.ONUAlarmRequest) (*pb.BBSimResponse, error) {
logger.Debug("GenerateONUAlarms() invoked")
if in.OnuSerial == "" {
return &pb.BBSimResponse{}, status.Errorf(codes.FailedPrecondition, "serial number can not be blank")
}
if len(in.OnuSerial) != SerialNumberLength {
return &pb.BBSimResponse{}, status.Errorf(codes.InvalidArgument, "invalid serial number given (length mismatch)")
}
if in.Status != "on" && in.Status != "off" {
return &pb.BBSimResponse{}, status.Errorf(codes.InvalidArgument, "invalid alarm status provided")
}
if s.alarmCh == nil {
return &pb.BBSimResponse{}, status.Errorf(codes.Internal, "alarm-channel not created, can not send alarm")
}
// TODO put these checks inside handleOnuAlarm for modularity
resp, err := s.handleOnuAlarm(in)
return resp, err
}
// GenerateOLTAlarm RPC generates alarm for the OLT
func (s *Server) GenerateOLTAlarm(ctx context.Context, in *pb.OLTAlarmRequest) (*pb.BBSimResponse, error) {
logger.Debug("GenerateOLTAlarm() invoked")
if in.Status != "on" && in.Status != "off" {
return &pb.BBSimResponse{}, status.Errorf(codes.InvalidArgument, "invalid alarm status provided")
}
if s.alarmCh == nil {
return &pb.BBSimResponse{}, status.Errorf(codes.Internal, "alarm-channel not created, can not send alarm")
}
resp, err := s.handleOltAlarm(in)
if err != nil {
return resp, err
}
return &pb.BBSimResponse{StatusMsg: RequestAccepted}, nil
}
// PerformDeviceAction rpc take the device request and performs OLT and ONU hard and soft reboot
func (s *Server) PerformDeviceAction(ctx context.Context, in *pb.DeviceAction) (*pb.BBSimResponse, error) {
logger.Debug("PerformDeviceAction() invoked")
if s.deviceActionCh == nil {
return &pb.BBSimResponse{}, status.Errorf(codes.Internal, "device action channel not created, can not entertain request")
}
in, err := s.validateDeviceActionRequest(in)
if err != nil {
return &pb.BBSimResponse{}, status.Errorf(codes.InvalidArgument, err.Error())
}
s.deviceActionCh <- in
return &pb.BBSimResponse{StatusMsg: RequestAccepted}, nil
}
// NewMgmtAPIServer method starts BBSim gRPC server.
func NewMgmtAPIServer(addrport string) (l net.Listener, g *grpc.Server, e error) {
logger.Info("BBSim gRPC server listening %s ...", addrport)
g = grpc.NewServer()
l, e = net.Listen("tcp", addrport)
return
}
// StartRestGatewayService method starts REST server for BBSim.
func StartRestGatewayService(grpcAddress string, hostandport string, wg *sync.WaitGroup) {
ctx := context.Background()
ctx, cancel := context.WithCancel(ctx)
defer cancel()
mux := runtime.NewServeMux()
opts := []grpc.DialOption{grpc.WithInsecure()}
// Register REST endpoints
err := pb.RegisterBBSimServiceHandlerFromEndpoint(ctx, mux, grpcAddress, opts)
if err != nil {
logger.Error("%v", err)
return
}
logger.Info("BBSim REST server listening %s ...", hostandport)
err = http.ListenAndServe(hostandport, mux)
if err != nil {
logger.Error("%v", err)
return
}
return
}