Skip to content

Commit

Permalink
add support to set labels without selector
Browse files Browse the repository at this point in the history
  • Loading branch information
Mrflatt committed Aug 30, 2024
1 parent 27d508f commit 54e367b
Show file tree
Hide file tree
Showing 3 changed files with 123 additions and 4 deletions.
2 changes: 1 addition & 1 deletion kustomize/commands/edit/add/addmetadata.go
Original file line number Diff line number Diff line change
Expand Up @@ -70,7 +70,7 @@ func newCmdAddLabel(fSys filesys.FileSystem, v func(map[string]string) error) *c
o.mapValidator = v
cmd := &cobra.Command{
Use: "label",
Short: "Adds one or more commonLabels to " +
Short: "Adds one or more commonLabels or labels to " +
konfig.DefaultKustomizationFileName(),
Example: `
add label {labelKey1:labelValue1} {labelKey2:labelValue2}`,
Expand Down
66 changes: 63 additions & 3 deletions kustomize/commands/edit/set/setlabel.go
Original file line number Diff line number Diff line change
Expand Up @@ -15,8 +15,10 @@ import (
)

type setLabelOptions struct {
metadata map[string]string
mapValidator func(map[string]string) error
metadata map[string]string
mapValidator func(map[string]string) error
labelsWithoutSelector bool
includeTemplates bool
}

// newCmdSetLabel sets one or more commonLabels to the kustomization file.
Expand All @@ -25,14 +27,20 @@ func newCmdSetLabel(fSys filesys.FileSystem, v func(map[string]string) error) *c
o.mapValidator = v
cmd := &cobra.Command{
Use: "label",
Short: "Sets one or more commonLabels in " +
Short: "Sets one or more commonLabels or labels in " +
konfig.DefaultKustomizationFileName(),
Example: `
set label {labelKey1:labelValue1} {labelKey2:labelValue2}`,
RunE: func(cmd *cobra.Command, args []string) error {
return o.runE(args, fSys, o.setLabels)
},
}
cmd.Flags().BoolVar(&o.labelsWithoutSelector, "without-selector", false,
"using set labels without selector option",
)
cmd.Flags().BoolVar(&o.includeTemplates, "include-templates", false,
"include labels in templates (requires --without-selector)",
)
return cmd
}

Expand Down Expand Up @@ -62,6 +70,9 @@ func (o *setLabelOptions) validateAndParse(args []string) error {
if len(args) < 1 {
return fmt.Errorf("must specify label")
}
if !o.labelsWithoutSelector && o.includeTemplates {
return fmt.Errorf("--without-selector flag must be specified for --include-templates to work")
}
m, err := util.ConvertSliceToMap(args, "label")
if err != nil {
return err
Expand All @@ -74,9 +85,36 @@ func (o *setLabelOptions) validateAndParse(args []string) error {
}

func (o *setLabelOptions) setLabels(m *types.Kustomization) error {
if o.labelsWithoutSelector {
o.removeDuplicateLabels(m)

var labelPairs *types.Label
for _, label := range m.Labels {
if !label.IncludeSelectors && label.IncludeTemplates == o.includeTemplates {
labelPairs = &label
break
}
}

if labelPairs != nil {
if labelPairs.Pairs == nil {
labelPairs.Pairs = make(map[string]string)
}
return o.writeToMap(labelPairs.Pairs)
}

m.Labels = append(m.Labels, types.Label{
Pairs: make(map[string]string),
IncludeSelectors: false,
IncludeTemplates: o.includeTemplates,
})
return o.writeToMap(m.Labels[len(m.Labels)-1].Pairs)
}

if m.CommonLabels == nil {
m.CommonLabels = make(map[string]string)
}

return o.writeToMap(m.CommonLabels)
}

Expand All @@ -86,3 +124,25 @@ func (o *setLabelOptions) writeToMap(m map[string]string) error {
}
return nil
}

func (o *setLabelOptions) removeDuplicateLabels(m *types.Kustomization) {
for k := range o.metadata {
delete(m.CommonLabels, k)
for idx, label := range m.Labels {
if label.IncludeTemplates != o.includeTemplates {
m.Labels = deleteLabel(k, label, m.Labels, idx)
}
if label.IncludeSelectors {
m.Labels = deleteLabel(k, label, m.Labels, idx)
}
}
}
}

func deleteLabel(key string, label types.Label, labels []types.Label, idx int) []types.Label {
delete(label.Pairs, key)
if len(label.Pairs) == 0 {
labels = append(labels[:idx], labels[idx+1:]...)
}
return labels
}
59 changes: 59 additions & 0 deletions kustomize/commands/edit/set/setlabel_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,8 @@ package set
import (
"testing"

"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
valtest_test "sigs.k8s.io/kustomize/api/testutils/valtest"
"sigs.k8s.io/kustomize/api/types"
"sigs.k8s.io/kustomize/kustomize/v5/commands/internal/kustfile"
Expand Down Expand Up @@ -152,3 +154,60 @@ func TestSetLabelExisting(t *testing.T) {
t.Errorf("unexpected error: %v", err.Error())
}
}

func TestSetLabelWithoutSelector(t *testing.T) {
var o setLabelOptions
o.metadata = map[string]string{"key1": "foo", "key2": "bar"}
o.labelsWithoutSelector = true

m := makeKustomization(t)
require.NoError(t, o.setLabels(m))
assert.Equal(t, m.Labels[0], types.Label{Pairs: map[string]string{"key1": "foo", "key2": "bar"}})
}

func TestSetLabelWithoutSelectorWithExistingLabels(t *testing.T) {
var o setLabelOptions
o.metadata = map[string]string{"key1": "foo", "key2": "bar"}
o.labelsWithoutSelector = true

m := makeKustomization(t)
require.NoError(t, o.setLabels(m))
assert.Equal(t, m.Labels[0], types.Label{Pairs: map[string]string{"key1": "foo", "key2": "bar"}})

o.metadata = map[string]string{"key3": "foobar"}
require.NoError(t, o.setLabels(m))
assert.Equal(t, m.Labels[0], types.Label{Pairs: map[string]string{"key1": "foo", "key2": "bar", "key3": "foobar"}})
}

func TestSetLabelWithoutSelectorWithDuplicateLabel(t *testing.T) {
var o setLabelOptions
o.metadata = map[string]string{"key1": "foo", "key2": "bar"}
o.labelsWithoutSelector = true
o.includeTemplates = true

m := makeKustomization(t)
require.NoError(t, o.setLabels(m))
assert.Equal(t, m.Labels[0], types.Label{Pairs: map[string]string{"key1": "foo", "key2": "bar"}, IncludeTemplates: true})

o.metadata = map[string]string{"key2": "bar"}
o.includeTemplates = false
require.NoError(t, o.setLabels(m))
assert.Equal(t, m.Labels[0], types.Label{Pairs: map[string]string{"key1": "foo"}, IncludeTemplates: true})
assert.Equal(t, m.Labels[1], types.Label{Pairs: map[string]string{"key2": "bar"}})
}

func TestSetLabelWithoutSelectorWithCommonLabel(t *testing.T) {
var o setLabelOptions
o.metadata = map[string]string{"key1": "foo", "key2": "bar"}

m := makeKustomization(t)
require.NoError(t, o.setLabels(m))
assert.Empty(t, m.Labels)
assert.Equal(t, m.CommonLabels, map[string]string{"app": "helloworld", "key1": "foo", "key2": "bar"})

o.metadata = map[string]string{"key2": "bar"}
o.labelsWithoutSelector = true
require.NoError(t, o.setLabels(m))
assert.Equal(t, m.CommonLabels, map[string]string{"app": "helloworld", "key1": "foo"})
assert.Equal(t, m.Labels[0], types.Label{Pairs: map[string]string{"key2": "bar"}})
}

0 comments on commit 54e367b

Please sign in to comment.