VOL-291 : PON simulator refactoring for cluster integration

- Added ponsim build target in Makefile
- Added new option to vcore to select comm type with ponsim
- Modified all proto files to include destination go package

Amendments:

- Clean up based on review comments
- Properly close GRPC connections in ponsim_olt adapter
- Added voltha namespace to some k8s templates

Change-Id: I2f349fa7b3550a8a8cc8fc676cc896f33fbb9372
diff --git a/ponsim/v2/grpc/nbi/bal_handler.go b/ponsim/v2/grpc/nbi/bal_handler.go
new file mode 100644
index 0000000..5cbafb3
--- /dev/null
+++ b/ponsim/v2/grpc/nbi/bal_handler.go
@@ -0,0 +1,82 @@
+package nbi
+
+import (
+	"context"
+	"github.com/opencord/voltha/ponsim/v2/common"
+	"github.com/opencord/voltha/protos/go/bal"
+)
+
+// TODO: fix BAL function parameters and returns
+
+type BalHandler struct {
+}
+
+func NewBalHandler() *BalHandler {
+	var handler *BalHandler
+	handler = &BalHandler{}
+	return handler
+}
+
+func (handler *BalHandler) BalApiInit(
+	ctx context.Context,
+	request *bal.BalInit,
+) (*bal.BalErr, error) {
+	common.Logger().Info("BalApiInit Called", ctx, request)
+	return &bal.BalErr{Err: bal.BalErrno_BAL_ERR_OK}, nil
+}
+
+func (handler *BalHandler) BalApiFinish(
+	ctx context.Context,
+	request *bal.BalCfg,
+) (*bal.BalErr, error) {
+	common.Logger().Info("BalApiFinish Called", ctx, request)
+	return &bal.BalErr{Err: bal.BalErrno_BAL_ERR_OK}, nil
+}
+
+func (handler *BalHandler) BalCfgSet(
+	ctx context.Context,
+	request *bal.BalCfg,
+) (*bal.BalErr, error) {
+	common.Logger().Info("BalCfgSet Called", ctx, request)
+	return &bal.BalErr{Err: bal.BalErrno_BAL_ERR_OK}, nil
+}
+
+func (handler *BalHandler) BalCfgClear(
+	ctx context.Context,
+	request *bal.BalKey,
+) (*bal.BalErr, error) {
+	common.Logger().Info("BalCfgClear Called", ctx, request)
+	return &bal.BalErr{Err: bal.BalErrno_BAL_ERR_OK}, nil
+}
+
+func (handler *BalHandler) BalCfgGet(
+	ctx context.Context,
+	request *bal.BalKey,
+) (*bal.BalCfg, error) {
+	common.Logger().Info("BalCfgGet Called", ctx, request)
+	return &bal.BalCfg{}, nil
+}
+
+func (handler *BalHandler) BalApiReboot(
+	ctx context.Context,
+	request *bal.BalReboot,
+) (*bal.BalErr, error) {
+	common.Logger().Info("BalApiReboot Called", ctx, request)
+	return &bal.BalErr{Err: bal.BalErrno_BAL_ERR_OK}, nil
+}
+
+func (handler *BalHandler) BalApiHeartbeat(
+	ctx context.Context,
+	request *bal.BalHeartbeat,
+) (*bal.BalRebootState, error) {
+	common.Logger().Info("BalApiHeartbeat Called", ctx, request)
+	return &bal.BalRebootState{}, nil
+}
+
+func (handler *BalHandler) BalCfgStatGet(
+	ctx context.Context,
+	request *bal.BalInterfaceKey,
+) (*bal.BalInterfaceStat, error) {
+	common.Logger().Info("BalCfgStatGet Called", ctx, request)
+	return &bal.BalInterfaceStat{}, nil
+}
diff --git a/ponsim/v2/grpc/nbi/ponsim_handler.go b/ponsim/v2/grpc/nbi/ponsim_handler.go
new file mode 100644
index 0000000..763f4bc
--- /dev/null
+++ b/ponsim/v2/grpc/nbi/ponsim_handler.go
@@ -0,0 +1,327 @@
+package nbi
+
+import (
+	"context"
+	"crypto/tls"
+	"errors"
+	"github.com/golang/protobuf/ptypes/empty"
+	"github.com/google/gopacket"
+	"github.com/google/gopacket/layers"
+	"github.com/opencord/voltha/ponsim/v2/common"
+	"github.com/opencord/voltha/ponsim/v2/core"
+	"github.com/opencord/voltha/protos/go/voltha"
+	"github.com/sirupsen/logrus"
+	"google.golang.org/grpc"
+	"google.golang.org/grpc/credentials"
+	"strconv"
+	"strings"
+)
+
+// TODO: Cleanup GRPC security config
+// TODO: Pass-in the certificate information as a structure parameter
+
+type PonSimHandler struct {
+	device core.PonSimInterface
+}
+
+/*
+NewPonSimHandler instantiates a handler for a PonSim device
+*/
+func NewPonSimHandler(device core.PonSimInterface) *PonSimHandler {
+	var handler *PonSimHandler
+	handler = &PonSimHandler{device: device}
+	return handler
+}
+
+/*
+SendFrame handles and forwards EGRESS packets (i.e. VOLTHA to OLT)
+*/
+func (handler *PonSimHandler) SendFrame(ctx context.Context, data *voltha.PonSimFrame) (*empty.Empty, error) {
+	frame := gopacket.NewPacket(data.Payload, layers.LayerTypeEthernet, gopacket.Default)
+
+	common.Logger().WithFields(logrus.Fields{
+		"handler": handler,
+		"frame":   frame.Dump(),
+	}).Info("Constructed frame")
+
+	handler.device.Forward(context.Background(), 2, frame)
+
+	out := new(empty.Empty)
+	return out, nil
+}
+
+/*
+ReceiveFrames handles a stream of INGRESS packets (i.e. OLT to VOLTHA)
+*/
+func (handler *PonSimHandler) ReceiveFrames(empty *empty.Empty, stream voltha.PonSim_ReceiveFramesServer) error {
+	common.Logger().WithFields(logrus.Fields{
+		"handler": handler,
+	}).Info("start-receiving-frames")
+
+	if _, ok := (handler.device).(*core.PonSimOltDevice); ok {
+		var data []byte
+		var ok bool
+
+		common.Logger().WithFields(logrus.Fields{
+			"handler": handler,
+			"device":  (handler.device).(*core.PonSimOltDevice),
+		}).Info("receiving-frames-from-olt-device")
+
+		for {
+			select {
+			case data, ok = <-(handler.device).(*core.PonSimOltDevice).GetOutgoing():
+				if ok {
+					frame := gopacket.NewPacket(data, layers.LayerTypeEthernet, gopacket.Default)
+					common.Logger().WithFields(logrus.Fields{
+						"handler": handler,
+						"frame":   frame,
+					}).Info("Received incoming data")
+
+					frameBytes := &voltha.PonSimFrame{Id: handler.device.GetAddress(), Payload: data}
+					if err := stream.Send(frameBytes); err != nil {
+						common.Logger().WithFields(logrus.Fields{
+							"handler": handler,
+							"frame":   frame,
+							"error":   err,
+						}).Error("Failed to send incoming data")
+						return err
+					}
+					common.Logger().WithFields(logrus.Fields{
+						"handler": handler,
+						"frame":   frame,
+					}).Info("Sent incoming data")
+
+				} else {
+					return errors.New("incoming data channel has closed")
+				}
+			}
+		}
+
+	} else {
+		common.Logger().WithFields(logrus.Fields{
+			"handler": handler,
+		}).Error("Not handling an OLT device")
+	}
+
+	return nil
+}
+
+/*
+GetDeviceInfo returns information of a PonSim device (OLT or ONU)
+*/
+func (handler *PonSimHandler) GetDeviceInfo(
+	ctx context.Context,
+	empty *empty.Empty,
+) (*voltha.PonSimDeviceInfo, error) {
+	common.Logger().WithFields(logrus.Fields{
+		"handler": handler,
+	}).Info("Getting device information")
+
+	var out *voltha.PonSimDeviceInfo
+
+	// Check which device type we're currently handling
+	if _, ok := (handler.device).(*core.PonSimOltDevice); ok {
+		common.Logger().WithFields(logrus.Fields{
+			"handler": handler,
+		}).Debug("Handling OLT device")
+		keys := make([]int32, 0, len((handler.device).(*core.PonSimOltDevice).GetOnus()))
+		for k := range (handler.device).(*core.PonSimOltDevice).GetOnus() {
+			keys = append(keys, k)
+		}
+		out = &voltha.PonSimDeviceInfo{NniPort: 0, UniPorts: []int32(keys)}
+
+	} else {
+		common.Logger().WithFields(logrus.Fields{
+			"handler": handler,
+		}).Debug("Handling ONU/OTHER device")
+
+		out = &voltha.PonSimDeviceInfo{}
+	}
+
+	common.Logger().WithFields(logrus.Fields{
+		"handler": handler,
+		"result":  out,
+	}).Info("Device information")
+
+	return out, nil
+}
+
+/*
+UpdateFlowTable populates and cleans up the flows for a PonSim device
+*/
+func (handler *PonSimHandler) UpdateFlowTable(
+	ctx context.Context,
+	table *voltha.FlowTable,
+) (*empty.Empty, error) {
+	common.Logger().WithFields(logrus.Fields{
+		"handler": handler,
+		"table":   table,
+	}).Info("Updating flows")
+
+	if _, ok := (handler.device).(*core.PonSimOltDevice); ok {
+		if table.Port == 0 {
+			common.Logger().WithFields(logrus.Fields{
+				"handler": handler,
+				"port":    table.Port,
+			}).Debug("Updating OLT flows")
+
+			if err := (handler.device).(*core.PonSimOltDevice).InstallFlows(ctx, table.Flows); err != nil {
+				common.Logger().WithFields(logrus.Fields{
+					"handler": handler,
+					"error":   err.Error(),
+					"flows":   table.Flows,
+				}).Error("Problem updating flows on OLT")
+			} else {
+				common.Logger().WithFields(logrus.Fields{
+					"handler": handler,
+				}).Debug("Updated OLT flows")
+			}
+
+		} else {
+			common.Logger().WithFields(logrus.Fields{
+				"handler": handler,
+				"port":    table.Port,
+			}).Debug("Updating ONU flows")
+
+			if child, ok := (handler.device).(*core.PonSimOltDevice).GetOnus()[table.Port]; ok {
+				// TODO: make it secure
+				ta := credentials.NewTLS(&tls.Config{
+					InsecureSkipVerify: true,
+				})
+
+				host := strings.Join([]string{
+					child.Device.Address,
+					strconv.Itoa(int(child.Device.Port)),
+				}, ":")
+
+				conn, err := grpc.Dial(
+					host,
+					grpc.WithTransportCredentials(ta),
+				)
+				if err != nil {
+					common.Logger().WithFields(logrus.Fields{
+						"handler": handler,
+						"error":   err.Error(),
+					}).Error("GRPC Connection problem")
+				}
+				defer conn.Close()
+				client := voltha.NewPonSimClient(conn)
+
+				if _, err = client.UpdateFlowTable(ctx, table); err != nil {
+					common.Logger().WithFields(logrus.Fields{
+						"handler": handler,
+						"host":    host,
+						"error":   err.Error(),
+					}).Error("Problem forwarding update request to ONU")
+				}
+			} else {
+				common.Logger().WithFields(logrus.Fields{
+					"handler": handler,
+					"port":    table.Port,
+				}).Warn("Unable to find ONU")
+			}
+
+		}
+	} else if _, ok := (handler.device).(*core.PonSimOnuDevice); ok {
+		if err := (handler.device).(*core.PonSimOnuDevice).InstallFlows(ctx, table.Flows); err != nil {
+			common.Logger().WithFields(logrus.Fields{
+				"handler": handler,
+				"error":   err.Error(),
+				"flows":   table.Flows,
+			}).Error("Problem updating flows on ONU")
+		} else {
+			common.Logger().WithFields(logrus.Fields{
+				"handler": handler,
+			}).Debug("Updated ONU flows")
+		}
+	} else {
+		common.Logger().WithFields(logrus.Fields{
+			"handler": handler,
+			"port":    table.Port,
+		}).Warn("Unknown device")
+	}
+
+	common.Logger().WithFields(logrus.Fields{
+		"handler": handler,
+		"table":   table,
+	}).Info("Updated flows")
+
+	out := new(empty.Empty)
+	return out, nil
+}
+
+/*
+GetStats retrieves statistics for a PonSim device
+*/
+func (handler *PonSimHandler) GetStats(
+	ctx context.Context,
+	empty *empty.Empty,
+) (*voltha.PonSimMetrics, error) {
+	common.Logger().WithFields(logrus.Fields{
+		"handler": handler,
+	}).Info("Retrieving stats")
+
+	var metrics *voltha.PonSimMetrics = new(voltha.PonSimMetrics)
+
+	if olt, ok := (handler.device).(*core.PonSimOltDevice); ok {
+		common.Logger().WithFields(logrus.Fields{
+			"handler": handler,
+			"olt":     olt,
+		}).Debug("Retrieving stats for OLT")
+
+		// Get stats for current device
+
+		// Loop through each onus to get stats from those as well?
+		// send grpc request to each onu
+		for _, child := range (handler.device).(*core.PonSimOltDevice).GetOnus() {
+			// TODO: make it secure
+			ta := credentials.NewTLS(&tls.Config{
+				InsecureSkipVerify: true,
+			})
+
+			host := strings.Join([]string{child.Device.Address, strconv.Itoa(int(child.Device.Port))}, ":")
+			conn, err := grpc.Dial(
+				host,
+				grpc.WithTransportCredentials(ta),
+			)
+			if err != nil {
+				common.Logger().WithFields(logrus.Fields{
+					"handler": handler,
+					"error":   err.Error(),
+				}).Error("GRPC Connection problem")
+			}
+			defer conn.Close()
+			client := voltha.NewPonSimClient(conn)
+
+			if _, err = client.GetStats(ctx, empty); err != nil {
+				common.Logger().WithFields(logrus.Fields{
+					"handler": handler,
+					"host":    host,
+					"error":   err.Error(),
+				}).Error("Problem forwarding stats request to ONU")
+			}
+		}
+		metrics = (handler.device).(*core.PonSimOltDevice).Counter.MakeProto()
+
+		common.Logger().WithFields(logrus.Fields{
+			"handler": handler,
+			"metrics": metrics,
+		}).Debug("OLT Metrics")
+
+	} else if onu, ok := (handler.device).(*core.PonSimOnuDevice); ok {
+		common.Logger().WithFields(logrus.Fields{
+			"handler": handler,
+			"onu":     onu,
+		}).Debug("Retrieving stats for ONU")
+	} else {
+		common.Logger().WithFields(logrus.Fields{
+			"handler": handler,
+		}).Warn("Unknown device")
+	}
+
+	common.Logger().WithFields(logrus.Fields{
+		"handler": handler,
+	}).Info("Retrieved stats")
+
+	return metrics, nil
+}
diff --git a/ponsim/v2/grpc/nbi/xponsim_handler.go b/ponsim/v2/grpc/nbi/xponsim_handler.go
new file mode 100644
index 0000000..fbc63eb
--- /dev/null
+++ b/ponsim/v2/grpc/nbi/xponsim_handler.go
@@ -0,0 +1,124 @@
+package nbi
+
+import (
+	"context"
+	"github.com/golang/protobuf/ptypes/empty"
+	"github.com/opencord/voltha/ponsim/v2/core"
+	"github.com/opencord/voltha/protos/go/voltha"
+)
+
+type XPonSimHandler struct {
+	device *core.XPonSimDevice
+}
+
+func NewXPonSimHandler() *XPonSimHandler {
+	var handler *XPonSimHandler
+	handler = &XPonSimHandler{}
+	return handler
+}
+
+func (handler *XPonSimHandler) CreateInterface(
+	ctx context.Context,
+	config *voltha.InterfaceConfig,
+) (*empty.Empty, error) {
+	handler.device.CreateInterface(ctx, config)
+	return &empty.Empty{}, nil
+}
+func (handler *XPonSimHandler) UpdateInterface(
+	ctx context.Context,
+	config *voltha.InterfaceConfig,
+) (*empty.Empty, error) {
+	handler.device.UpdateInterface(ctx, config)
+	return &empty.Empty{}, nil
+}
+func (handler *XPonSimHandler) RemoveInterface(
+	ctx context.Context,
+	config *voltha.InterfaceConfig,
+) (*empty.Empty, error) {
+	handler.device.RemoveInterface(ctx, config)
+	return &empty.Empty{}, nil
+}
+func (handler *XPonSimHandler) CreateTcont(
+	ctx context.Context,
+	config *voltha.TcontInterfaceConfig,
+) (*empty.Empty, error) {
+	handler.device.CreateTcont(ctx, config.TcontsConfigData, config.TrafficDescriptorProfileConfigData)
+	return &empty.Empty{}, nil
+}
+func (handler *XPonSimHandler) UpdateTcont(
+	ctx context.Context,
+	config *voltha.TcontInterfaceConfig,
+) (*empty.Empty, error) {
+	handler.device.UpdateTcont(ctx, config.TcontsConfigData, config.TrafficDescriptorProfileConfigData)
+	return &empty.Empty{}, nil
+}
+func (handler *XPonSimHandler) RemoveTcont(
+	ctx context.Context,
+	config *voltha.TcontInterfaceConfig,
+) (*empty.Empty, error) {
+	handler.device.RemoveTcont(ctx, config.TcontsConfigData, config.TrafficDescriptorProfileConfigData)
+	return &empty.Empty{}, nil
+}
+func (handler *XPonSimHandler) CreateGemport(
+	ctx context.Context,
+	config *voltha.InterfaceConfig,
+) (*empty.Empty, error) {
+	handler.device.CreateGemport(ctx, config)
+	return &empty.Empty{}, nil
+}
+func (handler *XPonSimHandler) UpdateGemport(
+	ctx context.Context,
+	config *voltha.InterfaceConfig,
+) (*empty.Empty, error) {
+	handler.device.UpdateGemport(ctx, config)
+	return &empty.Empty{}, nil
+}
+func (handler *XPonSimHandler) RemoveGemport(
+	ctx context.Context,
+	config *voltha.InterfaceConfig,
+) (*empty.Empty, error) {
+	handler.device.RemoveGemport(ctx, config)
+	return &empty.Empty{}, nil
+}
+func (handler *XPonSimHandler) CreateMulticastGemport(
+	ctx context.Context,
+	config *voltha.InterfaceConfig,
+) (*empty.Empty, error) {
+	handler.device.CreateMulticastGemport(ctx, config)
+	return &empty.Empty{}, nil
+}
+func (handler *XPonSimHandler) UpdateMulticastGemport(
+	ctx context.Context,
+	config *voltha.InterfaceConfig,
+) (*empty.Empty, error) {
+	handler.device.UpdateMulticastGemport(ctx, config)
+	return &empty.Empty{}, nil
+}
+func (handler *XPonSimHandler) RemoveMulticastGemport(
+	ctx context.Context,
+	config *voltha.InterfaceConfig,
+) (*empty.Empty, error) {
+	handler.device.RemoveMulticastGemport(ctx, config)
+	return &empty.Empty{}, nil
+}
+func (handler *XPonSimHandler) CreateMulticastDistributionSet(
+	ctx context.Context,
+	config *voltha.InterfaceConfig,
+) (*empty.Empty, error) {
+	handler.device.CreateMulticastDistributionSet(ctx, config)
+	return &empty.Empty{}, nil
+}
+func (handler *XPonSimHandler) UpdateMulticastDistributionSet(
+	ctx context.Context,
+	config *voltha.InterfaceConfig,
+) (*empty.Empty, error) {
+	handler.device.UpdateMulticastDistributionSet(ctx, config)
+	return &empty.Empty{}, nil
+}
+func (handler *XPonSimHandler) RemoveMulticastDistributionSet(
+	ctx context.Context,
+	config *voltha.InterfaceConfig,
+) (*empty.Empty, error) {
+	handler.device.RemoveMulticastDistributionSet(ctx, config)
+	return &empty.Empty{}, nil
+}