Skip to content

Commit 8e26470

Browse files
authored
feat: add support for matchExpressions when filtering for nodes (#1697)
* feat: add support for matchExpressions when filtering for nodes * fix: make generate
1 parent 6e5db6d commit 8e26470

10 files changed

+334
-12
lines changed

config/crds/troubleshoot.sh_analyzers.yaml

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1186,6 +1186,36 @@ spec:
11861186
type: string
11871187
selector:
11881188
properties:
1189+
matchExpressions:
1190+
items:
1191+
description: |-
1192+
A label selector requirement is a selector that contains values, a key, and an operator that
1193+
relates the key and values.
1194+
properties:
1195+
key:
1196+
description: key is the label key that the
1197+
selector applies to.
1198+
type: string
1199+
operator:
1200+
description: |-
1201+
operator represents a key's relationship to a set of values.
1202+
Valid operators are In, NotIn, Exists and DoesNotExist.
1203+
type: string
1204+
values:
1205+
description: |-
1206+
values is an array of string values. If the operator is In or NotIn,
1207+
the values array must be non-empty. If the operator is Exists or DoesNotExist,
1208+
the values array must be empty. This array is replaced during a strategic
1209+
merge patch.
1210+
items:
1211+
type: string
1212+
type: array
1213+
x-kubernetes-list-type: atomic
1214+
required:
1215+
- key
1216+
- operator
1217+
type: object
1218+
type: array
11891219
matchLabel:
11901220
additionalProperties:
11911221
type: string

config/crds/troubleshoot.sh_preflights.yaml

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1186,6 +1186,36 @@ spec:
11861186
type: string
11871187
selector:
11881188
properties:
1189+
matchExpressions:
1190+
items:
1191+
description: |-
1192+
A label selector requirement is a selector that contains values, a key, and an operator that
1193+
relates the key and values.
1194+
properties:
1195+
key:
1196+
description: key is the label key that the
1197+
selector applies to.
1198+
type: string
1199+
operator:
1200+
description: |-
1201+
operator represents a key's relationship to a set of values.
1202+
Valid operators are In, NotIn, Exists and DoesNotExist.
1203+
type: string
1204+
values:
1205+
description: |-
1206+
values is an array of string values. If the operator is In or NotIn,
1207+
the values array must be non-empty. If the operator is Exists or DoesNotExist,
1208+
the values array must be empty. This array is replaced during a strategic
1209+
merge patch.
1210+
items:
1211+
type: string
1212+
type: array
1213+
x-kubernetes-list-type: atomic
1214+
required:
1215+
- key
1216+
- operator
1217+
type: object
1218+
type: array
11891219
matchLabel:
11901220
additionalProperties:
11911221
type: string

config/crds/troubleshoot.sh_supportbundles.yaml

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1217,6 +1217,36 @@ spec:
12171217
type: string
12181218
selector:
12191219
properties:
1220+
matchExpressions:
1221+
items:
1222+
description: |-
1223+
A label selector requirement is a selector that contains values, a key, and an operator that
1224+
relates the key and values.
1225+
properties:
1226+
key:
1227+
description: key is the label key that the
1228+
selector applies to.
1229+
type: string
1230+
operator:
1231+
description: |-
1232+
operator represents a key's relationship to a set of values.
1233+
Valid operators are In, NotIn, Exists and DoesNotExist.
1234+
type: string
1235+
values:
1236+
description: |-
1237+
values is an array of string values. If the operator is In or NotIn,
1238+
the values array must be non-empty. If the operator is Exists or DoesNotExist,
1239+
the values array must be empty. This array is replaced during a strategic
1240+
merge patch.
1241+
items:
1242+
type: string
1243+
type: array
1244+
x-kubernetes-list-type: atomic
1245+
required:
1246+
- key
1247+
- operator
1248+
type: object
1249+
type: array
12201250
matchLabel:
12211251
additionalProperties:
12221252
type: string

pkg/analyze/node_resources.go

Lines changed: 19 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -8,11 +8,14 @@ import (
88
"strings"
99

1010
"github.com/pkg/errors"
11-
util "github.com/replicatedhq/troubleshoot/internal/util"
12-
troubleshootv1beta2 "github.com/replicatedhq/troubleshoot/pkg/apis/troubleshoot/v1beta2"
13-
"github.com/replicatedhq/troubleshoot/pkg/constants"
1411
corev1 "k8s.io/api/core/v1"
1512
"k8s.io/apimachinery/pkg/api/resource"
13+
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
14+
"k8s.io/apimachinery/pkg/labels"
15+
16+
"github.com/replicatedhq/troubleshoot/internal/util"
17+
troubleshootv1beta2 "github.com/replicatedhq/troubleshoot/pkg/apis/troubleshoot/v1beta2"
18+
"github.com/replicatedhq/troubleshoot/pkg/constants"
1619
)
1720

1821
type AnalyzeNodeResources struct {
@@ -381,13 +384,19 @@ func nodeMatchesFilters(node corev1.Node, filters *troubleshootv1beta2.NodeResou
381384

382385
// all filters must pass for this to pass
383386
if filters.Selector != nil {
384-
for k, v := range filters.Selector.MatchLabel {
385-
l, found := node.Labels[k]
386-
if !found {
387-
return false, nil
388-
} else if l != v {
389-
return false, nil
390-
}
387+
selector, err := metav1.LabelSelectorAsSelector(
388+
&metav1.LabelSelector{
389+
MatchLabels: filters.Selector.MatchLabel,
390+
MatchExpressions: filters.Selector.MatchExpressions,
391+
},
392+
)
393+
if err != nil {
394+
return false, errors.Wrap(err, "failed to create label selector")
395+
}
396+
397+
found := selector.Matches(labels.Set(node.Labels))
398+
if !found {
399+
return false, nil
391400
}
392401
}
393402

pkg/analyze/node_resources_test.go

Lines changed: 126 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,12 +3,13 @@ package analyzer
33
import (
44
"testing"
55

6-
troubleshootv1beta2 "github.com/replicatedhq/troubleshoot/pkg/apis/troubleshoot/v1beta2"
76
"github.com/stretchr/testify/assert"
87
"github.com/stretchr/testify/require"
98
corev1 "k8s.io/api/core/v1"
109
"k8s.io/apimachinery/pkg/api/resource"
1110
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
11+
12+
troubleshootv1beta2 "github.com/replicatedhq/troubleshoot/pkg/apis/troubleshoot/v1beta2"
1213
)
1314

1415
func Test_compareNodeResourceConditionalToActual(t *testing.T) {
@@ -501,6 +502,130 @@ func Test_nodeMatchesFilters(t *testing.T) {
501502
},
502503
expectResult: true,
503504
},
505+
{
506+
name: "true when the label expression matches with operator In",
507+
node: node,
508+
filters: &troubleshootv1beta2.NodeResourceFilters{
509+
Selector: &troubleshootv1beta2.NodeResourceSelectors{
510+
MatchExpressions: []metav1.LabelSelectorRequirement{
511+
{
512+
Key: "label",
513+
Operator: metav1.LabelSelectorOpIn,
514+
Values: []string{"value"},
515+
},
516+
},
517+
},
518+
},
519+
expectResult: true,
520+
},
521+
{
522+
name: "false when the label expression does not match with operator In",
523+
node: node,
524+
filters: &troubleshootv1beta2.NodeResourceFilters{
525+
Selector: &troubleshootv1beta2.NodeResourceSelectors{
526+
MatchExpressions: []metav1.LabelSelectorRequirement{
527+
{
528+
Key: "label",
529+
Operator: metav1.LabelSelectorOpIn,
530+
Values: []string{"value2"},
531+
},
532+
},
533+
},
534+
},
535+
expectResult: false,
536+
},
537+
{
538+
name: "true when the label expression matches with operator NotIn",
539+
node: node,
540+
filters: &troubleshootv1beta2.NodeResourceFilters{
541+
Selector: &troubleshootv1beta2.NodeResourceSelectors{
542+
MatchExpressions: []metav1.LabelSelectorRequirement{
543+
{
544+
Key: "label",
545+
Operator: metav1.LabelSelectorOpNotIn,
546+
Values: []string{"value2"},
547+
},
548+
},
549+
},
550+
},
551+
expectResult: true,
552+
},
553+
{
554+
name: "false when the label expression does not match with operator NotIn",
555+
node: node,
556+
filters: &troubleshootv1beta2.NodeResourceFilters{
557+
Selector: &troubleshootv1beta2.NodeResourceSelectors{
558+
MatchExpressions: []metav1.LabelSelectorRequirement{
559+
{
560+
Key: "label",
561+
Operator: metav1.LabelSelectorOpNotIn,
562+
Values: []string{"value"},
563+
},
564+
},
565+
},
566+
},
567+
expectResult: false,
568+
},
569+
{
570+
name: "true when the label expression matches with operator Exists",
571+
node: node,
572+
filters: &troubleshootv1beta2.NodeResourceFilters{
573+
Selector: &troubleshootv1beta2.NodeResourceSelectors{
574+
MatchExpressions: []metav1.LabelSelectorRequirement{
575+
{
576+
Key: "label",
577+
Operator: metav1.LabelSelectorOpExists,
578+
},
579+
},
580+
},
581+
},
582+
expectResult: true,
583+
},
584+
{
585+
name: "false when the label expression matches with operator Exists",
586+
node: node,
587+
filters: &troubleshootv1beta2.NodeResourceFilters{
588+
Selector: &troubleshootv1beta2.NodeResourceSelectors{
589+
MatchExpressions: []metav1.LabelSelectorRequirement{
590+
{
591+
Key: "label2",
592+
Operator: metav1.LabelSelectorOpExists,
593+
},
594+
},
595+
},
596+
},
597+
expectResult: false,
598+
},
599+
{
600+
name: "true when the label expression matches with operator DoesNotExist",
601+
node: node,
602+
filters: &troubleshootv1beta2.NodeResourceFilters{
603+
Selector: &troubleshootv1beta2.NodeResourceSelectors{
604+
MatchExpressions: []metav1.LabelSelectorRequirement{
605+
{
606+
Key: "label2",
607+
Operator: metav1.LabelSelectorOpDoesNotExist,
608+
},
609+
},
610+
},
611+
},
612+
expectResult: true,
613+
},
614+
{
615+
name: "false when the label expression does not match with operator DoesNotExist",
616+
node: node,
617+
filters: &troubleshootv1beta2.NodeResourceFilters{
618+
Selector: &troubleshootv1beta2.NodeResourceSelectors{
619+
MatchExpressions: []metav1.LabelSelectorRequirement{
620+
{
621+
Key: "label",
622+
Operator: metav1.LabelSelectorOpDoesNotExist,
623+
},
624+
},
625+
},
626+
},
627+
expectResult: false,
628+
},
504629
}
505630

506631
for _, test := range tests {

pkg/apis/troubleshoot/v1beta2/analyzer_shared.go

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,8 @@
11
package v1beta2
22

33
import (
4+
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
5+
46
"github.com/replicatedhq/troubleshoot/pkg/multitype"
57
)
68

@@ -133,7 +135,8 @@ type NodeResourceFilters struct {
133135
}
134136

135137
type NodeResourceSelectors struct {
136-
MatchLabel map[string]string `json:"matchLabel,omitempty" yaml:"matchLabel,omitempty"`
138+
MatchLabel map[string]string `json:"matchLabel,omitempty" yaml:"matchLabel,omitempty"`
139+
MatchExpressions []metav1.LabelSelectorRequirement `json:"matchExpressions,omitempty" yaml:"matchExpressions,omitempty"`
137140
}
138141

139142
type TextAnalyze struct {

pkg/apis/troubleshoot/v1beta2/zz_generated.deepcopy.go

Lines changed: 8 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

schemas/analyzer-troubleshoot-v1beta2.json

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1785,6 +1785,35 @@
17851785
"selector": {
17861786
"type": "object",
17871787
"properties": {
1788+
"matchExpressions": {
1789+
"type": "array",
1790+
"items": {
1791+
"description": "A label selector requirement is a selector that contains values, a key, and an operator that\nrelates the key and values.",
1792+
"type": "object",
1793+
"required": [
1794+
"key",
1795+
"operator"
1796+
],
1797+
"properties": {
1798+
"key": {
1799+
"description": "key is the label key that the selector applies to.",
1800+
"type": "string"
1801+
},
1802+
"operator": {
1803+
"description": "operator represents a key's relationship to a set of values.\nValid operators are In, NotIn, Exists and DoesNotExist.",
1804+
"type": "string"
1805+
},
1806+
"values": {
1807+
"description": "values is an array of string values. If the operator is In or NotIn,\nthe values array must be non-empty. If the operator is Exists or DoesNotExist,\nthe values array must be empty. This array is replaced during a strategic\nmerge patch.",
1808+
"type": "array",
1809+
"items": {
1810+
"type": "string"
1811+
},
1812+
"x-kubernetes-list-type": "atomic"
1813+
}
1814+
}
1815+
}
1816+
},
17881817
"matchLabel": {
17891818
"type": "object",
17901819
"additionalProperties": {

0 commit comments

Comments
 (0)