From 6ca56716aeec1d6a74982b83932e728bd61646db Mon Sep 17 00:00:00 2001
From: Malte Bauch <malte.bauch@extern.h-da.de>
Date: Wed, 13 Jul 2022 17:08:19 +0200
Subject: [PATCH] Add GetFlattenedOndList to api

---
 cli/adapter/PndAdapter.go           | 14 +++++++++-
 cli/cmd/deviceList.go               |  2 +-
 cli/cmd/prompt.go                   |  2 +-
 controller/api/device.go            | 16 +++++++++++
 controller/controller.go            |  1 +
 controller/northbound/server/pnd.go | 41 +++++++++++++++++++++++++++++
 6 files changed, 73 insertions(+), 3 deletions(-)

diff --git a/cli/adapter/PndAdapter.go b/cli/adapter/PndAdapter.go
index a02ac56ea..949b6cb10 100644
--- a/cli/adapter/PndAdapter.go
+++ b/cli/adapter/PndAdapter.go
@@ -75,7 +75,8 @@ func (p *PndAdapter) GetDevice(ctx context.Context, identifier string) (*ppb.Get
 }
 
 // GetDevices requests all devices belonging to the PrincipalNetworkDomain
-// attached to this adapter.
+// attached to this adapter. The requested devices also contain their config
+// information as gNMI notifications.
 func (p *PndAdapter) GetDevices(ctx context.Context) (*ppb.GetOndListResponse, error) {
 	resp, err := api.GetDevices(ctx, p.endpoint, p.id.String())
 	if err != nil {
@@ -84,6 +85,17 @@ func (p *PndAdapter) GetDevices(ctx context.Context) (*ppb.GetOndListResponse, e
 	return resp, nil
 }
 
+// GetFlattenedDevices requests all devices belonging to the PrincipalNetworkDomain
+// attached to this adapter. The devices do not contain the config information
+// as gNMI notifications.
+func (p *PndAdapter) GetFlattenedDevices(ctx context.Context) (*ppb.GetFlattenedOndListResponse, error) {
+	resp, err := api.GetFlattenedDevices(ctx, p.endpoint, p.id.String())
+	if err != nil {
+		return nil, err
+	}
+	return resp, nil
+}
+
 // RemoveDevice removes a device from the controller
 func (p *PndAdapter) RemoveDevice(ctx context.Context, did uuid.UUID) (*ppb.DeleteOndResponse, error) {
 	resp, err := api.DeleteDevice(ctx, p.endpoint, p.id.String(), did.String())
diff --git a/cli/cmd/deviceList.go b/cli/cmd/deviceList.go
index 9fc5247f3..d4ecad044 100644
--- a/cli/cmd/deviceList.go
+++ b/cli/cmd/deviceList.go
@@ -47,7 +47,7 @@ var deviceListCmd = &cobra.Command{
 	RunE: func(cmd *cobra.Command, args []string) error {
 		spinner, _ := pterm.DefaultSpinner.Start("Fetching data from controller")
 
-		resp, err := pndAdapter.GetDevices(createContextWithAuthorization())
+		resp, err := pndAdapter.GetFlattenedDevices(createContextWithAuthorization())
 		if err != nil {
 			spinner.Fail(err)
 			return err
diff --git a/cli/cmd/prompt.go b/cli/cmd/prompt.go
index 58246f531..7de142ae2 100644
--- a/cli/cmd/prompt.go
+++ b/cli/cmd/prompt.go
@@ -240,7 +240,7 @@ func completionBasedOnCmd(c *PromptCompleter, cmd *cobra.Command, inputSplit []s
 // the result is converted into a prompt.Suggest slice.
 func getDevices() ([]prompt.Suggest, error) {
 	spinner, _ := pterm.DefaultSpinner.Start("Fetching devices from controller.")
-	resp, err := pndAdapter.GetDevices(createContextWithAuthorization())
+	resp, err := pndAdapter.GetFlattenedDevices(createContextWithAuthorization())
 	if err != nil {
 		spinner.Fail(err)
 		return []prompt.Suggest{}, err
diff --git a/controller/api/device.go b/controller/api/device.go
index 22f51cf7d..779318606 100644
--- a/controller/api/device.go
+++ b/controller/api/device.go
@@ -135,6 +135,22 @@ func GetDevices(ctx context.Context, addr, pid string) (*ppb.GetOndListResponse,
 	return pndClient.GetOndList(ctx, req)
 }
 
+// GetDevices requests all devices belonging to a given
+// PrincipalNetworkDomain from the controller.
+func GetFlattenedDevices(ctx context.Context, addr, pid string) (*ppb.GetFlattenedOndListResponse, error) {
+	pndClient, err := nbi.PndClient(addr, dialOptions...)
+	if err != nil {
+		return nil, err
+	}
+
+	req := &ppb.GetOndListRequest{
+		Timestamp: time.Now().UnixNano(),
+		Pid:       pid,
+	}
+
+	return pndClient.GetFlattenedOndList(ctx, req)
+}
+
 // GetPath requests a specific path
 func GetPath(ctx context.Context, addr, pid, did, path string) (*ppb.GetPathResponse, error) {
 	pndClient, err := nbi.PndClient(addr, dialOptions...)
diff --git a/controller/controller.go b/controller/controller.go
index a1a8333c6..d40ac00e6 100644
--- a/controller/controller.go
+++ b/controller/controller.go
@@ -196,6 +196,7 @@ func ensureDefaultRoleExists() error {
 			"/gosdn.rbac.RoleService/DeleteRoles",
 			"/gosdn.pnd.PndService/GetOnd",
 			"/gosdn.pnd.PndService/GetOndList",
+			"/gosdn.pnd.PndService/GetFlattenedOndList",
 			"/gosdn.pnd.PndService/GetSbi",
 			"/gosdn.pnd.PndService/GetSbiList",
 			"/gosdn.pnd.PndService/GetPath",
diff --git a/controller/northbound/server/pnd.go b/controller/northbound/server/pnd.go
index 20133de7c..2876b063d 100644
--- a/controller/northbound/server/pnd.go
+++ b/controller/northbound/server/pnd.go
@@ -114,6 +114,47 @@ func (p PndServer) GetOndList(ctx context.Context, request *ppb.GetOndListReques
 	}, nil
 }
 
+// GetOndList returns a list of existing onds
+func (p PndServer) GetFlattenedOndList(ctx context.Context, request *ppb.GetOndListRequest) (*ppb.GetFlattenedOndListResponse, error) {
+	labels := prometheus.Labels{"service": "pnd", "rpc": "get"}
+	start := metrics.StartHook(labels, grpcRequestsTotal)
+	defer metrics.FinishHook(labels, start, grpcRequestDurationSecondsTotal, grpcRequestDurationSeconds)
+	pid, err := uuid.Parse(request.Pid)
+	if err != nil {
+		return nil, handleRPCError(labels, err)
+	}
+
+	pnd, err := p.pndStore.Get(store.Query{ID: pid})
+	if err != nil {
+		log.Error(err)
+		return nil, status.Errorf(codes.Aborted, "%v", err)
+	}
+
+	onds := pnd.Devices()
+	ondsBySpecificPath := make([]*ppb.FlattenedOrchestratedNetworkingDevice, len(onds))
+	for i, ond := range onds {
+		ondFlattened := &ppb.FlattenedOrchestratedNetworkingDevice{
+			Id:   ond.ID().String(),
+			Name: ond.Name(),
+			Sbi: &spb.SouthboundInterface{
+				Id:   ond.SBI().ID().String(),
+				Type: ond.SBI().Type(),
+			},
+		}
+		ondsBySpecificPath[i] = ondFlattened
+	}
+
+	return &ppb.GetFlattenedOndListResponse{
+		Timestamp: time.Now().UnixNano(),
+		Pnd: &ppb.PrincipalNetworkDomain{
+			Id:          pnd.ID().String(),
+			Name:        pnd.GetName(),
+			Description: pnd.GetDescription(),
+		},
+		Ond: ondsBySpecificPath,
+	}, nil
+}
+
 func fillOndBySpecificPath(pnd networkdomain.NetworkDomain, d device.Device, path string) (*ppb.OrchestratedNetworkingDevice, error) {
 	gnmiPath, err := ygot.StringToStructuredPath(path)
 	if err != nil {
-- 
GitLab