Skip to content
Snippets Groups Projects
Commit e83082b1 authored by Manuel Kieweg's avatar Manuel Kieweg
Browse files

Northbound Interface

parent 50722ba9
No related branches found
No related tags found
9 merge requests!246Develop,!245Develop into Master,!244Master into develop2 into master,!219Draft: Testing,!214Test pipelines,!195DO NOT MERGE 2,!194DO NOT MERGE! just for testing,!155Northbound Interface,!138Develop
This commit is part of merge request !138. Comments created here will be created in the context of that merge request.
...@@ -144,9 +144,9 @@ func update(clientset *kubernetes.Clientset, resource metav1.Common, env string) ...@@ -144,9 +144,9 @@ func update(clientset *kubernetes.Clientset, resource metav1.Common, env string)
opts := metav1.UpdateOptions{} opts := metav1.UpdateOptions{}
getOpts := metav1.GetOptions{} getOpts := metav1.GetOptions{}
ctx := context.Background() ctx := context.Background()
switch resource.(type) { switch resource := resource.(type) {
case *corev1.Service: case *corev1.Service:
service := resource.(*corev1.Service) service := resource
s, err := clientset.CoreV1().Services("cocsn").Get(ctx, env, getOpts) s, err := clientset.CoreV1().Services("cocsn").Get(ctx, env, getOpts)
if err != nil { if err != nil {
return err return err
...@@ -158,7 +158,7 @@ func update(clientset *kubernetes.Clientset, resource metav1.Common, env string) ...@@ -158,7 +158,7 @@ func update(clientset *kubernetes.Clientset, resource metav1.Common, env string)
} }
log.Printf("service %v updated", service.Name) log.Printf("service %v updated", service.Name)
case *netv1.Ingress: case *netv1.Ingress:
ingress := resource.(*netv1.Ingress) ingress := resource
i, err := clientset.NetworkingV1beta1().Ingresses("cocsn").Get(ctx, env, getOpts) i, err := clientset.NetworkingV1beta1().Ingresses("cocsn").Get(ctx, env, getOpts)
if err != nil { if err != nil {
return err return err
...@@ -170,7 +170,7 @@ func update(clientset *kubernetes.Clientset, resource metav1.Common, env string) ...@@ -170,7 +170,7 @@ func update(clientset *kubernetes.Clientset, resource metav1.Common, env string)
} }
log.Printf("ingress %v updated", ingress.Name) log.Printf("ingress %v updated", ingress.Name)
case *corev1.ConfigMap: case *corev1.ConfigMap:
config := resource.(*corev1.ConfigMap) config := resource
c, err := clientset.CoreV1().ConfigMaps("cocsn").Get(ctx, env+"-config", getOpts) c, err := clientset.CoreV1().ConfigMaps("cocsn").Get(ctx, env+"-config", getOpts)
if err != nil { if err != nil {
return err return err
...@@ -182,7 +182,7 @@ func update(clientset *kubernetes.Clientset, resource metav1.Common, env string) ...@@ -182,7 +182,7 @@ func update(clientset *kubernetes.Clientset, resource metav1.Common, env string)
} }
log.Printf("configMap %v updated", config.Name) log.Printf("configMap %v updated", config.Name)
case *appv1.Deployment: case *appv1.Deployment:
deployment := resource.(*appv1.Deployment) deployment := resource
d, err := clientset.AppsV1().Deployments("cocsn").Get(ctx, env, getOpts) d, err := clientset.AppsV1().Deployments("cocsn").Get(ctx, env, getOpts)
if err != nil { if err != nil {
return err return err
......
...@@ -5,7 +5,9 @@ import ( ...@@ -5,7 +5,9 @@ import (
"fmt" "fmt"
"strings" "strings"
"code.fbi.h-da.de/cocsn/gosdn/forks/goarista/gnmi" spb "code.fbi.h-da.de/cocsn/api/go/gosdn/southbound"
tpb "code.fbi.h-da.de/cocsn/api/go/gosdn/transport"
"code.fbi.h-da.de/cocsn/gosdn/nucleus" "code.fbi.h-da.de/cocsn/gosdn/nucleus"
gpb "github.com/openconfig/gnmi/proto/gnmi" gpb "github.com/openconfig/gnmi/proto/gnmi"
) )
...@@ -13,14 +15,12 @@ import ( ...@@ -13,14 +15,12 @@ import (
// Capabilities sends a gNMI Capabilities request to the specified target // Capabilities sends a gNMI Capabilities request to the specified target
// and prints the supported models to stdout // and prints the supported models to stdout
func Capabilities(a, u, p string) error { func Capabilities(a, u, p string) error {
cfg := gnmi.Config{ opts := &tpb.TransportOption{
Addr: a, Address: a,
Username: u, Username: u,
Password: p, Password: p,
Encoding: gpb.Encoding_JSON_IETF,
} }
opts := &nucleus.GnmiTransportOptions{Config: cfg} transport, err := nucleus.NewGnmiTransport(opts, nucleus.NewSBI(spb.Type_OPENCONFIG))
transport, err := nucleus.NewGnmiTransport(opts)
if err != nil { if err != nil {
return err return err
} }
......
package cli
import (
"context"
"code.fbi.h-da.de/cocsn/gosdn/nucleus/errors"
"code.fbi.h-da.de/cocsn/gosdn/forks/goarista/gnmi"
"code.fbi.h-da.de/cocsn/gosdn/nucleus"
gpb "github.com/openconfig/gnmi/proto/gnmi"
log "github.com/sirupsen/logrus"
)
// Get sends a gNMI Get request to the specified target and prints the response to stdout
func Get(a, u, p string, args ...string) (*gpb.GetResponse, error) {
sbi := &nucleus.OpenConfig{}
opts := &nucleus.GnmiTransportOptions{
Config: gnmi.Config{
Addr: a,
Username: u,
Password: p,
Encoding: gpb.Encoding_JSON_IETF,
},
SetNode: sbi.SetNode(),
}
t, err := nucleus.NewGnmiTransport(opts)
if err != nil {
return nil, err
}
resp, err := t.Get(context.Background(), args...)
if err != nil {
return nil, err
}
log.Debug(resp)
r, ok := resp.(*gpb.GetResponse)
if !ok {
return nil, &errors.ErrInvalidTypeAssertion{}
}
return r, nil
}
package cli
import (
"context"
"errors"
"time"
ppb "code.fbi.h-da.de/cocsn/api/go/gosdn/pnd"
spb "code.fbi.h-da.de/cocsn/api/go/gosdn/southbound"
tpb "code.fbi.h-da.de/cocsn/api/go/gosdn/transport"
nbi "code.fbi.h-da.de/cocsn/gosdn/northbound/client"
log "github.com/sirupsen/logrus"
"github.com/spf13/viper"
pb "code.fbi.h-da.de/cocsn/api/go/gosdn/core"
"google.golang.org/grpc"
)
var dialOptions []grpc.DialOption
func init() {
dialOptions = []grpc.DialOption{
grpc.WithInsecure(),
}
}
// Init initialises the CLI client.
func Init(addr string) error {
ctx := context.Background()
resp, err := getAllCore(ctx, addr)
if err != nil {
return err
}
if len(resp.Pnd) > 0 {
pid := resp.Pnd[0].Id
viper.Set("CLI_PND", pid)
log.Infof("PND: %v", pid)
if len(resp.Pnd[0].Sbi) != 0 {
sbi := resp.Pnd[0].Sbi[0].Id
viper.Set("CLI_SBI", sbi)
log.Infof("SBI: %v", sbi)
}
}
return nil
}
// GetIds requests all UUID information from the controller
func GetIds(addr string) ([]*ppb.PrincipalNetworkDomain, error) {
ctx := context.Background()
resp, err := getAllCore(ctx, addr)
if err != nil {
return nil, err
}
return resp.Pnd, nil
}
func getAllCore(ctx context.Context, addr string) (*pb.GetResponse, error) {
coreClient, err := nbi.CoreClient(addr, dialOptions...)
if err != nil {
return nil, err
}
req := &pb.GetRequest{
Timestamp: time.Now().UnixNano(),
All: true,
}
return coreClient.Get(ctx, req)
}
// AddPnd takes a name, description and SBI UUID to create a new
// PrincipalNetworkDomain on the controller
func AddPnd(addr, name, description, sbi string) (*pb.SetResponse, error) {
coreClient, err := nbi.CoreClient(addr, dialOptions...)
if err != nil {
return nil, err
}
ctx := context.Background()
req := &pb.SetRequest{
Timestamp: time.Now().UnixNano(),
Pnd: []*pb.SetPnd{
{
Name: name,
Description: description,
Sbi: sbi,
},
},
}
return coreClient.Set(ctx, req)
}
// GetPnd requests one or several PrincipalNetworkDomains from the
// controller. To request all PrincipalNetworkDomains without providing
// names or UUIDs use GetIds()
func GetPnd(addr string, args ...string) (*pb.GetResponse, error) {
coreClient, err := nbi.CoreClient(addr, dialOptions...)
if err != nil {
return nil, err
}
if len(args) <= 0 {
return nil, errors.New("not enough arguments")
}
ctx := context.Background()
req := &pb.GetRequest{
Timestamp: time.Now().UnixNano(),
Pid: args,
}
return coreClient.Get(ctx, req)
}
// GetChanges requests all pending and unconfirmed changes from the controller
func GetChanges(addr, pnd string) (*ppb.GetResponse, error) {
ctx := context.Background()
client, err := nbi.PndClient(addr, dialOptions...)
if err != nil {
return nil, err
}
req := &ppb.GetRequest{
Timestamp: time.Now().UnixNano(),
Request: &ppb.GetRequest_Change{
Change: &ppb.GetChange{
All: true,
},
},
Pid: pnd,
}
return client.Get(ctx, req)
}
// Commit sends a commit request for one or multiple changes to the
// controller.
func Commit(addr, pnd string, cuids ...string) (*ppb.SetResponse, error) {
changes := make([]*ppb.SetChange, len(cuids))
for i, arg := range cuids {
changes[i] = &ppb.SetChange{
Cuid: arg,
Op: ppb.SetChange_COMMIT,
}
}
return commitConfirm(addr, pnd, changes)
}
// Confirm sends a confirm request for one or multiple changes to the
// controller
func Confirm(addr, pnd string, cuids ...string) (*ppb.SetResponse, error) {
changes := make([]*ppb.SetChange, len(cuids))
for i, arg := range cuids {
changes[i] = &ppb.SetChange{
Cuid: arg,
Op: ppb.SetChange_CONFIRM,
}
}
return commitConfirm(addr, pnd, changes)
}
func commitConfirm(addr, pnd string, changes []*ppb.SetChange) (*ppb.SetResponse, error) {
ctx := context.Background()
client, err := nbi.PndClient(addr, dialOptions...)
if err != nil {
return nil, err
}
req := &ppb.SetRequest{
Timestamp: time.Now().UnixNano(),
Change: changes,
Pid: pnd,
}
return client.Set(ctx, req)
}
// AddDevice adds a new device to the controller. The device name is optional.
// If no name is provided a name will be generated upon device creation.
func AddDevice(addr, username, password, sbi, pnd, deviceAddress, deviceName string) (*ppb.SetResponse, error) {
pndClient, err := nbi.PndClient(addr, dialOptions...)
if err != nil {
return nil, err
}
req := &ppb.SetRequest{
Timestamp: time.Now().UnixNano(),
Ond: []*ppb.SetOnd{
{
Address: deviceAddress,
Sbi: &spb.SouthboundInterface{
Id: sbi,
},
DeviceName: deviceName,
TransportOption: &tpb.TransportOption{
Address: addr,
Username: username,
Password: password,
TransportOption: &tpb.TransportOption_GnmiTransportOption{
GnmiTransportOption: &tpb.GnmiTransportOption{},
},
},
},
},
Pid: pnd,
}
ctx := context.Background()
return pndClient.Set(ctx, req)
}
// GetDevice requests one or multiple devices belonging to a given
// PrincipalNetworkDomain from the controller. If no device identifier
// is provided, all devices are requested.
func GetDevice(addr, pid, path string, did ...string) (*ppb.GetResponse, error) {
pndClient, err := nbi.PndClient(addr, dialOptions...)
if err != nil {
return nil, err
}
var all bool
if len(did) == 0 {
all = true
}
req := &ppb.GetRequest{
Timestamp: time.Now().UnixNano(),
Request: &ppb.GetRequest_Ond{
Ond: &ppb.GetOnd{
All: all,
Did: did,
},
},
Pid: pid,
}
ctx := context.Background()
return pndClient.Get(ctx, req)
}
// Update creates a ChangeRequest to update the given path with the given value
// at the given OND on the controller.
func Update(addr, did, pid, path, value string) (*ppb.SetResponse, error) {
req := &ppb.ChangeRequest{
Id: did,
Path: path,
Value: value,
ApiOp: ppb.ApiOperation_UPDATE,
}
return sendChangeRequest(addr, pid, req)
}
// Replace creates a ChangeRequest to replace the given path with the given value
// at the given OND on the controller.
func Replace(addr, did, pid, path, value string) (*ppb.SetResponse, error) {
req := &ppb.ChangeRequest{
Id: did,
Path: path,
Value: value,
ApiOp: ppb.ApiOperation_REPLACE,
}
return sendChangeRequest(addr, pid, req)
}
// Delete creates a ChangeRequest to delete the given path node
// at the given OND on the controller.
func Delete(addr, did, pid, path string) (*ppb.SetResponse, error) {
req := &ppb.ChangeRequest{
Id: did,
Path: path,
ApiOp: ppb.ApiOperation_DELETE,
}
return sendChangeRequest(addr, pid, req)
}
func sendChangeRequest(addr, pid string, req *ppb.ChangeRequest) (*ppb.SetResponse, error) {
pndClient, err := nbi.PndClient(addr, dialOptions...)
if err != nil {
return nil, err
}
ctx := context.Background()
r := &ppb.SetRequest{
Timestamp: time.Now().UnixNano(),
ChangeRequest: []*ppb.ChangeRequest{req},
Pid: pid,
}
return pndClient.Set(ctx, r)
}
package cli
import (
"context"
"net"
"testing"
pb "code.fbi.h-da.de/cocsn/api/go/gosdn/core"
ppb "code.fbi.h-da.de/cocsn/api/go/gosdn/pnd"
spb "code.fbi.h-da.de/cocsn/api/go/gosdn/southbound"
"code.fbi.h-da.de/cocsn/gosdn/mocks"
nbi "code.fbi.h-da.de/cocsn/gosdn/northbound/server"
"code.fbi.h-da.de/cocsn/gosdn/nucleus"
"code.fbi.h-da.de/cocsn/yang-models/generated/openconfig"
"github.com/google/uuid"
log "github.com/sirupsen/logrus"
"github.com/stretchr/testify/mock"
"google.golang.org/grpc"
"google.golang.org/grpc/test/bufconn"
)
/*
Based on this StackOverflow answer: https://stackoverflow.com/a/52080545/4378176
*/
const bufSize = 1024 * 1024
const bufnet = "bufnet"
const pndID = "2043519e-46d1-4963-9a8e-d99007e104b8"
const changeID = "0992d600-f7d4-4906-9559-409b04d59a5f"
const sbiID = "f6fd4b35-f039-4111-9156-5e4501bb8a5a"
const ondID = "7e0ed8cc-ebf5-46fa-9794-741494914883"
var pndStore *nucleus.PndStore
var lis *bufconn.Listener
func init() {
dialOptions = []grpc.DialOption{
grpc.WithContextDialer(bufDialer),
grpc.WithInsecure(),
}
lis = bufconn.Listen(bufSize)
s := grpc.NewServer()
pndStore = nucleus.NewPndStore()
pndUUID, err := uuid.Parse(pndID)
if err != nil {
log.Fatal(err)
}
changeUUID, err := uuid.Parse(changeID)
if err != nil {
log.Fatal(err)
}
deviceUUID, err := uuid.Parse(ondID)
if err != nil {
log.Fatal(err)
}
mockPnd := mocks.PrincipalNetworkDomain{}
mockPnd.On("ID").Return(pndUUID)
mockPnd.On("GetName").Return("test")
mockPnd.On("GetDescription").Return("test")
mockPnd.On("PendingChanges").Return([]uuid.UUID{changeUUID})
mockPnd.On("CommittedChanges").Return([]uuid.UUID{changeUUID})
mockPnd.On("GetChange", mock.Anything).Return(&nucleus.Change{}, nil)
mockPnd.On("AddDevice", mock.Anything, mock.Anything, mock.Anything).Return(nil)
mockPnd.On("GetDevice", mock.Anything).Return(&nucleus.Device{
UUID: deviceUUID,
GoStruct: &openconfig.Device{},
}, nil)
mockPnd.On("Commit", mock.Anything).Return(nil)
mockPnd.On("Confirm", mock.Anything).Return(nil)
mockPnd.On("ChangeOND", mock.Anything, mock.Anything, mock.Anything, mock.Anything).Return(nil)
if err := pndStore.Add(&mockPnd); err != nil {
log.Fatal(err)
}
northbound := nbi.NewNBI(pndStore)
pb.RegisterCoreServer(s, northbound.Core)
ppb.RegisterPndServer(s, northbound.Pnd)
go func() {
if err := s.Serve(lis); err != nil {
log.Fatalf("Server exited with error: %v", err)
}
}()
}
func bufDialer(context.Context, string) (net.Conn, error) {
return lis.Dial()
}
func Test_Init(t *testing.T) {
if err := Init(bufnet); err != nil {
t.Error(err)
}
}
func Test_GetIds(t *testing.T) {
resp, err := GetIds(bufnet)
if err != nil {
t.Error(err)
return
}
log.Info(resp)
}
func Test_AddPnd(t *testing.T) {
sbi := nucleus.NewSBI(spb.Type_OPENCONFIG)
resp, err := AddPnd(bufnet, "test", "test pnd", sbi.ID().String())
if err != nil {
t.Error(err)
return
}
log.Info(resp)
}
func Test_GetPnd(t *testing.T) {
resp, err := GetPnd(bufnet, pndID)
if err != nil {
t.Error(err)
return
}
got := resp.Pnd[0].Id
if got != pndID {
t.Errorf("PND ID is %v, expected %v", got, pndID)
}
}
func Test_GetChanges(t *testing.T) {
resp, err := GetChanges(bufnet, pndID)
if err != nil {
t.Error(err)
return
}
log.Info(resp)
}
func Test_CommitConfirm(t *testing.T) {
resp, err := Commit(bufnet, pndID, changeID)
if err != nil {
t.Error(err)
return
}
log.Info(resp)
resp, err = Confirm(bufnet, pndID, changeID)
if err != nil {
t.Error(err)
return
}
log.Info(resp)
}
func Test_AddDevice(t *testing.T) {
resp, err := AddDevice(bufnet, "test", "test", sbiID, pndID, "test", "test")
if err != nil {
t.Error(err)
return
}
log.Info(resp)
}
func Test_GetDevice(t *testing.T) {
resp, err := GetDevice(bufnet, pndID, "", ondID)
if err != nil {
t.Error(err)
return
}
got := resp.Ond[0].Id
if got != ondID {
t.Errorf("PND ID is %v, expected %v", got, ondID)
}
}
func Test_Update(t *testing.T) {
resp, err := Update(bufnet, ondID, pndID, "", "")
if err != nil {
t.Error(err)
return
}
log.Info(resp)
}
func Test_Replace(t *testing.T) {
resp, err := Replace(bufnet, ondID, pndID, "", "")
if err != nil {
t.Error(err)
return
}
log.Info(resp)
}
func Test_Delete(t *testing.T) {
resp, err := Delete(bufnet, ondID, pndID, "")
if err != nil {
t.Error(err)
return
}
log.Info(resp)
}
package cli
import (
"errors"
"fmt"
"io/ioutil"
"net/http"
"strings"
log "github.com/sirupsen/logrus"
"github.com/spf13/viper"
)
const apiRoot = "?"
var builder *strings.Builder
func init() {
builder = &strings.Builder{}
}
// HTTPGet sends sends requests from the CLI to the gosdn HTTP API and processes any response data
func HTTPGet(apiEndpoint, f string, args ...string) error {
for _, p := range args {
builder.WriteString("&")
builder.WriteString(p)
}
resp, err := http.Get(apiEndpoint + apiRoot + "q=" + f + builder.String())
if err != nil {
log.Info(fmt.Sprintf("Err: %s", err))
return err
}
builder.Reset()
switch resp.StatusCode {
case http.StatusOK:
defer resp.Body.Close()
bytes, err := ioutil.ReadAll(resp.Body)
if err != nil {
return err
}
switch f {
case "init":
pnd := string(bytes[9:45])
sbi := string(bytes[55:91])
viper.Set("CLI_PND", pnd)
viper.Set("CLI_SBI", sbi)
err := viper.WriteConfig()
if err != nil {
log.Error(err)
}
default:
fmt.Println(string(bytes))
}
case http.StatusCreated:
defer resp.Body.Close()
bytes, err := ioutil.ReadAll(resp.Body)
if err != nil {
return err
}
uuid := string(bytes[19:55])
viper.Set("LAST_DEVICE_UUID", uuid)
fmt.Println(string(bytes))
case http.StatusAccepted:
default:
log.WithFields(log.Fields{
"status code": resp.StatusCode,
}).Error("operation unsuccessful")
return errors.New(resp.Status)
}
return nil
}
package cli
import (
model "code.fbi.h-da.de/cocsn/yang-models/generated/arista"
"github.com/openconfig/ygot/ytypes"
log "github.com/sirupsen/logrus"
)
var testSchema *ytypes.Schema
func init() {
var err error
testSchema, err = model.Schema()
if err != nil {
log.Fatal(err)
}
}
package cli
import (
"context"
"code.fbi.h-da.de/cocsn/gosdn/forks/goarista/gnmi"
"code.fbi.h-da.de/cocsn/gosdn/nucleus"
)
// Set sends a gNMI Set request to the specified target. Only one
// request per invocation supported.
func Set(a, u, p, typ string, args ...string) error {
opts := &nucleus.GnmiTransportOptions{
Config: gnmi.Config{
Addr: a,
Username: u,
Password: p,
},
}
t, err := nucleus.NewGnmiTransport(opts)
if err != nil {
return err
}
return t.Set(context.Background(), args)
}
...@@ -8,11 +8,11 @@ import ( ...@@ -8,11 +8,11 @@ import (
"syscall" "syscall"
"time" "time"
tpb "code.fbi.h-da.de/cocsn/api/go/gosdn/transport"
"code.fbi.h-da.de/cocsn/gosdn/nucleus/types" "code.fbi.h-da.de/cocsn/gosdn/nucleus/types"
"code.fbi.h-da.de/cocsn/gosdn/forks/goarista/gnmi" "code.fbi.h-da.de/cocsn/gosdn/forks/goarista/gnmi"
"code.fbi.h-da.de/cocsn/gosdn/nucleus" "code.fbi.h-da.de/cocsn/gosdn/nucleus"
gpb "github.com/openconfig/gnmi/proto/gnmi"
log "github.com/sirupsen/logrus" log "github.com/sirupsen/logrus"
) )
...@@ -20,18 +20,22 @@ import ( ...@@ -20,18 +20,22 @@ import (
// logs the response to stdout. Only 'stream' mode with 'sample' operation supported. // logs the response to stdout. Only 'stream' mode with 'sample' operation supported.
func Subscribe(address, username, password, deviceName string, sample, heartbeat int64, args ...string) error { func Subscribe(address, username, password, deviceName string, sample, heartbeat int64, args ...string) error {
sbi := &nucleus.OpenConfig{} sbi := &nucleus.OpenConfig{}
tOpts := &nucleus.GnmiTransportOptions{ tOpts := &tpb.TransportOption{
Config: gnmi.Config{ Address: address,
Addr: address, Username: username,
Username: username, Password: password,
Password: password, Tls: false,
Encoding: gpb.Encoding_JSON_IETF, TransportOption: &tpb.TransportOption_GnmiTransportOption{
GnmiTransportOption: &tpb.GnmiTransportOption{
Compression: "",
GrpcDialOptions: nil,
Token: "",
Encoding: 0,
},
}, },
SetNode: sbi.SetNode(),
RespChan: make(chan *gpb.SubscribeResponse),
} }
device, err := nucleus.NewDevice(sbi, tOpts, deviceName) device, err := nucleus.NewDevice(deviceName, tOpts, sbi)
if err != nil { if err != nil {
return err return err
} }
......
...@@ -34,9 +34,9 @@ package cmd ...@@ -34,9 +34,9 @@ package cmd
import ( import (
"code.fbi.h-da.de/cocsn/gosdn/cli" "code.fbi.h-da.de/cocsn/gosdn/cli"
"github.com/spf13/cobra" "github.com/spf13/cobra"
)
var deviceName string log "github.com/sirupsen/logrus"
)
// addDeviceCmd represents the addDevice command // addDeviceCmd represents the addDevice command
var addDeviceCmd = &cobra.Command{ var addDeviceCmd = &cobra.Command{
...@@ -47,21 +47,27 @@ var addDeviceCmd = &cobra.Command{ ...@@ -47,21 +47,27 @@ var addDeviceCmd = &cobra.Command{
Device address and user credentials need to be provided Device address and user credentials need to be provided
if they diverge from the default credentials.`, if they diverge from the default credentials.`,
RunE: func(cmd *cobra.Command, args []string) error { RunE: func(cmd *cobra.Command, args []string) error {
return cli.HTTPGet( resp, err := cli.AddDevice(
apiEndpoint, apiEndpoint,
"addDevice", username,
"address="+address, password,
"password="+password, cliSbi,
"username="+username, cliPnd,
"sbi="+cliSbi, address,
"pnd="+cliPnd, deviceName,
"name="+deviceName,
) )
if err != nil {
return err
}
log.Info(resp)
return nil
}, },
} }
var deviceName string
func init() { func init() {
cliCmd.AddCommand(addDeviceCmd) cliCmd.AddCommand(addDeviceCmd)
addDeviceCmd.PersistentFlags().StringVarP(&deviceName, "device-name", "n", "", "Human readable device name.") addDeviceCmd.Flags().StringVar(&deviceName, "name", "", "add a device name (optional)")
} }
...@@ -34,24 +34,37 @@ package cmd ...@@ -34,24 +34,37 @@ package cmd
import ( import (
"code.fbi.h-da.de/cocsn/gosdn/cli" "code.fbi.h-da.de/cocsn/gosdn/cli"
"github.com/spf13/cobra" "github.com/spf13/cobra"
log "github.com/sirupsen/logrus"
) )
var typ string // addCmd represents the add command
var addCmd = &cobra.Command{
Use: "add",
Short: "adds a new principal network domain to the controller",
Long: `A principal network domain is a main networking entity. This can be a
campus building or site.
// setCmd represents the set command A description must be passed as positional argument. A name and default SBI can be
var setCmd = &cobra.Command{ passed using flags`,
Use: "set", Args: cobra.ExactArgs(1),
Short: "set request",
Long: `Sends a gNMI Set request to the specified target. Only one
request per invocation supported.`,
RunE: func(cmd *cobra.Command, args []string) error { RunE: func(cmd *cobra.Command, args []string) error {
return cli.Set(address, username, password, typ, args...) resp, err := cli.AddPnd(apiEndpoint, pndName, args[0], pndDefaultSbi)
if err != nil {
return err
}
log.Info(resp)
return nil
}, },
} }
var pndName string
var pndDefaultSbi string
func init() { func init() {
rootCmd.AddCommand(setCmd) pndCmd.AddCommand(addCmd)
addCmd.Flags().StringVar(&pndName, "name", "", "the name of the pnd")
addCmd.Flags().StringVar(&pndDefaultSbi, "sbi", "openconfig", "the default SBI of the pnd")
setCmd.Flags().StringVarP(&typ, "type", "t", "update", "Type of the set request. "+
"Possible values: 'update', 'replace', and 'delete'")
} }
...@@ -46,13 +46,15 @@ var cliCmd = &cobra.Command{ ...@@ -46,13 +46,15 @@ var cliCmd = &cobra.Command{
Long: `Initialises the CLI. The first PND UUID and SBI UUID Long: `Initialises the CLI. The first PND UUID and SBI UUID
are written to the config file for subsequent requests.`, are written to the config file for subsequent requests.`,
RunE: func(cmd *cobra.Command, args []string) error { RunE: func(cmd *cobra.Command, args []string) error {
return cli.HTTPGet(apiEndpoint, "init") return cli.Init(apiEndpoint)
}, },
} }
var verbose bool
func init() { func init() {
rootCmd.AddCommand(cliCmd) rootCmd.AddCommand(cliCmd)
cliCmd.PersistentFlags().StringVar(&apiEndpoint, "controller", "http://gosdn-develop.apps.ocp.fbi.h-da.de/api", "address of the controller") cliCmd.PersistentFlags().StringVar(&apiEndpoint, "controller", "http://gosdn-develop.apps.ocp.fbi.h-da.de/api", "address of the controller")
pndCmd.PersistentFlags().BoolVar(&verbose, "verbose", false, "show ond and sbi info")
} }
...@@ -33,6 +33,7 @@ package cmd ...@@ -33,6 +33,7 @@ package cmd
import ( import (
"code.fbi.h-da.de/cocsn/gosdn/cli" "code.fbi.h-da.de/cocsn/gosdn/cli"
log "github.com/sirupsen/logrus"
"github.com/spf13/cobra" "github.com/spf13/cobra"
) )
...@@ -46,16 +47,18 @@ only one value supported for now. ...@@ -46,16 +47,18 @@ only one value supported for now.
Use "set replace" or "set delete" respectively`, Use "set replace" or "set delete" respectively`,
RunE: func(cmd *cobra.Command, args []string) error { RunE: func(cmd *cobra.Command, args []string) error {
return cli.HTTPGet( resp, err := cli.Update(
apiEndpoint, apiEndpoint,
"update", uuid,
"uuid="+uuid, cliPnd,
"cliSbi="+cliSbi, args[0],
"cliPnd="+cliPnd, args[1],
"path="+args[0],
"address="+address,
"value="+args[1],
) )
if err != nil {
return err
}
log.Info(resp)
return nil
}, },
} }
......
...@@ -33,6 +33,7 @@ package cmd ...@@ -33,6 +33,7 @@ package cmd
import ( import (
"code.fbi.h-da.de/cocsn/gosdn/cli" "code.fbi.h-da.de/cocsn/gosdn/cli"
log "github.com/sirupsen/logrus"
"github.com/spf13/cobra" "github.com/spf13/cobra"
) )
...@@ -42,13 +43,12 @@ var commitCmd = &cobra.Command{ ...@@ -42,13 +43,12 @@ var commitCmd = &cobra.Command{
Args: cobra.ExactArgs(1), Args: cobra.ExactArgs(1),
Short: "Commit the given change for the active PND", Short: "Commit the given change for the active PND",
Long: ``, Long: ``,
RunE: func(cmd *cobra.Command, args []string) error { Run: func(cmd *cobra.Command, args []string) {
return cli.HTTPGet( log.Info(cli.Commit(
apiEndpoint, apiEndpoint,
"change-commit", cliPnd,
"pnd="+cliPnd, args[0],
"cuid="+args[0], ))
)
}, },
} }
......
...@@ -33,6 +33,7 @@ package cmd ...@@ -33,6 +33,7 @@ package cmd
import ( import (
"code.fbi.h-da.de/cocsn/gosdn/cli" "code.fbi.h-da.de/cocsn/gosdn/cli"
log "github.com/sirupsen/logrus"
"github.com/spf13/cobra" "github.com/spf13/cobra"
) )
...@@ -42,13 +43,12 @@ var confirmCmd = &cobra.Command{ ...@@ -42,13 +43,12 @@ var confirmCmd = &cobra.Command{
Args: cobra.ExactArgs(1), Args: cobra.ExactArgs(1),
Short: "Confirms the given change for the active PND", Short: "Confirms the given change for the active PND",
Long: ``, Long: ``,
RunE: func(cmd *cobra.Command, args []string) error { Run: func(cmd *cobra.Command, args []string) {
return cli.HTTPGet( log.Info(cli.Confirm(
apiEndpoint, apiEndpoint,
"change-confirm", cliPnd,
"pnd="+cliPnd, args[0],
"cuid="+args[0], ))
)
}, },
} }
......
...@@ -33,6 +33,7 @@ package cmd ...@@ -33,6 +33,7 @@ package cmd
import ( import (
"code.fbi.h-da.de/cocsn/gosdn/cli" "code.fbi.h-da.de/cocsn/gosdn/cli"
log "github.com/sirupsen/logrus"
"github.com/spf13/cobra" "github.com/spf13/cobra"
) )
...@@ -43,16 +44,13 @@ var deleteCmd = &cobra.Command{ ...@@ -43,16 +44,13 @@ var deleteCmd = &cobra.Command{
Short: "set a value on a device", Short: "set a value on a device",
Long: `Set a path value for a given device. Only one path and Long: `Set a path value for a given device. Only one path and
only one value supported for now`, only one value supported for now`,
RunE: func(cmd *cobra.Command, args []string) error { Run: func(cmd *cobra.Command, args []string) {
return cli.HTTPGet( log.Info(cli.Delete(
apiEndpoint, apiEndpoint,
"delete", uuid,
"uuid="+uuid, cliPnd,
"cliSbi="+cliSbi, args[0],
"cliPnd="+cliPnd, ))
"path="+args[0],
"address="+address,
)
}, },
} }
......
...@@ -33,6 +33,7 @@ package cmd ...@@ -33,6 +33,7 @@ package cmd
import ( import (
"code.fbi.h-da.de/cocsn/gosdn/cli" "code.fbi.h-da.de/cocsn/gosdn/cli"
log "github.com/sirupsen/logrus"
"github.com/spf13/cobra" "github.com/spf13/cobra"
) )
...@@ -45,13 +46,17 @@ var getDeviceCmd = &cobra.Command{ ...@@ -45,13 +46,17 @@ var getDeviceCmd = &cobra.Command{
Device UUID or name needs to be specified as positional argument.`, Device UUID or name needs to be specified as positional argument.`,
RunE: func(cmd *cobra.Command, args []string) error { RunE: func(cmd *cobra.Command, args []string) error {
return cli.HTTPGet( resp, err := cli.GetDevice(
apiEndpoint, apiEndpoint,
"getDevice", cliPnd,
"identifier="+args[0], cliSbi,
"sbi="+cliSbi, args[0],
"pnd="+cliPnd,
) )
if err != nil {
return err
}
log.Info(resp)
return nil
}, },
} }
......
...@@ -33,6 +33,7 @@ package cmd ...@@ -33,6 +33,7 @@ package cmd
import ( import (
"code.fbi.h-da.de/cocsn/gosdn/cli" "code.fbi.h-da.de/cocsn/gosdn/cli"
log "github.com/sirupsen/logrus"
"github.com/spf13/cobra" "github.com/spf13/cobra"
) )
...@@ -42,7 +43,20 @@ var getIdsCmd = &cobra.Command{ ...@@ -42,7 +43,20 @@ var getIdsCmd = &cobra.Command{
Short: "gets device IDs from the controller", Short: "gets device IDs from the controller",
Long: `Gets device IDs from the controller and lists them.`, Long: `Gets device IDs from the controller and lists them.`,
RunE: func(cmd *cobra.Command, args []string) error { RunE: func(cmd *cobra.Command, args []string) error {
return cli.HTTPGet(apiEndpoint, "getIDs") resp, err := cli.GetIds(apiEndpoint)
if err != nil {
return err
}
for i, pnd := range resp {
log.Infof("PND %v: %v\n\tuuid: %v", i+1, pnd.Name, pnd.Id)
for j, ond := range pnd.Ond {
log.Infof("\tSBI %v: %v\n\tuuid: %v", j+1, ond.Name, ond.Id)
}
for k, sbi := range pnd.Sbi {
log.Infof("\tSBI %v: %v", k+1, sbi.Id)
}
}
return nil
}, },
} }
......
...@@ -33,21 +33,35 @@ package cmd ...@@ -33,21 +33,35 @@ package cmd
import ( import (
"code.fbi.h-da.de/cocsn/gosdn/cli" "code.fbi.h-da.de/cocsn/gosdn/cli"
log "github.com/sirupsen/logrus"
"github.com/spf13/cobra" "github.com/spf13/cobra"
) )
// getCmd represents the get command // getCmd represents the get command
var getCmd = &cobra.Command{ var getCmd = &cobra.Command{
Use: "gosdn get", Use: "get",
Short: "get request", Short: "get one or multiple pnds by uuid or name and print them to stdout",
Long: `Sends a gNMI Get request to the specified target and Long: ``,
prints the response to stdout`,
RunE: func(cmd *cobra.Command, args []string) error { RunE: func(cmd *cobra.Command, args []string) error {
_, err := cli.Get(address, username, password, args...) resp, err := cli.GetPnd(apiEndpoint, args...)
return err if err != nil {
return err
}
for i, pnd := range resp.Pnd {
log.Infof("PND %v: %v\n\tuuid: %v", i+1, pnd.Name, pnd.Id)
if verbose {
for j, ond := range pnd.Ond {
log.Infof("\tSBI %v: %v\n\tuuid: %v", j+1, ond.Name, ond.Id)
}
for k, sbi := range pnd.Sbi {
log.Infof("\tSBI %v: %v", k+1, sbi.Id)
}
}
}
return nil
}, },
} }
func init() { func init() {
rootCmd.AddCommand(getCmd) pndCmd.AddCommand(getCmd)
} }
...@@ -44,7 +44,7 @@ var initCmd = &cobra.Command{ ...@@ -44,7 +44,7 @@ var initCmd = &cobra.Command{
Same as invoking "gosdn cli" without any arguments`, Same as invoking "gosdn cli" without any arguments`,
RunE: func(cmd *cobra.Command, args []string) error { RunE: func(cmd *cobra.Command, args []string) error {
return cli.HTTPGet(apiEndpoint, "init") return cli.Init(apiEndpoint)
}, },
} }
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please register or to comment