Skip to content

Commit

Permalink
update elfMachine webhook
Browse files Browse the repository at this point in the history
  • Loading branch information
huaqing1994 committed Nov 11, 2024
1 parent ef10b41 commit a90f67d
Show file tree
Hide file tree
Showing 2 changed files with 198 additions and 1 deletion.
43 changes: 42 additions & 1 deletion webhooks/elfmachine_webhook_validation.go
Original file line number Diff line number Diff line change
Expand Up @@ -29,11 +29,17 @@ import (
"sigs.k8s.io/controller-runtime/pkg/webhook/admission"

infrav1 "github.com/smartxworks/cluster-api-provider-elf/api/v1beta1"
annotationsutil "github.com/smartxworks/cluster-api-provider-elf/pkg/util/annotations"
)

// Error messages.
const (
diskCapacityCanOnlyBeExpandedMsg = "the disk capacity can only be expanded"
canOnlyModifiedThroughElfMachineTemplate = "virtual machine resources should be the same as ElfMachineTemplate %s"

diskCapacityCanOnlyBeExpandedMsg = "the disk capacity can only be expanded"
vcpuCapacityCanOnlyBeExpandedMsg = "the vcpu capacity can only be expanded"
memoryCapacityCanOnlyBeExpandedMsg = "the memory capacity can only be expanded"
numCoresPerSocketCannotBeChanged = "the number of cores per socket cannot be changed"
)

func (v *ElfMachineValidator) SetupWebhookWithManager(mgr ctrl.Manager) error {
Expand Down Expand Up @@ -70,9 +76,44 @@ func (v *ElfMachineValidator) ValidateUpdate(ctx goctx.Context, oldObj, newObj r

var allErrs field.ErrorList

elfMachineTemplateName := annotationsutil.GetTemplateClonedFromName(elfMachine)
if elfMachineTemplateName != "" {
// If the ElfMachine was created using ElfMachineTemplate. ElfMachine's
// resources should be the same as this ElfMachineTemplate.
var elfMachineTemplate infrav1.ElfMachineTemplate
if err := v.Client.Get(ctx, client.ObjectKey{
Namespace: elfMachine.Namespace,
Name: annotationsutil.GetTemplateClonedFromName(elfMachine),
}, &elfMachineTemplate); err != nil {
return nil, apierrors.NewInternalError(err)
}

if elfMachine.Spec.DiskGiB != elfMachineTemplate.Spec.Template.Spec.DiskGiB {
allErrs = append(allErrs, field.Invalid(field.NewPath("spec", "diskGiB"), elfMachine.Spec.DiskGiB, fmt.Sprintf(canOnlyModifiedThroughElfMachineTemplate, elfMachineTemplateName)))
}
if elfMachine.Spec.NumCPUs != elfMachineTemplate.Spec.Template.Spec.NumCPUs {
allErrs = append(allErrs, field.Invalid(field.NewPath("spec", "numCPUs"), elfMachine.Spec.NumCPUs, fmt.Sprintf(canOnlyModifiedThroughElfMachineTemplate, elfMachineTemplateName)))
}
if elfMachine.Spec.NumCoresPerSocket != elfMachineTemplate.Spec.Template.Spec.NumCoresPerSocket {
allErrs = append(allErrs, field.Invalid(field.NewPath("spec", "numCoresPerSocket"), elfMachine.Spec.NumCoresPerSocket, fmt.Sprintf(canOnlyModifiedThroughElfMachineTemplate, elfMachineTemplateName)))
}
if elfMachine.Spec.MemoryMiB != elfMachineTemplate.Spec.Template.Spec.MemoryMiB {
allErrs = append(allErrs, field.Invalid(field.NewPath("spec", "memoryMiB"), elfMachine.Spec.MemoryMiB, fmt.Sprintf(canOnlyModifiedThroughElfMachineTemplate, elfMachineTemplateName)))
}
}

if elfMachine.Spec.DiskGiB < oldElfMachine.Spec.DiskGiB {
allErrs = append(allErrs, field.Invalid(field.NewPath("spec", "diskGiB"), elfMachine.Spec.DiskGiB, diskCapacityCanOnlyBeExpandedMsg))
}
if elfMachine.Spec.NumCPUs < oldElfMachine.Spec.NumCPUs {
allErrs = append(allErrs, field.Invalid(field.NewPath("spec", "numCPUs"), elfMachine.Spec.NumCPUs, vcpuCapacityCanOnlyBeExpandedMsg))
}
if elfMachine.Spec.MemoryMiB < oldElfMachine.Spec.MemoryMiB {
allErrs = append(allErrs, field.Invalid(field.NewPath("spec", "memoryMiB"), elfMachine.Spec.MemoryMiB, memoryCapacityCanOnlyBeExpandedMsg))
}
if oldElfMachine.Spec.NumCoresPerSocket != 0 && elfMachine.Spec.NumCoresPerSocket != oldElfMachine.Spec.NumCoresPerSocket {
allErrs = append(allErrs, field.Invalid(field.NewPath("spec", "numCoresPerSocket"), elfMachine.Spec.NumCoresPerSocket, numCoresPerSocketCannotBeChanged))
}

return nil, aggregateObjErrors(elfMachine.GroupVersionKind().GroupKind(), elfMachine.Name, allErrs)
}
Expand Down
156 changes: 156 additions & 0 deletions webhooks/elfmachine_webhook_validation_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -18,13 +18,15 @@ package webhooks

import (
goctx "context"
"fmt"
"testing"

. "github.com/onsi/gomega"
apierrors "k8s.io/apimachinery/pkg/api/errors"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/apimachinery/pkg/runtime"
"k8s.io/apimachinery/pkg/util/validation/field"
clusterv1 "sigs.k8s.io/cluster-api/api/v1beta1"
"sigs.k8s.io/controller-runtime/pkg/client"
"sigs.k8s.io/controller-runtime/pkg/client/fake"

Expand All @@ -37,6 +39,19 @@ func TestElfMachineValidatorValidateUpdate(t *testing.T) {
var tests []elfMachineTestCase
scheme := newScheme(g)

elfMachineTemplate := &infrav1.ElfMachineTemplate{
ObjectMeta: metav1.ObjectMeta{Name: "test"},
Spec: infrav1.ElfMachineTemplateSpec{
Template: infrav1.ElfMachineTemplateResource{
Spec: infrav1.ElfMachineSpec{
DiskGiB: 1,
NumCPUs: 1,
MemoryMiB: 1,
},
},
},
}

tests = append(tests, elfMachineTestCase{
Name: "Cannot reduce disk capacity",
OldEM: &infrav1.ElfMachine{
Expand All @@ -53,6 +68,147 @@ func TestElfMachineValidatorValidateUpdate(t *testing.T) {
field.Invalid(field.NewPath("spec", "diskGiB"), 1, diskCapacityCanOnlyBeExpandedMsg),
},
})
tests = append(tests, elfMachineTestCase{
Name: "Cannot reduce vcpu capacity",
OldEM: &infrav1.ElfMachine{
Spec: infrav1.ElfMachineSpec{
NumCPUs: 2,
},
},
EM: &infrav1.ElfMachine{
Spec: infrav1.ElfMachineSpec{
NumCPUs: 1,
},
},
Errs: field.ErrorList{
field.Invalid(field.NewPath("spec", "numCPUs"), 1, vcpuCapacityCanOnlyBeExpandedMsg),
},
})
tests = append(tests, elfMachineTestCase{
Name: "Cannot reduce memory capacity",
OldEM: &infrav1.ElfMachine{
Spec: infrav1.ElfMachineSpec{
MemoryMiB: 2,
},
},
EM: &infrav1.ElfMachine{
Spec: infrav1.ElfMachineSpec{
MemoryMiB: 1,
},
},
Errs: field.ErrorList{
field.Invalid(field.NewPath("spec", "memoryMiB"), 1, memoryCapacityCanOnlyBeExpandedMsg),
},
})
tests = append(tests, elfMachineTestCase{
Name: "Can update the default numCoresPerSocket",
OldEM: &infrav1.ElfMachine{
Spec: infrav1.ElfMachineSpec{
NumCoresPerSocket: 0,
},
},
EM: &infrav1.ElfMachine{
Spec: infrav1.ElfMachineSpec{
NumCoresPerSocket: 1,
},
},
Errs: nil,
})
tests = append(tests, elfMachineTestCase{
Name: "Cannot update numCoresPerSocket",
OldEM: &infrav1.ElfMachine{
Spec: infrav1.ElfMachineSpec{
NumCoresPerSocket: 1,
},
},
EM: &infrav1.ElfMachine{
Spec: infrav1.ElfMachineSpec{
NumCoresPerSocket: 2,
},
},
Errs: field.ErrorList{
field.Invalid(field.NewPath("spec", "numCoresPerSocket"), 2, numCoresPerSocketCannotBeChanged),
},
})

tests = append(tests, elfMachineTestCase{
Name: "Disk cannot be modified directly",
OldEM: &infrav1.ElfMachine{
Spec: infrav1.ElfMachineSpec{
DiskGiB: 1,
NumCPUs: 1,
MemoryMiB: 1,
},
},
EM: &infrav1.ElfMachine{
ObjectMeta: metav1.ObjectMeta{
Annotations: map[string]string{
clusterv1.TemplateClonedFromNameAnnotation: elfMachineTemplate.Name,
},
},
Spec: infrav1.ElfMachineSpec{
DiskGiB: 2,
NumCPUs: 1,
MemoryMiB: 1,
},
},
Objs: []client.Object{elfMachineTemplate},
Errs: field.ErrorList{
field.Invalid(field.NewPath("spec", "diskGiB"), 2, fmt.Sprintf(canOnlyModifiedThroughElfMachineTemplate, elfMachineTemplate.Name)),
},
})
tests = append(tests, elfMachineTestCase{
Name: "vcpu cannot be modified directly",
OldEM: &infrav1.ElfMachine{
Spec: infrav1.ElfMachineSpec{
DiskGiB: 1,
NumCPUs: 1,
MemoryMiB: 1,
},
},
EM: &infrav1.ElfMachine{
ObjectMeta: metav1.ObjectMeta{
Annotations: map[string]string{
clusterv1.TemplateClonedFromNameAnnotation: elfMachineTemplate.Name,
},
},
Spec: infrav1.ElfMachineSpec{
DiskGiB: 1,
NumCPUs: 2,
MemoryMiB: 1,
},
},
Objs: []client.Object{elfMachineTemplate},
Errs: field.ErrorList{
field.Invalid(field.NewPath("spec", "numCPUs"), 2, fmt.Sprintf(canOnlyModifiedThroughElfMachineTemplate, elfMachineTemplate.Name)),
},
})
tests = append(tests, elfMachineTestCase{
Name: "memory cannot be modified directly",
OldEM: &infrav1.ElfMachine{
Spec: infrav1.ElfMachineSpec{
DiskGiB: 1,
NumCPUs: 1,
MemoryMiB: 1,
},
},
EM: &infrav1.ElfMachine{
ObjectMeta: metav1.ObjectMeta{
Annotations: map[string]string{
clusterv1.TemplateClonedFromNameAnnotation: elfMachineTemplate.Name,
},
},
Spec: infrav1.ElfMachineSpec{
DiskGiB: 1,
NumCPUs: 1,
MemoryMiB: 2,
},
},
Objs: []client.Object{elfMachineTemplate},
Errs: field.ErrorList{
field.Invalid(field.NewPath("spec", "memoryMiB"), 2, fmt.Sprintf(canOnlyModifiedThroughElfMachineTemplate, elfMachineTemplate.Name)),
},
})

for _, tc := range tests {
t.Run(tc.Name, func(t *testing.T) {
Expand Down

0 comments on commit a90f67d

Please sign in to comment.