SEBA-256
Added cmd line switches to AbstractOLT and Client

Change-Id: Ib55e1bf62e90ee49508073c9fdf1b50ae6d8ba64
diff --git a/api/abstract_olt_api.proto b/api/abstract_olt_api.proto
index 6da61c8..fb4aee7 100644
--- a/api/abstract_olt_api.proto
+++ b/api/abstract_olt_api.proto
@@ -16,6 +16,13 @@
 package api;
 import "google/api/annotations.proto";
 
+message EchoMessage{
+   string Ping =1;
+}
+message EchoReplyMessage{
+   string Pong =1;
+}
+
 message AddChassisMessage{
    string CLLI =1;
    string VCoreIP =2;
@@ -75,6 +82,12 @@
    bool Success=1;
 }
 service AbstractOLT{
+   rpc Echo(EchoMessage) returns (EchoReplyMessage){
+      option(google.api.http)={
+        post:"/v1/Echo"
+	body:"*"
+      };
+   }
    rpc CreateChassis(AddChassisMessage) returns (AddChassisReturn) {
       option(google.api.http) = {
          post: "/v1/CreateAbstractChassis"
diff --git a/api/handler.go b/api/handler.go
index bb1a9b3..54115a6 100644
--- a/api/handler.go
+++ b/api/handler.go
@@ -36,6 +36,12 @@
 type Server struct {
 }
 
+func (s *Server) Echo(ctx context.Context, in *EchoMessage) (*EchoReplyMessage, error) {
+	ping := in.GetPing()
+	pong := EchoReplyMessage{Pong: ping}
+	return &pong, nil
+}
+
 /*
 CreateChassis - allocates a new Chassis struct and stores it in chassisMap
 */
diff --git a/client/main.go b/client/main.go
index 884274b..af87ec7 100644
--- a/client/main.go
+++ b/client/main.go
@@ -22,6 +22,7 @@
 	"fmt"
 	"log"
 	"runtime/debug"
+	"strings"
 
 	"gerrit.opencord.org/abstract-olt/api"
 	"google.golang.org/grpc"
@@ -29,6 +30,8 @@
 )
 
 func main() {
+	echo := flag.Bool("e", false, "echo")
+	message := flag.String("message", "ping", "message to be echoed back")
 	create := flag.Bool("c", false, "create?")
 	addOlt := flag.Bool("s", false, "addOlt?")
 	provOnt := flag.Bool("o", false, "provisionOnt?")
@@ -46,30 +49,56 @@
 	port := flag.Uint("port", 1, "port number 1-16 to provision ont to")
 	ont := flag.Uint("ont", 1, "ont number 1-64")
 	serial := flag.String("serial", "", "serial number of ont")
+	useSsl := flag.Bool("ssl", false, "use ssl")
+	useAuth := flag.Bool("auth", false, "use auth")
+	crtFile := flag.String("cert", "cert/server.crt", "Public cert for server to establish tls session")
+	serverAddressPort := flag.String("server", "localhost:7777", "address and port of AbstractOLT server")
+	fqdn := flag.String("fqdn", "", "FQDN of the service to match what is in server.crt")
 
 	flag.Parse()
+	if *useSsl {
+		if *fqdn == "" {
+			fqdn = &(strings.Split(*serverAddressPort, ":")[0])
+			fmt.Printf("using %s as the FQDN for the AbstractOLT server", *fqdn)
+		}
+	}
 
-	if (*create && *addOlt) || (*create && *provOnt) || (*addOlt && *provOnt) {
+	if (*echo && *addOlt) || (*echo && *create) || (*echo && *provOnt) || (*create && *addOlt) || (*create && *provOnt) || (*addOlt && *provOnt) {
 		fmt.Println("You can only call one method at a time")
 		usage()
 		return
 	}
-	if !(*create || *provOnt || *addOlt) {
+	if !(*create || *provOnt || *addOlt || *echo) {
 		fmt.Println("You didn't specify an operation to perform")
 		usage()
 		return
 	}
 	var conn *grpc.ClientConn
-	creds, err := credentials.NewClientTLSFromFile("cert/server.crt", "AbstractOLT.dev.atl.foundry.att.com")
-	if err != nil {
-		log.Fatalf("could not load tls cert: %s", err)
-	}
+	var err error
+
 	// Setup the login/pass
 	auth := Authentication{
 		Login:    "john",
 		Password: "doe",
 	}
-	conn, err = grpc.Dial(":7777", grpc.WithTransportCredentials(creds), grpc.WithPerRPCCredentials(&auth))
+	if *useSsl && *useAuth {
+
+		creds, err := credentials.NewClientTLSFromFile(*crtFile, *fqdn)
+		conn, err = grpc.Dial(*serverAddressPort, grpc.WithTransportCredentials(creds), grpc.WithPerRPCCredentials(&auth))
+		if err != nil {
+			log.Fatalf("could not load tls cert: %s", err)
+		}
+	} else if *useSsl {
+		creds, err := credentials.NewClientTLSFromFile("cert/server.crt", *fqdn)
+		conn, err = grpc.Dial(*serverAddressPort, grpc.WithTransportCredentials(creds))
+		if err != nil {
+			log.Fatalf("could not load tls cert: %s", err)
+		}
+	} else if *useAuth {
+		conn, err = grpc.Dial(*serverAddressPort, grpc.WithInsecure(), grpc.WithPerRPCCredentials(&auth))
+	} else {
+		conn, err = grpc.Dial(*serverAddressPort, grpc.WithInsecure())
+	}
 	if err != nil {
 		log.Fatalf("did not connect: %s", err)
 	}
@@ -82,10 +111,10 @@
 		addOltChassis(c, clli, oltAddress, oltPort, name, driver, oltType)
 	} else if *provOnt {
 		provisionONT(c, clli, slot, port, ont, serial)
-	} else {
+	} else if *echo {
+		ping(c, *message)
 	}
 
-	fmt.Println("TODO - Do something")
 }
 
 // Authentication holds the login/password
@@ -106,6 +135,15 @@
 func (a *Authentication) RequireTransportSecurity() bool {
 	return true
 }
+func ping(c api.AbstractOLTClient, message string) error {
+	response, err := c.Echo(context.Background(), &api.EchoMessage{Ping: message})
+	if err != nil {
+		fmt.Printf("Error when calling Echo: %s", err)
+		return err
+	}
+	log.Printf("Response from server: %s", response.GetPong())
+	return nil
+}
 
 func createChassis(c api.AbstractOLTClient, clli *string, xosAddress *string, xosPort *uint, rack *uint, shelf *uint) error {
 	fmt.Println("Calling Create Chassis")
@@ -169,8 +207,15 @@
 }
 func usage() {
 	var output = `
-   Usage ./client -[methodFlag] params
-   methFlags:
+	Usage ./client -server=[serverAddress:port] -[methodFlag] params
+	./client -ssl -fqdn=FQDN_OF_ABSTRACT_OLT_SERVER.CRT -cert PATH_TO_SERVER.CRT -server=[serverAddress:port] -[methodFlag] params : use ssl
+	./client -auth -server=[serverAddress:port] -[methodFlag] params : Authenticate session
+
+   methodFlags:
+   -e echo # used to test connectivity to server NOOP
+      params:
+	 -message string to be echoed back from the server
+	 e.g. ./client -server=localhost:7777 -e -message MESSAGE_TO_BE_ECHOED
    -c create chassis
       params:
          -clli CLLI_NAME
@@ -178,7 +223,7 @@
 	 -xos_port XOS_TOSCA_LISTEN_PORT
 	 -rack [optional default 1]
 	 -shelf [optional default 1]
-   e.g. ./client -c -clli MY_CLLI -xos_address 192.168.0.1 -xos_port 30007 -rack 1 -shelf 1
+	 e.g. ./client -server=localhost:7777 -c -clli MY_CLLI -xos_address 192.168.0.1 -xos_port 30007 -rack 1 -shelf 1
    -s add physical olt chassis to chassis
       params:
          -clli CLLI_NAME - identifies abstract chassis to assign olt chassis to
@@ -187,7 +232,7 @@
 	 -name - OLT_NAME internal human readable name to identify OLT_CHASSIS
 	 -driver [openolt,asfvolt16,adtran,tibits] - used to tell XOS which driver should be used to manange chassis
 	 -type [edgecore,adtran,tibit] - used to tell AbstractOLT how many ports are available on olt chassis
-   e.g. ./client -s -clli MY_CLLI -olt_address 192.168.1.100 -olt_port=9191 -name=slot1 -driver=openolt -type=adtran
+	 e.g. ./client -server abstractOltHost:7777 -s -clli MY_CLLI -olt_address 192.168.1.100 -olt_port=9191 -name=slot1 -driver=openolt -type=adtran
    -o provision ont - adds ont to whitelist in XOS  on a specific port on a specific olt chassis based on abstract -> phyisical mapping
       params:
 	 -clli CLLI_NAME
@@ -195,7 +240,7 @@
 	 -port OLT_PORT_NUMBER [1-16]
 	 -ont ONT_NUMBER [1-64]
 	 -serial ONT_SERIAL_NUM
-	e.g. ./client -o -clli=MY_CLLI -slot=1 -port=1 -ont=22 -serial=aer900jasdf `
+	 e.g. ./client -server=localhost:7777 -o -clli=MY_CLLI -slot=1 -port=1 -ont=22 -serial=aer900jasdf `
 
 	fmt.Println(output)
 }
diff --git a/cmd/AbstractOLT/AbstractOLT.go b/cmd/AbstractOLT/AbstractOLT.go
index 57ef9cd..8527ff6 100644
--- a/cmd/AbstractOLT/AbstractOLT.go
+++ b/cmd/AbstractOLT/AbstractOLT.go
@@ -37,6 +37,10 @@
 // private type for Context keys
 type contextKey int
 
+var useSsl *bool
+var useAuthentication *bool
+var certDirectory *string
+
 const (
 	clientIDKey contextKey = iota
 )
@@ -53,6 +57,7 @@
 
 // authenticateAgent check the client credentials
 func authenticateClient(ctx context.Context, s *api.Server) (string, error) {
+	//TODO if we decide to handle Authentication with AbstractOLT this will need to be bound to an authentication service
 	if md, ok := metadata.FromIncomingContext(ctx); ok {
 		clientLogin := strings.Join(md["login"], "")
 		clientPassword := strings.Join(md["password"], "")
@@ -86,9 +91,13 @@
 }
 
 func startGRPCServer(address, certFile, keyFile string) error {
+	if settings.GetDebug() {
+		log.Printf("startGRPCServer(LisenAddress:%s,CertFile:%s,KeyFile:%s\n", address, certFile, keyFile)
+	}
 	// create a listener on TCP port
 	lis, err := net.Listen("tcp", address)
 	if err != nil {
+		log.Printf("startGRPCServer failed to start with %v\n", err)
 		return fmt.Errorf("failed to listen: %v", err)
 	}
 
@@ -102,8 +111,17 @@
 	}
 
 	// Create an array of gRPC options with the credentials
-	opts := []grpc.ServerOption{grpc.Creds(creds),
-		grpc.UnaryInterceptor(unaryInterceptor)}
+	var opts []grpc.ServerOption
+	if *useSsl && *useAuthentication {
+		opts = []grpc.ServerOption{grpc.Creds(creds),
+			grpc.UnaryInterceptor(unaryInterceptor)}
+	} else if *useAuthentication {
+		opts = []grpc.ServerOption{grpc.UnaryInterceptor(unaryInterceptor)}
+	} else if *useSsl {
+		opts = []grpc.ServerOption{grpc.Creds(creds)}
+	} else {
+		opts = []grpc.ServerOption{}
+	}
 
 	// create a gRPC server object
 	grpcServer := grpc.NewServer(opts...)
@@ -120,11 +138,19 @@
 	return nil
 }
 func startRESTServer(address, grpcAddress, certFile string) error {
+	if settings.GetDebug() {
+		log.Printf("startRESTServer(Address:%s, GRPCAddress:%s,Cert File:%s\n", address, grpcAddress, certFile)
+	}
 	ctx := context.Background()
 	ctx, cancel := context.WithCancel(ctx)
 	defer cancel()
+	var mux *runtime.ServeMux
 
-	mux := runtime.NewServeMux(runtime.WithIncomingHeaderMatcher(credMatcher))
+	if *useAuthentication {
+		mux = runtime.NewServeMux(runtime.WithIncomingHeaderMatcher(credMatcher))
+	} else {
+		mux = runtime.NewServeMux()
+	}
 	creds, err := credentials.NewClientTLSFromFile(certFile, "")
 	if err != nil {
 		return fmt.Errorf("could not load TLS certificate: %s", err)
@@ -144,21 +170,51 @@
 }
 func main() {
 	debugPtr := flag.Bool("d", false, "Log Level Debug")
-	flag.Parse()
-	settings.SetDebug(*debugPtr)
+	useAuthentication = flag.Bool("a", false, "Use Authentication")
+	useSsl = flag.Bool("s", false, "Use SSL")
+	certDirectory = flag.String("cert_dir", "cert", "Directory where key files exist")
+	listenAddress := flag.String("listenAddress", "localhost", "IP Address to listen on")
+	grpcPort := flag.String("grpc_port", "7777", "Port to listen for GRPC")
+	restPort := flag.String("rest_port", "7778", "Port to listen for Rest Server")
+	logFile := flag.String("log_file", "AbstractOLT.log", "Name of the LogFile to write to")
+	h := flag.Bool("h", false, "Show usage")
+	help := flag.Bool("help", false, "Show usage")
 
-	file, err := os.OpenFile("AbstractOLT.log", os.O_CREATE|os.O_WRONLY|os.O_APPEND, 0666)
+	flag.Parse()
+
+	if *help || *h {
+		var usage = `./AbstractOLT -d [default false] : Runs in Debug mode
+Params:
+      -s [default false] -cert_dir [default $WORKING_DIR/cert]  DIR : Runs in SSL mode with server.crt and server.key found in  DIR
+      -a [default false] : Run in Authentication mode currently very basic
+      -listenAddress IP_ADDRESS [default localhost] -grpc_port [default 7777] PORT1 -rest_port [default 7778] PORT2: Listen for grpc on IP_ADDRESS:PORT1 and rest on IP_ADDRESS:PORT2
+      -log_file [default $WORKING_DIR/AbstractOLT.log] LOG_FILE
+      -h(elp) print this usage
+`
+		fmt.Println(usage)
+		return
+	}
+	settings.SetDebug(*debugPtr)
+	fmt.Println("Startup Params: debug:", *debugPtr, " Authentication:", *useAuthentication, " SSL:", *useSsl, "Cert Directory", *certDirectory,
+		"ListenAddress:", *listenAddress, " grpc port:", *grpcPort, " rest port:", *restPort, "Logging to ", *logFile)
+
+	file, err := os.OpenFile(*logFile, os.O_CREATE|os.O_WRONLY|os.O_APPEND, 0666)
 	if err != nil {
 		log.Fatalln("Failed to open log file", file, ":", err)
 	}
 	log.SetOutput(file)
 	log.SetFlags(log.Ldate | log.Ltime | log.Lmicroseconds | log.Lshortfile)
 	log.Printf("Setting Debug to %t\n", settings.GetDebug())
+	if settings.GetDebug() {
+		log.Println("Startup Params: debug:", *debugPtr, " Authentication:", *useAuthentication, " SSL:", *useSsl, "Cert Directory", *certDirectory,
+			"ListenAddress:", *listenAddress, " grpc port:", *grpcPort, " rest port:", *restPort, "Logging to ", *logFile)
+	}
 
-	grpcAddress := fmt.Sprintf("%s:%d", "AbstractOLT.dev.atl.foundry.att.com", 7777)
-	restAddress := fmt.Sprintf("%s:%d", "AbstractOLT.dev.atl.foundry.att.com", 7778)
-	certFile := "cert/server.crt"
-	keyFile := "cert/server.key"
+	grpcAddress := fmt.Sprintf("%s:%s", *listenAddress, *grpcPort)
+	restAddress := fmt.Sprintf("%s:%s", *listenAddress, *restPort)
+
+	certFile := fmt.Sprintf("%s/server.crt", *certDirectory)
+	keyFile := fmt.Sprintf("%s/server.key", *certDirectory)
 
 	// fire the gRPC server in a goroutine
 	go func() {
@@ -179,5 +235,6 @@
 	// infinite loop
 	log.Printf("Entering infinite loop")
 	select {}
+	//TODO publish periodic stats etc
 	fmt.Println("AbstractOLT")
 }