-
Notifications
You must be signed in to change notification settings - Fork 27
/
Copy pathclustersummary_types.go
317 lines (256 loc) · 10.7 KB
/
clustersummary_types.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
/*
Copyright 2024. projectsveltos.io. All rights reserved.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
package v1beta1
import (
"context"
"fmt"
"github.com/pkg/errors"
apierrors "k8s.io/apimachinery/pkg/api/errors"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/apimachinery/pkg/runtime/schema"
"k8s.io/apimachinery/pkg/types"
"sigs.k8s.io/controller-runtime/pkg/client"
libsveltosv1beta1 "github.com/projectsveltos/libsveltos/api/v1beta1"
)
const (
// ClusterSummaryFinalizer allows ClusterSummaryReconciler to clean up resources associated with
// ClusterSummary before removing it from the apiserver.
ClusterSummaryFinalizer = "clustersummaryfinalizer.projectsveltos.io"
ClusterSummaryKind = "ClusterSummary"
)
// +kubebuilder:validation:Enum:=Resources;Helm;Kustomize
type FeatureID string
const (
// FeatureResources is the identifier for generic Resources feature
FeatureResources = FeatureID("Resources")
// FeatureHelm is the identifier for Helm feature
FeatureHelm = FeatureID("Helm")
// FeatureKustomize is the identifier for Kustomize feature
FeatureKustomize = FeatureID("Kustomize")
)
// +kubebuilder:validation:Enum:=Provisioning;Provisioned;Failed;FailedNonRetriable;Removing;Removed
type FeatureStatus string
const (
// FeatureStatusProvisioning indicates that feature is being
// provisioned in the workload cluster
FeatureStatusProvisioning = FeatureStatus("Provisioning")
// FeatureStatusProvisioned indicates that feature has being
// provisioned in the workload cluster
FeatureStatusProvisioned = FeatureStatus("Provisioned")
// FeatureStatusFailed indicates that configuring the feature
// in the workload cluster failed
FeatureStatusFailed = FeatureStatus("Failed")
// FeatureStatusFailedNonRetriable indicates that configuring the feature
// in the workload cluster failed with a non retriable error
FeatureStatusFailedNonRetriable = FeatureStatus("FailedNonRetriable")
// FeatureStatusRemoving indicates that feature is being
// removed
FeatureStatusRemoving = FeatureStatus("Removing")
// FeatureStatusRemoved indicates that feature is removed
FeatureStatusRemoved = FeatureStatus("Removed")
)
// FeatureSummary contains a summary of the state of a workload
// cluster feature.
type FeatureSummary struct {
// FeatureID is an indentifier of the feature whose status is reported
FeatureID FeatureID `json:"featureID"`
// Hash represents of a unique value for a feature at a fixed point in
// time
// +optional
Hash []byte `json:"hash,omitempty"`
// The number of consecutive deployment failures.
// +optional
ConsecutiveFailures uint `json:"consecutiveFailures,omitempty"`
// Status represents the state of the feature in the workload cluster
// +optional
Status FeatureStatus `json:"status,omitempty"`
// FailureReason indicates the type of error that occurred.
// +optional
FailureReason *string `json:"failureReason,omitempty"`
// FailureMessage provides more information about the error.
// +optional
FailureMessage *string `json:"failureMessage,omitempty"`
// DeployedGroupVersionKind contains all GroupVersionKinds deployed in either
// the workload cluster or the management cluster because of this feature.
// Each element has format kind.version.group
// Deprecated: Replaced by FeatureDeploymentInfo field instead
// +optional
DeployedGroupVersionKind []string `json:"deployedGroupVersionKind,omitempty"`
// LastAppliedTime is the time feature was last reconciled
// +optional
LastAppliedTime *metav1.Time `json:"lastAppliedTime,omitempty"`
}
type FeatureDeploymentInfo struct {
// FeatureID is an indentifier of the feature whose status is reported
FeatureID FeatureID `json:"featureID"`
// DeployedGroupVersionKind contains all GroupVersionKinds deployed in either
// the workload cluster or the management cluster because of this feature.
// Each element has format kind.version.group
// +optional
DeployedGroupVersionKind []string `json:"deployedGroupVersionKind,omitempty"`
}
// HelChartStatus specifies whether ClusterSummary is successfully managing
// an helm chart or not
// +kubebuilder:validation:Enum:=Managing;Conflict
type HelmChartStatus string
const (
// HelChartStatusManaging indicates helm chart is successfully being managed
HelmChartStatusManaging = HelmChartStatus("Managing")
// HelChartStatusConflict indicates there is a conflict with another
// ClusterSummary to manage the helm chart
HelmChartStatusConflict = HelmChartStatus("Conflict")
)
type HelmChartSummary struct {
// ReleaseName is the chart release
// +kubebuilder:validation:MinLength=1
ReleaseName string `json:"releaseName"`
// ReleaseNamespace is the namespace release will be installed
// +kubebuilder:validation:MinLength=1
ReleaseNamespace string `json:"releaseNamespace"`
// Status indicates whether ClusterSummary can manage the helm
// chart or there is a conflict
Status HelmChartStatus `json:"status"`
// ValuesHash represents of a unique value for the values section
// +optional
ValuesHash []byte `json:"valuesHash,omitempty"`
// Status indicates whether ClusterSummary can manage the helm
// chart or there is a conflict
// +optional
ConflictMessage string `json:"conflictMessage,omitempty"`
}
// ClusterSummarySpec defines the desired state of ClusterSummary
type ClusterSummarySpec struct {
// ClusterNamespace is the namespace of the workload Cluster this
// ClusterSummary is for.
ClusterNamespace string `json:"clusterNamespace"`
// ClusterName is the name of the workload Cluster this ClusterSummary is for.
ClusterName string `json:"clusterName"`
// ClusterType is the type of Cluster
ClusterType libsveltosv1beta1.ClusterType `json:"clusterType"`
// ClusterProfileSpec represent the configuration that will be applied to
// the workload cluster.
ClusterProfileSpec Spec `json:"clusterProfileSpec,omitempty"`
}
// ClusterSummaryStatus defines the observed state of ClusterSummary
type ClusterSummaryStatus struct {
// Dependencies is a summary reporting the status of the dependencies
// for the associated ClusterProfile
Dependencies *string `json:"dependencies,omitempty"`
// FeatureSummaries reports the status of each workload cluster feature
// directly managed by ClusterProfile.
// +listType=map
// +listMapKey=featureID
// +optional
FeatureSummaries []FeatureSummary `json:"featureSummaries,omitempty"`
// DeployedGVKs reports the list of GVKs deployed by ClusterSummary
// in a managed cluster
// +listType=map
// +listMapKey=featureID
// +optional
DeployedGVKs []FeatureDeploymentInfo `json:"deployedGVKs,omitempty"`
// HelmReleaseSummaries reports the status of each helm chart
// directly managed by ClusterProfile.
// +listType=atomic
// +optional
HelmReleaseSummaries []HelmChartSummary `json:"helmReleaseSummaries,omitempty"`
}
//nolint: lll // marker
// +kubebuilder:object:root=true
// +kubebuilder:resource:path=clustersummaries,scope=Namespaced
// +kubebuilder:subresource:status
// +kubebuilder:storageversion
// +kubebuilder:printcolumn:name="Age",type="date",JSONPath=".metadata.creationTimestamp",description="Time duration since creation of ClusterSummary"
// +kubebuilder:printcolumn:name="HelmCharts",type="string",JSONPath=".status.featureSummaries[?(@.featureID==\"Helm\")].status",description="Indicates whether HelmCharts are all provisioned",priority=2
// +kubebuilder:printcolumn:name="KustomizeRefs",type="string",JSONPath=".status.featureSummaries[?(@.featureID==\"Kustomize\")].status",description="Indicates whether KustomizeRefs are all provisioned",priority=2
// +kubebuilder:printcolumn:name="PolicyRefs",type="string",JSONPath=".status.featureSummaries[?(@.featureID==\"Resources\")].status",description="Indicates whether PolicyRefs are all provisioned",priority=2
// ClusterSummary is the Schema for the clustersummaries API
type ClusterSummary struct {
metav1.TypeMeta `json:",inline"`
metav1.ObjectMeta `json:"metadata,omitempty"`
Spec ClusterSummarySpec `json:"spec,omitempty"`
Status ClusterSummaryStatus `json:"status,omitempty"`
}
//+kubebuilder:object:root=true
// ClusterSummaryList contains a list of ClusterSummary
type ClusterSummaryList struct {
metav1.TypeMeta `json:",inline"`
metav1.ListMeta `json:"metadata,omitempty"`
Items []ClusterSummary `json:"items"`
}
func init() {
SchemeBuilder.Register(&ClusterSummary{}, &ClusterSummaryList{})
}
func GetClusterSummary(ctx context.Context, c client.Client, namespace, name string,
) (*ClusterSummary, error) {
clusterSummary := &ClusterSummary{}
err := c.Get(ctx, types.NamespacedName{Namespace: namespace, Name: name}, clusterSummary)
if err != nil {
return nil, err
}
return clusterSummary, nil
}
// GetProfileOwnerReference returns the ClusterProfile/Profile owning a given ClusterSummary
func GetProfileOwnerReference(clusterSummary *ClusterSummary) (*metav1.OwnerReference, error) {
for _, ref := range clusterSummary.OwnerReferences {
if ref.Kind != ClusterProfileKind &&
ref.Kind != ProfileKind {
continue
}
gv, err := schema.ParseGroupVersion(ref.APIVersion)
if err != nil {
return nil, errors.WithStack(err)
}
if gv.Group == GroupVersion.Group {
return &ref, nil
}
}
return nil, fmt.Errorf("(Cluster)Profile owner not found")
}
// GetProfileOwnerAndTier returns the (Cluster)Profile owning this clusterSummary and its tier.
// Returns nil if (Cluster)Profile does not exist anymore.
func GetProfileOwnerAndTier(ctx context.Context, c client.Client, clusterSummary *ClusterSummary,
) (client.Object, int32, error) {
for _, ref := range clusterSummary.OwnerReferences {
gv, err := schema.ParseGroupVersion(ref.APIVersion)
if err != nil {
return nil, 0, errors.WithStack(err)
}
if gv.Group != GroupVersion.Group {
continue
}
if ref.Kind == ClusterProfileKind {
clusterProfile := &ClusterProfile{}
err := c.Get(ctx, types.NamespacedName{Name: ref.Name}, clusterProfile)
if err != nil {
if apierrors.IsNotFound(err) {
return nil, 0, nil
}
return nil, 0, err
}
return clusterProfile, clusterProfile.Spec.Tier, nil
} else if ref.Kind == ProfileKind {
profile := &Profile{}
err := c.Get(ctx,
types.NamespacedName{Namespace: clusterSummary.Namespace, Name: ref.Name},
profile)
if err != nil {
if apierrors.IsNotFound(err) {
return nil, 0, nil
}
return nil, 0, err
}
return profile, profile.Spec.Tier, nil
}
}
return nil, 0, nil
}