Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
88 changes: 4 additions & 84 deletions internal/deviceutil/deviceutil.go
Original file line number Diff line number Diff line change
Expand Up @@ -8,11 +8,7 @@ import (
"crypto/x509"
"errors"
"fmt"
"time"

"google.golang.org/grpc"
"google.golang.org/grpc/credentials"
"google.golang.org/grpc/credentials/insecure"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/apimachinery/pkg/labels"
"k8s.io/apimachinery/pkg/runtime/schema"
Expand Down Expand Up @@ -58,17 +54,19 @@ func GetOwnerDevice(ctx context.Context, r client.Reader, obj metav1.Object) (*v
func GetDeviceByName(ctx context.Context, r client.Reader, namespace, name string) (*v1alpha1.Device, error) {
obj := new(v1alpha1.Device)
if err := r.Get(ctx, client.ObjectKey{Namespace: namespace, Name: name}, obj); err != nil {
return nil, fmt.Errorf("failed to get %s/%s", v1alpha1.GroupVersion.WithKind(v1alpha1.DeviceKind).String(), name)
return nil, fmt.Errorf("failed to get %s/%s: %w", v1alpha1.GroupVersion.WithKind(v1alpha1.DeviceKind).String(), name, err)
}
return obj, nil
}

// GetDeviceBySerial finds and returns a Device object using the specified serial number.
// It returns an error if no device or multiple devices with the same serial number are found.
// Note: This function assumes that the [v1alpha1.DeviceSerialLabel] is unique across all Device objects in the cluster.
func GetDeviceBySerial(ctx context.Context, r client.Reader, namespace, serial string) (*v1alpha1.Device, error) {
deviceList := &v1alpha1.DeviceList{}
listOpts := &client.ListOptions{
LabelSelector: labels.SelectorFromSet(labels.Set{v1alpha1.DeviceSerialLabel: serial}),
}

if err := r.List(ctx, deviceList, listOpts); err != nil {
return nil, fmt.Errorf("failed to list %s objects: %w", v1alpha1.GroupVersion.WithKind(v1alpha1.DeviceKind).String(), err)
}
Expand All @@ -82,8 +80,6 @@ func GetDeviceBySerial(ctx context.Context, r client.Reader, namespace, serial s
}

// Connection holds the necessary information to connect to a device's API.
//
// TODO(felix-kaestner): find a better place for this struct, maybe in a 'connection' package?
type Connection struct {
// Address is the API address of the device, in the format "host:port".
Address string
Expand Down Expand Up @@ -140,79 +136,3 @@ func GetDeviceConnection(ctx context.Context, r client.Reader, obj *v1alpha1.Dev
TLS: conf,
}, nil
}

// NewGrpcClient creates a new gRPC client connection to a specified device using the provided [Connection].
// The connection will use TLS if the [Connection.TLS] field is set, otherwise it will use an insecure connection.
// If the [Connection.Username] and [Connection.Password] fields are set, basic authentication in the form of metadata will be used.
func NewGrpcClient(ctx context.Context, conn *Connection, o ...Option) (*grpc.ClientConn, error) {
creds := insecure.NewCredentials()
if conn.TLS != nil {
creds = credentials.NewTLS(conn.TLS)
}

opts := []grpc.DialOption{grpc.WithTransportCredentials(creds)}
if conn.Username != "" && conn.Password != "" {
opts = append(opts, grpc.WithPerRPCCredentials(&auth{
Username: conn.Username,
Password: conn.Password,
}))
}

for _, opt := range o {
dialOpt, err := opt()
if err != nil {
return nil, err
}
opts = append(opts, dialOpt)
}

return grpc.NewClient(conn.Address, opts...)
}

type Option func() (grpc.DialOption, error)

// WithDefaultTimeout returns a gRPC dial option that sets a default timeout for each RPC.
// If a deadline is already present in the context, it will not be modified.
func WithDefaultTimeout(timeout time.Duration) Option {
return func() (grpc.DialOption, error) {
if timeout <= 0 {
return nil, errors.New("timeout must be greater than zero")
}
return grpc.WithUnaryInterceptor(UnaryDefaultTimeoutInterceptor(timeout)), nil
}
}

type auth struct {
Username string
Password string // #nosec G117
SecureTransportCreds bool
}

var _ credentials.PerRPCCredentials = (*auth)(nil)

func (a *auth) GetRequestMetadata(_ context.Context, _ ...string) (map[string]string, error) {
return map[string]string{
"username": a.Username,
"password": a.Password,
}, nil
}

func (a *auth) RequireTransportSecurity() bool {
// Only called if the transport credentials are insecure.
return false
}

// UnaryDefaultTimeoutInterceptor returns a gRPC unary client interceptor that sets a default timeout
// for each RPC. If a deadline is already present , it will not be modified.
func UnaryDefaultTimeoutInterceptor(timeout time.Duration) grpc.UnaryClientInterceptor {
return func(ctx context.Context, method string, req, reply any, cc *grpc.ClientConn, invoker grpc.UnaryInvoker, opts ...grpc.CallOption) error {
if _, ok := ctx.Deadline(); ok {
return invoker(ctx, method, req, reply, cc, opts...)
}

ctx, cancel := context.WithTimeout(ctx, timeout)
defer cancel()

return invoker(ctx, method, req, reply, cc, opts...)
}
}
2 changes: 1 addition & 1 deletion internal/provider/cisco/iosxr/intf.go
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ import (
"fmt"
"regexp"

"github.com/ironcore-dev/network-operator/internal/provider/cisco/gnmiext/v2"
"github.com/ironcore-dev/network-operator/internal/transport/gnmiext"
)

type PhysIf struct {
Expand Down
8 changes: 4 additions & 4 deletions internal/provider/cisco/iosxr/provider.go
Original file line number Diff line number Diff line change
Expand Up @@ -9,11 +9,11 @@ import (
"fmt"
"strconv"

"github.com/ironcore-dev/network-operator/api/core/v1alpha1"
"github.com/ironcore-dev/network-operator/internal/deviceutil"
"github.com/ironcore-dev/network-operator/internal/provider"
"github.com/ironcore-dev/network-operator/internal/provider/cisco/gnmiext/v2"

"github.com/ironcore-dev/network-operator/api/core/v1alpha1"
"github.com/ironcore-dev/network-operator/internal/transport/gnmiext"
"github.com/ironcore-dev/network-operator/internal/transport/grpcext"

"google.golang.org/grpc"
)
Expand All @@ -33,7 +33,7 @@ func NewProvider() provider.Provider {
}

func (p *Provider) Connect(ctx context.Context, conn *deviceutil.Connection) (err error) {
p.conn, err = deviceutil.NewGrpcClient(ctx, conn)
p.conn, err = grpcext.NewClient(ctx, conn)
if err != nil {
return fmt.Errorf("failed to create grpc connection: %w", err)
}
Expand Down
40 changes: 20 additions & 20 deletions internal/provider/cisco/iosxr/provider_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -16,17 +16,17 @@ import (

"github.com/ironcore-dev/network-operator/api/core/v1alpha1"
"github.com/ironcore-dev/network-operator/internal/provider"
"github.com/ironcore-dev/network-operator/internal/provider/cisco/gnmiext/v2"
"github.com/ironcore-dev/network-operator/internal/transport/gnmiext"
)

type TestCase struct {
name string
val gnmiext.Configurable
val gnmiext.DataElement
}

var tests []TestCase

func Register(name string, val gnmiext.Configurable) {
func Register(name string, val gnmiext.DataElement) {
tests = append(tests, TestCase{
name: name,
val: val,
Expand Down Expand Up @@ -92,11 +92,11 @@ func Test_Payload(t *testing.T) {
type MockClient struct {
// Function fields for mocking different methods
CapabilitiesFunc func() *gnmiext.Capabilities
GetConfigFunc func(ctx context.Context, conf ...gnmiext.Configurable) error
PatchFunc func(ctx context.Context, conf ...gnmiext.Configurable) error
UpdateFunc func(ctx context.Context, conf ...gnmiext.Configurable) error
DeleteFunc func(ctx context.Context, conf ...gnmiext.Configurable) error
GetStateFunc func(ctx context.Context, conf ...gnmiext.Configurable) error
GetConfigFunc func(ctx context.Context, configs ...gnmiext.DataElement) error
PatchFunc func(ctx context.Context, patches ...gnmiext.DataElement) error
UpdateFunc func(ctx context.Context, updates ...gnmiext.DataElement) error
DeleteFunc func(ctx context.Context, deletes ...gnmiext.DataElement) error
GetStateFunc func(ctx context.Context, states ...gnmiext.DataElement) error
}

var _ gnmiext.Client = (*MockClient)(nil)
Expand All @@ -109,37 +109,37 @@ func (m *MockClient) Capabilities() *gnmiext.Capabilities {
return nil
}

func (m *MockClient) GetConfig(ctx context.Context, conf ...gnmiext.Configurable) error {
func (m *MockClient) GetConfig(ctx context.Context, configs ...gnmiext.DataElement) error {
if m.GetConfigFunc != nil {
return m.GetConfigFunc(ctx, conf...)
return m.GetConfigFunc(ctx, configs...)
}
return nil
}

func (m *MockClient) GetState(ctx context.Context, conf ...gnmiext.Configurable) error {
func (m *MockClient) GetState(ctx context.Context, states ...gnmiext.DataElement) error {
if m.GetStateFunc != nil {
return m.GetStateFunc(ctx, conf...)
return m.GetStateFunc(ctx, states...)
}
return nil
}

func (m *MockClient) Patch(ctx context.Context, conf ...gnmiext.Configurable) error {
func (m *MockClient) Patch(ctx context.Context, patches ...gnmiext.DataElement) error {
if m.PatchFunc != nil {
return m.PatchFunc(ctx, conf...)
return m.PatchFunc(ctx, patches...)
}
return nil
}

func (m *MockClient) Update(ctx context.Context, conf ...gnmiext.Configurable) error {
func (m *MockClient) Update(ctx context.Context, updates ...gnmiext.DataElement) error {
if m.UpdateFunc != nil {
return m.UpdateFunc(ctx, conf...)
return m.UpdateFunc(ctx, updates...)
}
return nil
}

func (m *MockClient) Delete(ctx context.Context, conf ...gnmiext.Configurable) error {
func (m *MockClient) Delete(ctx context.Context, deletes ...gnmiext.DataElement) error {
if m.DeleteFunc != nil {
return m.DeleteFunc(ctx, conf...)
return m.DeleteFunc(ctx, deletes...)
}
return nil
}
Expand Down Expand Up @@ -187,8 +187,8 @@ func Test_EnsureInterface(t *testing.T) {

func Test_GetState(t *testing.T) {
m := &MockClient{
GetStateFunc: func(ctx context.Context, conf ...gnmiext.Configurable) error {
conf[0].(*PhysIfState).State = "im-state-up"
GetStateFunc: func(ctx context.Context, states ...gnmiext.DataElement) error {
states[0].(*PhysIfState).State = "im-state-up"
return nil
},
}
Expand Down
4 changes: 2 additions & 2 deletions internal/provider/cisco/nxos/acl.go
Original file line number Diff line number Diff line change
Expand Up @@ -7,10 +7,10 @@ import (
"fmt"

"github.com/ironcore-dev/network-operator/api/core/v1alpha1"
"github.com/ironcore-dev/network-operator/internal/provider/cisco/gnmiext/v2"
"github.com/ironcore-dev/network-operator/internal/transport/gnmiext"
)

var _ gnmiext.Configurable = (*ACL)(nil)
var _ gnmiext.DataElement = (*ACL)(nil)

// ACL represents an IPv4 or IPv6 access control list, depending on the rules it contains.
// It can only contain either IPv4 or IPv6 rules, never both. It's name must be unique
Expand Down
6 changes: 3 additions & 3 deletions internal/provider/cisco/nxos/banner.go
Original file line number Diff line number Diff line change
Expand Up @@ -7,12 +7,12 @@ import (
"fmt"

"github.com/ironcore-dev/network-operator/api/core/v1alpha1"
"github.com/ironcore-dev/network-operator/internal/provider/cisco/gnmiext/v2"
"github.com/ironcore-dev/network-operator/internal/transport/gnmiext"
)

var (
_ gnmiext.Configurable = (*Banner)(nil)
_ gnmiext.Defaultable = (*Banner)(nil)
_ gnmiext.DataElement = (*Banner)(nil)
_ gnmiext.Defaultable = (*Banner)(nil)
)

// Banner represents the pre-login banner configuration of the device.
Expand Down
6 changes: 3 additions & 3 deletions internal/provider/cisco/nxos/bgp.go
Original file line number Diff line number Diff line change
Expand Up @@ -10,12 +10,12 @@ import (

nxv1alpha1 "github.com/ironcore-dev/network-operator/api/cisco/nx/v1alpha1"
"github.com/ironcore-dev/network-operator/api/core/v1alpha1"
"github.com/ironcore-dev/network-operator/internal/provider/cisco/gnmiext/v2"
"github.com/ironcore-dev/network-operator/internal/transport/gnmiext"
)

var (
_ gnmiext.Configurable = (*BGP)(nil)
_ gnmiext.Configurable = (*BGPDom)(nil)
_ gnmiext.DataElement = (*BGP)(nil)
_ gnmiext.DataElement = (*BGPDom)(nil)
)

type BGP struct {
Expand Down
4 changes: 2 additions & 2 deletions internal/provider/cisco/nxos/bgw.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,10 +4,10 @@
package nxos

import (
"github.com/ironcore-dev/network-operator/internal/provider/cisco/gnmiext/v2"
"github.com/ironcore-dev/network-operator/internal/transport/gnmiext"
)

var _ gnmiext.Configurable = (*MultisiteItems)(nil)
var _ gnmiext.DataElement = (*MultisiteItems)(nil)

type MultisiteItems struct {
SiteID string `json:"siteId"`
Expand Down
6 changes: 3 additions & 3 deletions internal/provider/cisco/nxos/cert.go
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ import (
"github.com/openconfig/gnoi/cert"
"google.golang.org/grpc"

"github.com/ironcore-dev/network-operator/internal/provider/cisco/gnmiext/v2"
"github.com/ironcore-dev/network-operator/internal/transport/gnmiext"
)

// Certificate represents a X.509 certificate and its associated private key.
Expand Down Expand Up @@ -91,8 +91,8 @@ func (c *Certificate) EncodeKeyPair() (private, public []byte, err error) {
}

var (
_ gnmiext.Configurable = (*Trustpoint)(nil)
_ gnmiext.Configurable = (*KeyPair)(nil)
_ gnmiext.DataElement = (*Trustpoint)(nil)
_ gnmiext.DataElement = (*KeyPair)(nil)
)

// Trustpoint represents a PKI trustpoint configuration on a NX-OS device.
Expand Down
4 changes: 2 additions & 2 deletions internal/provider/cisco/nxos/dhcprelay.go
Original file line number Diff line number Diff line change
Expand Up @@ -6,10 +6,10 @@ package nxos
import (
"net/netip"

"github.com/ironcore-dev/network-operator/internal/provider/cisco/gnmiext/v2"
"github.com/ironcore-dev/network-operator/internal/transport/gnmiext"
)

var _ gnmiext.Configurable = (*DHCPRelayConfig)(nil)
var _ gnmiext.DataElement = (*DHCPRelayConfig)(nil)

// DHCPRelayConfig represents the complete DHCP relay configuration tree.
type DHCPRelayConfig struct {
Expand Down
4 changes: 2 additions & 2 deletions internal/provider/cisco/nxos/dns.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,9 +3,9 @@

package nxos

import "github.com/ironcore-dev/network-operator/internal/provider/cisco/gnmiext/v2"
import "github.com/ironcore-dev/network-operator/internal/transport/gnmiext"

var _ gnmiext.Configurable = (*DNS)(nil)
var _ gnmiext.DataElement = (*DNS)(nil)

// DNS represents the DNS configuration on a NX-OS device.
type DNS struct {
Expand Down
4 changes: 2 additions & 2 deletions internal/provider/cisco/nxos/evi.go
Original file line number Diff line number Diff line change
Expand Up @@ -11,10 +11,10 @@ import (
"strconv"
"strings"

"github.com/ironcore-dev/network-operator/internal/provider/cisco/gnmiext/v2"
"github.com/ironcore-dev/network-operator/internal/transport/gnmiext"
)

var _ gnmiext.Configurable = (*BDEVI)(nil)
var _ gnmiext.DataElement = (*BDEVI)(nil)

// BDEVI represents a Bridge Domain Ethernet VPN Instance (MAC-VRF).
type BDEVI struct {
Expand Down
6 changes: 3 additions & 3 deletions internal/provider/cisco/nxos/feat.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,11 +3,11 @@

package nxos

import "github.com/ironcore-dev/network-operator/internal/provider/cisco/gnmiext/v2"
import "github.com/ironcore-dev/network-operator/internal/transport/gnmiext"

var (
_ gnmiext.Configurable = (*Feature)(nil)
_ gnmiext.Defaultable = (*Feature)(nil)
_ gnmiext.DataElement = (*Feature)(nil)
_ gnmiext.Defaultable = (*Feature)(nil)
)

// Feature represents a dynamic feature configuration on a NX-OS device.
Expand Down
Loading
Loading