Skip to content

Commit 03d2f84

Browse files
Add support for v1beta2 conditions to clusterctl describe
1 parent 6865cec commit 03d2f84

File tree

8 files changed

+1714
-150
lines changed

8 files changed

+1714
-150
lines changed

cmd/clusterctl/client/describe.go

+4
Original file line numberDiff line numberDiff line change
@@ -57,6 +57,9 @@ type DescribeClusterOptions struct {
5757
// Grouping groups machines objects in case the ready conditions
5858
// have the same Status, Severity and Reason.
5959
Grouping bool
60+
61+
// V1Beta2 instructs tree to use V1Beta2 conditions.
62+
V1Beta2 bool
6063
}
6164

6265
// DescribeCluster returns the object tree representing the status of a Cluster API cluster.
@@ -96,5 +99,6 @@ func (c *clusterctlClient) DescribeCluster(ctx context.Context, options Describe
9699
AddTemplateVirtualNode: options.AddTemplateVirtualNode,
97100
Echo: options.Echo,
98101
Grouping: options.Grouping,
102+
V1Beta2: options.V1Beta2,
99103
})
100104
}

cmd/clusterctl/client/tree/annotations.go

+58
Original file line numberDiff line numberDiff line change
@@ -47,6 +47,19 @@ const (
4747
// GroupItemsAnnotation contains the list of names for the objects included in a group object.
4848
GroupItemsAnnotation = "tree.cluster.x-k8s.io.io/group-items"
4949

50+
// GroupItemsAvailableCounter contains the number of available objects in the group, e.g. available Machines.
51+
GroupItemsAvailableCounter = "tree.cluster.x-k8s.io.io/group-items-available-count"
52+
53+
// GroupItemsReadyCounter contains the number of ready objects in the group, e.g. ready Machines.
54+
GroupItemsReadyCounter = "tree.cluster.x-k8s.io.io/group-items-ready-count"
55+
56+
// GroupItemsUpToDateCounter contains the number of up-to-date objects in the group, e.g. up-to-date Machines.
57+
GroupItemsUpToDateCounter = "tree.cluster.x-k8s.io.io/group-items-up-to-date-count"
58+
59+
// ObjectContractAnnotation is added to unstructured objects to track which Cluster API contract those objects abide to.
60+
// Note: Currently this annotation is applied only to control plane objects.
61+
ObjectContractAnnotation = "tree.cluster.x-k8s.io.io/object-contract"
62+
5063
// GroupItemsSeparator is the separator used in the GroupItemsAnnotation.
5164
GroupItemsSeparator = ", "
5265

@@ -91,6 +104,51 @@ func GetGroupItems(obj client.Object) string {
91104
return ""
92105
}
93106

107+
// GetGroupItemsAvailableCounter returns the number of available objects in the group, e.g. available Machines.
108+
func GetGroupItemsAvailableCounter(obj client.Object) int {
109+
val, ok := getAnnotation(obj, GroupItemsAvailableCounter)
110+
if !ok {
111+
return 0
112+
}
113+
if v, err := strconv.Atoi(val); err == nil {
114+
return v
115+
}
116+
return 0
117+
}
118+
119+
// GetGroupItemsReadyCounter returns the number of ready objects in the group, e.g. ready Machines.
120+
func GetGroupItemsReadyCounter(obj client.Object) int {
121+
val, ok := getAnnotation(obj, GroupItemsReadyCounter)
122+
if !ok {
123+
return 0
124+
}
125+
if v, err := strconv.Atoi(val); err == nil {
126+
return v
127+
}
128+
return 0
129+
}
130+
131+
// GetGroupItemsUpToDateCounter returns the number of up-to-date objects in the group, e.g. up-to-date Machines.
132+
func GetGroupItemsUpToDateCounter(obj client.Object) int {
133+
val, ok := getAnnotation(obj, GroupItemsUpToDateCounter)
134+
if !ok {
135+
return 0
136+
}
137+
if v, err := strconv.Atoi(val); err == nil {
138+
return v
139+
}
140+
return 0
141+
}
142+
143+
// GetObjectContract returns which Cluster API contract an unstructured object abides to.
144+
// Note: Currently this annotation is applied only to control plane objects.
145+
func GetObjectContract(obj client.Object) string {
146+
if val, ok := getAnnotation(obj, ObjectContractAnnotation); ok {
147+
return val
148+
}
149+
return ""
150+
}
151+
94152
// GetZOrder return the zOrder of the object. Objects with no zOrder have a default zOrder of 0.
95153
func GetZOrder(obj client.Object) int {
96154
if val, ok := getAnnotation(obj, ObjectZOrderAnnotation); ok {

cmd/clusterctl/client/tree/discovery.go

+10-3
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,7 @@ import (
2222
"github.com/pkg/errors"
2323
corev1 "k8s.io/api/core/v1"
2424
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
25-
unstructured "k8s.io/apimachinery/pkg/apis/meta/v1/unstructured"
25+
"k8s.io/apimachinery/pkg/apis/meta/v1/unstructured"
2626
"sigs.k8s.io/controller-runtime/pkg/client"
2727

2828
clusterv1 "sigs.k8s.io/cluster-api/api/v1beta1"
@@ -56,6 +56,9 @@ type DiscoverOptions struct {
5656
// Grouping groups machine objects in case the ready conditions
5757
// have the same Status, Severity and Reason.
5858
Grouping bool
59+
60+
// V1Beta2 instructs tree to use V1Beta2 conditions.
61+
V1Beta2 bool
5962
}
6063

6164
func (d DiscoverOptions) toObjectTreeOptions() ObjectTreeOptions {
@@ -97,6 +100,10 @@ func Discovery(ctx context.Context, c client.Client, namespace, name string, opt
97100
// Adds control plane
98101
controlPlane, err := external.Get(ctx, c, cluster.Spec.ControlPlaneRef)
99102
if err == nil {
103+
// Keep track that this objects abides to the Cluster API control plane contract,
104+
// so the consumers of the ObjectTree will know which info are available on this unstructured object
105+
// and how to extract them.
106+
addAnnotation(controlPlane, ObjectContractAnnotation, "ControlPlane")
100107
addControlPlane(cluster, controlPlane, tree, options)
101108
}
102109

@@ -217,7 +224,7 @@ func addControlPlane(cluster *clusterv1.Cluster, controlPlane *unstructured.Unst
217224
}
218225
}
219226

220-
func addMachineDeploymentToObjectTree(ctx context.Context, c client.Client, cluster *clusterv1.Cluster, workers *unstructured.Unstructured, machinesList *clusterv1.MachineList, tree *ObjectTree, options DiscoverOptions, addMachineFunc func(parent client.Object, m *clusterv1.Machine)) error {
227+
func addMachineDeploymentToObjectTree(ctx context.Context, c client.Client, cluster *clusterv1.Cluster, workers *NodeObject, machinesList *clusterv1.MachineList, tree *ObjectTree, options DiscoverOptions, addMachineFunc func(parent client.Object, m *clusterv1.Machine)) error {
221228
// Adds worker machines.
222229
machinesDeploymentList, err := getMachineDeploymentsInCluster(ctx, c, cluster.Namespace, cluster.Name)
223230
if err != nil {
@@ -275,7 +282,7 @@ func addMachineDeploymentToObjectTree(ctx context.Context, c client.Client, clus
275282
return nil
276283
}
277284

278-
func addMachinePoolsToObjectTree(ctx context.Context, c client.Client, workers *unstructured.Unstructured, machinePoolList *expv1.MachinePoolList, machinesList *clusterv1.MachineList, tree *ObjectTree, addMachineFunc func(parent client.Object, m *clusterv1.Machine)) {
285+
func addMachinePoolsToObjectTree(ctx context.Context, c client.Client, workers *NodeObject, machinePoolList *expv1.MachinePoolList, machinesList *clusterv1.MachineList, tree *ObjectTree, addMachineFunc func(parent client.Object, m *clusterv1.Machine)) {
279286
for i := range machinePoolList.Items {
280287
mp := &machinePoolList.Items[i]
281288
_, visible := tree.Add(workers, mp, GroupingObject(true))
+127
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,127 @@
1+
/*
2+
Copyright 2024 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 tree
18+
19+
import (
20+
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
21+
"k8s.io/apimachinery/pkg/runtime"
22+
"k8s.io/apimachinery/pkg/types"
23+
24+
clusterv1 "sigs.k8s.io/cluster-api/api/v1beta1"
25+
)
26+
27+
// NodeObject represent a node in the tree which doesn't correspond to Cluster, MachineDeployment, Machine etc.
28+
// An example of NodeObject are GroupNodes, which are used e.g. to represent a set of Machines.
29+
// Note: NodeObject implements condition getter and setter interfaces as well as the minimal set of methods
30+
// usually existing on Kubernetes objects.
31+
type NodeObject struct {
32+
metav1.TypeMeta
33+
metav1.ObjectMeta
34+
Status NodeStatus
35+
}
36+
37+
// NodeStatus is the status of a node object.
38+
type NodeStatus struct {
39+
Conditions clusterv1.Conditions
40+
V1Beta2 *NodeObjectV1Beta2Status
41+
}
42+
43+
// NodeObjectV1Beta2Status is the v1Beta2 status of a node object.
44+
type NodeObjectV1Beta2Status struct {
45+
Conditions []metav1.Condition
46+
}
47+
48+
// GetConditions returns the set of conditions for this object.
49+
func (o *NodeObject) GetConditions() clusterv1.Conditions {
50+
return o.Status.Conditions
51+
}
52+
53+
// SetConditions sets the conditions on this object.
54+
func (o *NodeObject) SetConditions(conditions clusterv1.Conditions) {
55+
o.Status.Conditions = conditions
56+
}
57+
58+
// GetV1Beta2Conditions returns the set of conditions for this object.
59+
func (o *NodeObject) GetV1Beta2Conditions() []metav1.Condition {
60+
if o.Status.V1Beta2 == nil {
61+
return nil
62+
}
63+
return o.Status.V1Beta2.Conditions
64+
}
65+
66+
// SetV1Beta2Conditions sets conditions for an API object.
67+
func (o *NodeObject) SetV1Beta2Conditions(conditions []metav1.Condition) {
68+
if o.Status.V1Beta2 == nil && conditions != nil {
69+
o.Status.V1Beta2 = &NodeObjectV1Beta2Status{}
70+
}
71+
o.Status.V1Beta2.Conditions = conditions
72+
}
73+
74+
// GetUID returns object's UID.
75+
func (o *NodeObject) GetUID() types.UID {
76+
return o.UID
77+
}
78+
79+
// SetUID sets object's UID.
80+
func (o *NodeObject) SetUID(uid types.UID) {
81+
o.UID = uid
82+
}
83+
84+
// GetCreationTimestamp returns object's CreationTimestamp.
85+
func (o *NodeObject) GetCreationTimestamp() metav1.Time {
86+
return o.CreationTimestamp
87+
}
88+
89+
// SetCreationTimestamp sets object's CreationTimestamp.
90+
func (o *NodeObject) SetCreationTimestamp(timestamp metav1.Time) {
91+
o.CreationTimestamp = timestamp
92+
}
93+
94+
// GetDeletionTimestamp returns object's DeletionTimestamp.
95+
func (o *NodeObject) GetDeletionTimestamp() *metav1.Time {
96+
return o.DeletionTimestamp
97+
}
98+
99+
// SetDeletionTimestamp sets object's DeletionTimestamp.
100+
func (o *NodeObject) SetDeletionTimestamp(timestamp *metav1.Time) {
101+
o.DeletionTimestamp = timestamp
102+
}
103+
104+
// GetOwnerReferences returns object's OwnerReferences.
105+
func (o *NodeObject) GetOwnerReferences() []metav1.OwnerReference {
106+
return o.OwnerReferences
107+
}
108+
109+
// SetOwnerReferences sets object's OwnerReferences.
110+
func (o *NodeObject) SetOwnerReferences(references []metav1.OwnerReference) {
111+
o.OwnerReferences = references
112+
}
113+
114+
// GetManagedFields returns object's ManagedFields.
115+
func (o *NodeObject) GetManagedFields() []metav1.ManagedFieldsEntry {
116+
return o.ManagedFields
117+
}
118+
119+
// SetManagedFields sets object's ManagedFields.
120+
func (o *NodeObject) SetManagedFields(managedFields []metav1.ManagedFieldsEntry) {
121+
o.ManagedFields = managedFields
122+
}
123+
124+
// DeepCopyObject returns a deep copy of the object.
125+
func (o *NodeObject) DeepCopyObject() runtime.Object {
126+
panic("implement me")
127+
}

0 commit comments

Comments
 (0)