diff --git a/cmd/main.go b/cmd/main.go index ca7492c..06c8aef 100644 --- a/cmd/main.go +++ b/cmd/main.go @@ -27,10 +27,15 @@ import ( _ "k8s.io/client-go/plugin/pkg/client/auth" "go.uber.org/zap/zapcore" + corev1 "k8s.io/api/core/v1" + "k8s.io/apimachinery/pkg/labels" "k8s.io/apimachinery/pkg/runtime" + "k8s.io/apimachinery/pkg/selection" utilruntime "k8s.io/apimachinery/pkg/util/runtime" clientgoscheme "k8s.io/client-go/kubernetes/scheme" ctrl "sigs.k8s.io/controller-runtime" + "sigs.k8s.io/controller-runtime/pkg/cache" + "sigs.k8s.io/controller-runtime/pkg/client" "sigs.k8s.io/controller-runtime/pkg/healthz" "sigs.k8s.io/controller-runtime/pkg/log/zap" "sigs.k8s.io/controller-runtime/pkg/metrics/filters" @@ -39,6 +44,7 @@ import ( kvmv1 "github.com/cobaltcore-dev/openstack-hypervisor-operator/api/v1" "github.com/cobaltcore-dev/openstack-hypervisor-operator/internal/controller" + "github.com/cobaltcore-dev/openstack-hypervisor-operator/internal/global" "github.com/cobaltcore-dev/openstack-hypervisor-operator/internal/logger" // +kubebuilder:scaffold:imports @@ -80,6 +86,7 @@ func main() { "If set, the metrics endpoint is served securely via HTTPS. Use --metrics-secure=false to use HTTP instead.") flag.BoolVar(&enableHTTP2, "enable-http2", false, "If set, HTTP/2 will be enabled for the metrics and webhook servers") + flag.StringVar(&global.LabelSelector, "label-selector", "", "Label selector to filter watched resources (namely nodes).") flag.StringVar(&certificateNamespace, "certificate-namespace", "monsoon3", "The namespace for the certificates. ") flag.StringVar(&certificateIssuerName, "certificate-issuer-name", "nova-hypervisor-agents-ca-issuer", @@ -138,6 +145,28 @@ func main() { } restConfig := ctrl.GetConfigOrDie() + var cacheOptions cache.Options + if global.LabelSelector != "" { + setupLog.Info("setting up cache with label selector", "selector", global.LabelSelector) + selector := labels.NewSelector() + req, err := labels.NewRequirement(global.LabelSelector, selection.Exists, nil) + if err != nil { + setupLog.Error(err, "unable to parse label selector") + os.Exit(1) + } + + cacheOptions = cache.Options{ + ByObject: map[client.Object]cache.ByObject{ + &corev1.Node{}: { + Label: selector.Add(*req), + }, + &kvmv1.Hypervisor{}: { + Label: selector.Add(*req), + }, + }, + } + } + mgr, err := ctrl.NewManager(restConfig, ctrl.Options{ Scheme: scheme, Metrics: metricsServerOptions, @@ -156,6 +185,9 @@ func main() { // if you are doing or is intended to do any operation such as perform cleanups // after the manager stops then its usage might be unsafe. // LeaderElectionReleaseOnCancel: true, + + // Optionally configure the cache to listen/watch for specific labeled resources only + Cache: cacheOptions, }) if err != nil { diff --git a/internal/controller/eviction_controller.go b/internal/controller/eviction_controller.go index 760afaf..4020407 100644 --- a/internal/controller/eviction_controller.go +++ b/internal/controller/eviction_controller.go @@ -29,15 +29,18 @@ import ( "github.com/gophercloud/gophercloud/v2/openstack/compute/v2/hypervisors" "github.com/gophercloud/gophercloud/v2/openstack/compute/v2/servers" "github.com/gophercloud/gophercloud/v2/openstack/compute/v2/services" + corev1 "k8s.io/api/core/v1" "k8s.io/apimachinery/pkg/api/meta" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" "k8s.io/apimachinery/pkg/runtime" + "k8s.io/apimachinery/pkg/types" ctrl "sigs.k8s.io/controller-runtime" "sigs.k8s.io/controller-runtime/pkg/client" "sigs.k8s.io/controller-runtime/pkg/controller/controllerutil" logger "sigs.k8s.io/controller-runtime/pkg/log" kvmv1 "github.com/cobaltcore-dev/openstack-hypervisor-operator/api/v1" + "github.com/cobaltcore-dev/openstack-hypervisor-operator/internal/global" "github.com/cobaltcore-dev/openstack-hypervisor-operator/internal/openstack" ) @@ -69,6 +72,14 @@ func (r *EvictionReconciler) Reconcile(ctx context.Context, req ctrl.Request) (c return ctrl.Result{}, client.IgnoreNotFound(err) } + if global.LabelSelector != "" { + // This test-fetch the Node assigned to the eviction, it won't be cached if it's not part of our partition so + // we won't reconcile evictions for nodes outside our partition + if err := r.Get(ctx, types.NamespacedName{Name: eviction.Spec.Hypervisor}, &corev1.Node{}); err != nil { + return ctrl.Result{}, client.IgnoreNotFound(err) + } + } + log := logger.FromContext(ctx). WithName("Eviction"). WithValues("hypervisor", eviction.Spec.Hypervisor) diff --git a/internal/controller/hypervisor_controller.go b/internal/controller/hypervisor_controller.go index d8eceae..1d8556f 100644 --- a/internal/controller/hypervisor_controller.go +++ b/internal/controller/hypervisor_controller.go @@ -37,6 +37,7 @@ import ( "sigs.k8s.io/controller-runtime/pkg/predicate" kvmv1 "github.com/cobaltcore-dev/openstack-hypervisor-operator/api/v1" + "github.com/cobaltcore-dev/openstack-hypervisor-operator/internal/global" ) const ( @@ -174,6 +175,11 @@ func (hv *HypervisorController) SetupWithManager(mgr ctrl.Manager) error { return fmt.Errorf("failed to create label selector predicate: %w", err) } + // append the custom label selector from global config + if global.LabelSelector != "" { + transferLabels = append(transferLabels, global.LabelSelector) + } + return ctrl.NewControllerManagedBy(mgr). Named(HypervisorControllerName). For(&corev1.Node{}). diff --git a/internal/global/global.go b/internal/global/global.go new file mode 100644 index 0000000..270e1e0 --- /dev/null +++ b/internal/global/global.go @@ -0,0 +1,23 @@ +/* +SPDX-FileCopyrightText: Copyright 2025 SAP SE or an SAP affiliate company and cobaltcore-dev contributors +SPDX-License-Identifier: Apache-2.0 + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package global + +var ( + // LabelSelector is a custom label that is used to select resources managed by the operator. + LabelSelector = "" +)