Skip to content

Commit

Permalink
Create Machines from OOBs (#72)
Browse files Browse the repository at this point in the history
* Create Machines from OOBs

* Make tests reliable
  • Loading branch information
Gchbg authored May 14, 2024
1 parent dfcbaf0 commit 870c75b
Show file tree
Hide file tree
Showing 11 changed files with 338 additions and 175 deletions.
6 changes: 3 additions & 3 deletions Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,7 @@ manifests: ## Generate WebhookConfiguration, ClusterRole and CustomResourceDefin
@go run sigs.k8s.io/controller-tools/cmd/controller-gen rbac:roleName=manager-role crd webhook paths="./..." output:crd:artifacts:config=config/crd/bases

.PHONY: generate
generate: ## Generate code containing DeepCopy, DeepCopyInto, and DeepCopyObject method implementations.
generate: manifests fmt vet ## Generate code containing DeepCopy, DeepCopyInto, and DeepCopyObject method implementations.
@go run sigs.k8s.io/controller-tools/cmd/controller-gen object:headerFile=".reuse/boilerplate.go.txt" paths="./..."
@internal/tools/generate.sh

Expand All @@ -49,7 +49,7 @@ vet: ## Run go vet against code.
@go vet ./...

.PHONY: test
test: manifests generate fmt vet ## Run tests.
test: ## Run tests.
@go run github.com/onsi/ginkgo/v2/ginkgo -r --race --randomize-suites --keep-going --randomize-all --repeat=1

.PHONY: lint
Expand All @@ -67,7 +67,7 @@ checklicense: ## Check that every file has a license header present.
##@ Build

.PHONY: build
build: manifests generate fmt vet ## Build manager binary.
build: generate ## Build manager binary.
@go build -o metal cmd/main.go

.PHONY: docker-build
Expand Down
3 changes: 2 additions & 1 deletion api/v1alpha1/machine_types.go
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ type MachineSpec struct {

OOBRef v1.LocalObjectReference `json:"oobRef"`

// +optional
InventoryRef *v1.LocalObjectReference `json:"inventoryRef,omitempty"`

// +optional
Expand Down Expand Up @@ -116,7 +117,7 @@ const (
// +kubebuilder:object:root=true
// +kubebuilder:subresource:status
// +kubebuilder:resource:scope=Cluster
// +kubebuilder:printcolumn:name="UUID",type=string,JSONPath=`.status.uuid`
// +kubebuilder:printcolumn:name="UUID",type=string,JSONPath=`.spec.uuid`
// +kubebuilder:printcolumn:name="Manufacturer",type=string,JSONPath=`.status.manufacturer`
// +kubebuilder:printcolumn:name="SKU",type=string,JSONPath=`.status.sku`,priority=100
// +kubebuilder:printcolumn:name="SerialNumber",type=string,JSONPath=`.status.serialNumber`,priority=100
Expand Down
2 changes: 1 addition & 1 deletion config/crd/bases/metal.ironcore.dev_machines.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ spec:
scope: Cluster
versions:
- additionalPrinterColumns:
- jsonPath: .status.uuid
- jsonPath: .spec.uuid
name: UUID
type: string
- jsonPath: .status.manufacturer
Expand Down
7 changes: 1 addition & 6 deletions internal/bmc/fake.go
Original file line number Diff line number Diff line change
Expand Up @@ -83,19 +83,14 @@ func (b *FakeBMC) DeleteUsers(_ context.Context, _ *regexp.Regexp) error {
}

func (b *FakeBMC) ReadInfo(_ context.Context) (Info, error) {
id, err := uuid.NewRandom()
if err != nil {
return Info{}, fmt.Errorf("cannot generate UUID: %w", err)
}

return Info{
Type: TypeMachine,
Manufacturer: "Fake",
SerialNumber: "0",
FirmwareVersion: "1",
Machines: []Machine{
{
UUID: id.String(),
UUID: uuid.NewSHA1(uuid.NameSpaceOID, []byte("Fake")).String(),
Manufacturer: "Fake",
SKU: "Fake-0",
SerialNumber: "1",
Expand Down
16 changes: 14 additions & 2 deletions internal/controller/indexes.go
Original file line number Diff line number Diff line change
Expand Up @@ -15,16 +15,28 @@ import (

func CreateIndexes(ctx context.Context, mgr manager.Manager) error {
indexer := mgr.GetFieldIndexer()
var err error

err := indexer.IndexField(ctx, &metalv1alpha1.MachineClaim{}, MachineClaimSpecMachineRef, func(obj client.Object) []string {
err = indexer.IndexField(ctx, &metalv1alpha1.Machine{}, MachineSpecOOBRefName, func(obj client.Object) []string {
machine := obj.(*metalv1alpha1.Machine)
if machine.Spec.OOBRef.Name == "" {
return nil
}
return []string{machine.Spec.OOBRef.Name}
})
if err != nil {
return fmt.Errorf("cannot index field %s: %w", MachineSpecOOBRefName, err)
}

err = indexer.IndexField(ctx, &metalv1alpha1.MachineClaim{}, MachineClaimSpecMachineRefName, func(obj client.Object) []string {
claim := obj.(*metalv1alpha1.MachineClaim)
if claim.Spec.MachineRef == nil || claim.Spec.MachineRef.Name == "" {
return nil
}
return []string{claim.Spec.MachineRef.Name}
})
if err != nil {
return fmt.Errorf("cannot index field %s: %w", MachineClaimSpecMachineRef, err)
return fmt.Errorf("cannot index field %s: %w", MachineClaimSpecMachineRefName, err)
}

err = indexer.IndexField(ctx, &metalv1alpha1.OOB{}, OOBSpecMACAddress, func(obj client.Object) []string {
Expand Down
6 changes: 6 additions & 0 deletions internal/controller/machine_controller.go
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,12 @@ import (
// +kubebuilder:rbac:groups=metal.ironcore.dev,resources=machines/status,verbs=get;update;patch
// +kubebuilder:rbac:groups=metal.ironcore.dev,resources=machines/finalizers,verbs=update

const (
MachineFieldManager = "metal.ironcore.dev/machine"
MachineFinalizer = "metal.ironcore.dev/machine"
MachineSpecOOBRefName = ".spec.oobRef.Name"
)

func NewMachineReconciler() (*MachineReconciler, error) {
return &MachineReconciler{}, nil
}
Expand Down
10 changes: 6 additions & 4 deletions internal/controller/machineclaim_controller.go
Original file line number Diff line number Diff line change
Expand Up @@ -31,9 +31,9 @@ import (
// +kubebuilder:rbac:groups=metal.ironcore.dev,resources=machines/finalizers,verbs=update

const (
MachineClaimFieldManager = "metal.ironcore.dev/machineclaim"
MachineClaimFinalizer = "metal.ironcore.dev/machineclaim"
MachineClaimSpecMachineRef = ".spec.machineRef.Name"
MachineClaimFieldManager = "metal.ironcore.dev/machineclaim"
MachineClaimFinalizer = "metal.ironcore.dev/machineclaim"
MachineClaimSpecMachineRefName = ".spec.machineRef.Name"
)

func NewMachineClaimReconciler() (*MachineClaimReconciler, error) {
Expand Down Expand Up @@ -393,7 +393,9 @@ func (r *MachineClaimReconciler) enqueueMachineClaimsFromMachine(ctx context.Con
machine := obj.(*metalv1alpha1.Machine)

claimList := metalv1alpha1.MachineClaimList{}
err := r.List(ctx, &claimList, client.MatchingFields{MachineClaimSpecMachineRef: machine.Name})
err := r.List(ctx, &claimList, client.MatchingFields{
MachineClaimSpecMachineRefName: machine.Name,
})
if err != nil {
log.Error(ctx, fmt.Errorf("cannot list MachineClaims: %w", err))
return nil
Expand Down
60 changes: 33 additions & 27 deletions internal/controller/machineclaim_controller_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,12 +4,15 @@
package controller

import (
"time"

"github.com/google/uuid"
. "github.com/onsi/ginkgo/v2"
. "github.com/onsi/gomega"
v1 "k8s.io/api/core/v1"
"k8s.io/apimachinery/pkg/api/errors"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"sigs.k8s.io/controller-runtime/pkg/client"
. "sigs.k8s.io/controller-runtime/pkg/envtest/komega"

metalv1alpha1 "github.com/ironcore-dev/metal/api/v1alpha1"
Expand All @@ -25,7 +28,36 @@ var _ = Describe("MachineClaim Controller", Serial, func() {
},
}
Expect(k8sClient.Create(ctx, ns)).To(Succeed())
DeferCleanup(k8sClient.Delete, ns)
DeferCleanup(func(ctx SpecContext) {
Expect(k8sClient.Delete(ctx, ns)).To(Succeed())
})

Eventually(ObjectList(&metalv1alpha1.MachineList{})).Should(HaveField("Items", HaveLen(0)))
Eventually(ObjectList(&metalv1alpha1.MachineClaimList{}, &client.ListOptions{
Namespace: ns.Name,
})).Should(HaveField("Items", HaveLen(0)))

DeferCleanup(func(ctx SpecContext) {
Eventually(ctx, func(g Gomega, ctx SpecContext) {
var machines metalv1alpha1.MachineList
g.Expect(ObjectList(&machines)()).To(SatisfyAll())
if len(machines.Items) > 0 {
g.Expect(k8sClient.DeleteAllOf(ctx, &machines.Items[0])).To(Succeed())
}
var claims metalv1alpha1.MachineClaimList
g.Expect(ObjectList(&claims)()).To(SatisfyAll())
if len(claims.Items) > 0 {
g.Expect(k8sClient.DeleteAllOf(ctx, &claims.Items[0], &client.DeleteAllOfOptions{
ListOptions: client.ListOptions{
Namespace: ns.Name,
},
})).To(Succeed())
}

g.Expect(ObjectList(&machines)()).To(HaveField("Items", BeEmpty()))
g.Expect(ObjectList(&claims)()).To(HaveField("Items", BeEmpty()))
}, time.Second*3).Should(Succeed())
})
})

It("should claim a Machine by ref", func(ctx SpecContext) {
Expand All @@ -42,10 +74,6 @@ var _ = Describe("MachineClaim Controller", Serial, func() {
},
}
Expect(k8sClient.Create(ctx, machine)).To(Succeed())
DeferCleanup(func(ctx SpecContext) {
Expect(k8sClient.Delete(ctx, machine)).To(Succeed())
Eventually(Get(machine)).Should(Satisfy(errors.IsNotFound))
})

By("Patching Machine state to Ready")
Eventually(UpdateStatus(machine, func() {
Expand Down Expand Up @@ -112,10 +140,6 @@ var _ = Describe("MachineClaim Controller", Serial, func() {
},
}
Expect(k8sClient.Create(ctx, machine)).To(Succeed())
DeferCleanup(func(ctx SpecContext) {
Expect(k8sClient.Delete(ctx, machine)).To(Succeed())
Eventually(Get(machine)).Should(Satisfy(errors.IsNotFound))
})

By("Patching Machine state to Ready")
Eventually(UpdateStatus(machine, func() {
Expand Down Expand Up @@ -190,12 +214,6 @@ var _ = Describe("MachineClaim Controller", Serial, func() {
HaveField("Finalizers", ContainElement(MachineClaimFinalizer)),
HaveField("Status.Phase", metalv1alpha1.MachineClaimPhaseUnbound),
))

By("Deleting the MachineClaim")
Expect(k8sClient.Delete(ctx, claim)).To(Succeed())

By("Expecting MachineClaim to be removed")
Eventually(Get(claim)).Should(Satisfy(errors.IsNotFound))
})

It("should not claim a Machine with no matching selector", func(ctx SpecContext) {
Expand All @@ -215,10 +233,6 @@ var _ = Describe("MachineClaim Controller", Serial, func() {
},
}
Expect(k8sClient.Create(ctx, machine)).To(Succeed())
DeferCleanup(func(ctx SpecContext) {
Expect(k8sClient.Delete(ctx, machine)).To(Succeed())
Eventually(Get(machine)).Should(Satisfy(errors.IsNotFound))
})

By("Patching Machine state to Ready")
Eventually(UpdateStatus(machine, func() {
Expand Down Expand Up @@ -276,10 +290,6 @@ var _ = Describe("MachineClaim Controller", Serial, func() {
},
}
Expect(k8sClient.Create(ctx, machine)).To(Succeed())
DeferCleanup(func(ctx SpecContext) {
Expect(k8sClient.Delete(ctx, machine)).To(Succeed())
Eventually(Get(machine)).Should(Satisfy(errors.IsNotFound))
})

By("Patching Machine state to Error")
Eventually(UpdateStatus(machine, func() {
Expand All @@ -301,10 +311,6 @@ var _ = Describe("MachineClaim Controller", Serial, func() {
},
}
Expect(k8sClient.Create(ctx, claim)).To(Succeed())
DeferCleanup(func(ctx SpecContext) {
Expect(k8sClient.Delete(ctx, claim)).To(Succeed())
Eventually(Get(claim)).Should(Satisfy(errors.IsNotFound))
})

By("Expecting finalizer and phase to be correct on the MachineClaim")
Eventually(Object(claim)).Should(SatisfyAll(
Expand Down
Loading

0 comments on commit 870c75b

Please sign in to comment.