Skip to content

Commit

Permalink
Add Generation variants of kmeta/labels.go (#117)
Browse files Browse the repository at this point in the history
Unlike `ResourceVersion`, which changes whenever the resource changes at all (including `/status` which can be high churn), `Generation` only changes when the `/spec` of a CRD changes (for CRDs starting in 1.11, right now they are locked at `generation: 1`).

These methods are useful for interacting with K8s resource now, and will be useful for CRDs soon.

Fixes: #116
  • Loading branch information
mattmoor authored and knative-prow-robot committed Oct 8, 2018
1 parent 1f15381 commit 1a50a39
Show file tree
Hide file tree
Showing 2 changed files with 131 additions and 0 deletions.
38 changes: 38 additions & 0 deletions kmeta/labels.go
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,13 @@ import (

// The methods in this file are used for managing subresources in cases where
// a controller instantiates different resources for each version of itself.
// There are two sets of methods available here:
// * `*VersionLabel*`: these methods act on `metadata.resourceVersion` and
// create new labels for EVERY change to the resource (incl. `/status`).
// * `*GenerationLabel*`: these methods act on `metadata.generation` and
// create new labels for changes to the resource's "spec" (typically, but
// some K8s resources change `metadata.generation` for annotations as well
// e.g. Deployment).
//
// For example, if an A might instantiate N B's at version 1 and M B's at
// version 2 then it can use MakeVersionLabels to decorate each subresource
Expand Down Expand Up @@ -66,6 +73,37 @@ func MakeOldVersionLabelSelector(om metav1.ObjectMetaAccessor) labels.Selector {
)
}

// MakeGenerationLabels constructs a set of labels to apply to subresources
// instantiated at this version of the parent resource, so that we can
// efficiently select them.
func MakeGenerationLabels(om metav1.ObjectMetaAccessor) labels.Set {
return map[string]string{
"controller": string(om.GetObjectMeta().GetUID()),
"generation": genStr(om),
}
}

// MakeGenerationLabelSelector constructs a selector for subresources
// instantiated at this version of the parent resource. This keys
// off of the labels populated by MakeGenerationLabels.
func MakeGenerationLabelSelector(om metav1.ObjectMetaAccessor) labels.Selector {
return labels.SelectorFromSet(MakeGenerationLabels(om))
}

// MakeOldGenerationLabelSelector constructs a selector for subresources
// instantiated at an older version of the parent resource. This keys
// off of the labels populated by MakeGenerationLabels.
func MakeOldGenerationLabelSelector(om metav1.ObjectMetaAccessor) labels.Selector {
return labels.NewSelector().Add(
mustNewRequirement("controller", selection.Equals, []string{string(om.GetObjectMeta().GetUID())}),
mustNewRequirement("generation", selection.NotEquals, []string{genStr(om)}),
)
}

func genStr(om metav1.ObjectMetaAccessor) string {
return fmt.Sprintf("%05d", om.GetObjectMeta().GetGeneration())
}

// mustNewRequirement panics if there are any errors constructing our selectors.
func mustNewRequirement(key string, op selection.Operator, vals []string) labels.Requirement {
r, err := labels.NewRequirement(key, op, vals)
Expand Down
93 changes: 93 additions & 0 deletions kmeta/labels_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -114,3 +114,96 @@ func TestMakeOldVersionLabelSelector(t *testing.T) {
})
}
}

func TestMakeGenerationLabels(t *testing.T) {
tests := []struct {
name string
om metav1.ObjectMeta
s string
}{{
name: "simple translation",
om: metav1.ObjectMeta{
UID: "1234",
Generation: 5,
},
s: "controller=1234,generation=00005",
}, {
name: "another simple translation",
om: metav1.ObjectMeta{
UID: "abcd",
Generation: 5432,
},
s: "controller=abcd,generation=05432",
}}

for _, test := range tests {
t.Run(test.name, func(t *testing.T) {
ls := MakeGenerationLabels(&test.om)
if want, got := test.s, ls.String(); got != want {
t.Errorf("MakeGenerationLabels() = %v, wanted %v", got, want)
}
})
}
}

func TestMakeGenerationLabelSelector(t *testing.T) {
tests := []struct {
name string
om metav1.ObjectMeta
s string
}{{
name: "simple translation",
om: metav1.ObjectMeta{
UID: "1234",
Generation: 5,
},
s: "controller=1234,generation=00005",
}, {
name: "another simple translation",
om: metav1.ObjectMeta{
UID: "abcd",
Generation: 5432,
},
s: "controller=abcd,generation=05432",
}}

for _, test := range tests {
t.Run(test.name, func(t *testing.T) {
ls := MakeGenerationLabelSelector(&test.om)
if want, got := test.s, ls.String(); got != want {
t.Errorf("MakeGenerationLabelSelector() = %v, wanted %v", got, want)
}
})
}
}

func TestMakeOldGenerationLabelSelector(t *testing.T) {
tests := []struct {
name string
om metav1.ObjectMeta
s string
}{{
name: "simple translation",
om: metav1.ObjectMeta{
UID: "1234",
Generation: 5,
},
s: "controller=1234,generation!=00005",
}, {
name: "another simple translation",
om: metav1.ObjectMeta{
UID: "abcd",
Generation: 5432,
},
s: "controller=abcd,generation!=05432",
}}

for _, test := range tests {
t.Run(test.name, func(t *testing.T) {
ls := MakeOldGenerationLabelSelector(&test.om)
if want, got := test.s, ls.String(); got != want {
t.Errorf("MakeOldGenerationLabelSelector() = %v, wanted %v", got, want)
}
})
}
}

0 comments on commit 1a50a39

Please sign in to comment.