Skip to content

Commit b0f0164

Browse files
authored
Merge pull request #565 from gianlucam76/referenced-resource-order
(feat) Add referenced resource data as annotations
2 parents b9a199d + 1256d68 commit b0f0164

File tree

5 files changed

+187
-63
lines changed

5 files changed

+187
-63
lines changed

lib/deployer/applier.go

Lines changed: 10 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -245,8 +245,8 @@ func CustomSplit(text string) ([]string, error) {
245245

246246
// GetResource returns sveltos Resource and the resource hash
247247
func GetResource(policy *unstructured.Unstructured, ignoreForConfigurationDrift bool,
248-
referencedObject *corev1.ObjectReference, profile client.Object, tier int32, featureID string,
249-
logger logr.Logger) (resource *libsveltosv1beta1.Resource, policyHash string) {
248+
referencedObject *corev1.ObjectReference, profile client.Object, profileTier, referenceTier int32,
249+
featureID string, logger logr.Logger) (resource *libsveltosv1beta1.Resource, policyHash string) {
250250

251251
resource = &libsveltosv1beta1.Resource{
252252
Name: policy.GetName(),
@@ -265,12 +265,13 @@ func GetResource(policy *unstructured.Unstructured, ignoreForConfigurationDrift
265265
}
266266

267267
// Get policy hash of referenced policy
268-
AddLabel(policy, ReferenceKindLabel, referencedObject.GetObjectKind().GroupVersionKind().Kind)
269-
AddLabel(policy, ReferenceNameLabel, referencedObject.Name)
270-
AddLabel(policy, ReferenceNamespaceLabel, referencedObject.Namespace)
271268
AddLabel(policy, ReasonLabel, featureID)
269+
AddAnnotation(policy, ReferenceKindAnnotation, referencedObject.GetObjectKind().GroupVersionKind().Kind)
270+
AddAnnotation(policy, ReferenceNameAnnotation, referencedObject.Name)
271+
AddAnnotation(policy, ReferenceNamespaceAnnotation, referencedObject.Namespace)
272+
AddAnnotation(policy, ReferenceTierAnnotation, fmt.Sprintf("%d", referenceTier))
272273
AddAnnotation(policy, PolicyHash, policyHash)
273-
AddAnnotation(policy, OwnerTier, fmt.Sprintf("%d", tier))
274+
AddAnnotation(policy, OwnerTier, fmt.Sprintf("%d", profileTier))
274275
AddAnnotation(policy, OwnerName, profile.GetName())
275276
AddAnnotation(policy, OwnerKind, profile.GetObjectKind().GroupVersionKind().Kind)
276277

@@ -358,13 +359,13 @@ func AddAnnotation(obj metav1.Object, annotationKey, annotationValue string) {
358359
// If resource cannot be deployed, return a ConflictError.
359360
// If any other error occurs while doing those verification, the error is returned
360361
func CanDeployResource(ctx context.Context, dr dynamic.ResourceInterface, policy *unstructured.Unstructured,
361-
referencedObject *corev1.ObjectReference, profile client.Object, profileTier int32, logger logr.Logger,
362-
) (resourceInfo *ResourceInfo, requeueOldOwner bool, err error) {
362+
referencedObject *corev1.ObjectReference, profile client.Object, profileTier, referenceTier int32,
363+
logger logr.Logger) (resourceInfo *ResourceInfo, requeueOldOwner bool, err error) {
363364

364365
l := logger.WithValues("resource",
365366
fmt.Sprintf("%s:%s/%s", referencedObject.Kind, referencedObject.Namespace, referencedObject.Name))
366367
resourceInfo, err = ValidateObjectForUpdate(ctx, dr, policy,
367-
referencedObject.Kind, referencedObject.Namespace, referencedObject.Name, profile)
368+
referencedObject.Kind, referencedObject.Namespace, referencedObject.Name, referenceTier, profile)
368369
if err != nil {
369370
var conflictErr *ConflictError
370371
ok := errors.As(err, &conflictErr)

lib/deployer/clean.go

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -37,7 +37,8 @@ func UndeployStaleResource(ctx context.Context, skipAnnotationKey, skipAnnotatio
3737

3838
// Verify if this policy was deployed because of a projectsveltos (ReferenceLabelName
3939
// is present as label in such a case).
40-
if !hasLabel(&r, ReferenceNameLabel, "") {
40+
// Check both labels (this used to be set) and annotations (this is what gets set now)
41+
if !hasLabel(&r, ReferenceNameLabel, "") && !hasAnnotation(&r, ReferenceNameAnnotation, "") {
4142
return nil, nil
4243
}
4344

@@ -115,13 +116,19 @@ func handleResourceDelete(ctx context.Context, c client.Client, policy client.Ob
115116
// If mode is set to LeavePolicies, leave policies in the workload cluster.
116117
// Remove all labels added by Sveltos.
117118
if leavePolicies {
119+
// for backward compatibility (those labels used to be set, but are now
120+
// replaced by corresponding annotations)
118121
l := policy.GetLabels()
119122
delete(l, ReferenceKindLabel)
120123
delete(l, ReferenceNameLabel)
121124
delete(l, ReferenceNamespaceLabel)
122125
policy.SetLabels(l)
123126

124127
annotations := policy.GetAnnotations()
128+
delete(annotations, ReferenceKindAnnotation)
129+
delete(annotations, ReferenceNameAnnotation)
130+
delete(annotations, ReferenceNamespaceAnnotation)
131+
delete(annotations, ReferenceTierAnnotation)
125132
delete(annotations, OwnerKind)
126133
delete(annotations, OwnerName)
127134
delete(annotations, OwnerTier)

lib/deployer/clean_test.go

Lines changed: 17 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -42,11 +42,14 @@ var _ = Describe("Clean utils", func() {
4242
ObjectMeta: metav1.ObjectMeta{
4343
Namespace: randomString(),
4444
Name: randomString(),
45+
Annotations: map[string]string{
46+
deployer.ReferenceKindAnnotation: randomString(),
47+
deployer.ReferenceNameAnnotation: randomString(),
48+
deployer.ReferenceNamespaceAnnotation: randomString(),
49+
randomKey: randomValue,
50+
},
4551
Labels: map[string]string{
46-
deployer.ReferenceKindLabel: randomString(),
47-
deployer.ReferenceNameLabel: randomString(),
48-
deployer.ReferenceNamespaceLabel: randomString(),
49-
randomKey: randomValue,
52+
randomKey: randomValue,
5053
},
5154
},
5255
}
@@ -61,8 +64,12 @@ var _ = Describe("Clean utils", func() {
6164

6265
currentDepl := &appsv1.Deployment{}
6366
Expect(c.Get(context.TODO(), types.NamespacedName{Namespace: depl.Namespace, Name: depl.Name}, currentDepl)).To(Succeed())
67+
Expect(len(currentDepl.Annotations)).To(Equal(1))
68+
v, ok := currentDepl.Annotations[randomKey]
69+
Expect(ok).To(BeTrue())
70+
Expect(v).To(Equal(randomValue))
6471
Expect(len(currentDepl.Labels)).To(Equal(1))
65-
v, ok := currentDepl.Labels[randomKey]
72+
v, ok = currentDepl.Labels[randomKey]
6673
Expect(ok).To(BeTrue())
6774
Expect(v).To(Equal(randomValue))
6875
})
@@ -74,11 +81,11 @@ var _ = Describe("Clean utils", func() {
7481
ObjectMeta: metav1.ObjectMeta{
7582
Namespace: randomString(),
7683
Name: randomString(),
77-
Labels: map[string]string{
78-
deployer.ReferenceKindLabel: randomString(),
79-
deployer.ReferenceNameLabel: randomString(),
80-
deployer.ReferenceNamespaceLabel: randomString(),
81-
randomKey: randomValue,
84+
Annotations: map[string]string{
85+
deployer.ReferenceKindAnnotation: randomString(),
86+
deployer.ReferenceNameAnnotation: randomString(),
87+
deployer.ReferenceNamespaceAnnotation: randomString(),
88+
randomKey: randomValue,
8289
},
8390
},
8491
}

lib/deployer/utils.go

Lines changed: 82 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@ package deployer
1919
import (
2020
"context"
2121
"fmt"
22+
"strconv"
2223
"strings"
2324

2425
corev1 "k8s.io/api/core/v1"
@@ -32,21 +33,44 @@ import (
3233
)
3334

3435
const (
35-
// ReferenceLabelKind is added to each policy deployed by a ClusterSummary
36+
// ReferenceKindLabel is added to each policy deployed by a ClusterSummary
3637
// instance to a managed Cluster. Indicates the Kind (ConfigMap or Secret)
3738
// containing the policy.
39+
// Deprecated: replaced by annotation
3840
ReferenceKindLabel = "projectsveltos.io/reference-kind"
3941

4042
// ReferenceNameLabel is added to each policy deployed by a ClusterSummary
4143
// instance to a managed Cluster. Indicates the name of the ConfigMap/Secret
4244
// containing the policy.
45+
// Deprecated: replaced by annotation
4346
ReferenceNameLabel = "projectsveltos.io/reference-name"
4447

4548
// ReferenceNamespaceLabel is added to each policy deployed by a ClusterSummary
4649
// instance to a managed Cluster. Indicates the namespace of the ConfigMap/Secret
4750
// containing the policy.
51+
// Deprecated: replaced by annotation
4852
ReferenceNamespaceLabel = "projectsveltos.io/reference-namespace"
4953

54+
// ReferenceKindAnnotation is added to each policy deployed by a ClusterSummary
55+
// instance to a managed Cluster. Indicates the Kind (ConfigMap or Secret)
56+
// containing the policy.
57+
ReferenceKindAnnotation = "projectsveltos.io/reference-kind"
58+
59+
// ReferenceNameAnnotation is added to each policy deployed by a ClusterSummary
60+
// instance to a managed Cluster. Indicates the name of the ConfigMap/Secret
61+
// containing the policy.
62+
ReferenceNameAnnotation = "projectsveltos.io/reference-name"
63+
64+
// ReferenceNamespaceAnnotation is added to each policy deployed by a ClusterSummary
65+
// instance to a managed Cluster. Indicates the namespace of the ConfigMap/Secret
66+
// containing the policy.
67+
ReferenceNamespaceAnnotation = "projectsveltos.io/reference-namespace"
68+
69+
// ReferenceTierAnnotation is added to each policy deployed by a ClusterSummary
70+
// instance to a managed Cluster. Indicates the namespace of the ConfigMap/Secret
71+
// containing the policy.
72+
ReferenceTierAnnotation = "projectsveltos.io/reference-tier"
73+
5074
// PolicyHash is the annotation set on a policy when deployed in a managed
5175
// cluster.
5276
PolicyHash = "projectsveltos.io/hash"
@@ -129,7 +153,7 @@ func (r *ResourceInfo) GetResourceVersion() string {
129153
// If object exists, return value of PolicyHash annotation.
130154
func ValidateObjectForUpdate(ctx context.Context, dr dynamic.ResourceInterface,
131155
object *unstructured.Unstructured, referenceKind, referenceNamespace, referenceName string,
132-
profile client.Object) (*ResourceInfo, error) {
156+
referenceTier int32, profile client.Object) (*ResourceInfo, error) {
133157

134158
if object == nil {
135159
return nil, nil
@@ -154,40 +178,27 @@ func ValidateObjectForUpdate(ctx context.Context, dr dynamic.ResourceInterface,
154178
}
155179
}
156180

157-
if labels := currentObject.GetLabels(); labels != nil {
158-
kind, kindOk := labels[ReferenceKindLabel]
159-
namespace, namespaceOk := labels[ReferenceNamespaceLabel]
160-
name, nameOk := labels[ReferenceNameLabel]
181+
kind, namespace, name, tier := getReferenceInfo(currentObject)
161182

162-
if kindOk {
183+
// if proposed tier is lower than current tier, do not check for conflict on referenced resource.
184+
if referenceTier >= tier {
185+
if kind != "" {
163186
if kind != referenceKind {
164187
return resourceInfo, &ConflictError{
165188
message: fmt.Sprintf("A conflict was detected while deploying resource %s:%s/%s. %s"+
166189
"This resource is currently deployed because of %s %s/%s.\n",
167190
object.GroupVersionKind().Kind, object.GetNamespace(), object.GetName(),
168191
getOwnerMessage(currentObject), kind, namespace, name)}
169192
}
170-
}
171-
if namespaceOk {
193+
172194
if namespace != referenceNamespace {
173195
return resourceInfo, &ConflictError{
174196
message: fmt.Sprintf("A conflict was detected while deploying resource %s:%s/%s. %s"+
175197
"This resource is currently deployed because of %s %s/%s.\n",
176198
object.GroupVersionKind().Kind, object.GetNamespace(), object.GetName(),
177199
getOwnerMessage(currentObject), kind, namespace, name)}
178200
}
179-
}
180-
if nameOk {
181-
if name != referenceName {
182-
return resourceInfo, &ConflictError{
183-
message: fmt.Sprintf("A conflict was detected while deploying resource %s:%s/%s. %s"+
184-
"This resource is currently deployed because of %s %s/%s.\n",
185-
object.GroupVersionKind().Kind, object.GetNamespace(), object.GetName(),
186-
getOwnerMessage(currentObject), kind, namespace, name)}
187-
}
188-
}
189201

190-
if nameOk {
191202
if name != referenceName {
192203
return resourceInfo, &ConflictError{
193204
message: fmt.Sprintf("A conflict was detected while deploying resource %s:%s/%s. %s"+
@@ -196,11 +207,11 @@ func ValidateObjectForUpdate(ctx context.Context, dr dynamic.ResourceInterface,
196207
getOwnerMessage(currentObject), kind, namespace, name)}
197208
}
198209
}
210+
}
199211

200-
err := validateSveltosOwner(object, currentObject, profile, kind, namespace, name)
201-
if err != nil {
202-
return resourceInfo, &ConflictError{message: err.Error()}
203-
}
212+
err = validateSveltosOwner(object, currentObject, profile, kind, namespace, name)
213+
if err != nil {
214+
return resourceInfo, &ConflictError{message: err.Error()}
204215
}
205216

206217
// Only in case object exists and there are no conflicts, return hash
@@ -211,6 +222,53 @@ func ValidateObjectForUpdate(ctx context.Context, dr dynamic.ResourceInterface,
211222
return resourceInfo, nil
212223
}
213224

225+
// getReferenceInfo extracts the kind, namespace, and name from object annotations
226+
// and falls back to labels if the annotations are missing or the annotation map is nil.
227+
func getReferenceInfo(object *unstructured.Unstructured) (kind, namespace, name string, tier int32) {
228+
// 1. Attempt to get info from Annotations
229+
annotations := object.GetAnnotations()
230+
if annotations != nil {
231+
kind = annotations[ReferenceKindAnnotation]
232+
namespace = annotations[ReferenceNamespaceAnnotation]
233+
name = annotations[ReferenceNameAnnotation]
234+
235+
const defaultTier = 100
236+
tier := int32(defaultTier)
237+
tierStr, tierOk := annotations[ReferenceTierAnnotation]
238+
if tierOk {
239+
tier64, err := strconv.ParseInt(tierStr, 10, 32)
240+
if err == nil {
241+
tier = int32(tier64)
242+
}
243+
// If ParseInt fails, 'tier' remains the DefaultTier (100)
244+
}
245+
246+
// If we found the kind, we assume the annotation set is complete enough.
247+
if kind != "" {
248+
return kind, namespace, name, tier
249+
}
250+
}
251+
252+
// 2. Fallback to Labels if annotations were nil OR kind was not found in annotations
253+
labels := object.GetLabels()
254+
if labels != nil {
255+
var kindOk bool
256+
257+
// NOTE: You had a bug in your original prompt's fallback logic where it
258+
// still referenced 'annotations'. This is corrected here to use 'labels'.
259+
kind, kindOk = labels[ReferenceKindLabel]
260+
namespace = labels[ReferenceNamespaceLabel]
261+
name = labels[ReferenceNameLabel]
262+
263+
if kindOk {
264+
return kind, namespace, name, tier
265+
}
266+
}
267+
268+
// 3. Info not found
269+
return "", "", "", tier
270+
}
271+
214272
func validateSveltosOwner(object, currentObject *unstructured.Unstructured, profile client.Object,
215273
kind, namespace, name string) error {
216274

0 commit comments

Comments
 (0)