Skip to content

Commit 45bdf70

Browse files
author
Kubernetes Submit Queue
authored
Merge pull request kubernetes#50140 from dixudx/kubectl_add_fieldSelector
Automatic merge from submit-queue (batch tested with PRs 53273, 55058, 55237, 50140). If you want to cherry-pick this change to another branch, please follow the instructions <a href="https://github.com/kubernetes/community/blob/master/contributors/devel/cherry-picks.md">here</a>. add field selector for kubectl get **What this PR does / why we need it**: When working in kubernetes#50075, I found current kubectl did not support using `field-selector`. **Which issue this PR fixes** *(optional, in `fixes #<issue number>(, fixes #<issue_number>, ...)` format, will close that issue when PR gets merged)*: fixes kubernetes#14129 **Special notes for your reviewer**: /cc @janetkuo @Kargakis /assign @derekwaynecarr @smarterclayton @bgrant0607 **Release note**: ```release-note add field selector for kubectl get ```
2 parents 552d2b3 + fa143c6 commit 45bdf70

25 files changed

+311
-70
lines changed

hack/make-rules/test-cmd-util.sh

+7
Original file line numberDiff line numberDiff line change
@@ -430,6 +430,13 @@ run_pod_tests() {
430430
kubectl create -f test/fixtures/doc-yaml/admin/limitrange/valid-pod.yaml "${kube_flags[@]}"
431431
# Post-condition: valid-pod POD is created
432432
kube::test::get_object_assert pods "{{range.items}}{{$id_field}}:{{end}}" 'valid-pod:'
433+
# Command
434+
output_message=$(kubectl get pods --field-selector metadata.name=valid-pod "${kube_flags[@]}")
435+
kube::test::if_has_string "${output_message}" "valid-pod"
436+
# Command
437+
phase=$(kubectl get "${kube_flags[@]}" pod valid-pod -o go-template='{{ .status.phase }}')
438+
output_message=$(kubectl get pods --field-selector status.phase="${phase}" "${kube_flags[@]}")
439+
kube::test::if_has_string "${output_message}" "valid-pod"
433440

434441
### Delete PODs with no parameter mustn't kill everything
435442
# Pre-condition: valid-pod POD exists

pkg/kubectl/cmd/annotate.go

+1-1
Original file line numberDiff line numberDiff line change
@@ -205,7 +205,7 @@ func (o AnnotateOptions) RunAnnotate(f cmdutil.Factory, cmd *cobra.Command) erro
205205
return err
206206
}
207207

208-
b = b.SelectorParam(o.selector).
208+
b = b.LabelSelectorParam(o.selector).
209209
Unstructured(f.UnstructuredClientForMapping, mapper, typer).
210210
ResourceTypeOrNameArgs(o.all, o.resources...).
211211
Latest()

pkg/kubectl/cmd/apply.go

+8-6
Original file line numberDiff line numberDiff line change
@@ -219,7 +219,7 @@ func RunApply(f cmdutil.Factory, cmd *cobra.Command, out, errOut io.Writer, opti
219219
ContinueOnError().
220220
NamespaceParam(cmdNamespace).DefaultNamespace().
221221
FilenameParam(enforceNamespace, &options.FilenameOptions).
222-
SelectorParam(options.Selector).
222+
LabelSelectorParam(options.Selector).
223223
IncludeUninitialized(includeUninitialized).
224224
Flatten().
225225
Do()
@@ -367,8 +367,8 @@ func RunApply(f cmdutil.Factory, cmd *cobra.Command, out, errOut io.Writer, opti
367367
clientFunc: f.UnstructuredClientForMapping,
368368
clientsetFunc: f.ClientSet,
369369

370-
selector: options.Selector,
371-
visitedUids: visitedUids,
370+
labelSelector: options.Selector,
371+
visitedUids: visitedUids,
372372

373373
cascade: options.Cascade,
374374
dryRun: dryRun,
@@ -453,8 +453,9 @@ type pruner struct {
453453
clientFunc resource.ClientMapperFunc
454454
clientsetFunc func() (internalclientset.Interface, error)
455455

456-
visitedUids sets.String
457-
selector string
456+
visitedUids sets.String
457+
labelSelector string
458+
fieldSelector string
458459

459460
cascade bool
460461
dryRun bool
@@ -474,7 +475,8 @@ func (p *pruner) prune(namespace string, mapping *meta.RESTMapping, shortOutput,
474475
mapping.GroupVersionKind.Version,
475476
false,
476477
&metav1.ListOptions{
477-
LabelSelector: p.selector,
478+
LabelSelector: p.labelSelector,
479+
FieldSelector: p.fieldSelector,
478480
IncludeUninitialized: includeUninitialized,
479481
},
480482
)

pkg/kubectl/cmd/apply_view_last_applied.go

+1-1
Original file line numberDiff line numberDiff line change
@@ -98,7 +98,7 @@ func (o *ViewLastAppliedOptions) Complete(f cmdutil.Factory, args []string) erro
9898
FilenameParam(enforceNamespace, &o.FilenameOptions).
9999
ResourceTypeOrNameArgs(enforceNamespace, args...).
100100
SelectAllParam(o.All).
101-
SelectorParam(o.Selector).
101+
LabelSelectorParam(o.Selector).
102102
Latest().
103103
Flatten().
104104
Do()

pkg/kubectl/cmd/clusterinfo.go

+1-1
Original file line numberDiff line numberDiff line change
@@ -74,7 +74,7 @@ func RunClusterInfo(f cmdutil.Factory, out io.Writer, cmd *cobra.Command) error
7474
// TODO use generalized labels once they are implemented (#341)
7575
b := f.NewBuilder().
7676
NamespaceParam(cmdNamespace).DefaultNamespace().
77-
SelectorParam("kubernetes.io/cluster-service=true").
77+
LabelSelectorParam("kubernetes.io/cluster-service=true").
7878
ResourceTypeOrNameArgs(false, []string{"services"}...).
7979
Latest()
8080
err = b.Do().Visit(func(r *resource.Info, err error) error {

pkg/kubectl/cmd/create.go

+1-1
Original file line numberDiff line numberDiff line change
@@ -194,7 +194,7 @@ func RunCreate(f cmdutil.Factory, cmd *cobra.Command, out, errOut io.Writer, opt
194194
ContinueOnError().
195195
NamespaceParam(cmdNamespace).DefaultNamespace().
196196
FilenameParam(enforceNamespace, &options.FilenameOptions).
197-
SelectorParam(options.Selector).
197+
LabelSelectorParam(options.Selector).
198198
Flatten().
199199
Do()
200200
err = r.Err()

pkg/kubectl/cmd/delete.go

+1-1
Original file line numberDiff line numberDiff line change
@@ -182,7 +182,7 @@ func (o *DeleteOptions) Complete(f cmdutil.Factory, out, errOut io.Writer, args
182182
ContinueOnError().
183183
NamespaceParam(cmdNamespace).DefaultNamespace().
184184
FilenameParam(enforceNamespace, &o.FilenameOptions).
185-
SelectorParam(o.Selector).
185+
LabelSelectorParam(o.Selector).
186186
IncludeUninitialized(includeUninitialized).
187187
SelectAllParam(o.DeleteAll).
188188
ResourceTypeOrNameArgs(false, args...).RequireObject(false).

pkg/kubectl/cmd/describe.go

+1-1
Original file line numberDiff line numberDiff line change
@@ -129,7 +129,7 @@ func RunDescribe(f cmdutil.Factory, out, cmdErr io.Writer, cmd *cobra.Command, a
129129
ContinueOnError().
130130
NamespaceParam(cmdNamespace).DefaultNamespace().AllNamespaces(allNamespaces).
131131
FilenameParam(enforceNamespace, options).
132-
SelectorParam(selector).
132+
LabelSelectorParam(selector).
133133
IncludeUninitialized(includeUninitialized).
134134
ResourceTypeOrNameArgs(true, args...).
135135
Flatten().

pkg/kubectl/cmd/drain.go

+1-1
Original file line numberDiff line numberDiff line change
@@ -243,7 +243,7 @@ func (o *DrainOptions) SetupDrain(cmd *cobra.Command, args []string) error {
243243
Flatten()
244244

245245
if len(o.Selector) > 0 {
246-
builder = builder.SelectorParam(o.Selector).
246+
builder = builder.LabelSelectorParam(o.Selector).
247247
ResourceTypes("nodes")
248248
}
249249

pkg/kubectl/cmd/label.go

+1-1
Original file line numberDiff line numberDiff line change
@@ -206,7 +206,7 @@ func (o *LabelOptions) RunLabel(f cmdutil.Factory, cmd *cobra.Command) error {
206206
return err
207207
}
208208

209-
b = b.SelectorParam(o.selector).
209+
b = b.LabelSelectorParam(o.selector).
210210
Unstructured(f.UnstructuredClientForMapping, mapper, typer).
211211
ResourceTypeOrNameArgs(o.all, o.resources...).
212212
Latest()

pkg/kubectl/cmd/logs.go

+1-1
Original file line numberDiff line numberDiff line change
@@ -199,7 +199,7 @@ func (o *LogsOptions) Complete(f cmdutil.Factory, out io.Writer, cmd *cobra.Comm
199199
builder.ResourceNames("pods", o.ResourceArg)
200200
}
201201
if selector != "" {
202-
builder.ResourceTypes("pods").SelectorParam(selector)
202+
builder.ResourceTypes("pods").LabelSelectorParam(selector)
203203
}
204204
infos, err := builder.Do().Infos()
205205
if err != nil {

pkg/kubectl/cmd/resource/get.go

+6-2
Original file line numberDiff line numberDiff line change
@@ -56,6 +56,7 @@ type GetOptions struct {
5656
ChunkSize int64
5757

5858
LabelSelector string
59+
FieldSelector string
5960
AllNamespaces bool
6061
Namespace string
6162
ExplicitNamespace bool
@@ -158,6 +159,7 @@ func NewCmdGet(f cmdutil.Factory, out io.Writer, errOut io.Writer) *cobra.Comman
158159
cmd.Flags().Int64Var(&options.ChunkSize, "chunk-size", 500, "Return large lists in chunks rather than all at once. Pass 0 to disable. This flag is beta and may change in the future.")
159160
cmd.Flags().BoolVar(&options.IgnoreNotFound, "ignore-not-found", options.IgnoreNotFound, "If the requested object does not exist the command will return exit code 0.")
160161
cmd.Flags().StringVarP(&options.LabelSelector, "selector", "l", options.LabelSelector, "Selector (label query) to filter on, supports '=', '==', and '!='.(e.g. -l key1=value1,key2=value2)")
162+
cmd.Flags().StringVar(&options.FieldSelector, "field-selector", options.FieldSelector, "Selector (field query) to filter on, supports '=', '==', and '!='.(e.g. --field-selector key1=value1,key2=value2). The server only supports a limited number of field queries per type.")
161163
cmd.Flags().BoolVar(&options.AllNamespaces, "all-namespaces", options.AllNamespaces, "If present, list the requested object(s) across all namespaces. Namespace in current context is ignored even if specified with --namespace.")
162164
cmdutil.AddIncludeUninitializedFlag(cmd)
163165
cmdutil.AddPrinterFlags(cmd)
@@ -233,7 +235,8 @@ func (options *GetOptions) Run(f cmdutil.Factory, cmd *cobra.Command, args []str
233235
Unstructured(f.UnstructuredClientForMapping, mapper, typer).
234236
NamespaceParam(options.Namespace).DefaultNamespace().AllNamespaces(options.AllNamespaces).
235237
FilenameParam(options.ExplicitNamespace, &options.FilenameOptions).
236-
SelectorParam(options.LabelSelector).
238+
LabelSelectorParam(options.LabelSelector).
239+
FieldSelectorParam(options.FieldSelector).
237240
ExportParam(options.Export).
238241
RequestChunksOf(options.ChunkSize).
239242
IncludeUninitialized(cmdutil.ShouldIncludeUninitialized(cmd, false)). // TODO: this needs to be better factored
@@ -450,7 +453,8 @@ func (options *GetOptions) watch(f cmdutil.Factory, cmd *cobra.Command, args []s
450453
Unstructured(f.UnstructuredClientForMapping, mapper, typer).
451454
NamespaceParam(options.Namespace).DefaultNamespace().AllNamespaces(options.AllNamespaces).
452455
FilenameParam(options.ExplicitNamespace, &options.FilenameOptions).
453-
SelectorParam(options.LabelSelector).
456+
LabelSelectorParam(options.LabelSelector).
457+
FieldSelectorParam(options.FieldSelector).
454458
ExportParam(options.Export).
455459
RequestChunksOf(options.ChunkSize).
456460
IncludeUninitialized(includeUninitialized).

pkg/kubectl/cmd/resource/get_test.go

+93-2
Original file line numberDiff line numberDiff line change
@@ -825,7 +825,7 @@ func TestGetMultipleTypeObjectsAsList(t *testing.T) {
825825
}
826826
}
827827

828-
func TestGetMultipleTypeObjectsWithSelector(t *testing.T) {
828+
func TestGetMultipleTypeObjectsWithLabelSelector(t *testing.T) {
829829
pods, svc, _ := testData()
830830

831831
f, tf, codec, _ := cmdtesting.NewAPIFactory()
@@ -868,6 +868,49 @@ func TestGetMultipleTypeObjectsWithSelector(t *testing.T) {
868868
}
869869
}
870870

871+
func TestGetMultipleTypeObjectsWithFieldSelector(t *testing.T) {
872+
pods, svc, _ := testData()
873+
874+
f, tf, codec, _ := cmdtesting.NewAPIFactory()
875+
tf.Printer = &testPrinter{}
876+
tf.UnstructuredClient = &fake.RESTClient{
877+
NegotiatedSerializer: unstructuredSerializer,
878+
Client: fake.CreateHTTPClient(func(req *http.Request) (*http.Response, error) {
879+
if req.URL.Query().Get(metav1.FieldSelectorQueryParam("v1")) != "a=b" {
880+
t.Fatalf("unexpected request: %#v\n%#v", req.URL, req)
881+
}
882+
switch req.URL.Path {
883+
case "/namespaces/test/pods":
884+
return &http.Response{StatusCode: 200, Header: defaultHeader(), Body: objBody(codec, pods)}, nil
885+
case "/namespaces/test/services":
886+
return &http.Response{StatusCode: 200, Header: defaultHeader(), Body: objBody(codec, svc)}, nil
887+
default:
888+
t.Fatalf("unexpected request: %#v\n%#v", req.URL, req)
889+
return nil, nil
890+
}
891+
}),
892+
}
893+
tf.Namespace = "test"
894+
buf := bytes.NewBuffer([]byte{})
895+
errBuf := bytes.NewBuffer([]byte{})
896+
897+
cmd := NewCmdGet(f, buf, errBuf)
898+
cmd.SetOutput(buf)
899+
900+
cmd.Flags().Set("field-selector", "a=b")
901+
cmd.Run(cmd, []string{"pods,services"})
902+
903+
expected, err := extractResourceList([]runtime.Object{pods, svc})
904+
if err != nil {
905+
t.Fatal(err)
906+
}
907+
verifyObjects(t, expected, tf.Printer.(*testPrinter).Objects)
908+
909+
if len(buf.String()) == 0 {
910+
t.Errorf("unexpected empty output")
911+
}
912+
}
913+
871914
func TestGetMultipleTypeObjectsWithDirectReference(t *testing.T) {
872915
_, svc, _ := testData()
873916
node := &api.Node{
@@ -1006,7 +1049,7 @@ func watchTestData() ([]api.Pod, []watch.Event) {
10061049
return pods, events
10071050
}
10081051

1009-
func TestWatchSelector(t *testing.T) {
1052+
func TestWatchLabelSelector(t *testing.T) {
10101053
pods, events := watchTestData()
10111054

10121055
f, tf, codec, _ := cmdtesting.NewAPIFactory()
@@ -1054,6 +1097,54 @@ func TestWatchSelector(t *testing.T) {
10541097
}
10551098
}
10561099

1100+
func TestWatchFieldSelector(t *testing.T) {
1101+
pods, events := watchTestData()
1102+
1103+
f, tf, codec, _ := cmdtesting.NewAPIFactory()
1104+
tf.Printer = &testPrinter{}
1105+
podList := &api.PodList{
1106+
Items: pods,
1107+
ListMeta: metav1.ListMeta{
1108+
ResourceVersion: "10",
1109+
},
1110+
}
1111+
tf.UnstructuredClient = &fake.RESTClient{
1112+
NegotiatedSerializer: unstructuredSerializer,
1113+
Client: fake.CreateHTTPClient(func(req *http.Request) (*http.Response, error) {
1114+
if req.URL.Query().Get(metav1.FieldSelectorQueryParam("v1")) != "a=b" {
1115+
t.Fatalf("unexpected request: %#v\n%#v", req.URL, req)
1116+
}
1117+
switch req.URL.Path {
1118+
case "/namespaces/test/pods":
1119+
if req.URL.Query().Get("watch") == "true" {
1120+
return &http.Response{StatusCode: 200, Header: defaultHeader(), Body: watchBody(codec, events[2:])}, nil
1121+
}
1122+
return &http.Response{StatusCode: 200, Header: defaultHeader(), Body: objBody(codec, podList)}, nil
1123+
default:
1124+
t.Fatalf("unexpected request: %#v\n%#v", req.URL, req)
1125+
return nil, nil
1126+
}
1127+
}),
1128+
}
1129+
tf.Namespace = "test"
1130+
buf := bytes.NewBuffer([]byte{})
1131+
errBuf := bytes.NewBuffer([]byte{})
1132+
1133+
cmd := NewCmdGet(f, buf, errBuf)
1134+
cmd.SetOutput(buf)
1135+
1136+
cmd.Flags().Set("watch", "true")
1137+
cmd.Flags().Set("field-selector", "a=b")
1138+
cmd.Run(cmd, []string{"pods"})
1139+
1140+
expected := []runtime.Object{&pods[0], &pods[1], events[2].Object, events[3].Object}
1141+
verifyObjects(t, expected, tf.Printer.(*testPrinter).Objects)
1142+
1143+
if len(buf.String()) == 0 {
1144+
t.Errorf("unexpected empty output")
1145+
}
1146+
}
1147+
10571148
func TestWatchResource(t *testing.T) {
10581149
pods, events := watchTestData()
10591150

pkg/kubectl/cmd/scale.go

+1-1
Original file line numberDiff line numberDiff line change
@@ -110,7 +110,7 @@ func RunScale(f cmdutil.Factory, out io.Writer, cmd *cobra.Command, args []strin
110110
FilenameParam(enforceNamespace, options).
111111
ResourceTypeOrNameArgs(all, args...).
112112
Flatten().
113-
SelectorParam(selector).
113+
LabelSelectorParam(selector).
114114
Do()
115115
err = r.Err()
116116
if resource.IsUsageError(err) {

pkg/kubectl/cmd/set/set_env.go

+2-2
Original file line numberDiff line numberDiff line change
@@ -240,7 +240,7 @@ func (o *EnvOptions) RunEnv(f cmdutil.Factory) error {
240240

241241
if !o.Local {
242242
b = b.
243-
SelectorParam(o.Selector).
243+
LabelSelectorParam(o.Selector).
244244
ResourceTypeOrNameArgs(o.All, o.From).
245245
Latest()
246246
} else {
@@ -304,7 +304,7 @@ func (o *EnvOptions) RunEnv(f cmdutil.Factory) error {
304304

305305
if !o.Local {
306306
b = b.
307-
SelectorParam(o.Selector).
307+
LabelSelectorParam(o.Selector).
308308
ResourceTypeOrNameArgs(o.All, o.Resources...).
309309
Latest()
310310
} else {

pkg/kubectl/cmd/set/set_image.go

+1-1
Original file line numberDiff line numberDiff line change
@@ -149,7 +149,7 @@ func (o *ImageOptions) Complete(f cmdutil.Factory, cmd *cobra.Command, args []st
149149

150150
if !o.Local {
151151
builder = builder.
152-
SelectorParam(o.Selector).
152+
LabelSelectorParam(o.Selector).
153153
ResourceTypeOrNameArgs(o.All, o.Resources...).
154154
Latest()
155155
} else {

pkg/kubectl/cmd/set/set_resources.go

+1-1
Original file line numberDiff line numberDiff line change
@@ -153,7 +153,7 @@ func (o *ResourcesOptions) Complete(f cmdutil.Factory, cmd *cobra.Command, args
153153

154154
if !o.Local {
155155
builder = builder.
156-
SelectorParam(o.Selector).
156+
LabelSelectorParam(o.Selector).
157157
ResourceTypeOrNameArgs(o.All, args...).
158158
Latest()
159159
} else {

pkg/kubectl/cmd/set/set_subject.go

+1-1
Original file line numberDiff line numberDiff line change
@@ -135,7 +135,7 @@ func (o *SubjectOptions) Complete(f cmdutil.Factory, cmd *cobra.Command, args []
135135

136136
if !o.Local {
137137
builder = builder.
138-
SelectorParam(o.Selector).
138+
LabelSelectorParam(o.Selector).
139139
ResourceTypeOrNameArgs(o.All, args...).
140140
Latest()
141141
} else {

pkg/kubectl/cmd/taint.go

+2-2
Original file line numberDiff line numberDiff line change
@@ -152,15 +152,15 @@ func (o *TaintOptions) Complete(f cmdutil.Factory, out io.Writer, cmd *cobra.Com
152152
ContinueOnError().
153153
NamespaceParam(namespace).DefaultNamespace()
154154
if o.selector != "" {
155-
o.builder = o.builder.SelectorParam(o.selector).ResourceTypes("node")
155+
o.builder = o.builder.LabelSelectorParam(o.selector).ResourceTypes("node")
156156
}
157157
if o.all {
158158
o.builder = o.builder.SelectAllParam(o.all).ResourceTypes("node").Flatten().Latest()
159159
}
160160
if !o.all && o.selector == "" && len(o.resources) >= 2 {
161161
o.builder = o.builder.ResourceNames("node", o.resources[1:]...)
162162
}
163-
o.builder = o.builder.SelectorParam(o.selector).
163+
o.builder = o.builder.LabelSelectorParam(o.selector).
164164
Flatten().
165165
Latest()
166166
o.f = f

0 commit comments

Comments
 (0)