Implemented the provision / activate ont workflow

Change-Id: Ife684f41e54e176879332922ad86f517358f15e7
diff --git a/Makefile b/Makefile
index 591f6bb..c4fd8f3 100644
--- a/Makefile
+++ b/Makefile
@@ -25,7 +25,7 @@
 PKG_LIST := $(shell go list ${PKG}/... | grep -v /vendor/)
 
 
-.PHONY: all api server client
+.PHONY: all api server client test
 
 all: server client
 
@@ -43,7 +43,15 @@
 	--grpc-gateway_out=logtostderr=true:api \
 	 api/abstract_olt_api.proto
 
-api/xos.go:
+api/xos.pb.go:
+	@protoc -I seba-api/ \
+	   -I${GOPATH}/src \
+	  -I${GOPATH}/src/github.com/grpc-ecosystem/grpc-gateway/third_party/googleapis \
+	  -I${GOPATH}/src/github.com/googleapis/google/api \
+	  -I${GOPATH}/src/github.com/googleapis/ \
+	  --go_out=plugins=grpc:seba-api \
+	  seba-api/xos.proto
+
 
 swagger:
 	@protoc -I api/ \
diff --git a/api/abstract_olt_api.proto b/api/abstract_olt_api.proto
index cf6e378..86f9a72 100644
--- a/api/abstract_olt_api.proto
+++ b/api/abstract_olt_api.proto
@@ -65,8 +65,8 @@
    Error error = 2;
 }
 message AddOntMessage{
-   string ChassisDeviceID=1;
-   string SlotDeviceID=2;
+   string CLLI=1;
+   int32 SlotNumber=2;
    int32 PortNumber=3;
    int32 OntNumber=4;
    string SerialNumber=5;
@@ -76,32 +76,31 @@
    Error error = 2;
 }
 
-service AddChassis{
+service AbstractOLT{
    rpc CreateChassis(AddChassisMessage) returns (AddChassisReturn) {
       option(google.api.http) = {
-         post: "/1/CreateAbstractChassis"
+         post: "/v1/CreateAbstractChassis"
 	 body:"*"
       };
    }
-}
 
-service AddOLTChassis {
    rpc CreateOLTChassis(AddOLTChassisMessage) returns (AddOLTChassisReturn) {
       option(google.api.http) = {
-         post: "/1/CreateOLTChassis"
+         post: "/v1/CreateOLTChassis"
 	 body:"*"
       };
    }
-}
-service ActivateSlot{
    rpc EnableSlot(ActivateSlotMessage) returns (ActivateSlotReturn){
       option(google.api.http) = {
-         post: "/1/EnableSlot"
+         post: "/v1/EnableSlot"
 	 body:"*"
       };
    }
-}
-service ActivateOnt {
-   rpc ProvisionOnt(AddOntMessage) returns (AddOntReturn) {}
+   rpc ProvisionOnt(AddOntMessage) returns (AddOntReturn) {
+      option(google.api.http) = {
+         post:"/v1/ProvsionOnt"
+	 body:"*"
+      };
+   }
 }
 
diff --git a/api/handler.go b/api/handler.go
index 7414e19..4aeae13 100644
--- a/api/handler.go
+++ b/api/handler.go
@@ -17,6 +17,7 @@
 package api
 
 import (
+	"errors"
 	"fmt"
 	"log"
 	"net"
@@ -47,7 +48,7 @@
 		return &AddChassisReturn{DeviceID: chassis.CLLI}, nil
 	}
 	abstractChassis := abstract.GenerateChassis(clli)
-	phyChassis := &physical.Chassis{CLLI: clli}
+	phyChassis := &physical.Chassis{CLLI: clli, VCoreAddress: net.TCPAddr{IP: net.ParseIP(in.GetVCoreIP()), Port: int(in.GetVCorePort())}}
 	if settings.GetDebug() {
 		output := fmt.Sprintf("%v", abstractChassis)
 		formatted := strings.Replace(output, "{", "\n{", -1)
@@ -71,7 +72,7 @@
 	}
 	oltType := in.GetType()
 	address := net.TCPAddr{IP: net.ParseIP(in.GetSlotIP()), Port: int(in.GetSlotPort())}
-	sOlt := physical.SimpleOLT{CLLI: clli, Hostname: in.GetHostname(), Address: address}
+	sOlt := physical.SimpleOLT{CLLI: clli, Hostname: in.GetHostname(), Address: address, Parent: chassis}
 
 	var olt physical.OLT
 	switch oltType {
@@ -95,7 +96,7 @@
 in the physical card to those in the abstract model
 */
 func AddCard(physChassis *physical.Chassis, olt physical.OLT) error {
-	physChassis.Linecards = append(physChassis.Linecards, olt)
+	physChassis.AddOLTChassis(olt)
 
 	ports := olt.GetPorts()
 	absChassis := (*models.GetAbstractChassisMap())[physChassis.CLLI]
@@ -105,7 +106,28 @@
 		absPort.PhysPort = &ports[i]
 		//AssignTraits(&ports[i], absPort)
 	}
-
 	//should probably worry about error at some point
 	return nil
 }
+
+/*
+EnableSlot - activates an OLT Chassis
+*/
+func (s *Server) EnableSlot(ctx context.Context, in *ActivateSlotMessage) (*ActivateSlotReturn, error) {
+	return nil, errors.New("garbage error")
+}
+
+/*
+ProvisionOnt provisions an ONT on a specific Chassis/LineCard/Port
+*/
+func (s *Server) ProvisionOnt(ctx context.Context, in *AddOntMessage) (*AddOntReturn, error) {
+	absChassisMap := models.GetAbstractChassisMap()
+	clli := in.GetCLLI()
+	chassis := (*absChassisMap)[clli]
+	err := chassis.ActivateONT(int(in.GetSlotNumber()), int(in.GetPortNumber()), int(in.GetPortNumber()), in.GetSerialNumber())
+
+	if err != nil {
+		return nil, err
+	}
+	return &AddOntReturn{Success: true}, nil
+}
diff --git a/api/handler_test.go b/api/handler_test.go
index 6121242..50c5355 100644
--- a/api/handler_test.go
+++ b/api/handler_test.go
@@ -21,10 +21,12 @@
 	"testing"
 
 	"gerrit.opencord.org/abstract-olt/api"
+	"gerrit.opencord.org/abstract-olt/models/abstract"
 	"golang.org/x/net/context"
 )
 
 var clli string
+var slotHostname = "SlotOne"
 var ctx context.Context
 var server api.Server
 
@@ -41,8 +43,9 @@
 
 }
 func TestHandler_CreateOLTChassis(t *testing.T) {
+	fmt.Println("in handlerTest_CreateChassis")
 	message := &api.AddOLTChassisMessage{CLLI: clli, SlotIP: "12.2.2.0", SlotPort: 9191,
-		Hostname: "SlotOne", Type: api.AddOLTChassisMessage_edgecore}
+		Hostname: slotHostname, Type: api.AddOLTChassisMessage_edgecore}
 	ret, err := server.CreateOLTChassis(ctx, message)
 	if err != nil {
 		t.Fatalf("CreateOLTChassis failed %v\n", err)
@@ -50,3 +53,30 @@
 	fmt.Printf("CreateOLTChassis success %v\n", ret)
 
 }
+func TestHandler_ProvisionOnt(t *testing.T) {
+	ctx = context.Background()
+	server = api.Server{}
+	fmt.Println("in handlerTest_CreateChassis")
+	// this one should succeed
+	message := &api.AddOntMessage{CLLI: clli, SlotNumber: 1, PortNumber: 3, OntNumber: 2, SerialNumber: "2033029402"}
+	ret, err := server.ProvisionOnt(ctx, message)
+	if err != nil {
+		t.Fatalf("ProvisionOnt failed %v\n", err)
+	}
+	// this one should fail
+	fmt.Println("here")
+	message = &api.AddOntMessage{CLLI: clli, SlotNumber: 2, PortNumber: 3, OntNumber: 2, SerialNumber: "2033029402"}
+	ret, err = server.ProvisionOnt(ctx, message)
+	if err != nil {
+		switch err.(type) {
+		case *abstract.UnprovisonedPortError:
+			fmt.Printf("ProvisionOnt failed as it should with %v\n", err)
+		default:
+			t.Fatalf("ProvsionOnt test failed with %v\n", err)
+		}
+	} else {
+		t.Fatalf("ProvsionOnt should have failed but didn't")
+	}
+	fmt.Printf("ProvisionOnt success %v\n", ret)
+
+}
diff --git a/client/main.go b/client/main.go
index 5594a09..94cd1e5 100644
--- a/client/main.go
+++ b/client/main.go
@@ -63,15 +63,14 @@
 	}
 	defer conn.Close()
 
-	c := api.NewAddChassisClient(conn)
+	c := api.NewAbstractOLTClient(conn)
 
 	response, err := c.CreateChassis(context.Background(), &api.AddChassisMessage{CLLI: "my cilli", VCoreIP: "192.168.0.1", VCorePort: 9191})
 	if err != nil {
 		log.Fatalf("Error when calling SayHello: %s", err)
 	}
 	log.Printf("Response from server: %s", response.GetDeviceID())
-	d := api.NewAddOLTChassisClient(conn)
-	newResponse, err := d.CreateOLTChassis(context.Background(), &api.AddOLTChassisMessage{CLLI: "my cilli", SlotIP: "12.2.2.0", SlotPort: 9191, Hostname: "SlotOne", Type: api.AddOLTChassisMessage_edgecore})
+	newResponse, err := c.CreateOLTChassis(context.Background(), &api.AddOLTChassisMessage{CLLI: "my cilli", SlotIP: "12.2.2.0", SlotPort: 9191, Hostname: "SlotOne", Type: api.AddOLTChassisMessage_edgecore})
 	if err != nil {
 		debug.PrintStack()
 		log.Fatalf("Error when calling SayHello: %s", err)
diff --git a/cmd/AbstractOLT/AbstractOLT.go b/cmd/AbstractOLT/AbstractOLT.go
index 19acd72..57ef9cd 100644
--- a/cmd/AbstractOLT/AbstractOLT.go
+++ b/cmd/AbstractOLT/AbstractOLT.go
@@ -109,8 +109,7 @@
 	grpcServer := grpc.NewServer(opts...)
 
 	// attach the Ping service to the server
-	api.RegisterAddChassisServer(grpcServer, &s)
-	api.RegisterAddOLTChassisServer(grpcServer, &s)
+	api.RegisterAbstractOLTServer(grpcServer, &s)
 
 	// start the server
 	log.Printf("starting HTTP/2 gRPC server on %s", address)
@@ -133,8 +132,7 @@
 
 	// Setup the client gRPC options
 	opts := []grpc.DialOption{grpc.WithTransportCredentials(creds)}
-	err = api.RegisterAddChassisHandlerFromEndpoint(ctx, mux, grpcAddress, opts)
-	_ = api.RegisterAddOLTChassisHandlerFromEndpoint(ctx, mux, grpcAddress, opts)
+	err = api.RegisterAbstractOLTHandlerFromEndpoint(ctx, mux, grpcAddress, opts)
 	if err != nil {
 		return fmt.Errorf("could not register service Ping: %s", err)
 	}
diff --git a/models/abstract/ChassisUtils.go b/models/abstract/ChassisUtils.go
index 4c41698..2377453 100644
--- a/models/abstract/ChassisUtils.go
+++ b/models/abstract/ChassisUtils.go
@@ -16,8 +16,6 @@
 
 package abstract
 
-import "errors"
-
 /*
 GenerateChassis - constructs a new AbstractOLT Chassis
 */
@@ -82,24 +80,3 @@
 /*
 NextPort pulls the first unMapped port in the abstract chassis so the next physical port can be mapped to it
 */
-func (chassis *Chassis) NextPort() (*Port, error) {
-	info := &chassis.AllocInfo
-
-	if info.outOfPorts {
-		return nil, errors.New("Abstract chassis out of ports")
-	}
-
-	nextPort := &chassis.Slots[info.slot].Ports[info.port]
-
-	info.port++
-	if info.port == MAX_PORTS {
-		info.port = 0
-		info.slot++
-		if info.slot == MAX_SLOTS {
-			info.slot = 0
-			info.outOfPorts = true
-		}
-	}
-
-	return nextPort, nil
-}
diff --git a/models/abstract/chassis.go b/models/abstract/chassis.go
index 52de90d..74a288c 100644
--- a/models/abstract/chassis.go
+++ b/models/abstract/chassis.go
@@ -16,6 +16,8 @@
 
 package abstract
 
+import "errors"
+
 const MAX_SLOTS int = 16
 const MAX_PORTS int = 16
 
@@ -34,3 +36,29 @@
 	port       int
 	outOfPorts bool
 }
+
+func (chassis *Chassis) NextPort() (*Port, error) {
+	info := &chassis.AllocInfo
+
+	if info.outOfPorts {
+		return nil, errors.New("Abstract chassis out of ports")
+	}
+
+	nextPort := &chassis.Slots[info.slot].Ports[info.port]
+
+	info.port++
+	if info.port == MAX_PORTS {
+		info.port = 0
+		info.slot++
+		if info.slot == MAX_SLOTS {
+			info.slot = 0
+			info.outOfPorts = true
+		}
+	}
+
+	return nextPort, nil
+}
+func (chassis *Chassis) ActivateONT(slotNumber int, portNumber int, ontNumber int, serialNumber string) error {
+	err := chassis.Slots[slotNumber-1].Ports[portNumber].provisionOnt(ontNumber, serialNumber)
+	return err
+}
diff --git a/models/abstract/port.go b/models/abstract/port.go
index c23249a..5dfa195 100644
--- a/models/abstract/port.go
+++ b/models/abstract/port.go
@@ -16,7 +16,11 @@
 
 package abstract
 
-import "gerrit.opencord.org/abstract-olt/models/physical"
+import (
+	"fmt"
+
+	"gerrit.opencord.org/abstract-olt/models/physical"
+)
 
 /*
 Port represents a single PON port on the OLT chassis
@@ -28,3 +32,26 @@
 	PhysPort *physical.PONPort
 	Parent   *Slot `json:"-"`
 }
+
+type UnprovisonedPortError struct {
+	oltNum  int
+	clli    string
+	portNum int
+}
+
+func (e *UnprovisonedPortError) Error() string {
+	return fmt.Sprintf("Port %d for olt %d on AbstractChasis  %s is not provisioned", e.portNum, e.oltNum, e.clli)
+}
+func (port *Port) provisionOnt(ontNumber int, serialNumber string) error {
+	if port.PhysPort == nil {
+		slot := port.Parent
+		chassis := slot.Parent
+		err := UnprovisonedPortError{oltNum: slot.Number, clli: chassis.CLLI, portNum: port.Number}
+		return &err
+	}
+
+	phyPort := port.PhysPort
+	ont := port.Onts[ontNumber-1]
+	phyPort.ActivateOnt(ontNumber, ont.Svlan, ont.Cvlan, serialNumber)
+	return nil
+}
diff --git a/models/physical/chassis.go b/models/physical/chassis.go
index 339a610..3f050aa 100644
--- a/models/physical/chassis.go
+++ b/models/physical/chassis.go
@@ -16,7 +16,10 @@
 
 package physical
 
-import "net"
+import (
+	"fmt"
+	"net"
+)
 
 /*
 Chassis is a model that takes up to 16 discreet OLT chassis as if it is a 16 slot OLT chassis
@@ -27,3 +30,16 @@
 	Dataswitch   DataSwitch
 	Linecards    []OLT
 }
+
+/*
+AddOLTChassis - adds a reference to a new olt chassis
+*/
+func (chassis *Chassis) AddOLTChassis(olt OLT) {
+	chassis.Linecards = append(chassis.Linecards, olt)
+	//TODO - api call to add olt i.e. preprovision_olt
+	fmt.Printf("chassis.AddOLTChassis(%s)\n", olt.GetHostname())
+}
+func (chassis *Chassis) provisionONT(ont Ont) {
+	//TODO - api call to provison s/c vlans and ont serial number etc
+	fmt.Printf("chassis.provisionONT(%s,SVlan:%d,CVlan:%d)\n", ont.SerialNumber, ont.Svlan, ont.Cvlan)
+}
diff --git a/models/physical/edgecore.go b/models/physical/edgecore.go
index 196d44e..cded2dc 100644
--- a/models/physical/edgecore.go
+++ b/models/physical/edgecore.go
@@ -29,6 +29,9 @@
 func CreateEdgecore(olt *SimpleOLT) *Edgecore {
 	var newPorts [16]PONPort
 	edge := Edgecore{SimpleOLT: *olt}
+	for i := 0; i < 16; i++ {
+		newPorts[i].Parent = &edge
+	}
 	edge.Ports = newPorts[:]
 	return &edge
 }
diff --git a/models/physical/olt.go b/models/physical/olt.go
index 3c2094d..beffec8 100644
--- a/models/physical/olt.go
+++ b/models/physical/olt.go
@@ -41,6 +41,7 @@
 	Address        net.TCPAddr
 	Number         int
 	Ports          []PONPort
+	Active         bool
 	Parent         *Chassis `json:"-"`
 	DataSwitchPort int
 }
diff --git a/models/physical/ont.go b/models/physical/ont.go
index 4bd47ac..4a9ca89 100644
--- a/models/physical/ont.go
+++ b/models/physical/ont.go
@@ -20,8 +20,9 @@
 Ont represents a single ont/onu connect to a splitter on a Port
 */
 type Ont struct {
-	Number int
-	Svlan  int
-	Cvlan  int
-	Parent *PONPort `json:"-"`
+	Number       int
+	Svlan        int
+	Cvlan        int
+	SerialNumber string
+	Parent       *PONPort `json:"-"`
 }
diff --git a/models/physical/ponport.go b/models/physical/ponport.go
index 99c282a..e17a07e 100644
--- a/models/physical/ponport.go
+++ b/models/physical/ponport.go
@@ -17,7 +17,7 @@
 package physical
 
 /*
-Port represents a single PON port on the OLT chassis
+PONPort represents a single PON port on the OLT chassis
 */
 type PONPort struct {
 	Number   int
@@ -25,3 +25,10 @@
 	Onts     [64]Ont
 	Parent   *Edgecore `json:"-"`
 }
+
+func (port *PONPort) ActivateOnt(number int, sVlan int, cVlan int, serialNumber string) {
+	ont := Ont{Number: number, Svlan: sVlan, Cvlan: cVlan, SerialNumber: serialNumber, Parent: port}
+	port.Onts[number-1] = ont
+	port.Parent.Parent.provisionONT(ont)
+
+}