diff --git a/api/v1beta1/hetznerbaremetalmachine_types.go b/api/v1beta1/hetznerbaremetalmachine_types.go index 6d906363d..44dd3a548 100644 --- a/api/v1beta1/hetznerbaremetalmachine_types.go +++ b/api/v1beta1/hetznerbaremetalmachine_types.go @@ -265,6 +265,11 @@ type HetznerBareMetalMachineStatus struct { // +optional Ready bool `json:"ready"` + // Phase represents the current phase of HetznerBareMetalMachineStatus actuation. + // E.g. Pending, Running, Terminating, Failed etc. + // +optional + Phase clusterv1.MachinePhase `json:"phase,omitempty"` + // Conditions defines current service state of the HetznerBareMetalMachine. // +optional Conditions clusterv1.Conditions `json:"conditions,omitempty"` @@ -279,6 +284,7 @@ type HetznerBareMetalMachineStatus struct { // +kubebuilder:printcolumn:name="ProviderID",type="string",JSONPath=".spec.providerID",description="Provider ID" // +kubebuilder:printcolumn:name="Ready",type="string",JSONPath=".status.ready",description="hetznerbaremetalmachine is Ready" // +kubebuilder:printcolumn:name="Cluster",type="string",JSONPath=".metadata.labels.cluster\\.x-k8s\\.io/cluster-name",description="Cluster to which this M3Machine belongs" +// +kubebuilder:printcolumn:name="Phase",type="string",JSONPath=".status.phase",description="HetznerBareMetalMachine status such as Pending/Provisioning/Running etc" // +kubebuilder:printcolumn:name="Reason",type="string",JSONPath=".status.conditions[?(@.type=='Ready')].reason" // +kubebuilder:printcolumn:name="Message",type="string",JSONPath=".status.conditions[?(@.type=='Ready')].message" diff --git a/config/crd/bases/infrastructure.cluster.x-k8s.io_hetznerbaremetalmachines.yaml b/config/crd/bases/infrastructure.cluster.x-k8s.io_hetznerbaremetalmachines.yaml index 2931d3292..e59dbc99b 100644 --- a/config/crd/bases/infrastructure.cluster.x-k8s.io_hetznerbaremetalmachines.yaml +++ b/config/crd/bases/infrastructure.cluster.x-k8s.io_hetznerbaremetalmachines.yaml @@ -39,6 +39,11 @@ spec: jsonPath: .metadata.labels.cluster\.x-k8s\.io/cluster-name name: Cluster type: string + - description: HetznerBareMetalMachine status such as Pending/Provisioning/Running + etc + jsonPath: .status.phase + name: Phase + type: string - jsonPath: .status.conditions[?(@.type=='Ready')].reason name: Reason type: string @@ -360,6 +365,10 @@ spec: description: LastUpdated identifies when this status was last observed. format: date-time type: string + phase: + description: Phase represents the current phase of HetznerBareMetalMachineStatus + actuation. E.g. Pending, Running, Terminating, Failed etc. + type: string ready: description: Ready is the state of the hetznerbaremetalmachine. type: boolean diff --git a/controllers/hetznerbaremetalmachine_controller.go b/controllers/hetznerbaremetalmachine_controller.go index 7e54f3aa2..6eb4b47d6 100644 --- a/controllers/hetznerbaremetalmachine_controller.go +++ b/controllers/hetznerbaremetalmachine_controller.go @@ -23,6 +23,11 @@ import ( "time" "github.com/go-logr/logr" + infrav1 "github.com/syself/cluster-api-provider-hetzner/api/v1beta1" + "github.com/syself/cluster-api-provider-hetzner/pkg/scope" + secretutil "github.com/syself/cluster-api-provider-hetzner/pkg/secrets" + "github.com/syself/cluster-api-provider-hetzner/pkg/services/baremetal/baremetal" + hcloudclient "github.com/syself/cluster-api-provider-hetzner/pkg/services/hcloud/client" apierrors "k8s.io/apimachinery/pkg/api/errors" "k8s.io/apimachinery/pkg/types" "k8s.io/klog/v2" @@ -38,12 +43,6 @@ import ( "sigs.k8s.io/controller-runtime/pkg/handler" "sigs.k8s.io/controller-runtime/pkg/reconcile" "sigs.k8s.io/controller-runtime/pkg/source" - - infrav1 "github.com/syself/cluster-api-provider-hetzner/api/v1beta1" - "github.com/syself/cluster-api-provider-hetzner/pkg/scope" - secretutil "github.com/syself/cluster-api-provider-hetzner/pkg/secrets" - "github.com/syself/cluster-api-provider-hetzner/pkg/services/baremetal/baremetal" - hcloudclient "github.com/syself/cluster-api-provider-hetzner/pkg/services/hcloud/client" ) // HetznerBareMetalMachineReconciler reconciles a HetznerBareMetalMachine object. diff --git a/controllers/hetznerbaremetalmachine_controller_test.go b/controllers/hetznerbaremetalmachine_controller_test.go index a0107bf45..ca43d6dd3 100644 --- a/controllers/hetznerbaremetalmachine_controller_test.go +++ b/controllers/hetznerbaremetalmachine_controller_test.go @@ -432,6 +432,18 @@ var _ = Describe("HetznerBareMetalMachineReconciler", func() { return bmMachine.Status.FailureMessage != nil && *bmMachine.Status.FailureMessage == baremetal.FailureMessageMaintenanceMode }, timeout).Should(BeTrue()) }) + + It("checks the hetznerBareMetalMachine status running phase", func() { + By("making sure that machine is in running state") + Eventually(func() bool { + if err := testEnv.Get(ctx, key, bmMachine); err != nil { + return false + } + + testEnv.GetLogger().Info("status of host and hetznerBareMetalMachine", "hetznerBareMetalMachine phase", bmMachine.Status.Phase, "host state", host.Spec.Status.ProvisioningState) + return bmMachine.Status.Phase == clusterv1.MachinePhaseRunning + }, timeout, time.Second).Should(BeTrue()) + }) }) }) @@ -491,6 +503,17 @@ var _ = Describe("HetznerBareMetalMachineReconciler", func() { return isPresentAndFalseWithReason(key, bmMachine, infrav1.HostAssociateSucceededCondition, infrav1.NoAvailableHostReason) }, timeout).Should(BeTrue()) }) + + It("checks the hetznerBareMetalMachine status pending phase", func() { + Eventually(func() bool { + if err := testEnv.Get(ctx, key, bmMachine); err != nil { + return false + } + + testEnv.GetLogger().Info("phase of hetznerBareMetalMachine", "phase", bmMachine.Status.Phase) + return bmMachine.Status.Phase == clusterv1.MachinePhasePending + }, timeout, time.Second).Should(BeTrue()) + }) }) Context("hetznerBareMetalMachine validation", func() { diff --git a/pkg/services/baremetal/baremetal/baremetal.go b/pkg/services/baremetal/baremetal/baremetal.go index 51ffc32d8..f13b8daee 100644 --- a/pkg/services/baremetal/baremetal/baremetal.go +++ b/pkg/services/baremetal/baremetal/baremetal.go @@ -85,6 +85,7 @@ func (s *Service) Reconcile(ctx context.Context) (res reconcile.Result, err erro // Make sure bootstrap data is available and populated. If not, return, we // will get an event from the machine update when the flag is set to true. if !s.scope.IsBootstrapReady() { + s.scope.BareMetalMachine.Status.Phase = clusterv1.MachinePhasePending conditions.MarkFalse( s.scope.BareMetalMachine, infrav1.BootstrapReadyCondition, @@ -132,6 +133,8 @@ func (s *Service) Delete(ctx context.Context) (res reconcile.Result, err error) } if host != nil && host.Spec.ConsumerRef != nil { + s.scope.BareMetalMachine.Status.Phase = clusterv1.MachinePhaseDeleting + // remove control plane as load balancer target if s.scope.IsControlPlane() && s.scope.HetznerCluster.Spec.ControlPlaneLoadBalancer.Enabled { if err := s.removeAttachedServerOfLoadBalancer(ctx, host); err != nil { @@ -189,6 +192,8 @@ func (s *Service) Delete(ctx context.Context) (res reconcile.Result, err error) "HetznerBareMetalMachine with name %s deleted", s.scope.Name(), ) + s.scope.BareMetalMachine.Status.Phase = clusterv1.MachinePhaseDeleted + return res, nil } @@ -274,6 +279,7 @@ func (s *Service) associate(ctx context.Context) error { return fmt.Errorf("failed to choose host: %w", err) } if host == nil { + s.scope.BareMetalMachine.Status.Phase = clusterv1.MachinePhasePending s.scope.V(1).Info("No available host found. Requeuing.") conditions.MarkFalse( s.scope.BareMetalMachine, @@ -307,6 +313,7 @@ func (s *Service) associate(ctx context.Context) error { } s.ensureMachineAnnotation(host) + return nil } @@ -538,6 +545,8 @@ func (s *Service) getLabelSelector() labels.Selector { func (s *Service) setProviderID(ctx context.Context) error { // nothing to do if providerID is set if s.scope.BareMetalMachine.Spec.ProviderID != nil { + conditions.MarkTrue(s.scope.BareMetalMachine, infrav1.HostProvisionSucceededCondition) + s.scope.BareMetalMachine.Status.Phase = clusterv1.MachinePhaseRunning return nil } @@ -553,6 +562,7 @@ func (s *Service) setProviderID(ctx context.Context) error { } if host.Spec.Status.ProvisioningState != infrav1.StateProvisioned { + s.scope.BareMetalMachine.Status.Phase = clusterv1.MachinePhaseProvisioning conditions.MarkFalse( s.scope.BareMetalMachine, infrav1.HostProvisionSucceededCondition, @@ -568,6 +578,7 @@ func (s *Service) setProviderID(ctx context.Context) error { providerID := providerIDFromServerID(host.Spec.ServerID) s.scope.BareMetalMachine.Spec.ProviderID = &providerID conditions.MarkTrue(s.scope.BareMetalMachine, infrav1.HostProvisionSucceededCondition) + s.scope.BareMetalMachine.Status.Phase = clusterv1.MachinePhaseRunning return nil }