Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
18 changes: 13 additions & 5 deletions internal/cmd/console/console_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,10 @@
package console

import (
"context"

metalv1alpha1 "github.com/ironcore-dev/metal-operator/api/v1alpha1"
"github.com/ironcore-dev/metal-operator/internal/controller"
. "github.com/onsi/ginkgo/v2"
. "github.com/onsi/gomega"
corev1 "k8s.io/api/core/v1"
Expand All @@ -14,6 +17,16 @@ import (
var _ = Describe("Console Access", func() {
_ = SetupTest()

AfterEach(func(ctx context.Context) {
By("Deleting the Server, BMC and BMCSecret resources")
Expect(k8sClient.DeleteAllOf(ctx, &metalv1alpha1.Server{})).To(Succeed())
Expect(k8sClient.DeleteAllOf(ctx, &metalv1alpha1.BMC{})).To(Succeed())
Expect(k8sClient.DeleteAllOf(ctx, &metalv1alpha1.BMCSecret{})).To(Succeed())

By("Ensuring clean state")
controller.EnsureCleanState()
})

It("Should successfully construct console config for Server with inline configuration", func(ctx SpecContext) {
By("Creating a BMCSecret")
bmcSecret := &metalv1alpha1.BMCSecret{
Expand All @@ -26,7 +39,6 @@ var _ = Describe("Console Access", func() {
},
}
Expect(k8sClient.Create(ctx, bmcSecret)).To(Succeed())
DeferCleanup(k8sClient.Delete, bmcSecret)

By("Creating a Server object")
server := &metalv1alpha1.Server{
Expand All @@ -45,7 +57,6 @@ var _ = Describe("Console Access", func() {
},
}
Expect(k8sClient.Create(ctx, server)).To(Succeed())
DeferCleanup(k8sClient.Delete, server)

config, err := GetConfigForServerName(ctx, k8sClient, server.Name)
Expect(err).NotTo(HaveOccurred())
Expand All @@ -68,7 +79,6 @@ var _ = Describe("Console Access", func() {
},
}
Expect(k8sClient.Create(ctx, bmcSecret)).To(Succeed())
DeferCleanup(k8sClient.Delete, bmcSecret)

bmc := &metalv1alpha1.BMC{
ObjectMeta: metav1.ObjectMeta{
Expand All @@ -85,7 +95,6 @@ var _ = Describe("Console Access", func() {
},
}
Expect(k8sClient.Create(ctx, bmc)).To(Succeed())
DeferCleanup(k8sClient.Delete, bmc)

By("Creating a Server object")
server := &metalv1alpha1.Server{
Expand All @@ -100,7 +109,6 @@ var _ = Describe("Console Access", func() {
},
}
Expect(k8sClient.Create(ctx, server)).To(Succeed())
DeferCleanup(k8sClient.Delete, server)

config, err := GetConfigForServerName(ctx, k8sClient, server.Name)
Expect(err).NotTo(HaveOccurred())
Expand Down
42 changes: 24 additions & 18 deletions internal/controller/test_helper.go
Original file line number Diff line number Diff line change
Expand Up @@ -16,35 +16,41 @@ func EnsureCleanState() {
GinkgoHelper()

Eventually(func(g Gomega) error {
bmcList := &metalv1alpha1.BMCList{}
g.Eventually(ObjectList(bmcList)).Should(HaveField("Items", HaveLen(0)))
endpoints := &metalv1alpha1.EndpointList{}
g.Eventually(ObjectList(endpoints)).Should(HaveField("Items", HaveLen(0)))

bmcSecretList := &metalv1alpha1.BMCSecretList{}
g.Eventually(ObjectList(bmcSecretList)).Should(HaveField("Items", HaveLen(0)))
bmcs := &metalv1alpha1.BMCList{}
g.Eventually(ObjectList(bmcs)).Should(HaveField("Items", HaveLen(0)))

claimList := &metalv1alpha1.ServerClaimList{}
g.Eventually(ObjectList(claimList)).Should(HaveField("Items", HaveLen(0)))
bmcSecrets := &metalv1alpha1.BMCSecretList{}
g.Eventually(ObjectList(bmcSecrets)).Should(HaveField("Items", HaveLen(0)))

claims := &metalv1alpha1.ServerClaimList{}
g.Eventually(ObjectList(claims)).Should(HaveField("Items", HaveLen(0)))

bmcSettingsList := &metalv1alpha1.BMCSettingsList{}
g.Eventually(ObjectList(bmcSettingsList)).Should(HaveField("Items", HaveLen(0)))

bmcVersionSetList := &metalv1alpha1.BMCVersionSetList{}
g.Eventually(ObjectList(bmcVersionSetList)).Should(HaveField("Items", HaveLen(0)))
bmcVersionSets := &metalv1alpha1.BMCVersionSetList{}
g.Eventually(ObjectList(bmcVersionSets)).Should(HaveField("Items", HaveLen(0)))

bmcVersions := &metalv1alpha1.BMCVersionList{}
g.Eventually(ObjectList(bmcVersions)).Should(HaveField("Items", HaveLen(0)))

bmcVersionList := &metalv1alpha1.BMCVersionList{}
g.Eventually(ObjectList(bmcVersionList)).Should(HaveField("Items", HaveLen(0)))
biosVersions := &metalv1alpha1.BIOSVersionList{}
g.Eventually(ObjectList(biosVersions)).Should(HaveField("Items", HaveLen(0)))

biosSettingsSetList := &metalv1alpha1.BIOSSettingsSetList{}
g.Eventually(ObjectList(biosSettingsSetList)).Should(HaveField("Items", HaveLen(0)))
biosSettingsSets := &metalv1alpha1.BIOSSettingsSetList{}
g.Eventually(ObjectList(biosSettingsSets)).Should(HaveField("Items", HaveLen(0)))

biosSettings := &metalv1alpha1.BIOSSettingsList{}
g.Eventually(ObjectList(biosSettings)).Should(HaveField("Items", HaveLen(0)))
biosSettingsList := &metalv1alpha1.BIOSSettingsList{}
g.Eventually(ObjectList(biosSettingsList)).Should(HaveField("Items", HaveLen(0)))

maintenanceList := &metalv1alpha1.ServerMaintenanceList{}
g.Eventually(ObjectList(maintenanceList)).Should(HaveField("Items", HaveLen(0)))
maintenances := &metalv1alpha1.ServerMaintenanceList{}
g.Eventually(ObjectList(maintenances)).Should(HaveField("Items", HaveLen(0)))

serverList := &metalv1alpha1.ServerList{}
g.Eventually(ObjectList(serverList)).Should(HaveField("Items", HaveLen(0)))
servers := &metalv1alpha1.ServerList{}
g.Eventually(ObjectList(servers)).Should(HaveField("Items", HaveLen(0)))

return nil
}).Should(Succeed())
Expand Down
2 changes: 1 addition & 1 deletion internal/webhook/v1alpha1/biossettings_webhook_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -98,7 +98,7 @@ var _ = Describe("BIOSSettings Webhook", func() {
Expect(k8sClient.Create(ctx, biosSettingsV2)).To(Succeed())
})

It("Should deny update if a Spec.ServerRef field is duplicate", func() {
It("Should deny update if spec.serverRef is duplicate", func() {
By("Creating a BIOSSettings with different ServerRef")
biosSettingsV2 := &metalv1alpha1.BIOSSettings{
ObjectMeta: metav1.ObjectMeta{
Expand Down
86 changes: 42 additions & 44 deletions internal/webhook/v1alpha1/biosversion_webhook.go
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ import (

// nolint:unused
// log is for logging in this package.
var biosversionlog = logf.Log.WithName("biosversion-resource")
var versionLog = logf.Log.WithName("biosversion-resource")

// SetupBIOSVersionWebhookWithManager registers the webhook for BIOSVersion in the manager.
func SetupBIOSVersionWebhookWithManager(mgr ctrl.Manager) error {
Expand All @@ -31,101 +31,99 @@ func SetupBIOSVersionWebhookWithManager(mgr ctrl.Manager) error {
Complete()
}

// TODO(user): EDIT THIS FILE! THIS IS SCAFFOLDING FOR YOU TO OWN!

// TODO(user): change verbs to "verbs=create;update;delete" if you want to enable deletion validation.
// NOTE: The 'path' attribute must follow a specific pattern and should not be modified directly here.
// Modifying the path for an invalid path can cause API server errors; failing to locate the webhook.
// +kubebuilder:webhook:path=/validate-metal-ironcore-dev-v1alpha1-biosversion,mutating=false,failurePolicy=fail,sideEffects=None,groups=metal.ironcore.dev,resources=biosversions,verbs=create;update;delete,versions=v1alpha1,name=vbiosversion-v1alpha1.kb.io,admissionReviewVersions=v1

// BIOSVersionCustomValidator struct is responsible for validating the BIOSVersion resource
// when it is created, updated, or deleted.
//
// NOTE: The +kubebuilder:object:generate=false marker prevents controller-gen from generating DeepCopy methods,
// as this struct is used only for temporary operations and does not need to be deeply copied.
type BIOSVersionCustomValidator struct {
Client client.Client
client.Client
}

var _ webhook.CustomValidator = &BIOSVersionCustomValidator{}

// ValidateCreate implements webhook.CustomValidator so a webhook will be registered for the type BIOSVersion.
func (v *BIOSVersionCustomValidator) ValidateCreate(ctx context.Context, obj runtime.Object) (admission.Warnings, error) {
biosversion, ok := obj.(*metalv1alpha1.BIOSVersion)
version, ok := obj.(*metalv1alpha1.BIOSVersion)
if !ok {
return nil, fmt.Errorf("expected a BIOSVersion object but got %T", obj)
}
biosversionlog.Info("Validation for BIOSVersion upon creation", "name", biosversion.GetName())
versionLog.Info("Validation for BIOSVersion upon creation", "name", version.GetName())

biosVersionList := &metalv1alpha1.BIOSVersionList{}
if err := v.Client.List(ctx, biosVersionList); err != nil {
return nil, fmt.Errorf("failed to list BIOSVersionList: %w", err)
versions := &metalv1alpha1.BIOSVersionList{}
if err := v.List(ctx, versions); err != nil {
return nil, fmt.Errorf("failed to list BIOSVersion: %w", err)
}
return checkForDuplicateBIOSVersionRefToServer(biosVersionList, biosversion)
return checkForDuplicateBIOSVersionRefToServer(versions, version)
}

// ValidateUpdate implements webhook.CustomValidator so a webhook will be registered for the type BIOSVersion.
func (v *BIOSVersionCustomValidator) ValidateUpdate(ctx context.Context, oldObj, newObj runtime.Object) (admission.Warnings, error) {
biosversion, ok := newObj.(*metalv1alpha1.BIOSVersion)
newVersion, ok := newObj.(*metalv1alpha1.BIOSVersion)
if !ok {
return nil, fmt.Errorf("expected a BIOSVersion object for the newObj but got %T", newObj)
}
biosversionlog.Info("Validation for BIOSVersion upon update", "name", biosversion.GetName())
versionLog.Info("Validation for BIOSVersion upon update", "name", newVersion.GetName())

oldBIOSVersion, ok := oldObj.(*metalv1alpha1.BIOSVersion)
oldVersion, ok := oldObj.(*metalv1alpha1.BIOSVersion)
if !ok {
return nil, fmt.Errorf("expected a BIOSVersion object for the oldObj but got %T", oldObj)
}
if oldBIOSVersion.Status.State == metalv1alpha1.BIOSVersionStateInProgress &&
!ShouldAllowForceUpdateInProgress(biosversion) && oldBIOSVersion.Spec.ServerMaintenanceRef != nil {
if oldVersion.Status.State == metalv1alpha1.BIOSVersionStateInProgress &&
!ShouldAllowForceUpdateInProgress(newVersion) && oldVersion.Spec.ServerMaintenanceRef != nil {
err := fmt.Errorf("BIOSVersion (%v) is in progress, unable to update %v",
oldBIOSVersion.Name,
biosversion.Name)
oldVersion.Name,
newVersion.Name)
return nil, apierrors.NewInvalid(
schema.GroupKind{Group: biosversion.GroupVersionKind().Group, Kind: biosversion.Kind},
biosversion.GetName(), field.ErrorList{field.Forbidden(field.NewPath("spec"), err.Error())})
schema.GroupKind{Group: newVersion.GroupVersionKind().Group, Kind: newVersion.Kind},
newVersion.GetName(), field.ErrorList{field.Forbidden(field.NewPath("spec"), err.Error())})
}

biosVersionList := &metalv1alpha1.BIOSVersionList{}
if err := v.Client.List(ctx, biosVersionList); err != nil {
return nil, fmt.Errorf("failed to list BIOSVersionList: %w", err)
versions := &metalv1alpha1.BIOSVersionList{}
if err := v.List(ctx, versions); err != nil {
return nil, fmt.Errorf("failed to list BIOSVersion: %w", err)
}

return checkForDuplicateBIOSVersionRefToServer(biosVersionList, biosversion)
return checkForDuplicateBIOSVersionRefToServer(versions, newVersion)
}

// ValidateDelete implements webhook.CustomValidator so a webhook will be registered for the type BIOSVersion.
func (v *BIOSVersionCustomValidator) ValidateDelete(ctx context.Context, obj runtime.Object) (admission.Warnings, error) {
biosversion, ok := obj.(*metalv1alpha1.BIOSVersion)
version, ok := obj.(*metalv1alpha1.BIOSVersion)
if !ok {
return nil, fmt.Errorf("expected a BIOSVersion object but got %T", obj)
}
biosversionlog.Info("Validation for BIOSVersion upon deletion", "name", biosversion.GetName())
versionLog.Info("Validation for BIOSVersion upon deletion", "name", version.GetName())

if biosversion.Status.State == metalv1alpha1.BIOSVersionStateInProgress && !ShouldAllowForceDeleteInProgress(biosversion) {
return nil, apierrors.NewBadRequest("The bios version in progress, unable to delete")
if version.Status.State == metalv1alpha1.BIOSVersionStateInProgress && !ShouldAllowForceDeleteInProgress(version) {
return nil, apierrors.NewBadRequest("The BIOS version is in progress and cannot be deleted")
}
return nil, nil
}

func checkForDuplicateBIOSVersionRefToServer(
biosVersionList *metalv1alpha1.BIOSVersionList,
biosVersion *metalv1alpha1.BIOSVersion,
) (admission.Warnings, error) {
for _, bv := range biosVersionList.Items {
if biosVersion.Name == bv.Name {
func checkForDuplicateBIOSVersionRefToServer(versions *metalv1alpha1.BIOSVersionList, version *metalv1alpha1.BIOSVersion) (admission.Warnings, error) {
if version.Spec.ServerRef == nil {
return nil, nil
}

for _, bv := range versions.Items {
if version.Name == bv.Name {
continue
}
if bv.Spec.ServerRef == nil {
continue
}
if biosVersion.Spec.ServerRef.Name == bv.Spec.ServerRef.Name {
err := fmt.Errorf("server (%v) referred in %v is duplicate of Server (%v) referred in %v",
biosVersion.Spec.ServerRef,
biosVersion.Name,
bv.Spec.ServerRef,
if version.Spec.ServerRef.Name == bv.Spec.ServerRef.Name {
err := fmt.Errorf("server (%s) referred in %s is duplicate of server (%s) referred in %s",
version.Spec.ServerRef.Name,
version.Name,
bv.Spec.ServerRef.Name,
bv.Name,
)
return nil, apierrors.NewInvalid(
schema.GroupKind{Group: biosVersion.GroupVersionKind().Group, Kind: biosVersion.Kind},
biosVersion.GetName(), field.ErrorList{field.Duplicate(field.NewPath("spec").Child("ServerRef").Child("Name"), err)})
schema.GroupKind{Group: version.GroupVersionKind().Group, Kind: version.Kind},
version.GetName(), field.ErrorList{field.Duplicate(field.NewPath("spec").Child("serverRef").Child("name"), err)})
}
}
return nil, nil
Expand Down
Loading
Loading