Skip to content

Commit

Permalink
Support toggling provisioning checks
Browse files Browse the repository at this point in the history
Signed-off-by: ekarlso <endre.karlson@gmail.com>
  • Loading branch information
ekarlso committed Sep 30, 2024
1 parent 321d629 commit 5299af1
Show file tree
Hide file tree
Showing 11 changed files with 226 additions and 9 deletions.
11 changes: 11 additions & 0 deletions api/v1alpha1/proxmoxmachine_types.go
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,15 @@ const (
IPV6Format = "v6"
)

type ProxmoxMachineChecks struct {
// Skip checking CloudInit which can be very useful for specific Operating Systems like TalOS
// +optional
SkipCloudInitStatus *bool `json:"skipCloudInitStatus,omitempty"`
// Skip checking QEMU Agent readiness which can be very useful for specific Operating Systems like TalOS
// +optional
SkipQemuGuestAgent *bool `json:"skipQemuGuestAgent,omitempty"`
}

// ProxmoxMachineSpec defines the desired state of a ProxmoxMachine.
type ProxmoxMachineSpec struct {
VirtualMachineCloneSpec `json:",inline"`
Expand Down Expand Up @@ -90,6 +99,8 @@ type ProxmoxMachineSpec struct {
// Network is the network configuration for this machine's VM.
// +optional
Network *NetworkSpec `json:"network,omitempty"`

Checks *ProxmoxMachineChecks `json:"checks,omitempty"`
}

// Storage is the physical storage on the node.
Expand Down
30 changes: 30 additions & 0 deletions api/v1alpha1/zz_generated.deepcopy.go

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Original file line number Diff line number Diff line change
Expand Up @@ -72,6 +72,15 @@ spec:
description: ProxmoxMachineSpec defines the desired state of
a ProxmoxMachine.
properties:
checks:
properties:
skipCloudInitStatus:
description: Skip checking CloudInit which can be very
useful for specific Operating Systems like TalOS
type: boolean
skipQemuGuestAgent:
type: boolean
type: object
description:
description: Description for the new VM.
type: string
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -90,6 +90,16 @@ spec:
description: ProxmoxMachineSpec defines the desired
state of a ProxmoxMachine.
properties:
checks:
properties:
skipCloudInitStatus:
description: Skip checking CloudInit which can
be very useful for specific Operating Systems
like TalOS
type: boolean
skipQemuGuestAgent:
type: boolean
type: object
description:
description: Description for the new VM.
type: string
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -65,6 +65,15 @@ spec:
spec:
description: ProxmoxMachineSpec defines the desired state of a ProxmoxMachine.
properties:
checks:
properties:
skipCloudInitStatus:
description: Skip checking CloudInit which can be very useful
for specific Operating Systems like TalOS
type: boolean
skipQemuGuestAgent:
type: boolean
type: object
description:
description: Description for the new VM.
type: string
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -72,6 +72,15 @@ spec:
description: ProxmoxMachineSpec defines the desired state of a
ProxmoxMachine.
properties:
checks:
properties:
skipCloudInitStatus:
description: Skip checking CloudInit which can be very
useful for specific Operating Systems like TalOS
type: boolean
skipQemuGuestAgent:
type: boolean
type: object
description:
description: Description for the new VM.
type: string
Expand Down
40 changes: 32 additions & 8 deletions internal/service/vmservice/vm.go
Original file line number Diff line number Diff line change
Expand Up @@ -108,22 +108,46 @@ func ReconcileVM(ctx context.Context, scope *scope.MachineScope) (infrav1alpha1.
return vm, nil
}

func skipQemuGuestCheck(mc *scope.MachineScope) bool {
if mc.ProxmoxMachine.Spec.Checks != nil {
return ptr.Deref(mc.ProxmoxMachine.Spec.Checks.SkipQemuGuestAgent, false)
}

return false
}

func skipCloudInitCheck(mc *scope.MachineScope) bool {
if mc.ProxmoxMachine.Spec.Checks != nil {
return ptr.Deref(mc.ProxmoxMachine.Spec.Checks.SkipCloudInitStatus, false)
}

return false
}

func checkCloudInitStatus(ctx context.Context, machineScope *scope.MachineScope) (requeue bool, err error) {
if !machineScope.VirtualMachine.IsRunning() {
// skip if the vm is not running.
return true, nil
}

if running, err := machineScope.InfraCluster.ProxmoxClient.CloudInitStatus(ctx, machineScope.VirtualMachine); err != nil || running {
if running {
return true, nil
if !skipQemuGuestCheck(machineScope) {
if err := machineScope.InfraCluster.ProxmoxClient.QemuAgentStatus(ctx, machineScope.VirtualMachine); err != nil {
return true, errors.Wrap(err, "error waiting for agent")
}
if errors.Is(goproxmox.ErrCloudInitFailed, err) {
conditions.MarkFalse(machineScope.ProxmoxMachine, infrav1alpha1.VMProvisionedCondition, infrav1alpha1.VMProvisionFailedReason, clusterv1.ConditionSeverityError, err.Error())
machineScope.SetFailureMessage(err)
machineScope.SetFailureReason(capierrors.MachineStatusError("BootstrapFailed"))
}

if !skipCloudInitCheck(machineScope) {
if running, err := machineScope.InfraCluster.ProxmoxClient.CloudInitStatus(ctx, machineScope.VirtualMachine); err != nil || running {
if running {
return true, nil
}
if errors.Is(goproxmox.ErrCloudInitFailed, err) {
conditions.MarkFalse(machineScope.ProxmoxMachine, infrav1alpha1.VMProvisionedCondition, infrav1alpha1.VMProvisionFailedReason, clusterv1.ConditionSeverityError, err.Error())
machineScope.SetFailureMessage(err)
machineScope.SetFailureReason(capierrors.MachineStatusError("BootstrapFailed"))
}
return false, err
}
return false, err
}

return false, nil
Expand Down
63 changes: 63 additions & 0 deletions internal/service/vmservice/vm_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,67 @@ func TestReconcileVM_EverythingReady(t *testing.T) {

proxmoxClient.EXPECT().GetVM(context.Background(), "node1", int64(123)).Return(vm, nil).Once()
proxmoxClient.EXPECT().CloudInitStatus(context.Background(), vm).Return(false, nil).Once()
proxmoxClient.EXPECT().QemuAgentStatus(context.Background(), vm).Return(nil).Once()

result, err := ReconcileVM(context.Background(), machineScope)
require.NoError(t, err)
require.Equal(t, infrav1alpha1.VirtualMachineStateReady, result.State)
require.Equal(t, "10.10.10.10", machineScope.ProxmoxMachine.Status.Addresses[1].Address)
}

func TestReconcileVM_QemuAgentCheckDisabled(t *testing.T) {
machineScope, proxmoxClient, _ := setupReconcilerTest(t)
vm := newRunningVM()
machineScope.SetVirtualMachineID(int64(vm.VMID))
machineScope.ProxmoxMachine.Status.IPAddresses = map[string]infrav1alpha1.IPAddress{infrav1alpha1.DefaultNetworkDevice: {IPV4: "10.10.10.10"}}
machineScope.ProxmoxMachine.Status.BootstrapDataProvided = ptr.To(true)
machineScope.ProxmoxMachine.Status.Ready = true
machineScope.ProxmoxMachine.Spec.Checks = &infrav1alpha1.ProxmoxMachineChecks{
SkipQemuGuestAgent: ptr.To(true),
}

proxmoxClient.EXPECT().GetVM(context.Background(), "node1", int64(123)).Return(vm, nil).Once()
proxmoxClient.EXPECT().CloudInitStatus(context.Background(), vm).Return(false, nil).Once()

result, err := ReconcileVM(context.Background(), machineScope)
require.NoError(t, err)
require.Equal(t, infrav1alpha1.VirtualMachineStateReady, result.State)
require.Equal(t, "10.10.10.10", machineScope.ProxmoxMachine.Status.Addresses[1].Address)
}

func TestReconcileVM_CloudInitCheckDisabled(t *testing.T) {
machineScope, proxmoxClient, _ := setupReconcilerTest(t)
vm := newRunningVM()
machineScope.SetVirtualMachineID(int64(vm.VMID))
machineScope.ProxmoxMachine.Status.IPAddresses = map[string]infrav1alpha1.IPAddress{infrav1alpha1.DefaultNetworkDevice: {IPV4: "10.10.10.10"}}
machineScope.ProxmoxMachine.Status.BootstrapDataProvided = ptr.To(true)
machineScope.ProxmoxMachine.Status.Ready = true
machineScope.ProxmoxMachine.Spec.Checks = &infrav1alpha1.ProxmoxMachineChecks{
SkipCloudInitStatus: ptr.To(true),
}

proxmoxClient.EXPECT().GetVM(context.Background(), "node1", int64(123)).Return(vm, nil).Once()
proxmoxClient.EXPECT().QemuAgentStatus(context.Background(), vm).Return(nil)

result, err := ReconcileVM(context.Background(), machineScope)
require.NoError(t, err)
require.Equal(t, infrav1alpha1.VirtualMachineStateReady, result.State)
require.Equal(t, "10.10.10.10", machineScope.ProxmoxMachine.Status.Addresses[1].Address)
}

func TestReconcileVM_InitCheckDisabled(t *testing.T) {
machineScope, proxmoxClient, _ := setupReconcilerTest(t)
vm := newRunningVM()
machineScope.SetVirtualMachineID(int64(vm.VMID))
machineScope.ProxmoxMachine.Status.IPAddresses = map[string]infrav1alpha1.IPAddress{infrav1alpha1.DefaultNetworkDevice: {IPV4: "10.10.10.10"}}
machineScope.ProxmoxMachine.Status.BootstrapDataProvided = ptr.To(true)
machineScope.ProxmoxMachine.Status.Ready = true
machineScope.ProxmoxMachine.Spec.Checks = &infrav1alpha1.ProxmoxMachineChecks{
SkipCloudInitStatus: ptr.To(true),
SkipQemuGuestAgent: ptr.To(true),
}

proxmoxClient.EXPECT().GetVM(context.Background(), "node1", int64(123)).Return(vm, nil).Once()

result, err := ReconcileVM(context.Background(), machineScope)
require.NoError(t, err)
Expand Down Expand Up @@ -323,6 +384,7 @@ func TestReconcileVM_CloudInitFailed(t *testing.T) {

proxmoxClient.EXPECT().GetVM(context.Background(), "node1", int64(123)).Return(vm, nil).Once()
proxmoxClient.EXPECT().CloudInitStatus(context.Background(), vm).Return(false, goproxmox.ErrCloudInitFailed).Once()
proxmoxClient.EXPECT().QemuAgentStatus(context.Background(), vm).Return(nil).Once()

_, err := ReconcileVM(context.Background(), machineScope)
require.Error(t, err, "unknown error")
Expand All @@ -340,6 +402,7 @@ func TestReconcileVM_CloudInitRunning(t *testing.T) {

proxmoxClient.EXPECT().GetVM(context.Background(), "node1", int64(123)).Return(vm, nil).Once()
proxmoxClient.EXPECT().CloudInitStatus(context.Background(), vm).Return(true, nil).Once()
proxmoxClient.EXPECT().QemuAgentStatus(context.Background(), vm).Return(nil).Once()

result, err := ReconcileVM(context.Background(), machineScope)
require.NoError(t, err)
Expand Down
3 changes: 2 additions & 1 deletion pkg/proxmox/client.go
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,7 @@ type Client interface {
TagVM(ctx context.Context, vm *proxmox.VirtualMachine, tag string) (*proxmox.Task, error)

UnmountCloudInitISO(ctx context.Context, vm *proxmox.VirtualMachine, device string) error

CloudInitStatus(ctx context.Context, vm *proxmox.VirtualMachine) (bool, error)

QemuAgentStatus(ctx context.Context, vm *proxmox.VirtualMachine) error
}
8 changes: 8 additions & 0 deletions pkg/proxmox/goproxmox/api_client.go
Original file line number Diff line number Diff line change
Expand Up @@ -300,3 +300,11 @@ func (c *APIClient) CloudInitStatus(ctx context.Context, vm *proxmox.VirtualMach

return false, nil
}

func (c *APIClient) QemuAgentStatus(ctx context.Context, vm *proxmox.VirtualMachine) error {
if err := vm.WaitForAgent(ctx, 5); err != nil {
return errors.Wrap(err, "error waiting for agent")
}

return nil
}
43 changes: 43 additions & 0 deletions pkg/proxmox/proxmoxtest/mock_client.go

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

0 comments on commit 5299af1

Please sign in to comment.