diff --git a/Programming.md b/Programming.md deleted file mode 100644 index 1f2cfa542ff47e019dac01647d0c5da8cca1f72a..0000000000000000000000000000000000000000 --- a/Programming.md +++ /dev/null @@ -1,33 +0,0 @@ -# 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 - diff --git a/build/cd/deploy.go b/build/cd/deploy.go index 7f61e2db03aa957787167eb5112399771b6b33d9..85bbeee80f276f8a9428e71eff125a0e14f60dbd 100644 --- a/build/cd/deploy.go +++ b/build/cd/deploy.go @@ -4,7 +4,7 @@ import ( "context" "os" - "code.fbi.h-da.de/cocsn/gosdn/nucleus" + nucleus "code.fbi.h-da.de/cocsn/gosdn/nucleus/errors" log "github.com/sirupsen/logrus" appv1 "k8s.io/api/apps/v1" corev1 "k8s.io/api/core/v1" diff --git a/build/ci/.golangci-config/.golangci.yml b/build/ci/.golangci-config/.golangci.yml index a25219bf493cf95a8d43c16df09d72bc3479b83c..17861c02518faca8181ceef7fc03b3115922ae6a 100644 --- a/build/ci/.golangci-config/.golangci.yml +++ b/build/ci/.golangci-config/.golangci.yml @@ -7,7 +7,7 @@ run: - test skip-dirs-default: true skip-files: - - nucleus/http.go + - http.go # output settings -> code-climate for GitLab output: format: code-climate diff --git a/build/ci/.test.yml b/build/ci/.test.yml index dd4f07a0a70490c2ce539a91081ad3c196d73f3e..e4209b3bb7773f44ee961cfd6379ad9554645963 100644 --- a/build/ci/.test.yml +++ b/build/ci/.test.yml @@ -44,6 +44,5 @@ unit-test: controller-test: script: - - cd ./nucleus - go test -race -v -run TestRun <<: *test \ No newline at end of file diff --git a/cli/get.go b/cli/get.go index 23406cde6824ef4915c76dfaee510543c2634e12..9b21ed48f24b7d256014cadf0cd50f3ab98f312f 100644 --- a/cli/get.go +++ b/cli/get.go @@ -3,6 +3,8 @@ 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" @@ -32,7 +34,7 @@ func Get(a, u, p string, args ...string) (*gpb.GetResponse, error) { log.Debug(resp) r, ok := resp.(*gpb.GetResponse) if !ok { - return nil, &nucleus.ErrInvalidTypeAssertion{} + return nil, &errors.ErrInvalidTypeAssertion{} } return r, nil } diff --git a/cli/subscribe.go b/cli/subscribe.go index ba56bf9cb6a42f20dcc27d955af7ab77d2169748..284a74d89de56df7c667fd813b4ecd7ef92037f7 100644 --- a/cli/subscribe.go +++ b/cli/subscribe.go @@ -8,6 +8,8 @@ import ( "syscall" "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/nucleus" gpb "github.com/openconfig/gnmi/proto/gnmi" @@ -48,7 +50,7 @@ func Subscribe(a, u, p string, sample, heartbeat int64, args ...string) error { } done := make(chan os.Signal, 1) 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() { if err := device.Transport.Subscribe(ctx); err != nil { log.Fatal(err) diff --git a/cmd/root.go b/cmd/root.go index 61b1e153fba0a4294eb7a18ff2538186739d5143..6cd3ea8457455237f38a789131cf59c25f87ab3b 100644 --- a/cmd/root.go +++ b/cmd/root.go @@ -35,7 +35,8 @@ import ( "context" "os" - "code.fbi.h-da.de/cocsn/gosdn/nucleus" + "code.fbi.h-da.de/cocsn/gosdn" + log "github.com/sirupsen/logrus" "github.com/spf13/cobra" @@ -60,7 +61,7 @@ for REST API calls.`, RunE: func(cmd *cobra.Command, args []string) error { ctx, cancel := context.WithCancel(context.Background()) defer cancel() - return nucleus.Run(ctx) + return gosdn.Run(ctx) }, } diff --git a/nucleus/controller.go b/controller.go similarity index 78% rename from nucleus/controller.go rename to controller.go index accd0b8885711474e714c0e3c38e462f27a832e5..9500225308f97fcddf863d0ee8b3decb417fbcb0 100644 --- a/nucleus/controller.go +++ b/controller.go @@ -1,4 +1,4 @@ -package nucleus +package gosdn import ( "context" @@ -8,7 +8,10 @@ import ( "sync" "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" ) @@ -21,8 +24,8 @@ type Core struct { // deprecated database database.Database - pndc pndStore - sbic sbiStore + pndc *nucleus.PndStore + sbic *nucleus.SbiStore httpServer *http.Server stopChan chan os.Signal } @@ -32,8 +35,8 @@ var c *Core func init() { c = &Core{ database: database.Database{}, - pndc: pndStore{store{}}, - sbic: sbiStore{store{}}, + pndc: nucleus.NewPndStore(), + sbic: nucleus.NewSbiStore(), stopChan: make(chan os.Signal, 1), } @@ -50,25 +53,26 @@ func initialize() error { // TODO: Start grpc listener here coreLock.Lock() defer coreLock.Unlock() - return httpAPI() + startHttpServer() + return nil } // createSouthboundInterfaces initializes the controller with its supported SBIs func createSouthboundInterfaces() error { - sbi := &OpenConfig{id: uuid.New()} - if err := c.sbic.add(sbi); err != nil { + sbi := nucleus.NewSBI(types.Openconfig) + if err := c.sbic.Add(sbi); err != nil { return err } return createPrincipalNetworkDomain(sbi) } // createPrincipalNetworkDomain initializes the controller with an initial PND -func createPrincipalNetworkDomain(sbi SouthboundInterface) error { - pnd, err := NewPND("base", "gosdn base pnd", uuid.New(), sbi) +func createPrincipalNetworkDomain(s nucleus.SouthboundInterface) error { + pnd, err := nucleus.NewPND("base", "gosdn base pnd", uuid.New(), s) if err != nil { return err } - err = c.pndc.add(pnd) + err = c.pndc.Add(pnd) if err != nil { return err } diff --git a/nucleus/controller_test.go b/controller_test.go similarity index 98% rename from nucleus/controller_test.go rename to controller_test.go index 1dc5b8bd001270ace098c39a81e027263df7869c..27546454382200f60e86a664c185d4871a1ce8b2 100644 --- a/nucleus/controller_test.go +++ b/controller_test.go @@ -1,4 +1,4 @@ -package nucleus +package gosdn import ( "context" diff --git a/gosdn.png b/gosdn.png deleted file mode 100644 index b16c83696fe11f6b983da0bf923457ecf59add8d..0000000000000000000000000000000000000000 Binary files a/gosdn.png and /dev/null differ diff --git a/gosdn.puml b/gosdn.puml deleted file mode 100644 index 1dc2379006cdef8990adf2f73dc4fe5ddd414c51..0000000000000000000000000000000000000000 --- a/gosdn.puml +++ /dev/null @@ -1,118 +0,0 @@ -@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 diff --git a/nucleus/http.go b/http.go similarity index 76% rename from nucleus/http.go rename to http.go index ee0590e4e5645ff665417c9be7ec3d6b1542d220..92ce1890a2a0d5585d0093f6614fa727d919184c 100644 --- a/nucleus/http.go +++ b/http.go @@ -1,7 +1,10 @@ -package nucleus +package gosdn import ( "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" "context" "fmt" "github.com/google/uuid" @@ -13,10 +16,10 @@ import ( "time" ) -var apiOpmap = map[string]Operation{ - "update": TransportUpdate, - "replace": TransportReplace, - "delete": TransportDelete, +var apiOpmap = map[string]types.Operation{ + "update": types.TransportUpdate, + "replace": types.TransportReplace, + "delete": types.TransportDelete, } func stopHttpServer() error { @@ -32,19 +35,17 @@ func registerHttpHandler() { fmt.Println("Recovered in f", r) } }() - http.HandleFunc("/api", httpHandler) + http.HandleFunc("/api", httpApi) http.HandleFunc("/livez", healthCheck) http.HandleFunc("/readyz", readynessCheck) } -// deprecated -func httpAPI() error { +func startHttpServer() { registerHttpHandler() c.httpServer = &http.Server{Addr: ":8080"} go func() { log.Info(c.httpServer.ListenAndServe()) }() - return nil } func healthCheck(writer http.ResponseWriter, request *http.Request) { @@ -55,8 +56,9 @@ func readynessCheck(writer http.ResponseWriter, request *http.Request) { writer.WriteHeader(http.StatusOK) } +// deprecated // nolint -func httpHandler(writer http.ResponseWriter, request *http.Request) { +func httpApi(writer http.ResponseWriter, request *http.Request) { log.WithFields(log.Fields{ "request": request, }).Debug("incoming request") @@ -89,16 +91,16 @@ func httpHandler(writer http.ResponseWriter, request *http.Request) { } } - var pnd PrincipalNetworkDomain - var sbi SouthboundInterface + var httpPnd nucleus.PrincipalNetworkDomain + var httpSbi nucleus.SouthboundInterface if query.Get("q") != "init" && query.Get("q") != "getIDs" { - pnd, err = c.pndc.get(pid) + httpPnd, err = c.pndc.Get(pid) if err != nil { handleServerError(writer, err) return } - sbic := pnd.GetSBIs() - sbi, err = sbic.(*sbiStore).get(sid) + sbic := httpPnd.GetSBIs() + httpSbi, err = sbic.(*nucleus.SbiStore).Get(sid) if err != nil { handleServerError(writer, err) return @@ -107,18 +109,18 @@ func httpHandler(writer http.ResponseWriter, request *http.Request) { switch q := query.Get("q"); q { case "addDevice": - d, err := NewDevice(sbi, &GnmiTransportOptions{ + d, err := nucleus.NewDevice(httpSbi, &nucleus.GnmiTransportOptions{ Config: gnmi.Config{ Addr: query.Get("address"), Password: query.Get("password"), Username: query.Get("username"), Encoding: gpb.Encoding_JSON_IETF, }, - SetNode: sbi.SetNode(), - Unmarshal: sbi.(*OpenConfig).Unmarshal(), + SetNode: httpSbi.SetNode(), + Unmarshal: httpSbi.(*nucleus.OpenConfig).Unmarshal(), RespChan: make(chan *gpb.SubscribeResponse), }) - err = pnd.AddDevice(d) + err = httpPnd.AddDevice(d) if err != nil { writer.WriteHeader(http.StatusInternalServerError) log.Error(err) @@ -128,10 +130,10 @@ func httpHandler(writer http.ResponseWriter, request *http.Request) { fmt.Fprintf(writer, "device added\n") fmt.Fprintf(writer, "UUID: %v\n", d.UUID) case "request": - err = pnd.Request(id, query.Get("path")) + err = httpPnd.Request(id, query.Get("path")) if err != nil { switch err.(type) { - case *ErrNotFound: + case *errors.ErrNotFound: writer.WriteHeader(http.StatusNotFound) default: writer.WriteHeader(http.StatusInternalServerError) @@ -141,10 +143,10 @@ func httpHandler(writer http.ResponseWriter, request *http.Request) { } writer.WriteHeader(http.StatusOK) case "requestAll": - err = pnd.RequestAll(query.Get("path")) + err = httpPnd.RequestAll(query.Get("path")) if err != nil { switch err.(type) { - case *ErrNotFound: + case *errors.ErrNotFound: writer.WriteHeader(http.StatusNotFound) default: writer.WriteHeader(http.StatusInternalServerError) @@ -154,10 +156,10 @@ func httpHandler(writer http.ResponseWriter, request *http.Request) { } writer.WriteHeader(http.StatusOK) case "getDevice": - device, err := pnd.MarshalDevice(id) + device, err := httpPnd.MarshalDevice(id) if err != nil { switch err.(type) { - case *ErrNotFound: + case *errors.ErrNotFound: writer.WriteHeader(http.StatusNotFound) default: writer.WriteHeader(http.StatusInternalServerError) @@ -173,7 +175,7 @@ func httpHandler(writer http.ResponseWriter, request *http.Request) { writeIDs(writer, "PNDs", pnds) writeIDs(writer, "SBIs", c.sbic.UUIDs()) for _, id := range pnds { - p, err := c.pndc.get(id) + p, err := c.pndc.Get(id) if err != nil { handleServerError(writer, err) return @@ -184,22 +186,22 @@ func httpHandler(writer http.ResponseWriter, request *http.Request) { writeIDs(writer, "PNDs", c.pndc.UUIDs()) writeIDs(writer, "SBIs", c.sbic.UUIDs()) 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) return } writer.WriteHeader(http.StatusOK) 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) return } writer.WriteHeader(http.StatusOK) case "change-list": - changes := pnd.Committed() + changes := httpPnd.Committed() writeIDs(writer, "Tentative changes", changes) case "change-list-pending": - changes := pnd.Pending() + changes := httpPnd.Pending() writeIDs(writer, "Pending changes", changes) case "change-commit": cuid, err := uuid.Parse(query.Get("cuid")) @@ -207,7 +209,7 @@ func httpHandler(writer http.ResponseWriter, request *http.Request) { handleServerError(writer, err) return } - if err := pnd.Commit(cuid); err != nil { + if err := httpPnd.Commit(cuid); err != nil { handleServerError(writer, err) return } @@ -218,7 +220,7 @@ func httpHandler(writer http.ResponseWriter, request *http.Request) { handleServerError(writer, err) return } - if err := pnd.Confirm(cuid); err != nil { + if err := httpPnd.Confirm(cuid); err != nil { handleServerError(writer, err) return } diff --git a/nucleus/http_test.go b/http_test.go similarity index 93% rename from nucleus/http_test.go rename to http_test.go index 49405d29d40da981b9fccc159430654a3f75d77f..47a7a3e12ecc20da64c1f5476ea938d6783c44d7 100644 --- a/nucleus/http_test.go +++ b/http_test.go @@ -1,21 +1,25 @@ -package nucleus +package gosdn import ( "errors" "net/http" "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/nucleus" "github.com/google/uuid" log "github.com/sirupsen/logrus" "github.com/stretchr/testify/mock" ) func testSetupHTTP() { - sbi = &OpenConfig{id: defaultSbiID} + sbi = nucleus.NewSBI(types.Openconfig) sbi.Schema() + defaultSbiID = sbi.ID() var err error - httpTestPND, err = NewPND("test", "test pnd", defaultPndID, sbi) + httpTestPND, err = nucleus.NewPND("test", "test pnd", defaultPndID, sbi) if err != nil { log.Fatal(err) } @@ -31,10 +35,10 @@ func testSetupHTTP() { } args = "&uuid=" + mdid.String() + "&pnd=" + defaultPndID.String() + "&sbi=" + defaultSbiID.String() argsNotFound = "&uuid=" + 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) } - if err := c.pndc.add(httpTestPND); err != nil { + if err := c.pndc.Add(httpTestPND); err != nil { log.Fatal(err) } } @@ -183,10 +187,7 @@ func Test_httpApi(t *testing.T) { }, } coreLock.Lock() - if err := httpAPI(); err != nil { - t.Errorf("httpApi() error = %v", err) - return - } + startHttpServer() coreLock.Unlock() for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { @@ -199,7 +200,7 @@ func Test_httpApi(t *testing.T) { t.Errorf("httpApi() got: %v, want %v", got.StatusCode, tt.want.StatusCode) } if tt.name == "add-device" { - for k := range httpTestPND.(*pndImplementation).devices.store { + for _, k := range httpTestPND.Devices() { if k != mdid { if err := httpTestPND.RemoveDevice(k); err != nil { t.Error(err) diff --git a/initialise_test.go b/initialise_test.go new file mode 100644 index 0000000000000000000000000000000000000000..5fbb298a7aa6a4cbc30aff8a80695aa1647eb34a --- /dev/null +++ b/initialise_test.go @@ -0,0 +1,88 @@ +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 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{}, + } +} diff --git a/nucleus/pnd/change.go b/nucleus/change.go similarity index 99% rename from nucleus/pnd/change.go rename to nucleus/change.go index a6e550c9cf52786cfe9d507d216ba57d3b9af773..a8743b1abfc63efbc5c3cbcb7c3e8dd7dcc2f628 100644 --- a/nucleus/pnd/change.go +++ b/nucleus/change.go @@ -1,4 +1,4 @@ -package pnd +package nucleus import ( "errors" diff --git a/nucleus/pnd/change_test.go b/nucleus/change_test.go similarity index 96% rename from nucleus/pnd/change_test.go rename to nucleus/change_test.go index 71f648557214b91c4c5ee059943954883725367b..b58598b33356c9ce8fae3e032afb78c5b1441f96 100644 --- a/nucleus/pnd/change_test.go +++ b/nucleus/change_test.go @@ -1,4 +1,4 @@ -package pnd +package nucleus import ( "context" @@ -33,7 +33,7 @@ func TestChange_CommitRollback(t *testing.T) { want := rollback callback := make(chan string) c := &Change{ - cuid: changeUUID, + cuid: cuid, duid: did, timestamp: time.Now(), previousState: rollbackDevice, @@ -67,7 +67,7 @@ func TestChange_CommitRollbackError(t *testing.T) { wantErr := false want := errors.New("this is an expected error") c := &Change{ - cuid: changeUUID, + cuid: cuid, duid: did, timestamp: time.Now(), previousState: rollbackDevice, @@ -101,7 +101,7 @@ func TestChange_CommitRollbackError(t *testing.T) { func TestChange_CommitError(t *testing.T) { wantErr := true c := &Change{ - cuid: changeUUID, + cuid: cuid, duid: did, timestamp: time.Now(), previousState: rollbackDevice, @@ -129,7 +129,7 @@ func TestChange_Commit(t *testing.T) { callback := make(chan string) c := &Change{ - cuid: changeUUID, + cuid: cuid, duid: did, timestamp: time.Now(), previousState: rollbackDevice, @@ -228,8 +228,8 @@ func TestChange_ID(t *testing.T) { }{ { name: "default", - fields: fields{cuid: changeUUID}, - want: changeUUID, + fields: fields{cuid: cuid}, + want: cuid, }, } for _, tt := range tests { diff --git a/nucleus/device.go b/nucleus/device.go index 4318f72420a10e61aa36f1bc7680452e0f640ff9..0c03706fc2c1866784b58d9689b25283f70f5465 100644 --- a/nucleus/device.go +++ b/nucleus/device.go @@ -1,6 +1,7 @@ package nucleus import ( + "code.fbi.h-da.de/cocsn/gosdn/nucleus/errors" "github.com/google/uuid" "github.com/openconfig/ygot/ygot" ) @@ -25,14 +26,14 @@ type Device struct { func NewDevice(sbi SouthboundInterface, opts TransportOptions) (*Device, error) { var transport Transport var err error - switch opts.(type) { + switch o := opts.(type) { case *GnmiTransportOptions: - transport, err = NewGnmiTransport(opts.(*GnmiTransportOptions)) + transport, err = NewGnmiTransport(o) if err != nil { return nil, err } default: - return nil, &ErrInvalidTransportOptions{opts} + return nil, &errors.ErrInvalidTransportOptions{Opt: o} } return &Device{ diff --git a/nucleus/errors.go b/nucleus/errors/errors.go similarity index 82% rename from nucleus/errors.go rename to nucleus/errors/errors.go index 7466b3ec10d37bf51b5f5605643882c359664f74..3aad202118e0bceb2b4e91dd34ce075c1ed454e5 100644 --- a/nucleus/errors.go +++ b/nucleus/errors/errors.go @@ -1,4 +1,4 @@ -package nucleus +package errors import ( "fmt" @@ -24,42 +24,42 @@ func (e *ErrNil) Error() string { // ErrNotFound implements the Error interface and is called if a specific ID // of a storable item could not be found. type ErrNotFound struct { - id interface{} + ID interface{} } func (e *ErrNotFound) Error() string { - return fmt.Sprintf("%v not found", e.id) + return fmt.Sprintf("%v not found", e.ID) } // ErrAlreadyExists implements the Error interface and is called if a specific ID // of a storable item already exists. type ErrAlreadyExists struct { - item interface{} + Item interface{} } func (e *ErrAlreadyExists) Error() string { - return fmt.Sprintf("%v already exists", e.item) + return fmt.Sprintf("%v already exists", e.Item) } // ErrInvalidTypeAssertion implements the Error interface and is called if the // type of a storable item does not correspond to the expected type. type ErrInvalidTypeAssertion struct { - v interface{} - t interface{} + Value interface{} + Type interface{} } func (e ErrInvalidTypeAssertion) Error() string { - return fmt.Sprintf("%v does not implement %v", e.v, e.t) + return fmt.Sprintf("%v does not implement %v", e.Value, e.Type) } // ErrUnsupportedPath implements the Error interface and is called if the // given path is not supported. type ErrUnsupportedPath struct { - p interface{} + Path interface{} } func (e ErrUnsupportedPath) Error() string { - return fmt.Sprintf("path %v is not supported", e.p) + return fmt.Sprintf("path %v is not supported", e.Path) } // ErrNotYetImplemented implements the Error interface and is called if a function @@ -73,30 +73,30 @@ func (e ErrNotYetImplemented) Error() string { // ErrInvalidParameters implements the Error interface and is called if the wrong // or no parameters have been provided. type ErrInvalidParameters struct { - f interface{} - r interface{} + Func interface{} + Param interface{} } func (e ErrInvalidParameters) Error() string { - return fmt.Sprintf("invalid parameters for %v: %v", e.f, e.r) + return fmt.Sprintf("invalid parameters for %v: %v", e.Func, e.Param) } // ErrInvalidTransportOptions implements the Error interface and is called if the // wrong TransportOptions have been provided. type ErrInvalidTransportOptions struct { - t interface{} + Opt interface{} } func (e ErrInvalidTransportOptions) Error() string { - return fmt.Sprintf("invalid transport options: %v", reflect.TypeOf(e.t)) + return fmt.Sprintf("invalid transport options: %v", reflect.TypeOf(e.Opt)) } // ErrOperationNotSupported implements the Error interface and is called if the // wrong Operation has been provided. type ErrOperationNotSupported struct { - o interface{} + Op interface{} } func (e ErrOperationNotSupported) Error() string { - return fmt.Sprintf("transport operation not supported: %v", reflect.TypeOf(e.o)) + return fmt.Sprintf("transport operation not supported: %v", reflect.TypeOf(e.Op)) } diff --git a/nucleus/gnmi_transport.go b/nucleus/gnmi_transport.go index fb0c18f6f11bf3a01fe42ce4f46e18f92e3fb7c5..d5f7c369d40eb384de23049ea771e474d7d0a7fe 100644 --- a/nucleus/gnmi_transport.go +++ b/nucleus/gnmi_transport.go @@ -5,6 +5,8 @@ import ( "reflect" "code.fbi.h-da.de/cocsn/gosdn/forks/goarista/gnmi" + "code.fbi.h-da.de/cocsn/gosdn/nucleus/errors" + "code.fbi.h-da.de/cocsn/gosdn/nucleus/types" pathutils "code.fbi.h-da.de/cocsn/gosdn/nucleus/util/path" gpb "github.com/openconfig/gnmi/proto/gnmi" "github.com/openconfig/gnmi/proto/gnmi_ext" @@ -14,25 +16,10 @@ import ( log "github.com/sirupsen/logrus" ) -// CtxKeyType is a custom type to be used as key in a context.WithValue() or -// context.Value() call. For more information see: -// https://www.calhoun.io/pitfalls-of-context-values-and-how-to-avoid-or-mitigate-them/ -// TODO: Unexport to comply with best practice -type CtxKeyType string - -const ( - // CtxKeyOpts context key for gnmi.SubscribeOptions - CtxKeyOpts CtxKeyType = "opts" - // CtxKeyConfig is a context key for gnmi.Config - CtxKeyConfig = "config" - // CtxKeyOperation is a context key for a gNMI operation (update, replace, delete) - CtxKeyOperation = "op" -) - -var opmap = map[Operation]string{ - TransportUpdate: "update", - TransportReplace: "replace", - TransportDelete: "delete", +var opmap = map[types.Operation]string{ + types.TransportUpdate: "update", + types.TransportReplace: "replace", + types.TransportDelete: "delete", } // Gnmi implements the Transport interface and provides an SBI with the @@ -78,7 +65,7 @@ func (g *Gnmi) GetOptions() interface{} { // Get takes a slice of gnmi paths, splits them and calls get for each one of them. func (g *Gnmi) Get(ctx context.Context, params ...string) (interface{}, error) { if g.client == nil { - return nil, &ErrNilClient{} + return nil, &errors.ErrNilClient{} } paths := gnmi.SplitPaths(params) return g.get(ctx, paths, "") @@ -88,12 +75,12 @@ func (g *Gnmi) Get(ctx context.Context, params ...string) (interface{}, error) { // It can contain an additional arbitrary amount of operations and extensions. func (g *Gnmi) Set(ctx context.Context, args ...interface{}) error { if g.client == nil { - return &ErrNilClient{} + return &errors.ErrNilClient{} } if len(args) == 0 { - return &ErrInvalidParameters{ - f: "gnmi.Set()", - r: "no parameters provided", + return &errors.ErrInvalidParameters{ + Func: "gnmi.Set()", + Param: "no parameters provided", } } @@ -110,19 +97,19 @@ func (g *Gnmi) Set(ctx context.Context, args ...interface{}) error { for _, o := range args { attrs, ok := o.([]string) if !ok { - return &ErrInvalidTypeAssertion{ - v: o, - t: reflect.TypeOf("placeholder"), + return &errors.ErrInvalidTypeAssertion{ + Value: o, + Type: reflect.TypeOf("placeholder"), } } else if attrs == nil || len(attrs) == 0 { - return &ErrInvalidParameters{ - f: "gnmi.Set()", - r: "no parameters provided", + return &errors.ErrInvalidParameters{ + Func: "gnmi.Set()", + Param: "no parameters provided", } } opts = append(opts, &gnmi.Operation{ // Hardcoded TransportUpdate until multiple operations are supported - Type: opmap[TransportUpdate], + Type: opmap[types.TransportUpdate], Origin: "", Target: "", Path: gnmi.SplitPath(attrs[0]), @@ -145,16 +132,16 @@ func (g *Gnmi) Set(ctx context.Context, args ...interface{}) error { case *gnmi_ext.Extension: exts = append(exts, p.(*gnmi_ext.Extension)) default: - return &ErrInvalidParameters{ - f: "gnmi.Set()", - r: "args contain invalid type", + return &errors.ErrInvalidParameters{ + Func: "gnmi.Set()", + Param: "args contain invalid type", } } } if len(ops) == 0 { - return &ErrInvalidParameters{ - f: "gnmi.Set()", - r: "no operations provided", + return &errors.ErrInvalidParameters{ + Func: "gnmi.Set()", + Param: "no operations provided", } } resp, err := g.set(ctx, ops, exts...) @@ -167,21 +154,21 @@ func (g *Gnmi) Set(ctx context.Context, args ...interface{}) error { func (g *Gnmi) applyDiff(ctx context.Context, payload ...interface{}) error { if len(payload) != 2 { - return &ErrInvalidParameters{} + return &errors.ErrInvalidParameters{} } - op := ctx.Value(CtxKeyOperation) + op := ctx.Value(types.CtxKeyOperation) oldstate, ok := payload[0].(ygot.GoStruct) if !ok { - return &ErrInvalidTypeAssertion{ - v: payload[0], - t: reflect.TypeOf("ygot.GoStruct"), + return &errors.ErrInvalidTypeAssertion{ + Value: payload[0], + Type: reflect.TypeOf("ygot.GoStruct"), } } newstate, ok := payload[1].(ygot.GoStruct) if !ok { - return &ErrInvalidTypeAssertion{ - v: payload[1], - t: reflect.TypeOf("ygot.GoStruct"), + return &errors.ErrInvalidTypeAssertion{ + Value: payload[1], + Type: reflect.TypeOf("ygot.GoStruct"), } } @@ -192,12 +179,12 @@ func (g *Gnmi) applyDiff(ctx context.Context, payload ...interface{}) error { req := &gpb.SetRequest{} if diff.Update != nil { switch op { - case TransportUpdate: + case types.TransportUpdate: req.Update = diff.Update - case TransportReplace: + case types.TransportReplace: req.Replace = diff.Update default: - return &ErrOperationNotSupported{} + return &errors.ErrOperationNotSupported{} } } else if diff.Delete != nil { req.Delete = diff.Delete @@ -210,7 +197,7 @@ func (g *Gnmi) applyDiff(ctx context.Context, payload ...interface{}) error { //Subscribe subscribes to a gNMI target func (g *Gnmi) Subscribe(ctx context.Context, params ...string) error { if g.client == nil { - return &ErrNilClient{} + return &errors.ErrNilClient{} } return g.subscribe(ctx) } @@ -254,7 +241,7 @@ func (g *Gnmi) Capabilities(ctx context.Context) (interface{}, error) { "target": g.Options.Addr, }).Info("sending gNMI capabilities request") ctx = gnmi.NewContext(ctx, &g.Options.Config) - ctx = context.WithValue(ctx, CtxKeyConfig, &g.Options.Config) //nolint + ctx = context.WithValue(ctx, types.CtxKeyConfig, &g.Options.Config) //nolint resp, err := g.client.Capabilities(ctx, &gpb.CapabilityRequest{}) if err != nil { return nil, err @@ -266,7 +253,7 @@ func (g *Gnmi) Capabilities(ctx context.Context) (interface{}, error) { func (g *Gnmi) get(ctx context.Context, paths [][]string, origin string) (interface{}, error) { ctx = gnmi.NewContext(ctx, &g.Options.Config) - ctx = context.WithValue(ctx, CtxKeyConfig, &g.Options.Config) //nolint + ctx = context.WithValue(ctx, types.CtxKeyConfig, &g.Options.Config) //nolint req, err := gnmi.NewGetRequest(ctx, paths, origin) if err != nil { return nil, err @@ -278,7 +265,7 @@ func (g *Gnmi) get(ctx context.Context, paths [][]string, origin string) (interf // and returns any response. func (g *Gnmi) getWithRequest(ctx context.Context, req *gpb.GetRequest) (interface{}, error) { if req == nil { - return nil, &ErrNil{} + return nil, &errors.ErrNil{} } log.WithFields(log.Fields{ "target": g.Options.Addr, @@ -315,11 +302,11 @@ func (g *Gnmi) set(ctx context.Context, setOps []*gnmi.Operation, // Subscribe calls GNMI subscribe func (g *Gnmi) subscribe(ctx context.Context) error { ctx = gnmi.NewContext(ctx, &g.Options.Config) - opts, ok := ctx.Value(CtxKeyOpts).(*gnmi.SubscribeOptions) + opts, ok := ctx.Value(types.CtxKeyOpts).(*gnmi.SubscribeOptions) if !ok { - return &ErrInvalidTypeAssertion{ - v: reflect.TypeOf(ctx.Value(CtxKeyOpts)), - t: reflect.TypeOf(&gnmi.SubscribeOptions{}), + return &errors.ErrInvalidTypeAssertion{ + Value: reflect.TypeOf(ctx.Value(types.CtxKeyOpts)), + Type: reflect.TypeOf(&gnmi.SubscribeOptions{}), } } go func() { diff --git a/nucleus/initialise_test.go b/nucleus/initialise_test.go index 4cb53d136315b294ac680ec6c81e760a964b7407..85b938a0d14aa442c196e020b9f413b8095bb9bb 100644 --- a/nucleus/initialise_test.go +++ b/nucleus/initialise_test.go @@ -16,8 +16,6 @@ import ( pb "google.golang.org/protobuf/proto" ) -const apiEndpoint = "http://localhost:8080" - // UUIDs for test cases var did uuid.UUID var mdid uuid.UUID @@ -28,16 +26,11 @@ var iid uuid.UUID var altIid uuid.UUID var cuid uuid.UUID -var sbi SouthboundInterface -var httpTestPND PrincipalNetworkDomain var gnmiMessages map[string]pb.Message var gnmiConfig *gnmi.Config -var httpTestDevice Device var startGnmiTarget chan string var stopGnmiTarget chan bool -var args string -var argsNotFound string var mockContext = mock.MatchedBy(func(ctx context.Context) bool { return true }) @@ -72,7 +65,6 @@ func TestMain(m *testing.M) { readTestUUIDs() testSetupGnmi() - testSetupHTTP() os.Exit(m.Run()) } @@ -136,11 +128,11 @@ func newPnd() pndImplementation { return pndImplementation{ name: "default", description: "default test pnd", - sbic: sbiStore{store{}}, - devices: deviceStore{store{}}, - pendingChanges: changeStore{store{}}, - committedChanges: changeStore{store{}}, - confirmedChanges: changeStore{store{}}, + sbic: SbiStore{store{}}, + devices: DeviceStore{store{}}, + pendingChanges: ChangeStore{store{}}, + committedChanges: ChangeStore{store{}}, + confirmedChanges: ChangeStore{store{}}, id: defaultPndID, errChans: make(map[uuid.UUID]chan error), } diff --git a/nucleus/pnd/initialise_test.go b/nucleus/pnd/initialise_test.go deleted file mode 100644 index 7451bd565d99f38a5b23abae7bc93fbb4d001503..0000000000000000000000000000000000000000 --- a/nucleus/pnd/initialise_test.go +++ /dev/null @@ -1,23 +0,0 @@ -package pnd - -import ( - "os" - "testing" - - "github.com/google/uuid" - log "github.com/sirupsen/logrus" -) - -// UUIDs for test cases -var changeUUID uuid.UUID -var did uuid.UUID - -func TestMain(m *testing.M) { - var err error - changeUUID, err = uuid.Parse("cfbb96cd-ecad-45d1-bebf-1851760f5087") - did, err = uuid.Parse("4d8246f8-e884-41d6-87f5-c2c784df9e44") - if err != nil { - log.Fatal(err) - } - os.Exit(m.Run()) -} diff --git a/nucleus/principalNetworkDomain.go b/nucleus/principalNetworkDomain.go index 375801125282b51c494b637165ab944918a1be44..e3d535d81d7dfee3557f6ce2f7d7bdd94ab7f6f1 100644 --- a/nucleus/principalNetworkDomain.go +++ b/nucleus/principalNetworkDomain.go @@ -3,8 +3,10 @@ package nucleus import ( "context" + "code.fbi.h-da.de/cocsn/gosdn/nucleus/errors" + "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/nucleus/pnd" //nolint "github.com/openconfig/ygot/ygot" "github.com/openconfig/ygot/ytypes" log "github.com/sirupsen/logrus" @@ -44,15 +46,15 @@ func NewPND(name, description string, id uuid.UUID, sbi SouthboundInterface) (Pr pnd := &pndImplementation{ name: name, description: description, - sbic: sbiStore{store{}}, - devices: deviceStore{store{}}, - pendingChanges: changeStore{store{}}, - committedChanges: changeStore{store{}}, - confirmedChanges: changeStore{store{}}, + sbic: SbiStore{store{}}, + devices: DeviceStore{store{}}, + pendingChanges: ChangeStore{store{}}, + committedChanges: ChangeStore{store{}}, + confirmedChanges: ChangeStore{store{}}, id: id, errChans: make(map[uuid.UUID]chan error), } - if err := pnd.sbic.add(sbi); err != nil { + if err := pnd.sbic.Add(sbi); err != nil { return nil, err } return pnd, nil @@ -61,11 +63,11 @@ func NewPND(name, description string, id uuid.UUID, sbi SouthboundInterface) (Pr type pndImplementation struct { name string description string - sbic sbiStore - devices deviceStore - pendingChanges changeStore - committedChanges changeStore - confirmedChanges changeStore + sbic SbiStore + devices DeviceStore + pendingChanges ChangeStore + committedChanges ChangeStore + confirmedChanges ChangeStore id uuid.UUID errChans map[uuid.UUID]chan error } @@ -79,7 +81,7 @@ func (pnd *pndImplementation) Committed() []uuid.UUID { } func (pnd *pndImplementation) Commit(u uuid.UUID) error { - change, err := pnd.pendingChanges.get(u) + change, err := pnd.pendingChanges.Get(u) if err != nil { return err } @@ -97,24 +99,24 @@ func (pnd *pndImplementation) Commit(u uuid.UUID) error { } } }() - if err := pnd.committedChanges.add(change); err != nil { + if err := pnd.committedChanges.Add(change); err != nil { return err } - return pnd.pendingChanges.delete(u) + return pnd.pendingChanges.Delete(u) } func (pnd *pndImplementation) Confirm(u uuid.UUID) error { - change, err := pnd.committedChanges.get(u) + change, err := pnd.committedChanges.Get(u) if err != nil { return err } if err := change.Confirm(); err != nil { return err } - if err := pnd.confirmedChanges.add(change); err != nil { + if err := pnd.confirmedChanges.Add(change); err != nil { return err } - return pnd.committedChanges.delete(u) + return pnd.committedChanges.Delete(u) } func (pnd *pndImplementation) ID() uuid.UUID { @@ -132,7 +134,7 @@ func (pnd *pndImplementation) GetName() string { // ContainsDevice checks if the given device uuid is registered for this PND func (pnd *pndImplementation) ContainsDevice(id uuid.UUID) bool { - return pnd.devices.exists(id) + return pnd.devices.Exists(id) } // GetDescription returns the current description of the PND @@ -154,9 +156,9 @@ func (pnd *pndImplementation) Destroy() error { func (pnd *pndImplementation) AddSbi(sbi interface{}) error { s, ok := sbi.(SouthboundInterface) if !ok { - return &ErrInvalidTypeAssertion{ - v: sbi, - t: "Device", + return &errors.ErrInvalidTypeAssertion{ + Value: sbi, + Type: "Device", } } return pnd.addSbi(s) @@ -174,16 +176,16 @@ func (pnd *pndImplementation) RemoveSbi(id uuid.UUID) error { func (pnd *pndImplementation) AddDevice(device interface{}) error { d, ok := device.(*Device) if !ok { - return &ErrInvalidTypeAssertion{ - v: device, - t: "Device", + return &errors.ErrInvalidTypeAssertion{ + Value: device, + Type: "Device", } } return pnd.addDevice(d) } func (pnd *pndImplementation) GetDevice(uuid uuid.UUID) (ygot.GoStruct, error) { - d, err := pnd.devices.get(uuid) + d, err := pnd.devices.Get(uuid) if err != nil { return nil, err } @@ -202,23 +204,23 @@ func destroy() error { } func (pnd *pndImplementation) addSbi(sbi SouthboundInterface) error { - return pnd.sbic.add(sbi) + return pnd.sbic.Add(sbi) } func (pnd *pndImplementation) removeSbi(id uuid.UUID) error { - return pnd.sbic.delete(id) + return pnd.sbic.Delete(id) } func (pnd *pndImplementation) addDevice(device *Device) error { - return pnd.devices.add(device) + return pnd.devices.Add(device) } func (pnd *pndImplementation) getDevice(id uuid.UUID) (*Device, error) { - return pnd.devices.get(id) + return pnd.devices.Get(id) } func (pnd *pndImplementation) removeDevice(id uuid.UUID) error { - return pnd.devices.delete(id) + return pnd.devices.Delete(id) } func (pnd *pndImplementation) MarshalDevice(uuid uuid.UUID) (string, error) { @@ -283,25 +285,25 @@ func (pnd *pndImplementation) ChangeOND(uuid uuid.UUID, operation interface{}, p return err } - if operation != TransportDelete && len(value) != 1 { - return &ErrInvalidParameters{ - f: pnd.ChangeOND, - r: value, + if operation != types.TransportDelete && len(value) != 1 { + return &errors.ErrInvalidParameters{ + Func: pnd.ChangeOND, + Param: value, } } switch operation { - case TransportUpdate, TransportReplace: + case types.TransportUpdate, types.TransportReplace: typedValue := gnmi.TypedValue(value[0]) if err := ytypes.SetNode(d.SBI.Schema().RootSchema(), cpy, p, typedValue); err != nil { return err } - case TransportDelete: + case types.TransportDelete: if err := ytypes.DeleteNode(d.SBI.Schema().RootSchema(), cpy, p); err != nil { return err } default: - return &ErrOperationNotSupported{o: operation} + return &errors.ErrOperationNotSupported{Op: operation} } callback := func(state ygot.GoStruct, change ygot.GoStruct) error { @@ -313,7 +315,7 @@ func (pnd *pndImplementation) ChangeOND(uuid uuid.UUID, operation interface{}, p change := NewChange(uuid, d.GoStruct, cpy, callback, errChan) pnd.errChans[change.ID()] = errChan - return pnd.pendingChanges.add(change) + return pnd.pendingChanges.Add(change) } func handleRollbackError(id uuid.UUID, err error) { diff --git a/nucleus/principalNetworkDomain_test.go b/nucleus/principalNetworkDomain_test.go index 9daf8230a63a4a585580e65a5f348057837e1a0f..17d5c0a30232b69ec82e180fc2fa75706d3d66c5 100644 --- a/nucleus/principalNetworkDomain_test.go +++ b/nucleus/principalNetworkDomain_test.go @@ -5,6 +5,8 @@ import ( "reflect" "testing" + "code.fbi.h-da.de/cocsn/gosdn/nucleus/types" + "code.fbi.h-da.de/cocsn/gosdn/mocks" "code.fbi.h-da.de/cocsn/yang-models/generated/openconfig" "github.com/google/uuid" @@ -123,7 +125,7 @@ func Test_pndImplementation_AddDevice(t *testing.T) { t.Errorf("AddDevice() Device %v not in device store %v", tt.args.device, pnd.devices) } - if err := pnd.devices.delete(did); err != nil { + if err := pnd.devices.Delete(did); err != nil { t.Error(err) } } @@ -186,7 +188,7 @@ func Test_pndImplementation_AddSbi(t *testing.T) { t.Errorf("AddSbi() SBI %v not in device store %v", tt.args.sbi, pnd.GetSBIs()) } - if err := pnd.sbic.delete(defaultSbiID); err != nil { + if err := pnd.sbic.Delete(defaultSbiID); err != nil { t.Error(err) } } @@ -222,14 +224,14 @@ func Test_pndImplementation_ContainsDevice(t *testing.T) { t.Run(tt.name, func(t *testing.T) { pnd := newPnd() if tt.name != "fails empty" { - if err := pnd.devices.add(tt.args.device); err != nil { + if err := pnd.devices.Add(tt.args.device); err != nil { t.Error(err) } } if got := pnd.ContainsDevice(tt.args.uuid); got != tt.want { t.Errorf("ContainsDevice() = %v, want %v", got, tt.want) } - if err := pnd.devices.delete(did); err != nil && tt.name != "fails empty" { + if err := pnd.devices.Delete(did); err != nil && tt.name != "fails empty" { t.Error(err) } }) @@ -240,8 +242,8 @@ func Test_pndImplementation_Destroy(t *testing.T) { type fields struct { name string description string - sbi sbiStore - devices deviceStore + sbi SbiStore + devices DeviceStore } tests := []struct { name string @@ -303,7 +305,7 @@ func Test_pndImplementation_GetSBIs(t *testing.T) { pnd := newPnd() tests := []struct { name string - want *sbiStore + want *SbiStore }{ {name: "default", want: &pnd.sbic}, } @@ -353,7 +355,7 @@ func Test_pndImplementation_MarshalDevice(t *testing.T) { if got != tt.want { t.Errorf("MarshalDevice() got = %v, want %v", got, tt.want) } - if err := pnd.devices.delete(did); err != nil { + if err := pnd.devices.Delete(did); err != nil { t.Error(err) } }) @@ -385,7 +387,7 @@ func Test_pndImplementation_RemoveDevice(t *testing.T) { if err := pnd.RemoveDevice(tt.args.uuid); (err != nil) != tt.wantErr { t.Errorf("RemoveDevice() error = %v, wantErr %v", err, tt.wantErr) } - if pnd.devices.exists(did) && tt.name == "default" { + if pnd.devices.Exists(did) && tt.name == "default" { t.Errorf("RemoveDevice() device still in device store %v", pnd.devices) } }) @@ -410,8 +412,8 @@ func Test_pndImplementation_RemoveSbi(t *testing.T) { pnd := &pndImplementation{ name: "test-remove-sbi", description: "test-remove-sbi", - sbic: sbiStore{store{}}, - devices: deviceStore{store{}}, + sbic: SbiStore{store{}}, + devices: DeviceStore{store{}}, id: defaultPndID, } if tt.name != "fails empty" { @@ -422,7 +424,7 @@ func Test_pndImplementation_RemoveSbi(t *testing.T) { if err := pnd.RemoveSbi(tt.args.id); (err != nil) != tt.wantErr { t.Errorf("RemoveSbi() error = %v, wantErr %v", err, tt.wantErr) } - if pnd.sbic.exists(tt.args.id) { + if pnd.sbic.Exists(tt.args.id) { t.Errorf("RemoveDevice() SBI still in SBI store %v", pnd.sbic) } }) @@ -470,7 +472,7 @@ func Test_pndImplementation_Request(t *testing.T) { if err := pnd.Request(tt.args.uuid, tt.args.path); (err != nil) != tt.wantErr { t.Errorf("Request() error = %v, wantErr %v", err, tt.wantErr) } - if err := pnd.devices.delete(mdid); err != nil { + if err := pnd.devices.Delete(mdid); err != nil { t.Error(err) } }) @@ -518,7 +520,7 @@ func Test_pndImplementation_RequestAll(t *testing.T) { if err := pnd.RequestAll(tt.args.path); (err != nil) != tt.wantErr { t.Errorf("RequestAll() error = %v, wantErr %v", err, tt.wantErr) } - if err := pnd.devices.delete(mdid); err != nil { + if err := pnd.devices.Delete(mdid); err != nil { t.Error(err) } }) @@ -545,7 +547,7 @@ func Test_pndImplementation_ChangeOND(t *testing.T) { fields: fields{}, args: args{ uuid: mdid, - operation: TransportUpdate, + operation: types.TransportUpdate, path: "/system/config/hostname", value: []string{"ceos3000"}, }, @@ -556,7 +558,7 @@ func Test_pndImplementation_ChangeOND(t *testing.T) { fields: fields{}, args: args{ uuid: mdid, - operation: TransportReplace, + operation: types.TransportReplace, path: "/system/config/hostname", value: []string{"ceos3000"}, }, @@ -567,7 +569,7 @@ func Test_pndImplementation_ChangeOND(t *testing.T) { fields: fields{}, args: args{ uuid: mdid, - operation: TransportDelete, + operation: types.TransportDelete, path: "/system/config/hostname", }, wantErr: false, @@ -577,7 +579,7 @@ func Test_pndImplementation_ChangeOND(t *testing.T) { fields: fields{}, args: args{ uuid: mdid, - operation: TransportDelete, + operation: types.TransportDelete, path: "/system/config/hostname", value: []string{"ceos3000"}, }, @@ -599,7 +601,7 @@ func Test_pndImplementation_ChangeOND(t *testing.T) { fields: fields{}, args: args{ uuid: mdid, - operation: TransportUpdate, + operation: types.TransportUpdate, path: "/system/config/hostname", value: []string{"ceos3000", "ceos3001"}, }, @@ -610,7 +612,7 @@ func Test_pndImplementation_ChangeOND(t *testing.T) { fields: fields{}, args: args{ uuid: mdid, - operation: TransportUpdate, + operation: types.TransportUpdate, path: "/system/config/hostname", }, wantErr: true, @@ -620,7 +622,7 @@ func Test_pndImplementation_ChangeOND(t *testing.T) { fields: fields{}, args: args{ uuid: mdid, - operation: TransportUpdate, + operation: types.TransportUpdate, path: "/system/config/hostname", }, wantErr: true, @@ -630,7 +632,7 @@ func Test_pndImplementation_ChangeOND(t *testing.T) { fields: fields{}, args: args{ uuid: did, - operation: TransportUpdate, + operation: types.TransportUpdate, }, wantErr: true, }, @@ -657,13 +659,14 @@ func Test_pndImplementation_ChangeOND(t *testing.T) { } func Test_pndImplementation_GetDevice(t *testing.T) { - p := newPnd() + pnd := newPnd() + sbi := NewSBI(types.Openconfig) d, err := NewDevice(sbi, &GnmiTransportOptions{}) if err != nil { t.Error(err) return } - if err = p.addDevice(d); err != nil { + if err = pnd.addDevice(d); err != nil { t.Error(err) return } @@ -691,7 +694,7 @@ func Test_pndImplementation_GetDevice(t *testing.T) { } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { - got, err := p.GetDevice(tt.args.uuid) + got, err := pnd.GetDevice(tt.args.uuid) if (err != nil) != tt.wantErr { t.Errorf("GetDevice() error = %v, wantErr %v", err, tt.wantErr) return @@ -727,7 +730,7 @@ func Test_pndImplementation_Confirm(t *testing.T) { t.Error(err) return } - if err := pnd.ChangeOND(d.ID(), TransportUpdate, "system/config/hostname", "ceos3000"); err != nil { + if err := pnd.ChangeOND(d.ID(), types.TransportUpdate, "system/config/hostname", "ceos3000"); err != nil { t.Error(err) return } diff --git a/nucleus/restconf_transport.go b/nucleus/restconf_transport.go index 7fe89a200b5cb0a0b58e488cae1ee93a98f4a3a2..6d7237aaf9c0adb5a5451b67cdc6e26d9aacc1ad 100644 --- a/nucleus/restconf_transport.go +++ b/nucleus/restconf_transport.go @@ -3,6 +3,8 @@ package nucleus import ( "context" + "code.fbi.h-da.de/cocsn/gosdn/nucleus/errors" + "github.com/openconfig/ygot/ytypes" ) @@ -12,17 +14,17 @@ type Restconf struct{} // Get not yet implemented func (r Restconf) Get(ctx context.Context, params ...string) (interface{}, error) { - return nil, &ErrNotYetImplemented{} + return nil, &errors.ErrNotYetImplemented{} } // Set not yet implemented func (r Restconf) Set(ctx context.Context, params ...interface{}) error { - return &ErrNotYetImplemented{} + return &errors.ErrNotYetImplemented{} } // Subscribe not yet implemented func (r Restconf) Subscribe(ctx context.Context, params ...string) error { - return &ErrNotYetImplemented{} + return &errors.ErrNotYetImplemented{} } // Type not yet implemented @@ -32,10 +34,10 @@ func (r Restconf) Type() string { // GetOptions not yet implemented func (r Restconf) GetOptions() interface{} { - return &ErrNotYetImplemented{} + return &errors.ErrNotYetImplemented{} } // ProcessResponse not yet implemented func (r Restconf) ProcessResponse(resp interface{}, root interface{}, models *ytypes.Schema) error { - return &ErrNotYetImplemented{} + return &errors.ErrNotYetImplemented{} } diff --git a/nucleus/southbound.go b/nucleus/southbound.go index bd7f6ff7f035be434321ff527290d5f2771b1026..b8eec7772e73d94aaaea5e3467c2b16bcbf86d61 100644 --- a/nucleus/southbound.go +++ b/nucleus/southbound.go @@ -3,6 +3,9 @@ package nucleus import ( "reflect" + "code.fbi.h-da.de/cocsn/gosdn/nucleus/errors" + "code.fbi.h-da.de/cocsn/gosdn/nucleus/types" + "code.fbi.h-da.de/cocsn/yang-models/generated/openconfig" "github.com/google/uuid" gpb "github.com/openconfig/gnmi/proto/gnmi" @@ -27,8 +30,14 @@ type SouthboundInterface interface { ID() uuid.UUID } -// Tapi is the implementation of an TAPI SBI. -type Tapi struct { +// NewSBI creates a SouthboundInterface of a given type. +func NewSBI(southbound types.Southbound) SouthboundInterface { + switch southbound { + case types.Openconfig: + return &OpenConfig{id: uuid.New()} + default: + return nil + } } // OpenConfig is the implementation of an OpenConfig SBI. @@ -88,7 +97,7 @@ func unmarshal(bytes []byte, fields []string, goStruct interface{}, opt ...ytype return openconfig.Unmarshal(bytes, goStruct.(*openconfig.Device), opt...) case 1: default: - return &ErrUnsupportedPath{fields} + return &errors.ErrUnsupportedPath{Path: fields} } var c ygot.GoStruct var field string diff --git a/nucleus/store.go b/nucleus/store.go index 35edfb62a7c733fccfb4b8f1612553da485161f8..291ed361c39491e49c499a2cefab1e556df88578 100644 --- a/nucleus/store.go +++ b/nucleus/store.go @@ -4,7 +4,8 @@ import ( "reflect" "sync" - p "code.fbi.h-da.de/cocsn/gosdn/nucleus/pnd" + "code.fbi.h-da.de/cocsn/gosdn/nucleus/errors" + "github.com/google/uuid" log "github.com/sirupsen/logrus" ) @@ -16,18 +17,54 @@ type Storable interface { ID() uuid.UUID } +// Store describes an interface for store implementations. +type Store interface { + Exists(id uuid.UUID) bool + Add(item Storable) error + Get(id uuid.UUID) (Storable, error) + Delete(id uuid.UUID) error + UUIDs() []uuid.UUID +} + +// NewStore returns a generic Store +func NewStore() Store { + return store{} +} + +// NewPndStore returns a PndStore +func NewPndStore() *PndStore { + return &PndStore{store{}} +} + +// NewSbiStore returns a SbiStore +func NewSbiStore() *SbiStore { + return &SbiStore{store{}} +} + +// NewDeviceStore returns a DeviceStore +func NewDeviceStore() *DeviceStore { + return &DeviceStore{store{}} +} + +// NewChangeStore returns a ChangeStore +func NewChangeStore() *ChangeStore { + return &ChangeStore{store{}} +} + type store map[uuid.UUID]Storable -func (s store) exists(id uuid.UUID) bool { +// Exists takes a Storable's UUID and checks its existence in the store. +func (s store) Exists(id uuid.UUID) bool { storeLock.RLock() defer storeLock.RUnlock() _, ok := s[id] return ok } -func (s store) add(item Storable) error { - if s.exists(item.ID()) { - return &ErrAlreadyExists{item: item} +// Add adds a Storable to the Store +func (s store) Add(item Storable) error { + if s.Exists(item.ID()) { + return &errors.ErrAlreadyExists{Item: item} } storeLock.Lock() s[item.ID()] = item @@ -39,9 +76,11 @@ func (s store) add(item Storable) error { return nil } -func (s store) get(id uuid.UUID) (Storable, error) { - if !s.exists(id) { - return nil, &ErrNotFound{id: id} +// Get takes a Storable's UUID and returns the Storable. If the requested +// Storable does not exist an error is returned. +func (s store) Get(id uuid.UUID) (Storable, error) { + if !s.Exists(id) { + return nil, &errors.ErrNotFound{ID: id} } log.WithFields(log.Fields{ "uuid": id, @@ -51,9 +90,11 @@ func (s store) get(id uuid.UUID) (Storable, error) { return s[id], nil } -func (s store) delete(id uuid.UUID) error { - if !s.exists(id) { - return &ErrNotFound{id: id} +// Delete takes a Storable's UUID and deletes it. If the specified UUID does not +// exist in the Store an error is returned. +func (s store) Delete(id uuid.UUID) error { + if !s.Exists(id) { + return &errors.ErrNotFound{ID: id} } storeLock.Lock() delete(s, id) @@ -64,6 +105,7 @@ func (s store) delete(id uuid.UUID) error { return nil } +// UUIDs returns all UUIDs in the store. func (s store) UUIDs() []uuid.UUID { storeLock.RLock() defer storeLock.RUnlock() @@ -76,20 +118,23 @@ func (s store) UUIDs() []uuid.UUID { return keys } -type sbiStore struct { +// SbiStore is used to store SouthboundInterfaces +type SbiStore struct { store } -func (s sbiStore) get(id uuid.UUID) (SouthboundInterface, error) { - item, err := s.store.get(id) +// Get takes a SouthboundInterface's UUID and returns the SouthboundInterface. If the requested +// SouthboundInterface does not exist an error is returned. +func (s SbiStore) Get(id uuid.UUID) (SouthboundInterface, error) { + item, err := s.store.Get(id) if err != nil { return nil, err } sbi, ok := item.(SouthboundInterface) if !ok { - return nil, &ErrInvalidTypeAssertion{ - v: sbi, - t: "SouthboundInterface", + return nil, &errors.ErrInvalidTypeAssertion{ + Value: sbi, + Type: "SouthboundInterface", } } log.WithFields(log.Fields{ @@ -98,20 +143,23 @@ func (s sbiStore) get(id uuid.UUID) (SouthboundInterface, error) { return sbi, nil } -type pndStore struct { +// PndStore is used to store PrincipalNetworkDomains +type PndStore struct { store } -func (s pndStore) get(id uuid.UUID) (PrincipalNetworkDomain, error) { - item, err := s.store.get(id) +// Get takes a PrincipalNetworkDomain's UUID and returns the PrincipalNetworkDomain. If the requested +// PrincipalNetworkDomain does not exist an error is returned. +func (s PndStore) Get(id uuid.UUID) (PrincipalNetworkDomain, error) { + item, err := s.store.Get(id) if err != nil { return nil, err } pnd, ok := item.(PrincipalNetworkDomain) if !ok { - return nil, &ErrInvalidTypeAssertion{ - v: pnd, - t: "PrincipalNetworkDomain", + return nil, &errors.ErrInvalidTypeAssertion{ + Value: pnd, + Type: "PrincipalNetworkDomain", } } log.WithFields(log.Fields{ @@ -120,20 +168,23 @@ func (s pndStore) get(id uuid.UUID) (PrincipalNetworkDomain, error) { return pnd, nil } -type deviceStore struct { +// DeviceStore is used to store Devices +type DeviceStore struct { store } -func (s deviceStore) get(id uuid.UUID) (*Device, error) { - item, err := s.store.get(id) +// Get takes a Device's UUID and returns the Device. If the requested +// Device does not exist an error is returned. +func (s DeviceStore) Get(id uuid.UUID) (*Device, error) { + item, err := s.store.Get(id) if err != nil { return nil, err } device, ok := item.(*Device) if !ok { - return nil, &ErrInvalidTypeAssertion{ - v: device, - t: reflect.TypeOf(&Device{}), + return nil, &errors.ErrInvalidTypeAssertion{ + Value: device, + Type: reflect.TypeOf(&Device{}), } } log.WithFields(log.Fields{ @@ -142,20 +193,23 @@ func (s deviceStore) get(id uuid.UUID) (*Device, error) { return device, nil } -type changeStore struct { +// ChangeStore is used to store Changes +type ChangeStore struct { store } -func (s changeStore) get(id uuid.UUID) (*p.Change, error) { - item, err := s.store.get(id) +// Get takes a Change's UUID and returns the Change. If the requested +// Change does not exist an error is returned. +func (s ChangeStore) Get(id uuid.UUID) (*Change, error) { + item, err := s.store.Get(id) if err != nil { return nil, err } - change, ok := item.(*p.Change) + change, ok := item.(*Change) if !ok { - return nil, &ErrInvalidTypeAssertion{ - v: change, - t: reflect.TypeOf(&p.Change{}), + return nil, &errors.ErrInvalidTypeAssertion{ + Value: change, + Type: reflect.TypeOf(&Change{}), } } log.WithFields(log.Fields{ diff --git a/nucleus/store_test.go b/nucleus/store_test.go index affb9a1fb5727ff9eb30a316102590e8fc945128..f2db1ed61741fb75f4ab4360bc192610573f3697 100644 --- a/nucleus/store_test.go +++ b/nucleus/store_test.go @@ -42,11 +42,11 @@ func Test_store_add(t *testing.T) { tt.args.item.(*mocks.Storable).On("ID").Return(iid) switch tt.name { case "already exixts": - _ = tt.s.add(tt.args.item) + _ = tt.s.Add(tt.args.item) default: } - if err := tt.s.add(tt.args.item); (err != nil) != tt.wantErr { - t.Errorf("add() error = %v, wantErr %v", err, tt.wantErr) + if err := tt.s.Add(tt.args.item); (err != nil) != tt.wantErr { + t.Errorf("Add() error = %v, wantErr %v", err, tt.wantErr) } }) } @@ -87,7 +87,7 @@ func Test_store_delete(t *testing.T) { } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { - if err := tt.s.delete(tt.args.id); (err != nil) != tt.wantErr { + if err := tt.s.Delete(tt.args.id); (err != nil) != tt.wantErr { t.Errorf("delete() error = %v, wantErr %v", err, tt.wantErr) } if tt.name == "default" { @@ -135,7 +135,7 @@ func Test_store_exists(t *testing.T) { } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { - if got := tt.s.exists(tt.args.id); got != tt.want { + if got := tt.s.Exists(tt.args.id); got != tt.want { t.Errorf("exists() = %v, want %v", got, tt.want) } }) @@ -181,7 +181,7 @@ func Test_store_get(t *testing.T) { } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { - got, err := tt.s.get(tt.args.id) + got, err := tt.s.Get(tt.args.id) if (err != nil) != tt.wantErr { t.Errorf("get() error = %v, wantErr %v", err, tt.wantErr) return @@ -282,10 +282,10 @@ func Test_sbiStore_get(t *testing.T) { } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { - s := sbiStore{ + s := SbiStore{ store: tt.fields.store, } - got, err := s.get(tt.args.id) + got, err := s.Get(tt.args.id) if (err != nil) != tt.wantErr { t.Errorf("get() error = %v, wantErr %v", err, tt.wantErr) return @@ -355,10 +355,10 @@ func Test_pndStore_get(t *testing.T) { } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { - s := pndStore{ + s := PndStore{ store: tt.fields.store, } - got, err := s.get(tt.args.id) + got, err := s.Get(tt.args.id) if (err != nil) != tt.wantErr { t.Errorf("get() error = %v, wantErr %v", err, tt.wantErr) return @@ -422,10 +422,10 @@ func Test_deviceStore_get(t *testing.T) { } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { - s := deviceStore{ + s := DeviceStore{ store: tt.fields.store, } - got, err := s.get(tt.args.id) + got, err := s.Get(tt.args.id) if (err != nil) != tt.wantErr { t.Errorf("get() error = %v, wantErr %v", err, tt.wantErr) return diff --git a/nucleus/transport.go b/nucleus/transport.go index 050629580f632a11d7c5da420928285429f07cbd..4a1764e42a37f2724083a5d260c9bdee23f41a43 100644 --- a/nucleus/transport.go +++ b/nucleus/transport.go @@ -8,20 +8,6 @@ import ( "github.com/openconfig/ygot/ytypes" ) -// Operation codes numerous operations used to change the state of remote resources. -// It is used as a unified code. Each Transport implementation needs to map these -// accordingly to its specification. -type Operation int - -const ( - // TransportUpdate codes an update operation - TransportUpdate Operation = iota - // TransportReplace codes a replace operation - TransportReplace - // TransportDelete codes a delete operation - TransportDelete -) - // Transport provides an interface for Transport implementations // like RESTCONF or gnmi type Transport interface { diff --git a/nucleus/types/context.go b/nucleus/types/context.go new file mode 100644 index 0000000000000000000000000000000000000000..aa514b17b4068fec76f569f0113c9e3a1dd568d1 --- /dev/null +++ b/nucleus/types/context.go @@ -0,0 +1,16 @@ +package types + +// CtxKeyType is a custom type to be used as key in a context.WithValue() or +// context.Value() call. For more information see: +// https://www.calhoun.io/pitfalls-of-context-values-and-how-to-avoid-or-mitigate-them/ +// TODO: Unexport to comply with best practice +type CtxKeyType string + +const ( + // CtxKeyOpts context key for gnmi.SubscribeOptions + CtxKeyOpts CtxKeyType = "opts" + // CtxKeyConfig is a context key for gnmi.Config + CtxKeyConfig = "config" + // CtxKeyOperation is a context key for a gNMI operation (update, replace, delete) + CtxKeyOperation = "op" +) diff --git a/nucleus/types/sbi.go b/nucleus/types/sbi.go new file mode 100644 index 0000000000000000000000000000000000000000..4f52211e91eb4db96a0b072787e4415184f50ff5 --- /dev/null +++ b/nucleus/types/sbi.go @@ -0,0 +1,9 @@ +package types + +// Southbound codes numerous SouthboundInterface implementations used by NewSBI() +type Southbound int + +const ( + // Openconfig describes an OpenConfig SBI + Openconfig Southbound = iota +) diff --git a/nucleus/types/transport.go b/nucleus/types/transport.go new file mode 100644 index 0000000000000000000000000000000000000000..9b0cfe965ccbabfaa7d0a86fd09a317915b8548b --- /dev/null +++ b/nucleus/types/transport.go @@ -0,0 +1,15 @@ +package types + +// Operation codes numerous operations used to change the state of remote resources. +// It is used as a unified code. Each Transport implementation needs to map these +// accordingly to its specification. +type Operation int + +const ( + // TransportUpdate codes an update operation + TransportUpdate Operation = iota + // TransportReplace codes a replace operation + TransportReplace + // TransportDelete codes a delete operation + TransportDelete +) diff --git a/test/integration/nucleusIntegration_test.go b/test/integration/nucleusIntegration_test.go index ed6d78fd929ed1d8379ca0cc18bc11d2e65e5f83..ccd5d942adb7e8436eaf117811505deed12ae416 100644 --- a/test/integration/nucleusIntegration_test.go +++ b/test/integration/nucleusIntegration_test.go @@ -3,6 +3,7 @@ package integration import ( "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/types" "context" gpb "github.com/openconfig/gnmi/proto/gnmi" pb "google.golang.org/protobuf/proto" @@ -236,7 +237,7 @@ func TestGnmi_SubscribeIntegration(t *testing.T) { t.Error(err) return } - ctx := context.WithValue(context.Background(), nucleus.CtxKeyOpts, tt.args.opts) //nolint + ctx := context.WithValue(context.Background(), types.CtxKeyOpts, tt.args.opts) //nolint ctx, cancel := context.WithCancel(ctx) go func() { subErr := g.Subscribe(ctx)