diff --git a/Tiltfile b/Tiltfile
index 6605ef886..0828a89e1 100644
--- a/Tiltfile
+++ b/Tiltfile
@@ -24,7 +24,7 @@ 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'])
@@ -32,6 +32,7 @@ k8s_resource('network-operator-controller-manager', resource_deps=['controller-g
# Sample resources with manual trigger mode
def device_yaml():
decoded = read_yaml_stream('./config/samples/v1alpha1_device.yaml')
+ decoded[0]['spec']['provider'] = provider
ip = str(local("docker run --rm busybox:1.37.0 nslookup -type=a host.docker.internal 2>/dev/null | grep 'Address:' | tail -n 1 | awk '{print $2}' || echo ''", quiet=True)).rstrip('\n')
if len(ip) > 0:
decoded[0]['spec']['endpoint']['address'] = ip+':9339'
diff --git a/api/core/v1alpha1/device_types.go b/api/core/v1alpha1/device_types.go
index b8c5c5ae3..afaeb5259 100644
--- a/api/core/v1alpha1/device_types.go
+++ b/api/core/v1alpha1/device_types.go
@@ -24,10 +24,12 @@ type DeviceSpec struct {
// +required
Endpoint Endpoint `json:"endpoint"`
- // Provider is the name of the provider plugin which is responsible for reconciling the CRD connected to the device
- // +optional
- // +immutable
- Provider string `json:"provider,omitempty"`
+ // Provider identifies the provider implementation used to reconcile this Device and all CRDs that reference it.
+ // Immutable.
+ // +required
+ // +kubebuilder:validation:MinLength=1
+ // +kubebuilder:validation:XValidation:rule="self == oldSelf",message="Provider is immutable"
+ Provider string `json:"provider"`
// 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.
diff --git a/api/core/v1alpha1/groupversion_info.go b/api/core/v1alpha1/groupversion_info.go
index 2bac14340..0ada11111 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 4a5e46f87..3c46969cd 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
@@ -195,9 +195,14 @@ spec:
the Device and its associated objects.
type: boolean
provider:
- description: Provider is the name of the provider plugin which is
- responsible for reconciling the CRD connected to the device
+ description: |-
+ Provider identifies the provider implementation used to reconcile this Device and all CRDs that reference it.
+ Immutable.
+ minLength: 1
type: string
+ x-kubernetes-validations:
+ - message: Provider is immutable
+ rule: self == oldSelf
provisioning:
description: |-
Provisioning is an optional configuration for the device provisioning process.
@@ -304,6 +309,7 @@ spec:
type: object
required:
- endpoint
+ - provider
type: object
status:
description: |-
diff --git a/cmd/main.go b/cmd/main.go
index 530804326..6fa3e3839 100644
--- a/cmd/main.go
+++ b/cmd/main.go
@@ -50,7 +50,6 @@ import (
evpncontroller "github.com/ironcore-dev/network-operator/internal/controller/evpn"
poolcontroller "github.com/ironcore-dev/network-operator/internal/controller/pool"
"github.com/ironcore-dev/network-operator/internal/deviceutil"
- "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"
@@ -97,7 +96,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
@@ -123,7 +121,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.")
@@ -259,13 +256,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 == "" {
@@ -313,7 +303,6 @@ func main() { //nolint:gocyclo
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")
@@ -325,7 +314,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 {
@@ -338,7 +326,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")
@@ -350,7 +337,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")
@@ -362,7 +348,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")
@@ -374,7 +359,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")
@@ -386,7 +370,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")
@@ -398,7 +381,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")
@@ -410,7 +392,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")
@@ -422,7 +403,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")
@@ -434,7 +414,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")
@@ -446,7 +425,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")
@@ -458,7 +436,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")
@@ -470,7 +447,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 {
@@ -483,7 +459,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 {
@@ -496,7 +471,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 {
@@ -509,7 +483,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 {
@@ -522,7 +495,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 {
@@ -535,7 +507,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")
@@ -547,7 +518,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 {
@@ -560,7 +530,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 {
@@ -573,7 +542,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")
@@ -585,7 +553,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")
@@ -597,7 +564,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")
@@ -609,7 +575,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")
@@ -621,7 +586,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")
@@ -633,7 +597,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")
@@ -645,7 +608,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 {
@@ -658,7 +620,6 @@ func main() { //nolint:gocyclo
Scheme: mgr.GetScheme(),
Recorder: mgr.GetEventRecorder("configbackup-controller"),
WatchFilterValue: watchFilterValue,
- Provider: prov,
Locker: locker,
}).SetupWithManager(ctx, mgr); err != nil {
setupLog.Error(err, "unable to create controller", "controller", "ConfigBackup")
@@ -670,7 +631,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 {
@@ -794,14 +754,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 cadd01f42..724198272 100644
--- a/config/crd/bases/networking.metal.ironcore.dev_devices.yaml
+++ b/config/crd/bases/networking.metal.ironcore.dev_devices.yaml
@@ -192,9 +192,14 @@ spec:
the Device and its associated objects.
type: boolean
provider:
- description: Provider is the name of the provider plugin which is
- responsible for reconciling the CRD connected to the device
+ description: |-
+ Provider identifies the provider implementation used to reconcile this Device and all CRDs that reference it.
+ Immutable.
+ minLength: 1
type: string
+ x-kubernetes-validations:
+ - message: Provider is immutable
+ rule: self == oldSelf
provisioning:
description: |-
Provisioning is an optional configuration for the device provisioning process.
@@ -301,6 +306,7 @@ spec:
type: object
required:
- endpoint
+ - provider
type: object
status:
description: |-
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 53c923bea..aedac321c 100644
--- a/docs/api-reference/index.md
+++ b/docs/api-reference/index.md
@@ -1786,7 +1786,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 provider plugin which is responsible for reconciling the CRD connected to the device | | Optional: \{\}
|
+| `provider` _string_ | Provider identifies the provider implementation used to reconcile this Device and all CRDs that reference it.
Immutable. | | MinLength: 1
Required: \{\}
|
| `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..69ba93257 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,35 @@ 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
+ }
+
+ 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 d6a8ec9c5..3fd3b21be 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..510ddf5dd 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,35 @@ 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
+ }
+
+ 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 ff04a99a6..553267d5b 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..1432fa21f 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,35 @@ 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
+ }
+
+ 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 860a82909..801d7469f 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..b90fc6999 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,24 +81,28 @@ func (r *AAAReconciler) Reconcile(ctx context.Context, req ctrl.Request) (_ ctrl
return ctrl.Result{}, err
}
- prov, ok := r.Provider().(provider.AAAProvider)
- if !ok {
+ device, err := deviceutil.GetDeviceByName(ctx, r, obj.Namespace, obj.Spec.DeviceRef.Name)
+ if err != nil {
+ return ctrl.Result{}, err
+ }
+
+ prov, err := provider.LoadProvider[provider.AAAProvider](device.Spec.Provider)
+ if err != nil {
+ reason := v1alpha1.NotImplementedReason
+ if errors.Is(err, provider.NotFoundError{}) {
+ reason = v1alpha1.ProviderNotFoundReason
+ }
if meta.SetStatusCondition(&obj.Status.Conditions, metav1.Condition{
Type: v1alpha1.ReadyCondition,
Status: metav1.ConditionFalse,
- Reason: v1alpha1.NotImplementedReason,
- Message: "Provider does not implement provider.AAAProvider",
+ Reason: reason,
+ Message: err.Error(),
}) {
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 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..f8febca74 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,24 +83,28 @@ func (r *AccessControlListReconciler) Reconcile(ctx context.Context, req ctrl.Re
return ctrl.Result{}, err
}
- prov, ok := r.Provider().(provider.ACLProvider)
- if !ok {
+ device, err := deviceutil.GetDeviceByName(ctx, r, obj.Namespace, obj.Spec.DeviceRef.Name)
+ if err != nil {
+ return ctrl.Result{}, err
+ }
+
+ prov, err := provider.LoadProvider[provider.ACLProvider](device.Spec.Provider)
+ if err != nil {
+ reason := v1alpha1.NotImplementedReason
+ if errors.Is(err, provider.NotFoundError{}) {
+ reason = v1alpha1.ProviderNotFoundReason
+ }
if meta.SetStatusCondition(&obj.Status.Conditions, metav1.Condition{
Type: v1alpha1.ReadyCondition,
Status: metav1.ConditionFalse,
- Reason: v1alpha1.NotImplementedReason,
- Message: "Provider does not implement provider.AccessControlListProvider",
+ Reason: reason,
+ Message: err.Error(),
}) {
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 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 45718d5af..5e61ca42d 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..012b3b108 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,24 +87,28 @@ func (r *BannerReconciler) Reconcile(ctx context.Context, req ctrl.Request) (_ c
return ctrl.Result{}, err
}
- prov, ok := r.Provider().(provider.BannerProvider)
- if !ok {
+ device, err := deviceutil.GetDeviceByName(ctx, r, obj.Namespace, obj.Spec.DeviceRef.Name)
+ if err != nil {
+ return ctrl.Result{}, err
+ }
+
+ prov, err := provider.LoadProvider[provider.BannerProvider](device.Spec.Provider)
+ if err != nil {
+ reason := v1alpha1.NotImplementedReason
+ if errors.Is(err, provider.NotFoundError{}) {
+ reason = v1alpha1.ProviderNotFoundReason
+ }
if meta.SetStatusCondition(&obj.Status.Conditions, metav1.Condition{
Type: v1alpha1.ReadyCondition,
Status: metav1.ConditionFalse,
- Reason: v1alpha1.NotImplementedReason,
- Message: "Provider does not implement provider.BannerProvider",
+ Reason: reason,
+ Message: err.Error(),
}) {
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 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 411ccf2d4..3513a43d8 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..c2f37ad35 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,24 +96,28 @@ func (r *BGPReconciler) Reconcile(ctx context.Context, req ctrl.Request) (_ ctrl
return ctrl.Result{}, err
}
- prov, ok := r.Provider().(provider.BGPProvider)
- if !ok {
+ device, err := deviceutil.GetDeviceByName(ctx, r, obj.Namespace, obj.Spec.DeviceRef.Name)
+ if err != nil {
+ return ctrl.Result{}, err
+ }
+
+ prov, err := provider.LoadProvider[provider.BGPProvider](device.Spec.Provider)
+ if err != nil {
+ reason := v1alpha1.NotImplementedReason
+ if errors.Is(err, provider.NotFoundError{}) {
+ reason = v1alpha1.ProviderNotFoundReason
+ }
if meta.SetStatusCondition(&obj.Status.Conditions, metav1.Condition{
Type: v1alpha1.ReadyCondition,
Status: metav1.ConditionFalse,
- Reason: v1alpha1.NotImplementedReason,
- Message: "Provider does not implement provider.BGPProvider",
+ Reason: reason,
+ Message: err.Error(),
}) {
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 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 2a70a6c2e..279751e35 100644
--- a/internal/controller/core/bgp_controller_test.go
+++ b/internal/controller/core/bgp_controller_test.go
@@ -30,6 +30,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..dd8b2d8bd 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,24 +100,28 @@ func (r *BGPPeerReconciler) Reconcile(ctx context.Context, req ctrl.Request) (_
return ctrl.Result{}, err
}
- prov, ok := r.Provider().(provider.BGPPeerProvider)
- if !ok {
+ device, err := deviceutil.GetDeviceByName(ctx, r, obj.Namespace, obj.Spec.DeviceRef.Name)
+ if err != nil {
+ return ctrl.Result{}, err
+ }
+
+ prov, err := provider.LoadProvider[provider.BGPPeerProvider](device.Spec.Provider)
+ if err != nil {
+ reason := v1alpha1.NotImplementedReason
+ if errors.Is(err, provider.NotFoundError{}) {
+ reason = v1alpha1.ProviderNotFoundReason
+ }
if meta.SetStatusCondition(&obj.Status.Conditions, metav1.Condition{
Type: v1alpha1.ReadyCondition,
Status: metav1.ConditionFalse,
- Reason: v1alpha1.NotImplementedReason,
- Message: "Provider does not implement provider.BGPPeerProvider",
+ Reason: reason,
+ Message: err.Error(),
}) {
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 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 767ad455e..691a427e6 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..e8c8e2b0c 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,24 +86,28 @@ func (r *CertificateReconciler) Reconcile(ctx context.Context, req ctrl.Request)
return ctrl.Result{}, err
}
- prov, ok := r.Provider().(provider.CertificateProvider)
- if !ok {
+ device, err := deviceutil.GetDeviceByName(ctx, r, obj.Namespace, obj.Spec.DeviceRef.Name)
+ if err != nil {
+ return ctrl.Result{}, err
+ }
+
+ prov, err := provider.LoadProvider[provider.CertificateProvider](device.Spec.Provider)
+ if err != nil {
+ reason := v1alpha1.NotImplementedReason
+ if errors.Is(err, provider.NotFoundError{}) {
+ reason = v1alpha1.ProviderNotFoundReason
+ }
if meta.SetStatusCondition(&obj.Status.Conditions, metav1.Condition{
Type: v1alpha1.ReadyCondition,
Status: metav1.ConditionFalse,
- Reason: v1alpha1.NotImplementedReason,
- Message: "Provider does not implement provider.CertificateProvider",
+ Reason: reason,
+ Message: err.Error(),
}) {
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 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 501f8f0e5..35d9a3c1a 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/configbackup_controller.go b/internal/controller/core/configbackup_controller.go
index 74c9ba653..4704ee352 100644
--- a/internal/controller/core/configbackup_controller.go
+++ b/internal/controller/core/configbackup_controller.go
@@ -51,9 +51,6 @@ type ConfigBackupReconciler 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 config backup.
- Provider provider.ProviderFunc
-
// Locker is used to synchronize operations on resources targeting the same device.
Locker *resourcelock.ResourceLocker
}
@@ -80,24 +77,28 @@ func (r *ConfigBackupReconciler) Reconcile(ctx context.Context, req ctrl.Request
return ctrl.Result{}, err
}
- prov, ok := r.Provider().(provider.ConfigBackupProvider)
- if !ok {
+ device, err := deviceutil.GetDeviceByName(ctx, r, obj.Namespace, obj.Spec.DeviceRef.Name)
+ if err != nil {
+ return ctrl.Result{}, err
+ }
+
+ prov, err := provider.LoadProvider[provider.ConfigBackupProvider](device.Spec.Provider)
+ if err != nil {
+ reason := v1alpha1.NotImplementedReason
+ if errors.Is(err, provider.NotFoundError{}) {
+ reason = v1alpha1.ProviderNotFoundReason
+ }
if meta.SetStatusCondition(&obj.Status.Conditions, metav1.Condition{
Type: v1alpha1.ReadyCondition,
Status: metav1.ConditionFalse,
- Reason: v1alpha1.NotImplementedReason,
- Message: "Provider does not implement provider.ConfigBackupProvider",
+ Reason: reason,
+ Message: err.Error(),
}) {
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 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/configbackup_controller_test.go b/internal/controller/core/configbackup_controller_test.go
index a39ff0275..ec0e2be46 100644
--- a/internal/controller/core/configbackup_controller_test.go
+++ b/internal/controller/core/configbackup_controller_test.go
@@ -32,6 +32,7 @@ var _ = Describe("ConfigBackup Controller", func() {
},
Spec: v1alpha1.DeviceSpec{
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..8b7d25839 100644
--- a/internal/controller/core/device_controller.go
+++ b/internal/controller/core/device_controller.go
@@ -49,9 +49,6 @@ type DeviceReconciler 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
-
// HeartbeatInterval is the duration after which the controller requeues the reconciliation,
// regardless of changes.
HeartbeatInterval time.Duration
@@ -128,8 +125,7 @@ func (r *DeviceReconciler) Reconcile(ctx context.Context, req ctrl.Request) (_ c
obj.Status.Phase = v1alpha1.DevicePhaseRunning
return ctrl.Result{}, nil
}
-
- if _, ok := r.Provider().(provider.ProvisioningProvider); !ok {
+ if _, err := provider.LoadProvider[provider.ProvisioningProvider](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 +189,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.LoadProvider[provider.ProvisioningProvider](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 +203,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 +384,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 +443,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 bb4e5238a..375513a7e 100644
--- a/internal/controller/core/device_controller_test.go
+++ b/internal/controller/core/device_controller_test.go
@@ -70,6 +70,7 @@ var _ = Describe("Device Controller", func() {
Name: name,
},
},
+ Provider: "test-provider",
},
}
Expect(k8sClient.Create(ctx, device)).To(Succeed())
@@ -158,6 +159,7 @@ var _ = Describe("Device Controller", func() {
Name: name,
},
},
+ Provider: "test-provider",
Provisioning: &v1alpha1.Provisioning{
Image: v1alpha1.Image{
URL: "http://example.com/nxos.bin",
@@ -202,6 +204,7 @@ var _ = Describe("Device Controller", func() {
Name: name,
},
},
+ Provider: "test-provider",
Provisioning: &v1alpha1.Provisioning{
Image: v1alpha1.Image{
URL: "http://example.com/nxos.bin",
@@ -259,6 +262,7 @@ var _ = Describe("Device Controller", func() {
Name: name,
},
},
+ Provider: "test-provider",
Provisioning: &v1alpha1.Provisioning{
Image: v1alpha1.Image{
URL: "http://example.com/nxos.bin",
@@ -319,6 +323,7 @@ var _ = Describe("Device Controller", func() {
Name: name,
},
},
+ Provider: "test-provider",
},
}
Expect(k8sClient.Create(ctx, device)).To(Succeed())
@@ -347,6 +352,7 @@ var _ = Describe("Device Controller", func() {
Name: name,
},
},
+ Provider: "test-provider",
},
}
Expect(k8sClient.Create(ctx, device)).To(Succeed())
@@ -402,6 +408,7 @@ var _ = Describe("Device Controller", func() {
Name: name,
},
},
+ Provider: "test-provider",
Provisioning: &v1alpha1.Provisioning{
BootScript: v1alpha1.TemplateSource{
Inline: new("boot nxos.bin"),
@@ -489,6 +496,7 @@ var _ = Describe("Device Controller", func() {
Name: name,
},
},
+ Provider: "test-provider",
},
}
Expect(k8sClient.Create(ctx, device)).To(Succeed())
@@ -537,6 +545,7 @@ var _ = Describe("Device Controller", func() {
Name: name,
},
},
+ Provider: "test-provider",
Provisioning: &v1alpha1.Provisioning{
Image: v1alpha1.Image{
URL: "http://example.com/nxos.bin",
@@ -590,6 +599,7 @@ var _ = Describe("Device Controller", func() {
Name: name,
},
},
+ Provider: "test-provider",
Provisioning: &v1alpha1.Provisioning{
Image: v1alpha1.Image{
URL: "http://example.com/nxos.bin",
@@ -656,6 +666,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..f0d0b844c 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,24 +89,28 @@ func (r *DHCPRelayReconciler) Reconcile(ctx context.Context, req ctrl.Request) (
return ctrl.Result{}, err
}
- prov, ok := r.Provider().(provider.DHCPRelayProvider)
- if !ok {
+ device, err := deviceutil.GetDeviceByName(ctx, r, obj.Namespace, obj.Spec.DeviceRef.Name)
+ if err != nil {
+ return ctrl.Result{}, err
+ }
+
+ prov, err := provider.LoadProvider[provider.DHCPRelayProvider](device.Spec.Provider)
+ if err != nil {
+ reason := v1alpha1.NotImplementedReason
+ if errors.Is(err, provider.NotFoundError{}) {
+ reason = v1alpha1.ProviderNotFoundReason
+ }
if meta.SetStatusCondition(&obj.Status.Conditions, metav1.Condition{
Type: v1alpha1.ReadyCondition,
Status: metav1.ConditionFalse,
- Reason: v1alpha1.NotImplementedReason,
- Message: "Provider does not implement provider.DHCPRelayProvider",
+ Reason: reason,
+ Message: err.Error(),
}) {
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 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 e11406d5c..9f7649b67 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())
@@ -383,6 +384,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())
@@ -469,6 +471,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())
@@ -485,6 +488,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())
@@ -627,6 +631,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())
@@ -643,6 +648,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())
@@ -811,6 +817,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())
@@ -986,6 +993,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..99ab7d453 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,24 +83,28 @@ func (r *DNSReconciler) Reconcile(ctx context.Context, req ctrl.Request) (_ ctrl
return ctrl.Result{}, err
}
- prov, ok := r.Provider().(provider.DNSProvider)
- if !ok {
+ device, err := deviceutil.GetDeviceByName(ctx, r, obj.Namespace, obj.Spec.DeviceRef.Name)
+ if err != nil {
+ return ctrl.Result{}, err
+ }
+
+ prov, err := provider.LoadProvider[provider.DNSProvider](device.Spec.Provider)
+ if err != nil {
+ reason := v1alpha1.NotImplementedReason
+ if errors.Is(err, provider.NotFoundError{}) {
+ reason = v1alpha1.ProviderNotFoundReason
+ }
if meta.SetStatusCondition(&obj.Status.Conditions, metav1.Condition{
Type: v1alpha1.ReadyCondition,
Status: metav1.ConditionFalse,
- Reason: v1alpha1.NotImplementedReason,
- Message: "Provider does not implement provider.DNSProvider",
+ Reason: reason,
+ Message: err.Error(),
}) {
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 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 4b5c86c94..fac4535bb 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..797c5433a 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,24 +87,28 @@ func (r *EthernetSegmentReconciler) Reconcile(ctx context.Context, req ctrl.Requ
return ctrl.Result{}, err
}
- prov, ok := r.Provider().(provider.EthernetSegmentProvider)
- if !ok {
+ device, err := deviceutil.GetDeviceByName(ctx, r, obj.Namespace, obj.Spec.DeviceRef.Name)
+ if err != nil {
+ return ctrl.Result{}, err
+ }
+
+ prov, err := provider.LoadProvider[provider.EthernetSegmentProvider](device.Spec.Provider)
+ if err != nil {
+ reason := v1alpha1.NotImplementedReason
+ if errors.Is(err, provider.NotFoundError{}) {
+ reason = v1alpha1.ProviderNotFoundReason
+ }
if meta.SetStatusCondition(&obj.Status.Conditions, metav1.Condition{
Type: v1alpha1.ReadyCondition,
Status: metav1.ConditionFalse,
- Reason: v1alpha1.NotImplementedReason,
- Message: "Provider does not implement provider.EthernetSegmentProvider",
+ Reason: reason,
+ Message: err.Error(),
}) {
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 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 bff49709e..4d948b941 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..bc006779b 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,24 +85,28 @@ func (r *EVPNInstanceReconciler) Reconcile(ctx context.Context, req ctrl.Request
return ctrl.Result{}, err
}
- prov, ok := r.Provider().(provider.EVPNInstanceProvider)
- if !ok {
+ device, err := deviceutil.GetDeviceByName(ctx, r, obj.Namespace, obj.Spec.DeviceRef.Name)
+ if err != nil {
+ return ctrl.Result{}, err
+ }
+
+ prov, err := provider.LoadProvider[provider.EVPNInstanceProvider](device.Spec.Provider)
+ if err != nil {
+ reason := v1alpha1.NotImplementedReason
+ if errors.Is(err, provider.NotFoundError{}) {
+ reason = v1alpha1.ProviderNotFoundReason
+ }
if meta.SetStatusCondition(&obj.Status.Conditions, metav1.Condition{
Type: v1alpha1.ReadyCondition,
Status: metav1.ConditionFalse,
- Reason: v1alpha1.NotImplementedReason,
- Message: "Provider does not implement provider.EVPNInstanceProvider",
+ Reason: reason,
+ Message: err.Error(),
}) {
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 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 1165bc63d..381445a01 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..424751531 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
@@ -98,24 +95,28 @@ func (r *InterfaceReconciler) Reconcile(ctx context.Context, req ctrl.Request) (
return ctrl.Result{}, err
}
- prov, ok := r.Provider().(provider.InterfaceProvider)
- if !ok {
+ device, err := deviceutil.GetDeviceByName(ctx, r, obj.Namespace, obj.Spec.DeviceRef.Name)
+ if err != nil {
+ return ctrl.Result{}, err
+ }
+
+ prov, err := provider.LoadProvider[provider.InterfaceProvider](device.Spec.Provider)
+ if err != nil {
+ reason := v1alpha1.NotImplementedReason
+ if errors.Is(err, provider.NotFoundError{}) {
+ reason = v1alpha1.ProviderNotFoundReason
+ }
if meta.SetStatusCondition(&obj.Status.Conditions, metav1.Condition{
Type: v1alpha1.ReadyCondition,
Status: metav1.ConditionFalse,
- Reason: v1alpha1.NotImplementedReason,
- Message: "Provider does not implement provider.InterfaceProvider",
+ Reason: reason,
+ Message: err.Error(),
}) {
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 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 ab497fb8a..117e115e3 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())
@@ -1282,6 +1283,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())
@@ -1295,6 +1297,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..90c053a40 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,24 +84,28 @@ func (r *ISISReconciler) Reconcile(ctx context.Context, req ctrl.Request) (_ ctr
return ctrl.Result{}, err
}
- prov, ok := r.Provider().(provider.ISISProvider)
- if !ok {
+ device, err := deviceutil.GetDeviceByName(ctx, r, obj.Namespace, obj.Spec.DeviceRef.Name)
+ if err != nil {
+ return ctrl.Result{}, err
+ }
+
+ prov, err := provider.LoadProvider[provider.ISISProvider](device.Spec.Provider)
+ if err != nil {
+ reason := v1alpha1.NotImplementedReason
+ if errors.Is(err, provider.NotFoundError{}) {
+ reason = v1alpha1.ProviderNotFoundReason
+ }
if meta.SetStatusCondition(&obj.Status.Conditions, metav1.Condition{
Type: v1alpha1.ReadyCondition,
Status: metav1.ConditionFalse,
- Reason: v1alpha1.NotImplementedReason,
- Message: "Provider does not implement provider.ISISProvider",
+ Reason: reason,
+ Message: err.Error(),
}) {
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 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 f6d635ac1..6bacae7ed 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())
@@ -136,6 +137,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..f4aff99d6 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,24 +84,28 @@ 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
+ }
+
+ prov, err := provider.LoadProvider[provider.LLDPProvider](device.Spec.Provider)
+ if err != nil {
+ reason := v1alpha1.NotImplementedReason
+ if errors.Is(err, provider.NotFoundError{}) {
+ reason = v1alpha1.ProviderNotFoundReason
+ }
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: reason,
+ Message: err.Error(),
}) {
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 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/lldp_controller_test.go b/internal/controller/core/lldp_controller_test.go
index 8b17a1c8e..a0a4a8966 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())
@@ -328,6 +329,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())
@@ -452,6 +454,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())
@@ -599,6 +602,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())
@@ -682,6 +686,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())
@@ -833,6 +838,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())
@@ -1074,6 +1080,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())
@@ -1263,6 +1270,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..a9587b0d9 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,24 +83,28 @@ func (r *ManagementAccessReconciler) Reconcile(ctx context.Context, req ctrl.Req
return ctrl.Result{}, err
}
- prov, ok := r.Provider().(provider.ManagementAccessProvider)
- if !ok {
+ device, err := deviceutil.GetDeviceByName(ctx, r, obj.Namespace, obj.Spec.DeviceRef.Name)
+ if err != nil {
+ return ctrl.Result{}, err
+ }
+
+ prov, err := provider.LoadProvider[provider.ManagementAccessProvider](device.Spec.Provider)
+ if err != nil {
+ reason := v1alpha1.NotImplementedReason
+ if errors.Is(err, provider.NotFoundError{}) {
+ reason = v1alpha1.ProviderNotFoundReason
+ }
if meta.SetStatusCondition(&obj.Status.Conditions, metav1.Condition{
Type: v1alpha1.ReadyCondition,
Status: metav1.ConditionFalse,
- Reason: v1alpha1.NotImplementedReason,
- Message: "Provider does not implement provider.ManagementAccessProvider",
+ Reason: reason,
+ Message: err.Error(),
}) {
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 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 d5b10b730..224759d1f 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..badad3f0f 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,24 +83,28 @@ func (r *NTPReconciler) Reconcile(ctx context.Context, req ctrl.Request) (_ ctrl
return ctrl.Result{}, err
}
- prov, ok := r.Provider().(provider.NTPProvider)
- if !ok {
+ device, err := deviceutil.GetDeviceByName(ctx, r, obj.Namespace, obj.Spec.DeviceRef.Name)
+ if err != nil {
+ return ctrl.Result{}, err
+ }
+
+ prov, err := provider.LoadProvider[provider.NTPProvider](device.Spec.Provider)
+ if err != nil {
+ reason := v1alpha1.NotImplementedReason
+ if errors.Is(err, provider.NotFoundError{}) {
+ reason = v1alpha1.ProviderNotFoundReason
+ }
if meta.SetStatusCondition(&obj.Status.Conditions, metav1.Condition{
Type: v1alpha1.ReadyCondition,
Status: metav1.ConditionFalse,
- Reason: v1alpha1.NotImplementedReason,
- Message: "Provider does not implement provider.NTPProvider",
+ Reason: reason,
+ Message: err.Error(),
}) {
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 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 972e9c75b..6eb7e3d5a 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..07e92b6a9 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,24 +84,28 @@ 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
+ }
+
+ prov, err := provider.LoadProvider[provider.NVEProvider](device.Spec.Provider)
+ if err != nil {
+ reason := v1alpha1.NotImplementedReason
+ if errors.Is(err, provider.NotFoundError{}) {
+ reason = v1alpha1.ProviderNotFoundReason
+ }
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: reason,
+ Message: err.Error(),
}) {
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 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/nve_controller_test.go b/internal/controller/core/nve_controller_test.go
index 7accaf843..3e6d920e0 100644
--- a/internal/controller/core/nve_controller_test.go
+++ b/internal/controller/core/nve_controller_test.go
@@ -37,6 +37,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())
@@ -325,6 +327,7 @@ var _ = Describe("NVE Controller", func() {
},
Spec: v1alpha1.DeviceSpec{
Endpoint: v1alpha1.Endpoint{Address: testEndpointAddr},
+ Provider: "test-provider",
},
}
Expect(k8sClient.Create(ctx, device)).To(Succeed())
@@ -399,6 +402,7 @@ var _ = Describe("NVE Controller", func() {
},
Spec: v1alpha1.DeviceSpec{
Endpoint: v1alpha1.Endpoint{Address: testEndpointAddr},
+ Provider: "test-provider",
},
}
Expect(k8sClient.Create(ctx, device)).To(Succeed())
@@ -494,6 +498,7 @@ var _ = Describe("NVE Controller", func() {
},
Spec: v1alpha1.DeviceSpec{
Endpoint: v1alpha1.Endpoint{Address: testEndpointAddr},
+ Provider: "test-provider",
},
}
Expect(k8sClient.Create(ctx, device)).To(Succeed())
@@ -603,6 +608,7 @@ var _ = Describe("NVE Controller", func() {
},
Spec: v1alpha1.DeviceSpec{
Endpoint: v1alpha1.Endpoint{Address: testEndpointAddr},
+ Provider: "test-provider",
},
}
Expect(k8sClient.Create(ctx, device)).To(Succeed())
@@ -703,6 +709,7 @@ var _ = Describe("NVE Controller", func() {
},
Spec: v1alpha1.DeviceSpec{
Endpoint: v1alpha1.Endpoint{Address: testEndpointAddr},
+ Provider: "test-provider",
},
}
Expect(k8sClient.Create(ctx, device)).To(Succeed())
@@ -717,6 +724,7 @@ var _ = Describe("NVE Controller", func() {
},
Spec: v1alpha1.DeviceSpec{
Endpoint: v1alpha1.Endpoint{Address: testEndpointAddr},
+ Provider: "test-provider",
},
}
Expect(k8sClient.Create(ctx, device2)).To(Succeed())
@@ -823,6 +831,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..18976be7b 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,24 +90,28 @@ func (r *OSPFReconciler) Reconcile(ctx context.Context, req ctrl.Request) (_ ctr
return ctrl.Result{}, err
}
- prov, ok := r.Provider().(provider.OSPFProvider)
- if !ok {
+ device, err := deviceutil.GetDeviceByName(ctx, r, obj.Namespace, obj.Spec.DeviceRef.Name)
+ if err != nil {
+ return ctrl.Result{}, err
+ }
+
+ prov, err := provider.LoadProvider[provider.OSPFProvider](device.Spec.Provider)
+ if err != nil {
+ reason := v1alpha1.NotImplementedReason
+ if errors.Is(err, provider.NotFoundError{}) {
+ reason = v1alpha1.ProviderNotFoundReason
+ }
if meta.SetStatusCondition(&obj.Status.Conditions, metav1.Condition{
Type: v1alpha1.ReadyCondition,
Status: metav1.ConditionFalse,
- Reason: v1alpha1.NotImplementedReason,
- Message: "Provider does not implement provider.OSPFProvider",
+ Reason: reason,
+ Message: err.Error(),
}) {
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 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 e7c7d0a9c..01c0a808b 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())
@@ -135,6 +136,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..87d4d8558 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,24 +84,28 @@ func (r *PIMReconciler) Reconcile(ctx context.Context, req ctrl.Request) (_ ctrl
return ctrl.Result{}, err
}
- prov, ok := r.Provider().(provider.PIMProvider)
- if !ok {
+ device, err := deviceutil.GetDeviceByName(ctx, r, obj.Namespace, obj.Spec.DeviceRef.Name)
+ if err != nil {
+ return ctrl.Result{}, err
+ }
+
+ prov, err := provider.LoadProvider[provider.PIMProvider](device.Spec.Provider)
+ if err != nil {
+ reason := v1alpha1.NotImplementedReason
+ if errors.Is(err, provider.NotFoundError{}) {
+ reason = v1alpha1.ProviderNotFoundReason
+ }
if meta.SetStatusCondition(&obj.Status.Conditions, metav1.Condition{
Type: v1alpha1.ReadyCondition,
Status: metav1.ConditionFalse,
- Reason: v1alpha1.NotImplementedReason,
- Message: "Provider does not implement provider.PIMProvider",
+ Reason: reason,
+ Message: err.Error(),
}) {
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 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 427e58d41..e4b8c7afa 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())
@@ -129,6 +130,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..fb1e37d51 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,24 +83,28 @@ func (r *PrefixSetReconciler) Reconcile(ctx context.Context, req ctrl.Request) (
return ctrl.Result{}, err
}
- prov, ok := r.Provider().(provider.PrefixSetProvider)
- if !ok {
+ device, err := deviceutil.GetDeviceByName(ctx, r, obj.Namespace, obj.Spec.DeviceRef.Name)
+ if err != nil {
+ return ctrl.Result{}, err
+ }
+
+ prov, err := provider.LoadProvider[provider.PrefixSetProvider](device.Spec.Provider)
+ if err != nil {
+ reason := v1alpha1.NotImplementedReason
+ if errors.Is(err, provider.NotFoundError{}) {
+ reason = v1alpha1.ProviderNotFoundReason
+ }
if meta.SetStatusCondition(&obj.Status.Conditions, metav1.Condition{
Type: v1alpha1.ReadyCondition,
Status: metav1.ConditionFalse,
- Reason: v1alpha1.NotImplementedReason,
- Message: "Provider does not implement provider.PrefixSetProvider",
+ Reason: reason,
+ Message: err.Error(),
}) {
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 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 540a886ff..e132c59f6 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..f01172ea7 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,24 +83,28 @@ func (r *RoutingPolicyReconciler) Reconcile(ctx context.Context, req ctrl.Reques
return ctrl.Result{}, err
}
- prov, ok := r.Provider().(provider.RoutingPolicyProvider)
- if !ok {
+ device, err := deviceutil.GetDeviceByName(ctx, r, obj.Namespace, obj.Spec.DeviceRef.Name)
+ if err != nil {
+ return ctrl.Result{}, err
+ }
+
+ prov, err := provider.LoadProvider[provider.RoutingPolicyProvider](device.Spec.Provider)
+ if err != nil {
+ reason := v1alpha1.NotImplementedReason
+ if errors.Is(err, provider.NotFoundError{}) {
+ reason = v1alpha1.ProviderNotFoundReason
+ }
if meta.SetStatusCondition(&obj.Status.Conditions, metav1.Condition{
Type: v1alpha1.ReadyCondition,
Status: metav1.ConditionFalse,
- Reason: v1alpha1.NotImplementedReason,
- Message: "Provider does not implement provider.RoutingPolicyProvider",
+ Reason: reason,
+ Message: err.Error(),
}) {
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 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 d9579f6da..43b6349df 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..0986cbd39 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,24 +83,28 @@ func (r *SNMPReconciler) Reconcile(ctx context.Context, req ctrl.Request) (_ ctr
return ctrl.Result{}, err
}
- prov, ok := r.Provider().(provider.SNMPProvider)
- if !ok {
+ device, err := deviceutil.GetDeviceByName(ctx, r, obj.Namespace, obj.Spec.DeviceRef.Name)
+ if err != nil {
+ return ctrl.Result{}, err
+ }
+
+ prov, err := provider.LoadProvider[provider.SNMPProvider](device.Spec.Provider)
+ if err != nil {
+ reason := v1alpha1.NotImplementedReason
+ if errors.Is(err, provider.NotFoundError{}) {
+ reason = v1alpha1.ProviderNotFoundReason
+ }
if meta.SetStatusCondition(&obj.Status.Conditions, metav1.Condition{
Type: v1alpha1.ReadyCondition,
Status: metav1.ConditionFalse,
- Reason: v1alpha1.NotImplementedReason,
- Message: "Provider does not implement provider.SNMPProvider",
+ Reason: reason,
+ Message: err.Error(),
}) {
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 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 145dfee47..c57ad388c 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 051a89864..e9ac6eebf 100644
--- a/internal/controller/core/suite_test.go
+++ b/internal/controller/core/suite_test.go
@@ -117,13 +117,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())
@@ -132,7 +131,6 @@ var _ = BeforeSuite(func() {
Client: k8sManager.GetClient(),
Scheme: k8sManager.GetScheme(),
Recorder: recorder,
- Provider: prov,
Locker: testLocker,
RequeueInterval: time.Second,
}).SetupWithManager(ctx, k8sManager)
@@ -142,7 +140,6 @@ var _ = BeforeSuite(func() {
Client: k8sManager.GetClient(),
Scheme: k8sManager.GetScheme(),
Recorder: recorder,
- Provider: prov,
Locker: testLocker,
}).SetupWithManager(ctx, k8sManager)
Expect(err).NotTo(HaveOccurred())
@@ -151,7 +148,6 @@ var _ = BeforeSuite(func() {
Client: k8sManager.GetClient(),
Scheme: k8sManager.GetScheme(),
Recorder: recorder,
- Provider: prov,
Locker: testLocker,
}).SetupWithManager(ctx, k8sManager)
Expect(err).NotTo(HaveOccurred())
@@ -160,7 +156,6 @@ var _ = BeforeSuite(func() {
Client: k8sManager.GetClient(),
Scheme: k8sManager.GetScheme(),
Recorder: recorder,
- Provider: prov,
Locker: testLocker,
}).SetupWithManager(ctx, k8sManager)
Expect(err).NotTo(HaveOccurred())
@@ -169,7 +164,6 @@ var _ = BeforeSuite(func() {
Client: k8sManager.GetClient(),
Scheme: k8sManager.GetScheme(),
Recorder: recorder,
- Provider: prov,
Locker: testLocker,
}).SetupWithManager(ctx, k8sManager)
Expect(err).NotTo(HaveOccurred())
@@ -178,7 +172,6 @@ var _ = BeforeSuite(func() {
Client: k8sManager.GetClient(),
Scheme: k8sManager.GetScheme(),
Recorder: recorder,
- Provider: prov,
Locker: testLocker,
}).SetupWithManager(ctx, k8sManager)
Expect(err).NotTo(HaveOccurred())
@@ -187,7 +180,6 @@ var _ = BeforeSuite(func() {
Client: k8sManager.GetClient(),
Scheme: k8sManager.GetScheme(),
Recorder: recorder,
- Provider: prov,
Locker: testLocker,
}).SetupWithManager(ctx, k8sManager)
Expect(err).NotTo(HaveOccurred())
@@ -196,7 +188,6 @@ var _ = BeforeSuite(func() {
Client: k8sManager.GetClient(),
Scheme: k8sManager.GetScheme(),
Recorder: recorder,
- Provider: prov,
Locker: testLocker,
}).SetupWithManager(ctx, k8sManager)
Expect(err).NotTo(HaveOccurred())
@@ -205,7 +196,6 @@ var _ = BeforeSuite(func() {
Client: k8sManager.GetClient(),
Scheme: k8sManager.GetScheme(),
Recorder: recorder,
- Provider: prov,
Locker: testLocker,
}).SetupWithManager(ctx, k8sManager)
Expect(err).NotTo(HaveOccurred())
@@ -214,7 +204,6 @@ var _ = BeforeSuite(func() {
Client: k8sManager.GetClient(),
Scheme: k8sManager.GetScheme(),
Recorder: recorder,
- Provider: prov,
Locker: testLocker,
}).SetupWithManager(ctx, k8sManager)
Expect(err).NotTo(HaveOccurred())
@@ -223,7 +212,6 @@ var _ = BeforeSuite(func() {
Client: k8sManager.GetClient(),
Scheme: k8sManager.GetScheme(),
Recorder: recorder,
- Provider: prov,
Locker: testLocker,
}).SetupWithManager(ctx, k8sManager)
Expect(err).NotTo(HaveOccurred())
@@ -232,7 +220,6 @@ var _ = BeforeSuite(func() {
Client: k8sManager.GetClient(),
Scheme: k8sManager.GetScheme(),
Recorder: recorder,
- Provider: prov,
Locker: testLocker,
}).SetupWithManager(ctx, k8sManager)
Expect(err).NotTo(HaveOccurred())
@@ -241,7 +228,6 @@ var _ = BeforeSuite(func() {
Client: k8sManager.GetClient(),
Scheme: k8sManager.GetScheme(),
Recorder: recorder,
- Provider: prov,
Locker: testLocker,
}).SetupWithManager(ctx, k8sManager)
Expect(err).NotTo(HaveOccurred())
@@ -250,7 +236,6 @@ var _ = BeforeSuite(func() {
Client: k8sManager.GetClient(),
Scheme: k8sManager.GetScheme(),
Recorder: recorder,
- Provider: prov,
Locker: testLocker,
RequeueInterval: time.Second,
}).SetupWithManager(ctx, k8sManager)
@@ -260,7 +245,6 @@ var _ = BeforeSuite(func() {
Client: k8sManager.GetClient(),
Scheme: k8sManager.GetScheme(),
Recorder: recorder,
- Provider: prov,
Locker: testLocker,
RequeueInterval: time.Second,
}).SetupWithManager(ctx, k8sManager)
@@ -270,7 +254,6 @@ var _ = BeforeSuite(func() {
Client: k8sManager.GetClient(),
Scheme: k8sManager.GetScheme(),
Recorder: recorder,
- Provider: prov,
Locker: testLocker,
RequeueInterval: time.Second,
}).SetupWithManager(ctx, k8sManager)
@@ -280,7 +263,6 @@ var _ = BeforeSuite(func() {
Client: k8sManager.GetClient(),
Scheme: k8sManager.GetScheme(),
Recorder: recorder,
- Provider: prov,
Locker: testLocker,
RequeueInterval: time.Second,
}).SetupWithManager(ctx, k8sManager)
@@ -290,7 +272,6 @@ var _ = BeforeSuite(func() {
Client: k8sManager.GetClient(),
Scheme: k8sManager.GetScheme(),
Recorder: recorder,
- Provider: prov,
Locker: testLocker,
}).SetupWithManager(ctx, k8sManager)
Expect(err).NotTo(HaveOccurred())
@@ -299,7 +280,6 @@ var _ = BeforeSuite(func() {
Client: k8sManager.GetClient(),
Scheme: k8sManager.GetScheme(),
Recorder: recorder,
- Provider: prov,
Locker: testLocker,
RequeueInterval: time.Second,
}).SetupWithManager(ctx, k8sManager)
@@ -309,7 +289,6 @@ var _ = BeforeSuite(func() {
Client: k8sManager.GetClient(),
Scheme: k8sManager.GetScheme(),
Recorder: recorder,
- Provider: prov,
Locker: testLocker,
}).SetupWithManager(ctx, k8sManager)
Expect(err).NotTo(HaveOccurred())
@@ -318,7 +297,6 @@ var _ = BeforeSuite(func() {
Client: k8sManager.GetClient(),
Scheme: k8sManager.GetScheme(),
Recorder: recorder,
- Provider: prov,
Locker: testLocker,
}).SetupWithManager(ctx, k8sManager)
Expect(err).NotTo(HaveOccurred())
@@ -327,7 +305,6 @@ var _ = BeforeSuite(func() {
Client: k8sManager.GetClient(),
Scheme: k8sManager.GetScheme(),
Recorder: recorder,
- Provider: prov,
Locker: testLocker,
RequeueInterval: time.Second,
}).SetupWithManager(ctx, k8sManager)
@@ -337,7 +314,6 @@ var _ = BeforeSuite(func() {
Client: k8sManager.GetClient(),
Scheme: k8sManager.GetScheme(),
Recorder: recorder,
- Provider: prov,
Locker: testLocker,
RequeueInterval: time.Second,
}).SetupWithManager(ctx, k8sManager)
@@ -347,7 +323,6 @@ var _ = BeforeSuite(func() {
Client: k8sManager.GetClient(),
Scheme: k8sManager.GetScheme(),
Recorder: recorder,
- Provider: prov,
Locker: testLocker,
}).SetupWithManager(ctx, k8sManager)
Expect(err).NotTo(HaveOccurred())
@@ -356,7 +331,6 @@ var _ = BeforeSuite(func() {
Client: k8sManager.GetClient(),
Scheme: k8sManager.GetScheme(),
Recorder: recorder,
- Provider: prov,
Locker: testLocker,
RequeueInterval: time.Second,
}).SetupWithManager(ctx, k8sManager)
diff --git a/internal/controller/core/syslog_controller.go b/internal/controller/core/syslog_controller.go
index 12d8dd364..203c2bc05 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,24 +83,28 @@ func (r *SyslogReconciler) Reconcile(ctx context.Context, req ctrl.Request) (_ c
return ctrl.Result{}, err
}
- prov, ok := r.Provider().(provider.SyslogProvider)
- if !ok {
+ device, err := deviceutil.GetDeviceByName(ctx, r, obj.Namespace, obj.Spec.DeviceRef.Name)
+ if err != nil {
+ return ctrl.Result{}, err
+ }
+
+ prov, err := provider.LoadProvider[provider.SyslogProvider](device.Spec.Provider)
+ if err != nil {
+ reason := v1alpha1.NotImplementedReason
+ if errors.Is(err, provider.NotFoundError{}) {
+ reason = v1alpha1.ProviderNotFoundReason
+ }
if meta.SetStatusCondition(&obj.Status.Conditions, metav1.Condition{
Type: v1alpha1.ReadyCondition,
Status: metav1.ConditionFalse,
- Reason: v1alpha1.NotImplementedReason,
- Message: "Provider does not implement provider.SyslogProvider",
+ Reason: reason,
+ Message: err.Error(),
}) {
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 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 8e477ca06..37d40d6f6 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..76f483035 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,24 +86,28 @@ func (r *UserReconciler) Reconcile(ctx context.Context, req ctrl.Request) (_ ctr
return ctrl.Result{}, err
}
- prov, ok := r.Provider().(provider.UserProvider)
- if !ok {
+ device, err := deviceutil.GetDeviceByName(ctx, r, obj.Namespace, obj.Spec.DeviceRef.Name)
+ if err != nil {
+ return ctrl.Result{}, err
+ }
+
+ prov, err := provider.LoadProvider[provider.UserProvider](device.Spec.Provider)
+ if err != nil {
+ reason := v1alpha1.NotImplementedReason
+ if errors.Is(err, provider.NotFoundError{}) {
+ reason = v1alpha1.ProviderNotFoundReason
+ }
if meta.SetStatusCondition(&obj.Status.Conditions, metav1.Condition{
Type: v1alpha1.ReadyCondition,
Status: metav1.ConditionFalse,
- Reason: v1alpha1.NotImplementedReason,
- Message: "Provider does not implement provider.UserProvider",
+ Reason: reason,
+ Message: err.Error(),
}) {
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 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 94cf845e6..f433d9cde 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..f4fc66eb9 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,24 +87,28 @@ func (r *VLANReconciler) Reconcile(ctx context.Context, req ctrl.Request) (_ ctr
return ctrl.Result{}, err
}
- prov, ok := r.Provider().(provider.VLANProvider)
- if !ok {
+ device, err := deviceutil.GetDeviceByName(ctx, r, obj.Namespace, obj.Spec.DeviceRef.Name)
+ if err != nil {
+ return ctrl.Result{}, err
+ }
+
+ prov, err := provider.LoadProvider[provider.VLANProvider](device.Spec.Provider)
+ if err != nil {
+ reason := v1alpha1.NotImplementedReason
+ if errors.Is(err, provider.NotFoundError{}) {
+ reason = v1alpha1.ProviderNotFoundReason
+ }
if meta.SetStatusCondition(&obj.Status.Conditions, metav1.Condition{
Type: v1alpha1.ReadyCondition,
Status: metav1.ConditionFalse,
- Reason: v1alpha1.NotImplementedReason,
- Message: "Provider does not implement provider.VLANProvider",
+ Reason: reason,
+ Message: err.Error(),
}) {
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 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 edc1b8cd5..e9fb2b95f 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..a07158b4f 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,24 +85,28 @@ func (r *VRFReconciler) Reconcile(ctx context.Context, req ctrl.Request) (_ ctrl
return ctrl.Result{}, err
}
- prov, ok := r.Provider().(provider.VRFProvider)
- if !ok {
+ device, err := deviceutil.GetDeviceByName(ctx, r, obj.Namespace, obj.Spec.DeviceRef.Name)
+ if err != nil {
+ return ctrl.Result{}, err
+ }
+
+ prov, err := provider.LoadProvider[provider.VRFProvider](device.Spec.Provider)
+ if err != nil {
+ reason := v1alpha1.NotImplementedReason
+ if errors.Is(err, provider.NotFoundError{}) {
+ reason = v1alpha1.ProviderNotFoundReason
+ }
if meta.SetStatusCondition(&obj.Status.Conditions, metav1.Condition{
Type: v1alpha1.ReadyCondition,
Status: metav1.ConditionFalse,
- Reason: v1alpha1.NotImplementedReason,
- Message: "Provider does not implement provider.VRFProvider",
+ Reason: reason,
+ Message: err.Error(),
}) {
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 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 e9d76ff51..3b6c3e4a8 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 39d9aa68a..0d8d246b4 100644
--- a/internal/provider/cisco/iosxr/provider.go
+++ b/internal/provider/cisco/iosxr/provider.go
@@ -612,5 +612,5 @@ func (p *Provider) DeletePrefixSet(ctx context.Context, req *provider.PrefixSetR
}
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 83a54ecd3..02bbf55f0 100644
--- a/internal/provider/cisco/nxos/provider.go
+++ b/internal/provider/cisco/nxos/provider.go
@@ -4016,5 +4016,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 1ad8a2f18..a2560920a 100644
--- a/internal/provider/provider.go
+++ b/internal/provider/provider.go
@@ -51,6 +51,8 @@ type MaintenanceProvider interface {
// ProvisioningProvider is the interface for the realization of the provisioning-related operations over different providers.
type ProvisioningProvider interface {
+ Provider
+
// Reprovision prepares the device for reprovisioning by resetting it and reenabling provisioning mechanisms.
Reprovision(context.Context, *deviceutil.Connection) error
// HashProvisioningPassword takes a plaintext password and returns the hashed password along with the hash type.
@@ -899,3 +901,43 @@ 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 {
+ Message string
+}
+
+func (e NotFoundError) Error() string {
+ return e.Message
+}
+
+func (e NotFoundError) Is(target error) bool {
+ _, ok := target.(NotFoundError)
+ return ok
+}
+
+type NotImplementedError struct {
+ Message string
+}
+
+func (e NotImplementedError) Error() string {
+ return e.Message
+}
+
+func (e NotImplementedError) Is(target error) bool {
+ _, ok := target.(NotImplementedError)
+ return ok
+}
+
+// LoadProvider returns a provider instance cast to the requested interface type T.
+// Returns NotFoundError if the provider is not registered, NotImplementedError if it does not implement T.
+func LoadProvider[T Provider](providerName string) (zero T, _ error) {
+ prov, err := Get(providerName)
+ if err != nil {
+ return zero, NotFoundError{Message: fmt.Sprintf("Provider %q is not registered", providerName)}
+ }
+ provider, ok := prov().(T)
+ if !ok {
+ return zero, NotImplementedError{Message: fmt.Sprintf("provider %q does not implement %T", providerName, zero)}
+ }
+ return provider, nil
+}
diff --git a/internal/provisioning/http.go b/internal/provisioning/http.go
index a414297b2..2f938c435 100644
--- a/internal/provisioning/http.go
+++ b/internal/provisioning/http.go
@@ -91,7 +91,6 @@ type HTTPServer struct {
Mux *http.ServeMux
Recorder events.EventRecorder
ValidateSourceIP bool
- Provider provider.ProvisioningProvider
Port int
}
@@ -306,7 +305,14 @@ func (s *HTTPServer) HandleProvisioningRequest(w http.ResponseWriter, r *http.Re
return
}
- hashedPassword, hashAlgorithm, err := s.Provider.HashProvisioningPassword(string(pass))
+ prov, err := provider.LoadProvider[provider.ProvisioningProvider](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{} })
}