Skip to content

Commit 4ef4e90

Browse files
committed
fix tests and clean up some codes.
1 parent 80d6c2f commit 4ef4e90

File tree

21 files changed

+245
-192
lines changed

21 files changed

+245
-192
lines changed

applylib/applyset/applyset.go

Lines changed: 53 additions & 58 deletions
Original file line numberDiff line numberDiff line change
@@ -94,7 +94,9 @@ func New(options Options) (*ApplySet, error) {
9494
parent := options.Parent
9595
parentRef := &kubectlapply.ApplySetParentRef{Name: parent.Name(), Namespace: parent.Namespace(), RESTMapping: parent.RESTMapping()}
9696
kapplyset := kubectlapply.NewApplySet(parentRef, kubectlapply.ApplySetTooling{Name: options.Tooling}, options.RESTMapper)
97-
options.PatchOptions.FieldManager = kapplyset.FieldManager()
97+
if options.PatchOptions.FieldManager == "" {
98+
options.PatchOptions.FieldManager = kapplyset.FieldManager()
99+
}
98100
a := &ApplySet{
99101
parentClient: options.ParentClient,
100102
client: options.Client,
@@ -176,7 +178,7 @@ func (a *ApplySet) ApplyOnce(ctx context.Context) (*ApplyResults, error) {
176178
}
177179
}
178180
if err := a.WithParent(ctx, kapplyset); err != nil {
179-
return results, fmt.Errorf("unable to update Parent %v", err)
181+
return results, fmt.Errorf("unable to update Parent: %w", err)
180182
}
181183

182184
for i := range trackers.items {
@@ -198,11 +200,11 @@ func (a *ApplySet) ApplyOnce(ctx context.Context) (*ApplyResults, error) {
198200
if restMapping == nil {
199201
// Should be impossible
200202
results.applyError(gvk, nn, fmt.Errorf("rest mapping result not found for %v", gvk))
203+
continue
201204
}
202205

203206
if err := a.updateManifestLabel(obj, kapplyset.LabelsForMember()); err != nil {
204-
klog.Errorf("unable to update label for %v/%v %v: %v", obj.GetName(), obj.GetNamespace(), gvk, err)
205-
continue
207+
return results, fmt.Errorf("unable to update label for %v/%v %v: %w", obj.GetName(), obj.GetNamespace(), gvk, err)
206208
}
207209

208210
gvr := restMapping.Resource
@@ -252,40 +254,23 @@ func (a *ApplySet) ApplyOnce(ctx context.Context) (*ApplyResults, error) {
252254
// We want to be more cautions on pruning and only do it if all manifests are applied.
253255
if a.prune && results.applyFailCount == 0 {
254256
klog.V(4).Infof("Prune is enabled")
255-
err := func() error {
256-
pruneObjects, err := kapplyset.FindAllObjectsToPrune(ctx, a.client, visitedUids)
257-
if err != nil {
258-
return err
259-
}
260-
if err = a.deleteObjects(ctx, pruneObjects, results); err != nil {
261-
return err
262-
}
263-
return nil
264-
}()
257+
pruneObjects, err := kapplyset.FindAllObjectsToPrune(ctx, a.client, visitedUids)
265258
if err != nil {
266-
klog.Errorf("encounter error on pruning %v", err)
267-
if e := a.updateParentLabelsAndAnnotations(ctx, kapplyset, "superset"); e != nil {
268-
return results, e
269-
}
259+
return results, err
260+
}
261+
if err = a.deleteObjects(ctx, pruneObjects, results); err != nil {
262+
return results, err
263+
}
264+
// "latest" mode updates the parent "applyset.kubernetes.io/contains-group-resources" annotations
265+
// to only contain the current manifest GVRs.
266+
if err := a.updateParentLabelsAndAnnotations(ctx, kapplyset, "latest"); err != nil {
267+
klog.Errorf("update parent failed %v", err)
270268
}
271-
}
272-
if err := a.updateParentLabelsAndAnnotations(ctx, kapplyset, "latest"); err != nil {
273-
klog.Errorf("update parent failed %v", err)
274269
}
275270
return results, nil
276271
}
277272

278-
func mergeMap(from, to map[string]string) map[string]string {
279-
if to == nil {
280-
to = make(map[string]string)
281-
}
282-
for k, v := range from {
283-
to[k] = v
284-
}
285-
return to
286-
}
287-
288-
// updateLabel adds the "applyset.kubernetes.io/part-of: Parent-ID" label to the manifest.
273+
// updateManifestLabel adds the "applyset.kubernetes.io/part-of: Parent-ID" label to the manifest.
289274
func (a *ApplySet) updateManifestLabel(obj ApplyableObject, applysetLabels map[string]string) error {
290275
u, ok := obj.(*unstructured.Unstructured)
291276
if !ok {
@@ -296,14 +281,14 @@ func (a *ApplySet) updateManifestLabel(obj ApplyableObject, applysetLabels map[s
296281
if labels == nil {
297282
labels = make(map[string]string)
298283
}
299-
newLabels := mergeMap(applysetLabels, labels)
300-
u.SetLabels(newLabels)
284+
for k, v := range applysetLabels {
285+
labels[k] = v
286+
}
287+
u.SetLabels(labels)
301288
return nil
302289
}
303290

304291
// updateParentLabelsAndAnnotations updates the parent labels and annotations.
305-
// This method leverages the kubectlapply to build the parent labels and annotations, but avoid using the
306-
// `resource.NewHelper` and cmdutil to patch the parent.
307292
func (a *ApplySet) updateParentLabelsAndAnnotations(ctx context.Context, kapplyset *kubectlapply.ApplySet, mode kubectlapply.ApplySetUpdateMode) error {
308293
parent, err := meta.Accessor(a.parent.GetSubject())
309294
if err != nil {
@@ -315,26 +300,46 @@ func (a *ApplySet) updateParentLabelsAndAnnotations(ctx context.Context, kapplys
315300
return err
316301
}
317302
partialParent := kapplyset.BuildParentPatch(mode)
318-
newAnnotations := mergeMap(partialParent.Annotations, parent.GetAnnotations())
319-
parent.SetAnnotations(newAnnotations)
320-
newLabels := mergeMap(partialParent.Labels, parent.GetLabels())
321-
parent.SetLabels(newLabels)
322303

323-
return a.updateParent(ctx, original, parent)
304+
// update annotation
305+
annotations := parent.GetAnnotations()
306+
if annotations == nil {
307+
annotations = make(map[string]string)
308+
}
309+
for k, v := range partialParent.Annotations {
310+
annotations[k] = v
311+
}
312+
parent.SetAnnotations(annotations)
313+
314+
// update labels
315+
labels := parent.GetLabels()
316+
if labels == nil {
317+
labels = make(map[string]string)
318+
}
319+
for k, v := range partialParent.Labels {
320+
labels[k] = v
321+
}
322+
parent.SetLabels(labels)
323+
324+
// update parent in the cluster.
325+
if !reflect.DeepEqual(original.GetLabels(), parent.GetLabels()) || !reflect.DeepEqual(original.GetAnnotations(), parent.GetAnnotations()) {
326+
if err := a.parentClient.Update(ctx, parent.(client.Object)); err != nil {
327+
return fmt.Errorf("error updating parent %w", err)
328+
}
329+
}
330+
return nil
324331
}
325332

326333
func (a *ApplySet) deleteObjects(ctx context.Context, pruneObjects []kubectlapply.PruneObject, results *ApplyResults) error {
327334
for i := range pruneObjects {
328335
pruneObject := &pruneObjects[i]
329-
330336
name := pruneObject.Name
331337
namespace := pruneObject.Namespace
332338
mapping := pruneObject.Mapping
333339
gvk := pruneObject.Object.GetObjectKind().GroupVersionKind()
334340
nn := types.NamespacedName{Namespace: namespace, Name: name}
335341

336342
if err := a.client.Resource(mapping.Resource).Namespace(namespace).Delete(ctx, name, a.deleteOptions); err != nil {
337-
klog.Error("unable to delete resource ")
338343
results.pruneError(gvk, nn, fmt.Errorf("error from delete: %w", err))
339344
} else {
340345
klog.Infof("pruned resource %v", pruneObject.String())
@@ -344,16 +349,16 @@ func (a *ApplySet) deleteObjects(ctx context.Context, pruneObjects []kubectlappl
344349
return nil
345350
}
346351

352+
// WithParent guarantees the parent has the right applyset labels.
353+
// It uses "superset" mode to determine the "applyset.kubernetes.io/contains-group-resources" which contains both
354+
//
355+
// previous manifests GVRs and the current manifests GVRs.
347356
func (a *ApplySet) WithParent(ctx context.Context, kapplyset *kubectlapply.ApplySet) error {
348357
parent := a.parent.GetSubject()
349358
object, err := meta.Accessor(parent)
350359
if err != nil {
351360
return err
352361
}
353-
original, err := meta.Accessor(parent.DeepCopyObject())
354-
if err != nil {
355-
return err
356-
}
357362
//kubectlapply requires the tooling and id to exist.
358363
{
359364
annotations := object.GetAnnotations()
@@ -378,15 +383,5 @@ func (a *ApplySet) WithParent(ctx context.Context, kapplyset *kubectlapply.Apply
378383
return err
379384
}
380385

381-
return a.updateParent(ctx, original, object)
382-
}
383-
384-
func (a *ApplySet) updateParent(ctx context.Context, original, current metav1.Object) error {
385-
if !reflect.DeepEqual(original.GetLabels(), current.GetLabels()) || !reflect.DeepEqual(original.GetAnnotations(), current.GetAnnotations()) {
386-
if err := a.parentClient.Update(ctx, current.(client.Object)); err != nil {
387-
return fmt.Errorf("error updating parent %v", err)
388-
}
389-
}
390-
klog.V(4).Infof("parent labels and annotations are not changed, skip updating")
391-
return nil
386+
return a.updateParentLabelsAndAnnotations(ctx, kapplyset, "superset")
392387
}

applylib/applyset/applyset_test.go

Lines changed: 12 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,6 @@ import (
2323

2424
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
2525
"k8s.io/apimachinery/pkg/apis/meta/v1/unstructured"
26-
"k8s.io/apimachinery/pkg/runtime/schema"
2726
"k8s.io/apimachinery/pkg/types"
2827
"sigs.k8s.io/kubebuilder-declarative-pattern/applylib/testutils"
2928
"sigs.k8s.io/yaml"
@@ -32,7 +31,14 @@ import (
3231
func TestApplySet(t *testing.T) {
3332
h := testutils.NewHarness(t)
3433

35-
existing := ``
34+
// The parent should exist in the cluster
35+
existing := `
36+
apiVersion: v1
37+
kind: ConfigMap
38+
metadata:
39+
name: test
40+
namespace: default
41+
`
3642

3743
apply := `
3844
apiVersion: v1
@@ -61,16 +67,17 @@ data:
6167

6268
force := true
6369
patchOptions.Force = &force
64-
65-
parentGVK := schema.GroupVersionKind{Group: "", Version: "v1", Kind: "ConfigMap"}
70+
parent := h.ParseObjects(existing)[0]
71+
parentGVK := parent.GroupVersionKind()
6672
restmapping, err := h.RESTMapper().RESTMapping(parentGVK.GroupKind(), parentGVK.Version)
6773
if err != nil {
6874
h.Fatalf("error building parent restmappaing: %v", err)
6975
}
7076
s, err := New(Options{
71-
Parent: NewParentRef(parentGVK, "test", "default", restmapping),
77+
Parent: NewParentRef(parent, "test", "default", restmapping),
7278
RESTMapper: h.RESTMapper(),
7379
Client: h.DynamicClient(),
80+
ParentClient: h.Client(),
7481
PatchOptions: patchOptions,
7582
DeleteOptions: metav1.DeleteOptions{},
7683
Prune: true,

applylib/applyset/testdata/testapplyset/expected.yaml

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@ apiVersion: v1
22
kind: Namespace
33
metadata:
44
labels:
5-
applyset.kubernetes.io/part-of: applyset-k3TRa7vXhJ2Gw-i5Jd_xbW5nDsiGbtAt-ocL_pzzFEE-v1
5+
applyset.kubernetes.io/part-of: applyset-XYWvxXDUlCqMdjmmY1arThcdGiF0cvBW6sAfSMWYUdE-v1
66
kubernetes.io/metadata.name: test-applyset
77
name: test-applyset
88
spec:
@@ -18,6 +18,6 @@ data:
1818
kind: ConfigMap
1919
metadata:
2020
labels:
21-
applyset.kubernetes.io/part-of: applyset-k3TRa7vXhJ2Gw-i5Jd_xbW5nDsiGbtAt-ocL_pzzFEE-v1
21+
applyset.kubernetes.io/part-of: applyset-XYWvxXDUlCqMdjmmY1arThcdGiF0cvBW6sAfSMWYUdE-v1
2222
name: foo
2323
namespace: test-applyset

pkg/patterns/declarative/metrics_test.go

Lines changed: 19 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -29,21 +29,32 @@ import (
2929
core "k8s.io/api/core/v1"
3030
"k8s.io/apimachinery/pkg/api/meta"
3131
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
32+
"k8s.io/apimachinery/pkg/apis/meta/v1/unstructured"
33+
"k8s.io/apimachinery/pkg/runtime"
3234
"k8s.io/apimachinery/pkg/runtime/schema"
3335
"k8s.io/apimachinery/pkg/types"
3436
"k8s.io/client-go/dynamic"
3537
"k8s.io/client-go/rest"
3638
"k8s.io/klog/v2"
39+
"sigs.k8s.io/controller-runtime/pkg/client/fake"
3740
"sigs.k8s.io/controller-runtime/pkg/manager"
3841
"sigs.k8s.io/controller-runtime/pkg/reconcile"
3942
"sigs.k8s.io/kubebuilder-declarative-pattern/applylib/applyset"
4043
"sigs.k8s.io/kubebuilder-declarative-pattern/mockkubeapiserver"
4144
"sigs.k8s.io/kubebuilder-declarative-pattern/pkg/patterns/declarative/pkg/applier"
4245
"sigs.k8s.io/kubebuilder-declarative-pattern/pkg/patterns/declarative/pkg/manifest"
43-
"sigs.k8s.io/kubebuilder-declarative-pattern/pkg/restmapper"
4446
"sigs.k8s.io/yaml"
4547
)
4648

49+
func fakeParent() runtime.Object {
50+
parent := &unstructured.Unstructured{}
51+
parent.SetKind("ConfigMap")
52+
parent.SetAPIVersion("v1")
53+
parent.SetName("test")
54+
parent.SetNamespace("default")
55+
return parent
56+
}
57+
4758
// This test checks gvkString function
4859
func TestGVKString(t *testing.T) {
4960
testCases := []struct {
@@ -263,11 +274,6 @@ func TestAddIfNotPresent(t *testing.T) {
263274
Host: addr.String(),
264275
}
265276

266-
restMapper, err := restmapper.NewControllerRESTMapper(restConfig)
267-
if err != nil {
268-
t.Fatalf("error getting rest mapper: %v", err)
269-
}
270-
271277
// Create manager
272278
mgrOpt := manager.Options{
273279
MetricsBindAddress: "0", // Don't open unneeded ports
@@ -527,16 +533,19 @@ func TestAddIfNotPresent(t *testing.T) {
527533
var options applier.ApplierOptions
528534
options.Namespace = st.defaultNamespace
529535
options.Objects = objList
530-
options.RESTMapper = restMapper
536+
options.RESTMapper = mgr.GetRESTMapper()
531537
options.RESTConfig = restConfig
532-
gvk := schema.GroupVersionKind{Group: "", Version: "v1", Kind: "ConfigMap"}
538+
parent := fakeParent()
539+
options.Client = fake.NewClientBuilder().WithRuntimeObjects(parent).Build()
540+
gvk := parent.GetObjectKind().GroupVersionKind()
533541
restmapping, err := options.RESTMapper.RESTMapping(gvk.GroupKind(), gvk.Version)
534542
if err != nil {
535543
t.Fatalf("failed to get restmapping for parent: %v", err)
536544
}
537-
options.ParentRef = applyset.NewParentRef(gvk, "kdp-test", "default", restmapping)
545+
options.ParentRef = applyset.NewParentRef(parent, "kdp-test", "default", restmapping)
538546
applier := applier.NewApplySetApplier(
539547
metav1.PatchOptions{FieldManager: "kdp-test"}, metav1.DeleteOptions{}, applier.ApplysetOptions{})
548+
540549
if err := applier.Apply(ctx, options); err != nil {
541550
t.Fatalf("failed to apply objects: %v", err)
542551
}
@@ -546,7 +555,7 @@ func TestAddIfNotPresent(t *testing.T) {
546555
t.Fatalf("error parsing manifest: %v", err)
547556
}
548557

549-
if err := deleteObjects(ctx, restConfig, restMapper, st.defaultNamespace, objects); err != nil {
558+
if err := deleteObjects(ctx, restConfig, mgr.GetRESTMapper(), st.defaultNamespace, objects); err != nil {
550559
t.Fatalf("error deleting objects: %v", err)
551560
}
552561
} else {

pkg/patterns/declarative/pkg/applier/applylib.go

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -125,11 +125,11 @@ func (a *ApplySetApplier) Apply(ctx context.Context, opt ApplierOptions) error {
125125
}
126126

127127
// NewParentRef maps a declarative object's information to the ParentRef defined in the applyset library.
128-
func NewParentRef(restMapper meta.RESTMapper, object runtime.Object, name, namespace string) applyset.Parent {
128+
func NewParentRef(restMapper meta.RESTMapper, object runtime.Object, name, namespace string) (applyset.Parent, error) {
129129
gvk := object.GetObjectKind().GroupVersionKind()
130130
restMapping, err := restMapper.RESTMapping(gvk.GroupKind(), gvk.Version)
131131
if err != nil {
132-
return nil
132+
return nil, err
133133
}
134-
return applyset.NewParentRef(object, name, namespace, restMapping)
134+
return applyset.NewParentRef(object, name, namespace, restMapping), nil
135135
}

0 commit comments

Comments
 (0)