Skip to content

Commit 975e240

Browse files
authored
Merge pull request #11923 from fabriziopandini/add-v1beta2-conditions-to-DevMachine-Docker
🌱 Add v1beta2 conditions to DevMachine and DevCluster with Docker backend
2 parents cb6b1a9 + 4cefa67 commit 975e240

File tree

7 files changed

+312
-97
lines changed

7 files changed

+312
-97
lines changed

api/v1beta1/v1beta2_condition_consts.go

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -209,4 +209,7 @@ const (
209209

210210
// ProvisionedV1Beta2Reason documents an object or a piece of infrastructure being provisioned.
211211
ProvisionedV1Beta2Reason = "Provisioned"
212+
213+
// NotProvisionedV1Beta2Reason documents an object or a piece of infrastructure is not provisioned.
214+
NotProvisionedV1Beta2Reason = "NotProvisioned"
212215
)

test/infrastructure/docker/api/v1beta1/devcluster_types.go

Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,46 @@ const (
2828
ListenerAnnotationName = "inmemorycluster.infrastructure.cluster.x-k8s.io/listener"
2929
)
3030

31+
// DevCluster's v1Beta2 conditions that apply to all the supported backends.
32+
33+
// DevCluster's Ready condition and corresponding reasons that will be used in v1Beta2 API version.
34+
const (
35+
// DevClusterReadyV1Beta2Condition is true if
36+
// - The DevCluster's is using a docker backend and LoadBalancerAvailable is true.
37+
DevClusterReadyV1Beta2Condition = clusterv1.ReadyV1Beta2Condition
38+
39+
// DevClusterReadyV1Beta2Reason surfaces when the DevCluster readiness criteria is met.
40+
DevClusterReadyV1Beta2Reason = clusterv1.ReadyV1Beta2Reason
41+
42+
// DevClusterNotReadyV1Beta2Reason surfaces when the DevCluster readiness criteria is not met.
43+
DevClusterNotReadyV1Beta2Reason = clusterv1.NotReadyV1Beta2Reason
44+
45+
// DevClusterReadyUnknownV1Beta2Reason surfaces when at least one DevCluster readiness criteria is unknown
46+
// and no DevCluster readiness criteria is not met.
47+
DevClusterReadyUnknownV1Beta2Reason = clusterv1.ReadyUnknownV1Beta2Reason
48+
)
49+
50+
// DevCluster's v1Beta2 conditions that apply to the docker backend.
51+
52+
// LoadBalancerAvailable condition and corresponding reasons that will be used in v1Beta2 API version for a DevCluster's docker backend.
53+
const (
54+
// DevClusterDockerLoadBalancerAvailableV1Beta2Condition documents the availability of the container that implements
55+
// the load balancer for a DevCluster's docker backend..
56+
DevClusterDockerLoadBalancerAvailableV1Beta2Condition string = "LoadBalancerAvailable"
57+
58+
// DevClusterDockerLoadBalancerNotAvailableV1Beta2Reason surfaces when the container that implements
59+
// the load balancer for a DevCluster's docker backend is not available.
60+
DevClusterDockerLoadBalancerNotAvailableV1Beta2Reason = clusterv1.NotAvailableV1Beta2Reason
61+
62+
// DevClusterDockerLoadBalancerAvailableV1Beta2Reason surfaces when the container that implements
63+
// the load balancer for a DevCluster's docker backend is available.
64+
DevClusterDockerLoadBalancerAvailableV1Beta2Reason = clusterv1.AvailableV1Beta2Reason
65+
66+
// DevClusterDockerLoadBalancerDeletingV1Beta2Reason surfaces when the container that implements
67+
// the load balancer for a DevCluster's docker backend is deleting.
68+
DevClusterDockerLoadBalancerDeletingV1Beta2Reason = clusterv1.DeletingV1Beta2Reason
69+
)
70+
3171
// DevClusterSpec defines the desired state of the DevCluster infrastructure.
3272
type DevClusterSpec struct {
3373
// controlPlaneEndpoint represents the endpoint used to communicate with the control plane.

test/infrastructure/docker/api/v1beta1/devmachine_types.go

Lines changed: 59 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -70,8 +70,10 @@ const (
7070

7171
// DevMachine's Ready condition and corresponding reasons that will be used in v1Beta2 API version.
7272
const (
73-
// DevMachineReadyV1Beta2Condition is true if the DevMachine's VMProvisioned, NodeProvisioned,
74-
// EtcdProvisioned (if present) and APIServerProvisioned (if present) conditions are true.
73+
// DevMachineReadyV1Beta2Condition is true if
74+
// - The DevMachine's is using a docker backend and LoadBalancerAvailable is true.
75+
// - The DevMachine's is using an in memory backend and VMProvisioned, NodeProvisioned,
76+
// EtcdProvisioned (if present) and APIServerProvisioned (if present) conditions are true
7577
DevMachineReadyV1Beta2Condition = clusterv1.ReadyV1Beta2Condition
7678

7779
// DevMachineReadyV1Beta2Reason surfaces when the DevMachine readiness criteria is met.
@@ -85,6 +87,61 @@ const (
8587
DevMachineReadyUnknownV1Beta2Reason = clusterv1.ReadyUnknownV1Beta2Reason
8688
)
8789

90+
// DevMachine's v1Beta2 conditions that apply to the docker backend.
91+
92+
// ContainerProvisioned condition and corresponding reasons that will be used in v1Beta2 API version for a DevMachine's docker backend.
93+
const (
94+
// DevMachineDockerContainerProvisionedV1Beta2Condition documents the status of the provisioning of the container
95+
// generated by a DevMachine's docker backend.
96+
//
97+
// NOTE as a difference from other providers, container provisioning and bootstrap are directly managed
98+
// by the DevMachine's docker backend controller (not by cloud-init).
99+
DevMachineDockerContainerProvisionedV1Beta2Condition string = "ContainerProvisioned"
100+
101+
// DevMachineDockerContainerWaitingForClusterInfrastructureReadyV1Beta2Reason documents the container for a DevMachine's docker backend waiting for the cluster
102+
// infrastructure to be ready.
103+
DevMachineDockerContainerWaitingForClusterInfrastructureReadyV1Beta2Reason = clusterv1.WaitingForClusterInfrastructureReadyV1Beta2Reason
104+
105+
// DevMachineDockerContainerWaitingForControlPlaneInitializedV1Beta2Reason documents a container for a DevMachine's docker backend waiting
106+
// for the control plane to be initialized.
107+
DevMachineDockerContainerWaitingForControlPlaneInitializedV1Beta2Reason = clusterv1.WaitingForControlPlaneInitializedV1Beta2Reason
108+
109+
// DevMachineDockerContainerWaitingForBootstrapDataV1Beta2Reason documents a container for a DevMachine's docker backend waiting for the bootstrap
110+
// data to be ready.
111+
DevMachineDockerContainerWaitingForBootstrapDataV1Beta2Reason = clusterv1.WaitingForBootstrapDataV1Beta2Reason
112+
113+
// DevMachineDockerContainerProvisionedV1Beta2Reason documents the container for a DevMachine's docker backend is provisioned.
114+
DevMachineDockerContainerProvisionedV1Beta2Reason = clusterv1.ProvisionedV1Beta2Reason
115+
116+
// DevMachineDockerContainerNotProvisionedV1Beta2Reason documents the container for a DevMachine's docker
117+
// backend is not provisioned.
118+
DevMachineDockerContainerNotProvisionedV1Beta2Reason = clusterv1.NotProvisionedV1Beta2Reason
119+
120+
// DevMachineDockerContainerDeletingV1Beta2Reason surfaces when the container for a DevMachine's docker
121+
// backend is deleting.
122+
DevMachineDockerContainerDeletingV1Beta2Reason = clusterv1.DeletingV1Beta2Reason
123+
)
124+
125+
// BootstrapExecSucceeded condition and corresponding reasons that will be used in v1Beta2 API version for a DevMachine's docker backend.
126+
const (
127+
// DevMachineDockerContainerBootstrapExecSucceededV1Beta2Condition provides an observation of the DevMachine's docker backend bootstrap process.
128+
// It is set based on successful execution of bootstrap commands and on the existence of
129+
// the /run/cluster-api/bootstrap-success.complete file.
130+
// The condition gets generated after ContainerProvisioned condition is True.
131+
//
132+
// NOTE as a difference from other providers, container provisioning and bootstrap are directly managed
133+
// by the DevMachine's docker backend controller (not by cloud-init).
134+
DevMachineDockerContainerBootstrapExecSucceededV1Beta2Condition string = "BootstrapExecSucceeded"
135+
136+
// DevMachineDockerContainerBootstrapExecSucceededV1Beta2Reason documents the container for a DevMachine's docker backend having
137+
// completed bootstrap exec commands.
138+
DevMachineDockerContainerBootstrapExecSucceededV1Beta2Reason string = "Succeeded"
139+
140+
// DevMachineDockerContainerBootstrapExecNotSucceededV1Beta2Reason documents the container for a DevMachine's docker backend not having
141+
// completed bootstrap exec commands.
142+
DevMachineDockerContainerBootstrapExecNotSucceededV1Beta2Reason string = "NotSucceeded"
143+
)
144+
88145
// DevMachine's v1Beta2 conditions that apply to the in memory backend.
89146

90147
// VirtualMachineProvisioned condition and corresponding reasons that will be used in v1Beta2 API version for a DevMachine's in memory backend.

test/infrastructure/docker/internal/controllers/backends/docker/dockercluster_backend.go

Lines changed: 65 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -19,9 +19,12 @@ package docker
1919

2020
import (
2121
"context"
22+
"fmt"
2223
"strconv"
24+
"time"
2325

2426
"github.com/pkg/errors"
27+
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
2528
ctrl "sigs.k8s.io/controller-runtime"
2629
"sigs.k8s.io/controller-runtime/pkg/client"
2730
"sigs.k8s.io/controller-runtime/pkg/controller/controllerutil"
@@ -31,16 +34,14 @@ import (
3134
infrav1 "sigs.k8s.io/cluster-api/test/infrastructure/docker/api/v1beta1"
3235
"sigs.k8s.io/cluster-api/test/infrastructure/docker/internal/docker"
3336
"sigs.k8s.io/cluster-api/util/conditions"
37+
v1beta2conditions "sigs.k8s.io/cluster-api/util/conditions/v1beta2"
3438
"sigs.k8s.io/cluster-api/util/patch"
3539
)
3640

3741
// ClusterBackEndReconciler reconciles a DockerCluster object.
3842
type ClusterBackEndReconciler struct {
3943
client.Client
4044
ContainerRuntime container.Runtime
41-
42-
NewPatchHelperFunc func(obj client.Object, crClient client.Client) (*patch.Helper, error)
43-
PatchDevClusterFunc func(ctx context.Context, patchHelper *patch.Helper, dockerCluster *infrav1.DevCluster) error
4445
}
4546

4647
// ReconcileNormal handle docker backend for DevCluster not yet deleted.
@@ -61,19 +62,37 @@ func (r *ClusterBackEndReconciler) ReconcileNormal(ctx context.Context, cluster
6162
strconv.Itoa(dockerCluster.Spec.ControlPlaneEndpoint.Port))
6263
if err != nil {
6364
conditions.MarkFalse(dockerCluster, infrav1.LoadBalancerAvailableCondition, infrav1.LoadBalancerProvisioningFailedReason, clusterv1.ConditionSeverityWarning, err.Error())
65+
v1beta2conditions.Set(dockerCluster, metav1.Condition{
66+
Type: infrav1.DevClusterDockerLoadBalancerAvailableV1Beta2Condition,
67+
Status: metav1.ConditionFalse,
68+
Reason: infrav1.DevClusterDockerLoadBalancerNotAvailableV1Beta2Reason,
69+
Message: fmt.Sprintf("Failed to create helper for managing the externalLoadBalancer: %v", err),
70+
})
6471
return ctrl.Result{}, errors.Wrapf(err, "failed to create helper for managing the externalLoadBalancer")
6572
}
6673

6774
// Create the docker container hosting the load balancer.
6875
if err := externalLoadBalancer.Create(ctx); err != nil {
6976
conditions.MarkFalse(dockerCluster, infrav1.LoadBalancerAvailableCondition, infrav1.LoadBalancerProvisioningFailedReason, clusterv1.ConditionSeverityWarning, err.Error())
77+
v1beta2conditions.Set(dockerCluster, metav1.Condition{
78+
Type: infrav1.DevClusterDockerLoadBalancerAvailableV1Beta2Condition,
79+
Status: metav1.ConditionFalse,
80+
Reason: infrav1.DevClusterDockerLoadBalancerNotAvailableV1Beta2Reason,
81+
Message: fmt.Sprintf("Failed to create load balancer: %v", err),
82+
})
7083
return ctrl.Result{}, errors.Wrap(err, "failed to create load balancer")
7184
}
7285

7386
// Set APIEndpoints with the load balancer IP so the Cluster API Cluster Controller can pull it
7487
lbIP, err := externalLoadBalancer.IP(ctx)
7588
if err != nil {
7689
conditions.MarkFalse(dockerCluster, infrav1.LoadBalancerAvailableCondition, infrav1.LoadBalancerProvisioningFailedReason, clusterv1.ConditionSeverityWarning, err.Error())
90+
v1beta2conditions.Set(dockerCluster, metav1.Condition{
91+
Type: infrav1.DevClusterDockerLoadBalancerAvailableV1Beta2Condition,
92+
Status: metav1.ConditionFalse,
93+
Reason: infrav1.DevClusterDockerLoadBalancerNotAvailableV1Beta2Reason,
94+
Message: fmt.Sprintf("Failed to get ip for the load balancer: %v", err),
95+
})
7796
return ctrl.Result{}, errors.Wrap(err, "failed to get ip for the load balancer")
7897
}
7998

@@ -86,6 +105,11 @@ func (r *ClusterBackEndReconciler) ReconcileNormal(ctx context.Context, cluster
86105
// Mark the dockerCluster ready
87106
dockerCluster.Status.Ready = true
88107
conditions.MarkTrue(dockerCluster, infrav1.LoadBalancerAvailableCondition)
108+
v1beta2conditions.Set(dockerCluster, metav1.Condition{
109+
Type: infrav1.DevClusterDockerLoadBalancerAvailableV1Beta2Condition,
110+
Status: metav1.ConditionTrue,
111+
Reason: infrav1.DevClusterDockerLoadBalancerAvailableV1Beta2Reason,
112+
})
89113

90114
return ctrl.Result{}, nil
91115
}
@@ -103,28 +127,26 @@ func (r *ClusterBackEndReconciler) ReconcileDelete(ctx context.Context, cluster
103127
strconv.Itoa(dockerCluster.Spec.ControlPlaneEndpoint.Port))
104128
if err != nil {
105129
conditions.MarkFalse(dockerCluster, infrav1.LoadBalancerAvailableCondition, infrav1.LoadBalancerProvisioningFailedReason, clusterv1.ConditionSeverityWarning, err.Error())
130+
v1beta2conditions.Set(dockerCluster, metav1.Condition{
131+
Type: infrav1.DevClusterDockerLoadBalancerAvailableV1Beta2Condition,
132+
Status: metav1.ConditionFalse,
133+
Reason: infrav1.DevClusterDockerLoadBalancerNotAvailableV1Beta2Reason,
134+
Message: fmt.Sprintf("Failed to create helper for managing the externalLoadBalancer: %v", err),
135+
})
136+
106137
return ctrl.Result{}, errors.Wrapf(err, "failed to create helper for managing the externalLoadBalancer")
107138
}
108139

109-
// Set the LoadBalancerAvailableCondition reporting delete is started, and issue a patch in order to make
140+
// Set the LoadBalancerAvailableCondition reporting delete is started, and requeue in order to make
110141
// this visible to the users.
111-
// NB. The operation in docker is fast, so there is the chance the user will not notice the status change;
112-
// nevertheless we are issuing a patch so we can test a pattern that will be used by other providers as well
113-
newPatchHelperFunc := r.NewPatchHelperFunc
114-
if newPatchHelperFunc == nil {
115-
newPatchHelperFunc = patch.NewHelper
116-
}
117-
patchHelper, err := newPatchHelperFunc(dockerCluster, r.Client)
118-
if err != nil {
119-
return ctrl.Result{}, err
120-
}
121-
conditions.MarkFalse(dockerCluster, infrav1.LoadBalancerAvailableCondition, clusterv1.DeletingReason, clusterv1.ConditionSeverityInfo, "")
122-
patchDevClusterFunc := r.PatchDevClusterFunc
123-
if patchDevClusterFunc == nil {
124-
patchDevClusterFunc = r.PatchDevCluster
125-
}
126-
if err := patchDevClusterFunc(ctx, patchHelper, dockerCluster); err != nil {
127-
return ctrl.Result{}, errors.Wrap(err, "failed to patch DockerCluster")
142+
if conditions.GetReason(dockerCluster, infrav1.LoadBalancerAvailableCondition) != clusterv1.DeletingReason {
143+
conditions.MarkFalse(dockerCluster, infrav1.LoadBalancerAvailableCondition, clusterv1.DeletingReason, clusterv1.ConditionSeverityInfo, "")
144+
v1beta2conditions.Set(dockerCluster, metav1.Condition{
145+
Type: infrav1.DevClusterDockerLoadBalancerAvailableV1Beta2Condition,
146+
Status: metav1.ConditionFalse,
147+
Reason: infrav1.DevClusterDockerLoadBalancerDeletingV1Beta2Reason,
148+
})
149+
return ctrl.Result{RequeueAfter: 1 * time.Second}, nil
128150
}
129151

130152
// Delete the docker container hosting the load balancer
@@ -152,6 +174,24 @@ func (r *ClusterBackEndReconciler) PatchDevCluster(ctx context.Context, patchHel
152174
),
153175
conditions.WithStepCounterIf(dockerCluster.ObjectMeta.DeletionTimestamp.IsZero()),
154176
)
177+
if err := v1beta2conditions.SetSummaryCondition(dockerCluster, dockerCluster, infrav1.DevClusterReadyV1Beta2Condition,
178+
v1beta2conditions.ForConditionTypes{
179+
infrav1.DevClusterDockerLoadBalancerAvailableV1Beta2Condition,
180+
},
181+
// Using a custom merge strategy to override reasons applied during merge.
182+
v1beta2conditions.CustomMergeStrategy{
183+
MergeStrategy: v1beta2conditions.DefaultMergeStrategy(
184+
// Use custom reasons.
185+
v1beta2conditions.ComputeReasonFunc(v1beta2conditions.GetDefaultComputeMergeReasonFunc(
186+
infrav1.DevClusterNotReadyV1Beta2Reason,
187+
infrav1.DevClusterReadyUnknownV1Beta2Reason,
188+
infrav1.DevClusterReadyV1Beta2Reason,
189+
)),
190+
),
191+
},
192+
); err != nil {
193+
return errors.Wrapf(err, "failed to set %s condition", infrav1.DevClusterReadyV1Beta2Condition)
194+
}
155195

156196
// Patch the object, ignoring conflicts on the conditions owned by this controller.
157197
return patchHelper.Patch(
@@ -161,5 +201,9 @@ func (r *ClusterBackEndReconciler) PatchDevCluster(ctx context.Context, patchHel
161201
clusterv1.ReadyCondition,
162202
infrav1.LoadBalancerAvailableCondition,
163203
}},
204+
patch.WithOwnedV1Beta2Conditions{Conditions: []string{
205+
infrav1.DevClusterReadyV1Beta2Condition,
206+
infrav1.DevClusterDockerLoadBalancerAvailableV1Beta2Condition,
207+
}},
164208
)
165209
}

0 commit comments

Comments
 (0)