add fieldSelector for kubectl get

This commit is contained in:
Di Xu 2017-08-04 17:56:44 +08:00
parent 057b7bf767
commit 4a3131ddaa
5 changed files with 53 additions and 21 deletions

View File

@ -367,7 +367,7 @@ func RunApply(f cmdutil.Factory, cmd *cobra.Command, out, errOut io.Writer, opti
clientFunc: f.UnstructuredClientForMapping, clientFunc: f.UnstructuredClientForMapping,
clientsetFunc: f.ClientSet, clientsetFunc: f.ClientSet,
selector: options.Selector, labelSelector: options.Selector,
visitedUids: visitedUids, visitedUids: visitedUids,
cascade: options.Cascade, cascade: options.Cascade,
@ -454,7 +454,8 @@ type pruner struct {
clientsetFunc func() (internalclientset.Interface, error) clientsetFunc func() (internalclientset.Interface, error)
visitedUids sets.String visitedUids sets.String
selector string labelSelector string
fieldSelector string
cascade bool cascade bool
dryRun bool dryRun bool
@ -474,7 +475,8 @@ func (p *pruner) prune(namespace string, mapping *meta.RESTMapping, shortOutput,
mapping.GroupVersionKind.Version, mapping.GroupVersionKind.Version,
false, false,
&metav1.ListOptions{ &metav1.ListOptions{
LabelSelector: p.selector, LabelSelector: p.labelSelector,
FieldSelector: p.fieldSelector,
IncludeUninitialized: includeUninitialized, IncludeUninitialized: includeUninitialized,
}, },
) )

View File

@ -56,6 +56,7 @@ type GetOptions struct {
ChunkSize int64 ChunkSize int64
LabelSelector string LabelSelector string
FieldSelector string
AllNamespaces bool AllNamespaces bool
Namespace string Namespace string
ExplicitNamespace bool ExplicitNamespace bool
@ -158,6 +159,7 @@ func NewCmdGet(f cmdutil.Factory, out io.Writer, errOut io.Writer) *cobra.Comman
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.") 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.")
cmd.Flags().BoolVar(&options.IgnoreNotFound, "ignore-not-found", options.IgnoreNotFound, "If the requested object does not exist the command will return exit code 0.") cmd.Flags().BoolVar(&options.IgnoreNotFound, "ignore-not-found", options.IgnoreNotFound, "If the requested object does not exist the command will return exit code 0.")
cmd.Flags().StringVarP(&options.LabelSelector, "selector", "l", options.LabelSelector, "Selector (label query) to filter on, supports '=', '==', and '!='.(e.g. -l key1=value1,key2=value2)") cmd.Flags().StringVarP(&options.LabelSelector, "selector", "l", options.LabelSelector, "Selector (label query) to filter on, supports '=', '==', and '!='.(e.g. -l key1=value1,key2=value2)")
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.")
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.") 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.")
cmdutil.AddIncludeUninitializedFlag(cmd) cmdutil.AddIncludeUninitializedFlag(cmd)
cmdutil.AddPrinterFlags(cmd) cmdutil.AddPrinterFlags(cmd)
@ -234,6 +236,7 @@ func (options *GetOptions) Run(f cmdutil.Factory, cmd *cobra.Command, args []str
NamespaceParam(options.Namespace).DefaultNamespace().AllNamespaces(options.AllNamespaces). NamespaceParam(options.Namespace).DefaultNamespace().AllNamespaces(options.AllNamespaces).
FilenameParam(options.ExplicitNamespace, &options.FilenameOptions). FilenameParam(options.ExplicitNamespace, &options.FilenameOptions).
LabelSelectorParam(options.LabelSelector). LabelSelectorParam(options.LabelSelector).
FieldSelectorParam(options.FieldSelector).
ExportParam(options.Export). ExportParam(options.Export).
RequestChunksOf(options.ChunkSize). RequestChunksOf(options.ChunkSize).
IncludeUninitialized(cmdutil.ShouldIncludeUninitialized(cmd, false)). // TODO: this needs to be better factored IncludeUninitialized(cmdutil.ShouldIncludeUninitialized(cmd, false)). // TODO: this needs to be better factored
@ -451,6 +454,7 @@ func (options *GetOptions) watch(f cmdutil.Factory, cmd *cobra.Command, args []s
NamespaceParam(options.Namespace).DefaultNamespace().AllNamespaces(options.AllNamespaces). NamespaceParam(options.Namespace).DefaultNamespace().AllNamespaces(options.AllNamespaces).
FilenameParam(options.ExplicitNamespace, &options.FilenameOptions). FilenameParam(options.ExplicitNamespace, &options.FilenameOptions).
LabelSelectorParam(options.LabelSelector). LabelSelectorParam(options.LabelSelector).
FieldSelectorParam(options.FieldSelector).
ExportParam(options.Export). ExportParam(options.Export).
RequestChunksOf(options.ChunkSize). RequestChunksOf(options.ChunkSize).
IncludeUninitialized(includeUninitialized). IncludeUninitialized(includeUninitialized).

View File

@ -54,6 +54,7 @@ type Builder struct {
dir bool dir bool
labelSelector *string labelSelector *string
fieldSelector *string
selectAll bool selectAll bool
includeUninitialized bool includeUninitialized bool
limitChunks int64 limitChunks int64
@ -296,6 +297,22 @@ func (b *Builder) LabelSelector(selector string) *Builder {
return b return b
} }
// FieldSelectorParam defines a selector that should be applied to the object types to load.
// This will not affect files loaded from disk or URL. If the parameter is empty it is
// a no-op - to select all resources.
func (b *Builder) FieldSelectorParam(s string) *Builder {
s = strings.TrimSpace(s)
if len(s) == 0 {
return b
}
if b.selectAll {
b.errs = append(b.errs, fmt.Errorf("found non-empty field selector %q with previously set 'all' parameter. ", s))
return b
}
b.fieldSelector = &s
return b
}
// ExportParam accepts the export boolean for these resources // ExportParam accepts the export boolean for these resources
func (b *Builder) ExportParam(export bool) *Builder { func (b *Builder) ExportParam(export bool) *Builder {
b.export = export b.export = export
@ -350,7 +367,7 @@ func (b *Builder) RequestChunksOf(chunkSize int64) *Builder {
// SelectEverythingParam // SelectEverythingParam
func (b *Builder) SelectAllParam(selectAll bool) *Builder { func (b *Builder) SelectAllParam(selectAll bool) *Builder {
if selectAll && b.labelSelector != nil { if selectAll && (b.labelSelector != nil || b.fieldSelector != nil) {
b.errs = append(b.errs, fmt.Errorf("setting 'all' parameter but found a non empty selector. ")) b.errs = append(b.errs, fmt.Errorf("setting 'all' parameter but found a non empty selector. "))
return b return b
} }
@ -595,7 +612,7 @@ func (b *Builder) visitorResult() *Result {
} }
// visit selectors // visit selectors
if b.labelSelector != nil { if b.labelSelector != nil || b.fieldSelector != nil {
return b.visitBySelector() return b.visitBySelector()
} }
@ -635,6 +652,14 @@ func (b *Builder) visitBySelector() *Result {
return result return result
} }
var labelSelector, fieldSelector string
if b.labelSelector != nil {
labelSelector = *b.labelSelector
}
if b.fieldSelector != nil {
fieldSelector = *b.fieldSelector
}
visitors := []Visitor{} visitors := []Visitor{}
for _, mapping := range mappings { for _, mapping := range mappings {
client, err := b.mapper.ClientForMapping(mapping) client, err := b.mapper.ClientForMapping(mapping)
@ -646,7 +671,7 @@ func (b *Builder) visitBySelector() *Result {
if mapping.Scope.Name() != meta.RESTScopeNameNamespace { if mapping.Scope.Name() != meta.RESTScopeNameNamespace {
selectorNamespace = "" selectorNamespace = ""
} }
visitors = append(visitors, NewSelector(client, mapping, selectorNamespace, *b.labelSelector, b.export, b.includeUninitialized, b.limitChunks)) visitors = append(visitors, NewSelector(client, mapping, selectorNamespace, labelSelector, fieldSelector, b.export, b.includeUninitialized, b.limitChunks))
} }
if b.continueOnError { if b.continueOnError {
result.visitor = EagerVisitorList(visitors) result.visitor = EagerVisitorList(visitors)

View File

@ -75,15 +75,12 @@ func (m *Helper) List(namespace, apiVersion string, export bool, options *metav1
return req.Do().Get() return req.Do().Get()
} }
func (m *Helper) Watch(namespace, resourceVersion, apiVersion string, labelSelector string) (watch.Interface, error) { func (m *Helper) Watch(namespace, apiVersion string, options *metav1.ListOptions) (watch.Interface, error) {
options.Watch = true
return m.RESTClient.Get(). return m.RESTClient.Get().
NamespaceIfScoped(namespace, m.NamespaceScoped). NamespaceIfScoped(namespace, m.NamespaceScoped).
Resource(m.Resource). Resource(m.Resource).
VersionedParams(&metav1.ListOptions{ VersionedParams(options, metav1.ParameterCodec).
ResourceVersion: resourceVersion,
Watch: true,
LabelSelector: labelSelector,
}, metav1.ParameterCodec).
Watch() Watch()
} }

View File

@ -31,18 +31,20 @@ type Selector struct {
Mapping *meta.RESTMapping Mapping *meta.RESTMapping
Namespace string Namespace string
LabelSelector string LabelSelector string
FieldSelector string
Export bool Export bool
IncludeUninitialized bool IncludeUninitialized bool
LimitChunks int64 LimitChunks int64
} }
// NewSelector creates a resource selector which hides details of getting items by their label selector. // NewSelector creates a resource selector which hides details of getting items by their label selector.
func NewSelector(client RESTClient, mapping *meta.RESTMapping, namespace string, selector string, export, includeUninitialized bool, limitChunks int64) *Selector { func NewSelector(client RESTClient, mapping *meta.RESTMapping, namespace, labelSelector, fieldSelector string, export, includeUninitialized bool, limitChunks int64) *Selector {
return &Selector{ return &Selector{
Client: client, Client: client,
Mapping: mapping, Mapping: mapping,
Namespace: namespace, Namespace: namespace,
LabelSelector: selector, LabelSelector: labelSelector,
FieldSelector: fieldSelector,
Export: export, Export: export,
IncludeUninitialized: includeUninitialized, IncludeUninitialized: includeUninitialized,
LimitChunks: limitChunks, LimitChunks: limitChunks,
@ -59,6 +61,7 @@ func (r *Selector) Visit(fn VisitorFunc) error {
r.Export, r.Export,
&metav1.ListOptions{ &metav1.ListOptions{
LabelSelector: r.LabelSelector, LabelSelector: r.LabelSelector,
FieldSelector: r.FieldSelector,
IncludeUninitialized: r.IncludeUninitialized, IncludeUninitialized: r.IncludeUninitialized,
Limit: r.LimitChunks, Limit: r.LimitChunks,
Continue: continueToken, Continue: continueToken,
@ -71,17 +74,17 @@ func (r *Selector) Visit(fn VisitorFunc) error {
if errors.IsBadRequest(err) || errors.IsNotFound(err) { if errors.IsBadRequest(err) || errors.IsNotFound(err) {
if se, ok := err.(*errors.StatusError); ok { if se, ok := err.(*errors.StatusError); ok {
// modify the message without hiding this is an API error // modify the message without hiding this is an API error
if len(r.LabelSelector) == 0 { if len(r.LabelSelector) == 0 && len(r.FieldSelector) == 0 {
se.ErrStatus.Message = fmt.Sprintf("Unable to list %q: %v", r.Mapping.Resource, se.ErrStatus.Message) se.ErrStatus.Message = fmt.Sprintf("Unable to list %q: %v", r.Mapping.Resource, se.ErrStatus.Message)
} else { } else {
se.ErrStatus.Message = fmt.Sprintf("Unable to find %q that match the selector %q: %v", r.Mapping.Resource, r.LabelSelector, se.ErrStatus.Message) se.ErrStatus.Message = fmt.Sprintf("Unable to find %q that match label selector %q, field selector %q: %v", r.Mapping.Resource, r.LabelSelector, r.FieldSelector, se.ErrStatus.Message)
} }
return se return se
} }
if len(r.LabelSelector) == 0 { if len(r.LabelSelector) == 0 && len(r.FieldSelector) == 0 {
return fmt.Errorf("Unable to list %q: %v", r.Mapping.Resource, err) return fmt.Errorf("Unable to list %q: %v", r.Mapping.Resource, err)
} }
return fmt.Errorf("Unable to find %q that match the selector %q: %v", r.Mapping.Resource, r.LabelSelector, err) return fmt.Errorf("Unable to find %q that match label selector %q, field selector %q: %v", r.Mapping.Resource, r.LabelSelector, r.FieldSelector, err)
} }
return err return err
} }
@ -107,7 +110,8 @@ func (r *Selector) Visit(fn VisitorFunc) error {
} }
func (r *Selector) Watch(resourceVersion string) (watch.Interface, error) { func (r *Selector) Watch(resourceVersion string) (watch.Interface, error) {
return NewHelper(r.Client, r.Mapping).Watch(r.Namespace, resourceVersion, r.ResourceMapping().GroupVersionKind.GroupVersion().String(), r.LabelSelector) return NewHelper(r.Client, r.Mapping).Watch(r.Namespace, r.ResourceMapping().GroupVersionKind.GroupVersion().String(),
&metav1.ListOptions{ResourceVersion: resourceVersion, LabelSelector: r.LabelSelector, FieldSelector: r.FieldSelector})
} }
// ResourceMapping returns the mapping for this resource and implements ResourceMapping // ResourceMapping returns the mapping for this resource and implements ResourceMapping