diff --git a/.github/workflows/lint.yml b/.github/workflows/lint.yml index a9f1dc0e..14e4c320 100644 --- a/.github/workflows/lint.yml +++ b/.github/workflows/lint.yml @@ -17,4 +17,4 @@ jobs: - name: golangci-lint uses: golangci/golangci-lint-action@v9 with: - version: v2.5 + version: v2.6 diff --git a/Makefile b/Makefile index 8965c3f9..f3bdfd52 100644 --- a/Makefile +++ b/Makefile @@ -201,7 +201,7 @@ CONTROLLER_TOOLS_VERSION ?= v0.17.1 ENVTEST_VERSION ?= $(shell go list -m -f "{{ .Version }}" sigs.k8s.io/controller-runtime | awk -F'[v.]' '{printf "release-%d.%d", $$2, $$3}') #ENVTEST_K8S_VERSION is the version of Kubernetes to use for setting up ENVTEST binaries (i.e. 1.31) ENVTEST_K8S_VERSION ?= $(shell go list -m -f "{{ .Version }}" k8s.io/api | awk -F'[v.]' '{printf "1.%d.%d",$$3, $$2}') -GOLANGCI_LINT_VERSION ?= v2.1 +GOLANGCI_LINT_VERSION ?= v2.6 ADDLICENSE_VERSION ?= v1.1.1 GOIMPORTS_VERSION ?= v0.31.0 GEN_CRD_API_REFERENCE_DOCS_VERSION ?= v0.3.0 diff --git a/cmdutils/suite_test.go b/cmdutils/suite_test.go index 8a70eb9f..75bd8f74 100644 --- a/cmdutils/suite_test.go +++ b/cmdutils/suite_test.go @@ -59,7 +59,7 @@ var _ = BeforeSuite(func() { // Note that you must have the required binaries setup under the bin directory to perform // the tests directly. When we run make test it will be setup and used automatically. BinaryAssetsDirectory: filepath.Join("..", "bin", "k8s", - fmt.Sprintf("1.31.0-%s-%s", runtime.GOOS, runtime.GOARCH)), + fmt.Sprintf("1.34.0-%s-%s", runtime.GOOS, runtime.GOARCH)), } sourceCfg, err := sourceEnv.Start() @@ -89,7 +89,7 @@ var _ = BeforeSuite(func() { // Note that you must have the required binaries setup under the bin directory to perform // the tests directly. When we run make test it will be setup and used automatically. BinaryAssetsDirectory: filepath.Join("..", "bin", "k8s", - fmt.Sprintf("1.31.0-%s-%s", runtime.GOOS, runtime.GOARCH)), + fmt.Sprintf("1.34.0-%s-%s", runtime.GOOS, runtime.GOARCH)), } // cfg is defined in this file globally. diff --git a/docs/api-reference/api.md b/docs/api-reference/api.md index 67366f20..3b52b64c 100644 --- a/docs/api-reference/api.md +++ b/docs/api-reference/api.md @@ -48,7 +48,7 @@ string metadata
- + Kubernetes meta/v1.ObjectMeta @@ -86,7 +86,7 @@ string ignitionSecretRef
- + Kubernetes core/v1.LocalObjectReference @@ -168,7 +168,7 @@ string metadata
- + Kubernetes meta/v1.ObjectMeta @@ -272,7 +272,7 @@ string ignitionSecretRef
- + Kubernetes core/v1.LocalObjectReference @@ -285,7 +285,7 @@ Kubernetes core/v1.LocalObjectReference ipxeScriptSecretRef
- + Kubernetes core/v1.LocalObjectReference @@ -342,7 +342,7 @@ string ignitionSecretRef
- + Kubernetes core/v1.LocalObjectReference @@ -432,7 +432,7 @@ HTTPBootConfigState conditions
- + []Kubernetes meta/v1.Condition @@ -540,7 +540,7 @@ string ignitionSecretRef
- + Kubernetes core/v1.LocalObjectReference @@ -553,7 +553,7 @@ Kubernetes core/v1.LocalObjectReference ipxeScriptSecretRef
- + Kubernetes core/v1.LocalObjectReference @@ -622,7 +622,7 @@ IPXEBootConfigState conditions
- + []Kubernetes meta/v1.Condition diff --git a/hack/api-reference/config.json b/hack/api-reference/config.json index 80e79d89..f9acfffe 100644 --- a/hack/api-reference/config.json +++ b/hack/api-reference/config.json @@ -21,7 +21,7 @@ }, { "typeMatchPrefix": "^k8s\\.io/(api|apimachinery/pkg/apis)/", - "docsURLTemplate": "https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.31/#{{lower .TypeIdentifier}}-{{arrIndex .PackageSegments -1}}-{{arrIndex .PackageSegments -2}}" + "docsURLTemplate": "https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.34/#{{lower .TypeIdentifier}}-{{arrIndex .PackageSegments -1}}-{{arrIndex .PackageSegments -2}}" } ], "typeDisplayNamePrefixOverrides": { diff --git a/internal/controller/httpbootconfig_controller.go b/internal/controller/httpbootconfig_controller.go index e50119c8..7504d39b 100644 --- a/internal/controller/httpbootconfig_controller.go +++ b/internal/controller/httpbootconfig_controller.go @@ -13,7 +13,6 @@ import ( ctrl "sigs.k8s.io/controller-runtime" "sigs.k8s.io/controller-runtime/pkg/client" "sigs.k8s.io/controller-runtime/pkg/handler" - "sigs.k8s.io/controller-runtime/pkg/log" "sigs.k8s.io/controller-runtime/pkg/reconcile" "github.com/go-logr/logr" @@ -32,55 +31,53 @@ type HTTPBootConfigReconciler struct { //+kubebuilder:rbac:groups="",resources=secrets,verbs=get;list;watch func (r *HTTPBootConfigReconciler) Reconcile(ctx context.Context, req ctrl.Request) (ctrl.Result, error) { - log := log.FromContext(ctx) - - HTTPBootConfig := &bootv1alpha1.HTTPBootConfig{} - if err := r.Get(ctx, req.NamespacedName, HTTPBootConfig); err != nil { + log := ctrl.LoggerFrom(ctx) + config := &bootv1alpha1.HTTPBootConfig{} + if err := r.Get(ctx, req.NamespacedName, config); err != nil { return ctrl.Result{}, client.IgnoreNotFound(err) } - - return r.reconcileExists(ctx, log, HTTPBootConfig) + return r.reconcileExists(ctx, log, config) } -func (r *HTTPBootConfigReconciler) reconcileExists(ctx context.Context, log logr.Logger, HTTPBootConfig *bootv1alpha1.HTTPBootConfig) (ctrl.Result, error) { - if !HTTPBootConfig.DeletionTimestamp.IsZero() { - return r.delete(ctx, log, HTTPBootConfig) +func (r *HTTPBootConfigReconciler) reconcileExists(ctx context.Context, log logr.Logger, config *bootv1alpha1.HTTPBootConfig) (ctrl.Result, error) { + if !config.DeletionTimestamp.IsZero() { + return r.delete(ctx, log, config) } - - return r.reconcile(ctx, log, HTTPBootConfig) + return r.reconcile(ctx, log, config) } -func (r *HTTPBootConfigReconciler) reconcile(ctx context.Context, log logr.Logger, HTTPBootConfig *bootv1alpha1.HTTPBootConfig) (ctrl.Result, error) { +func (r *HTTPBootConfigReconciler) reconcile(ctx context.Context, log logr.Logger, config *bootv1alpha1.HTTPBootConfig) (ctrl.Result, error) { + log.V(1).Info("Reconciling HTTPBootConfig") + log.V(1).Info("Ensuring Ignition") - state, ignitionErr := r.ensureIgnition(ctx, log, HTTPBootConfig) - if ignitionErr != nil { - patchError := r.patchStatus(ctx, HTTPBootConfig, state) - if patchError != nil { - return ctrl.Result{}, fmt.Errorf("failed to patch status %w %w", ignitionErr, patchError) + state, err := r.ensureIgnition(ctx, log, config) + if err != nil { + if err := r.patchStatus(ctx, config, state); err != nil { + return ctrl.Result{}, err } - - log.V(1).Info("Failed to Ensure Ignition", "Error", ignitionErr) + log.V(1).Info("Failed to Ensure Ignition", "Error", err) return ctrl.Result{}, nil } + log.V(1).Info("Ensured Ignition") - patchErr := r.patchStatus(ctx, HTTPBootConfig, state) - if patchErr != nil { - return ctrl.Result{}, fmt.Errorf("failed to patch status %w", patchErr) + if err := r.patchStatus(ctx, config, state); err != nil { + return ctrl.Result{}, err } + log.V(1).Info("Reconciled HTTPBootConfig") return ctrl.Result{}, nil } -func (r *HTTPBootConfigReconciler) ensureIgnition(ctx context.Context, _ logr.Logger, HTTPBootConfig *bootv1alpha1.HTTPBootConfig) (bootv1alpha1.HTTPBootConfigState, error) { +func (r *HTTPBootConfigReconciler) ensureIgnition(ctx context.Context, _ logr.Logger, config *bootv1alpha1.HTTPBootConfig) (bootv1alpha1.HTTPBootConfigState, error) { // Verify if the IgnitionRef is set, and it has the intended data key. - if HTTPBootConfig.Spec.IgnitionSecretRef != nil { - IgnitionSecret := &corev1.Secret{} - if err := r.Get(ctx, client.ObjectKey{Name: HTTPBootConfig.Spec.IgnitionSecretRef.Name, Namespace: HTTPBootConfig.Namespace}, IgnitionSecret); err != nil { + if config.Spec.IgnitionSecretRef != nil { + ignitionSecret := &corev1.Secret{} + if err := r.Get(ctx, client.ObjectKey{Name: config.Spec.IgnitionSecretRef.Name, Namespace: config.Namespace}, ignitionSecret); err != nil { return bootv1alpha1.HTTPBootConfigStateError, err - // TODO: Add some validation steps to ensure that the IgntionData is compliant, if necessary. + // TODO: Add some validation steps to ensure that the IgnitionData is compliant, if necessary. // Assume for now, that it's going to json format. } - if IgnitionSecret.Data[bootv1alpha1.DefaultIgnitionKey] == nil { + if ignitionSecret.Data[bootv1alpha1.DefaultIgnitionKey] == nil { return bootv1alpha1.HTTPBootConfigStateError, fmt.Errorf("ignition data is missing") } } @@ -93,64 +90,61 @@ func (r *HTTPBootConfigReconciler) delete(_ context.Context, log logr.Logger, _ // TODO + log.V(1).Info("Deleted HTTPBootConfig") return ctrl.Result{}, nil } -// SetupWithManager sets up the controller with the Manager. -func (r *HTTPBootConfigReconciler) SetupWithManager(mgr ctrl.Manager) error { - return ctrl.NewControllerManagedBy(mgr). - For(&bootv1alpha1.HTTPBootConfig{}). - Watches( - &corev1.Secret{}, - handler.EnqueueRequestsFromMapFunc(r.enqueueHTTPBootConfigReferencingIgnitionSecret), - ). - Complete(r) -} - -func (r *HTTPBootConfigReconciler) patchStatus( - ctx context.Context, - HTTPBootConfig *bootv1alpha1.HTTPBootConfig, - state bootv1alpha1.HTTPBootConfigState, -) error { - if HTTPBootConfig.Status.State == state { +func (r *HTTPBootConfigReconciler) patchStatus(ctx context.Context, config *bootv1alpha1.HTTPBootConfig, state bootv1alpha1.HTTPBootConfigState) error { + if config.Status.State == state { return nil } - base := HTTPBootConfig.DeepCopy() - HTTPBootConfig.Status.State = state + base := config.DeepCopy() + config.Status.State = state - if err := r.Status().Patch(ctx, HTTPBootConfig, client.MergeFrom(base)); err != nil { - return fmt.Errorf("error patching HTTPBootConfig: %w", err) + if err := r.Status().Patch(ctx, config, client.MergeFrom(base)); err != nil { + return err } return nil } func (r *HTTPBootConfigReconciler) enqueueHTTPBootConfigReferencingIgnitionSecret(ctx context.Context, secret client.Object) []reconcile.Request { - log := log.Log.WithValues("secret", secret.GetName()) + log := ctrl.LoggerFrom(ctx) secretObj, ok := secret.(*corev1.Secret) if !ok { log.Error(nil, "cant decode object into Secret", secret) return nil } - list := &bootv1alpha1.HTTPBootConfigList{} - if err := r.List(ctx, list, client.InNamespace("")); err != nil { - log.Error(err, "failed to list HTTPBootConfig for secret", secret) + configList := &bootv1alpha1.HTTPBootConfigList{} + if err := r.List(ctx, configList, client.InNamespace("")); err != nil { + log.Error(err, "failed to list HTTPBootConfig for Secret", "Secret", client.ObjectKeyFromObject(secretObj)) return nil } var requests []reconcile.Request - for _, HTTPBootConfig := range list.Items { - if HTTPBootConfig.Spec.IgnitionSecretRef != nil && - HTTPBootConfig.Spec.IgnitionSecretRef.Name == secretObj.Name && - HTTPBootConfig.Namespace == secretObj.Namespace { + for _, config := range configList.Items { + if config.Spec.IgnitionSecretRef != nil && + config.Spec.IgnitionSecretRef.Name == secretObj.Name && + config.Namespace == secretObj.Namespace { requests = append(requests, reconcile.Request{ NamespacedName: types.NamespacedName{ - Name: HTTPBootConfig.Name, - Namespace: HTTPBootConfig.Namespace, + Name: config.Name, + Namespace: config.Namespace, }, }) } } return requests } + +// SetupWithManager sets up the controller with the Manager. +func (r *HTTPBootConfigReconciler) SetupWithManager(mgr ctrl.Manager) error { + return ctrl.NewControllerManagedBy(mgr). + For(&bootv1alpha1.HTTPBootConfig{}). + Watches( + &corev1.Secret{}, + handler.EnqueueRequestsFromMapFunc(r.enqueueHTTPBootConfigReferencingIgnitionSecret), + ). + Complete(r) +} diff --git a/internal/controller/ipxebootconfig_controller.go b/internal/controller/ipxebootconfig_controller.go index e27baf5e..ad2d68b9 100644 --- a/internal/controller/ipxebootconfig_controller.go +++ b/internal/controller/ipxebootconfig_controller.go @@ -12,7 +12,6 @@ import ( ctrl "sigs.k8s.io/controller-runtime" "sigs.k8s.io/controller-runtime/pkg/client" "sigs.k8s.io/controller-runtime/pkg/handler" - "sigs.k8s.io/controller-runtime/pkg/log" "sigs.k8s.io/controller-runtime/pkg/reconcile" "github.com/go-logr/logr" @@ -32,49 +31,47 @@ type IPXEBootConfigReconciler struct { //+kubebuilder:rbac:groups="",resources=secrets,verbs=get;list;watch func (r *IPXEBootConfigReconciler) Reconcile(ctx context.Context, req ctrl.Request) (ctrl.Result, error) { - log := log.FromContext(ctx) - IPXEBootConfig := &bootv1alpha1.IPXEBootConfig{} - if err := r.Get(ctx, req.NamespacedName, IPXEBootConfig); err != nil { + log := ctrl.LoggerFrom(ctx) + config := &bootv1alpha1.IPXEBootConfig{} + if err := r.Get(ctx, req.NamespacedName, config); err != nil { return ctrl.Result{}, client.IgnoreNotFound(err) } - - return r.reconcileExists(ctx, log, IPXEBootConfig) + return r.reconcileExists(ctx, log, config) } -func (r *IPXEBootConfigReconciler) reconcileExists(ctx context.Context, log logr.Logger, IPXEBootConfig *bootv1alpha1.IPXEBootConfig) (ctrl.Result, error) { - if !IPXEBootConfig.DeletionTimestamp.IsZero() { - return r.delete(ctx, log, IPXEBootConfig) +func (r *IPXEBootConfigReconciler) reconcileExists(ctx context.Context, log logr.Logger, config *bootv1alpha1.IPXEBootConfig) (ctrl.Result, error) { + if !config.DeletionTimestamp.IsZero() { + return r.delete(ctx, log, config) } - - return r.reconcile(ctx, log, IPXEBootConfig) + return r.reconcile(ctx, log, config) } -func (r *IPXEBootConfigReconciler) reconcile(ctx context.Context, log logr.Logger, ipxeBootConfig *bootv1alpha1.IPXEBootConfig) (ctrl.Result, error) { +func (r *IPXEBootConfigReconciler) reconcile(ctx context.Context, log logr.Logger, config *bootv1alpha1.IPXEBootConfig) (ctrl.Result, error) { + log.V(1).Info("Reconciling IPXEBootConfig") + log.V(1).Info("Ensuring Ignition") - state, ignitionErr := r.ensureIgnition(ctx, log, ipxeBootConfig) - if ignitionErr != nil { - patchError := r.patchStatus(ctx, ipxeBootConfig, state) - if patchError != nil { - return ctrl.Result{}, fmt.Errorf("failed to patch status %w %w", ignitionErr, patchError) + state, err := r.ensureIgnition(ctx, log, config) + if err != nil { + if err := r.patchStatus(ctx, config, state); err != nil { + return ctrl.Result{}, err } - - log.V(1).Info("Failed to Ensure Ignition", "Error", ignitionErr) - return ctrl.Result{}, nil + return ctrl.Result{}, fmt.Errorf("failed to ensure Ignition: %w", err) } + log.V(1).Info("Ensured Ignition") - patchErr := r.patchStatus(ctx, ipxeBootConfig, state) - if patchErr != nil { - return ctrl.Result{}, fmt.Errorf("failed to patch status %w", patchErr) + if err := r.patchStatus(ctx, config, state); err != nil { + return ctrl.Result{}, fmt.Errorf("failed to patch status %w", err) } + log.V(1).Info("Reconciled IPXEBootConfig") return ctrl.Result{}, nil } -func (r *IPXEBootConfigReconciler) ensureIgnition(ctx context.Context, _ logr.Logger, ipxeBootConfig *bootv1alpha1.IPXEBootConfig) (bootv1alpha1.IPXEBootConfigState, error) { +func (r *IPXEBootConfigReconciler) ensureIgnition(ctx context.Context, _ logr.Logger, config *bootv1alpha1.IPXEBootConfig) (bootv1alpha1.IPXEBootConfigState, error) { // Verify if the IgnitionRef is set, and it has the intended data key. - if ipxeBootConfig.Spec.IgnitionSecretRef != nil { + if config.Spec.IgnitionSecretRef != nil { IgnitionSecret := &corev1.Secret{} - if err := r.Get(ctx, client.ObjectKey{Name: ipxeBootConfig.Spec.IgnitionSecretRef.Name, Namespace: ipxeBootConfig.Namespace}, IgnitionSecret); err != nil { + if err := r.Get(ctx, client.ObjectKey{Name: config.Spec.IgnitionSecretRef.Name, Namespace: config.Namespace}, IgnitionSecret); err != nil { return bootv1alpha1.IPXEBootConfigStateError, err // TODO: Add some validation steps to ensure that the IgntionData is compliant, if necessary. // Assume for now, that it's going to json format. @@ -88,24 +85,14 @@ func (r *IPXEBootConfigReconciler) ensureIgnition(ctx context.Context, _ logr.Lo } func (r *IPXEBootConfigReconciler) delete(_ context.Context, log logr.Logger, _ *bootv1alpha1.IPXEBootConfig) (ctrl.Result, error) { - log.V(1).Info("Deleting ipxeBootConfig") + log.V(1).Info("Deleting IPXEBootConfig") // TODO + log.V(1).Info("Deleted IPXEBootConfig") return ctrl.Result{}, nil } -// SetupWithManager sets up the controller with the Manager. -func (r *IPXEBootConfigReconciler) SetupWithManager(mgr ctrl.Manager) error { - return ctrl.NewControllerManagedBy(mgr). - For(&bootv1alpha1.IPXEBootConfig{}). - Watches( - &corev1.Secret{}, - handler.EnqueueRequestsFromMapFunc(r.enqueueIPXEBootConfigReferencingIgnitionSecret), - ). - Complete(r) -} - func (r *IPXEBootConfigReconciler) patchStatus( ctx context.Context, ipxeBootConfig *bootv1alpha1.IPXEBootConfig, @@ -121,29 +108,40 @@ func (r *IPXEBootConfigReconciler) patchStatus( } func (r *IPXEBootConfigReconciler) enqueueIPXEBootConfigReferencingIgnitionSecret(ctx context.Context, secret client.Object) []reconcile.Request { - log := log.Log.WithValues("secret", secret.GetName()) + log := ctrl.LoggerFrom(ctx) secretObj, ok := secret.(*corev1.Secret) if !ok { log.Error(nil, "cant decode object into Secret", secret) return nil } - list := &bootv1alpha1.IPXEBootConfigList{} - if err := r.List(ctx, list, client.InNamespace(secretObj.Namespace)); err != nil { - log.Error(err, "failed to list IPXEBootConfig for secret", secret) + configList := &bootv1alpha1.IPXEBootConfigList{} + if err := r.List(ctx, configList, client.InNamespace(secretObj.Namespace)); err != nil { + log.Error(err, "failed to list IPXEBootConfig for Secret", "Secret", client.ObjectKeyFromObject(secretObj)) return nil } var requests []reconcile.Request - for _, ipxeBootConfig := range list.Items { - if ipxeBootConfig.Spec.IgnitionSecretRef != nil && ipxeBootConfig.Spec.IgnitionSecretRef.Name == secretObj.Name { + for _, config := range configList.Items { + if config.Spec.IgnitionSecretRef != nil && config.Spec.IgnitionSecretRef.Name == secretObj.Name { requests = append(requests, reconcile.Request{ NamespacedName: types.NamespacedName{ - Name: ipxeBootConfig.Name, - Namespace: ipxeBootConfig.Namespace, + Name: config.Name, + Namespace: config.Namespace, }, }) } } return requests } + +// SetupWithManager sets up the controller with the Manager. +func (r *IPXEBootConfigReconciler) SetupWithManager(mgr ctrl.Manager) error { + return ctrl.NewControllerManagedBy(mgr). + For(&bootv1alpha1.IPXEBootConfig{}). + Watches( + &corev1.Secret{}, + handler.EnqueueRequestsFromMapFunc(r.enqueueIPXEBootConfigReferencingIgnitionSecret), + ). + Complete(r) +} diff --git a/internal/controller/serverbootconfiguration_http_controller.go b/internal/controller/serverbootconfiguration_http_controller.go index 6ba556da..d59ac0a3 100644 --- a/internal/controller/serverbootconfiguration_http_controller.go +++ b/internal/controller/serverbootconfiguration_http_controller.go @@ -17,7 +17,6 @@ import ( corev1 "k8s.io/api/core/v1" "k8s.io/apimachinery/pkg/types" "sigs.k8s.io/controller-runtime/pkg/handler" - "sigs.k8s.io/controller-runtime/pkg/log" "sigs.k8s.io/controller-runtime/pkg/reconcile" "github.com/go-logr/logr" @@ -131,7 +130,6 @@ func (r *ServerBootConfigurationHTTPReconciler) reconcile(ctx context.Context, l log.V(1).Info("Patched server boot config state") log.V(1).Info("Reconciled ServerBootConfiguration") - return ctrl.Result{}, nil } @@ -253,42 +251,42 @@ func (r *ServerBootConfigurationHTTPReconciler) getUKIDigestFromNestedManifest(c return "", fmt.Errorf("UKI layer digest not found") } -// SetupWithManager sets up the controller with the Manager. -func (r *ServerBootConfigurationHTTPReconciler) SetupWithManager(mgr ctrl.Manager) error { - return ctrl.NewControllerManagedBy(mgr). - For(&metalv1alpha1.ServerBootConfiguration{}). - Owns(&bootv1alpha1.HTTPBootConfig{}). - Watches( - &corev1.Secret{}, - handler.EnqueueRequestsFromMapFunc(r.enqueueServerBootConfigReferencingIgnitionSecret), - ). - Complete(r) -} - func (r *ServerBootConfigurationHTTPReconciler) enqueueServerBootConfigReferencingIgnitionSecret(ctx context.Context, secret client.Object) []reconcile.Request { - log := log.Log.WithValues("secret", secret.GetName()) + log := ctrl.LoggerFrom(ctx) secretObj, ok := secret.(*corev1.Secret) if !ok { log.Error(nil, "can't decode object into Secret", secret) return nil } - list := &metalv1alpha1.ServerBootConfigurationList{} - if err := r.List(ctx, list, client.InNamespace(secretObj.Namespace)); err != nil { + bootConfigList := &metalv1alpha1.ServerBootConfigurationList{} + if err := r.List(ctx, bootConfigList, client.InNamespace(secretObj.Namespace)); err != nil { log.Error(err, "failed to list ServerBootConfiguration for secret", secret) return nil } var requests []reconcile.Request - for _, serverBootConfig := range list.Items { - if serverBootConfig.Spec.IgnitionSecretRef != nil && serverBootConfig.Spec.IgnitionSecretRef.Name == secretObj.Name { + for _, bootConfig := range bootConfigList.Items { + if bootConfig.Spec.IgnitionSecretRef != nil && bootConfig.Spec.IgnitionSecretRef.Name == secretObj.Name { requests = append(requests, reconcile.Request{ NamespacedName: types.NamespacedName{ - Name: serverBootConfig.Name, - Namespace: serverBootConfig.Namespace, + Name: bootConfig.Name, + Namespace: bootConfig.Namespace, }, }) } } return requests } + +// SetupWithManager sets up the controller with the Manager. +func (r *ServerBootConfigurationHTTPReconciler) SetupWithManager(mgr ctrl.Manager) error { + return ctrl.NewControllerManagedBy(mgr). + For(&metalv1alpha1.ServerBootConfiguration{}). + Owns(&bootv1alpha1.HTTPBootConfig{}). + Watches( + &corev1.Secret{}, + handler.EnqueueRequestsFromMapFunc(r.enqueueServerBootConfigReferencingIgnitionSecret), + ). + Complete(r) +} diff --git a/internal/controller/serverbootconfiguration_pxe_controller.go b/internal/controller/serverbootconfiguration_pxe_controller.go index 4bbcb3a9..d7135f45 100644 --- a/internal/controller/serverbootconfiguration_pxe_controller.go +++ b/internal/controller/serverbootconfiguration_pxe_controller.go @@ -26,7 +26,6 @@ import ( corev1 "k8s.io/api/core/v1" "k8s.io/apimachinery/pkg/types" "sigs.k8s.io/controller-runtime/pkg/handler" - "sigs.k8s.io/controller-runtime/pkg/log" "sigs.k8s.io/controller-runtime/pkg/reconcile" "github.com/ironcore-dev/boot-operator/api/v1alpha1" @@ -45,13 +44,6 @@ import ( ocispec "github.com/opencontainers/image-spec/specs-go/v1" ) -type ServerBootConfigurationPXEReconciler struct { - client.Client - Scheme *runtime.Scheme - IPXEServiceURL string - Architecture string -} - const ( MediaTypeKernel = "application/vnd.ironcore.image.kernel" MediaTypeInitrd = "application/vnd.ironcore.image.initramfs" @@ -62,6 +54,13 @@ const ( CNAMEPrefixMetalPXE = "metal_pxe" ) +type ServerBootConfigurationPXEReconciler struct { + client.Client + Scheme *runtime.Scheme + IPXEServiceURL string + Architecture string +} + //+kubebuilder:rbac:groups=metal.ironcore.dev,resources=serverbootconfigurations,verbs=get;list;watch //+kubebuilder:rbac:groups=metal.ironcore.dev,resources=serverbootconfigurations/status,verbs=get;update;patch //+kubebuilder:rbac:groups=metal.ironcore.dev,resources=serverbootconfigurations/finalizers,verbs=update @@ -92,38 +91,38 @@ func (r *ServerBootConfigurationPXEReconciler) delete(_ context.Context, _ logr. return ctrl.Result{}, nil } -func (r *ServerBootConfigurationPXEReconciler) reconcile(ctx context.Context, log logr.Logger, config *metalv1alpha1.ServerBootConfiguration) (ctrl.Result, error) { +func (r *ServerBootConfigurationPXEReconciler) reconcile(ctx context.Context, log logr.Logger, bootConfig *metalv1alpha1.ServerBootConfiguration) (ctrl.Result, error) { log.V(1).Info("Reconciling ServerBootConfiguration") - systemUUID, err := r.getSystemUUIDFromBootConfig(ctx, config) + systemUUID, err := r.getSystemUUIDFromBootConfig(ctx, bootConfig) if err != nil { return ctrl.Result{}, fmt.Errorf("failed to get system UUID from BootConfig: %w", err) } log.V(1).Info("Got system UUID from BootConfig", "systemUUID", systemUUID) - systemIPs, err := r.getSystemIPFromBootConfig(ctx, config) + systemIPs, err := r.getSystemIPFromBootConfig(ctx, bootConfig) if err != nil { return ctrl.Result{}, fmt.Errorf("failed to get system IP from BootConfig: %w", err) } log.V(1).Info("Got system IP from BootConfig", "systemIPs", systemIPs) - kernelURL, initrdURL, squashFSURL, err := r.getImageDetailsFromConfig(ctx, config) + kernelURL, initrdURL, squashFSURL, err := r.getImageDetailsFromConfig(ctx, bootConfig) if err != nil { - if err := r.patchState(ctx, config, metalv1alpha1.ServerBootConfigurationStateError); err != nil { + if err := r.patchState(ctx, bootConfig, metalv1alpha1.ServerBootConfigurationStateError); err != nil { return ctrl.Result{}, fmt.Errorf("failed to patch server boot config state to %s: %w", metalv1alpha1.ServerBootConfigurationStateError, err) } return ctrl.Result{}, fmt.Errorf("failed to get image details from BootConfig: %w", err) } log.V(1).Info("Extracted OS image layer details") - ipxeConfig := &v1alpha1.IPXEBootConfig{ + config := &v1alpha1.IPXEBootConfig{ TypeMeta: metav1.TypeMeta{ APIVersion: "boot.ironcore.dev/v1alpha1", Kind: "IPXEBootConfig", }, ObjectMeta: metav1.ObjectMeta{ - Namespace: config.Namespace, - Name: config.Name, + Namespace: bootConfig.Namespace, + Name: bootConfig.Name, }, Spec: v1alpha1.IPXEBootConfigSpec{ SystemUUID: systemUUID, @@ -133,26 +132,26 @@ func (r *ServerBootConfigurationPXEReconciler) reconcile(ctx context.Context, lo SquashfsURL: squashFSURL, }, } - if config.Spec.IgnitionSecretRef != nil { - ipxeConfig.Spec.IgnitionSecretRef = config.Spec.IgnitionSecretRef + if bootConfig.Spec.IgnitionSecretRef != nil { + config.Spec.IgnitionSecretRef = bootConfig.Spec.IgnitionSecretRef } - if err := controllerutil.SetControllerReference(config, ipxeConfig, r.Scheme); err != nil { + if err := controllerutil.SetControllerReference(bootConfig, config, r.Scheme); err != nil { return ctrl.Result{}, fmt.Errorf("failed to set controller reference: %w", err) } log.V(1).Info("Set controller reference") - if err := r.Patch(ctx, ipxeConfig, client.Apply, fieldOwner, client.ForceOwnership); err != nil { + if err := r.Patch(ctx, config, client.Apply, fieldOwner, client.ForceOwnership); err != nil { return ctrl.Result{}, fmt.Errorf("failed to apply IPXE config: %w", err) } log.V(1).Info("Applied IPXE config for server boot config") - if err := r.Get(ctx, client.ObjectKey{Namespace: config.Namespace, Name: config.Name}, ipxeConfig); err != nil { + if err := r.Get(ctx, client.ObjectKey{Namespace: bootConfig.Namespace, Name: bootConfig.Name}, config); err != nil { return ctrl.Result{}, fmt.Errorf("failed to get IPXE config: %w", err) } - if err := r.patchConfigStateFromIPXEState(ctx, ipxeConfig, config); err != nil { - return ctrl.Result{}, fmt.Errorf("failed to patch server boot config state to %s: %w", ipxeConfig.Status.State, err) + if err := r.patchConfigStateFromIPXEState(ctx, config, bootConfig); err != nil { + return ctrl.Result{}, fmt.Errorf("failed to patch server boot config state to %s: %w", config.Status.State, err) } log.V(1).Info("Patched server boot config state") @@ -160,26 +159,21 @@ func (r *ServerBootConfigurationPXEReconciler) reconcile(ctx context.Context, lo return ctrl.Result{}, nil } -func (r *ServerBootConfigurationPXEReconciler) patchConfigStateFromIPXEState(ctx context.Context, ipxeConfig *v1alpha1.IPXEBootConfig, cfg *metalv1alpha1.ServerBootConfiguration) error { - key := types.NamespacedName{Name: cfg.Name, Namespace: cfg.Namespace} - var cur metalv1alpha1.ServerBootConfiguration - if err := r.Get(ctx, key, &cur); err != nil { - return err - } - base := cur.DeepCopy() +func (r *ServerBootConfigurationPXEReconciler) patchConfigStateFromIPXEState(ctx context.Context, config *v1alpha1.IPXEBootConfig, bootConfig *metalv1alpha1.ServerBootConfiguration) error { + bootConfigBase := bootConfig.DeepCopy() - switch ipxeConfig.Status.State { + switch config.Status.State { case v1alpha1.IPXEBootConfigStateReady: - cur.Status.State = metalv1alpha1.ServerBootConfigurationStateReady + bootConfig.Status.State = metalv1alpha1.ServerBootConfigurationStateReady case v1alpha1.IPXEBootConfigStateError: - cur.Status.State = metalv1alpha1.ServerBootConfigurationStateError + bootConfig.Status.State = metalv1alpha1.ServerBootConfigurationStateError } - for _, c := range ipxeConfig.Status.Conditions { - apimeta.SetStatusCondition(&cur.Status.Conditions, c) + for _, c := range config.Status.Conditions { + apimeta.SetStatusCondition(&bootConfig.Status.Conditions, c) } - return r.Status().Patch(ctx, &cur, client.MergeFrom(base)) + return r.Status().Patch(ctx, bootConfig, client.MergeFrom(bootConfigBase)) } func (r *ServerBootConfigurationPXEReconciler) patchState(ctx context.Context, config *metalv1alpha1.ServerBootConfiguration, state metalv1alpha1.ServerBootConfigurationState) error { @@ -194,19 +188,18 @@ func (r *ServerBootConfigurationPXEReconciler) patchState(ctx context.Context, c func (r *ServerBootConfigurationPXEReconciler) getSystemUUIDFromBootConfig(ctx context.Context, config *metalv1alpha1.ServerBootConfiguration) (string, error) { server := &metalv1alpha1.Server{} if err := r.Get(ctx, client.ObjectKey{Name: config.Spec.ServerRef.Name}, server); err != nil { - return "", fmt.Errorf("failed to get Server: %w", err) + return "", err } - return server.Spec.UUID, nil } func (r *ServerBootConfigurationPXEReconciler) getSystemIPFromBootConfig(ctx context.Context, config *metalv1alpha1.ServerBootConfiguration) ([]string, error) { server := &metalv1alpha1.Server{} if err := r.Get(ctx, client.ObjectKey{Name: config.Spec.ServerRef.Name}, server); err != nil { - return nil, fmt.Errorf("failed to get Server: %w", err) + return nil, err } - systemIPs := []string{} + systemIPs := make([]string, 0, 1) for _, nic := range server.Status.NetworkInterfaces { systemIPs = append(systemIPs, nic.IP.String()) } @@ -350,42 +343,42 @@ func fetchContent(ctx context.Context, resolver remotes.Resolver, ref string, de return data, nil } -// SetupWithManager sets up the controller with the Manager. -func (r *ServerBootConfigurationPXEReconciler) SetupWithManager(mgr ctrl.Manager) error { - return ctrl.NewControllerManagedBy(mgr). - For(&metalv1alpha1.ServerBootConfiguration{}). - Owns(&v1alpha1.IPXEBootConfig{}). - Watches( - &corev1.Secret{}, - handler.EnqueueRequestsFromMapFunc(r.enqueueServerBootConfigReferencingIgnitionSecret), - ). - Complete(r) -} - -func (r *ServerBootConfigurationPXEReconciler) enqueueServerBootConfigReferencingIgnitionSecret(ctx context.Context, secret client.Object) []reconcile.Request { - log := log.Log.WithValues("secret", secret.GetName()) +func (r *ServerBootConfigurationPXEReconciler) enqueueServerBootConfigFromIgnitionSecret(ctx context.Context, secret client.Object) []reconcile.Request { + log := ctrl.LoggerFrom(ctx) secretObj, ok := secret.(*corev1.Secret) if !ok { log.Error(nil, "can't decode object into Secret", secret) return nil } - list := &metalv1alpha1.ServerBootConfigurationList{} - if err := r.List(ctx, list, client.InNamespace(secretObj.Namespace)); err != nil { - log.Error(err, "failed to list ServerBootConfiguration for secret", secret) + bootConfigList := &metalv1alpha1.ServerBootConfigurationList{} + if err := r.List(ctx, bootConfigList, client.InNamespace(secretObj.Namespace)); err != nil { + log.Error(err, "failed to list ServerBootConfiguration for Secret", "Secret", client.ObjectKeyFromObject(secretObj)) return nil } var requests []reconcile.Request - for _, serverBootConfig := range list.Items { - if serverBootConfig.Spec.IgnitionSecretRef != nil && serverBootConfig.Spec.IgnitionSecretRef.Name == secretObj.Name { + for _, bootConfig := range bootConfigList.Items { + if bootConfig.Spec.IgnitionSecretRef != nil && bootConfig.Spec.IgnitionSecretRef.Name == secretObj.Name { requests = append(requests, reconcile.Request{ NamespacedName: types.NamespacedName{ - Name: serverBootConfig.Name, - Namespace: serverBootConfig.Namespace, + Name: bootConfig.Name, + Namespace: bootConfig.Namespace, }, }) } } return requests } + +// SetupWithManager sets up the controller with the Manager. +func (r *ServerBootConfigurationPXEReconciler) SetupWithManager(mgr ctrl.Manager) error { + return ctrl.NewControllerManagedBy(mgr). + For(&metalv1alpha1.ServerBootConfiguration{}). + Owns(&v1alpha1.IPXEBootConfig{}). + Watches( + &corev1.Secret{}, + handler.EnqueueRequestsFromMapFunc(r.enqueueServerBootConfigFromIgnitionSecret), + ). + Complete(r) +} diff --git a/internal/controller/suite_test.go b/internal/controller/suite_test.go index 144d77c3..3bd6d233 100644 --- a/internal/controller/suite_test.go +++ b/internal/controller/suite_test.go @@ -75,7 +75,7 @@ var _ = BeforeSuite(func() { // Note that you must have the required binaries setup under the bin directory to perform // the tests directly. When we run make test it will be setup and used automatically. BinaryAssetsDirectory: filepath.Join("..", "..", "bin", "k8s", - fmt.Sprintf("1.31.0-%s-%s", runtime.GOOS, runtime.GOARCH)), + fmt.Sprintf("1.34.0-%s-%s", runtime.GOOS, runtime.GOARCH)), } var err error