diff --git a/api/apiIntegration_test.go b/api/apiIntegration_test.go index 9839da725ee9a573f3afc768654ea40e126ddd7f..2b4de2dc543b751dc79fa8e64f50dd3e4cc93b03 100644 --- a/api/apiIntegration_test.go +++ b/api/apiIntegration_test.go @@ -4,6 +4,7 @@ import ( "os" "testing" + "code.fbi.h-da.de/cocsn/api/go/gosdn/pnd" tpb "code.fbi.h-da.de/cocsn/api/go/gosdn/transport" "code.fbi.h-da.de/cocsn/gosdn/nucleus/util/proto" guuid "github.com/google/uuid" @@ -110,7 +111,7 @@ func TestApiIntegration(t *testing.T) { cliPnd := viper.GetString("CLI_PND") cliSbi := viper.GetString("CLI_SBI") - if _, err := AddDevice( + if _, err := addDevice( testAPIEndpoint, testUsername, testPassword, @@ -124,7 +125,7 @@ func TestApiIntegration(t *testing.T) { } did := viper.GetString("LAST_DEVICE_UUID") - _, err := GetDevice( + _, err := getDevice( testAPIEndpoint, cliPnd, testPath, @@ -135,7 +136,7 @@ func TestApiIntegration(t *testing.T) { return } - _, err = GetDevice( + _, err = getDevice( testAPIEndpoint, cliPnd, "", @@ -147,19 +148,20 @@ func TestApiIntegration(t *testing.T) { } hostname := guuid.New().String() - _, err = Update( + _, err = changeRequest( testAPIEndpoint, did, cliPnd, testPath, hostname, + pnd.ApiOperation_UPDATE, ) if (err != nil) != tt.wantErr { t.Errorf("gosdn cli set error = %v, wantErr %v", err, tt.wantErr) return } - resp, err := GetDevice(testAddress, testUsername, testPassword, testPath) + resp, err := getDevice(testAddress, testUsername, testPassword, testPath) if err != nil { if !tt.wantErr { t.Errorf("Get() error = %v, wantErr %v", err, tt.wantErr) diff --git a/api/grpc_test.go b/api/api_test.go similarity index 91% rename from api/grpc_test.go rename to api/api_test.go index 549652a2ee0afd4939159ce37fa5cb39d2ecf72f..8bd94f6f5b6d2ee314c7c65d64d760362fd289f6 100644 --- a/api/grpc_test.go +++ b/api/api_test.go @@ -154,7 +154,7 @@ func Test_CommitConfirm(t *testing.T) { } func Test_AddDevice(t *testing.T) { - resp, err := AddDevice(bufnet, "test", "test", sbiID, pndID, "test", "test") + resp, err := addDevice(bufnet, "test", "test", sbiID, pndID, "test", "test") if err != nil { t.Error(err) return @@ -163,7 +163,7 @@ func Test_AddDevice(t *testing.T) { } func Test_GetDevice(t *testing.T) { - resp, err := GetDevice(bufnet, pndID, "", ondID) + resp, err := getDevice(bufnet, pndID, "", ondID) if err != nil { t.Error(err) return @@ -175,7 +175,7 @@ func Test_GetDevice(t *testing.T) { } func Test_Update(t *testing.T) { - resp, err := Update(bufnet, ondID, pndID, "", "") + resp, err := changeRequest(bufnet, ondID, pndID, "", "", ppb.ApiOperation_UPDATE) if err != nil { t.Error(err) return @@ -184,7 +184,7 @@ func Test_Update(t *testing.T) { } func Test_Replace(t *testing.T) { - resp, err := Replace(bufnet, ondID, pndID, "", "") + resp, err := changeRequest(bufnet, ondID, pndID, "", "", ppb.ApiOperation_REPLACE) if err != nil { t.Error(err) return @@ -193,7 +193,7 @@ func Test_Replace(t *testing.T) { } func Test_Delete(t *testing.T) { - resp, err := Delete(bufnet, ondID, pndID, "") + resp, err := changeRequest(bufnet, ondID, pndID, "", "", ppb.ApiOperation_DELETE) if err != nil { t.Error(err) return diff --git a/api/go.mod b/api/go.mod index 0e0e8f2c94ce0c188d5d000abf9d84185009d28b..e3c75264d71e73e5a04413b5717b77667865118c 100644 --- a/api/go.mod +++ b/api/go.mod @@ -8,10 +8,9 @@ require ( code.fbi.h-da.de/cocsn/yang-models v0.0.7 github.com/google/uuid v1.2.0 github.com/openconfig/gnmi v0.0.0-20210527163611-d3a3e30199da - github.com/openconfig/goyang v0.2.4 - github.com/openconfig/ygot v0.10.11 github.com/sirupsen/logrus v1.8.1 github.com/spf13/viper v1.7.1 github.com/stretchr/testify v1.7.0 google.golang.org/grpc v1.37.0 + google.golang.org/protobuf v1.26.0 ) diff --git a/api/go.sum b/api/go.sum index 3054b8cd0aefee49f78fabf0040db1706546a087..697c8302ec0d6fb98a2900b54d8c6ea3c9d4bdce 100644 --- a/api/go.sum +++ b/api/go.sum @@ -171,7 +171,6 @@ github.com/golang/snappy v0.0.1/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEW github.com/golang/snappy v0.0.2/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q= github.com/google/btree v0.0.0-20180813153112-4030bb1f1f0c/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ= github.com/google/btree v1.0.0/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ= -github.com/google/gnxi v0.0.0-20210423111716-4b504ef806a7 h1:cJ62uhbZcclaYm9gq4JNyazqSY7bUEggwZdw0nHTT7o= github.com/google/gnxi v0.0.0-20210423111716-4b504ef806a7/go.mod h1:dPTuHPVOqxZ2yGKPjymiMt1vrZa8KHXWKX+Lx1z5d88= github.com/google/go-cmp v0.2.0/go.mod h1:oXzfMopK8JAjlY9xF4vHSVASa0yLyX7SntLO5aqRK0M= github.com/google/go-cmp v0.3.0/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU= diff --git a/api/grpc.go b/api/grpc.go index 2c5dccc3fa56c908529e6cbf751f8fe1406bc631..e5e7c22802541a7d52e49b2ee00136c094e44b70 100644 --- a/api/grpc.go +++ b/api/grpc.go @@ -5,15 +5,13 @@ import ( "errors" "time" + 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" - tpb "code.fbi.h-da.de/cocsn/api/go/gosdn/transport" nbi "code.fbi.h-da.de/cocsn/gosdn/northbound/client" - "github.com/google/uuid" + log "github.com/sirupsen/logrus" "github.com/spf13/viper" - pb "code.fbi.h-da.de/cocsn/api/go/gosdn/core" "google.golang.org/grpc" ) @@ -107,177 +105,3 @@ func GetPnd(addr string, args ...string) (*pb.GetResponse, error) { } 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: deviceAddress, - Username: username, - Password: password, - TransportOption: &tpb.TransportOption_GnmiTransportOption{ - GnmiTransportOption: &tpb.GnmiTransportOption{}, - }, - }, - }, - }, - Pid: pnd, - } - if sbi == "csbi" { - req.Ond[0].Sbi.Id = uuid.Nil.String() - req.Ond[0].Sbi.Type = spb.Type_CONTAINERISED - req.Ond[0].TransportOption.Csbi = true - } - 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) -} diff --git a/api/pnd.go b/api/pnd.go new file mode 100644 index 0000000000000000000000000000000000000000..0cab2dfb430dd12c9ee93fc30189f658c5d493dc --- /dev/null +++ b/api/pnd.go @@ -0,0 +1,260 @@ +package api + +import ( + "context" + "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" + "code.fbi.h-da.de/cocsn/gosdn/interfaces/change" + "code.fbi.h-da.de/cocsn/gosdn/interfaces/device" + "code.fbi.h-da.de/cocsn/gosdn/interfaces/southbound" + "code.fbi.h-da.de/cocsn/gosdn/interfaces/store" + nbi "code.fbi.h-da.de/cocsn/gosdn/northbound/client" + "code.fbi.h-da.de/cocsn/gosdn/nucleus/errors" + "github.com/google/uuid" +) + +type PrincipalNetworkDomainAdapter struct { + id uuid.UUID + endpoint string +} + +func (p *PrincipalNetworkDomainAdapter) Destroy() error { + return &errors.ErrNotYetImplemented{} +} + +func (p *PrincipalNetworkDomainAdapter) AddSbi(s southbound.SouthboundInterface) error { + return &errors.ErrNotYetImplemented{} +} + +func (p *PrincipalNetworkDomainAdapter) RemoveSbi(uuid.UUID) error { + return &errors.ErrNotYetImplemented{} +} + +func (p *PrincipalNetworkDomainAdapter) AddDevice(name string, opts *tpb.TransportOption, sid uuid.UUID) error { + + return &errors.ErrNotYetImplemented{} +} + +func (p *PrincipalNetworkDomainAdapter) GetDevice(identifier string) (device.Device, error) { + return nil, &errors.ErrNotYetImplemented{} +} + +func (p *PrincipalNetworkDomainAdapter) RemoveDevice(uuid.UUID) error { + return &errors.ErrNotYetImplemented{} +} + +func (p *PrincipalNetworkDomainAdapter) Devices() []uuid.UUID { + return nil +} + +func (p *PrincipalNetworkDomainAdapter) ChangeOND(uuid uuid.UUID, operation ppb.ApiOperation, path string, value ...string) error { + return &errors.ErrNotYetImplemented{} +} + +func (p *PrincipalNetworkDomainAdapter) Request(uuid.UUID, string) error { + return &errors.ErrNotYetImplemented{} +} + +func (p *PrincipalNetworkDomainAdapter) RequestAll(string) error { + return &errors.ErrNotYetImplemented{} +} + +func (p *PrincipalNetworkDomainAdapter) GetName() string { + return "" +} + +func (p *PrincipalNetworkDomainAdapter) GetDescription() string { + return "" +} + +func (p *PrincipalNetworkDomainAdapter) MarshalDevice(string) (string, error) { + return "", &errors.ErrNotYetImplemented{} +} + +func (p *PrincipalNetworkDomainAdapter) ContainsDevice(uuid.UUID) bool { + return false +} + +func (p *PrincipalNetworkDomainAdapter) GetSBIs() store.Store { + return nil +} + +func (p *PrincipalNetworkDomainAdapter) ID() uuid.UUID { + return p.id +} + +func (p *PrincipalNetworkDomainAdapter) PendingChanges() []uuid.UUID { + return nil +} + +func (p *PrincipalNetworkDomainAdapter) CommittedChanges() []uuid.UUID { + return nil +} + +func (p *PrincipalNetworkDomainAdapter) GetChange(uuid.UUID, ...int) (change.Change, error) { + return nil, &errors.ErrNotYetImplemented{} +} + +func (p *PrincipalNetworkDomainAdapter) Commit(uuid.UUID) error { + return &errors.ErrNotYetImplemented{} +} + +func (p *PrincipalNetworkDomainAdapter) Confirm(uuid.UUID) error { + return &errors.ErrNotYetImplemented{} +} + +// 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: deviceAddress, + Username: username, + Password: password, + TransportOption: &tpb.TransportOption_GnmiTransportOption{ + GnmiTransportOption: &tpb.GnmiTransportOption{}, + }, + }, + }, + }, + Pid: pnd, + } + if sbi == "csbi" { + req.Ond[0].Sbi.Id = uuid.Nil.String() + req.Ond[0].Sbi.Type = spb.Type_CONTAINERISED + req.Ond[0].TransportOption.Csbi = true + } + 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) +} + +// change creates a ChangeRequest for the specified OND. ApiOperations are +// used to specify the type of the change (update, replace, delete as specified +// in https://github.com/openconfig/reference/blob/master/rpc/gnmi/gnmi-specification.md#34-modifying-state) +// For delete operations the value field needs to contain an empty string. +func changeRequest(addr, did, pid, path, value string, op ppb.ApiOperation) (*ppb.SetResponse, error) { + req := &ppb.ChangeRequest{ + Id: did, + Path: path, + Value: value, + ApiOp: op, + } + 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) +}