Skip to content
Snippets Groups Projects
Commit d3acdec8 authored by André Sterba's avatar André Sterba
Browse files

Merge branch 'develop' into istaester/autogenerate-device-names

parents ff928b38 a94be2bb
No related branches found
No related tags found
1 merge request!150Let user set a name for a device or autogenerate it
Pipeline #70475 passed
This commit is part of merge request !150. Comments created here will be created in the context of that merge request.
# Collection of programming stuff
## Dependencies
* github.com/spf13/cobra: used for basic cli of gosdn, such as starting the daemon, get versioning info etc
* grpc
* ygot
## Structure of the code
main.go: main() function
nucleus/: core functionality of gosdn
ygot (yang for go tools).
Checkout this in go: go get github.com/openconfig/ygot/ygot
## Usefull things to know
Regenerate gRPC code (https://grpc.io/docs/languages/go/quickstart/#regenerate-grpc-code)
* ( cd ~/go/src/github.com/grpc-go/cmd/protoc-gen-go-grpc/ && go install . )
*
protoc \
--go_out=Mgrpc/service_config/service_config.proto=/internal/proto/grpc_service_config:. \
--go-grpc_out=Mgrpc/service_config/service_config.proto=/internal/proto/grpc_service_config:. \
--go_opt=paths=source_relative \
--go-grpc_opt=paths=source_relative \
cliInterface/gosdnCLI.proto
Generate the ygot code:
just type: go generate
...@@ -4,7 +4,7 @@ import ( ...@@ -4,7 +4,7 @@ import (
"context" "context"
"os" "os"
"code.fbi.h-da.de/cocsn/gosdn/nucleus" nucleus "code.fbi.h-da.de/cocsn/gosdn/nucleus/errors"
log "github.com/sirupsen/logrus" log "github.com/sirupsen/logrus"
appv1 "k8s.io/api/apps/v1" appv1 "k8s.io/api/apps/v1"
corev1 "k8s.io/api/core/v1" corev1 "k8s.io/api/core/v1"
......
run: run:
timeout: 5m timeout: 10m
issues-exit-code: 1 issues-exit-code: 1
# directories to be ignored by linters # directories to be ignored by linters
skip-dirs: skip-dirs:
...@@ -7,7 +7,7 @@ run: ...@@ -7,7 +7,7 @@ run:
- test - test
skip-dirs-default: true skip-dirs-default: true
skip-files: skip-files:
- nucleus/http.go - http.go
# output settings -> code-climate for GitLab # output settings -> code-climate for GitLab
output: output:
format: code-climate format: code-climate
...@@ -26,8 +26,11 @@ linters: ...@@ -26,8 +26,11 @@ linters:
disable-all: true disable-all: true
enable: enable:
- gofmt - gofmt
- goimports
- golint - golint
- gocyclo - gocyclo
- govet - govet
issues: issues:
exclude-use-default: false exclude-use-default: false
max-issues-per-linter: 0
max-same-issues: 0
\ No newline at end of file
...@@ -44,6 +44,5 @@ unit-test: ...@@ -44,6 +44,5 @@ unit-test:
controller-test: controller-test:
script: script:
- cd ./nucleus
- go test -race -v -run TestRun - go test -race -v -run TestRun
<<: *test <<: *test
\ No newline at end of file
package cli package cli
import ( import (
"code.fbi.h-da.de/cocsn/gosdn/forks/goarista/gnmi"
"code.fbi.h-da.de/cocsn/gosdn/nucleus"
"context" "context"
"fmt" "fmt"
gpb "github.com/openconfig/gnmi/proto/gnmi"
"strings" "strings"
"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"
) )
// Capabilities sends a gNMI Capabilities request to the specified target // Capabilities sends a gNMI Capabilities request to the specified target
......
package cli package cli
import ( 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/forks/goarista/gnmi"
"code.fbi.h-da.de/cocsn/gosdn/nucleus" "code.fbi.h-da.de/cocsn/gosdn/nucleus"
"context"
gpb "github.com/openconfig/gnmi/proto/gnmi" gpb "github.com/openconfig/gnmi/proto/gnmi"
log "github.com/sirupsen/logrus" log "github.com/sirupsen/logrus"
) )
...@@ -31,7 +34,7 @@ func Get(a, u, p string, args ...string) (*gpb.GetResponse, error) { ...@@ -31,7 +34,7 @@ func Get(a, u, p string, args ...string) (*gpb.GetResponse, error) {
log.Debug(resp) log.Debug(resp)
r, ok := resp.(*gpb.GetResponse) r, ok := resp.(*gpb.GetResponse)
if !ok { if !ok {
return nil, &nucleus.ErrInvalidTypeAssertion{} return nil, &errors.ErrInvalidTypeAssertion{}
} }
return r, nil return r, nil
} }
package cli package cli
import ( import (
"context"
"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"
"context"
) )
// Set sends a gNMI Set request to the specified target. Only one // Set sends a gNMI Set request to the specified target. Only one
......
...@@ -8,6 +8,8 @@ import ( ...@@ -8,6 +8,8 @@ import (
"syscall" "syscall"
"time" "time"
"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" gpb "github.com/openconfig/gnmi/proto/gnmi"
...@@ -48,7 +50,7 @@ func Subscribe(address, username, password, deviceName string, sample, heartbeat ...@@ -48,7 +50,7 @@ func Subscribe(address, username, password, deviceName string, sample, heartbeat
} }
done := make(chan os.Signal, 1) done := make(chan os.Signal, 1)
signal.Notify(done, syscall.SIGILL, syscall.SIGTERM) signal.Notify(done, syscall.SIGILL, syscall.SIGTERM)
ctx := context.WithValue(context.Background(), nucleus.CtxKeyOpts, opts) //nolint ctx := context.WithValue(context.Background(), types.CtxKeyOpts, opts) //nolint
go func() { go func() {
if err := device.Transport.Subscribe(ctx); err != nil { if err := device.Transport.Subscribe(ctx); err != nil {
log.Fatal(err) log.Fatal(err)
......
package cli package cli
import ( import (
"context"
"net"
"reflect"
"code.fbi.h-da.de/cocsn/gosdn/forks/google/gnmi" "code.fbi.h-da.de/cocsn/gosdn/forks/google/gnmi"
oc "code.fbi.h-da.de/cocsn/yang-models/generated/openconfig" oc "code.fbi.h-da.de/cocsn/yang-models/generated/openconfig"
"context"
pb "github.com/openconfig/gnmi/proto/gnmi" pb "github.com/openconfig/gnmi/proto/gnmi"
"github.com/openconfig/goyang/pkg/yang" "github.com/openconfig/goyang/pkg/yang"
"github.com/openconfig/ygot/util" "github.com/openconfig/ygot/util"
...@@ -11,8 +14,6 @@ import ( ...@@ -11,8 +14,6 @@ import (
log "github.com/sirupsen/logrus" log "github.com/sirupsen/logrus"
"google.golang.org/grpc" "google.golang.org/grpc"
"google.golang.org/grpc/reflection" "google.golang.org/grpc/reflection"
"net"
"reflect"
) )
type server struct { type server struct {
......
...@@ -35,7 +35,8 @@ import ( ...@@ -35,7 +35,8 @@ import (
"context" "context"
"os" "os"
"code.fbi.h-da.de/cocsn/gosdn/nucleus" "code.fbi.h-da.de/cocsn/gosdn"
log "github.com/sirupsen/logrus" log "github.com/sirupsen/logrus"
"github.com/spf13/cobra" "github.com/spf13/cobra"
...@@ -60,7 +61,7 @@ for REST API calls.`, ...@@ -60,7 +61,7 @@ for REST API calls.`,
RunE: func(cmd *cobra.Command, args []string) error { RunE: func(cmd *cobra.Command, args []string) error {
ctx, cancel := context.WithCancel(context.Background()) ctx, cancel := context.WithCancel(context.Background())
defer cancel() defer cancel()
return nucleus.Run(ctx) return gosdn.Run(ctx)
}, },
} }
......
...@@ -33,6 +33,7 @@ package cmd ...@@ -33,6 +33,7 @@ package cmd
import ( import (
"errors" "errors"
"github.com/spf13/cobra" "github.com/spf13/cobra"
) )
......
package nucleus package gosdn
import ( import (
"code.fbi.h-da.de/cocsn/gosdn/database"
"context" "context"
"github.com/google/uuid"
log "github.com/sirupsen/logrus"
"net/http" "net/http"
"os" "os"
"os/signal" "os/signal"
"sync" "sync"
"time" "time"
"code.fbi.h-da.de/cocsn/gosdn/nucleus/types"
"code.fbi.h-da.de/cocsn/gosdn/database"
"code.fbi.h-da.de/cocsn/gosdn/nucleus"
"github.com/google/uuid"
log "github.com/sirupsen/logrus"
) )
var coreLock sync.RWMutex var coreLock sync.RWMutex
...@@ -20,8 +24,8 @@ type Core struct { ...@@ -20,8 +24,8 @@ type Core struct {
// deprecated // deprecated
database database.Database database database.Database
pndc pndStore pndc *nucleus.PndStore
sbic sbiStore sbic *nucleus.SbiStore
httpServer *http.Server httpServer *http.Server
stopChan chan os.Signal stopChan chan os.Signal
} }
...@@ -31,8 +35,8 @@ var c *Core ...@@ -31,8 +35,8 @@ var c *Core
func init() { func init() {
c = &Core{ c = &Core{
database: database.Database{}, database: database.Database{},
pndc: pndStore{store{}}, pndc: nucleus.NewPndStore(),
sbic: sbiStore{store{}}, sbic: nucleus.NewSbiStore(),
stopChan: make(chan os.Signal, 1), stopChan: make(chan os.Signal, 1),
} }
...@@ -49,25 +53,26 @@ func initialize() error { ...@@ -49,25 +53,26 @@ func initialize() error {
// TODO: Start grpc listener here // TODO: Start grpc listener here
coreLock.Lock() coreLock.Lock()
defer coreLock.Unlock() defer coreLock.Unlock()
return httpAPI() startHttpServer()
return nil
} }
// createSouthboundInterfaces initializes the controller with its supported SBIs // createSouthboundInterfaces initializes the controller with its supported SBIs
func createSouthboundInterfaces() error { func createSouthboundInterfaces() error {
sbi := &OpenConfig{id: uuid.New()} sbi := nucleus.NewSBI(types.Openconfig)
if err := c.sbic.add(sbi); err != nil { if err := c.sbic.Add(sbi); err != nil {
return err return err
} }
return createPrincipalNetworkDomain(sbi) return createPrincipalNetworkDomain(sbi)
} }
// createPrincipalNetworkDomain initializes the controller with an initial PND // createPrincipalNetworkDomain initializes the controller with an initial PND
func createPrincipalNetworkDomain(sbi SouthboundInterface) error { func createPrincipalNetworkDomain(s nucleus.SouthboundInterface) error {
pnd, err := NewPND("base", "gosdn base pnd", uuid.New(), sbi) pnd, err := nucleus.NewPND("base", "gosdn base pnd", uuid.New(), s)
if err != nil { if err != nil {
return err return err
} }
err = c.pndc.add(pnd) err = c.pndc.Add(pnd)
if err != nil { if err != nil {
return err return err
} }
......
package nucleus package gosdn
import ( import (
"context" "context"
......
...@@ -2,6 +2,7 @@ package database ...@@ -2,6 +2,7 @@ package database
import ( import (
"errors" "errors"
"github.com/neo4j/neo4j-go-driver/neo4j" "github.com/neo4j/neo4j-go-driver/neo4j"
log "github.com/sirupsen/logrus" log "github.com/sirupsen/logrus"
"github.com/spf13/viper" "github.com/spf13/viper"
......
gosdn.png

132 KiB

@startuml
namespace nucleus {
class ClientConfig << (S,Aquamarine) >> {
+ Identifier string
+ Endpoint string
+ Username string
+ Password string
+ GjsonDefaultPath string
+ GjsonConnectionsPath string
}
class Core << (S,Aquamarine) >> {
- devices <font color=blue>map</font>[string]Device
- southboundInterfaces <font color=blue>map</font>[string]interfaces.SouthboundInterface
- prinipalNetworkDomains <font color=blue>map</font>[uuid.UUID]interfaces.PrincipalNetworkDomain
- database database.Database
- config controllerConfig
+ IsRunning <font color=blue>chan</font> bool
- readControllerConfig(configFileController string) error
+ Init(socket string, configFileController string, configFileClient string, IsRunningChannel <font color=blue>chan</font> bool)
+ AttachDatabase()
+ Shutdown()
}
class Device << (S,Aquamarine) >> {
- device ygot.GoStruct
+ SBI interfaces.SouthboundInterface
+ Config DeviceConfig
}
class DeviceConfig << (S,Aquamarine) >> {
+ Identifier uuid.UUID
+ Endpoint string
+ Username string
+ Password string
}
interface PrincipalNetworkDomain {
+ Destroy() error
+ AddSbi() error
+ RemoveSbi() error
+ AddDevice( interfaces.Device) error
+ RemoveDevice(uuid uuid.UUID) error
}
interface SouthboundInterface {
}
class buf << (S,Aquamarine) >> {
+ Write(p []byte) (int, error)
}
class controllerConfig << (S,Aquamarine) >> {
+ CliSocket string
+ DatabaseSocket string
+ DatabaseUser string
+ DatabasePassword string
+ DatabaseCrypto bool
+ ConfigPath string
}
class logConnection << (S,Aquamarine) >> {
- stream proto.GrpcCli_CreateLogStreamServer
- id string
- active bool
- error <font color=blue>chan</font> error
}
class nucleus.buf << (T, #FF7700) >> {
}
class pndImplementation << (S,Aquamarine) >> {
- name string
- sbiContainer <font color=blue>map</font>[string]*interfaces.SouthboundInterface
- devices <font color=blue>map</font>[uuid.UUID]Device
+ Destroy() error
+ AddSbi() error
+ RemoveSbi() error
+ AddDevice(device Device) error
+ RemoveDevice(uuid uuid.UUID) error
}
class server << (S,Aquamarine) >> {
- core *Core
- logConnections []*logConnection
+ SayHello(ctx context.Context, in *proto.HelloRequest) (*proto.HelloReply, error)
+ CreateLogStream(req *emptypb.Empty, stream proto.GrpcCli_CreateLogStreamServer) error
+ BroadcastLog(log *proto.LogReply)
+ Shutdown(ctx context.Context, in *proto.ShutdownRequest) (*proto.ShutdownReply, error)
+ TAPIGetEdge(ctx context.Context, in *proto.TAPIRequest) (*proto.TAPIReply, error)
+ TAPIGetEdgeNode(ctx context.Context, in *proto.TAPIRequest) (*proto.TAPIReply, error)
+ TAPIGetLink(ctx context.Context, in *proto.TAPIRequest) (*proto.TAPIReply, error)
}
}
"proto.UnimplementedGrpcCliServer" *-- "nucleus.server"
namespace sbi {
class OpenConfig << (S,Aquamarine) >> {
- name string
- clientContainer []Client
+ AddClient() error
+ RemoveClient() error
+ CollectHeartbeats() error
+ ListClients() <font color=blue>map</font>[int]interfaces.Client
}
}
"__builtin__.[]byte" #.. "nucleus.buf"
@enduml
package nucleus package gosdn
import ( import (
"context" "context"
...@@ -8,17 +8,21 @@ import ( ...@@ -8,17 +8,21 @@ import (
"net/url" "net/url"
"time" "time"
"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/errors"
"code.fbi.h-da.de/cocsn/gosdn/nucleus/types"
"github.com/google/uuid" "github.com/google/uuid"
"code.fbi.h-da.de/cocsn/gosdn/forks/goarista/gnmi"
gpb "github.com/openconfig/gnmi/proto/gnmi" gpb "github.com/openconfig/gnmi/proto/gnmi"
log "github.com/sirupsen/logrus" log "github.com/sirupsen/logrus"
) )
var apiOpmap = map[string]Operation{ var apiOpmap = map[string]types.Operation{
"update": TransportUpdate, "update": types.TransportUpdate,
"replace": TransportReplace, "replace": types.TransportReplace,
"delete": TransportDelete, "delete": types.TransportDelete,
} }
func stopHttpServer() error { func stopHttpServer() error {
...@@ -34,19 +38,17 @@ func registerHttpHandler() { ...@@ -34,19 +38,17 @@ func registerHttpHandler() {
fmt.Println("Recovered in f", r) fmt.Println("Recovered in f", r)
} }
}() }()
http.HandleFunc("/api", httpHandler) http.HandleFunc("/api", httpApi)
http.HandleFunc("/livez", healthCheck) http.HandleFunc("/livez", healthCheck)
http.HandleFunc("/readyz", readynessCheck) http.HandleFunc("/readyz", readynessCheck)
} }
// deprecated func startHttpServer() {
func httpAPI() error {
registerHttpHandler() registerHttpHandler()
c.httpServer = &http.Server{Addr: ":8080"} c.httpServer = &http.Server{Addr: ":8080"}
go func() { go func() {
log.Info(c.httpServer.ListenAndServe()) log.Info(c.httpServer.ListenAndServe())
}() }()
return nil
} }
func healthCheck(writer http.ResponseWriter, request *http.Request) { func healthCheck(writer http.ResponseWriter, request *http.Request) {
...@@ -57,8 +59,9 @@ func readynessCheck(writer http.ResponseWriter, request *http.Request) { ...@@ -57,8 +59,9 @@ func readynessCheck(writer http.ResponseWriter, request *http.Request) {
writer.WriteHeader(http.StatusOK) writer.WriteHeader(http.StatusOK)
} }
// deprecated
// nolint // nolint
func httpHandler(writer http.ResponseWriter, request *http.Request) { func httpApi(writer http.ResponseWriter, request *http.Request) {
log.WithFields(log.Fields{ log.WithFields(log.Fields{
"request": request, "request": request,
}).Debug("incoming request") }).Debug("incoming request")
...@@ -91,16 +94,16 @@ func httpHandler(writer http.ResponseWriter, request *http.Request) { ...@@ -91,16 +94,16 @@ func httpHandler(writer http.ResponseWriter, request *http.Request) {
} }
} }
var pnd PrincipalNetworkDomain var httpPnd nucleus.PrincipalNetworkDomain
var sbi SouthboundInterface var httpSbi nucleus.SouthboundInterface
if query.Get("q") != "init" && query.Get("q") != "getIDs" { if query.Get("q") != "init" && query.Get("q") != "getIDs" {
pnd, err = c.pndc.get(pid) httpPnd, err = c.pndc.Get(pid)
if err != nil { if err != nil {
handleServerError(writer, err) handleServerError(writer, err)
return return
} }
sbic := pnd.GetSBIs() sbic := httpPnd.GetSBIs()
sbi, err = sbic.(*sbiStore).get(sid) httpSbi, err = sbic.(*nucleus.SbiStore).Get(sid)
if err != nil { if err != nil {
handleServerError(writer, err) handleServerError(writer, err)
return return
...@@ -109,15 +112,15 @@ func httpHandler(writer http.ResponseWriter, request *http.Request) { ...@@ -109,15 +112,15 @@ func httpHandler(writer http.ResponseWriter, request *http.Request) {
switch q := query.Get("q"); q { switch q := query.Get("q"); q {
case "addDevice": case "addDevice":
d, err := NewDevice(sbi, &GnmiTransportOptions{ d, err := nucleus.NewDevice(httpSbi, &nucleus.GnmiTransportOptions{
Config: gnmi.Config{ Config: gnmi.Config{
Addr: query.Get("address"), Addr: query.Get("address"),
Password: query.Get("password"), Password: query.Get("password"),
Username: query.Get("username"), Username: query.Get("username"),
Encoding: gpb.Encoding_JSON_IETF, Encoding: gpb.Encoding_JSON_IETF,
}, },
SetNode: sbi.SetNode(), SetNode: httpSbi.SetNode(),
Unmarshal: sbi.(*OpenConfig).Unmarshal(), Unmarshal: httpSbi.(*nucleus.OpenConfig).Unmarshal(),
RespChan: make(chan *gpb.SubscribeResponse), RespChan: make(chan *gpb.SubscribeResponse),
}, },
query.Get("name"), query.Get("name"),
...@@ -129,7 +132,7 @@ func httpHandler(writer http.ResponseWriter, request *http.Request) { ...@@ -129,7 +132,7 @@ func httpHandler(writer http.ResponseWriter, request *http.Request) {
return return
} }
err = pnd.AddDevice(d) err = httpPnd.AddDevice(d)
if err != nil { if err != nil {
writer.WriteHeader(http.StatusInternalServerError) writer.WriteHeader(http.StatusInternalServerError)
log.Error(err) log.Error(err)
...@@ -141,10 +144,10 @@ func httpHandler(writer http.ResponseWriter, request *http.Request) { ...@@ -141,10 +144,10 @@ func httpHandler(writer http.ResponseWriter, request *http.Request) {
fmt.Fprintf(writer, "Name: %s\n", d.Name) fmt.Fprintf(writer, "Name: %s\n", d.Name)
fmt.Fprintf(writer, "UUID: %v\n", d.UUID) fmt.Fprintf(writer, "UUID: %v\n", d.UUID)
case "request": case "request":
err = pnd.Request(id, query.Get("path")) err = httpPnd.Request(id, query.Get("path"))
if err != nil { if err != nil {
switch err.(type) { switch err.(type) {
case *ErrNotFound: case *errors.ErrNotFound:
writer.WriteHeader(http.StatusNotFound) writer.WriteHeader(http.StatusNotFound)
default: default:
writer.WriteHeader(http.StatusInternalServerError) writer.WriteHeader(http.StatusInternalServerError)
...@@ -154,10 +157,10 @@ func httpHandler(writer http.ResponseWriter, request *http.Request) { ...@@ -154,10 +157,10 @@ func httpHandler(writer http.ResponseWriter, request *http.Request) {
} }
writer.WriteHeader(http.StatusOK) writer.WriteHeader(http.StatusOK)
case "requestAll": case "requestAll":
err = pnd.RequestAll(query.Get("path")) err = httpPnd.RequestAll(query.Get("path"))
if err != nil { if err != nil {
switch err.(type) { switch err.(type) {
case *ErrNotFound: case *errors.ErrNotFound:
writer.WriteHeader(http.StatusNotFound) writer.WriteHeader(http.StatusNotFound)
default: default:
writer.WriteHeader(http.StatusInternalServerError) writer.WriteHeader(http.StatusInternalServerError)
...@@ -178,10 +181,10 @@ func httpHandler(writer http.ResponseWriter, request *http.Request) { ...@@ -178,10 +181,10 @@ func httpHandler(writer http.ResponseWriter, request *http.Request) {
idAsString := id.String() idAsString := id.String()
if idAsString == "00000000-0000-0000-0000-000000000000" { if idAsString == "00000000-0000-0000-0000-000000000000" {
device, err := pnd.MarshalDeviceByName(deviceIdentifier) device, err := httpPnd.MarshalDeviceByName(deviceIdentifier)
if err != nil { if err != nil {
switch err.(type) { switch err.(type) {
case *ErrNotFound: case *errors.ErrNotFound:
writer.WriteHeader(http.StatusNotFound) writer.WriteHeader(http.StatusNotFound)
default: default:
writer.WriteHeader(http.StatusInternalServerError) writer.WriteHeader(http.StatusInternalServerError)
...@@ -195,10 +198,10 @@ func httpHandler(writer http.ResponseWriter, request *http.Request) { ...@@ -195,10 +198,10 @@ func httpHandler(writer http.ResponseWriter, request *http.Request) {
fmt.Fprintf(writer, "%v", device) fmt.Fprintf(writer, "%v", device)
} else { } else {
device, err := pnd.MarshalDevice(id) device, err := httpPnd.MarshalDevice(id)
if err != nil { if err != nil {
switch err.(type) { switch err.(type) {
case *ErrNotFound: case *errors.ErrNotFound:
writer.WriteHeader(http.StatusNotFound) writer.WriteHeader(http.StatusNotFound)
default: default:
writer.WriteHeader(http.StatusInternalServerError) writer.WriteHeader(http.StatusInternalServerError)
...@@ -217,7 +220,7 @@ func httpHandler(writer http.ResponseWriter, request *http.Request) { ...@@ -217,7 +220,7 @@ func httpHandler(writer http.ResponseWriter, request *http.Request) {
writeIDs(writer, "PNDs", pnds) writeIDs(writer, "PNDs", pnds)
writeIDs(writer, "SBIs", c.sbic.UUIDs()) writeIDs(writer, "SBIs", c.sbic.UUIDs())
for _, id := range pnds { for _, id := range pnds {
p, err := c.pndc.get(id) p, err := c.pndc.Get(id)
if err != nil { if err != nil {
handleServerError(writer, err) handleServerError(writer, err)
return return
...@@ -228,22 +231,22 @@ func httpHandler(writer http.ResponseWriter, request *http.Request) { ...@@ -228,22 +231,22 @@ func httpHandler(writer http.ResponseWriter, request *http.Request) {
writeIDs(writer, "PNDs", c.pndc.UUIDs()) writeIDs(writer, "PNDs", c.pndc.UUIDs())
writeIDs(writer, "SBIs", c.sbic.UUIDs()) writeIDs(writer, "SBIs", c.sbic.UUIDs())
case "update", "replace": case "update", "replace":
if err := pnd.ChangeOND(id, apiOpmap[q], query.Get("path"), query.Get("value")); err != nil { if err := httpPnd.ChangeOND(id, apiOpmap[q], query.Get("path"), query.Get("value")); err != nil {
handleServerError(writer, err) handleServerError(writer, err)
return return
} }
writer.WriteHeader(http.StatusOK) writer.WriteHeader(http.StatusOK)
case "delete": case "delete":
if err := pnd.ChangeOND(id, TransportDelete, query.Get("path")); err != nil { if err := httpPnd.ChangeOND(id, types.TransportDelete, query.Get("path")); err != nil {
handleServerError(writer, err) handleServerError(writer, err)
return return
} }
writer.WriteHeader(http.StatusOK) writer.WriteHeader(http.StatusOK)
case "change-list": case "change-list":
changes := pnd.Committed() changes := httpPnd.Committed()
writeIDs(writer, "Tentative changes", changes) writeIDs(writer, "Tentative changes", changes)
case "change-list-pending": case "change-list-pending":
changes := pnd.Pending() changes := httpPnd.Pending()
writeIDs(writer, "Pending changes", changes) writeIDs(writer, "Pending changes", changes)
case "change-commit": case "change-commit":
cuid, err := uuid.Parse(query.Get("cuid")) cuid, err := uuid.Parse(query.Get("cuid"))
...@@ -251,7 +254,7 @@ func httpHandler(writer http.ResponseWriter, request *http.Request) { ...@@ -251,7 +254,7 @@ func httpHandler(writer http.ResponseWriter, request *http.Request) {
handleServerError(writer, err) handleServerError(writer, err)
return return
} }
if err := pnd.Commit(cuid); err != nil { if err := httpPnd.Commit(cuid); err != nil {
handleServerError(writer, err) handleServerError(writer, err)
return return
} }
...@@ -262,7 +265,7 @@ func httpHandler(writer http.ResponseWriter, request *http.Request) { ...@@ -262,7 +265,7 @@ func httpHandler(writer http.ResponseWriter, request *http.Request) {
handleServerError(writer, err) handleServerError(writer, err)
return return
} }
if err := pnd.Confirm(cuid); err != nil { if err := httpPnd.Confirm(cuid); err != nil {
handleServerError(writer, err) handleServerError(writer, err)
return return
} }
......
package nucleus package gosdn
import ( import (
"errors" "errors"
"net/http" "net/http"
"testing" "testing"
"code.fbi.h-da.de/cocsn/gosdn/nucleus/types"
"code.fbi.h-da.de/cocsn/gosdn/mocks" "code.fbi.h-da.de/cocsn/gosdn/mocks"
"code.fbi.h-da.de/cocsn/gosdn/nucleus"
"github.com/google/uuid" "github.com/google/uuid"
log "github.com/sirupsen/logrus" log "github.com/sirupsen/logrus"
"github.com/stretchr/testify/mock" "github.com/stretchr/testify/mock"
) )
func testSetupHTTP() { func testSetupHTTP() {
sbi = &OpenConfig{id: defaultSbiID} sbi = nucleus.NewSBI(types.Openconfig)
sbi.Schema() sbi.Schema()
defaultSbiID = sbi.ID()
var err error var err error
httpTestPND, err = NewPND("test", "test pnd", defaultPndID, sbi) httpTestPND, err = nucleus.NewPND("test", "test pnd", defaultPndID, sbi)
if err != nil { if err != nil {
log.Fatal(err) log.Fatal(err)
} }
...@@ -32,10 +36,10 @@ func testSetupHTTP() { ...@@ -32,10 +36,10 @@ func testSetupHTTP() {
args = "&uuid=" + mdid.String() + "&pnd=" + defaultPndID.String() + "&sbi=" + defaultSbiID.String() args = "&uuid=" + mdid.String() + "&pnd=" + defaultPndID.String() + "&sbi=" + defaultSbiID.String()
argsNotFound = "&uuid=" + uuid.New().String() + "&pnd=" + defaultPndID.String() + "&sbi=" + defaultSbiID.String() argsNotFound = "&uuid=" + uuid.New().String() + "&pnd=" + defaultPndID.String() + "&sbi=" + defaultSbiID.String()
argsNotFoundGetDevice = "&identifier=" + uuid.New().String() + "&pnd=" + defaultPndID.String() + "&sbi=" + defaultSbiID.String() argsNotFoundGetDevice = "&identifier=" + uuid.New().String() + "&pnd=" + defaultPndID.String() + "&sbi=" + defaultSbiID.String()
if err := c.sbic.add(sbi); err != nil { if err := c.sbic.Add(sbi); err != nil {
log.Fatal(err) log.Fatal(err)
} }
if err := c.pndc.add(httpTestPND); err != nil { if err := c.pndc.Add(httpTestPND); err != nil {
log.Fatal(err) log.Fatal(err)
} }
} }
...@@ -184,10 +188,7 @@ func Test_httpApi(t *testing.T) { ...@@ -184,10 +188,7 @@ func Test_httpApi(t *testing.T) {
}, },
} }
coreLock.Lock() coreLock.Lock()
if err := httpAPI(); err != nil { startHttpServer()
t.Errorf("httpApi() error = %v", err)
return
}
coreLock.Unlock() coreLock.Unlock()
for _, tt := range tests { for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) { t.Run(tt.name, func(t *testing.T) {
...@@ -200,7 +201,7 @@ func Test_httpApi(t *testing.T) { ...@@ -200,7 +201,7 @@ func Test_httpApi(t *testing.T) {
t.Errorf("httpApi() got: %v, want %v", got.StatusCode, tt.want.StatusCode) t.Errorf("httpApi() got: %v, want %v", got.StatusCode, tt.want.StatusCode)
} }
if tt.name == "add-device" { if tt.name == "add-device" {
for k := range httpTestPND.(*pndImplementation).devices.store { for _, k := range httpTestPND.Devices() {
if k != mdid { if k != mdid {
if err := httpTestPND.RemoveDevice(k); err != nil { if err := httpTestPND.RemoveDevice(k); err != nil {
t.Error(err) t.Error(err)
......
package gosdn
import (
"context"
"os"
"testing"
"code.fbi.h-da.de/cocsn/gosdn/mocks"
"code.fbi.h-da.de/cocsn/gosdn/nucleus"
"code.fbi.h-da.de/cocsn/gosdn/nucleus/util/proto"
"github.com/google/uuid"
gpb "github.com/openconfig/gnmi/proto/gnmi"
log "github.com/sirupsen/logrus"
"github.com/stretchr/testify/mock"
pb "google.golang.org/protobuf/proto"
)
const apiEndpoint = "http://localhost:8080"
// UUIDs for test cases
var mdid uuid.UUID
var defaultSbiID uuid.UUID
var defaultPndID uuid.UUID
var cuid uuid.UUID
var sbi nucleus.SouthboundInterface
var httpTestPND nucleus.PrincipalNetworkDomain
var gnmiMessages map[string]pb.Message
var httpTestDevice nucleus.Device
var args string
var argsNotFound string
var argsNotFoundGetDevice string
var mockContext = mock.MatchedBy(func(ctx context.Context) bool { return true })
// TestMain bootstraps all tests. Humongous beast
// TODO: Move somewhere more sensible
func TestMain(m *testing.M) {
log.SetReportCaller(true)
if os.Getenv("GOSDN_LOG") == "nolog" {
log.SetLevel(log.PanicLevel)
}
gnmiMessages = map[string]pb.Message{
"./test/proto/cap-resp-arista-ceos": &gpb.CapabilityResponse{},
"./test/proto/req-full-node": &gpb.GetRequest{},
"./test/proto/req-full-node-arista-ceos": &gpb.GetRequest{},
"./test/proto/req-interfaces-arista-ceos": &gpb.GetRequest{},
"./test/proto/req-interfaces-interface-arista-ceos": &gpb.GetRequest{},
"./test/proto/req-interfaces-wildcard": &gpb.GetRequest{},
"./test/proto/resp-full-node": &gpb.GetResponse{},
"./test/proto/resp-full-node-arista-ceos": &gpb.GetResponse{},
"./test/proto/resp-interfaces-arista-ceos": &gpb.GetResponse{},
"./test/proto/resp-interfaces-interface-arista-ceos": &gpb.GetResponse{},
"./test/proto/resp-interfaces-wildcard": &gpb.GetResponse{},
"./test/proto/resp-set-system-config-hostname": &gpb.SetResponse{},
}
for k, v := range gnmiMessages {
if err := proto.Read(k, v); err != nil {
log.Fatalf("error parsing %v: %v", k, err)
}
}
readTestUUIDs()
testSetupHTTP()
os.Exit(m.Run())
}
func readTestUUIDs() {
var err error
mdid, err = uuid.Parse("688a264e-5f85-40f8-bd13-afc42fcd5c7a")
defaultPndID, err = uuid.Parse("b4016412-eec5-45a1-aa29-f59915357bad")
cuid, err = uuid.Parse("3e8219b0-e926-400d-8660-217f2a25a7c6")
if err != nil {
log.Fatal(err)
}
}
func mockDevice() nucleus.Device {
sbi := &nucleus.OpenConfig{}
return nucleus.Device{
UUID: mdid,
GoStruct: sbi.Schema().Root,
SBI: sbi,
Transport: &mocks.Transport{},
}
}
package pnd package nucleus
import ( import (
"errors" "errors"
"os"
"sync"
"time"
"github.com/google/uuid" "github.com/google/uuid"
"github.com/openconfig/ygot/ygot" "github.com/openconfig/ygot/ygot"
log "github.com/sirupsen/logrus" log "github.com/sirupsen/logrus"
"golang.org/x/net/context" "golang.org/x/net/context"
"os"
"sync"
"time"
) )
var changeTimeout time.Duration var changeTimeout time.Duration
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please register or to comment