Skip to content

Commit d69b7cc

Browse files
Add bootOptions to TinkerbellMachine spec:
Also, update to latest Workflow spec. This latest spec will handle network and iso booting. It will also toggle the allowPXE field in the Hardware object. Remove using the allowPXE field to track if Hardware is ready. Hardware is ready when the workflow is successful and/or the Hardware has label "v1alpha1.tinkerbell.org/inUse" equal to true. Signed-off-by: Jacob Weinstock <[email protected]>
1 parent af96332 commit d69b7cc

12 files changed

+146
-286
lines changed

api/v1beta1/tinkerbellmachine_types.go

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,9 @@ const (
2828
MachineFinalizer = "tinkerbellmachine.infrastructure.cluster.x-k8s.io"
2929
)
3030

31+
// BootMode defines the type of booting that will be done. i.e. netboot, iso, etc.
32+
type BootMode string
33+
3134
// TinkerbellMachineSpec defines the desired state of TinkerbellMachine.
3235
type TinkerbellMachineSpec struct {
3336
// ImageLookupFormat is the URL naming format to use for machine images when
@@ -69,12 +72,32 @@ type TinkerbellMachineSpec struct {
6972
// +optional
7073
HardwareAffinity *HardwareAffinity `json:"hardwareAffinity,omitempty"`
7174

75+
// BootOptions are options that control the booting of Hardware.
76+
// +optional
77+
BootOptions BootOptions `json:"bootOptions,omitempty"`
78+
7279
// Those fields are set programmatically, but they cannot be re-constructed from "state of the world", so
7380
// we put them in spec instead of status.
7481
HardwareName string `json:"hardwareName,omitempty"`
7582
ProviderID string `json:"providerID,omitempty"`
7683
}
7784

85+
// BootOptions are options that control the booting of Hardware.
86+
type BootOptions struct {
87+
// ISOURL is the URL of the ISO that will be one-time booted.
88+
// When this field is set, the controller will create a job.bmc.tinkerbell.org object
89+
// for getting the associated hardware into a CDROM booting state.
90+
// A HardwareRef that contains a spec.BmcRef must be provided.
91+
// +optional
92+
// +kubebuilder:validation:Format=url
93+
ISOURL string `json:"isoURL,omitempty"`
94+
95+
// BootMode is the type of booting that will be done.
96+
// +optional
97+
// +kubebuilder:validation:Enum=none;netboot;iso
98+
BootMode BootMode `json:"bootMode,omitempty"`
99+
}
100+
78101
// HardwareAffinity defines the required and preferred hardware affinities.
79102
type HardwareAffinity struct {
80103
// Required are the required hardware affinity terms. The terms are OR'd together, hardware must match one term to

api/v1beta1/zz_generated.deepcopy.go

Lines changed: 16 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

config/crd/bases/infrastructure.cluster.x-k8s.io_tinkerbellmachines.yaml

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -62,6 +62,25 @@ spec:
6262
spec:
6363
description: TinkerbellMachineSpec defines the desired state of TinkerbellMachine.
6464
properties:
65+
bootOptions:
66+
description: BootOptions are options that control the booting of Hardware.
67+
properties:
68+
bootMode:
69+
description: BootMode is the type of booting that will be done.
70+
enum:
71+
- none
72+
- netboot
73+
- iso
74+
type: string
75+
isoURL:
76+
description: |-
77+
ISOURL is the URL of the ISO that will be one-time booted.
78+
When this field is set, the controller will create a job.bmc.tinkerbell.org object
79+
for getting the associated hardware into a CDROM booting state.
80+
A HardwareRef that contains a spec.BmcRef must be provided.
81+
format: url
82+
type: string
83+
type: object
6584
hardwareAffinity:
6685
description: HardwareAffinity allows filtering for hardware.
6786
properties:

config/crd/bases/infrastructure.cluster.x-k8s.io_tinkerbellmachinetemplates.yaml

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -51,6 +51,27 @@ spec:
5151
description: Spec is the specification of the desired behavior
5252
of the machine.
5353
properties:
54+
bootOptions:
55+
description: BootOptions are options that control the booting
56+
of Hardware.
57+
properties:
58+
bootMode:
59+
description: BootMode is the type of booting that will
60+
be done.
61+
enum:
62+
- none
63+
- netboot
64+
- iso
65+
type: string
66+
isoURL:
67+
description: |-
68+
ISOURL is the URL of the ISO that will be one-time booted.
69+
When this field is set, the controller will create a job.bmc.tinkerbell.org object
70+
for getting the associated hardware into a CDROM booting state.
71+
A HardwareRef that contains a spec.BmcRef must be provided.
72+
format: url
73+
type: string
74+
type: object
5475
hardwareAffinity:
5576
description: HardwareAffinity allows filtering for hardware.
5677
properties:

controller/machine/bmc.go

Lines changed: 0 additions & 96 deletions
Original file line numberDiff line numberDiff line change
@@ -10,102 +10,6 @@ import (
1010
"k8s.io/apimachinery/pkg/types"
1111
)
1212

13-
// ensureHardwareProvisionJob ensures the hardware is ready to be provisioned.
14-
// Uses the BMCRef from the hardware to create a BMCJob.
15-
// The BMCJob is responsible for getting the machine to desired state for provisioning.
16-
// If a BMCJob is already found and has failed, we error.
17-
func (scope *machineReconcileScope) ensureHardwareProvisionJob(hw *tinkv1.Hardware) error {
18-
if hw.Spec.BMCRef == nil {
19-
scope.log.Info("Hardware BMC reference not present; skipping BMCJob creation",
20-
"BMCRef", hw.Spec.BMCRef, "Hardware", hw.Name)
21-
22-
return nil
23-
}
24-
25-
bmcJob := &rufiov1.Job{}
26-
jobName := fmt.Sprintf("%s-provision", scope.tinkerbellMachine.Name)
27-
28-
err := scope.getBMCJob(jobName, bmcJob)
29-
if err != nil {
30-
if apierrors.IsNotFound(err) {
31-
// Create a BMCJob for hardware provisioning
32-
return scope.createHardwareProvisionJob(hw, jobName)
33-
}
34-
35-
return err
36-
}
37-
38-
if bmcJob.HasCondition(rufiov1.JobFailed, rufiov1.ConditionTrue) {
39-
return fmt.Errorf("bmc job %s/%s failed", bmcJob.Namespace, bmcJob.Name) //nolint:goerr113
40-
}
41-
42-
return nil
43-
}
44-
45-
// getBMCJob fetches the BMCJob with name JName.
46-
func (scope *machineReconcileScope) getBMCJob(jName string, bmj *rufiov1.Job) error {
47-
namespacedName := types.NamespacedName{
48-
Name: jName,
49-
Namespace: scope.tinkerbellMachine.Namespace,
50-
}
51-
52-
if err := scope.client.Get(scope.ctx, namespacedName, bmj); err != nil {
53-
return fmt.Errorf("GET BMCJob: %w", err)
54-
}
55-
56-
return nil
57-
}
58-
59-
// createHardwareProvisionJob creates a BMCJob object with the required tasks for hardware provisioning.
60-
func (scope *machineReconcileScope) createHardwareProvisionJob(hw *tinkv1.Hardware, name string) error {
61-
job := &rufiov1.Job{
62-
ObjectMeta: metav1.ObjectMeta{
63-
Name: name,
64-
Namespace: scope.tinkerbellMachine.Namespace,
65-
OwnerReferences: []metav1.OwnerReference{
66-
{
67-
APIVersion: "infrastructure.cluster.x-k8s.io/v1beta1",
68-
Kind: "TinkerbellMachine",
69-
Name: scope.tinkerbellMachine.Name,
70-
UID: scope.tinkerbellMachine.ObjectMeta.UID,
71-
},
72-
},
73-
},
74-
Spec: rufiov1.JobSpec{
75-
MachineRef: rufiov1.MachineRef{
76-
Name: hw.Spec.BMCRef.Name,
77-
Namespace: scope.tinkerbellMachine.Namespace,
78-
},
79-
Tasks: []rufiov1.Action{
80-
{
81-
PowerAction: rufiov1.PowerHardOff.Ptr(),
82-
},
83-
{
84-
OneTimeBootDeviceAction: &rufiov1.OneTimeBootDeviceAction{
85-
Devices: []rufiov1.BootDevice{
86-
rufiov1.PXE,
87-
},
88-
EFIBoot: hw.Spec.Interfaces[0].DHCP.UEFI,
89-
},
90-
},
91-
{
92-
PowerAction: rufiov1.PowerOn.Ptr(),
93-
},
94-
},
95-
},
96-
}
97-
98-
if err := scope.client.Create(scope.ctx, job); err != nil {
99-
return fmt.Errorf("creating job: %w", err)
100-
}
101-
102-
scope.log.Info("Created BMCJob to get hardware ready for provisioning",
103-
"Name", job.Name,
104-
"Namespace", job.Namespace)
105-
106-
return nil
107-
}
108-
10913
// createPowerOffJob creates a BMCJob object with the required tasks for hardware power off.
11014
func (scope *machineReconcileScope) createPowerOffJob(hw *tinkv1.Hardware) error {
11115
controller := true

controller/machine/hardware.go

Lines changed: 18 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,6 @@ import (
99
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
1010
"k8s.io/apimachinery/pkg/labels"
1111
"k8s.io/apimachinery/pkg/types"
12-
"k8s.io/utils/ptr"
1312
"sigs.k8s.io/cluster-api/util/patch"
1413
"sigs.k8s.io/controller-runtime/pkg/client"
1514
"sigs.k8s.io/controller-runtime/pkg/controller/controllerutil"
@@ -25,6 +24,9 @@ const (
2524
// HardwareOwnerNamespaceLabel is a label set by either CAPT controllers or Tinkerbell controller to indicate
2625
// that given hardware takes part of at least one workflow.
2726
HardwareOwnerNamespaceLabel = "v1alpha1.tinkerbell.org/ownerNamespace"
27+
28+
// HardwareInUseLabel signifies that the Hardware with this label has be provisioned by CAPT.
29+
HardwareInUseLabel = "v1alpha1.tinkerbell.org/inUse"
2830
)
2931

3032
var (
@@ -71,34 +73,15 @@ func hardwareIP(hardware *tinkv1.Hardware) (string, error) {
7173
return hardware.Spec.Interfaces[0].DHCP.IP.Address, nil
7274
}
7375

74-
func isHardwareReady(hw *tinkv1.Hardware) bool {
75-
// if allowpxe false for all interface, hardware ready
76-
if len(hw.Spec.Interfaces) == 0 {
77-
return false
78-
}
79-
80-
for _, ifc := range hw.Spec.Interfaces {
81-
if ifc.Netboot != nil {
82-
if *ifc.Netboot.AllowPXE {
83-
return false
84-
}
85-
}
86-
}
87-
88-
return true
89-
}
90-
9176
// patchHardwareStates patches a hardware's metadata and instance states.
92-
func (scope *machineReconcileScope) patchHardwareStates(hw *tinkv1.Hardware, allowpxe bool) error {
77+
func (scope *machineReconcileScope) patchHardwareLabel(hw *tinkv1.Hardware, labels map[string]string) error {
9378
patchHelper, err := patch.NewHelper(hw, scope.client)
9479
if err != nil {
9580
return fmt.Errorf("initializing patch helper for selected hardware: %w", err)
9681
}
9782

98-
for _, ifc := range hw.Spec.Interfaces {
99-
if ifc.Netboot != nil {
100-
ifc.Netboot.AllowPXE = ptr.To(allowpxe)
101-
}
83+
for k, v := range labels {
84+
hw.ObjectMeta.Labels[k] = v
10285
}
10386

10487
if err := patchHelper.Patch(scope.ctx, hw); err != nil {
@@ -291,16 +274,19 @@ func (scope *machineReconcileScope) releaseHardware(hw *tinkv1.Hardware) error {
291274

292275
delete(hw.ObjectMeta.Labels, HardwareOwnerNameLabel)
293276
delete(hw.ObjectMeta.Labels, HardwareOwnerNamespaceLabel)
294-
// setting the AllowPXE=true indicates to Smee that this hardware should be allowed
295-
// to netboot. FYI, this is not authoritative.
296-
// Other hardware values can be set to prohibit netbooting of a machine.
297-
// See this Boots function for the logic around this:
298-
// https://github.com/tinkerbell/smee/blob/main/internal/ipxe/script/ipxe.go#L112
299-
for _, ifc := range hw.Spec.Interfaces {
300-
if ifc.Netboot != nil {
301-
ifc.Netboot.AllowPXE = ptr.To(true)
277+
delete(hw.ObjectMeta.Labels, HardwareInUseLabel)
278+
/*
279+
// setting the AllowPXE=true indicates to Smee that this hardware should be allowed
280+
// to netboot. FYI, this is not authoritative.
281+
// Other hardware values can be set to prohibit netbooting of a machine.
282+
// See this Boots function for the logic around this:
283+
// https://github.com/tinkerbell/smee/blob/main/internal/ipxe/script/ipxe.go#L112
284+
for _, ifc := range hw.Spec.Interfaces {
285+
if ifc.Netboot != nil {
286+
ifc.Netboot.AllowPXE = ptr.To(true)
287+
}
302288
}
303-
}
289+
*/
304290

305291
controllerutil.RemoveFinalizer(hw, infrastructurev1.MachineFinalizer)
306292

controller/machine/scope.go

Lines changed: 7 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -126,15 +126,10 @@ func (scope *machineReconcileScope) Reconcile() error {
126126
}
127127

128128
func (scope *machineReconcileScope) reconcile(hw *tinkv1.Hardware) error {
129-
if isHardwareReady(hw) {
129+
// If the workflow has completed the TinkerbellMachine is ready.
130+
if v, found := hw.ObjectMeta.Labels[HardwareInUseLabel]; found && v == "true" {
130131
scope.log.Info("Marking TinkerbellMachine as Ready")
131132
scope.tinkerbellMachine.Status.Ready = true
132-
133-
return nil
134-
}
135-
136-
if ensureJobErr := scope.ensureHardwareProvisionJob(hw); ensureJobErr != nil {
137-
return fmt.Errorf("failed to ensure hardware ready for provisioning: %w", ensureJobErr)
138133
}
139134

140135
wf, err := scope.ensureTemplateAndWorkflow(hw)
@@ -151,17 +146,17 @@ func (scope *machineReconcileScope) reconcile(hw *tinkv1.Hardware) error {
151146
return errWorkflowFailed
152147
}
153148

154-
if !lastActionStarted(wf) {
149+
if wf.Status.State != tinkv1.WorkflowStateSuccess {
155150
return nil
156151
}
157152

158-
if err := scope.patchHardwareStates(hw, false); err != nil {
159-
return fmt.Errorf("failed to patch hardware: %w", err)
160-
}
161-
162153
scope.log.Info("Marking TinkerbellMachine as Ready")
163154
scope.tinkerbellMachine.Status.Ready = true
164155

156+
if err := scope.patchHardwareLabel(hw, map[string]string{HardwareInUseLabel: "true"}); err != nil {
157+
return fmt.Errorf("failed to patch hardware: %w", err)
158+
}
159+
165160
return nil
166161
}
167162

controller/machine/tinkerbellmachine.go

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -68,6 +68,7 @@ func (r *TinkerbellMachineReconciler) Reconcile(ctx context.Context, req ctrl.Re
6868
}
6969

7070
log := ctrl.LoggerFrom(ctx)
71+
log.Info("starting reconcile")
7172

7273
scope := &machineReconcileScope{
7374
log: log,

0 commit comments

Comments
 (0)