Skip to content

feat/multi provider support - #470

Open
sven-rosenzweig wants to merge 2 commits into
mainfrom
feat/multi_provider_support
Open

feat/multi provider support#470
sven-rosenzweig wants to merge 2 commits into
mainfrom
feat/multi_provider_support

Conversation

@sven-rosenzweig

@sven-rosenzweig sven-rosenzweig commented Jul 30, 2026

Copy link
Copy Markdown
Contributor

Migrate to Multi Provider Support

With this commit, we do not use the provider flag anymore.
The provider func now is loaded dynamically on every reconciliation.
Requires the device.spec.provider field to be set on every device.

@sven-rosenzweig
sven-rosenzweig force-pushed the feat/multi_provider_support branch 3 times, most recently from 31d11c8 to f2aed7d Compare July 30, 2026 11:48
@github-actions github-actions Bot added size/L and removed size/XL labels Jul 30, 2026
@sven-rosenzweig sven-rosenzweig changed the title Feat/multi provider support feat/multi provider support Aug 6, 2026
@sven-rosenzweig
sven-rosenzweig force-pushed the feat/multi_provider_support branch 5 times, most recently from 68eb544 to b448d2a Compare August 6, 2026 13:42
@sven-rosenzweig

Copy link
Copy Markdown
Contributor Author

Do not merge until the device.spec.provider field is introduced everywhere.

@sven-rosenzweig
sven-rosenzweig marked this pull request as ready for review August 6, 2026 13:48
@sven-rosenzweig
sven-rosenzweig force-pushed the feat/multi_provider_support branch from b448d2a to 1dd9e0a Compare August 6, 2026 13:48
Replace 'openconfig' with 'openconfig.networking.metal.ironcore.dev'.

Signed-off-by: Sven Rosenzweig <sven.rosenzweig@sap.com>
With this commit, we do not use the provider flag anymore.
The provider func now is loaded dynamically on every reconciliation.
Requires the `device.spec.provider` field to be set on every device.

Signed-off-by: Sven Rosenzweig <sven.rosenzweig@sap.com>
@sven-rosenzweig
sven-rosenzweig force-pushed the feat/multi_provider_support branch from 1dd9e0a to 33ea131 Compare August 6, 2026 13:49
@github-actions

github-actions Bot commented Aug 6, 2026

Copy link
Copy Markdown

Merging this branch will decrease overall coverage

Impacted Packages Coverage Δ 🤖
github.com/ironcore-dev/network-operator/api/core/v1alpha1 1.72% (ø)
github.com/ironcore-dev/network-operator/cmd 0.00% (ø)
github.com/ironcore-dev/network-operator/internal/controller/cisco/nx 64.14% (-0.56%) 👎
github.com/ironcore-dev/network-operator/internal/controller/core 60.70% (-0.98%) 👎
github.com/ironcore-dev/network-operator/internal/provider 0.00% (ø)
github.com/ironcore-dev/network-operator/internal/provider/cisco/iosxr 34.90% (ø)
github.com/ironcore-dev/network-operator/internal/provider/cisco/nxos 9.26% (ø)
github.com/ironcore-dev/network-operator/internal/provider/openconfig 0.00% (ø)
github.com/ironcore-dev/network-operator/internal/provisioning 75.41% (-0.74%) 👎

Coverage by file

Changed files (no unit tests)

Changed File Coverage Δ Total Covered Missed 🤖
github.com/ironcore-dev/network-operator/api/core/v1alpha1/device_types.go 48.48% (ø) 33 16 17
github.com/ironcore-dev/network-operator/api/core/v1alpha1/groupversion_info.go 0.00% (ø) 2 0 2
github.com/ironcore-dev/network-operator/cmd/main.go 0.00% (ø) 300 (-8) 0 300 (-8)
github.com/ironcore-dev/network-operator/internal/controller/cisco/nx/bordergateway_controller.go 52.67% (-0.29%) 243 (+7) 128 (+3) 115 (+4) 👎
github.com/ironcore-dev/network-operator/internal/controller/cisco/nx/system_controller.go 64.23% (-1.29%) 123 (+7) 79 (+3) 44 (+4) 👎
github.com/ironcore-dev/network-operator/internal/controller/cisco/nx/vpcdomain_controller.go 77.10% (-0.57%) 214 (+8) 165 (+5) 49 (+3) 👎
github.com/ironcore-dev/network-operator/internal/controller/core/aaa_controller.go 0.00% (ø) 144 (+5) 0 144 (+5)
github.com/ironcore-dev/network-operator/internal/controller/core/acl_controller.go 56.85% (-1.31%) 146 (+5) 83 (+1) 63 (+4) 👎
github.com/ironcore-dev/network-operator/internal/controller/core/banner_controller.go 56.90% (-1.09%) 174 (+5) 99 (+1) 75 (+4) 👎
github.com/ironcore-dev/network-operator/internal/controller/core/bgp_controller.go 69.42% (-0.20%) 242 (+5) 168 (+3) 74 (+2) 👎
github.com/ironcore-dev/network-operator/internal/controller/core/bgp_peer_controller.go 57.49% (-0.58%) 327 (+5) 188 (+1) 139 (+4) 👎
github.com/ironcore-dev/network-operator/internal/controller/core/certificate_controller.go 59.38% (+0.02%) 160 (+5) 95 (+3) 65 (+2) 👍
github.com/ironcore-dev/network-operator/internal/controller/core/configbackup_controller.go 61.93% (-0.98%) 218 (+5) 135 (+1) 83 (+4) 👎
github.com/ironcore-dev/network-operator/internal/controller/core/device_controller.go 62.50% (-1.27%) 272 (+7) 170 (+1) 102 (+6) 👎
github.com/ironcore-dev/network-operator/internal/controller/core/dhcprelay_controller.go 65.02% (-0.87%) 263 (+5) 171 (+1) 92 (+4) 👎
github.com/ironcore-dev/network-operator/internal/controller/core/dns_controller.go 60.14% (-1.45%) 143 (+5) 86 (+1) 57 (+4) 👎
github.com/ironcore-dev/network-operator/internal/controller/core/ethernetsegment_controller.go 65.26% (-1.09%) 213 (+5) 139 (+1) 74 (+4) 👎
github.com/ironcore-dev/network-operator/internal/controller/core/evpninstance_controller.go 61.54% (-0.81%) 260 (+5) 160 (+1) 100 (+4) 👎
github.com/ironcore-dev/network-operator/internal/controller/core/interface_controller.go 71.21% (-0.44%) 587 (+5) 418 (+1) 169 (+4) 👎
github.com/ironcore-dev/network-operator/internal/controller/core/isis_controller.go 58.99% (-1.13%) 178 (+5) 105 (+1) 73 (+4) 👎
github.com/ironcore-dev/network-operator/internal/controller/core/lldp_controller.go 68.47% (-1.12%) 222 (+5) 152 (+1) 70 (+4) 👎
github.com/ironcore-dev/network-operator/internal/controller/core/managementaccess_controller.go 56.64% (-1.33%) 143 (+5) 81 (+1) 62 (+4) 👎
github.com/ironcore-dev/network-operator/internal/controller/core/ntp_controller.go 56.64% (-1.33%) 143 (+5) 81 (+1) 62 (+4) 👎
github.com/ironcore-dev/network-operator/internal/controller/core/nve_controller.go 66.52% (-1.08%) 221 (+5) 147 (+1) 74 (+4) 👎
github.com/ironcore-dev/network-operator/internal/controller/core/ospf_controller.go 58.85% (-0.95%) 209 (+5) 123 (+1) 86 (+4) 👎
github.com/ironcore-dev/network-operator/internal/controller/core/pim_controller.go 58.52% (-1.13%) 176 (+5) 103 (+1) 73 (+4) 👎
github.com/ironcore-dev/network-operator/internal/controller/core/prefixset_controller.go 60.27% (-1.43%) 146 (+5) 88 (+1) 58 (+4) 👎
github.com/ironcore-dev/network-operator/internal/controller/core/routingpolicy_controller.go 66.84% (-1.23%) 196 (+5) 131 (+1) 65 (+4) 👎
github.com/ironcore-dev/network-operator/internal/controller/core/snmp_controller.go 56.64% (-1.33%) 143 (+5) 81 (+1) 62 (+4) 👎
github.com/ironcore-dev/network-operator/internal/controller/core/syslog_controller.go 56.85% (-1.31%) 146 (+5) 83 (+1) 63 (+4) 👎
github.com/ironcore-dev/network-operator/internal/controller/core/user_controller.go 55.75% (-1.06%) 174 (+5) 97 (+1) 77 (+4) 👎
github.com/ironcore-dev/network-operator/internal/controller/core/vlan_controller.go 60.65% (-1.35%) 155 (+5) 94 (+1) 61 (+4) 👎
github.com/ironcore-dev/network-operator/internal/controller/core/vrf_controller.go 60.84% (-1.48%) 143 (+5) 87 (+1) 56 (+4) 👎
github.com/ironcore-dev/network-operator/internal/provider/cisco/iosxr/provider.go 21.08% (ø) 223 47 176
github.com/ironcore-dev/network-operator/internal/provider/cisco/nxos/provider.go 0.38% (ø) 2127 8 2119
github.com/ironcore-dev/network-operator/internal/provider/openconfig/provider.go 0.00% (ø) 14 0 14
github.com/ironcore-dev/network-operator/internal/provider/provider.go 0.00% (ø) 57 (+15) 0 57 (+15)
github.com/ironcore-dev/network-operator/internal/provisioning/http.go 75.41% (-0.74%) 244 (+5) 184 (+2) 60 (+3) 👎

Please note that the "Total", "Covered", and "Missed" counts above refer to code statements instead of lines of code. The value in brackets refers to the test coverage of that file in the old version of the code.

Changed unit test files

  • github.com/ironcore-dev/network-operator/internal/controller/cisco/nx/bordergateway_controller_test.go
  • github.com/ironcore-dev/network-operator/internal/controller/cisco/nx/suite_test.go
  • github.com/ironcore-dev/network-operator/internal/controller/cisco/nx/system_controller_test.go
  • github.com/ironcore-dev/network-operator/internal/controller/cisco/nx/vpcdomain_controller_test.go
  • github.com/ironcore-dev/network-operator/internal/controller/core/acl_controller_test.go
  • github.com/ironcore-dev/network-operator/internal/controller/core/banner_controller_test.go
  • github.com/ironcore-dev/network-operator/internal/controller/core/bgp_controller_test.go
  • github.com/ironcore-dev/network-operator/internal/controller/core/bgp_peer_controller_test.go
  • github.com/ironcore-dev/network-operator/internal/controller/core/certificate_controller_test.go
  • github.com/ironcore-dev/network-operator/internal/controller/core/configbackup_controller_test.go
  • github.com/ironcore-dev/network-operator/internal/controller/core/device_controller_test.go
  • github.com/ironcore-dev/network-operator/internal/controller/core/dhcprelay_controller_test.go
  • github.com/ironcore-dev/network-operator/internal/controller/core/dns_controller_test.go
  • github.com/ironcore-dev/network-operator/internal/controller/core/ethernetsegment_controller_test.go
  • github.com/ironcore-dev/network-operator/internal/controller/core/evpninstance_controller_test.go
  • github.com/ironcore-dev/network-operator/internal/controller/core/interface_controller_test.go
  • github.com/ironcore-dev/network-operator/internal/controller/core/isis_controller_test.go
  • github.com/ironcore-dev/network-operator/internal/controller/core/lldp_controller_test.go
  • github.com/ironcore-dev/network-operator/internal/controller/core/managementaccess_controller_test.go
  • github.com/ironcore-dev/network-operator/internal/controller/core/ntp_controller_test.go
  • github.com/ironcore-dev/network-operator/internal/controller/core/nve_controller_test.go
  • github.com/ironcore-dev/network-operator/internal/controller/core/ospf_controller_test.go
  • github.com/ironcore-dev/network-operator/internal/controller/core/pim_controller_test.go
  • github.com/ironcore-dev/network-operator/internal/controller/core/prefixset_controller_test.go
  • github.com/ironcore-dev/network-operator/internal/controller/core/routingpolicy_controller_test.go
  • github.com/ironcore-dev/network-operator/internal/controller/core/snmp_controller_test.go
  • github.com/ironcore-dev/network-operator/internal/controller/core/suite_test.go
  • github.com/ironcore-dev/network-operator/internal/controller/core/syslog_controller_test.go
  • github.com/ironcore-dev/network-operator/internal/controller/core/user_controller_test.go
  • github.com/ironcore-dev/network-operator/internal/controller/core/vlan_controller_test.go
  • github.com/ironcore-dev/network-operator/internal/controller/core/vrf_controller_test.go
  • github.com/ironcore-dev/network-operator/internal/provisioning/http_test.go

// +required
Endpoint Endpoint `json:"endpoint"`

// Provider identifies the network provider plugin used to reconcile this Device and all CRDs that reference it.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
// Provider identifies the network provider plugin used to reconcile this Device and all CRDs that reference it.
// Provider identifies the provider implementation used to reconcile this Device and all CRDs that reference it.

Comment on lines +93 to +95
if device.Spec.Provider == "" {
return ctrl.Result{}, fmt.Errorf("device %q has no provider set", device.Name)
}

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is not possible as this is a required field. Therefore I wouldn't check this.

Applies to all controllers.

Comment on lines +28 to +29
// +required
// +immutable

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
// +required
// +immutable
// Immutable.
// +required
// +kubebuilder:validation:MinLength=1
// +kubebuilder:validation:XValidation:rule="self == oldSelf",message="Provider is immutable"

There is no +immutable marker.


// Provider is the driver that will be used to create & delete the interface.
Provider provider.ProviderFunc
// Provider provider.ProviderFunc

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why commented out?


// LoadProvider returns a provider instance cast to the requested interface type T.
// Returns NotFoundError if the provider is not registered, NotImplementedError if it does not implement T.
func LoadProvider[T Provider](providerName string) (T, error) {

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
func LoadProvider[T Provider](providerName string) (T, error) {
func LoadProvider[T Provider](providerName string) (zero T, _ error) {

Safes you the var zero T statements.

var zero T
return zero, NotFoundError{Message: fmt.Sprintf("Provider %q is not registered", providerName)}
}
genericProvider, ok := prov().(T)

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
genericProvider, ok := prov().(T)
provider, ok := prov().(T)

That name doesn't seem fitting.

Comment on lines +905 to +929
type NotFoundError struct {
Message string
}

type NotImplementedError struct {
Message string
}

func (e NotImplementedError) Error() string {
return e.Message
}

func (e NotFoundError) Error() string {
return e.Message
}

func (e NotFoundError) Is(target error) bool {
_, ok := target.(NotFoundError)
return ok
}

func (e NotImplementedError) Is(target error) bool {
_, ok := target.(NotImplementedError)
return ok
}

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
type NotFoundError struct {
Message string
}
type NotImplementedError struct {
Message string
}
func (e NotImplementedError) Error() string {
return e.Message
}
func (e NotFoundError) Error() string {
return e.Message
}
func (e NotFoundError) Is(target error) bool {
_, ok := target.(NotFoundError)
return ok
}
func (e NotImplementedError) Is(target error) bool {
_, ok := target.(NotImplementedError)
return ok
}
type NotFoundError struct
func (e NotFoundError) Error() string
func (e NotFoundError) Is(target error) bool
type NotImplementedError struct
func (e NotImplementedError) Error() string
func (e NotImplementedError) Is(target error) bool

This order is a bit better.

ValidateSourceIP bool
Provider provider.ProvisioningProvider
Port int
// Provider provider.ProvisioningProvider

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why commented out?

Comment thread Tiltfile
local_resource('controller-gen', 'make generate', deps=['api/', 'hack/boilerplate.go.txt'])
local_resource('crds', 'make install', deps=['api/'])

provider = os.getenv('PROVIDER', 'openconfig')

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We wanted to still keep supporting this env variable for local development and set it on the device sample via the device_yaml function.

diff --git a/Tiltfile b/Tiltfile
index 65ac2499..0828a89e 100644
--- a/Tiltfile
+++ b/Tiltfile
@@ -21,6 +21,8 @@ docker_build('controller:latest', '.', only=[
 local_resource('controller-gen', 'make generate', deps=['api/', 'hack/boilerplate.go.txt'])
 local_resource('crds', 'make install', deps=['api/'])
 
+provider = os.getenv('PROVIDER', 'openconfig')
+
 manager = kustomize('config/develop')
 manager = str(manager)
 
@@ -30,6 +32,7 @@ k8s_resource('network-operator-controller-manager', resource_deps=['controller-g
 # Sample resources with manual trigger mode
 def device_yaml():
     decoded = read_yaml_stream('./config/samples/v1alpha1_device.yaml')
+    decoded[0]['spec']['provider'] = provider
     ip = str(local("docker run --rm busybox:1.37.0 nslookup -type=a host.docker.internal 2>/dev/null | grep 'Address:' | tail -n 1 | awk '{print $2}' || echo ''", quiet=True)).rstrip('\n')
     if len(ip) > 0:
         decoded[0]['spec']['endpoint']['address'] = ip+':9339'

// Provider identifies the network provider plugin used to reconcile this Device and all CRDs that reference it.
// +required
// +immutable
Provider string `json:"provider,omitempty"`

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
Provider string `json:"provider,omitempty"`
Provider string `json:"provider"`

No omitempty when the field is required.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants