Skip to content

Commit

Permalink
Restart deployment when forced reboot is requested
Browse files Browse the repository at this point in the history
The only way to do it is to go through cleaning.
  • Loading branch information
dtantsur committed Mar 24, 2023
1 parent cb80760 commit d1e306b
Show file tree
Hide file tree
Showing 8 changed files with 39 additions and 14 deletions.
16 changes: 9 additions & 7 deletions controllers/metal3.io/baremetalhost_controller.go
Original file line number Diff line number Diff line change
Expand Up @@ -1138,12 +1138,7 @@ func (r *BareMetalHostReconciler) actionProvisioning(prov provisioner.Provisione
info.host.HardwareProfile()))}
}

if clearRebootAnnotations(info.host) {
if err := r.Update(context.TODO(), info.host); err != nil {
return actionError{errors.Wrap(err, "failed to remove reboot annotations from host")}
}
return actionContinue{}
}
_, _, forceReboot := hasRebootAnnotation(info)

var image metal3v1alpha1.Image
if info.host.Spec.Image != nil {
Expand All @@ -1157,7 +1152,7 @@ func (r *BareMetalHostReconciler) actionProvisioning(prov provisioner.Provisione
BootMode: info.host.Status.Provisioning.BootMode,
HardwareProfile: hwProf,
RootDeviceHints: info.host.Status.Provisioning.RootDeviceHints.DeepCopy(),
})
}, forceReboot)
if err != nil {
return actionError{errors.Wrap(err, "failed to provision")}
}
Expand Down Expand Up @@ -1189,6 +1184,13 @@ func (r *BareMetalHostReconciler) actionProvisioning(prov provisioner.Provisione
info.host.Status.Provisioning.CustomDeploy = info.host.Spec.CustomDeploy.DeepCopy()
}

if clearRebootAnnotations(info.host) {
if err := r.Update(context.TODO(), info.host); err != nil {
return actionError{errors.Wrap(err, "failed to remove reboot annotations from host")}
}
return actionContinue{}
}

// After provisioning we always requeue to ensure we enter the
// "provisioned" state and start monitoring power status.
return actionComplete{}
Expand Down
2 changes: 1 addition & 1 deletion controllers/metal3.io/host_state_machine_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -1338,7 +1338,7 @@ func (m *mockProvisioner) Adopt(data provisioner.AdoptData, force bool) (result
return m.getNextResultByMethod("Adopt"), err
}

func (m *mockProvisioner) Provision(data provisioner.ProvisionData) (result provisioner.Result, err error) {
func (m *mockProvisioner) Provision(data provisioner.ProvisionData, forceReboot bool) (result provisioner.Result, err error) {
return m.getNextResultByMethod("Provision"), err
}

Expand Down
2 changes: 1 addition & 1 deletion controllers/metal3.io/hostfirmwaresettings_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -83,7 +83,7 @@ func (m *hsfMockProvisioner) Adopt(data provisioner.AdoptData, force bool) (resu
return
}

func (m *hsfMockProvisioner) Provision(data provisioner.ProvisionData) (result provisioner.Result, err error) {
func (m *hsfMockProvisioner) Provision(data provisioner.ProvisionData, forceReboot bool) (result provisioner.Result, err error) {
return
}

Expand Down
2 changes: 1 addition & 1 deletion pkg/provisioner/demo/demo.go
Original file line number Diff line number Diff line change
Expand Up @@ -227,7 +227,7 @@ func (p *demoProvisioner) Adopt(data provisioner.AdoptData, force bool) (result
// Provision writes the image from the host spec to the host. It may
// be called multiple times, and should return true for its dirty flag
// until the provisioning operation is completed.
func (p *demoProvisioner) Provision(data provisioner.ProvisionData) (result provisioner.Result, err error) {
func (p *demoProvisioner) Provision(data provisioner.ProvisionData, forceReboot bool) (result provisioner.Result, err error) {

hostName := p.objectMeta.Name
p.log.Info("provisioning image to host")
Expand Down
2 changes: 1 addition & 1 deletion pkg/provisioner/fixture/fixture.go
Original file line number Diff line number Diff line change
Expand Up @@ -212,7 +212,7 @@ func (p *fixtureProvisioner) Adopt(data provisioner.AdoptData, force bool) (resu
// Provision writes the image from the host spec to the host. It may
// be called multiple times, and should return true for its dirty flag
// until the provisioning operation is completed.
func (p *fixtureProvisioner) Provision(data provisioner.ProvisionData) (result provisioner.Result, err error) {
func (p *fixtureProvisioner) Provision(data provisioner.ProvisionData, forceReboot bool) (result provisioner.Result, err error) {
p.log.Info("provisioning image to host")

if data.CustomDeploy != nil && p.state.customDeploy == nil {
Expand Down
14 changes: 13 additions & 1 deletion pkg/provisioner/ironic/ironic.go
Original file line number Diff line number Diff line change
Expand Up @@ -1523,7 +1523,7 @@ func (p *ironicProvisioner) getCustomDeploySteps(customDeploy *metal3v1alpha1.Cu
// Provision writes the image from the host spec to the host. It may
// be called multiple times, and should return true for its dirty flag
// until the provisioning operation is completed.
func (p *ironicProvisioner) Provision(data provisioner.ProvisionData) (result provisioner.Result, err error) {
func (p *ironicProvisioner) Provision(data provisioner.ProvisionData, forceReboot bool) (result provisioner.Result, err error) {
ironicNode, err := p.getNode()
if err != nil {
return transientError(err)
Expand Down Expand Up @@ -1616,6 +1616,18 @@ func (p *ironicProvisioner) Provision(data provisioner.ProvisionData) (result pr
p.log.Info("finished provisioning")
return operationComplete()

case nodes.DeployWait:
if forceReboot {
p.log.Info("aborting provisioning to update the image")
_, result, err = p.tryChangeNodeProvisionState(
ironicNode,
nodes.ProvisionStateOpts{Target: nodes.TargetDeleted},
)
return
}

fallthrough

default:
// wait states like cleaning and clean wait
p.log.Info("waiting for host to become available",
Expand Down
13 changes: 12 additions & 1 deletion pkg/provisioner/ironic/provision_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -123,6 +123,17 @@ func TestProvision(t *testing.T) {
expectedRequestAfter: 10,
expectedDirty: true,
},
{
name: "forceReboot: Deploy Wait",
ironic: testserver.NewIronic(t).WithDefaultResponses().Node(nodes.Node{
ProvisionState: string(nodes.DeployWait),
UUID: nodeUUID,
}),
forceReboot: true,
expectedRequestAfter: 10,
expectedDirty: true,
expectedProvisionState: nodes.TargetDeleted,
},
{
name: "fault state",
ironic: testserver.NewIronic(t).WithDefaultResponses().Node(nodes.Node{
Expand Down Expand Up @@ -176,7 +187,7 @@ func TestProvision(t *testing.T) {
Image: testImage,
HostConfig: fixture.NewHostConfigData("testUserData", "test: NetworkData", "test: Meta"),
BootMode: v1alpha1.DefaultBootMode,
})
}, tc.forceReboot)

assert.Equal(t, tc.expectedDirty, result.Dirty)
assert.Equal(t, time.Second*time.Duration(tc.expectedRequestAfter), result.RequeueAfter)
Expand Down
2 changes: 1 addition & 1 deletion pkg/provisioner/provisioner.go
Original file line number Diff line number Diff line change
Expand Up @@ -154,7 +154,7 @@ type Provisioner interface {
// Provision writes the image from the host spec to the host. It
// may be called multiple times, and should return true for its
// dirty flag until the provisioning operation is completed.
Provision(data ProvisionData) (result Result, err error)
Provision(data ProvisionData, forceReboot bool) (result Result, err error)

// Deprovision removes the host from the image. It may be called
// multiple times, and should return true for its dirty flag until
Expand Down

0 comments on commit d1e306b

Please sign in to comment.