From ddf7f9e08cceaf553b62166c81ee1ff45c4846a6 Mon Sep 17 00:00:00 2001 From: Boris Glimcher Date: Thu, 19 Oct 2023 21:12:55 +0300 Subject: [PATCH 1/2] refactor: split evpn folder Fixes #268 Signed-off-by: Boris Glimcher --- pkg/{evpn => bridge}/bridge.go | 0 pkg/{evpn => bridge}/bridge_netlink.go | 0 pkg/{evpn => bridge}/bridge_test.go | 0 pkg/{evpn => bridge}/bridge_validate.go | 0 pkg/{evpn => port}/port.go | 0 pkg/{evpn => port}/port_test.go | 0 pkg/{evpn => port}/port_validate.go | 0 pkg/{evpn => svi}/svi.go | 0 pkg/{evpn => svi}/svi_frr.go | 0 pkg/{evpn => svi}/svi_netlink.go | 0 pkg/{evpn => svi}/svi_test.go | 0 pkg/{evpn => svi}/svi_validate.go | 0 pkg/{evpn => vrf}/vrf.go | 0 pkg/{evpn => vrf}/vrf_frr.go | 0 pkg/{evpn => vrf}/vrf_netlink.go | 0 pkg/{evpn => vrf}/vrf_test.go | 0 pkg/{evpn => vrf}/vrf_validate.go | 0 17 files changed, 0 insertions(+), 0 deletions(-) rename pkg/{evpn => bridge}/bridge.go (100%) rename pkg/{evpn => bridge}/bridge_netlink.go (100%) rename pkg/{evpn => bridge}/bridge_test.go (100%) rename pkg/{evpn => bridge}/bridge_validate.go (100%) rename pkg/{evpn => port}/port.go (100%) rename pkg/{evpn => port}/port_test.go (100%) rename pkg/{evpn => port}/port_validate.go (100%) rename pkg/{evpn => svi}/svi.go (100%) rename pkg/{evpn => svi}/svi_frr.go (100%) rename pkg/{evpn => svi}/svi_netlink.go (100%) rename pkg/{evpn => svi}/svi_test.go (100%) rename pkg/{evpn => svi}/svi_validate.go (100%) rename pkg/{evpn => vrf}/vrf.go (100%) rename pkg/{evpn => vrf}/vrf_frr.go (100%) rename pkg/{evpn => vrf}/vrf_netlink.go (100%) rename pkg/{evpn => vrf}/vrf_test.go (100%) rename pkg/{evpn => vrf}/vrf_validate.go (100%) diff --git a/pkg/evpn/bridge.go b/pkg/bridge/bridge.go similarity index 100% rename from pkg/evpn/bridge.go rename to pkg/bridge/bridge.go diff --git a/pkg/evpn/bridge_netlink.go b/pkg/bridge/bridge_netlink.go similarity index 100% rename from pkg/evpn/bridge_netlink.go rename to pkg/bridge/bridge_netlink.go diff --git a/pkg/evpn/bridge_test.go b/pkg/bridge/bridge_test.go similarity index 100% rename from pkg/evpn/bridge_test.go rename to pkg/bridge/bridge_test.go diff --git a/pkg/evpn/bridge_validate.go b/pkg/bridge/bridge_validate.go similarity index 100% rename from pkg/evpn/bridge_validate.go rename to pkg/bridge/bridge_validate.go diff --git a/pkg/evpn/port.go b/pkg/port/port.go similarity index 100% rename from pkg/evpn/port.go rename to pkg/port/port.go diff --git a/pkg/evpn/port_test.go b/pkg/port/port_test.go similarity index 100% rename from pkg/evpn/port_test.go rename to pkg/port/port_test.go diff --git a/pkg/evpn/port_validate.go b/pkg/port/port_validate.go similarity index 100% rename from pkg/evpn/port_validate.go rename to pkg/port/port_validate.go diff --git a/pkg/evpn/svi.go b/pkg/svi/svi.go similarity index 100% rename from pkg/evpn/svi.go rename to pkg/svi/svi.go diff --git a/pkg/evpn/svi_frr.go b/pkg/svi/svi_frr.go similarity index 100% rename from pkg/evpn/svi_frr.go rename to pkg/svi/svi_frr.go diff --git a/pkg/evpn/svi_netlink.go b/pkg/svi/svi_netlink.go similarity index 100% rename from pkg/evpn/svi_netlink.go rename to pkg/svi/svi_netlink.go diff --git a/pkg/evpn/svi_test.go b/pkg/svi/svi_test.go similarity index 100% rename from pkg/evpn/svi_test.go rename to pkg/svi/svi_test.go diff --git a/pkg/evpn/svi_validate.go b/pkg/svi/svi_validate.go similarity index 100% rename from pkg/evpn/svi_validate.go rename to pkg/svi/svi_validate.go diff --git a/pkg/evpn/vrf.go b/pkg/vrf/vrf.go similarity index 100% rename from pkg/evpn/vrf.go rename to pkg/vrf/vrf.go diff --git a/pkg/evpn/vrf_frr.go b/pkg/vrf/vrf_frr.go similarity index 100% rename from pkg/evpn/vrf_frr.go rename to pkg/vrf/vrf_frr.go diff --git a/pkg/evpn/vrf_netlink.go b/pkg/vrf/vrf_netlink.go similarity index 100% rename from pkg/evpn/vrf_netlink.go rename to pkg/vrf/vrf_netlink.go diff --git a/pkg/evpn/vrf_test.go b/pkg/vrf/vrf_test.go similarity index 100% rename from pkg/evpn/vrf_test.go rename to pkg/vrf/vrf_test.go diff --git a/pkg/evpn/vrf_validate.go b/pkg/vrf/vrf_validate.go similarity index 100% rename from pkg/evpn/vrf_validate.go rename to pkg/vrf/vrf_validate.go From 667e0a77e6da4cb0b481a9864c48978017cd188e Mon Sep 17 00:00:00 2001 From: Boris Glimcher Date: Thu, 19 Oct 2023 21:29:25 +0300 Subject: [PATCH 2/2] refactor: split server object per package Signed-off-by: Boris Glimcher --- cmd/main.go | 18 ++-- pkg/bridge/bridge.go | 4 +- pkg/bridge/bridge_netlink.go | 4 +- pkg/bridge/bridge_test.go | 4 +- pkg/bridge/bridge_validate.go | 4 +- pkg/bridge/common.go | 103 +++++++++++++++++++++ pkg/bridge/server.go | 58 ++++++++++++ pkg/bridge/server_test.go | 64 +++++++++++++ pkg/evpn/evpn.go | 125 -------------------------- pkg/evpn/evpn_test.go | 102 --------------------- pkg/port/common.go | 131 +++++++++++++++++++++++++++ pkg/port/port.go | 4 +- pkg/port/port_test.go | 4 +- pkg/port/port_validate.go | 4 +- pkg/port/server.go | 58 ++++++++++++ pkg/port/server_test.go | 64 +++++++++++++ pkg/svi/common.go | 164 ++++++++++++++++++++++++++++++++++ pkg/svi/server.go | 58 ++++++++++++ pkg/svi/server_test.go | 64 +++++++++++++ pkg/svi/svi.go | 4 +- pkg/svi/svi_frr.go | 4 +- pkg/svi/svi_netlink.go | 4 +- pkg/svi/svi_test.go | 4 +- pkg/svi/svi_validate.go | 4 +- pkg/vrf/common.go | 112 +++++++++++++++++++++++ pkg/vrf/server.go | 58 ++++++++++++ pkg/vrf/server_test.go | 64 +++++++++++++ pkg/vrf/vrf.go | 4 +- pkg/vrf/vrf_frr.go | 4 +- pkg/vrf/vrf_netlink.go | 4 +- pkg/vrf/vrf_test.go | 4 +- pkg/vrf/vrf_validate.go | 4 +- 32 files changed, 1044 insertions(+), 267 deletions(-) create mode 100644 pkg/bridge/common.go create mode 100644 pkg/bridge/server.go create mode 100644 pkg/bridge/server_test.go create mode 100644 pkg/port/common.go create mode 100644 pkg/port/server.go create mode 100644 pkg/port/server_test.go create mode 100644 pkg/svi/common.go create mode 100644 pkg/svi/server.go create mode 100644 pkg/svi/server_test.go create mode 100644 pkg/vrf/common.go create mode 100644 pkg/vrf/server.go create mode 100644 pkg/vrf/server_test.go diff --git a/cmd/main.go b/cmd/main.go index 44ff7172..dd66cf17 100644 --- a/cmd/main.go +++ b/cmd/main.go @@ -16,8 +16,11 @@ import ( pc "github.com/opiproject/opi-api/inventory/v1/gen/go" pe "github.com/opiproject/opi-api/network/evpn-gw/v1alpha1/gen/go" - "github.com/opiproject/opi-evpn-bridge/pkg/evpn" + "github.com/opiproject/opi-evpn-bridge/pkg/bridge" + "github.com/opiproject/opi-evpn-bridge/pkg/port" + "github.com/opiproject/opi-evpn-bridge/pkg/svi" "github.com/opiproject/opi-evpn-bridge/pkg/utils" + "github.com/opiproject/opi-evpn-bridge/pkg/vrf" "github.com/opiproject/opi-smbios-bridge/pkg/inventory" "github.com/philippgille/gokv" @@ -105,12 +108,15 @@ func runGrpcServer(grpcPort int, tlsFiles string, store gokv.Store) { ) s := grpc.NewServer(serverOptions...) - opi := evpn.NewServer(store) + bridgeServer := bridge.NewServer(store) + portServer := port.NewServer(store) + vrfServer := vrf.NewServer(store) + sviServer := svi.NewServer(store) - pe.RegisterLogicalBridgeServiceServer(s, opi) - pe.RegisterBridgePortServiceServer(s, opi) - pe.RegisterVrfServiceServer(s, opi) - pe.RegisterSviServiceServer(s, opi) + pe.RegisterLogicalBridgeServiceServer(s, bridgeServer) + pe.RegisterBridgePortServiceServer(s, portServer) + pe.RegisterVrfServiceServer(s, vrfServer) + pe.RegisterSviServiceServer(s, sviServer) pc.RegisterInventorySvcServer(s, &inventory.Server{}) reflection.Register(s) diff --git a/pkg/bridge/bridge.go b/pkg/bridge/bridge.go index 7c5b18a8..5b4744c4 100644 --- a/pkg/bridge/bridge.go +++ b/pkg/bridge/bridge.go @@ -2,8 +2,8 @@ // Copyright (c) 2022-2023 Intel Corporation, or its subsidiaries. // Copyright (c) 2022-2023 Dell Inc, or its subsidiaries. -// Package evpn is the main package of the application -package evpn +// Package bridge is the main package of the application +package bridge import ( "context" diff --git a/pkg/bridge/bridge_netlink.go b/pkg/bridge/bridge_netlink.go index a0d4da02..67f954e6 100644 --- a/pkg/bridge/bridge_netlink.go +++ b/pkg/bridge/bridge_netlink.go @@ -2,8 +2,8 @@ // Copyright (c) 2022-2023 Intel Corporation, or its subsidiaries. // Copyright (c) 2022-2023 Dell Inc, or its subsidiaries. -// Package evpn is the main package of the application -package evpn +// Package bridge is the main package of the application +package bridge import ( "context" diff --git a/pkg/bridge/bridge_test.go b/pkg/bridge/bridge_test.go index 62554775..02d82093 100644 --- a/pkg/bridge/bridge_test.go +++ b/pkg/bridge/bridge_test.go @@ -2,8 +2,8 @@ // Copyright (c) 2022-2023 Intel Corporation, or its subsidiaries. // Copyright (c) 2022-2023 Dell Inc, or its subsidiaries. -// Package evpn is the main package of the application -package evpn +// Package bridge is the main package of the application +package bridge import ( "context" diff --git a/pkg/bridge/bridge_validate.go b/pkg/bridge/bridge_validate.go index 21695b2a..5f62bda5 100644 --- a/pkg/bridge/bridge_validate.go +++ b/pkg/bridge/bridge_validate.go @@ -1,8 +1,8 @@ // SPDX-License-Identifier: Apache-2.0 // Copyright (c) 2022-2023 Dell Inc, or its subsidiaries. -// Package evpn is the main package of the application -package evpn +// Package bridge is the main package of the application +package bridge import ( "fmt" diff --git a/pkg/bridge/common.go b/pkg/bridge/common.go new file mode 100644 index 00000000..87709d3e --- /dev/null +++ b/pkg/bridge/common.go @@ -0,0 +1,103 @@ +// SPDX-License-Identifier: Apache-2.0 +// Copyright (c) 2022-2023 Dell Inc, or its subsidiaries. + +// Package bridge is the main package of the application +package bridge + +import ( + "context" + "fmt" + "log" + "net" + + "google.golang.org/grpc" + "google.golang.org/grpc/codes" + "google.golang.org/grpc/status" + "google.golang.org/grpc/test/bufconn" + "google.golang.org/protobuf/proto" + + pb "github.com/opiproject/opi-api/network/evpn-gw/v1alpha1/gen/go" +) + +// TODO: move all of this to a common place +const ( + tenantbridgeName = "br-tenant" +) + +func resourceIDToFullName(_ string, resourceID string) string { + return fmt.Sprintf("//network.opiproject.org/bridges/%s", resourceID) +} + +func protoClone[T proto.Message](protoStruct T) T { + return proto.Clone(protoStruct).(T) +} + +func extractPagination(pageSize int32, pageToken string, pagination map[string]int) (size int, offset int, err error) { + const ( + maxPageSize = 250 + defaultPageSize = 50 + ) + switch { + case pageSize < 0: + return -1, -1, status.Error(codes.InvalidArgument, "negative PageSize is not allowed") + case pageSize == 0: + size = defaultPageSize + case pageSize > maxPageSize: + size = maxPageSize + default: + size = int(pageSize) + } + // fetch offset from the database using opaque token + offset = 0 + if pageToken != "" { + var ok bool + offset, ok = pagination[pageToken] + if !ok { + return -1, -1, status.Errorf(codes.NotFound, "unable to find pagination token %s", pageToken) + } + log.Printf("Found offset %d from pagination token: %s", offset, pageToken) + } + return size, offset, nil +} + +func limitPagination[T any](result []T, offset int, size int) ([]T, bool) { + end := offset + size + hasMoreElements := false + if end < len(result) { + hasMoreElements = true + } else { + end = len(result) + } + return result[offset:end], hasMoreElements +} + +func dialer(opi *Server) func(context.Context, string) (net.Conn, error) { + listener := bufconn.Listen(1024 * 1024) + server := grpc.NewServer() + + pb.RegisterLogicalBridgeServiceServer(server, opi) + + go func() { + if err := server.Serve(listener); err != nil { + log.Fatal(err) + } + }() + + return func(context.Context, string) (net.Conn, error) { + return listener.Dial() + } +} + +func equalProtoSlices[T proto.Message](x, y []T) bool { + if len(x) != len(y) { + return false + } + + for i := 0; i < len(x); i++ { + if !proto.Equal(x[i], y[i]) { + return false + } + } + + return true +} diff --git a/pkg/bridge/server.go b/pkg/bridge/server.go new file mode 100644 index 00000000..d089d94f --- /dev/null +++ b/pkg/bridge/server.go @@ -0,0 +1,58 @@ +// SPDX-License-Identifier: Apache-2.0 +// Copyright (c) 2022-2023 Dell Inc, or its subsidiaries. + +// Package bridge is the main package of the application +package bridge + +import ( + "log" + + "go.opentelemetry.io/otel" + "go.opentelemetry.io/otel/trace" + + "github.com/philippgille/gokv" + + pb "github.com/opiproject/opi-api/network/evpn-gw/v1alpha1/gen/go" + + "github.com/opiproject/opi-evpn-bridge/pkg/utils" +) + +// Server represents the Server object +type Server struct { + pb.UnimplementedLogicalBridgeServiceServer + Pagination map[string]int + ListHelper map[string]bool + nLink utils.Netlink + frr utils.Frr + tracer trace.Tracer + store gokv.Store +} + +// NewServer creates initialized instance of EVPN server +func NewServer(store gokv.Store) *Server { + nLink := utils.NewNetlinkWrapper() + frr := utils.NewFrrWrapper() + return NewServerWithArgs(nLink, frr, store) +} + +// NewServerWithArgs creates initialized instance of EVPN server +// with externally created Netlink +func NewServerWithArgs(nLink utils.Netlink, frr utils.Frr, store gokv.Store) *Server { + if frr == nil { + log.Panic("nil for Frr is not allowed") + } + if nLink == nil { + log.Panic("nil for Netlink is not allowed") + } + if store == nil { + log.Panic("nil for Store is not allowed") + } + return &Server{ + ListHelper: make(map[string]bool), + Pagination: make(map[string]int), + nLink: nLink, + frr: frr, + tracer: otel.Tracer(""), + store: store, + } +} diff --git a/pkg/bridge/server_test.go b/pkg/bridge/server_test.go new file mode 100644 index 00000000..328f35e9 --- /dev/null +++ b/pkg/bridge/server_test.go @@ -0,0 +1,64 @@ +// SPDX-License-Identifier: Apache-2.0 +// Copyright (c) 2022-2023 Dell Inc, or its subsidiaries. + +// Package bridge is the main package of the application +package bridge + +import ( + "testing" + + "github.com/philippgille/gokv" + "github.com/philippgille/gokv/gomap" + + "github.com/opiproject/opi-evpn-bridge/pkg/utils" +) + +func TestFrontEnd_NewServerWithArgs(t *testing.T) { + tests := map[string]struct { + frr utils.Frr + nLink utils.Netlink + store gokv.Store + wantPanic bool + }{ + "nil netlink argument": { + frr: &utils.FrrWrapper{}, + nLink: nil, + store: gomap.NewStore(gomap.DefaultOptions), + wantPanic: true, + }, + "nil store argument": { + frr: &utils.FrrWrapper{}, + nLink: &utils.NetlinkWrapper{}, + store: nil, + wantPanic: true, + }, + "nil frr argument": { + frr: nil, + nLink: &utils.NetlinkWrapper{}, + store: gomap.NewStore(gomap.DefaultOptions), + wantPanic: true, + }, + "all valid arguments": { + frr: &utils.FrrWrapper{}, + nLink: &utils.NetlinkWrapper{}, + store: gomap.NewStore(gomap.DefaultOptions), + wantPanic: false, + }, + } + + for testName, tt := range tests { + t.Run(testName, func(t *testing.T) { + defer func() { + r := recover() + if (r != nil) != tt.wantPanic { + t.Errorf("NewServerWithArgs() recover = %v, wantPanic = %v", r, tt.wantPanic) + } + }() + + server := NewServerWithArgs(tt.nLink, tt.frr, tt.store) + if server == nil && !tt.wantPanic { + t.Error("expected non nil server or panic") + } + }) + } +} diff --git a/pkg/evpn/evpn.go b/pkg/evpn/evpn.go index 85fa974a..02e04d27 100644 --- a/pkg/evpn/evpn.go +++ b/pkg/evpn/evpn.go @@ -4,128 +4,3 @@ // Package evpn is the main package of the application package evpn - -import ( - "crypto/rand" - "fmt" - "log" - - "go.opentelemetry.io/otel" - "go.opentelemetry.io/otel/trace" - - "google.golang.org/grpc/codes" - "google.golang.org/grpc/status" - "google.golang.org/protobuf/proto" - - "github.com/philippgille/gokv" - - pb "github.com/opiproject/opi-api/network/evpn-gw/v1alpha1/gen/go" - - "github.com/opiproject/opi-evpn-bridge/pkg/utils" -) - -const ( - tenantbridgeName = "br-tenant" -) - -// Server represents the Server object -type Server struct { - pb.UnimplementedVrfServiceServer - pb.UnimplementedSviServiceServer - pb.UnimplementedLogicalBridgeServiceServer - pb.UnimplementedBridgePortServiceServer - Pagination map[string]int - ListHelper map[string]bool - nLink utils.Netlink - frr utils.Frr - tracer trace.Tracer - store gokv.Store -} - -// NewServer creates initialized instance of EVPN server -func NewServer(store gokv.Store) *Server { - nLink := utils.NewNetlinkWrapper() - frr := utils.NewFrrWrapper() - return NewServerWithArgs(nLink, frr, store) -} - -// NewServerWithArgs creates initialized instance of EVPN server -// with externally created Netlink -func NewServerWithArgs(nLink utils.Netlink, frr utils.Frr, store gokv.Store) *Server { - if frr == nil { - log.Panic("nil for Frr is not allowed") - } - if nLink == nil { - log.Panic("nil for Netlink is not allowed") - } - if store == nil { - log.Panic("nil for Store is not allowed") - } - return &Server{ - ListHelper: make(map[string]bool), - Pagination: make(map[string]int), - nLink: nLink, - frr: frr, - tracer: otel.Tracer(""), - store: store, - } -} - -func resourceIDToFullName(container string, resourceID string) string { - return fmt.Sprintf("//network.opiproject.org/%s/%s", container, resourceID) -} - -func protoClone[T proto.Message](protoStruct T) T { - return proto.Clone(protoStruct).(T) -} - -func generateRandMAC() ([]byte, error) { - buf := make([]byte, 6) - if _, err := rand.Read(buf); err != nil { - return nil, fmt.Errorf("unable to retrieve 6 rnd bytes: %s", err) - } - - // Set locally administered addresses bit and reset multicast bit - buf[0] = (buf[0] | 0x02) & 0xfe - - return buf, nil -} - -func extractPagination(pageSize int32, pageToken string, pagination map[string]int) (size int, offset int, err error) { - const ( - maxPageSize = 250 - defaultPageSize = 50 - ) - switch { - case pageSize < 0: - return -1, -1, status.Error(codes.InvalidArgument, "negative PageSize is not allowed") - case pageSize == 0: - size = defaultPageSize - case pageSize > maxPageSize: - size = maxPageSize - default: - size = int(pageSize) - } - // fetch offset from the database using opaque token - offset = 0 - if pageToken != "" { - var ok bool - offset, ok = pagination[pageToken] - if !ok { - return -1, -1, status.Errorf(codes.NotFound, "unable to find pagination token %s", pageToken) - } - log.Printf("Found offset %d from pagination token: %s", offset, pageToken) - } - return size, offset, nil -} - -func limitPagination[T any](result []T, offset int, size int) ([]T, bool) { - end := offset + size - hasMoreElements := false - if end < len(result) { - hasMoreElements = true - } else { - end = len(result) - } - return result[offset:end], hasMoreElements -} diff --git a/pkg/evpn/evpn_test.go b/pkg/evpn/evpn_test.go index c2b30787..02e04d27 100644 --- a/pkg/evpn/evpn_test.go +++ b/pkg/evpn/evpn_test.go @@ -4,105 +4,3 @@ // Package evpn is the main package of the application package evpn - -import ( - "context" - "log" - "net" - "testing" - - "google.golang.org/grpc" - "google.golang.org/grpc/test/bufconn" - "google.golang.org/protobuf/proto" - - "github.com/philippgille/gokv" - "github.com/philippgille/gokv/gomap" - - pb "github.com/opiproject/opi-api/network/evpn-gw/v1alpha1/gen/go" - - "github.com/opiproject/opi-evpn-bridge/pkg/utils" -) - -func dialer(opi *Server) func(context.Context, string) (net.Conn, error) { - listener := bufconn.Listen(1024 * 1024) - server := grpc.NewServer() - - pb.RegisterLogicalBridgeServiceServer(server, opi) - pb.RegisterBridgePortServiceServer(server, opi) - pb.RegisterVrfServiceServer(server, opi) - pb.RegisterSviServiceServer(server, opi) - - go func() { - if err := server.Serve(listener); err != nil { - log.Fatal(err) - } - }() - - return func(context.Context, string) (net.Conn, error) { - return listener.Dial() - } -} - -func equalProtoSlices[T proto.Message](x, y []T) bool { - if len(x) != len(y) { - return false - } - - for i := 0; i < len(x); i++ { - if !proto.Equal(x[i], y[i]) { - return false - } - } - - return true -} - -func TestFrontEnd_NewServerWithArgs(t *testing.T) { - tests := map[string]struct { - frr utils.Frr - nLink utils.Netlink - store gokv.Store - wantPanic bool - }{ - "nil netlink argument": { - frr: &utils.FrrWrapper{}, - nLink: nil, - store: gomap.NewStore(gomap.DefaultOptions), - wantPanic: true, - }, - "nil store argument": { - frr: &utils.FrrWrapper{}, - nLink: &utils.NetlinkWrapper{}, - store: nil, - wantPanic: true, - }, - "nil frr argument": { - frr: nil, - nLink: &utils.NetlinkWrapper{}, - store: gomap.NewStore(gomap.DefaultOptions), - wantPanic: true, - }, - "all valid arguments": { - frr: &utils.FrrWrapper{}, - nLink: &utils.NetlinkWrapper{}, - store: gomap.NewStore(gomap.DefaultOptions), - wantPanic: false, - }, - } - - for testName, tt := range tests { - t.Run(testName, func(t *testing.T) { - defer func() { - r := recover() - if (r != nil) != tt.wantPanic { - t.Errorf("NewServerWithArgs() recover = %v, wantPanic = %v", r, tt.wantPanic) - } - }() - - server := NewServerWithArgs(tt.nLink, tt.frr, tt.store) - if server == nil && !tt.wantPanic { - t.Error("expected non nil server or panic") - } - }) - } -} diff --git a/pkg/port/common.go b/pkg/port/common.go new file mode 100644 index 00000000..bf704682 --- /dev/null +++ b/pkg/port/common.go @@ -0,0 +1,131 @@ +// SPDX-License-Identifier: Apache-2.0 +// Copyright (c) 2022-2023 Dell Inc, or its subsidiaries. + +// Package port is the main package of the application +package port + +import ( + "context" + "fmt" + "log" + "net" + + "google.golang.org/grpc" + "google.golang.org/grpc/codes" + "google.golang.org/grpc/status" + "google.golang.org/grpc/test/bufconn" + "google.golang.org/protobuf/proto" + + pb "github.com/opiproject/opi-api/network/evpn-gw/v1alpha1/gen/go" + pc "github.com/opiproject/opi-api/network/opinetcommon/v1alpha1/gen/go" +) + +// TODO: move all of this to a common place +const ( + tenantbridgeName = "br-tenant" +) + +var ( + testLogicalBridgeID = "opi-bridge9" + testLogicalBridgeName = resourceIDToFullName("bridges", testLogicalBridgeID) + testLogicalBridge = pb.LogicalBridge{ + Spec: &pb.LogicalBridgeSpec{ + Vni: proto.Uint32(11), + VlanId: 22, + VtepIpPrefix: &pc.IPPrefix{ + Addr: &pc.IPAddress{ + Af: pc.IpAf_IP_AF_INET, + V4OrV6: &pc.IPAddress_V4Addr{ + V4Addr: 167772162, + }, + }, + Len: 24, + }, + }, + } + testLogicalBridgeWithStatus = pb.LogicalBridge{ + Name: testLogicalBridgeName, + Spec: testLogicalBridge.Spec, + Status: &pb.LogicalBridgeStatus{ + OperStatus: pb.LBOperStatus_LB_OPER_STATUS_UP, + }, + } +) + +func resourceIDToFullName(_ string, resourceID string) string { + return fmt.Sprintf("//network.opiproject.org/ports/%s", resourceID) +} + +func protoClone[T proto.Message](protoStruct T) T { + return proto.Clone(protoStruct).(T) +} + +func extractPagination(pageSize int32, pageToken string, pagination map[string]int) (size int, offset int, err error) { + const ( + maxPageSize = 250 + defaultPageSize = 50 + ) + switch { + case pageSize < 0: + return -1, -1, status.Error(codes.InvalidArgument, "negative PageSize is not allowed") + case pageSize == 0: + size = defaultPageSize + case pageSize > maxPageSize: + size = maxPageSize + default: + size = int(pageSize) + } + // fetch offset from the database using opaque token + offset = 0 + if pageToken != "" { + var ok bool + offset, ok = pagination[pageToken] + if !ok { + return -1, -1, status.Errorf(codes.NotFound, "unable to find pagination token %s", pageToken) + } + log.Printf("Found offset %d from pagination token: %s", offset, pageToken) + } + return size, offset, nil +} + +func limitPagination[T any](result []T, offset int, size int) ([]T, bool) { + end := offset + size + hasMoreElements := false + if end < len(result) { + hasMoreElements = true + } else { + end = len(result) + } + return result[offset:end], hasMoreElements +} + +func dialer(opi *Server) func(context.Context, string) (net.Conn, error) { + listener := bufconn.Listen(1024 * 1024) + server := grpc.NewServer() + + pb.RegisterBridgePortServiceServer(server, opi) + + go func() { + if err := server.Serve(listener); err != nil { + log.Fatal(err) + } + }() + + return func(context.Context, string) (net.Conn, error) { + return listener.Dial() + } +} + +func equalProtoSlices[T proto.Message](x, y []T) bool { + if len(x) != len(y) { + return false + } + + for i := 0; i < len(x); i++ { + if !proto.Equal(x[i], y[i]) { + return false + } + } + + return true +} diff --git a/pkg/port/port.go b/pkg/port/port.go index f971c250..2e0aec55 100644 --- a/pkg/port/port.go +++ b/pkg/port/port.go @@ -2,8 +2,8 @@ // Copyright (c) 2022-2023 Intel Corporation, or its subsidiaries. // Copyright (c) 2022-2023 Dell Inc, or its subsidiaries. -// Package evpn is the main package of the application -package evpn +// Package port is the main package of the application +package port import ( "context" diff --git a/pkg/port/port_test.go b/pkg/port/port_test.go index f10da542..90fac034 100644 --- a/pkg/port/port_test.go +++ b/pkg/port/port_test.go @@ -2,8 +2,8 @@ // Copyright (c) 2022-2023 Intel Corporation, or its subsidiaries. // Copyright (c) 2022-2023 Dell Inc, or its subsidiaries. -// Package evpn is the main package of the application -package evpn +// Package port is the main package of the application +package port import ( "context" diff --git a/pkg/port/port_validate.go b/pkg/port/port_validate.go index 8c97ecc0..a7ab6e4d 100644 --- a/pkg/port/port_validate.go +++ b/pkg/port/port_validate.go @@ -1,8 +1,8 @@ // SPDX-License-Identifier: Apache-2.0 // Copyright (c) 2022-2023 Dell Inc, or its subsidiaries. -// Package evpn is the main package of the application -package evpn +// Package port is the main package of the application +package port import ( "fmt" diff --git a/pkg/port/server.go b/pkg/port/server.go new file mode 100644 index 00000000..9299cafa --- /dev/null +++ b/pkg/port/server.go @@ -0,0 +1,58 @@ +// SPDX-License-Identifier: Apache-2.0 +// Copyright (c) 2022-2023 Dell Inc, or its subsidiaries. + +// Package port is the main package of the application +package port + +import ( + "log" + + "go.opentelemetry.io/otel" + "go.opentelemetry.io/otel/trace" + + "github.com/philippgille/gokv" + + pb "github.com/opiproject/opi-api/network/evpn-gw/v1alpha1/gen/go" + + "github.com/opiproject/opi-evpn-bridge/pkg/utils" +) + +// Server represents the Server object +type Server struct { + pb.UnimplementedBridgePortServiceServer + Pagination map[string]int + ListHelper map[string]bool + nLink utils.Netlink + frr utils.Frr + tracer trace.Tracer + store gokv.Store +} + +// NewServer creates initialized instance of EVPN server +func NewServer(store gokv.Store) *Server { + nLink := utils.NewNetlinkWrapper() + frr := utils.NewFrrWrapper() + return NewServerWithArgs(nLink, frr, store) +} + +// NewServerWithArgs creates initialized instance of EVPN server +// with externally created Netlink +func NewServerWithArgs(nLink utils.Netlink, frr utils.Frr, store gokv.Store) *Server { + if frr == nil { + log.Panic("nil for Frr is not allowed") + } + if nLink == nil { + log.Panic("nil for Netlink is not allowed") + } + if store == nil { + log.Panic("nil for Store is not allowed") + } + return &Server{ + ListHelper: make(map[string]bool), + Pagination: make(map[string]int), + nLink: nLink, + frr: frr, + tracer: otel.Tracer(""), + store: store, + } +} diff --git a/pkg/port/server_test.go b/pkg/port/server_test.go new file mode 100644 index 00000000..a34bfadb --- /dev/null +++ b/pkg/port/server_test.go @@ -0,0 +1,64 @@ +// SPDX-License-Identifier: Apache-2.0 +// Copyright (c) 2022-2023 Dell Inc, or its subsidiaries. + +// Package port is the main package of the application +package port + +import ( + "testing" + + "github.com/philippgille/gokv" + "github.com/philippgille/gokv/gomap" + + "github.com/opiproject/opi-evpn-bridge/pkg/utils" +) + +func TestFrontEnd_NewServerWithArgs(t *testing.T) { + tests := map[string]struct { + frr utils.Frr + nLink utils.Netlink + store gokv.Store + wantPanic bool + }{ + "nil netlink argument": { + frr: &utils.FrrWrapper{}, + nLink: nil, + store: gomap.NewStore(gomap.DefaultOptions), + wantPanic: true, + }, + "nil store argument": { + frr: &utils.FrrWrapper{}, + nLink: &utils.NetlinkWrapper{}, + store: nil, + wantPanic: true, + }, + "nil frr argument": { + frr: nil, + nLink: &utils.NetlinkWrapper{}, + store: gomap.NewStore(gomap.DefaultOptions), + wantPanic: true, + }, + "all valid arguments": { + frr: &utils.FrrWrapper{}, + nLink: &utils.NetlinkWrapper{}, + store: gomap.NewStore(gomap.DefaultOptions), + wantPanic: false, + }, + } + + for testName, tt := range tests { + t.Run(testName, func(t *testing.T) { + defer func() { + r := recover() + if (r != nil) != tt.wantPanic { + t.Errorf("NewServerWithArgs() recover = %v, wantPanic = %v", r, tt.wantPanic) + } + }() + + server := NewServerWithArgs(tt.nLink, tt.frr, tt.store) + if server == nil && !tt.wantPanic { + t.Error("expected non nil server or panic") + } + }) + } +} diff --git a/pkg/svi/common.go b/pkg/svi/common.go new file mode 100644 index 00000000..6e337b45 --- /dev/null +++ b/pkg/svi/common.go @@ -0,0 +1,164 @@ +// SPDX-License-Identifier: Apache-2.0 +// Copyright (c) 2022-2023 Dell Inc, or its subsidiaries. + +// Package svi is the main package of the application +package svi + +import ( + "context" + "fmt" + "log" + "net" + + "google.golang.org/grpc" + "google.golang.org/grpc/codes" + "google.golang.org/grpc/status" + "google.golang.org/grpc/test/bufconn" + "google.golang.org/protobuf/proto" + + pb "github.com/opiproject/opi-api/network/evpn-gw/v1alpha1/gen/go" + pc "github.com/opiproject/opi-api/network/opinetcommon/v1alpha1/gen/go" +) + +// TODO: move all of this to a common place +const ( + tenantbridgeName = "br-tenant" +) + +var ( + testLogicalBridgeID = "opi-bridge9" + testLogicalBridgeName = resourceIDToFullName("bridges", testLogicalBridgeID) + testLogicalBridge = pb.LogicalBridge{ + Spec: &pb.LogicalBridgeSpec{ + Vni: proto.Uint32(11), + VlanId: 22, + VtepIpPrefix: &pc.IPPrefix{ + Addr: &pc.IPAddress{ + Af: pc.IpAf_IP_AF_INET, + V4OrV6: &pc.IPAddress_V4Addr{ + V4Addr: 167772162, + }, + }, + Len: 24, + }, + }, + } + testLogicalBridgeWithStatus = pb.LogicalBridge{ + Name: testLogicalBridgeName, + Spec: testLogicalBridge.Spec, + Status: &pb.LogicalBridgeStatus{ + OperStatus: pb.LBOperStatus_LB_OPER_STATUS_UP, + }, + } + + testVrfID = "opi-vrf8" + testVrfName = resourceIDToFullName("vrfs", testVrfID) + testVrf = pb.Vrf{ + Spec: &pb.VrfSpec{ + Vni: proto.Uint32(1000), + LoopbackIpPrefix: &pc.IPPrefix{ + // Addr: &pc.IPAddress{ + // Af: pc.IpAf_IP_AF_INET, + // V4OrV6: &pc.IPAddress_V4Addr{ + // V4Addr: 167772162, + // }, + // }, + Len: 24, + }, + VtepIpPrefix: &pc.IPPrefix{ + Addr: &pc.IPAddress{ + Af: pc.IpAf_IP_AF_INET, + V4OrV6: &pc.IPAddress_V4Addr{ + V4Addr: 167772162, + }, + }, + Len: 24, + }, + }, + } + testVrfWithStatus = pb.Vrf{ + Name: testVrfName, + Spec: testVrf.Spec, + Status: &pb.VrfStatus{ + LocalAs: 4, + }, + } +) + +func resourceIDToFullName(_ string, resourceID string) string { + return fmt.Sprintf("//network.opiproject.org/svis/%s", resourceID) +} + +func protoClone[T proto.Message](protoStruct T) T { + return proto.Clone(protoStruct).(T) +} + +func extractPagination(pageSize int32, pageToken string, pagination map[string]int) (size int, offset int, err error) { + const ( + maxPageSize = 250 + defaultPageSize = 50 + ) + switch { + case pageSize < 0: + return -1, -1, status.Error(codes.InvalidArgument, "negative PageSize is not allowed") + case pageSize == 0: + size = defaultPageSize + case pageSize > maxPageSize: + size = maxPageSize + default: + size = int(pageSize) + } + // fetch offset from the database using opaque token + offset = 0 + if pageToken != "" { + var ok bool + offset, ok = pagination[pageToken] + if !ok { + return -1, -1, status.Errorf(codes.NotFound, "unable to find pagination token %s", pageToken) + } + log.Printf("Found offset %d from pagination token: %s", offset, pageToken) + } + return size, offset, nil +} + +func limitPagination[T any](result []T, offset int, size int) ([]T, bool) { + end := offset + size + hasMoreElements := false + if end < len(result) { + hasMoreElements = true + } else { + end = len(result) + } + return result[offset:end], hasMoreElements +} + +func dialer(opi *Server) func(context.Context, string) (net.Conn, error) { + listener := bufconn.Listen(1024 * 1024) + server := grpc.NewServer() + + pb.RegisterSviServiceServer(server, opi) + + go func() { + if err := server.Serve(listener); err != nil { + log.Fatal(err) + } + }() + + return func(context.Context, string) (net.Conn, error) { + return listener.Dial() + } +} + +func equalProtoSlices[T proto.Message](x, y []T) bool { + if len(x) != len(y) { + return false + } + + for i := 0; i < len(x); i++ { + if !proto.Equal(x[i], y[i]) { + return false + } + } + + return true +} diff --git a/pkg/svi/server.go b/pkg/svi/server.go new file mode 100644 index 00000000..e67f7425 --- /dev/null +++ b/pkg/svi/server.go @@ -0,0 +1,58 @@ +// SPDX-License-Identifier: Apache-2.0 +// Copyright (c) 2022-2023 Dell Inc, or its subsidiaries. + +// Package svi is the main package of the application +package svi + +import ( + "log" + + "go.opentelemetry.io/otel" + "go.opentelemetry.io/otel/trace" + + "github.com/philippgille/gokv" + + pb "github.com/opiproject/opi-api/network/evpn-gw/v1alpha1/gen/go" + + "github.com/opiproject/opi-evpn-bridge/pkg/utils" +) + +// Server represents the Server object +type Server struct { + pb.UnimplementedSviServiceServer + Pagination map[string]int + ListHelper map[string]bool + nLink utils.Netlink + frr utils.Frr + tracer trace.Tracer + store gokv.Store +} + +// NewServer creates initialized instance of EVPN server +func NewServer(store gokv.Store) *Server { + nLink := utils.NewNetlinkWrapper() + frr := utils.NewFrrWrapper() + return NewServerWithArgs(nLink, frr, store) +} + +// NewServerWithArgs creates initialized instance of EVPN server +// with externally created Netlink +func NewServerWithArgs(nLink utils.Netlink, frr utils.Frr, store gokv.Store) *Server { + if frr == nil { + log.Panic("nil for Frr is not allowed") + } + if nLink == nil { + log.Panic("nil for Netlink is not allowed") + } + if store == nil { + log.Panic("nil for Store is not allowed") + } + return &Server{ + ListHelper: make(map[string]bool), + Pagination: make(map[string]int), + nLink: nLink, + frr: frr, + tracer: otel.Tracer(""), + store: store, + } +} diff --git a/pkg/svi/server_test.go b/pkg/svi/server_test.go new file mode 100644 index 00000000..5f55b0bb --- /dev/null +++ b/pkg/svi/server_test.go @@ -0,0 +1,64 @@ +// SPDX-License-Identifier: Apache-2.0 +// Copyright (c) 2022-2023 Dell Inc, or its subsidiaries. + +// Package svi is the main package of the application +package svi + +import ( + "testing" + + "github.com/philippgille/gokv" + "github.com/philippgille/gokv/gomap" + + "github.com/opiproject/opi-evpn-bridge/pkg/utils" +) + +func TestFrontEnd_NewServerWithArgs(t *testing.T) { + tests := map[string]struct { + frr utils.Frr + nLink utils.Netlink + store gokv.Store + wantPanic bool + }{ + "nil netlink argument": { + frr: &utils.FrrWrapper{}, + nLink: nil, + store: gomap.NewStore(gomap.DefaultOptions), + wantPanic: true, + }, + "nil store argument": { + frr: &utils.FrrWrapper{}, + nLink: &utils.NetlinkWrapper{}, + store: nil, + wantPanic: true, + }, + "nil frr argument": { + frr: nil, + nLink: &utils.NetlinkWrapper{}, + store: gomap.NewStore(gomap.DefaultOptions), + wantPanic: true, + }, + "all valid arguments": { + frr: &utils.FrrWrapper{}, + nLink: &utils.NetlinkWrapper{}, + store: gomap.NewStore(gomap.DefaultOptions), + wantPanic: false, + }, + } + + for testName, tt := range tests { + t.Run(testName, func(t *testing.T) { + defer func() { + r := recover() + if (r != nil) != tt.wantPanic { + t.Errorf("NewServerWithArgs() recover = %v, wantPanic = %v", r, tt.wantPanic) + } + }() + + server := NewServerWithArgs(tt.nLink, tt.frr, tt.store) + if server == nil && !tt.wantPanic { + t.Error("expected non nil server or panic") + } + }) + } +} diff --git a/pkg/svi/svi.go b/pkg/svi/svi.go index e8d114c1..ac80084f 100644 --- a/pkg/svi/svi.go +++ b/pkg/svi/svi.go @@ -2,8 +2,8 @@ // Copyright (c) 2022-2023 Intel Corporation, or its subsidiaries. // Copyright (c) 2022-2023 Dell Inc, or its subsidiaries. -// Package evpn is the main package of the application -package evpn +// Package svi is the main package of the application +package svi import ( "context" diff --git a/pkg/svi/svi_frr.go b/pkg/svi/svi_frr.go index 46886bfa..74f5132a 100644 --- a/pkg/svi/svi_frr.go +++ b/pkg/svi/svi_frr.go @@ -1,8 +1,8 @@ // SPDX-License-Identifier: Apache-2.0 // Copyright (c) 2022-2023 Dell Inc, or its subsidiaries. -// Package evpn is the main package of the application -package evpn +// Package svi is the main package of the application +package svi import ( "context" diff --git a/pkg/svi/svi_netlink.go b/pkg/svi/svi_netlink.go index 1912e01a..175b3bfd 100644 --- a/pkg/svi/svi_netlink.go +++ b/pkg/svi/svi_netlink.go @@ -2,8 +2,8 @@ // Copyright (c) 2022-2023 Intel Corporation, or its subsidiaries. // Copyright (c) 2022-2023 Dell Inc, or its subsidiaries. -// Package evpn is the main package of the application -package evpn +// Package svi is the main package of the application +package svi import ( "context" diff --git a/pkg/svi/svi_test.go b/pkg/svi/svi_test.go index 38b0f8a0..f42f6ad9 100644 --- a/pkg/svi/svi_test.go +++ b/pkg/svi/svi_test.go @@ -2,8 +2,8 @@ // Copyright (c) 2022-2023 Intel Corporation, or its subsidiaries. // Copyright (c) 2022-2023 Dell Inc, or its subsidiaries. -// Package evpn is the main package of the application -package evpn +// Package svi is the main package of the application +package svi import ( "context" diff --git a/pkg/svi/svi_validate.go b/pkg/svi/svi_validate.go index 76f5d688..f1b77bd6 100644 --- a/pkg/svi/svi_validate.go +++ b/pkg/svi/svi_validate.go @@ -1,8 +1,8 @@ // SPDX-License-Identifier: Apache-2.0 // Copyright (c) 2022-2023 Dell Inc, or its subsidiaries. -// Package evpn is the main package of the application -package evpn +// Package svi is the main package of the application +package svi import ( "go.einride.tech/aip/fieldbehavior" diff --git a/pkg/vrf/common.go b/pkg/vrf/common.go new file mode 100644 index 00000000..cde7fc76 --- /dev/null +++ b/pkg/vrf/common.go @@ -0,0 +1,112 @@ +// SPDX-License-Identifier: Apache-2.0 +// Copyright (c) 2022-2023 Dell Inc, or its subsidiaries. + +// Package vrf is the main package of the application +package vrf + +import ( + "context" + "crypto/rand" + "fmt" + "log" + "net" + + "google.golang.org/grpc" + "google.golang.org/grpc/codes" + "google.golang.org/grpc/status" + "google.golang.org/grpc/test/bufconn" + "google.golang.org/protobuf/proto" + + pb "github.com/opiproject/opi-api/network/evpn-gw/v1alpha1/gen/go" +) + +// TODO: move all of this to a common place +func resourceIDToFullName(_ string, resourceID string) string { + return fmt.Sprintf("//network.opiproject.org/vrfs/%s", resourceID) +} + +func protoClone[T proto.Message](protoStruct T) T { + return proto.Clone(protoStruct).(T) +} + +func generateRandMAC() ([]byte, error) { + buf := make([]byte, 6) + if _, err := rand.Read(buf); err != nil { + return nil, fmt.Errorf("unable to retrieve 6 rnd bytes: %s", err) + } + + // Set locally administered addresses bit and reset multicast bit + buf[0] = (buf[0] | 0x02) & 0xfe + + return buf, nil +} + +func extractPagination(pageSize int32, pageToken string, pagination map[string]int) (size int, offset int, err error) { + const ( + maxPageSize = 250 + defaultPageSize = 50 + ) + switch { + case pageSize < 0: + return -1, -1, status.Error(codes.InvalidArgument, "negative PageSize is not allowed") + case pageSize == 0: + size = defaultPageSize + case pageSize > maxPageSize: + size = maxPageSize + default: + size = int(pageSize) + } + // fetch offset from the database using opaque token + offset = 0 + if pageToken != "" { + var ok bool + offset, ok = pagination[pageToken] + if !ok { + return -1, -1, status.Errorf(codes.NotFound, "unable to find pagination token %s", pageToken) + } + log.Printf("Found offset %d from pagination token: %s", offset, pageToken) + } + return size, offset, nil +} + +func limitPagination[T any](result []T, offset int, size int) ([]T, bool) { + end := offset + size + hasMoreElements := false + if end < len(result) { + hasMoreElements = true + } else { + end = len(result) + } + return result[offset:end], hasMoreElements +} + +func dialer(opi *Server) func(context.Context, string) (net.Conn, error) { + listener := bufconn.Listen(1024 * 1024) + server := grpc.NewServer() + + pb.RegisterVrfServiceServer(server, opi) + + go func() { + if err := server.Serve(listener); err != nil { + log.Fatal(err) + } + }() + + return func(context.Context, string) (net.Conn, error) { + return listener.Dial() + } +} + +func equalProtoSlices[T proto.Message](x, y []T) bool { + if len(x) != len(y) { + return false + } + + for i := 0; i < len(x); i++ { + if !proto.Equal(x[i], y[i]) { + return false + } + } + + return true +} diff --git a/pkg/vrf/server.go b/pkg/vrf/server.go new file mode 100644 index 00000000..42631aae --- /dev/null +++ b/pkg/vrf/server.go @@ -0,0 +1,58 @@ +// SPDX-License-Identifier: Apache-2.0 +// Copyright (c) 2022-2023 Dell Inc, or its subsidiaries. + +// Package vrf is the main package of the application +package vrf + +import ( + "log" + + "go.opentelemetry.io/otel" + "go.opentelemetry.io/otel/trace" + + "github.com/philippgille/gokv" + + pb "github.com/opiproject/opi-api/network/evpn-gw/v1alpha1/gen/go" + + "github.com/opiproject/opi-evpn-bridge/pkg/utils" +) + +// Server represents the Server object +type Server struct { + pb.UnimplementedVrfServiceServer + Pagination map[string]int + ListHelper map[string]bool + nLink utils.Netlink + frr utils.Frr + tracer trace.Tracer + store gokv.Store +} + +// NewServer creates initialized instance of EVPN server +func NewServer(store gokv.Store) *Server { + nLink := utils.NewNetlinkWrapper() + frr := utils.NewFrrWrapper() + return NewServerWithArgs(nLink, frr, store) +} + +// NewServerWithArgs creates initialized instance of EVPN server +// with externally created Netlink +func NewServerWithArgs(nLink utils.Netlink, frr utils.Frr, store gokv.Store) *Server { + if frr == nil { + log.Panic("nil for Frr is not allowed") + } + if nLink == nil { + log.Panic("nil for Netlink is not allowed") + } + if store == nil { + log.Panic("nil for Store is not allowed") + } + return &Server{ + ListHelper: make(map[string]bool), + Pagination: make(map[string]int), + nLink: nLink, + frr: frr, + tracer: otel.Tracer(""), + store: store, + } +} diff --git a/pkg/vrf/server_test.go b/pkg/vrf/server_test.go new file mode 100644 index 00000000..8a6fd167 --- /dev/null +++ b/pkg/vrf/server_test.go @@ -0,0 +1,64 @@ +// SPDX-License-Identifier: Apache-2.0 +// Copyright (c) 2022-2023 Dell Inc, or its subsidiaries. + +// Package vrf is the main package of the application +package vrf + +import ( + "testing" + + "github.com/philippgille/gokv" + "github.com/philippgille/gokv/gomap" + + "github.com/opiproject/opi-evpn-bridge/pkg/utils" +) + +func TestFrontEnd_NewServerWithArgs(t *testing.T) { + tests := map[string]struct { + frr utils.Frr + nLink utils.Netlink + store gokv.Store + wantPanic bool + }{ + "nil netlink argument": { + frr: &utils.FrrWrapper{}, + nLink: nil, + store: gomap.NewStore(gomap.DefaultOptions), + wantPanic: true, + }, + "nil store argument": { + frr: &utils.FrrWrapper{}, + nLink: &utils.NetlinkWrapper{}, + store: nil, + wantPanic: true, + }, + "nil frr argument": { + frr: nil, + nLink: &utils.NetlinkWrapper{}, + store: gomap.NewStore(gomap.DefaultOptions), + wantPanic: true, + }, + "all valid arguments": { + frr: &utils.FrrWrapper{}, + nLink: &utils.NetlinkWrapper{}, + store: gomap.NewStore(gomap.DefaultOptions), + wantPanic: false, + }, + } + + for testName, tt := range tests { + t.Run(testName, func(t *testing.T) { + defer func() { + r := recover() + if (r != nil) != tt.wantPanic { + t.Errorf("NewServerWithArgs() recover = %v, wantPanic = %v", r, tt.wantPanic) + } + }() + + server := NewServerWithArgs(tt.nLink, tt.frr, tt.store) + if server == nil && !tt.wantPanic { + t.Error("expected non nil server or panic") + } + }) + } +} diff --git a/pkg/vrf/vrf.go b/pkg/vrf/vrf.go index 610773cd..26996d38 100644 --- a/pkg/vrf/vrf.go +++ b/pkg/vrf/vrf.go @@ -2,8 +2,8 @@ // Copyright (c) 2022-2023 Intel Corporation, or its subsidiaries. // Copyright (c) 2022-2023 Dell Inc, or its subsidiaries. -// Package evpn is the main package of the application -package evpn +// Package vrf is the main package of the application +package vrf import ( "context" diff --git a/pkg/vrf/vrf_frr.go b/pkg/vrf/vrf_frr.go index b06d916f..92b103dd 100644 --- a/pkg/vrf/vrf_frr.go +++ b/pkg/vrf/vrf_frr.go @@ -1,8 +1,8 @@ // SPDX-License-Identifier: Apache-2.0 // Copyright (c) 2022-2023 Dell Inc, or its subsidiaries. -// Package evpn is the main package of the application -package evpn +// Package vrf is the main package of the application +package vrf import ( "context" diff --git a/pkg/vrf/vrf_netlink.go b/pkg/vrf/vrf_netlink.go index a61f2062..e93d0a5c 100644 --- a/pkg/vrf/vrf_netlink.go +++ b/pkg/vrf/vrf_netlink.go @@ -2,8 +2,8 @@ // Copyright (c) 2022-2023 Intel Corporation, or its subsidiaries. // Copyright (c) 2022-2023 Dell Inc, or its subsidiaries. -// Package evpn is the main package of the application -package evpn +// Package vrf is the main package of the application +package vrf import ( "context" diff --git a/pkg/vrf/vrf_test.go b/pkg/vrf/vrf_test.go index 1a36ea13..d5e88db5 100644 --- a/pkg/vrf/vrf_test.go +++ b/pkg/vrf/vrf_test.go @@ -2,8 +2,8 @@ // Copyright (c) 2022-2023 Intel Corporation, or its subsidiaries. // Copyright (c) 2022-2023 Dell Inc, or its subsidiaries. -// Package evpn is the main package of the application -package evpn +// Package vrf is the main package of the application +package vrf import ( "context" diff --git a/pkg/vrf/vrf_validate.go b/pkg/vrf/vrf_validate.go index 31360830..ccc7d591 100644 --- a/pkg/vrf/vrf_validate.go +++ b/pkg/vrf/vrf_validate.go @@ -1,8 +1,8 @@ // SPDX-License-Identifier: Apache-2.0 // Copyright (c) 2022-2023 Dell Inc, or its subsidiaries. -// Package evpn is the main package of the application -package evpn +// Package vrf is the main package of the application +package vrf import ( "go.einride.tech/aip/fieldbehavior"