diff --git a/Tiltfile b/Tiltfile
index 825ff85f8..de65b9851 100644
--- a/Tiltfile
+++ b/Tiltfile
@@ -21,10 +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).replace('--provider=openconfig', '--provider={}'.format(provider))
+manager = str(manager)
k8s_yaml(blob(manager))
k8s_resource('network-operator-controller-manager', resource_deps=['controller-gen'])
diff --git a/api/core/v1alpha1/device_types.go b/api/core/v1alpha1/device_types.go
index a9a7e6cb6..f3b0881f6 100644
--- a/api/core/v1alpha1/device_types.go
+++ b/api/core/v1alpha1/device_types.go
@@ -24,6 +24,12 @@ type DeviceSpec struct {
// +required
Endpoint Endpoint `json:"endpoint"`
+ // Provider is the name of the responsible for reconciling the object connected to the device.
+ // ToDo: Make this a required field once we have multiple providers implemented.
+ // ToDo: make this of type uri e.g. nx.cisco.networking.metal.ironcore.dev
+ // +optional
+ Provider string `json:"provider,omitempty"`
+
// Provisioning is an optional configuration for the device provisioning process.
// It can be used to provide initial configuration templates or scripts that are applied during the device provisioning.
// +optional
diff --git a/api/core/v1alpha1/groupversion_info.go b/api/core/v1alpha1/groupversion_info.go
index b1d017686..3d65b21f8 100644
--- a/api/core/v1alpha1/groupversion_info.go
+++ b/api/core/v1alpha1/groupversion_info.go
@@ -181,6 +181,9 @@ const (
// ErrorReason indicates that an error occurred while reconciling the resource.
ErrorReason = "Error"
+ // ProviderNotFoundReason indicates that the provider specified in the resource's device.spec.provider field was not found.
+ ProviderNotFoundReason = "ProviderNotFound"
+
// WaitingForDependenciesReason indicates that the resource is waiting for its dependencies to be ready.
WaitingForDependenciesReason = "WaitingForDependencies"
diff --git a/charts/network-operator/templates/crd/devices.networking.metal.ironcore.dev.yaml b/charts/network-operator/templates/crd/devices.networking.metal.ironcore.dev.yaml
index 16aef9365..7ec03a40e 100644
--- a/charts/network-operator/templates/crd/devices.networking.metal.ironcore.dev.yaml
+++ b/charts/network-operator/templates/crd/devices.networking.metal.ironcore.dev.yaml
@@ -194,6 +194,12 @@ spec:
description: Paused can be used to prevent controllers from processing
the Device and its associated objects.
type: boolean
+ provider:
+ description: |-
+ Provider is the name of the responsible for reconciling the object connected to the device.
+ ToDo: Make this a required field once we have multiple providers implemented.
+ ToDo: make this of type uri e.g. nx.cisco.networking.metal.ironcore.dev
+ type: string
provisioning:
description: |-
Provisioning is an optional configuration for the device provisioning process.
diff --git a/cmd/main.go b/cmd/main.go
index afb5498ba..210ba5df0 100644
--- a/cmd/main.go
+++ b/cmd/main.go
@@ -48,7 +48,6 @@ import (
nxcontroller "github.com/ironcore-dev/network-operator/internal/controller/cisco/nx"
corecontroller "github.com/ironcore-dev/network-operator/internal/controller/core"
poolcontroller "github.com/ironcore-dev/network-operator/internal/controller/pool"
- "github.com/ironcore-dev/network-operator/internal/provider"
"github.com/ironcore-dev/network-operator/internal/provisioning"
"github.com/ironcore-dev/network-operator/internal/resourcelock"
tftpserver "github.com/ironcore-dev/network-operator/internal/tftp"
@@ -94,7 +93,6 @@ func main() { //nolint:gocyclo
var tlsOpts []func(*tls.Config)
var watchNamespace string
var watchFilterValue string
- var providerName string
var requeueInterval time.Duration
var heartbeatInterval time.Duration
var tftpPort int
@@ -120,7 +118,6 @@ func main() { //nolint:gocyclo
flag.BoolVar(&enableHTTP2, "enable-http2", false, "If set, HTTP/2 will be enabled for the metrics and webhook servers")
flag.StringVar(&watchNamespace, "namespace", "", "Namespace that the controller watches to reconcile api objects. If unspecified, the controller watches for api objects across all namespaces.")
flag.StringVar(&watchFilterValue, "watch-filter", "", fmt.Sprintf("Label value that the controller watches to reconcile api objects. Label key is always %q. If unspecified, the controller watches for all api objects.", v1alpha1.WatchLabel))
- flag.StringVar(&providerName, "provider", "openconfig", "The provider to use for the controller. If not specified, the default provider is used. Available providers: "+strings.Join(provider.Providers(), ", "))
flag.DurationVar(&requeueInterval, "requeue-interval", time.Hour, "The interval after which Kubernetes resources should be reconciled again regardless of whether they have changed.")
flag.DurationVar(&heartbeatInterval, "heartbeat-interval", 30*time.Second, "The interval after which the controller retries a reachability check on each device.")
flag.IntVar(&tftpPort, "tftp-port", 1069, "The port on which the inline TFTP server listens. Set to 0 to disable the TFTP server.")
@@ -256,13 +253,6 @@ func main() { //nolint:gocyclo
os.Exit(1)
}
- setupLog.Info("Using provider", "provider", providerName)
- prov, err := provider.Get(providerName)
- if err != nil {
- setupLog.Error(err, "failed to get provider", "provider", providerName)
- os.Exit(1)
- }
-
ctx := ctrl.SetupSignalHandler()
if lockerNamespace == "" {
@@ -306,11 +296,11 @@ func main() { //nolint:gocyclo
}
if err := (&corecontroller.DeviceReconciler{
- Client: mgr.GetClient(),
- Scheme: mgr.GetScheme(),
- Recorder: mgr.GetEventRecorder("device-controller"),
- WatchFilterValue: watchFilterValue,
- Provider: prov,
+ Client: mgr.GetClient(),
+ Scheme: mgr.GetScheme(),
+ Recorder: mgr.GetEventRecorder("device-controller"),
+ WatchFilterValue: watchFilterValue,
+ // Provider: prov,
HeartbeatInterval: heartbeatInterval,
}).SetupWithManager(mgr); err != nil {
setupLog.Error(err, "unable to create controller", "controller", "Device")
@@ -322,7 +312,6 @@ func main() { //nolint:gocyclo
Scheme: mgr.GetScheme(),
Recorder: mgr.GetEventRecorder("interface-controller"),
WatchFilterValue: watchFilterValue,
- Provider: prov,
Locker: locker,
RequeueInterval: requeueInterval,
}).SetupWithManager(ctx, mgr); err != nil {
@@ -335,7 +324,6 @@ func main() { //nolint:gocyclo
Scheme: mgr.GetScheme(),
Recorder: mgr.GetEventRecorder("banner-controller"),
WatchFilterValue: watchFilterValue,
- Provider: prov,
Locker: locker,
}).SetupWithManager(ctx, mgr); err != nil {
setupLog.Error(err, "unable to create controller", "controller", "Banner")
@@ -347,7 +335,6 @@ func main() { //nolint:gocyclo
Scheme: mgr.GetScheme(),
Recorder: mgr.GetEventRecorder("user-controller"),
WatchFilterValue: watchFilterValue,
- Provider: prov,
Locker: locker,
}).SetupWithManager(ctx, mgr); err != nil {
setupLog.Error(err, "unable to create controller", "controller", "User")
@@ -359,7 +346,6 @@ func main() { //nolint:gocyclo
Scheme: mgr.GetScheme(),
Recorder: mgr.GetEventRecorder("dns-controller"),
WatchFilterValue: watchFilterValue,
- Provider: prov,
Locker: locker,
}).SetupWithManager(ctx, mgr); err != nil {
setupLog.Error(err, "unable to create controller", "controller", "DNS")
@@ -371,7 +357,6 @@ func main() { //nolint:gocyclo
Scheme: mgr.GetScheme(),
Recorder: mgr.GetEventRecorder("ntp-controller"),
WatchFilterValue: watchFilterValue,
- Provider: prov,
Locker: locker,
}).SetupWithManager(ctx, mgr); err != nil {
setupLog.Error(err, "unable to create controller", "controller", "NTP")
@@ -383,7 +368,6 @@ func main() { //nolint:gocyclo
Scheme: mgr.GetScheme(),
Recorder: mgr.GetEventRecorder("acl-controller"),
WatchFilterValue: watchFilterValue,
- Provider: prov,
Locker: locker,
}).SetupWithManager(ctx, mgr); err != nil {
setupLog.Error(err, "unable to create controller", "controller", "AccessControlList")
@@ -395,7 +379,6 @@ func main() { //nolint:gocyclo
Scheme: mgr.GetScheme(),
Recorder: mgr.GetEventRecorder("certificate-controller"),
WatchFilterValue: watchFilterValue,
- Provider: prov,
Locker: locker,
}).SetupWithManager(ctx, mgr); err != nil {
setupLog.Error(err, "unable to create controller", "controller", "Certificate")
@@ -407,7 +390,6 @@ func main() { //nolint:gocyclo
Scheme: mgr.GetScheme(),
Recorder: mgr.GetEventRecorder("snmp-controller"),
WatchFilterValue: watchFilterValue,
- Provider: prov,
Locker: locker,
}).SetupWithManager(ctx, mgr); err != nil {
setupLog.Error(err, "unable to create controller", "controller", "SNMP")
@@ -419,7 +401,6 @@ func main() { //nolint:gocyclo
Scheme: mgr.GetScheme(),
Recorder: mgr.GetEventRecorder("syslog-controller"),
WatchFilterValue: watchFilterValue,
- Provider: prov,
Locker: locker,
}).SetupWithManager(ctx, mgr); err != nil {
setupLog.Error(err, "unable to create controller", "controller", "Syslog")
@@ -431,7 +412,6 @@ func main() { //nolint:gocyclo
Scheme: mgr.GetScheme(),
Recorder: mgr.GetEventRecorder("managementaccess-controller"),
WatchFilterValue: watchFilterValue,
- Provider: prov,
Locker: locker,
}).SetupWithManager(ctx, mgr); err != nil {
setupLog.Error(err, "unable to create controller", "controller", "ManagementAccess")
@@ -443,7 +423,6 @@ func main() { //nolint:gocyclo
Scheme: mgr.GetScheme(),
Recorder: mgr.GetEventRecorder("isis-controller"),
WatchFilterValue: watchFilterValue,
- Provider: prov,
Locker: locker,
}).SetupWithManager(ctx, mgr); err != nil {
setupLog.Error(err, "unable to create controller", "controller", "ISIS")
@@ -455,7 +434,6 @@ func main() { //nolint:gocyclo
Scheme: mgr.GetScheme(),
Recorder: mgr.GetEventRecorder("pim-controller"),
WatchFilterValue: watchFilterValue,
- Provider: prov,
Locker: locker,
}).SetupWithManager(ctx, mgr); err != nil {
setupLog.Error(err, "unable to create controller", "controller", "PIM")
@@ -467,7 +445,6 @@ func main() { //nolint:gocyclo
Scheme: mgr.GetScheme(),
Recorder: mgr.GetEventRecorder("bgp-controller"),
WatchFilterValue: watchFilterValue,
- Provider: prov,
Locker: locker,
RequeueInterval: requeueInterval,
}).SetupWithManager(ctx, mgr); err != nil {
@@ -480,7 +457,6 @@ func main() { //nolint:gocyclo
Scheme: mgr.GetScheme(),
Recorder: mgr.GetEventRecorder("bgppeer-controller"),
WatchFilterValue: watchFilterValue,
- Provider: prov,
Locker: locker,
RequeueInterval: requeueInterval,
}).SetupWithManager(ctx, mgr); err != nil {
@@ -493,7 +469,6 @@ func main() { //nolint:gocyclo
Scheme: mgr.GetScheme(),
Recorder: mgr.GetEventRecorder("lldp-controller"),
WatchFilterValue: watchFilterValue,
- Provider: prov,
Locker: locker,
RequeueInterval: requeueInterval,
}).SetupWithManager(ctx, mgr); err != nil {
@@ -506,7 +481,6 @@ func main() { //nolint:gocyclo
Scheme: mgr.GetScheme(),
Recorder: mgr.GetEventRecorder("ospf-controller"),
WatchFilterValue: watchFilterValue,
- Provider: prov,
Locker: locker,
RequeueInterval: requeueInterval,
}).SetupWithManager(ctx, mgr); err != nil {
@@ -519,7 +493,6 @@ func main() { //nolint:gocyclo
Scheme: mgr.GetScheme(),
Recorder: mgr.GetEventRecorder("vlan-controller"),
WatchFilterValue: watchFilterValue,
- Provider: prov,
Locker: locker,
RequeueInterval: requeueInterval,
}).SetupWithManager(ctx, mgr); err != nil {
@@ -532,7 +505,6 @@ func main() { //nolint:gocyclo
Scheme: mgr.GetScheme(),
Recorder: mgr.GetEventRecorder("vrf-controller"),
WatchFilterValue: watchFilterValue,
- Provider: prov,
Locker: locker,
}).SetupWithManager(ctx, mgr); err != nil {
setupLog.Error(err, "unable to create controller", "controller", "VRF")
@@ -544,7 +516,6 @@ func main() { //nolint:gocyclo
Scheme: mgr.GetScheme(),
Recorder: mgr.GetEventRecorder("cisco-nx-vpcdomain-controller"),
WatchFilterValue: watchFilterValue,
- Provider: prov,
Locker: locker,
RequeueInterval: requeueInterval,
}).SetupWithManager(ctx, mgr); err != nil {
@@ -557,7 +528,6 @@ func main() { //nolint:gocyclo
Scheme: mgr.GetScheme(),
Recorder: mgr.GetEventRecorder("nve-controller"),
WatchFilterValue: watchFilterValue,
- Provider: prov,
Locker: locker,
RequeueInterval: requeueInterval,
}).SetupWithManager(ctx, mgr); err != nil {
@@ -570,7 +540,6 @@ func main() { //nolint:gocyclo
Scheme: mgr.GetScheme(),
Recorder: mgr.GetEventRecorder("cisco-nx-system-controller"),
WatchFilterValue: watchFilterValue,
- Provider: prov,
Locker: locker,
}).SetupWithManager(ctx, mgr); err != nil {
setupLog.Error(err, "unable to create controller", "controller", "System")
@@ -582,7 +551,6 @@ func main() { //nolint:gocyclo
Scheme: mgr.GetScheme(),
Recorder: mgr.GetEventRecorder("evpn-instance-controller"),
WatchFilterValue: watchFilterValue,
- Provider: prov,
Locker: locker,
}).SetupWithManager(ctx, mgr); err != nil {
setupLog.Error(err, "unable to create controller", "controller", "EVPNInstance")
@@ -594,7 +562,6 @@ func main() { //nolint:gocyclo
Scheme: mgr.GetScheme(),
Recorder: mgr.GetEventRecorder("aaa-controller"),
WatchFilterValue: watchFilterValue,
- Provider: prov,
Locker: locker,
}).SetupWithManager(mgr); err != nil {
setupLog.Error(err, "unable to create controller", "controller", "AAA")
@@ -606,7 +573,6 @@ func main() { //nolint:gocyclo
Scheme: mgr.GetScheme(),
Recorder: mgr.GetEventRecorder("prefixset-controller"),
WatchFilterValue: watchFilterValue,
- Provider: prov,
Locker: locker,
}).SetupWithManager(ctx, mgr); err != nil {
setupLog.Error(err, "unable to create controller", "controller", "PrefixSet")
@@ -618,7 +584,6 @@ func main() { //nolint:gocyclo
Scheme: mgr.GetScheme(),
Recorder: mgr.GetEventRecorder("routingpolicy-controller"),
WatchFilterValue: watchFilterValue,
- Provider: prov,
Locker: locker,
}).SetupWithManager(ctx, mgr); err != nil {
setupLog.Error(err, "unable to create controller", "controller", "RoutingPolicy")
@@ -630,7 +595,6 @@ func main() { //nolint:gocyclo
Scheme: mgr.GetScheme(),
Recorder: mgr.GetEventRecorder("cisco-nx-border-gateway-controller"),
WatchFilterValue: watchFilterValue,
- Provider: prov,
Locker: locker,
}).SetupWithManager(ctx, mgr); err != nil {
setupLog.Error(err, "unable to create controller", "controller", "BorderGateway")
@@ -642,7 +606,6 @@ func main() { //nolint:gocyclo
Scheme: mgr.GetScheme(),
Recorder: mgr.GetEventRecorder("dhcprelay-controller"),
WatchFilterValue: watchFilterValue,
- Provider: prov,
Locker: locker,
RequeueInterval: requeueInterval,
}).SetupWithManager(ctx, mgr); err != nil {
@@ -655,7 +618,6 @@ func main() { //nolint:gocyclo
Scheme: mgr.GetScheme(),
Recorder: mgr.GetEventRecorder("ethernetsegment-controller"),
WatchFilterValue: watchFilterValue,
- Provider: prov,
Locker: locker,
RequeueInterval: requeueInterval,
}).SetupWithManager(ctx, mgr); err != nil {
@@ -779,14 +741,12 @@ func main() { //nolint:gocyclo
// is implemented and the port is set to a non-zero value.
// The server is added to the manager so it starts after the cache is synced
// and shuts down gracefully when the manager stops.
- provisioningProvider, ok := prov().(provider.ProvisioningProvider)
- if provisioningHTTPPort != 0 && ok {
+ if provisioningHTTPPort != 0 {
provisioningServer := &provisioning.HTTPServer{
Client: mgr.GetClient(),
Logger: ctrl.Log.WithName("provisioning"),
Recorder: mgr.GetEventRecorder("provisioning"),
ValidateSourceIP: provisioningHTTPValidateSourceIP,
- Provider: provisioningProvider,
Port: provisioningHTTPPort,
}
setupLog.Info("Adding provisioning HTTP server to manager", "port", provisioningHTTPPort, "validateSourceIP", provisioningHTTPValidateSourceIP)
diff --git a/config/crd/bases/networking.metal.ironcore.dev_devices.yaml b/config/crd/bases/networking.metal.ironcore.dev_devices.yaml
index 67379c014..90c518dd8 100644
--- a/config/crd/bases/networking.metal.ironcore.dev_devices.yaml
+++ b/config/crd/bases/networking.metal.ironcore.dev_devices.yaml
@@ -191,6 +191,12 @@ spec:
description: Paused can be used to prevent controllers from processing
the Device and its associated objects.
type: boolean
+ provider:
+ description: |-
+ Provider is the name of the responsible for reconciling the object connected to the device.
+ ToDo: Make this a required field once we have multiple providers implemented.
+ ToDo: make this of type uri e.g. nx.cisco.networking.metal.ironcore.dev
+ type: string
provisioning:
description: |-
Provisioning is an optional configuration for the device provisioning process.
diff --git a/config/develop/manager_patch.yaml b/config/develop/manager_patch.yaml
index 4fddb21a4..3736922fb 100644
--- a/config/develop/manager_patch.yaml
+++ b/config/develop/manager_patch.yaml
@@ -3,7 +3,6 @@
value:
- --leader-elect=false
- --health-probe-bind-address=:8081
- - --provider=openconfig
- --requeue-interval=30s
- --max-concurrent-reconciles=5
- --zap-log-level=3
diff --git a/docs/api-reference/index.md b/docs/api-reference/index.md
index 6a39c2b3b..9509edada 100644
--- a/docs/api-reference/index.md
+++ b/docs/api-reference/index.md
@@ -1319,6 +1319,7 @@ _Appears in:_
| --- | --- | --- | --- |
| `paused` _boolean_ | Paused can be used to prevent controllers from processing the Device and its associated objects. | false | Optional: \{\}
|
| `endpoint` _[Endpoint](#endpoint)_ | Endpoint contains the connection information for the device. | | Required: \{\}
|
+| `provider` _string_ | Provider is the name of the responsible for reconciling the object connected to the device.
ToDo: Make this a required field once we have multiple providers implemented.
ToDo: make this of type uri e.g. nx.cisco.networking.metal.ironcore.dev | | Optional: \{\}
|
| `provisioning` _[Provisioning](#provisioning)_ | Provisioning is an optional configuration for the device provisioning process.
It can be used to provide initial configuration templates or scripts that are applied during the device provisioning. | | Optional: \{\}
|
diff --git a/internal/controller/cisco/nx/bordergateway_controller.go b/internal/controller/cisco/nx/bordergateway_controller.go
index 1e9b2324f..b77dced69 100644
--- a/internal/controller/cisco/nx/bordergateway_controller.go
+++ b/internal/controller/cisco/nx/bordergateway_controller.go
@@ -51,9 +51,6 @@ type BorderGatewayReconciler struct {
// More info: https://book.kubebuilder.io/reference/raising-events
Recorder events.EventRecorder
- // Provider is the driver that will be used to create & delete the bordergateway.
- Provider provider.ProviderFunc
-
// Locker is used to synchronize operations on resources targeting the same device.
Locker *resourcelock.ResourceLocker
}
@@ -88,22 +85,39 @@ func (r *BorderGatewayReconciler) Reconcile(ctx context.Context, req ctrl.Reques
return ctrl.Result{}, err
}
- prov, ok := r.Provider().(Provider)
- if !ok {
+ device, err := deviceutil.GetDeviceByName(ctx, r, obj.Namespace, obj.Spec.DeviceRef.Name)
+ if err != nil {
+ return ctrl.Result{}, err
+ }
+
+ if device.Spec.Provider == "" {
+ return ctrl.Result{}, fmt.Errorf("device %q has no provider set", device.Name)
+ }
+
+ p, err := provider.Get(device.Spec.Provider)
+ if err != nil {
if meta.SetStatusCondition(&obj.Status.Conditions, metav1.Condition{
Type: v1alpha1.ReadyCondition,
Status: metav1.ConditionFalse,
- Reason: v1alpha1.ErrorReason,
- Message: "Invalid provider configured for BorderGateway reconciler",
+ Reason: v1alpha1.ProviderNotFoundReason,
+ Message: fmt.Sprintf("Provider %q is not registered", device.Spec.Provider),
}) {
return ctrl.Result{}, r.Status().Update(ctx, obj)
}
return ctrl.Result{}, nil
}
+ prov, ok := p().(Provider)
- device, err := deviceutil.GetDeviceByName(ctx, r, obj.Namespace, obj.Spec.DeviceRef.Name)
- if err != nil {
- return ctrl.Result{}, err
+ if !ok {
+ if meta.SetStatusCondition(&obj.Status.Conditions, metav1.Condition{
+ Type: v1alpha1.ReadyCondition,
+ Status: metav1.ConditionFalse,
+ Reason: v1alpha1.NotImplementedReason,
+ Message: "Provider does not implement provider.BorderGatewayProvider",
+ }) {
+ return ctrl.Result{}, r.Status().Update(ctx, obj)
+ }
+ return ctrl.Result{}, nil
}
if isPaused, requeue, err := paused.EnsureCondition(ctx, r.Client, device, obj); isPaused || requeue || err != nil {
diff --git a/internal/controller/cisco/nx/bordergateway_controller_test.go b/internal/controller/cisco/nx/bordergateway_controller_test.go
index bc6e27b97..8e0a93f10 100644
--- a/internal/controller/cisco/nx/bordergateway_controller_test.go
+++ b/internal/controller/cisco/nx/bordergateway_controller_test.go
@@ -31,6 +31,7 @@ var _ = Describe("BorderGateway Controller", func() {
Namespace: metav1.NamespaceDefault,
},
Spec: v1alpha1.DeviceSpec{
+ Provider: "test-provider",
Endpoint: v1alpha1.Endpoint{
Address: "192.168.10.2:9339",
},
diff --git a/internal/controller/cisco/nx/suite_test.go b/internal/controller/cisco/nx/suite_test.go
index 215331851..1020aefb6 100644
--- a/internal/controller/cisco/nx/suite_test.go
+++ b/internal/controller/cisco/nx/suite_test.go
@@ -116,13 +116,12 @@ var _ = BeforeSuite(func() {
_, err = k8sManager.GetCache().GetInformer(ctx, &coordinationv1.Lease{})
Expect(err).NotTo(HaveOccurred())
- prov := func() provider.Provider { return testProvider }
+ provider.Register("test-provider", func() provider.Provider { return testProvider })
err = (&SystemReconciler{
Client: k8sManager.GetClient(),
Scheme: k8sManager.GetScheme(),
Recorder: recorder,
- Provider: prov,
Locker: testLocker,
}).SetupWithManager(ctx, k8sManager)
Expect(err).NotTo(HaveOccurred())
@@ -131,7 +130,6 @@ var _ = BeforeSuite(func() {
Client: k8sManager.GetClient(),
Scheme: scheme.Scheme,
Recorder: recorder,
- Provider: prov,
Locker: testLocker,
}).SetupWithManager(ctx, k8sManager)
Expect(err).NotTo(HaveOccurred())
@@ -140,7 +138,6 @@ var _ = BeforeSuite(func() {
Client: k8sManager.GetClient(),
Scheme: k8sManager.GetScheme(),
Recorder: recorder,
- Provider: prov,
Locker: testLocker,
}).SetupWithManager(ctx, k8sManager)
Expect(err).NotTo(HaveOccurred())
@@ -153,7 +150,6 @@ var _ = BeforeSuite(func() {
Client: k8sManager.GetClient(),
Scheme: k8sManager.GetScheme(),
Recorder: recorder,
- Provider: prov,
HeartbeatInterval: 10 * time.Minute,
}).SetupWithManager(k8sManager)
Expect(err).NotTo(HaveOccurred())
diff --git a/internal/controller/cisco/nx/system_controller.go b/internal/controller/cisco/nx/system_controller.go
index 58551fea2..74f60836b 100644
--- a/internal/controller/cisco/nx/system_controller.go
+++ b/internal/controller/cisco/nx/system_controller.go
@@ -48,9 +48,6 @@ type SystemReconciler struct {
// More info: https://book.kubebuilder.io/reference/raising-events
Recorder events.EventRecorder
- // Provider is the driver that will be used to create & delete the system.
- Provider provider.ProviderFunc
-
// Locker is used to synchronize operations on resources targeting the same device.
Locker *resourcelock.ResourceLocker
}
@@ -85,22 +82,39 @@ func (r *SystemReconciler) Reconcile(ctx context.Context, req ctrl.Request) (_ c
return ctrl.Result{}, err
}
- prov, ok := r.Provider().(Provider)
- if !ok {
+ device, err := deviceutil.GetDeviceByName(ctx, r, obj.Namespace, obj.Spec.DeviceRef.Name)
+ if err != nil {
+ return ctrl.Result{}, err
+ }
+
+ if device.Spec.Provider == "" {
+ return ctrl.Result{}, fmt.Errorf("device %q has no provider set", device.Name)
+ }
+
+ p, err := provider.Get(device.Spec.Provider)
+ if err != nil {
if meta.SetStatusCondition(&obj.Status.Conditions, metav1.Condition{
Type: v1alpha1.ReadyCondition,
Status: metav1.ConditionFalse,
- Reason: v1alpha1.ErrorReason,
- Message: "Invalid provider configured for System reconciler",
+ Reason: v1alpha1.ProviderNotFoundReason,
+ Message: fmt.Sprintf("Provider %q is not registered", device.Spec.Provider),
}) {
return ctrl.Result{}, r.Status().Update(ctx, obj)
}
return ctrl.Result{}, nil
}
+ prov, ok := p().(Provider)
- device, err := deviceutil.GetDeviceByName(ctx, r, obj.Namespace, obj.Spec.DeviceRef.Name)
- if err != nil {
- return ctrl.Result{}, err
+ if !ok {
+ if meta.SetStatusCondition(&obj.Status.Conditions, metav1.Condition{
+ Type: v1alpha1.ReadyCondition,
+ Status: metav1.ConditionFalse,
+ Reason: v1alpha1.NotImplementedReason,
+ Message: "Provider does not implement provider.SystemProvider",
+ }) {
+ return ctrl.Result{}, r.Status().Update(ctx, obj)
+ }
+ return ctrl.Result{}, nil
}
if isPaused, requeue, err := paused.EnsureCondition(ctx, r.Client, device, obj); isPaused || requeue || err != nil {
diff --git a/internal/controller/cisco/nx/system_controller_test.go b/internal/controller/cisco/nx/system_controller_test.go
index 1553a5c6d..f77e844a3 100644
--- a/internal/controller/cisco/nx/system_controller_test.go
+++ b/internal/controller/cisco/nx/system_controller_test.go
@@ -29,6 +29,7 @@ var _ = Describe("System Controller", func() {
Namespace: metav1.NamespaceDefault,
},
Spec: v1alpha1.DeviceSpec{
+ Provider: "test-provider",
Endpoint: v1alpha1.Endpoint{
Address: "192.168.10.2:9339",
},
diff --git a/internal/controller/cisco/nx/vpcdomain_controller.go b/internal/controller/cisco/nx/vpcdomain_controller.go
index a6320c5f0..bff820fa6 100644
--- a/internal/controller/cisco/nx/vpcdomain_controller.go
+++ b/internal/controller/cisco/nx/vpcdomain_controller.go
@@ -51,9 +51,6 @@ type VPCDomainReconciler struct {
// More info: https://book.kubebuilder.io/reference/raising-events
Recorder events.EventRecorder
- // Provider is the driver that will be used to create & delete the vPC
- Provider provider.ProviderFunc
-
// Locker is used to synchronize operations on resources targeting the same device.
Locker *resourcelock.ResourceLocker
@@ -89,20 +86,39 @@ func (r *VPCDomainReconciler) Reconcile(ctx context.Context, req ctrl.Request) (
return ctrl.Result{}, err
}
- prov, ok := r.Provider().(Provider)
- if !ok {
- meta.SetStatusCondition(&obj.Status.Conditions, metav1.Condition{
+ device, err := deviceutil.GetDeviceByName(ctx, r, obj.Namespace, obj.Spec.DeviceRef.Name)
+ if err != nil {
+ return ctrl.Result{}, err
+ }
+
+ if device.Spec.Provider == "" {
+ return ctrl.Result{}, fmt.Errorf("device %q has no provider set", device.Name)
+ }
+
+ p, err := provider.Get(device.Spec.Provider)
+ if err != nil {
+ if meta.SetStatusCondition(&obj.Status.Conditions, metav1.Condition{
Type: v1alpha1.ReadyCondition,
Status: metav1.ConditionFalse,
- Reason: v1alpha1.NotImplementedReason,
- Message: "Invalid provider configured for VPCDomain reconciler",
- })
- return ctrl.Result{}, r.Status().Update(ctx, obj)
+ Reason: v1alpha1.ProviderNotFoundReason,
+ Message: fmt.Sprintf("Provider %q is not registered", device.Spec.Provider),
+ }) {
+ return ctrl.Result{}, r.Status().Update(ctx, obj)
+ }
+ return ctrl.Result{}, nil
}
+ prov, ok := p().(Provider)
- device, err := deviceutil.GetDeviceByName(ctx, r, obj.Namespace, obj.Spec.DeviceRef.Name)
- if err != nil {
- return ctrl.Result{}, err
+ if !ok {
+ if meta.SetStatusCondition(&obj.Status.Conditions, metav1.Condition{
+ Type: v1alpha1.ReadyCondition,
+ Status: metav1.ConditionFalse,
+ Reason: v1alpha1.NotImplementedReason,
+ Message: "Provider does not implement provider.VPCDomainProvider",
+ }) {
+ return ctrl.Result{}, r.Status().Update(ctx, obj)
+ }
+ return ctrl.Result{}, nil
}
if isPaused, requeue, err := paused.EnsureCondition(ctx, r.Client, device, obj); isPaused || requeue || err != nil {
diff --git a/internal/controller/cisco/nx/vpcdomain_controller_test.go b/internal/controller/cisco/nx/vpcdomain_controller_test.go
index 5af9d41cc..10322a5aa 100644
--- a/internal/controller/cisco/nx/vpcdomain_controller_test.go
+++ b/internal/controller/cisco/nx/vpcdomain_controller_test.go
@@ -31,6 +31,7 @@ var _ = Describe("VPCDomain Controller", func() {
Namespace: metav1.NamespaceDefault,
},
Spec: corev1.DeviceSpec{
+ Provider: "test-provider",
Endpoint: corev1.Endpoint{
Address: "192.168.10.2:9339",
},
@@ -208,7 +209,7 @@ var _ = Describe("VPCDomain Controller", func() {
GenerateName: "vpc-dep-",
Namespace: metav1.NamespaceDefault,
},
- Spec: corev1.DeviceSpec{Endpoint: corev1.Endpoint{Address: "192.168.10.2:9339"}},
+ Spec: corev1.DeviceSpec{Provider: "test-provider", Endpoint: corev1.Endpoint{Address: "192.168.10.2:9339"}},
}
Expect(k8sClient.Create(ctx, deviceA)).To(Succeed())
name = deviceA.Name
@@ -216,7 +217,7 @@ var _ = Describe("VPCDomain Controller", func() {
By("Creating Device B")
Expect(k8sClient.Create(ctx, &corev1.Device{
ObjectMeta: metav1.ObjectMeta{Name: name + "-b", Namespace: metav1.NamespaceDefault},
- Spec: corev1.DeviceSpec{Endpoint: corev1.Endpoint{Address: "192.168.10.3:9339"}},
+ Spec: corev1.DeviceSpec{Provider: "test-provider", Endpoint: corev1.Endpoint{Address: "192.168.10.3:9339"}},
})).To(Succeed())
By("Creating physical interfaces on Device A and B")
diff --git a/internal/controller/core/aaa_controller.go b/internal/controller/core/aaa_controller.go
index c38b1061e..e83d8d528 100644
--- a/internal/controller/core/aaa_controller.go
+++ b/internal/controller/core/aaa_controller.go
@@ -46,9 +46,6 @@ type AAAReconciler struct {
// More info: https://book.kubebuilder.io/reference/raising-events
Recorder events.EventRecorder
- // Provider is the driver that will be used to create & delete the AAA configuration.
- Provider provider.ProviderFunc
-
// Locker is used to synchronize operations on resources targeting the same device.
Locker *resourcelock.ResourceLocker
}
@@ -84,7 +81,29 @@ func (r *AAAReconciler) Reconcile(ctx context.Context, req ctrl.Request) (_ ctrl
return ctrl.Result{}, err
}
- prov, ok := r.Provider().(provider.AAAProvider)
+ device, err := deviceutil.GetDeviceByName(ctx, r, obj.Namespace, obj.Spec.DeviceRef.Name)
+ if err != nil {
+ return ctrl.Result{}, err
+ }
+
+ if device.Spec.Provider == "" {
+ return ctrl.Result{}, fmt.Errorf("device %q has no provider set", device.Name)
+ }
+
+ p, err := provider.Get(device.Spec.Provider)
+ if err != nil {
+ if meta.SetStatusCondition(&obj.Status.Conditions, metav1.Condition{
+ Type: v1alpha1.ReadyCondition,
+ Status: metav1.ConditionFalse,
+ Reason: v1alpha1.ProviderNotFoundReason,
+ Message: fmt.Sprintf("Provider %q is not registered", device.Spec.Provider),
+ }) {
+ return ctrl.Result{}, r.Status().Update(ctx, obj)
+ }
+ return ctrl.Result{}, nil
+ }
+ prov, ok := p().(provider.AAAProvider)
+
if !ok {
if meta.SetStatusCondition(&obj.Status.Conditions, metav1.Condition{
Type: v1alpha1.ReadyCondition,
@@ -97,11 +116,6 @@ func (r *AAAReconciler) Reconcile(ctx context.Context, req ctrl.Request) (_ ctrl
return ctrl.Result{}, nil
}
- device, err := deviceutil.GetDeviceByName(ctx, r, obj.Namespace, obj.Spec.DeviceRef.Name)
- if err != nil {
- return ctrl.Result{}, err
- }
-
if isPaused, requeue, err := paused.EnsureCondition(ctx, r.Client, device, obj); isPaused || requeue || err != nil {
return ctrl.Result{}, err
}
diff --git a/internal/controller/core/acl_controller.go b/internal/controller/core/acl_controller.go
index eba3251ef..ac6443680 100644
--- a/internal/controller/core/acl_controller.go
+++ b/internal/controller/core/acl_controller.go
@@ -49,9 +49,6 @@ type AccessControlListReconciler struct {
// More info: https://book.kubebuilder.io/reference/raising-events
Recorder events.EventRecorder
- // Provider is the driver that will be used to create & delete the accesscontrollist.
- Provider provider.ProviderFunc
-
// Locker is used to synchronize operations on resources targeting the same device.
Locker *resourcelock.ResourceLocker
}
@@ -86,7 +83,29 @@ func (r *AccessControlListReconciler) Reconcile(ctx context.Context, req ctrl.Re
return ctrl.Result{}, err
}
- prov, ok := r.Provider().(provider.ACLProvider)
+ device, err := deviceutil.GetDeviceByName(ctx, r, obj.Namespace, obj.Spec.DeviceRef.Name)
+ if err != nil {
+ return ctrl.Result{}, err
+ }
+
+ if device.Spec.Provider == "" {
+ return ctrl.Result{}, fmt.Errorf("device %q has no provider set", device.Name)
+ }
+
+ p, err := provider.Get(device.Spec.Provider)
+ if err != nil {
+ if meta.SetStatusCondition(&obj.Status.Conditions, metav1.Condition{
+ Type: v1alpha1.ReadyCondition,
+ Status: metav1.ConditionFalse,
+ Reason: v1alpha1.ProviderNotFoundReason,
+ Message: fmt.Sprintf("Provider %q is not registered", device.Spec.Provider),
+ }) {
+ return ctrl.Result{}, r.Status().Update(ctx, obj)
+ }
+ return ctrl.Result{}, nil
+ }
+ prov, ok := p().(provider.ACLProvider)
+
if !ok {
if meta.SetStatusCondition(&obj.Status.Conditions, metav1.Condition{
Type: v1alpha1.ReadyCondition,
@@ -99,11 +118,6 @@ func (r *AccessControlListReconciler) Reconcile(ctx context.Context, req ctrl.Re
return ctrl.Result{}, nil
}
- device, err := deviceutil.GetDeviceByName(ctx, r, obj.Namespace, obj.Spec.DeviceRef.Name)
- if err != nil {
- return ctrl.Result{}, err
- }
-
if isPaused, requeue, err := paused.EnsureCondition(ctx, r.Client, device, obj); isPaused || requeue || err != nil {
return ctrl.Result{Requeue: requeue}, err
}
diff --git a/internal/controller/core/acl_controller_test.go b/internal/controller/core/acl_controller_test.go
index dda2bd847..4b2ab2927 100644
--- a/internal/controller/core/acl_controller_test.go
+++ b/internal/controller/core/acl_controller_test.go
@@ -33,6 +33,7 @@ var _ = Describe("AccessControlList Controller", func() {
Endpoint: v1alpha1.Endpoint{
Address: "192.168.10.2:9339",
},
+ Provider: "test-provider",
},
}
Expect(k8sClient.Create(ctx, device)).To(Succeed())
diff --git a/internal/controller/core/banner_controller.go b/internal/controller/core/banner_controller.go
index 9e474648e..c4bc58086 100644
--- a/internal/controller/core/banner_controller.go
+++ b/internal/controller/core/banner_controller.go
@@ -51,9 +51,6 @@ type BannerReconciler struct {
// More info: https://book.kubebuilder.io/reference/raising-events
Recorder events.EventRecorder
- // Provider is the driver that will be used to create & delete the banner.
- Provider provider.ProviderFunc
-
// Locker is used to synchronize operations on resources targeting the same device.
Locker *resourcelock.ResourceLocker
}
@@ -90,7 +87,29 @@ func (r *BannerReconciler) Reconcile(ctx context.Context, req ctrl.Request) (_ c
return ctrl.Result{}, err
}
- prov, ok := r.Provider().(provider.BannerProvider)
+ device, err := deviceutil.GetDeviceByName(ctx, r, obj.Namespace, obj.Spec.DeviceRef.Name)
+ if err != nil {
+ return ctrl.Result{}, err
+ }
+
+ if device.Spec.Provider == "" {
+ return ctrl.Result{}, fmt.Errorf("device %q has no provider set", device.Name)
+ }
+
+ p, err := provider.Get(device.Spec.Provider)
+ if err != nil {
+ if meta.SetStatusCondition(&obj.Status.Conditions, metav1.Condition{
+ Type: v1alpha1.ReadyCondition,
+ Status: metav1.ConditionFalse,
+ Reason: v1alpha1.ProviderNotFoundReason,
+ Message: fmt.Sprintf("Provider %q is not registered", device.Spec.Provider),
+ }) {
+ return ctrl.Result{}, r.Status().Update(ctx, obj)
+ }
+ return ctrl.Result{}, nil
+ }
+ prov, ok := p().(provider.BannerProvider)
+
if !ok {
if meta.SetStatusCondition(&obj.Status.Conditions, metav1.Condition{
Type: v1alpha1.ReadyCondition,
@@ -103,11 +122,6 @@ func (r *BannerReconciler) Reconcile(ctx context.Context, req ctrl.Request) (_ c
return ctrl.Result{}, nil
}
- device, err := deviceutil.GetDeviceByName(ctx, r, obj.Namespace, obj.Spec.DeviceRef.Name)
- if err != nil {
- return ctrl.Result{}, err
- }
-
if isPaused, requeue, err := paused.EnsureCondition(ctx, r.Client, device, obj); isPaused || requeue || err != nil {
return ctrl.Result{Requeue: requeue}, err
}
diff --git a/internal/controller/core/banner_controller_test.go b/internal/controller/core/banner_controller_test.go
index 0a944ce95..60dd4d978 100644
--- a/internal/controller/core/banner_controller_test.go
+++ b/internal/controller/core/banner_controller_test.go
@@ -31,6 +31,7 @@ var _ = Describe("Banner Controller", func() {
Endpoint: v1alpha1.Endpoint{
Address: "192.168.10.2:9339",
},
+ Provider: "test-provider",
},
}
Expect(k8sClient.Create(ctx, device)).To(Succeed())
diff --git a/internal/controller/core/bgp_controller.go b/internal/controller/core/bgp_controller.go
index 58e1f6892..7bbf7cd91 100644
--- a/internal/controller/core/bgp_controller.go
+++ b/internal/controller/core/bgp_controller.go
@@ -56,9 +56,6 @@ type BGPReconciler struct {
// More info: https://book.kubebuilder.io/reference/raising-events
Recorder events.EventRecorder
- // Provider is the driver that will be used to create & delete the bgp.
- Provider provider.ProviderFunc
-
// Locker is used to synchronize operations on resources targeting the same device.
Locker *resourcelock.ResourceLocker
@@ -99,7 +96,29 @@ func (r *BGPReconciler) Reconcile(ctx context.Context, req ctrl.Request) (_ ctrl
return ctrl.Result{}, err
}
- prov, ok := r.Provider().(provider.BGPProvider)
+ device, err := deviceutil.GetDeviceByName(ctx, r, obj.Namespace, obj.Spec.DeviceRef.Name)
+ if err != nil {
+ return ctrl.Result{}, err
+ }
+
+ if device.Spec.Provider == "" {
+ return ctrl.Result{}, fmt.Errorf("device %q has no provider set", device.Name)
+ }
+
+ p, err := provider.Get(device.Spec.Provider)
+ if err != nil {
+ if meta.SetStatusCondition(&obj.Status.Conditions, metav1.Condition{
+ Type: v1alpha1.ReadyCondition,
+ Status: metav1.ConditionFalse,
+ Reason: v1alpha1.ProviderNotFoundReason,
+ Message: fmt.Sprintf("Provider %q is not registered", device.Spec.Provider),
+ }) {
+ return ctrl.Result{}, r.Status().Update(ctx, obj)
+ }
+ return ctrl.Result{}, nil
+ }
+ prov, ok := p().(provider.BGPProvider)
+
if !ok {
if meta.SetStatusCondition(&obj.Status.Conditions, metav1.Condition{
Type: v1alpha1.ReadyCondition,
@@ -112,11 +131,6 @@ func (r *BGPReconciler) Reconcile(ctx context.Context, req ctrl.Request) (_ ctrl
return ctrl.Result{}, nil
}
- device, err := deviceutil.GetDeviceByName(ctx, r, obj.Namespace, obj.Spec.DeviceRef.Name)
- if err != nil {
- return ctrl.Result{}, err
- }
-
if isPaused, requeue, err := paused.EnsureCondition(ctx, r.Client, device, obj); isPaused || requeue || err != nil {
return ctrl.Result{Requeue: requeue}, err
}
diff --git a/internal/controller/core/bgp_controller_test.go b/internal/controller/core/bgp_controller_test.go
index e1a44db42..f10e60169 100644
--- a/internal/controller/core/bgp_controller_test.go
+++ b/internal/controller/core/bgp_controller_test.go
@@ -31,6 +31,7 @@ var _ = Describe("BGP Controller", func() {
Endpoint: v1alpha1.Endpoint{
Address: "192.168.10.2:9339",
},
+ Provider: "test-provider",
},
}
Expect(k8sClient.Create(ctx, device)).To(Succeed())
diff --git a/internal/controller/core/bgp_peer_controller.go b/internal/controller/core/bgp_peer_controller.go
index 72ec7ee4d..5238a5b59 100644
--- a/internal/controller/core/bgp_peer_controller.go
+++ b/internal/controller/core/bgp_peer_controller.go
@@ -59,9 +59,6 @@ type BGPPeerReconciler struct {
// More info: https://book.kubebuilder.io/reference/raising-events
Recorder events.EventRecorder
- // Provider is the driver that will be used to create & delete the bgppeer.
- Provider provider.ProviderFunc
-
// Locker is used to synchronize operations on resources targeting the same device.
Locker *resourcelock.ResourceLocker
@@ -103,7 +100,29 @@ func (r *BGPPeerReconciler) Reconcile(ctx context.Context, req ctrl.Request) (_
return ctrl.Result{}, err
}
- prov, ok := r.Provider().(provider.BGPPeerProvider)
+ device, err := deviceutil.GetDeviceByName(ctx, r, obj.Namespace, obj.Spec.DeviceRef.Name)
+ if err != nil {
+ return ctrl.Result{}, err
+ }
+
+ if device.Spec.Provider == "" {
+ return ctrl.Result{}, fmt.Errorf("device %q has no provider set", device.Name)
+ }
+
+ p, err := provider.Get(device.Spec.Provider)
+ if err != nil {
+ if meta.SetStatusCondition(&obj.Status.Conditions, metav1.Condition{
+ Type: v1alpha1.ReadyCondition,
+ Status: metav1.ConditionFalse,
+ Reason: v1alpha1.ProviderNotFoundReason,
+ Message: fmt.Sprintf("Provider %q is not registered", device.Spec.Provider),
+ }) {
+ return ctrl.Result{}, r.Status().Update(ctx, obj)
+ }
+ return ctrl.Result{}, nil
+ }
+ prov, ok := p().(provider.BGPPeerProvider)
+
if !ok {
if meta.SetStatusCondition(&obj.Status.Conditions, metav1.Condition{
Type: v1alpha1.ReadyCondition,
@@ -116,11 +135,6 @@ func (r *BGPPeerReconciler) Reconcile(ctx context.Context, req ctrl.Request) (_
return ctrl.Result{}, nil
}
- device, err := deviceutil.GetDeviceByName(ctx, r, obj.Namespace, obj.Spec.DeviceRef.Name)
- if err != nil {
- return ctrl.Result{}, err
- }
-
if isPaused, requeue, err := paused.EnsureCondition(ctx, r.Client, device, obj); isPaused || requeue || err != nil {
return ctrl.Result{Requeue: requeue}, err
}
diff --git a/internal/controller/core/bgp_peer_controller_test.go b/internal/controller/core/bgp_peer_controller_test.go
index df8588957..9ad49fa7c 100644
--- a/internal/controller/core/bgp_peer_controller_test.go
+++ b/internal/controller/core/bgp_peer_controller_test.go
@@ -31,6 +31,7 @@ var _ = Describe("BGPPeer Controller", func() {
Endpoint: v1alpha1.Endpoint{
Address: "192.168.10.2:9339",
},
+ Provider: "test-provider",
},
}
Expect(k8sClient.Create(ctx, device)).To(Succeed())
diff --git a/internal/controller/core/certificate_controller.go b/internal/controller/core/certificate_controller.go
index 640a8c75d..5c0276fdb 100644
--- a/internal/controller/core/certificate_controller.go
+++ b/internal/controller/core/certificate_controller.go
@@ -51,9 +51,6 @@ type CertificateReconciler struct {
// More info: https://book.kubebuilder.io/reference/raising-events
Recorder events.EventRecorder
- // Provider is the driver that will be used to create & delete the certificate.
- Provider provider.ProviderFunc
-
// Locker is used to synchronize operations on resources targeting the same device.
Locker *resourcelock.ResourceLocker
}
@@ -89,7 +86,29 @@ func (r *CertificateReconciler) Reconcile(ctx context.Context, req ctrl.Request)
return ctrl.Result{}, err
}
- prov, ok := r.Provider().(provider.CertificateProvider)
+ device, err := deviceutil.GetDeviceByName(ctx, r, obj.Namespace, obj.Spec.DeviceRef.Name)
+ if err != nil {
+ return ctrl.Result{}, err
+ }
+
+ if device.Spec.Provider == "" {
+ return ctrl.Result{}, fmt.Errorf("device %q has no provider set", device.Name)
+ }
+
+ p, err := provider.Get(device.Spec.Provider)
+ if err != nil {
+ if meta.SetStatusCondition(&obj.Status.Conditions, metav1.Condition{
+ Type: v1alpha1.ReadyCondition,
+ Status: metav1.ConditionFalse,
+ Reason: v1alpha1.ProviderNotFoundReason,
+ Message: fmt.Sprintf("Provider %q is not registered", device.Spec.Provider),
+ }) {
+ return ctrl.Result{}, r.Status().Update(ctx, obj)
+ }
+ return ctrl.Result{}, nil
+ }
+ prov, ok := p().(provider.CertificateProvider)
+
if !ok {
if meta.SetStatusCondition(&obj.Status.Conditions, metav1.Condition{
Type: v1alpha1.ReadyCondition,
@@ -102,11 +121,6 @@ func (r *CertificateReconciler) Reconcile(ctx context.Context, req ctrl.Request)
return ctrl.Result{}, nil
}
- device, err := deviceutil.GetDeviceByName(ctx, r, obj.Namespace, obj.Spec.DeviceRef.Name)
- if err != nil {
- return ctrl.Result{}, err
- }
-
if isPaused, requeue, err := paused.EnsureCondition(ctx, r.Client, device, obj); isPaused || requeue || err != nil {
return ctrl.Result{Requeue: requeue}, err
}
diff --git a/internal/controller/core/certificate_controller_test.go b/internal/controller/core/certificate_controller_test.go
index 8d345b18f..67448e579 100644
--- a/internal/controller/core/certificate_controller_test.go
+++ b/internal/controller/core/certificate_controller_test.go
@@ -42,6 +42,7 @@ var _ = Describe("Certificate Controller", func() {
Endpoint: v1alpha1.Endpoint{
Address: "192.168.10.2:9339",
},
+ Provider: "test-provider",
},
}
Expect(k8sClient.Create(ctx, device)).To(Succeed())
diff --git a/internal/controller/core/device_controller.go b/internal/controller/core/device_controller.go
index 9fa361d08..f6b749827 100644
--- a/internal/controller/core/device_controller.go
+++ b/internal/controller/core/device_controller.go
@@ -50,7 +50,7 @@ type DeviceReconciler struct {
Recorder events.EventRecorder
// Provider is the driver that will be used to create & delete the interface.
- Provider provider.ProviderFunc
+ // Provider provider.ProviderFunc
// HeartbeatInterval is the duration after which the controller requeues the reconciliation,
// regardless of changes.
@@ -129,7 +129,7 @@ func (r *DeviceReconciler) Reconcile(ctx context.Context, req ctrl.Request) (_ c
return ctrl.Result{}, nil
}
- if _, ok := r.Provider().(provider.ProvisioningProvider); !ok {
+ if _, err := provider.LoadProvisioningProvider(obj.Spec.Provider); err != nil {
// Skip provisioning if the provider does not support it.
log.Info("Provider does not support provisioning, skipping")
obj.Status.Phase = v1alpha1.DevicePhaseFailed
@@ -193,7 +193,11 @@ func (r *DeviceReconciler) Reconcile(ctx context.Context, req ctrl.Request) (_ c
return ctrl.Result{}, nil
}
log.Info("Device provisioning completed, running post provisioning checks")
- prov, _ := r.Provider().(provider.ProvisioningProvider)
+ prov, err := provider.LoadProvisioningProvider(obj.Spec.Provider)
+ if err != nil {
+ log.Error(err, "Failed to load provisioning provider")
+ return ctrl.Result{}, err
+ }
if ok := prov.VerifyProvisioned(ctx, conn, obj); !ok {
return ctrl.Result{RequeueAfter: r.HeartbeatInterval}, nil
}
@@ -203,7 +207,7 @@ func (r *DeviceReconciler) Reconcile(ctx context.Context, req ctrl.Request) (_ c
return ctrl.Result{}, nil
case v1alpha1.DevicePhaseRunning:
- if prov, ok := r.Provider().(provider.DeviceProvider); ok {
+ if prov, err := provider.LoadProvider[provider.DeviceProvider](obj.Spec.Provider); err == nil {
if err := r.reconcile(ctx, obj, prov, conn); err != nil {
log.Error(err, "Failed to reconcile resource")
return ctrl.Result{}, err
@@ -384,7 +388,10 @@ func (r *DeviceReconciler) reconcile(ctx context.Context, device *v1alpha1.Devic
}
func (r *DeviceReconciler) reconcileMinimal(ctx context.Context, device *v1alpha1.Device, conn *deviceutil.Connection) (reterr error) {
- prov := r.Provider()
+ prov, err := provider.LoadProvider[provider.DeviceProvider](device.Spec.Provider)
+ if err != nil {
+ return fmt.Errorf("failed to load device provider: %w", err)
+ }
if err := prov.Connect(ctx, conn); err != nil {
conditions.Set(device, metav1.Condition{
Type: v1alpha1.ReachableCondition,
@@ -440,7 +447,11 @@ func (r *DeviceReconciler) reconcileMaintenance(ctx context.Context, obj *v1alph
v1alpha1.DeviceMaintenanceFactoryReset,
v1alpha1.DeviceMaintenanceReprovision:
- prov := r.Provider()
+ prov, err := provider.LoadProvider[provider.DeviceProvider](obj.Spec.Provider)
+ if err != nil {
+ return fmt.Errorf("failed to load device provider: %w", err)
+ }
+
if err := prov.Connect(ctx, conn); err != nil {
return fmt.Errorf("failed to connect to device: %w", err)
}
diff --git a/internal/controller/core/device_controller_test.go b/internal/controller/core/device_controller_test.go
index 7ff8af567..22d8a515f 100644
--- a/internal/controller/core/device_controller_test.go
+++ b/internal/controller/core/device_controller_test.go
@@ -72,6 +72,7 @@ var _ = Describe("Device Controller", func() {
Name: name,
},
},
+ Provider: "test-provider",
},
}
Expect(k8sClient.Create(ctx, device)).To(Succeed())
@@ -160,6 +161,7 @@ var _ = Describe("Device Controller", func() {
Name: name,
},
},
+ Provider: "test-provider",
Provisioning: &v1alpha1.Provisioning{
Image: v1alpha1.Image{
URL: "http://example.com/nxos.bin",
@@ -204,6 +206,7 @@ var _ = Describe("Device Controller", func() {
Name: name,
},
},
+ Provider: "test-provider",
Provisioning: &v1alpha1.Provisioning{
Image: v1alpha1.Image{
URL: "http://example.com/nxos.bin",
@@ -261,6 +264,7 @@ var _ = Describe("Device Controller", func() {
Name: name,
},
},
+ Provider: "test-provider",
Provisioning: &v1alpha1.Provisioning{
Image: v1alpha1.Image{
URL: "http://example.com/nxos.bin",
@@ -321,6 +325,7 @@ var _ = Describe("Device Controller", func() {
Name: name,
},
},
+ Provider: "test-provider",
},
}
Expect(k8sClient.Create(ctx, device)).To(Succeed())
@@ -349,6 +354,7 @@ var _ = Describe("Device Controller", func() {
Name: name,
},
},
+ Provider: "test-provider",
},
}
Expect(k8sClient.Create(ctx, device)).To(Succeed())
@@ -404,6 +410,7 @@ var _ = Describe("Device Controller", func() {
Name: name,
},
},
+ Provider: "test-provider",
Provisioning: &v1alpha1.Provisioning{
BootScript: v1alpha1.TemplateSource{
Inline: new("boot nxos.bin"),
@@ -491,6 +498,7 @@ var _ = Describe("Device Controller", func() {
Name: name,
},
},
+ Provider: "test-provider",
},
}
Expect(k8sClient.Create(ctx, device)).To(Succeed())
@@ -539,6 +547,7 @@ var _ = Describe("Device Controller", func() {
Name: name,
},
},
+ Provider: "test-provider",
Provisioning: &v1alpha1.Provisioning{
Image: v1alpha1.Image{
URL: "http://example.com/nxos.bin",
@@ -592,6 +601,7 @@ var _ = Describe("Device Controller", func() {
Name: name,
},
},
+ Provider: "test-provider",
Provisioning: &v1alpha1.Provisioning{
Image: v1alpha1.Image{
URL: "http://example.com/nxos.bin",
@@ -658,6 +668,7 @@ var _ = Describe("Device Controller", func() {
Name: name,
},
},
+ Provider: "test-provider",
},
}
Expect(k8sClient.Create(ctx, device)).To(Succeed())
diff --git a/internal/controller/core/dhcprelay_controller.go b/internal/controller/core/dhcprelay_controller.go
index ec88c2a47..e7cfda254 100644
--- a/internal/controller/core/dhcprelay_controller.go
+++ b/internal/controller/core/dhcprelay_controller.go
@@ -51,9 +51,6 @@ type DHCPRelayReconciler struct {
// More info: https://book.kubebuilder.io/reference/raising-events
Recorder events.EventRecorder
- // Provider is the driver that will be used to create & delete the dhcp relay configuration.
- Provider provider.ProviderFunc
-
// Locker is used to synchronize operations on resources targeting the same device.
Locker *resourcelock.ResourceLocker
@@ -92,7 +89,29 @@ func (r *DHCPRelayReconciler) Reconcile(ctx context.Context, req ctrl.Request) (
return ctrl.Result{}, err
}
- prov, ok := r.Provider().(provider.DHCPRelayProvider)
+ device, err := deviceutil.GetDeviceByName(ctx, r, obj.Namespace, obj.Spec.DeviceRef.Name)
+ if err != nil {
+ return ctrl.Result{}, err
+ }
+
+ if device.Spec.Provider == "" {
+ return ctrl.Result{}, fmt.Errorf("device %q has no provider set", device.Name)
+ }
+
+ p, err := provider.Get(device.Spec.Provider)
+ if err != nil {
+ if meta.SetStatusCondition(&obj.Status.Conditions, metav1.Condition{
+ Type: v1alpha1.ReadyCondition,
+ Status: metav1.ConditionFalse,
+ Reason: v1alpha1.ProviderNotFoundReason,
+ Message: fmt.Sprintf("Provider %q is not registered", device.Spec.Provider),
+ }) {
+ return ctrl.Result{}, r.Status().Update(ctx, obj)
+ }
+ return ctrl.Result{}, nil
+ }
+ prov, ok := p().(provider.DHCPRelayProvider)
+
if !ok {
if meta.SetStatusCondition(&obj.Status.Conditions, metav1.Condition{
Type: v1alpha1.ReadyCondition,
@@ -105,11 +124,6 @@ func (r *DHCPRelayReconciler) Reconcile(ctx context.Context, req ctrl.Request) (
return ctrl.Result{}, nil
}
- device, err := deviceutil.GetDeviceByName(ctx, r, obj.Namespace, obj.Spec.DeviceRef.Name)
- if err != nil {
- return ctrl.Result{}, err
- }
-
if isPaused, requeue, err := paused.EnsureCondition(ctx, r.Client, device, obj); isPaused || requeue || err != nil {
return ctrl.Result{Requeue: requeue}, err
}
diff --git a/internal/controller/core/dhcprelay_controller_test.go b/internal/controller/core/dhcprelay_controller_test.go
index e440f1b03..149383b4f 100644
--- a/internal/controller/core/dhcprelay_controller_test.go
+++ b/internal/controller/core/dhcprelay_controller_test.go
@@ -46,6 +46,7 @@ var _ = Describe("DHCPRelay Controller", func() {
Endpoint: v1alpha1.Endpoint{
Address: "192.168.10.50:9339",
},
+ Provider: "test-provider",
},
}
Expect(k8sClient.Create(ctx, device)).To(Succeed())
@@ -391,6 +392,7 @@ var _ = Describe("DHCPRelay Controller", func() {
Endpoint: v1alpha1.Endpoint{
Address: "192.168.10.51:9339",
},
+ Provider: "test-provider",
},
}
Expect(k8sClient.Create(ctx, device)).To(Succeed())
@@ -478,6 +480,7 @@ var _ = Describe("DHCPRelay Controller", func() {
Endpoint: v1alpha1.Endpoint{
Address: "192.168.10.52:9339",
},
+ Provider: "test-provider",
},
}
Expect(k8sClient.Create(ctx, device)).To(Succeed())
@@ -494,6 +497,7 @@ var _ = Describe("DHCPRelay Controller", func() {
Endpoint: v1alpha1.Endpoint{
Address: "192.168.10.53:9339",
},
+ Provider: "test-provider",
},
}
Expect(k8sClient.Create(ctx, otherDevice)).To(Succeed())
@@ -637,6 +641,7 @@ var _ = Describe("DHCPRelay Controller", func() {
Endpoint: v1alpha1.Endpoint{
Address: "192.168.10.57:9339",
},
+ Provider: "test-provider",
},
}
Expect(k8sClient.Create(ctx, device)).To(Succeed())
@@ -653,6 +658,7 @@ var _ = Describe("DHCPRelay Controller", func() {
Endpoint: v1alpha1.Endpoint{
Address: "192.168.10.58:9339",
},
+ Provider: "test-provider",
},
}
Expect(k8sClient.Create(ctx, otherDevice)).To(Succeed())
@@ -822,6 +828,7 @@ var _ = Describe("DHCPRelay Controller", func() {
Endpoint: v1alpha1.Endpoint{
Address: "192.168.10.54:9339",
},
+ Provider: "test-provider",
},
}
Expect(k8sClient.Create(ctx, device)).To(Succeed())
@@ -1004,6 +1011,7 @@ var _ = Describe("DHCPRelay Controller", func() {
Endpoint: v1alpha1.Endpoint{
Address: "192.168.10.55:9339",
},
+ Provider: "test-provider",
},
}
Expect(k8sClient.Create(ctx, device)).To(Succeed())
diff --git a/internal/controller/core/dns_controller.go b/internal/controller/core/dns_controller.go
index 6abe047ad..391f75e91 100644
--- a/internal/controller/core/dns_controller.go
+++ b/internal/controller/core/dns_controller.go
@@ -49,9 +49,6 @@ type DNSReconciler struct {
// More info: https://book.kubebuilder.io/reference/raising-events
Recorder events.EventRecorder
- // Provider is the driver that will be used to create & delete the dns.
- Provider provider.ProviderFunc
-
// Locker is used to synchronize operations on resources targeting the same device.
Locker *resourcelock.ResourceLocker
}
@@ -86,7 +83,29 @@ func (r *DNSReconciler) Reconcile(ctx context.Context, req ctrl.Request) (_ ctrl
return ctrl.Result{}, err
}
- prov, ok := r.Provider().(provider.DNSProvider)
+ device, err := deviceutil.GetDeviceByName(ctx, r, obj.Namespace, obj.Spec.DeviceRef.Name)
+ if err != nil {
+ return ctrl.Result{}, err
+ }
+
+ if device.Spec.Provider == "" {
+ return ctrl.Result{}, fmt.Errorf("device %q has no provider set", device.Name)
+ }
+
+ p, err := provider.Get(device.Spec.Provider)
+ if err != nil {
+ if meta.SetStatusCondition(&obj.Status.Conditions, metav1.Condition{
+ Type: v1alpha1.ReadyCondition,
+ Status: metav1.ConditionFalse,
+ Reason: v1alpha1.ProviderNotFoundReason,
+ Message: fmt.Sprintf("Provider %q is not registered", device.Spec.Provider),
+ }) {
+ return ctrl.Result{}, r.Status().Update(ctx, obj)
+ }
+ return ctrl.Result{}, nil
+ }
+ prov, ok := p().(provider.DNSProvider)
+
if !ok {
if meta.SetStatusCondition(&obj.Status.Conditions, metav1.Condition{
Type: v1alpha1.ReadyCondition,
@@ -99,11 +118,6 @@ func (r *DNSReconciler) Reconcile(ctx context.Context, req ctrl.Request) (_ ctrl
return ctrl.Result{}, nil
}
- device, err := deviceutil.GetDeviceByName(ctx, r, obj.Namespace, obj.Spec.DeviceRef.Name)
- if err != nil {
- return ctrl.Result{}, err
- }
-
if isPaused, requeue, err := paused.EnsureCondition(ctx, r.Client, device, obj); isPaused || requeue || err != nil {
return ctrl.Result{Requeue: requeue}, err
}
diff --git a/internal/controller/core/dns_controller_test.go b/internal/controller/core/dns_controller_test.go
index 13fa24508..3e7cddd52 100644
--- a/internal/controller/core/dns_controller_test.go
+++ b/internal/controller/core/dns_controller_test.go
@@ -31,6 +31,7 @@ var _ = Describe("DNS Controller", func() {
Endpoint: v1alpha1.Endpoint{
Address: "192.168.10.2:9339",
},
+ Provider: "test-provider",
},
}
Expect(k8sClient.Create(ctx, device)).To(Succeed())
diff --git a/internal/controller/core/ethernetsegment_controller.go b/internal/controller/core/ethernetsegment_controller.go
index 8f0a3ee21..099736a23 100644
--- a/internal/controller/core/ethernetsegment_controller.go
+++ b/internal/controller/core/ethernetsegment_controller.go
@@ -49,9 +49,6 @@ type EthernetSegmentReconciler struct {
// More info: https://book.kubebuilder.io/reference/raising-events
Recorder events.EventRecorder
- // Provider is the driver that will be used to create & delete the ethernetsegment.
- Provider provider.ProviderFunc
-
// Locker is used to synchronize operations on resources targeting the same device.
Locker *resourcelock.ResourceLocker
@@ -90,7 +87,29 @@ func (r *EthernetSegmentReconciler) Reconcile(ctx context.Context, req ctrl.Requ
return ctrl.Result{}, err
}
- prov, ok := r.Provider().(provider.EthernetSegmentProvider)
+ device, err := deviceutil.GetDeviceByName(ctx, r, obj.Namespace, obj.Spec.DeviceRef.Name)
+ if err != nil {
+ return ctrl.Result{}, err
+ }
+
+ if device.Spec.Provider == "" {
+ return ctrl.Result{}, fmt.Errorf("device %q has no provider set", device.Name)
+ }
+
+ p, err := provider.Get(device.Spec.Provider)
+ if err != nil {
+ if meta.SetStatusCondition(&obj.Status.Conditions, metav1.Condition{
+ Type: v1alpha1.ReadyCondition,
+ Status: metav1.ConditionFalse,
+ Reason: v1alpha1.ProviderNotFoundReason,
+ Message: fmt.Sprintf("Provider %q is not registered", device.Spec.Provider),
+ }) {
+ return ctrl.Result{}, r.Status().Update(ctx, obj)
+ }
+ return ctrl.Result{}, nil
+ }
+ prov, ok := p().(provider.EthernetSegmentProvider)
+
if !ok {
if meta.SetStatusCondition(&obj.Status.Conditions, metav1.Condition{
Type: v1alpha1.ReadyCondition,
@@ -103,11 +122,6 @@ func (r *EthernetSegmentReconciler) Reconcile(ctx context.Context, req ctrl.Requ
return ctrl.Result{}, nil
}
- device, err := deviceutil.GetDeviceByName(ctx, r, obj.Namespace, obj.Spec.DeviceRef.Name)
- if err != nil {
- return ctrl.Result{}, err
- }
-
if isPaused, requeue, err := paused.EnsureCondition(ctx, r.Client, device, obj); isPaused || requeue || err != nil {
return ctrl.Result{Requeue: requeue}, err
}
diff --git a/internal/controller/core/ethernetsegment_controller_test.go b/internal/controller/core/ethernetsegment_controller_test.go
index 84f7cd983..49842bfcc 100644
--- a/internal/controller/core/ethernetsegment_controller_test.go
+++ b/internal/controller/core/ethernetsegment_controller_test.go
@@ -32,6 +32,7 @@ var _ = Describe("EthernetSegment Controller", func() {
Endpoint: v1alpha1.Endpoint{
Address: "192.168.10.2:9339",
},
+ Provider: "test-provider",
},
}
Expect(k8sClient.Create(ctx, device)).To(Succeed())
diff --git a/internal/controller/core/evpninstance_controller.go b/internal/controller/core/evpninstance_controller.go
index 724c293b4..fe93001b7 100644
--- a/internal/controller/core/evpninstance_controller.go
+++ b/internal/controller/core/evpninstance_controller.go
@@ -49,9 +49,6 @@ type EVPNInstanceReconciler struct {
// More info: https://book.kubebuilder.io/reference/raising-events
Recorder events.EventRecorder
- // Provider is the driver that will be used to create & delete the evpninstance.
- Provider provider.ProviderFunc
-
// Locker is used to synchronize operations on resources targeting the same device.
Locker *resourcelock.ResourceLocker
}
@@ -88,7 +85,29 @@ func (r *EVPNInstanceReconciler) Reconcile(ctx context.Context, req ctrl.Request
return ctrl.Result{}, err
}
- prov, ok := r.Provider().(provider.EVPNInstanceProvider)
+ device, err := deviceutil.GetDeviceByName(ctx, r, obj.Namespace, obj.Spec.DeviceRef.Name)
+ if err != nil {
+ return ctrl.Result{}, err
+ }
+
+ if device.Spec.Provider == "" {
+ return ctrl.Result{}, fmt.Errorf("device %q has no provider set", device.Name)
+ }
+
+ p, err := provider.Get(device.Spec.Provider)
+ if err != nil {
+ if meta.SetStatusCondition(&obj.Status.Conditions, metav1.Condition{
+ Type: v1alpha1.ReadyCondition,
+ Status: metav1.ConditionFalse,
+ Reason: v1alpha1.ProviderNotFoundReason,
+ Message: fmt.Sprintf("Provider %q is not registered", device.Spec.Provider),
+ }) {
+ return ctrl.Result{}, r.Status().Update(ctx, obj)
+ }
+ return ctrl.Result{}, nil
+ }
+ prov, ok := p().(provider.EVPNInstanceProvider)
+
if !ok {
if meta.SetStatusCondition(&obj.Status.Conditions, metav1.Condition{
Type: v1alpha1.ReadyCondition,
@@ -101,11 +120,6 @@ func (r *EVPNInstanceReconciler) Reconcile(ctx context.Context, req ctrl.Request
return ctrl.Result{}, nil
}
- device, err := deviceutil.GetDeviceByName(ctx, r, obj.Namespace, obj.Spec.DeviceRef.Name)
- if err != nil {
- return ctrl.Result{}, err
- }
-
if isPaused, requeue, err := paused.EnsureCondition(ctx, r.Client, device, obj); isPaused || requeue || err != nil {
return ctrl.Result{Requeue: requeue}, err
}
diff --git a/internal/controller/core/evpninstance_controller_test.go b/internal/controller/core/evpninstance_controller_test.go
index 0b3ca6ebe..3bd2fefdf 100644
--- a/internal/controller/core/evpninstance_controller_test.go
+++ b/internal/controller/core/evpninstance_controller_test.go
@@ -32,6 +32,7 @@ var _ = Describe("EVPNInstance Controller", func() {
Endpoint: v1alpha1.Endpoint{
Address: "192.168.10.2:9339",
},
+ Provider: "test-provider",
},
}
Expect(k8sClient.Create(ctx, device)).To(Succeed())
diff --git a/internal/controller/core/interface_controller.go b/internal/controller/core/interface_controller.go
index 8e5f7a46d..e43cf6a2b 100644
--- a/internal/controller/core/interface_controller.go
+++ b/internal/controller/core/interface_controller.go
@@ -54,9 +54,6 @@ type InterfaceReconciler struct {
// More info: https://book.kubebuilder.io/reference/raising-events
Recorder events.EventRecorder
- // Provider is the driver that will be used to create & delete the interface.
- Provider provider.ProviderFunc
-
// Locker is used to synchronize operations on resources targeting the same device.
Locker *resourcelock.ResourceLocker
@@ -65,6 +62,34 @@ type InterfaceReconciler struct {
RequeueInterval time.Duration
}
+// handleProviderError handles provider loading errors and updates the object status condition accordingly.
+// Returns (handled, error) where handled=true means the error was processed and reconciliation should return.
+func (r *InterfaceReconciler) handleProviderError(ctx context.Context, obj *v1alpha1.Interface, providerName string, err error) (bool, error) {
+ if errors.Is(err, provider.NotFoundError{}) {
+ if meta.SetStatusCondition(&obj.Status.Conditions, metav1.Condition{
+ Type: v1alpha1.ReadyCondition,
+ Status: metav1.ConditionFalse,
+ Reason: v1alpha1.ProviderNotFoundReason,
+ Message: fmt.Sprintf("Provider %q is not registered", providerName),
+ }) {
+ return true, r.Status().Update(ctx, obj)
+ }
+ return true, nil
+ }
+ if errors.Is(err, provider.NotImplementedError{}) {
+ if meta.SetStatusCondition(&obj.Status.Conditions, metav1.Condition{
+ Type: v1alpha1.ReadyCondition,
+ Status: metav1.ConditionFalse,
+ Reason: v1alpha1.NotImplementedReason,
+ Message: "Provider does not implement provider.InterfaceProvider",
+ }) {
+ return true, r.Status().Update(ctx, obj)
+ }
+ return true, nil
+ }
+ return false, err
+}
+
// +kubebuilder:rbac:groups=networking.metal.ironcore.dev,resources=interfaces,verbs=get;list;watch;create;update;patch;delete
// +kubebuilder:rbac:groups=networking.metal.ironcore.dev,resources=interfaces/status,verbs=get;update;patch
// +kubebuilder:rbac:groups=networking.metal.ironcore.dev,resources=interfaces/finalizers,verbs=update
@@ -98,24 +123,22 @@ func (r *InterfaceReconciler) Reconcile(ctx context.Context, req ctrl.Request) (
return ctrl.Result{}, err
}
- prov, ok := r.Provider().(provider.InterfaceProvider)
- if !ok {
- if meta.SetStatusCondition(&obj.Status.Conditions, metav1.Condition{
- Type: v1alpha1.ReadyCondition,
- Status: metav1.ConditionFalse,
- Reason: v1alpha1.NotImplementedReason,
- Message: "Provider does not implement provider.InterfaceProvider",
- }) {
- return ctrl.Result{}, r.Status().Update(ctx, obj)
- }
- return ctrl.Result{}, nil
- }
-
device, err := deviceutil.GetDeviceByName(ctx, r, obj.Namespace, obj.Spec.DeviceRef.Name)
if err != nil {
return ctrl.Result{}, err
}
+ if device.Spec.Provider == "" {
+ return ctrl.Result{}, fmt.Errorf("device %q has no provider set", device.Name)
+ }
+
+ prov, err := provider.LoadProvider[provider.InterfaceProvider](device.Spec.Provider)
+ if err != nil {
+ if handled, herr := r.handleProviderError(ctx, obj, device.Spec.Provider, err); handled {
+ return ctrl.Result{}, herr
+ }
+ }
+
if isPaused, requeue, err := paused.EnsureCondition(ctx, r.Client, device, obj); isPaused || requeue || err != nil {
return ctrl.Result{Requeue: requeue}, err
}
diff --git a/internal/controller/core/interface_controller_test.go b/internal/controller/core/interface_controller_test.go
index a250cb2af..cf9109ca5 100644
--- a/internal/controller/core/interface_controller_test.go
+++ b/internal/controller/core/interface_controller_test.go
@@ -35,6 +35,7 @@ var _ = Describe("Interface Controller", func() {
Endpoint: v1alpha1.Endpoint{
Address: "192.168.10.2:9339",
},
+ Provider: "test-provider",
},
}
Expect(k8sClient.Create(ctx, device)).To(Succeed())
@@ -1276,6 +1277,7 @@ var _ = Describe("Interface Controller", func() {
Endpoint: v1alpha1.Endpoint{
Address: "192.168.10.10:9339",
},
+ Provider: "test-provider",
},
}
Expect(k8sClient.Create(ctx, localDevice)).To(Succeed())
@@ -1289,6 +1291,7 @@ var _ = Describe("Interface Controller", func() {
Endpoint: v1alpha1.Endpoint{
Address: "192.168.10.11:9339",
},
+ Provider: "test-provider",
},
}
Expect(k8sClient.Create(ctx, remoteDevice)).To(Succeed())
diff --git a/internal/controller/core/isis_controller.go b/internal/controller/core/isis_controller.go
index 00c77033b..3e0a3a132 100644
--- a/internal/controller/core/isis_controller.go
+++ b/internal/controller/core/isis_controller.go
@@ -50,9 +50,6 @@ type ISISReconciler struct {
// More info: https://book.kubebuilder.io/reference/raising-events
Recorder events.EventRecorder
- // Provider is the driver that will be used to create & delete the isis.
- Provider provider.ProviderFunc
-
// Locker is used to synchronize operations on resources targeting the same device.
Locker *resourcelock.ResourceLocker
}
@@ -87,7 +84,29 @@ func (r *ISISReconciler) Reconcile(ctx context.Context, req ctrl.Request) (_ ctr
return ctrl.Result{}, err
}
- prov, ok := r.Provider().(provider.ISISProvider)
+ device, err := deviceutil.GetDeviceByName(ctx, r, obj.Namespace, obj.Spec.DeviceRef.Name)
+ if err != nil {
+ return ctrl.Result{}, err
+ }
+
+ if device.Spec.Provider == "" {
+ return ctrl.Result{}, fmt.Errorf("device %q has no provider set", device.Name)
+ }
+
+ p, err := provider.Get(device.Spec.Provider)
+ if err != nil {
+ if meta.SetStatusCondition(&obj.Status.Conditions, metav1.Condition{
+ Type: v1alpha1.ReadyCondition,
+ Status: metav1.ConditionFalse,
+ Reason: v1alpha1.ProviderNotFoundReason,
+ Message: fmt.Sprintf("Provider %q is not registered", device.Spec.Provider),
+ }) {
+ return ctrl.Result{}, r.Status().Update(ctx, obj)
+ }
+ return ctrl.Result{}, nil
+ }
+ prov, ok := p().(provider.ISISProvider)
+
if !ok {
if meta.SetStatusCondition(&obj.Status.Conditions, metav1.Condition{
Type: v1alpha1.ReadyCondition,
@@ -100,11 +119,6 @@ func (r *ISISReconciler) Reconcile(ctx context.Context, req ctrl.Request) (_ ctr
return ctrl.Result{}, nil
}
- device, err := deviceutil.GetDeviceByName(ctx, r, obj.Namespace, obj.Spec.DeviceRef.Name)
- if err != nil {
- return ctrl.Result{}, err
- }
-
if isPaused, requeue, err := paused.EnsureCondition(ctx, r.Client, device, obj); isPaused || requeue || err != nil {
return ctrl.Result{Requeue: requeue}, err
}
diff --git a/internal/controller/core/isis_controller_test.go b/internal/controller/core/isis_controller_test.go
index 3331cf3eb..a966dbd56 100644
--- a/internal/controller/core/isis_controller_test.go
+++ b/internal/controller/core/isis_controller_test.go
@@ -31,6 +31,7 @@ var _ = Describe("ISIS Controller", func() {
Endpoint: v1alpha1.Endpoint{
Address: "192.168.10.2:9339",
},
+ Provider: "test-provider",
},
}
Expect(k8sClient.Create(ctx, device)).To(Succeed())
@@ -138,6 +139,7 @@ var _ = Describe("ISIS Controller", func() {
Endpoint: v1alpha1.Endpoint{
Address: "192.168.10.2:9339",
},
+ Provider: "test-provider",
},
}
Expect(k8sClient.Create(ctx, device)).To(Succeed())
diff --git a/internal/controller/core/lldp_controller.go b/internal/controller/core/lldp_controller.go
index 4a4471b45..695301514 100644
--- a/internal/controller/core/lldp_controller.go
+++ b/internal/controller/core/lldp_controller.go
@@ -51,9 +51,6 @@ type LLDPReconciler struct {
// More info: https://book.kubebuilder.io/reference/raising-events
Recorder events.EventRecorder
- // Provider is the driver that will be used to create & delete the LLDP.
- Provider provider.ProviderFunc
-
// Locker is used to synchronize operations on resources targeting the same device.
Locker *resourcelock.ResourceLocker
@@ -87,22 +84,39 @@ func (r *LLDPReconciler) Reconcile(ctx context.Context, req ctrl.Request) (_ ctr
return ctrl.Result{}, err
}
- prov, ok := r.Provider().(provider.LLDPProvider)
- if !ok {
+ device, err := deviceutil.GetDeviceByName(ctx, r, obj.Namespace, obj.Spec.DeviceRef.Name)
+ if err != nil {
+ return ctrl.Result{}, err
+ }
+
+ if device.Spec.Provider == "" {
+ return ctrl.Result{}, fmt.Errorf("device %q has no provider set", device.Name)
+ }
+
+ p, err := provider.Get(device.Spec.Provider)
+ if err != nil {
if meta.SetStatusCondition(&obj.Status.Conditions, metav1.Condition{
Type: v1alpha1.ReadyCondition,
Status: metav1.ConditionFalse,
- Reason: v1alpha1.NotImplementedReason,
- Message: "Provider does not implement provider LLDPProvider",
+ Reason: v1alpha1.ProviderNotFoundReason,
+ Message: fmt.Sprintf("Provider %q is not registered", device.Spec.Provider),
}) {
return ctrl.Result{}, r.Status().Update(ctx, obj)
}
return ctrl.Result{}, nil
}
+ prov, ok := p().(provider.LLDPProvider)
- device, err := deviceutil.GetDeviceByName(ctx, r, obj.Namespace, obj.Spec.DeviceRef.Name)
- if err != nil {
- return ctrl.Result{}, err
+ if !ok {
+ if meta.SetStatusCondition(&obj.Status.Conditions, metav1.Condition{
+ Type: v1alpha1.ReadyCondition,
+ Status: metav1.ConditionFalse,
+ Reason: v1alpha1.NotImplementedReason,
+ Message: "Provider does not implement provider.LLDPProvider",
+ }) {
+ return ctrl.Result{}, r.Status().Update(ctx, obj)
+ }
+ return ctrl.Result{}, nil
}
if isPaused, requeue, err := paused.EnsureCondition(ctx, r.Client, device, obj); isPaused || requeue || err != nil {
diff --git a/internal/controller/core/lldp_controller_test.go b/internal/controller/core/lldp_controller_test.go
index f47e833da..3367e4984 100644
--- a/internal/controller/core/lldp_controller_test.go
+++ b/internal/controller/core/lldp_controller_test.go
@@ -37,6 +37,7 @@ var _ = Describe("LLDP Controller", func() {
Endpoint: v1alpha1.Endpoint{
Address: "192.168.10.2:9339",
},
+ Provider: "test-provider",
},
}
Expect(k8sClient.Create(ctx, device)).To(Succeed())
@@ -334,6 +335,7 @@ var _ = Describe("LLDP Controller", func() {
Endpoint: v1alpha1.Endpoint{
Address: "192.168.10.6:9339",
},
+ Provider: "test-provider",
},
}
Expect(k8sClient.Create(ctx, device)).To(Succeed())
@@ -456,6 +458,7 @@ var _ = Describe("LLDP Controller", func() {
Endpoint: v1alpha1.Endpoint{
Address: "192.168.10.2:9339",
},
+ Provider: "test-provider",
},
}
Expect(k8sClient.Create(ctx, device)).To(Succeed())
@@ -604,6 +607,7 @@ var _ = Describe("LLDP Controller", func() {
Endpoint: v1alpha1.Endpoint{
Address: "192.168.10.3:9339",
},
+ Provider: "test-provider",
},
}
Expect(k8sClient.Create(ctx, device)).To(Succeed())
@@ -688,6 +692,7 @@ var _ = Describe("LLDP Controller", func() {
Endpoint: v1alpha1.Endpoint{
Address: "192.168.10.99:9339",
},
+ Provider: "test-provider",
},
}
Expect(k8sClient.Create(ctx, otherDevice)).To(Succeed())
@@ -839,6 +844,7 @@ var _ = Describe("LLDP Controller", func() {
Endpoint: v1alpha1.Endpoint{
Address: "192.168.10.4:9339",
},
+ Provider: "test-provider",
},
}
Expect(k8sClient.Create(ctx, device)).To(Succeed())
@@ -1081,6 +1087,7 @@ var _ = Describe("LLDP Controller", func() {
Endpoint: v1alpha1.Endpoint{
Address: "192.168.10.7:9339",
},
+ Provider: "test-provider",
},
}
Expect(k8sClient.Create(ctx, device)).To(Succeed())
@@ -1272,6 +1279,7 @@ var _ = Describe("LLDP Controller", func() {
Endpoint: v1alpha1.Endpoint{
Address: "192.168.10.8:9339",
},
+ Provider: "test-provider",
},
}
Expect(k8sClient.Create(ctx, device)).To(Succeed())
diff --git a/internal/controller/core/managementaccess_controller.go b/internal/controller/core/managementaccess_controller.go
index 1cd63f6d2..10ca3eb7c 100644
--- a/internal/controller/core/managementaccess_controller.go
+++ b/internal/controller/core/managementaccess_controller.go
@@ -49,9 +49,6 @@ type ManagementAccessReconciler struct {
// More info: https://book.kubebuilder.io/reference/raising-events
Recorder events.EventRecorder
- // Provider is the driver that will be used to create & delete the managementaccess.
- Provider provider.ProviderFunc
-
// Locker is used to synchronize operations on resources targeting the same device.
Locker *resourcelock.ResourceLocker
}
@@ -86,7 +83,29 @@ func (r *ManagementAccessReconciler) Reconcile(ctx context.Context, req ctrl.Req
return ctrl.Result{}, err
}
- prov, ok := r.Provider().(provider.ManagementAccessProvider)
+ device, err := deviceutil.GetDeviceByName(ctx, r, obj.Namespace, obj.Spec.DeviceRef.Name)
+ if err != nil {
+ return ctrl.Result{}, err
+ }
+
+ if device.Spec.Provider == "" {
+ return ctrl.Result{}, fmt.Errorf("device %q has no provider set", device.Name)
+ }
+
+ p, err := provider.Get(device.Spec.Provider)
+ if err != nil {
+ if meta.SetStatusCondition(&obj.Status.Conditions, metav1.Condition{
+ Type: v1alpha1.ReadyCondition,
+ Status: metav1.ConditionFalse,
+ Reason: v1alpha1.ProviderNotFoundReason,
+ Message: fmt.Sprintf("Provider %q is not registered", device.Spec.Provider),
+ }) {
+ return ctrl.Result{}, r.Status().Update(ctx, obj)
+ }
+ return ctrl.Result{}, nil
+ }
+ prov, ok := p().(provider.ManagementAccessProvider)
+
if !ok {
if meta.SetStatusCondition(&obj.Status.Conditions, metav1.Condition{
Type: v1alpha1.ReadyCondition,
@@ -99,11 +118,6 @@ func (r *ManagementAccessReconciler) Reconcile(ctx context.Context, req ctrl.Req
return ctrl.Result{}, nil
}
- device, err := deviceutil.GetDeviceByName(ctx, r, obj.Namespace, obj.Spec.DeviceRef.Name)
- if err != nil {
- return ctrl.Result{}, err
- }
-
if isPaused, requeue, err := paused.EnsureCondition(ctx, r.Client, device, obj); isPaused || requeue || err != nil {
return ctrl.Result{Requeue: requeue}, err
}
diff --git a/internal/controller/core/managementaccess_controller_test.go b/internal/controller/core/managementaccess_controller_test.go
index bc52d7479..57f39e5a5 100644
--- a/internal/controller/core/managementaccess_controller_test.go
+++ b/internal/controller/core/managementaccess_controller_test.go
@@ -31,6 +31,7 @@ var _ = Describe("ManagementAccess Controller", func() {
Endpoint: v1alpha1.Endpoint{
Address: "192.168.10.2:9339",
},
+ Provider: "test-provider",
},
}
Expect(k8sClient.Create(ctx, device)).To(Succeed())
diff --git a/internal/controller/core/ntp_controller.go b/internal/controller/core/ntp_controller.go
index 806799a50..4000388f6 100644
--- a/internal/controller/core/ntp_controller.go
+++ b/internal/controller/core/ntp_controller.go
@@ -49,9 +49,6 @@ type NTPReconciler struct {
// More info: https://book.kubebuilder.io/reference/raising-events
Recorder events.EventRecorder
- // Provider is the driver that will be used to create & delete the ntp.
- Provider provider.ProviderFunc
-
// Locker is used to synchronize operations on resources targeting the same device.
Locker *resourcelock.ResourceLocker
}
@@ -86,7 +83,29 @@ func (r *NTPReconciler) Reconcile(ctx context.Context, req ctrl.Request) (_ ctrl
return ctrl.Result{}, err
}
- prov, ok := r.Provider().(provider.NTPProvider)
+ device, err := deviceutil.GetDeviceByName(ctx, r, obj.Namespace, obj.Spec.DeviceRef.Name)
+ if err != nil {
+ return ctrl.Result{}, err
+ }
+
+ if device.Spec.Provider == "" {
+ return ctrl.Result{}, fmt.Errorf("device %q has no provider set", device.Name)
+ }
+
+ p, err := provider.Get(device.Spec.Provider)
+ if err != nil {
+ if meta.SetStatusCondition(&obj.Status.Conditions, metav1.Condition{
+ Type: v1alpha1.ReadyCondition,
+ Status: metav1.ConditionFalse,
+ Reason: v1alpha1.ProviderNotFoundReason,
+ Message: fmt.Sprintf("Provider %q is not registered", device.Spec.Provider),
+ }) {
+ return ctrl.Result{}, r.Status().Update(ctx, obj)
+ }
+ return ctrl.Result{}, nil
+ }
+ prov, ok := p().(provider.NTPProvider)
+
if !ok {
if meta.SetStatusCondition(&obj.Status.Conditions, metav1.Condition{
Type: v1alpha1.ReadyCondition,
@@ -99,11 +118,6 @@ func (r *NTPReconciler) Reconcile(ctx context.Context, req ctrl.Request) (_ ctrl
return ctrl.Result{}, nil
}
- device, err := deviceutil.GetDeviceByName(ctx, r, obj.Namespace, obj.Spec.DeviceRef.Name)
- if err != nil {
- return ctrl.Result{}, err
- }
-
if isPaused, requeue, err := paused.EnsureCondition(ctx, r.Client, device, obj); isPaused || requeue || err != nil {
return ctrl.Result{Requeue: requeue}, err
}
diff --git a/internal/controller/core/ntp_controller_test.go b/internal/controller/core/ntp_controller_test.go
index c51dab2bb..43acc5de0 100644
--- a/internal/controller/core/ntp_controller_test.go
+++ b/internal/controller/core/ntp_controller_test.go
@@ -31,6 +31,7 @@ var _ = Describe("NTP Controller", func() {
Endpoint: v1alpha1.Endpoint{
Address: "192.168.10.2:9339",
},
+ Provider: "test-provider",
},
}
Expect(k8sClient.Create(ctx, device)).To(Succeed())
diff --git a/internal/controller/core/nve_controller.go b/internal/controller/core/nve_controller.go
index bb032f748..da9aa736d 100644
--- a/internal/controller/core/nve_controller.go
+++ b/internal/controller/core/nve_controller.go
@@ -51,9 +51,6 @@ type NetworkVirtualizationEdgeReconciler struct {
// More info: https://book.kubebuilder.io/reference/raising-events
Recorder events.EventRecorder
- // Provider is the driver that will be used to create & delete the dns.
- Provider provider.ProviderFunc
-
// Locker is used to synchronize operations on resources targeting the same device.
Locker *resourcelock.ResourceLocker
@@ -87,22 +84,39 @@ func (r *NetworkVirtualizationEdgeReconciler) Reconcile(ctx context.Context, req
return ctrl.Result{}, err
}
- prov, ok := r.Provider().(provider.NVEProvider)
- if !ok {
+ device, err := deviceutil.GetDeviceByName(ctx, r, obj.Namespace, obj.Spec.DeviceRef.Name)
+ if err != nil {
+ return ctrl.Result{}, err
+ }
+
+ if device.Spec.Provider == "" {
+ return ctrl.Result{}, fmt.Errorf("device %q has no provider set", device.Name)
+ }
+
+ p, err := provider.Get(device.Spec.Provider)
+ if err != nil {
if meta.SetStatusCondition(&obj.Status.Conditions, metav1.Condition{
Type: v1alpha1.ReadyCondition,
Status: metav1.ConditionFalse,
- Reason: v1alpha1.NotImplementedReason,
- Message: "Provider does not implement provider NVEProvider",
+ Reason: v1alpha1.ProviderNotFoundReason,
+ Message: fmt.Sprintf("Provider %q is not registered", device.Spec.Provider),
}) {
return ctrl.Result{}, r.Status().Update(ctx, obj)
}
return ctrl.Result{}, nil
}
+ prov, ok := p().(provider.NVEProvider)
- device, err := deviceutil.GetDeviceByName(ctx, r, obj.Namespace, obj.Spec.DeviceRef.Name)
- if err != nil {
- return ctrl.Result{}, err
+ if !ok {
+ if meta.SetStatusCondition(&obj.Status.Conditions, metav1.Condition{
+ Type: v1alpha1.ReadyCondition,
+ Status: metav1.ConditionFalse,
+ Reason: v1alpha1.NotImplementedReason,
+ Message: "Provider does not implement provider.NVEProvider",
+ }) {
+ return ctrl.Result{}, r.Status().Update(ctx, obj)
+ }
+ return ctrl.Result{}, nil
}
if isPaused, requeue, err := paused.EnsureCondition(ctx, r.Client, device, obj); isPaused || requeue || err != nil {
diff --git a/internal/controller/core/nve_controller_test.go b/internal/controller/core/nve_controller_test.go
index 0ce53e624..b0b238a95 100644
--- a/internal/controller/core/nve_controller_test.go
+++ b/internal/controller/core/nve_controller_test.go
@@ -38,6 +38,7 @@ var _ = Describe("NVE Controller", func() {
},
Spec: v1alpha1.DeviceSpec{
Endpoint: v1alpha1.Endpoint{Address: testEndpointAddr},
+ Provider: "test-provider",
},
}
Expect(k8sClient.Create(ctx, device)).To(Succeed())
@@ -206,6 +207,7 @@ var _ = Describe("NVE Controller", func() {
},
Spec: v1alpha1.DeviceSpec{
Endpoint: v1alpha1.Endpoint{Address: testEndpointAddr},
+ Provider: "test-provider",
},
}
Expect(k8sClient.Create(ctx, device)).To(Succeed())
@@ -324,6 +326,7 @@ var _ = Describe("NVE Controller", func() {
},
Spec: v1alpha1.DeviceSpec{
Endpoint: v1alpha1.Endpoint{Address: testEndpointAddr},
+ Provider: "test-provider",
},
}
Expect(k8sClient.Create(ctx, device)).To(Succeed())
@@ -398,6 +401,7 @@ var _ = Describe("NVE Controller", func() {
},
Spec: v1alpha1.DeviceSpec{
Endpoint: v1alpha1.Endpoint{Address: testEndpointAddr},
+ Provider: "test-provider",
},
}
Expect(k8sClient.Create(ctx, device)).To(Succeed())
@@ -492,6 +496,7 @@ var _ = Describe("NVE Controller", func() {
},
Spec: v1alpha1.DeviceSpec{
Endpoint: v1alpha1.Endpoint{Address: testEndpointAddr},
+ Provider: "test-provider",
},
}
Expect(k8sClient.Create(ctx, device)).To(Succeed())
@@ -600,6 +605,7 @@ var _ = Describe("NVE Controller", func() {
},
Spec: v1alpha1.DeviceSpec{
Endpoint: v1alpha1.Endpoint{Address: testEndpointAddr},
+ Provider: "test-provider",
},
}
Expect(k8sClient.Create(ctx, device)).To(Succeed())
@@ -699,6 +705,7 @@ var _ = Describe("NVE Controller", func() {
},
Spec: v1alpha1.DeviceSpec{
Endpoint: v1alpha1.Endpoint{Address: testEndpointAddr},
+ Provider: "test-provider",
},
}
Expect(k8sClient.Create(ctx, device)).To(Succeed())
@@ -714,6 +721,7 @@ var _ = Describe("NVE Controller", func() {
},
Spec: v1alpha1.DeviceSpec{
Endpoint: v1alpha1.Endpoint{Address: testEndpointAddr},
+ Provider: "test-provider",
},
}
Expect(k8sClient.Create(ctx, device2)).To(Succeed())
@@ -818,6 +826,7 @@ var _ = Describe("NVE Controller", func() {
},
Spec: v1alpha1.DeviceSpec{
Endpoint: v1alpha1.Endpoint{Address: testEndpointAddr},
+ Provider: "test-provider",
},
}
Expect(k8sClient.Create(ctx, device)).To(Succeed())
diff --git a/internal/controller/core/ospf_controller.go b/internal/controller/core/ospf_controller.go
index 2e69c38fe..589553274 100644
--- a/internal/controller/core/ospf_controller.go
+++ b/internal/controller/core/ospf_controller.go
@@ -52,9 +52,6 @@ type OSPFReconciler struct {
// More info: https://book.kubebuilder.io/reference/raising-events
Recorder events.EventRecorder
- // Provider is the driver that will be used to create & delete the ospf.
- Provider provider.ProviderFunc
-
// Locker is used to synchronize operations on resources targeting the same device.
Locker *resourcelock.ResourceLocker
@@ -93,7 +90,29 @@ func (r *OSPFReconciler) Reconcile(ctx context.Context, req ctrl.Request) (_ ctr
return ctrl.Result{}, err
}
- prov, ok := r.Provider().(provider.OSPFProvider)
+ device, err := deviceutil.GetDeviceByName(ctx, r, obj.Namespace, obj.Spec.DeviceRef.Name)
+ if err != nil {
+ return ctrl.Result{}, err
+ }
+
+ if device.Spec.Provider == "" {
+ return ctrl.Result{}, fmt.Errorf("device %q has no provider set", device.Name)
+ }
+
+ p, err := provider.Get(device.Spec.Provider)
+ if err != nil {
+ if meta.SetStatusCondition(&obj.Status.Conditions, metav1.Condition{
+ Type: v1alpha1.ReadyCondition,
+ Status: metav1.ConditionFalse,
+ Reason: v1alpha1.ProviderNotFoundReason,
+ Message: fmt.Sprintf("Provider %q is not registered", device.Spec.Provider),
+ }) {
+ return ctrl.Result{}, r.Status().Update(ctx, obj)
+ }
+ return ctrl.Result{}, nil
+ }
+ prov, ok := p().(provider.OSPFProvider)
+
if !ok {
if meta.SetStatusCondition(&obj.Status.Conditions, metav1.Condition{
Type: v1alpha1.ReadyCondition,
@@ -106,11 +125,6 @@ func (r *OSPFReconciler) Reconcile(ctx context.Context, req ctrl.Request) (_ ctr
return ctrl.Result{}, nil
}
- device, err := deviceutil.GetDeviceByName(ctx, r, obj.Namespace, obj.Spec.DeviceRef.Name)
- if err != nil {
- return ctrl.Result{}, err
- }
-
if isPaused, requeue, err := paused.EnsureCondition(ctx, r.Client, device, obj); isPaused || requeue || err != nil {
return ctrl.Result{Requeue: requeue}, err
}
diff --git a/internal/controller/core/ospf_controller_test.go b/internal/controller/core/ospf_controller_test.go
index 183991695..1ce039dbc 100644
--- a/internal/controller/core/ospf_controller_test.go
+++ b/internal/controller/core/ospf_controller_test.go
@@ -32,6 +32,7 @@ var _ = Describe("OSPF Controller", func() {
Endpoint: v1alpha1.Endpoint{
Address: "192.168.10.2:9339",
},
+ Provider: "test-provider",
},
}
Expect(k8sClient.Create(ctx, device)).To(Succeed())
@@ -137,6 +138,7 @@ var _ = Describe("OSPF Controller", func() {
Endpoint: v1alpha1.Endpoint{
Address: "192.168.10.3:9339",
},
+ Provider: "test-provider",
},
}
Expect(k8sClient.Create(ctx, device)).To(Succeed())
diff --git a/internal/controller/core/pim_controller.go b/internal/controller/core/pim_controller.go
index 5bd8d03ea..d8b264054 100644
--- a/internal/controller/core/pim_controller.go
+++ b/internal/controller/core/pim_controller.go
@@ -50,9 +50,6 @@ type PIMReconciler struct {
// More info: https://book.kubebuilder.io/reference/raising-events
Recorder events.EventRecorder
- // Provider is the driver that will be used to create & delete the pim.
- Provider provider.ProviderFunc
-
// Locker is used to synchronize operations on resources targeting the same device.
Locker *resourcelock.ResourceLocker
}
@@ -87,7 +84,29 @@ func (r *PIMReconciler) Reconcile(ctx context.Context, req ctrl.Request) (_ ctrl
return ctrl.Result{}, err
}
- prov, ok := r.Provider().(provider.PIMProvider)
+ device, err := deviceutil.GetDeviceByName(ctx, r, obj.Namespace, obj.Spec.DeviceRef.Name)
+ if err != nil {
+ return ctrl.Result{}, err
+ }
+
+ if device.Spec.Provider == "" {
+ return ctrl.Result{}, fmt.Errorf("device %q has no provider set", device.Name)
+ }
+
+ p, err := provider.Get(device.Spec.Provider)
+ if err != nil {
+ if meta.SetStatusCondition(&obj.Status.Conditions, metav1.Condition{
+ Type: v1alpha1.ReadyCondition,
+ Status: metav1.ConditionFalse,
+ Reason: v1alpha1.ProviderNotFoundReason,
+ Message: fmt.Sprintf("Provider %q is not registered", device.Spec.Provider),
+ }) {
+ return ctrl.Result{}, r.Status().Update(ctx, obj)
+ }
+ return ctrl.Result{}, nil
+ }
+ prov, ok := p().(provider.PIMProvider)
+
if !ok {
if meta.SetStatusCondition(&obj.Status.Conditions, metav1.Condition{
Type: v1alpha1.ReadyCondition,
@@ -100,11 +119,6 @@ func (r *PIMReconciler) Reconcile(ctx context.Context, req ctrl.Request) (_ ctrl
return ctrl.Result{}, nil
}
- device, err := deviceutil.GetDeviceByName(ctx, r, obj.Namespace, obj.Spec.DeviceRef.Name)
- if err != nil {
- return ctrl.Result{}, err
- }
-
if isPaused, requeue, err := paused.EnsureCondition(ctx, r.Client, device, obj); isPaused || requeue || err != nil {
return ctrl.Result{Requeue: requeue}, err
}
diff --git a/internal/controller/core/pim_controller_test.go b/internal/controller/core/pim_controller_test.go
index 241796bf7..c36800ddd 100644
--- a/internal/controller/core/pim_controller_test.go
+++ b/internal/controller/core/pim_controller_test.go
@@ -32,6 +32,7 @@ var _ = Describe("PIM Controller", func() {
Endpoint: v1alpha1.Endpoint{
Address: "192.168.10.2:9339",
},
+ Provider: "test-provider",
},
}
Expect(k8sClient.Create(ctx, device)).To(Succeed())
@@ -131,6 +132,7 @@ var _ = Describe("PIM Controller", func() {
Endpoint: v1alpha1.Endpoint{
Address: "192.168.10.2:9339",
},
+ Provider: "test-provider",
},
}
Expect(k8sClient.Create(ctx, device)).To(Succeed())
diff --git a/internal/controller/core/prefixset_controller.go b/internal/controller/core/prefixset_controller.go
index 73a220631..76799a74d 100644
--- a/internal/controller/core/prefixset_controller.go
+++ b/internal/controller/core/prefixset_controller.go
@@ -49,9 +49,6 @@ type PrefixSetReconciler struct {
// More info: https://book.kubebuilder.io/reference/raising-events
Recorder events.EventRecorder
- // Provider is the driver that will be used to create & delete the prefixset.
- Provider provider.ProviderFunc
-
// Locker is used to synchronize operations on resources targeting the same device.
Locker *resourcelock.ResourceLocker
}
@@ -86,7 +83,29 @@ func (r *PrefixSetReconciler) Reconcile(ctx context.Context, req ctrl.Request) (
return ctrl.Result{}, err
}
- prov, ok := r.Provider().(provider.PrefixSetProvider)
+ device, err := deviceutil.GetDeviceByName(ctx, r, obj.Namespace, obj.Spec.DeviceRef.Name)
+ if err != nil {
+ return ctrl.Result{}, err
+ }
+
+ if device.Spec.Provider == "" {
+ return ctrl.Result{}, fmt.Errorf("device %q has no provider set", device.Name)
+ }
+
+ p, err := provider.Get(device.Spec.Provider)
+ if err != nil {
+ if meta.SetStatusCondition(&obj.Status.Conditions, metav1.Condition{
+ Type: v1alpha1.ReadyCondition,
+ Status: metav1.ConditionFalse,
+ Reason: v1alpha1.ProviderNotFoundReason,
+ Message: fmt.Sprintf("Provider %q is not registered", device.Spec.Provider),
+ }) {
+ return ctrl.Result{}, r.Status().Update(ctx, obj)
+ }
+ return ctrl.Result{}, nil
+ }
+ prov, ok := p().(provider.PrefixSetProvider)
+
if !ok {
if meta.SetStatusCondition(&obj.Status.Conditions, metav1.Condition{
Type: v1alpha1.ReadyCondition,
@@ -99,11 +118,6 @@ func (r *PrefixSetReconciler) Reconcile(ctx context.Context, req ctrl.Request) (
return ctrl.Result{}, nil
}
- device, err := deviceutil.GetDeviceByName(ctx, r, obj.Namespace, obj.Spec.DeviceRef.Name)
- if err != nil {
- return ctrl.Result{}, err
- }
-
if isPaused, requeue, err := paused.EnsureCondition(ctx, r.Client, device, obj); isPaused || requeue || err != nil {
return ctrl.Result{Requeue: requeue}, err
}
diff --git a/internal/controller/core/prefixset_controller_test.go b/internal/controller/core/prefixset_controller_test.go
index 5560d2af0..ea4a40d1b 100644
--- a/internal/controller/core/prefixset_controller_test.go
+++ b/internal/controller/core/prefixset_controller_test.go
@@ -32,6 +32,7 @@ var _ = Describe("PrefixSet Controller", func() {
Endpoint: v1alpha1.Endpoint{
Address: "192.168.10.2:9339",
},
+ Provider: "test-provider",
},
}
Expect(k8sClient.Create(ctx, device)).To(Succeed())
diff --git a/internal/controller/core/routingpolicy_controller.go b/internal/controller/core/routingpolicy_controller.go
index 63acc8c37..0f0aa4182 100644
--- a/internal/controller/core/routingpolicy_controller.go
+++ b/internal/controller/core/routingpolicy_controller.go
@@ -49,9 +49,6 @@ type RoutingPolicyReconciler struct {
// More info: https://book.kubebuilder.io/reference/raising-events
Recorder events.EventRecorder
- // Provider is the driver that will be used to create & delete the routingpolicy.
- Provider provider.ProviderFunc
-
// Locker is used to synchronize operations on resources targeting the same device.
Locker *resourcelock.ResourceLocker
}
@@ -86,7 +83,29 @@ func (r *RoutingPolicyReconciler) Reconcile(ctx context.Context, req ctrl.Reques
return ctrl.Result{}, err
}
- prov, ok := r.Provider().(provider.RoutingPolicyProvider)
+ device, err := deviceutil.GetDeviceByName(ctx, r, obj.Namespace, obj.Spec.DeviceRef.Name)
+ if err != nil {
+ return ctrl.Result{}, err
+ }
+
+ if device.Spec.Provider == "" {
+ return ctrl.Result{}, fmt.Errorf("device %q has no provider set", device.Name)
+ }
+
+ p, err := provider.Get(device.Spec.Provider)
+ if err != nil {
+ if meta.SetStatusCondition(&obj.Status.Conditions, metav1.Condition{
+ Type: v1alpha1.ReadyCondition,
+ Status: metav1.ConditionFalse,
+ Reason: v1alpha1.ProviderNotFoundReason,
+ Message: fmt.Sprintf("Provider %q is not registered", device.Spec.Provider),
+ }) {
+ return ctrl.Result{}, r.Status().Update(ctx, obj)
+ }
+ return ctrl.Result{}, nil
+ }
+ prov, ok := p().(provider.RoutingPolicyProvider)
+
if !ok {
if meta.SetStatusCondition(&obj.Status.Conditions, metav1.Condition{
Type: v1alpha1.ReadyCondition,
@@ -99,11 +118,6 @@ func (r *RoutingPolicyReconciler) Reconcile(ctx context.Context, req ctrl.Reques
return ctrl.Result{}, nil
}
- device, err := deviceutil.GetDeviceByName(ctx, r, obj.Namespace, obj.Spec.DeviceRef.Name)
- if err != nil {
- return ctrl.Result{}, err
- }
-
if isPaused, requeue, err := paused.EnsureCondition(ctx, r.Client, device, obj); isPaused || requeue || err != nil {
return ctrl.Result{Requeue: requeue}, err
}
diff --git a/internal/controller/core/routingpolicy_controller_test.go b/internal/controller/core/routingpolicy_controller_test.go
index 8ee79ae21..37df446f1 100644
--- a/internal/controller/core/routingpolicy_controller_test.go
+++ b/internal/controller/core/routingpolicy_controller_test.go
@@ -34,6 +34,7 @@ var _ = Describe("RoutingPolicy Controller", func() {
Endpoint: v1alpha1.Endpoint{
Address: "192.168.10.2:9339",
},
+ Provider: "test-provider",
},
}
Expect(k8sClient.Create(ctx, device)).To(Succeed())
diff --git a/internal/controller/core/snmp_controller.go b/internal/controller/core/snmp_controller.go
index 2c2012e62..bba8be1a0 100644
--- a/internal/controller/core/snmp_controller.go
+++ b/internal/controller/core/snmp_controller.go
@@ -49,9 +49,6 @@ type SNMPReconciler struct {
// More info: https://book.kubebuilder.io/reference/raising-events
Recorder events.EventRecorder
- // Provider is the driver that will be used to create & delete the snmp.
- Provider provider.ProviderFunc
-
// Locker is used to synchronize operations on resources targeting the same device.
Locker *resourcelock.ResourceLocker
}
@@ -86,7 +83,29 @@ func (r *SNMPReconciler) Reconcile(ctx context.Context, req ctrl.Request) (_ ctr
return ctrl.Result{}, err
}
- prov, ok := r.Provider().(provider.SNMPProvider)
+ device, err := deviceutil.GetDeviceByName(ctx, r, obj.Namespace, obj.Spec.DeviceRef.Name)
+ if err != nil {
+ return ctrl.Result{}, err
+ }
+
+ if device.Spec.Provider == "" {
+ return ctrl.Result{}, fmt.Errorf("device %q has no provider set", device.Name)
+ }
+
+ p, err := provider.Get(device.Spec.Provider)
+ if err != nil {
+ if meta.SetStatusCondition(&obj.Status.Conditions, metav1.Condition{
+ Type: v1alpha1.ReadyCondition,
+ Status: metav1.ConditionFalse,
+ Reason: v1alpha1.ProviderNotFoundReason,
+ Message: fmt.Sprintf("Provider %q is not registered", device.Spec.Provider),
+ }) {
+ return ctrl.Result{}, r.Status().Update(ctx, obj)
+ }
+ return ctrl.Result{}, nil
+ }
+ prov, ok := p().(provider.SNMPProvider)
+
if !ok {
if meta.SetStatusCondition(&obj.Status.Conditions, metav1.Condition{
Type: v1alpha1.ReadyCondition,
@@ -99,11 +118,6 @@ func (r *SNMPReconciler) Reconcile(ctx context.Context, req ctrl.Request) (_ ctr
return ctrl.Result{}, nil
}
- device, err := deviceutil.GetDeviceByName(ctx, r, obj.Namespace, obj.Spec.DeviceRef.Name)
- if err != nil {
- return ctrl.Result{}, err
- }
-
if isPaused, requeue, err := paused.EnsureCondition(ctx, r.Client, device, obj); isPaused || requeue || err != nil {
return ctrl.Result{Requeue: requeue}, err
}
diff --git a/internal/controller/core/snmp_controller_test.go b/internal/controller/core/snmp_controller_test.go
index 8a32f1f49..8bc1c7c1d 100644
--- a/internal/controller/core/snmp_controller_test.go
+++ b/internal/controller/core/snmp_controller_test.go
@@ -31,6 +31,7 @@ var _ = Describe("SNMP Controller", func() {
Endpoint: v1alpha1.Endpoint{
Address: "192.168.10.2:9339",
},
+ Provider: "test-provider",
},
}
Expect(k8sClient.Create(ctx, device)).To(Succeed())
diff --git a/internal/controller/core/suite_test.go b/internal/controller/core/suite_test.go
index 78443d627..2e50e4e4b 100644
--- a/internal/controller/core/suite_test.go
+++ b/internal/controller/core/suite_test.go
@@ -115,13 +115,12 @@ var _ = BeforeSuite(func() {
_, err = k8sManager.GetCache().GetInformer(ctx, &coordinationv1.Lease{})
Expect(err).NotTo(HaveOccurred())
- prov := func() provider.Provider { return testProvider }
+ provider.Register("test-provider", func() provider.Provider { return testProvider })
err = (&DeviceReconciler{
Client: k8sManager.GetClient(),
Scheme: k8sManager.GetScheme(),
Recorder: recorder,
- Provider: prov,
HeartbeatInterval: time.Second,
}).SetupWithManager(k8sManager)
Expect(err).NotTo(HaveOccurred())
@@ -130,7 +129,6 @@ var _ = BeforeSuite(func() {
Client: k8sManager.GetClient(),
Scheme: k8sManager.GetScheme(),
Recorder: recorder,
- Provider: prov,
Locker: testLocker,
RequeueInterval: time.Second,
}).SetupWithManager(ctx, k8sManager)
@@ -140,7 +138,6 @@ var _ = BeforeSuite(func() {
Client: k8sManager.GetClient(),
Scheme: k8sManager.GetScheme(),
Recorder: recorder,
- Provider: prov,
Locker: testLocker,
}).SetupWithManager(ctx, k8sManager)
Expect(err).NotTo(HaveOccurred())
@@ -149,7 +146,6 @@ var _ = BeforeSuite(func() {
Client: k8sManager.GetClient(),
Scheme: k8sManager.GetScheme(),
Recorder: recorder,
- Provider: prov,
Locker: testLocker,
}).SetupWithManager(ctx, k8sManager)
Expect(err).NotTo(HaveOccurred())
@@ -158,7 +154,6 @@ var _ = BeforeSuite(func() {
Client: k8sManager.GetClient(),
Scheme: k8sManager.GetScheme(),
Recorder: recorder,
- Provider: prov,
Locker: testLocker,
}).SetupWithManager(ctx, k8sManager)
Expect(err).NotTo(HaveOccurred())
@@ -167,7 +162,6 @@ var _ = BeforeSuite(func() {
Client: k8sManager.GetClient(),
Scheme: k8sManager.GetScheme(),
Recorder: recorder,
- Provider: prov,
Locker: testLocker,
}).SetupWithManager(ctx, k8sManager)
Expect(err).NotTo(HaveOccurred())
@@ -176,7 +170,6 @@ var _ = BeforeSuite(func() {
Client: k8sManager.GetClient(),
Scheme: k8sManager.GetScheme(),
Recorder: recorder,
- Provider: prov,
Locker: testLocker,
}).SetupWithManager(ctx, k8sManager)
Expect(err).NotTo(HaveOccurred())
@@ -185,7 +178,6 @@ var _ = BeforeSuite(func() {
Client: k8sManager.GetClient(),
Scheme: k8sManager.GetScheme(),
Recorder: recorder,
- Provider: prov,
Locker: testLocker,
}).SetupWithManager(ctx, k8sManager)
Expect(err).NotTo(HaveOccurred())
@@ -194,7 +186,6 @@ var _ = BeforeSuite(func() {
Client: k8sManager.GetClient(),
Scheme: k8sManager.GetScheme(),
Recorder: recorder,
- Provider: prov,
Locker: testLocker,
}).SetupWithManager(ctx, k8sManager)
Expect(err).NotTo(HaveOccurred())
@@ -203,7 +194,6 @@ var _ = BeforeSuite(func() {
Client: k8sManager.GetClient(),
Scheme: k8sManager.GetScheme(),
Recorder: recorder,
- Provider: prov,
Locker: testLocker,
}).SetupWithManager(ctx, k8sManager)
Expect(err).NotTo(HaveOccurred())
@@ -212,7 +202,6 @@ var _ = BeforeSuite(func() {
Client: k8sManager.GetClient(),
Scheme: k8sManager.GetScheme(),
Recorder: recorder,
- Provider: prov,
Locker: testLocker,
}).SetupWithManager(ctx, k8sManager)
Expect(err).NotTo(HaveOccurred())
@@ -221,7 +210,6 @@ var _ = BeforeSuite(func() {
Client: k8sManager.GetClient(),
Scheme: k8sManager.GetScheme(),
Recorder: recorder,
- Provider: prov,
Locker: testLocker,
}).SetupWithManager(ctx, k8sManager)
Expect(err).NotTo(HaveOccurred())
@@ -230,7 +218,6 @@ var _ = BeforeSuite(func() {
Client: k8sManager.GetClient(),
Scheme: k8sManager.GetScheme(),
Recorder: recorder,
- Provider: prov,
Locker: testLocker,
}).SetupWithManager(ctx, k8sManager)
Expect(err).NotTo(HaveOccurred())
@@ -239,7 +226,6 @@ var _ = BeforeSuite(func() {
Client: k8sManager.GetClient(),
Scheme: k8sManager.GetScheme(),
Recorder: recorder,
- Provider: prov,
Locker: testLocker,
}).SetupWithManager(ctx, k8sManager)
Expect(err).NotTo(HaveOccurred())
@@ -248,7 +234,6 @@ var _ = BeforeSuite(func() {
Client: k8sManager.GetClient(),
Scheme: k8sManager.GetScheme(),
Recorder: recorder,
- Provider: prov,
Locker: testLocker,
RequeueInterval: time.Second,
}).SetupWithManager(ctx, k8sManager)
@@ -258,7 +243,6 @@ var _ = BeforeSuite(func() {
Client: k8sManager.GetClient(),
Scheme: k8sManager.GetScheme(),
Recorder: recorder,
- Provider: prov,
Locker: testLocker,
RequeueInterval: time.Second,
}).SetupWithManager(ctx, k8sManager)
@@ -268,7 +252,6 @@ var _ = BeforeSuite(func() {
Client: k8sManager.GetClient(),
Scheme: k8sManager.GetScheme(),
Recorder: recorder,
- Provider: prov,
Locker: testLocker,
RequeueInterval: time.Second,
}).SetupWithManager(ctx, k8sManager)
@@ -278,7 +261,6 @@ var _ = BeforeSuite(func() {
Client: k8sManager.GetClient(),
Scheme: k8sManager.GetScheme(),
Recorder: recorder,
- Provider: prov,
Locker: testLocker,
RequeueInterval: time.Second,
}).SetupWithManager(ctx, k8sManager)
@@ -288,7 +270,6 @@ var _ = BeforeSuite(func() {
Client: k8sManager.GetClient(),
Scheme: k8sManager.GetScheme(),
Recorder: recorder,
- Provider: prov,
Locker: testLocker,
}).SetupWithManager(ctx, k8sManager)
Expect(err).NotTo(HaveOccurred())
@@ -297,7 +278,6 @@ var _ = BeforeSuite(func() {
Client: k8sManager.GetClient(),
Scheme: k8sManager.GetScheme(),
Recorder: recorder,
- Provider: prov,
Locker: testLocker,
RequeueInterval: time.Second,
}).SetupWithManager(ctx, k8sManager)
@@ -307,7 +287,6 @@ var _ = BeforeSuite(func() {
Client: k8sManager.GetClient(),
Scheme: k8sManager.GetScheme(),
Recorder: recorder,
- Provider: prov,
Locker: testLocker,
}).SetupWithManager(ctx, k8sManager)
Expect(err).NotTo(HaveOccurred())
@@ -316,7 +295,6 @@ var _ = BeforeSuite(func() {
Client: k8sManager.GetClient(),
Scheme: k8sManager.GetScheme(),
Recorder: recorder,
- Provider: prov,
Locker: testLocker,
}).SetupWithManager(ctx, k8sManager)
Expect(err).NotTo(HaveOccurred())
@@ -325,7 +303,6 @@ var _ = BeforeSuite(func() {
Client: k8sManager.GetClient(),
Scheme: k8sManager.GetScheme(),
Recorder: recorder,
- Provider: prov,
Locker: testLocker,
RequeueInterval: time.Second,
}).SetupWithManager(ctx, k8sManager)
@@ -335,7 +312,6 @@ var _ = BeforeSuite(func() {
Client: k8sManager.GetClient(),
Scheme: k8sManager.GetScheme(),
Recorder: recorder,
- Provider: prov,
Locker: testLocker,
RequeueInterval: time.Second,
}).SetupWithManager(ctx, k8sManager)
@@ -345,7 +321,6 @@ var _ = BeforeSuite(func() {
Client: k8sManager.GetClient(),
Scheme: k8sManager.GetScheme(),
Recorder: recorder,
- Provider: prov,
Locker: testLocker,
}).SetupWithManager(ctx, k8sManager)
Expect(err).NotTo(HaveOccurred())
diff --git a/internal/controller/core/syslog_controller.go b/internal/controller/core/syslog_controller.go
index 12d8dd364..93945a1b1 100644
--- a/internal/controller/core/syslog_controller.go
+++ b/internal/controller/core/syslog_controller.go
@@ -49,9 +49,6 @@ type SyslogReconciler struct {
// More info: https://book.kubebuilder.io/reference/raising-events
Recorder events.EventRecorder
- // Provider is the driver that will be used to create & delete the syslog.
- Provider provider.ProviderFunc
-
// Locker is used to synchronize operations on resources targeting the same device.
Locker *resourcelock.ResourceLocker
}
@@ -86,7 +83,29 @@ func (r *SyslogReconciler) Reconcile(ctx context.Context, req ctrl.Request) (_ c
return ctrl.Result{}, err
}
- prov, ok := r.Provider().(provider.SyslogProvider)
+ device, err := deviceutil.GetDeviceByName(ctx, r, obj.Namespace, obj.Spec.DeviceRef.Name)
+ if err != nil {
+ return ctrl.Result{}, err
+ }
+
+ if device.Spec.Provider == "" {
+ return ctrl.Result{}, fmt.Errorf("device %q has no provider set", device.Name)
+ }
+
+ p, err := provider.Get(device.Spec.Provider)
+ if err != nil {
+ if meta.SetStatusCondition(&obj.Status.Conditions, metav1.Condition{
+ Type: v1alpha1.ReadyCondition,
+ Status: metav1.ConditionFalse,
+ Reason: v1alpha1.ProviderNotFoundReason,
+ Message: fmt.Sprintf("Provider %q is not registered", device.Spec.Provider),
+ }) {
+ return ctrl.Result{}, r.Status().Update(ctx, obj)
+ }
+ return ctrl.Result{}, nil
+ }
+ prov, ok := p().(provider.SyslogProvider)
+
if !ok {
if meta.SetStatusCondition(&obj.Status.Conditions, metav1.Condition{
Type: v1alpha1.ReadyCondition,
@@ -99,11 +118,6 @@ func (r *SyslogReconciler) Reconcile(ctx context.Context, req ctrl.Request) (_ c
return ctrl.Result{}, nil
}
- device, err := deviceutil.GetDeviceByName(ctx, r, obj.Namespace, obj.Spec.DeviceRef.Name)
- if err != nil {
- return ctrl.Result{}, err
- }
-
if isPaused, requeue, err := paused.EnsureCondition(ctx, r.Client, device, obj); isPaused || requeue || err != nil {
return ctrl.Result{Requeue: requeue}, err
}
diff --git a/internal/controller/core/syslog_controller_test.go b/internal/controller/core/syslog_controller_test.go
index fc16816b0..b3be65a07 100644
--- a/internal/controller/core/syslog_controller_test.go
+++ b/internal/controller/core/syslog_controller_test.go
@@ -31,6 +31,7 @@ var _ = Describe("Syslog Controller", func() {
Endpoint: v1alpha1.Endpoint{
Address: "192.168.10.2:9339",
},
+ Provider: "test-provider",
},
}
Expect(k8sClient.Create(ctx, device)).To(Succeed())
diff --git a/internal/controller/core/user_controller.go b/internal/controller/core/user_controller.go
index ff16800a3..a053ded3e 100644
--- a/internal/controller/core/user_controller.go
+++ b/internal/controller/core/user_controller.go
@@ -51,9 +51,6 @@ type UserReconciler struct {
// More info: https://book.kubebuilder.io/reference/raising-events
Recorder events.EventRecorder
- // Provider is the driver that will be used to create & delete the user.
- Provider provider.ProviderFunc
-
// Locker is used to synchronize operations on resources targeting the same device.
Locker *resourcelock.ResourceLocker
}
@@ -89,7 +86,29 @@ func (r *UserReconciler) Reconcile(ctx context.Context, req ctrl.Request) (_ ctr
return ctrl.Result{}, err
}
- prov, ok := r.Provider().(provider.UserProvider)
+ device, err := deviceutil.GetDeviceByName(ctx, r, obj.Namespace, obj.Spec.DeviceRef.Name)
+ if err != nil {
+ return ctrl.Result{}, err
+ }
+
+ if device.Spec.Provider == "" {
+ return ctrl.Result{}, fmt.Errorf("device %q has no provider set", device.Name)
+ }
+
+ p, err := provider.Get(device.Spec.Provider)
+ if err != nil {
+ if meta.SetStatusCondition(&obj.Status.Conditions, metav1.Condition{
+ Type: v1alpha1.ReadyCondition,
+ Status: metav1.ConditionFalse,
+ Reason: v1alpha1.ProviderNotFoundReason,
+ Message: fmt.Sprintf("Provider %q is not registered", device.Spec.Provider),
+ }) {
+ return ctrl.Result{}, r.Status().Update(ctx, obj)
+ }
+ return ctrl.Result{}, nil
+ }
+ prov, ok := p().(provider.UserProvider)
+
if !ok {
if meta.SetStatusCondition(&obj.Status.Conditions, metav1.Condition{
Type: v1alpha1.ReadyCondition,
@@ -102,11 +121,6 @@ func (r *UserReconciler) Reconcile(ctx context.Context, req ctrl.Request) (_ ctr
return ctrl.Result{}, nil
}
- device, err := deviceutil.GetDeviceByName(ctx, r, obj.Namespace, obj.Spec.DeviceRef.Name)
- if err != nil {
- return ctrl.Result{}, err
- }
-
if isPaused, requeue, err := paused.EnsureCondition(ctx, r.Client, device, obj); isPaused || requeue || err != nil {
return ctrl.Result{Requeue: requeue}, err
}
diff --git a/internal/controller/core/user_controller_test.go b/internal/controller/core/user_controller_test.go
index 308660ea1..52a0c813c 100644
--- a/internal/controller/core/user_controller_test.go
+++ b/internal/controller/core/user_controller_test.go
@@ -33,6 +33,7 @@ var _ = Describe("User Controller", func() {
Endpoint: v1alpha1.Endpoint{
Address: "192.168.10.2:9339",
},
+ Provider: "test-provider",
},
}
Expect(k8sClient.Create(ctx, device)).To(Succeed())
diff --git a/internal/controller/core/vlan_controller.go b/internal/controller/core/vlan_controller.go
index c86866302..470d5c106 100644
--- a/internal/controller/core/vlan_controller.go
+++ b/internal/controller/core/vlan_controller.go
@@ -49,9 +49,6 @@ type VLANReconciler struct {
// More info: https://book.kubebuilder.io/reference/raising-events
Recorder events.EventRecorder
- // Provider is the driver that will be used to create & delete the vlan.
- Provider provider.ProviderFunc
-
// Locker is used to synchronize operations on resources targeting the same device.
Locker *resourcelock.ResourceLocker
@@ -90,7 +87,29 @@ func (r *VLANReconciler) Reconcile(ctx context.Context, req ctrl.Request) (_ ctr
return ctrl.Result{}, err
}
- prov, ok := r.Provider().(provider.VLANProvider)
+ device, err := deviceutil.GetDeviceByName(ctx, r, obj.Namespace, obj.Spec.DeviceRef.Name)
+ if err != nil {
+ return ctrl.Result{}, err
+ }
+
+ if device.Spec.Provider == "" {
+ return ctrl.Result{}, fmt.Errorf("device %q has no provider set", device.Name)
+ }
+
+ p, err := provider.Get(device.Spec.Provider)
+ if err != nil {
+ if meta.SetStatusCondition(&obj.Status.Conditions, metav1.Condition{
+ Type: v1alpha1.ReadyCondition,
+ Status: metav1.ConditionFalse,
+ Reason: v1alpha1.ProviderNotFoundReason,
+ Message: fmt.Sprintf("Provider %q is not registered", device.Spec.Provider),
+ }) {
+ return ctrl.Result{}, r.Status().Update(ctx, obj)
+ }
+ return ctrl.Result{}, nil
+ }
+ prov, ok := p().(provider.VLANProvider)
+
if !ok {
if meta.SetStatusCondition(&obj.Status.Conditions, metav1.Condition{
Type: v1alpha1.ReadyCondition,
@@ -103,11 +122,6 @@ func (r *VLANReconciler) Reconcile(ctx context.Context, req ctrl.Request) (_ ctr
return ctrl.Result{}, nil
}
- device, err := deviceutil.GetDeviceByName(ctx, r, obj.Namespace, obj.Spec.DeviceRef.Name)
- if err != nil {
- return ctrl.Result{}, err
- }
-
if isPaused, requeue, err := paused.EnsureCondition(ctx, r.Client, device, obj); isPaused || requeue || err != nil {
return ctrl.Result{Requeue: requeue}, err
}
diff --git a/internal/controller/core/vlan_controller_test.go b/internal/controller/core/vlan_controller_test.go
index 51a078a48..2f347e174 100644
--- a/internal/controller/core/vlan_controller_test.go
+++ b/internal/controller/core/vlan_controller_test.go
@@ -32,6 +32,7 @@ var _ = Describe("VLAN Controller", func() {
Endpoint: v1alpha1.Endpoint{
Address: "192.168.10.2:9339",
},
+ Provider: "test-provider",
},
}
Expect(k8sClient.Create(ctx, device)).To(Succeed())
diff --git a/internal/controller/core/vrf_controller.go b/internal/controller/core/vrf_controller.go
index 05a1cb30a..6336613fe 100644
--- a/internal/controller/core/vrf_controller.go
+++ b/internal/controller/core/vrf_controller.go
@@ -49,9 +49,6 @@ type VRFReconciler struct {
// More info: https://book.kubebuilder.io/reference/raising-events
Recorder events.EventRecorder
- // Provider is the driver that will be used to create & delete the isis.
- Provider provider.ProviderFunc
-
// Locker is used to synchronize operations on resources targeting the same device.
Locker *resourcelock.ResourceLocker
}
@@ -88,7 +85,29 @@ func (r *VRFReconciler) Reconcile(ctx context.Context, req ctrl.Request) (_ ctrl
return ctrl.Result{}, err
}
- prov, ok := r.Provider().(provider.VRFProvider)
+ device, err := deviceutil.GetDeviceByName(ctx, r, obj.Namespace, obj.Spec.DeviceRef.Name)
+ if err != nil {
+ return ctrl.Result{}, err
+ }
+
+ if device.Spec.Provider == "" {
+ return ctrl.Result{}, fmt.Errorf("device %q has no provider set", device.Name)
+ }
+
+ p, err := provider.Get(device.Spec.Provider)
+ if err != nil {
+ if meta.SetStatusCondition(&obj.Status.Conditions, metav1.Condition{
+ Type: v1alpha1.ReadyCondition,
+ Status: metav1.ConditionFalse,
+ Reason: v1alpha1.ProviderNotFoundReason,
+ Message: fmt.Sprintf("Provider %q is not registered", device.Spec.Provider),
+ }) {
+ return ctrl.Result{}, r.Status().Update(ctx, obj)
+ }
+ return ctrl.Result{}, nil
+ }
+ prov, ok := p().(provider.VRFProvider)
+
if !ok {
if meta.SetStatusCondition(&obj.Status.Conditions, metav1.Condition{
Type: v1alpha1.ReadyCondition,
@@ -101,11 +120,6 @@ func (r *VRFReconciler) Reconcile(ctx context.Context, req ctrl.Request) (_ ctrl
return ctrl.Result{}, nil
}
- device, err := deviceutil.GetDeviceByName(ctx, r, obj.Namespace, obj.Spec.DeviceRef.Name)
- if err != nil {
- return ctrl.Result{}, err
- }
-
if isPaused, requeue, err := paused.EnsureCondition(ctx, r.Client, device, obj); isPaused || requeue || err != nil {
return ctrl.Result{Requeue: requeue}, err
}
diff --git a/internal/controller/core/vrf_controller_test.go b/internal/controller/core/vrf_controller_test.go
index 58ecb8622..34903eb92 100644
--- a/internal/controller/core/vrf_controller_test.go
+++ b/internal/controller/core/vrf_controller_test.go
@@ -33,6 +33,7 @@ var _ = Describe("VRF Controller", func() {
Endpoint: v1alpha1.Endpoint{
Address: "192.168.10.2:9339",
},
+ Provider: "test-provider",
},
}
Expect(k8sClient.Create(ctx, device)).To(Succeed())
diff --git a/internal/provider/cisco/iosxr/provider.go b/internal/provider/cisco/iosxr/provider.go
index c05255a09..a88262c6e 100644
--- a/internal/provider/cisco/iosxr/provider.go
+++ b/internal/provider/cisco/iosxr/provider.go
@@ -575,5 +575,5 @@ func (p *Provider) GetPeerStatus(ctx context.Context, req *provider.BGPPeerStatu
}
func init() {
- provider.Register("cisco-iosxr-gnmi", NewProvider)
+ provider.Register("iosxr.cisco.networking.metal.ironcore.dev", NewProvider)
}
diff --git a/internal/provider/cisco/nxos/provider.go b/internal/provider/cisco/nxos/provider.go
index 381e5ac9a..c6619861f 100644
--- a/internal/provider/cisco/nxos/provider.go
+++ b/internal/provider/cisco/nxos/provider.go
@@ -3822,5 +3822,5 @@ func (p *Provider) DeleteAAA(ctx context.Context, req *provider.DeleteAAARequest
}
func init() {
- provider.Register("cisco-nxos-gnmi", NewProvider)
+ provider.Register("nx.cisco.networking.metal.ironcore.dev", NewProvider)
}
diff --git a/internal/provider/openconfig/provider.go b/internal/provider/openconfig/provider.go
index 6ad131ff0..6f7becc2c 100644
--- a/internal/provider/openconfig/provider.go
+++ b/internal/provider/openconfig/provider.go
@@ -55,5 +55,5 @@ func (p *Provider) Disconnect(_ context.Context, _ *deviceutil.Connection) error
}
func init() {
- provider.Register("openconfig", NewProvider)
+ provider.Register("openconfig.networking.metal.ironcore.dev", NewProvider)
}
diff --git a/internal/provider/provider.go b/internal/provider/provider.go
index 4ba8ff86f..789d78aba 100644
--- a/internal/provider/provider.go
+++ b/internal/provider/provider.go
@@ -824,3 +824,56 @@ type ProviderConfig struct { //nolint:revive // stutter is intentional; Provider
func (p ProviderConfig) Into(v any) error {
return runtime.DefaultUnstructuredConverter.FromUnstructured(p.obj.Object, v)
}
+
+type NotFoundError struct {
+ providerName string
+}
+
+type NotImplementedError struct {
+ reason string
+}
+
+func (e NotImplementedError) Error() string {
+ return e.reason
+}
+
+func (e NotFoundError) Error() string {
+ return e.providerName
+}
+
+func (e NotFoundError) Is(target error) bool {
+ _, ok := target.(NotFoundError)
+ return ok
+}
+
+func (e NotImplementedError) Is(target error) bool {
+ _, ok := target.(NotImplementedError)
+ return ok
+}
+
+// Load Provider
+func LoadProvider[T Provider](providerName string) (T, error) {
+ prov, err := Get(providerName)
+ if err != nil {
+ var zero T
+ return zero, err
+ }
+ genericProvider, ok := prov().(T)
+ if !ok {
+ var zero T
+ return zero, fmt.Errorf("provider %q does not implement the required interface", providerName)
+ }
+ return genericProvider, nil
+}
+
+func LoadProvisioningProvider(providerName string) (ProvisioningProvider, error) {
+ prov, err := Get(providerName)
+ if err != nil {
+ return nil, err
+ }
+ provisioningProvider, ok := prov().(ProvisioningProvider)
+ if !ok {
+ return nil, NotImplementedError{reason: fmt.Sprintf("provider %q does not implement ProvisioningProvider interface", providerName)}
+ }
+ return provisioningProvider, nil
+}
diff --git a/internal/provisioning/http.go b/internal/provisioning/http.go
index a414297b2..b46bc8597 100644
--- a/internal/provisioning/http.go
+++ b/internal/provisioning/http.go
@@ -91,8 +91,8 @@ type HTTPServer struct {
Mux *http.ServeMux
Recorder events.EventRecorder
ValidateSourceIP bool
- Provider provider.ProvisioningProvider
- Port int
+ // Provider provider.ProvisioningProvider
+ Port int
}
func (s *HTTPServer) Start(ctx context.Context) error {
@@ -306,7 +306,14 @@ func (s *HTTPServer) HandleProvisioningRequest(w http.ResponseWriter, r *http.Re
return
}
- hashedPassword, hashAlgorithm, err := s.Provider.HashProvisioningPassword(string(pass))
+ prov, err := provider.LoadProvisioningProvider(device.Spec.Provider)
+ if err != nil {
+ s.Logger.Error(err, "Failed to get provider", "provider", device.Spec.Provider, "device", device.Name, "error", err)
+ http.Error(w, "Failed to get provider", http.StatusPreconditionRequired)
+ return
+ }
+
+ hashedPassword, hashAlgorithm, err := prov.HashProvisioningPassword(string(pass))
if err != nil {
s.Logger.Error(err, "Failed to hash provisioning password", "device", device.Name)
http.Error(w, "Failed to hash provisioning password", http.StatusInternalServerError)
diff --git a/internal/provisioning/http_test.go b/internal/provisioning/http_test.go
index 4b5477552..345e50f55 100644
--- a/internal/provisioning/http_test.go
+++ b/internal/provisioning/http_test.go
@@ -27,6 +27,7 @@ import (
"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"
)
var (
@@ -39,6 +40,7 @@ var (
},
},
Spec: v1alpha1.DeviceSpec{
+ Provider: "test-provider",
Endpoint: v1alpha1.Endpoint{
Address: "192.168.1.100:22",
SecretRef: &v1alpha1.SecretReference{
@@ -79,6 +81,14 @@ type MockProvider struct {
mock.Mock
}
+func (m *MockProvider) Connect(ctx context.Context, conn *deviceutil.Connection) error {
+ return nil
+}
+
+func (m *MockProvider) Disconnect(ctx context.Context, conn *deviceutil.Connection) error {
+ return nil
+}
+
func (m *MockProvider) HashProvisioningPassword(password string) (string, string, error) {
return "hashedpass", "sha256", nil
}
@@ -419,6 +429,7 @@ func TestHandleProvisioningRequest(t *testing.T) {
},
Spec: v1alpha1.DeviceSpec{
Endpoint: v1alpha1.Endpoint{Address: "192.168.1.200:22"},
+ Provider: "test-provider",
},
Status: v1alpha1.DeviceStatus{SerialNumber: "ABC123"},
},
@@ -437,6 +448,7 @@ func TestHandleProvisioningRequest(t *testing.T) {
Labels: map[string]string{v1alpha1.DeviceSerialLabel: "ABC123"},
},
Spec: v1alpha1.DeviceSpec{
+ Provider: "test-provider",
Endpoint: v1alpha1.Endpoint{
Address: "192.168.1.100:22",
SecretRef: &v1alpha1.SecretReference{
@@ -506,7 +518,6 @@ func TestHandleProvisioningRequest(t *testing.T) {
Client: k8sClient,
Logger: klog.NewKlogr(),
ValidateSourceIP: tt.validateSourceIP,
- Provider: new(MockProvider),
}
rr := httptest.NewRecorder()
@@ -986,6 +997,7 @@ func TestGetMTLSClientCA(t *testing.T) {
Labels: map[string]string{v1alpha1.DeviceSerialLabel: "ABC123"},
},
Spec: v1alpha1.DeviceSpec{
+ Provider: "test-provider",
Endpoint: v1alpha1.Endpoint{
Address: "192.168.1.100:22",
},
@@ -1010,6 +1022,7 @@ func TestGetMTLSClientCA(t *testing.T) {
Labels: map[string]string{v1alpha1.DeviceSerialLabel: "ABC123"},
},
Spec: v1alpha1.DeviceSpec{
+ Provider: "test-provider",
Endpoint: v1alpha1.Endpoint{
Address: "192.168.1.100:22",
TLS: &v1alpha1.TLS{
@@ -1042,6 +1055,7 @@ func TestGetMTLSClientCA(t *testing.T) {
Labels: map[string]string{v1alpha1.DeviceSerialLabel: "ABC123"},
},
Spec: v1alpha1.DeviceSpec{
+ Provider: "test-provider",
Endpoint: v1alpha1.Endpoint{
Address: "192.168.1.100:22",
TLS: &v1alpha1.TLS{
@@ -1073,6 +1087,7 @@ func TestGetMTLSClientCA(t *testing.T) {
Labels: map[string]string{v1alpha1.DeviceSerialLabel: "ABC123"},
},
Spec: v1alpha1.DeviceSpec{
+ Provider: "test-provider",
Endpoint: v1alpha1.Endpoint{
Address: "192.168.1.100:22",
TLS: &v1alpha1.TLS{
@@ -1152,4 +1167,5 @@ func TestGetMTLSClientCA(t *testing.T) {
func init() {
utilruntime.Must(v1alpha1.AddToScheme(scheme.Scheme))
+ provider.Register("test-provider", func() provider.Provider { return &MockProvider{} })
}