Skip to content

Commit 910f46d

Browse files
add conditions to kcp
1 parent 650a357 commit 910f46d

10 files changed

+151
-2
lines changed
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,48 @@
1+
/*
2+
Copyright 2020 The Kubernetes Authors.
3+
4+
Licensed under the Apache License, Version 2.0 (the "License");
5+
you may not use this file except in compliance with the License.
6+
You may obtain a copy of the License at
7+
8+
http://www.apache.org/licenses/LICENSE-2.0
9+
10+
Unless required by applicable law or agreed to in writing, software
11+
distributed under the License is distributed on an "AS IS" BASIS,
12+
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
See the License for the specific language governing permissions and
14+
limitations under the License.
15+
*/
16+
17+
package v1alpha3
18+
19+
import clusterv1 "sigs.k8s.io/cluster-api/api/v1alpha3"
20+
21+
// Conditions and condition Reasons for the KubeadmControlPlane object
22+
23+
const (
24+
// MachinesReady reports an aggregate of current status of the machines controlled by the KubeadmControlPlane.
25+
MachinesReadyCondition clusterv1.ConditionType = "MachinesReady"
26+
)
27+
28+
const (
29+
// CertificatesAvailableCondition documents that cluster certificates were generated as part of the
30+
// processing of a a KubeadmControlPlane object.
31+
// IMPORTANT: This condition won't be re-created after clusterctl move.
32+
CertificatesAvailableCondition clusterv1.ConditionType = "CertificatesAvailable"
33+
34+
// CertificatesGenerationFailedReason (Severity=Warning) documents a KubeadmControlPlane controller detecting
35+
// an error while generating certificates; those kind of errors are usually temporary and the controller
36+
// automatically recover from them.
37+
CertificatesGenerationFailedReason = "CertificatesGenerationFailed"
38+
)
39+
40+
const (
41+
// AvailableCondition documents that the first control plane instance has completed the kubeadm init operation
42+
// and so the control plane is available and an API server instance is ready for processing requests.
43+
AvailableCondition clusterv1.ConditionType = "Available"
44+
45+
// WaitingForKubeadmInitReason (Severity=Info) a KubeadmControlPlane object waiting for the first
46+
// control plane instance to complete the kubeadm init operation.
47+
WaitingForKubeadmInitReason = "WaitingForKubeadmInit"
48+
)

controlplane/kubeadm/api/v1alpha3/kubeadm_control_plane_types.go

+13
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@ package v1alpha3
1919
import (
2020
corev1 "k8s.io/api/core/v1"
2121
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
22+
clusterv1 "sigs.k8s.io/cluster-api/api/v1alpha3"
2223

2324
cabpkv1 "sigs.k8s.io/cluster-api/bootstrap/kubeadm/api/v1alpha3"
2425
"sigs.k8s.io/cluster-api/errors"
@@ -114,6 +115,10 @@ type KubeadmControlPlaneStatus struct {
114115
// ObservedGeneration is the latest generation observed by the controller.
115116
// +optional
116117
ObservedGeneration int64 `json:"observedGeneration,omitempty"`
118+
119+
// Conditions defines current service state of the KubeadmControlPlane.
120+
// +optional
121+
Conditions clusterv1.Conditions `json:"conditions,omitempty"`
117122
}
118123

119124
// +kubebuilder:object:root=true
@@ -137,6 +142,14 @@ type KubeadmControlPlane struct {
137142
Status KubeadmControlPlaneStatus `json:"status,omitempty"`
138143
}
139144

145+
func (in *KubeadmControlPlane) GetConditions() clusterv1.Conditions {
146+
return in.Status.Conditions
147+
}
148+
149+
func (in *KubeadmControlPlane) SetConditions(conditions clusterv1.Conditions) {
150+
in.Status.Conditions = conditions
151+
}
152+
140153
// +kubebuilder:object:root=true
141154

142155
// KubeadmControlPlaneList contains a list of KubeadmControlPlane.

controlplane/kubeadm/api/v1alpha3/zz_generated.deepcopy.go

+8
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

controlplane/kubeadm/config/crd/bases/controlplane.cluster.x-k8s.io_kubeadmcontrolplanes.yaml

+44
Original file line numberDiff line numberDiff line change
@@ -1045,6 +1045,50 @@ spec:
10451045
status:
10461046
description: KubeadmControlPlaneStatus defines the observed state of KubeadmControlPlane.
10471047
properties:
1048+
conditions:
1049+
description: Conditions defines current service state of the KubeadmControlPlane.
1050+
items:
1051+
description: Condition defines an observation of a Cluster API resource
1052+
operational state.
1053+
properties:
1054+
lastTransitionTime:
1055+
description: Last time the condition transitioned from one status
1056+
to another. This should be when the underlying condition changed.
1057+
If that is not known, then using the time when the API field
1058+
changed is acceptable.
1059+
format: date-time
1060+
type: string
1061+
message:
1062+
description: A human readable message indicating details about
1063+
the transition. This field may be empty.
1064+
type: string
1065+
reason:
1066+
description: The reason for the condition's last transition
1067+
in CamelCase. The specific API may choose whether or not this
1068+
field is considered a guaranteed API. This field may not be
1069+
empty.
1070+
type: string
1071+
severity:
1072+
description: Severity provides an explicit classification of
1073+
Reason code, so the users or machines can immediately understand
1074+
the current situation and act accordingly. The Severity field
1075+
MUST be set only when Status=False.
1076+
type: string
1077+
status:
1078+
description: Status of the condition, one of True, False, Unknown.
1079+
type: string
1080+
type:
1081+
description: Type of condition in CamelCase or in foo.example.com/CamelCase.
1082+
Many .condition.type values are consistent across resources
1083+
like Available, but because arbitrary conditions can be useful
1084+
(see .node.status.conditions), the ability to deconflict is
1085+
important.
1086+
type: string
1087+
required:
1088+
- status
1089+
- type
1090+
type: object
1091+
type: array
10481092
failureMessage:
10491093
description: ErrorMessage indicates that there is a terminal problem
10501094
reconciling the state, and will be set to a descriptive error message.

controlplane/kubeadm/controllers/controller.go

+18
Original file line numberDiff line numberDiff line change
@@ -49,6 +49,7 @@ import (
4949
capierrors "sigs.k8s.io/cluster-api/errors"
5050
"sigs.k8s.io/cluster-api/util"
5151
"sigs.k8s.io/cluster-api/util/annotations"
52+
"sigs.k8s.io/cluster-api/util/conditions"
5253
"sigs.k8s.io/cluster-api/util/patch"
5354
"sigs.k8s.io/cluster-api/util/predicates"
5455
"sigs.k8s.io/cluster-api/util/secret"
@@ -161,6 +162,15 @@ func (r *KubeadmControlPlaneReconciler) Reconcile(req ctrl.Request) (res ctrl.Re
161162
}
162163
}
163164

165+
// Always update the readyCondition.
166+
conditions.SetSummary(kcp,
167+
conditions.WithConditions(
168+
controlplanev1.MachinesReadyCondition,
169+
controlplanev1.AvailableCondition,
170+
controlplanev1.CertificatesAvailableCondition,
171+
),
172+
)
173+
164174
// Always attempt to update status.
165175
if err := r.updateStatus(ctx, kcp, cluster); err != nil {
166176
var connFailure *internal.RemoteClusterConnectionError
@@ -220,8 +230,10 @@ func (r *KubeadmControlPlaneReconciler) reconcile(ctx context.Context, cluster *
220230
controllerRef := metav1.NewControllerRef(kcp, controlplanev1.GroupVersion.WithKind("KubeadmControlPlane"))
221231
if err := certificates.LookupOrGenerate(ctx, r.Client, util.ObjectKey(cluster), *controllerRef); err != nil {
222232
logger.Error(err, "unable to lookup or create cluster certificates")
233+
conditions.MarkFalse(kcp, controlplanev1.CertificatesAvailableCondition, controlplanev1.CertificatesGenerationFailedReason, clusterv1.ConditionSeverityWarning, err.Error())
223234
return ctrl.Result{}, err
224235
}
236+
conditions.MarkTrue(kcp, controlplanev1.CertificatesAvailableCondition)
225237

226238
// If ControlPlaneEndpoint is not set, return early
227239
if cluster.Spec.ControlPlaneEndpoint.IsZero() {
@@ -255,6 +267,11 @@ func (r *KubeadmControlPlaneReconciler) reconcile(ctx context.Context, cluster *
255267
}
256268

257269
controlPlane := internal.NewControlPlane(cluster, kcp, ownedMachines)
270+
271+
// Aggregate the operational state of all the machines; while aggregating we are adding the
272+
// source ref to the aggregate reason (reason@machine/name) so the problem can be easily tracked down to its source.
273+
conditions.SetAggregate(controlPlane.KCP, controlplanev1.MachinesReadyCondition, ownedMachines.ConditionGetters(), conditions.AddSourceRef())
274+
258275
requireUpgrade := controlPlane.MachinesNeedingUpgrade()
259276
// Upgrade takes precedence over other operations
260277
if len(requireUpgrade) > 0 {
@@ -271,6 +288,7 @@ func (r *KubeadmControlPlaneReconciler) reconcile(ctx context.Context, cluster *
271288
case numMachines < desiredReplicas && numMachines == 0:
272289
// Create new Machine w/ init
273290
logger.Info("Initializing control plane", "Desired", desiredReplicas, "Existing", numMachines)
291+
conditions.MarkFalse(controlPlane.KCP, controlplanev1.AvailableCondition, controlplanev1.WaitingForKubeadmInitReason, clusterv1.ConditionSeverityInfo, "")
274292
return r.initializeControlPlane(ctx, cluster, kcp, controlPlane)
275293
// We are scaling up
276294
case numMachines < desiredReplicas && numMachines > 0:

controlplane/kubeadm/controllers/controller_test.go

+4-2
Original file line numberDiff line numberDiff line change
@@ -43,12 +43,13 @@ import (
4343
"sigs.k8s.io/cluster-api/controlplane/kubeadm/internal"
4444
"sigs.k8s.io/cluster-api/controlplane/kubeadm/internal/hash"
4545
capierrors "sigs.k8s.io/cluster-api/errors"
46+
"sigs.k8s.io/cluster-api/test/helpers"
4647
"sigs.k8s.io/cluster-api/util"
48+
"sigs.k8s.io/cluster-api/util/conditions"
4749
"sigs.k8s.io/cluster-api/util/kubeconfig"
4850
"sigs.k8s.io/cluster-api/util/secret"
4951
ctrl "sigs.k8s.io/controller-runtime"
5052
"sigs.k8s.io/controller-runtime/pkg/client"
51-
"sigs.k8s.io/controller-runtime/pkg/client/fake"
5253
"sigs.k8s.io/controller-runtime/pkg/controller/controllerutil"
5354
"sigs.k8s.io/controller-runtime/pkg/handler"
5455
"sigs.k8s.io/controller-runtime/pkg/log"
@@ -756,6 +757,7 @@ kubernetesVersion: metav1.16.1`,
756757

757758
g.Expect(kcp.Status.Selector).NotTo(BeEmpty())
758759
g.Expect(kcp.Status.Replicas).To(BeEquivalentTo(1))
760+
g.Expect(conditions.IsFalse(kcp, controlplanev1.AvailableCondition)).To(BeTrue())
759761

760762
s, err := secret.GetFromNamespacedName(context.Background(), fakeClient, client.ObjectKey{Namespace: "test", Name: "foo"}, secret.ClusterCA)
761763
g.Expect(err).NotTo(HaveOccurred())
@@ -1180,7 +1182,7 @@ func newFakeClient(g *WithT, initObjs ...runtime.Object) client.Client {
11801182
g.Expect(controlplanev1.AddToScheme(scheme.Scheme)).To(Succeed())
11811183
return &fakeClient{
11821184
startTime: time.Now(),
1183-
Client: fake.NewFakeClientWithScheme(scheme.Scheme, initObjs...),
1185+
Client: helpers.NewFakeClientWithScheme(scheme.Scheme, initObjs...),
11841186
}
11851187
}
11861188

controlplane/kubeadm/controllers/scale_test.go

+1
Original file line numberDiff line numberDiff line change
@@ -184,6 +184,7 @@ func TestKubeadmControlPlaneReconciler_scaleUpControlPlane(t *testing.T) {
184184
endMachines := internal.NewFilterableMachineCollectionFromMachineList(controlPlaneMachines)
185185
for _, m := range endMachines {
186186
bm, ok := beforeMachines[m.Name]
187+
bm.SetResourceVersion("1")
187188
g.Expect(ok).To(BeTrue())
188189
g.Expect(m).To(Equal(bm))
189190
}

controlplane/kubeadm/controllers/status.go

+2
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,7 @@ import (
2525
"sigs.k8s.io/cluster-api/controlplane/kubeadm/internal/hash"
2626
"sigs.k8s.io/cluster-api/controlplane/kubeadm/internal/machinefilters"
2727
"sigs.k8s.io/cluster-api/util"
28+
"sigs.k8s.io/cluster-api/util/conditions"
2829
)
2930

3031
// updateStatus is called after every reconcilitation loop in a defer statement to always make sure we have the
@@ -69,6 +70,7 @@ func (r *KubeadmControlPlaneReconciler) updateStatus(ctx context.Context, kcp *c
6970
// This only gets initialized once and does not change if the kubeadm config map goes away.
7071
if status.HasKubeadmConfig {
7172
kcp.Status.Initialized = true
73+
conditions.MarkTrue(kcp, controlplanev1.AvailableCondition)
7274
}
7375

7476
if kcp.Status.ReadyReplicas > 0 {

controlplane/kubeadm/controllers/status_test.go

+2
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,7 @@ import (
3232
clusterv1 "sigs.k8s.io/cluster-api/api/v1alpha3"
3333
controlplanev1 "sigs.k8s.io/cluster-api/controlplane/kubeadm/api/v1alpha3"
3434
"sigs.k8s.io/cluster-api/controlplane/kubeadm/internal"
35+
"sigs.k8s.io/cluster-api/util/conditions"
3536
"sigs.k8s.io/controller-runtime/pkg/log"
3637
)
3738

@@ -197,6 +198,7 @@ func TestKubeadmControlPlaneReconciler_updateStatusAllMachinesReady(t *testing.T
197198
g.Expect(kcp.Status.FailureMessage).To(BeNil())
198199
g.Expect(kcp.Status.FailureReason).To(BeEquivalentTo(""))
199200
g.Expect(kcp.Status.Initialized).To(BeTrue())
201+
g.Expect(conditions.IsTrue(kcp, controlplanev1.AvailableCondition)).To(BeTrue())
200202
g.Expect(kcp.Status.Ready).To(BeTrue())
201203
}
202204

controlplane/kubeadm/internal/machine_collection.go

+11
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,7 @@ import (
3333
clusterv1 "sigs.k8s.io/cluster-api/api/v1alpha3"
3434
"sigs.k8s.io/cluster-api/controlplane/kubeadm/internal/machinefilters"
3535
"sigs.k8s.io/cluster-api/util"
36+
"sigs.k8s.io/cluster-api/util/conditions"
3637
)
3738

3839
// FilterableMachineCollection is a set of Machines
@@ -134,3 +135,13 @@ func (s FilterableMachineCollection) DeepCopy() FilterableMachineCollection {
134135
}
135136
return result
136137
}
138+
139+
// ConditionGetters returns the slice with machines converted into conditions.Getter.
140+
func (s FilterableMachineCollection) ConditionGetters() []conditions.Getter {
141+
res := make([]conditions.Getter, 0, len(s))
142+
for _, v := range s {
143+
value := *v
144+
res = append(res, &value)
145+
}
146+
return res
147+
}

0 commit comments

Comments
 (0)