mirror of
https://github.com/k3s-io/kubernetes.git
synced 2025-08-01 07:47:56 +00:00
allow kubectl -f to filter by selector
This commit is contained in:
parent
b2527640e7
commit
5f2569c16d
@ -35,6 +35,11 @@ import (
|
|||||||
"k8s.io/kubernetes/pkg/util/strategicpatch"
|
"k8s.io/kubernetes/pkg/util/strategicpatch"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
type ApplyOptions struct {
|
||||||
|
FilenameOptions resource.FilenameOptions
|
||||||
|
Selector string
|
||||||
|
}
|
||||||
|
|
||||||
const (
|
const (
|
||||||
// maxPatchRetry is the maximum number of conflicts retry for during a patch operation before returning failure
|
// maxPatchRetry is the maximum number of conflicts retry for during a patch operation before returning failure
|
||||||
maxPatchRetry = 5
|
maxPatchRetry = 5
|
||||||
@ -61,7 +66,7 @@ var (
|
|||||||
)
|
)
|
||||||
|
|
||||||
func NewCmdApply(f *cmdutil.Factory, out io.Writer) *cobra.Command {
|
func NewCmdApply(f *cmdutil.Factory, out io.Writer) *cobra.Command {
|
||||||
options := &resource.FilenameOptions{}
|
var options ApplyOptions
|
||||||
|
|
||||||
cmd := &cobra.Command{
|
cmd := &cobra.Command{
|
||||||
Use: "apply -f FILENAME",
|
Use: "apply -f FILENAME",
|
||||||
@ -71,15 +76,16 @@ func NewCmdApply(f *cmdutil.Factory, out io.Writer) *cobra.Command {
|
|||||||
Run: func(cmd *cobra.Command, args []string) {
|
Run: func(cmd *cobra.Command, args []string) {
|
||||||
cmdutil.CheckErr(validateArgs(cmd, args))
|
cmdutil.CheckErr(validateArgs(cmd, args))
|
||||||
cmdutil.CheckErr(cmdutil.ValidateOutputArgs(cmd))
|
cmdutil.CheckErr(cmdutil.ValidateOutputArgs(cmd))
|
||||||
cmdutil.CheckErr(RunApply(f, cmd, out, options))
|
cmdutil.CheckErr(RunApply(f, cmd, out, &options))
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
usage := "that contains the configuration to apply"
|
usage := "that contains the configuration to apply"
|
||||||
cmdutil.AddFilenameOptionFlags(cmd, options, usage)
|
cmdutil.AddFilenameOptionFlags(cmd, &options.FilenameOptions, usage)
|
||||||
cmd.MarkFlagRequired("filename")
|
cmd.MarkFlagRequired("filename")
|
||||||
cmd.Flags().Bool("overwrite", true, "Automatically resolve conflicts between the modified and live configuration by using values from the modified configuration")
|
cmd.Flags().Bool("overwrite", true, "Automatically resolve conflicts between the modified and live configuration by using values from the modified configuration")
|
||||||
cmdutil.AddValidateFlags(cmd)
|
cmdutil.AddValidateFlags(cmd)
|
||||||
|
cmd.Flags().StringVarP(&options.Selector, "selector", "l", "", "Selector (label query) to filter on")
|
||||||
cmdutil.AddOutputFlagsForMutation(cmd)
|
cmdutil.AddOutputFlagsForMutation(cmd)
|
||||||
cmdutil.AddRecordFlag(cmd)
|
cmdutil.AddRecordFlag(cmd)
|
||||||
cmdutil.AddInclude3rdPartyFlags(cmd)
|
cmdutil.AddInclude3rdPartyFlags(cmd)
|
||||||
@ -94,7 +100,7 @@ func validateArgs(cmd *cobra.Command, args []string) error {
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func RunApply(f *cmdutil.Factory, cmd *cobra.Command, out io.Writer, options *resource.FilenameOptions) error {
|
func RunApply(f *cmdutil.Factory, cmd *cobra.Command, out io.Writer, options *ApplyOptions) error {
|
||||||
shortOutput := cmdutil.GetFlagString(cmd, "output") == "name"
|
shortOutput := cmdutil.GetFlagString(cmd, "output") == "name"
|
||||||
schema, err := f.Validator(cmdutil.GetFlagBool(cmd, "validate"), cmdutil.GetFlagString(cmd, "schema-cache-dir"))
|
schema, err := f.Validator(cmdutil.GetFlagBool(cmd, "validate"), cmdutil.GetFlagString(cmd, "schema-cache-dir"))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@ -111,7 +117,8 @@ func RunApply(f *cmdutil.Factory, cmd *cobra.Command, out io.Writer, options *re
|
|||||||
Schema(schema).
|
Schema(schema).
|
||||||
ContinueOnError().
|
ContinueOnError().
|
||||||
NamespaceParam(cmdNamespace).DefaultNamespace().
|
NamespaceParam(cmdNamespace).DefaultNamespace().
|
||||||
FilenameParam(enforceNamespace, options).
|
FilenameParam(enforceNamespace, &options.FilenameOptions).
|
||||||
|
SelectorParam(options.Selector).
|
||||||
Flatten().
|
Flatten().
|
||||||
Do()
|
Do()
|
||||||
err = r.Err()
|
err = r.Err()
|
||||||
|
@ -538,6 +538,11 @@ func (b *Builder) visitorResult() *Result {
|
|||||||
b.selector = labels.Everything()
|
b.selector = labels.Everything()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// visit items specified by paths
|
||||||
|
if len(b.paths) != 0 {
|
||||||
|
return b.visitByPaths()
|
||||||
|
}
|
||||||
|
|
||||||
// visit selectors
|
// visit selectors
|
||||||
if b.selector != nil {
|
if b.selector != nil {
|
||||||
return b.visitBySelector()
|
return b.visitBySelector()
|
||||||
@ -553,11 +558,6 @@ func (b *Builder) visitorResult() *Result {
|
|||||||
return b.visitByName()
|
return b.visitByName()
|
||||||
}
|
}
|
||||||
|
|
||||||
// visit items specified by paths
|
|
||||||
if len(b.paths) != 0 {
|
|
||||||
return b.visitByPaths()
|
|
||||||
}
|
|
||||||
|
|
||||||
if len(b.resources) != 0 {
|
if len(b.resources) != 0 {
|
||||||
return &Result{err: fmt.Errorf("resource(s) were provided, but no name, label selector, or --all flag specified")}
|
return &Result{err: fmt.Errorf("resource(s) were provided, but no name, label selector, or --all flag specified")}
|
||||||
}
|
}
|
||||||
@ -574,14 +574,6 @@ func (b *Builder) visitBySelector() *Result {
|
|||||||
if len(b.resources) == 0 {
|
if len(b.resources) == 0 {
|
||||||
return &Result{err: fmt.Errorf("at least one resource must be specified to use a selector")}
|
return &Result{err: fmt.Errorf("at least one resource must be specified to use a selector")}
|
||||||
}
|
}
|
||||||
// empty selector has different error message for paths being provided
|
|
||||||
if len(b.paths) != 0 {
|
|
||||||
if b.selector.Empty() {
|
|
||||||
return &Result{err: fmt.Errorf("when paths, URLs, or stdin is provided as input, you may not specify a resource by arguments as well")}
|
|
||||||
} else {
|
|
||||||
return &Result{err: fmt.Errorf("a selector may not be specified when path, URL, or stdin is provided as input")}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
mappings, err := b.resourceMappings()
|
mappings, err := b.resourceMappings()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return &Result{err: err}
|
return &Result{err: err}
|
||||||
@ -613,9 +605,6 @@ func (b *Builder) visitByResource() *Result {
|
|||||||
isSingular = len(b.resourceTuples) == 1
|
isSingular = len(b.resourceTuples) == 1
|
||||||
}
|
}
|
||||||
|
|
||||||
if len(b.paths) != 0 {
|
|
||||||
return &Result{singular: isSingular, err: fmt.Errorf("when paths, URLs, or stdin is provided as input, you may not specify a resource by arguments as well")}
|
|
||||||
}
|
|
||||||
if len(b.resources) != 0 {
|
if len(b.resources) != 0 {
|
||||||
return &Result{singular: isSingular, err: fmt.Errorf("you may not specify individual resources and bulk resources in the same call")}
|
return &Result{singular: isSingular, err: fmt.Errorf("you may not specify individual resources and bulk resources in the same call")}
|
||||||
}
|
}
|
||||||
@ -718,6 +707,12 @@ func (b *Builder) visitByPaths() *Result {
|
|||||||
if len(b.resources) != 0 {
|
if len(b.resources) != 0 {
|
||||||
return &Result{singular: singular, err: fmt.Errorf("when paths, URLs, or stdin is provided as input, you may not specify resource arguments as well")}
|
return &Result{singular: singular, err: fmt.Errorf("when paths, URLs, or stdin is provided as input, you may not specify resource arguments as well")}
|
||||||
}
|
}
|
||||||
|
if len(b.names) != 0 {
|
||||||
|
return &Result{err: fmt.Errorf("name cannot be provided when a path is specified")}
|
||||||
|
}
|
||||||
|
if len(b.resourceTuples) != 0 {
|
||||||
|
return &Result{err: fmt.Errorf("resource/name arguments cannot be provided when a path is specified")}
|
||||||
|
}
|
||||||
|
|
||||||
var visitors Visitor
|
var visitors Visitor
|
||||||
if b.continueOnError {
|
if b.continueOnError {
|
||||||
@ -738,6 +733,9 @@ func (b *Builder) visitByPaths() *Result {
|
|||||||
}
|
}
|
||||||
visitors = NewDecoratedVisitor(visitors, RetrieveLatest)
|
visitors = NewDecoratedVisitor(visitors, RetrieveLatest)
|
||||||
}
|
}
|
||||||
|
if b.selector != nil {
|
||||||
|
visitors = NewFilteredVisitor(visitors, FilterBySelector(b.selector))
|
||||||
|
}
|
||||||
return &Result{singular: singular, visitor: visitors, sources: b.paths}
|
return &Result{singular: singular, visitor: visitors, sources: b.paths}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -31,6 +31,7 @@ import (
|
|||||||
"k8s.io/kubernetes/pkg/api/meta"
|
"k8s.io/kubernetes/pkg/api/meta"
|
||||||
"k8s.io/kubernetes/pkg/api/unversioned"
|
"k8s.io/kubernetes/pkg/api/unversioned"
|
||||||
"k8s.io/kubernetes/pkg/api/validation"
|
"k8s.io/kubernetes/pkg/api/validation"
|
||||||
|
"k8s.io/kubernetes/pkg/labels"
|
||||||
"k8s.io/kubernetes/pkg/runtime"
|
"k8s.io/kubernetes/pkg/runtime"
|
||||||
utilerrors "k8s.io/kubernetes/pkg/util/errors"
|
utilerrors "k8s.io/kubernetes/pkg/util/errors"
|
||||||
"k8s.io/kubernetes/pkg/util/yaml"
|
"k8s.io/kubernetes/pkg/util/yaml"
|
||||||
@ -639,3 +640,51 @@ func RetrieveLazy(info *Info, err error) error {
|
|||||||
}
|
}
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type FilterFunc func(info *Info, err error) (bool, error)
|
||||||
|
|
||||||
|
type FilteredVisitor struct {
|
||||||
|
visitor Visitor
|
||||||
|
filters []FilterFunc
|
||||||
|
}
|
||||||
|
|
||||||
|
func NewFilteredVisitor(v Visitor, fn ...FilterFunc) Visitor {
|
||||||
|
if len(fn) == 0 {
|
||||||
|
return v
|
||||||
|
}
|
||||||
|
return FilteredVisitor{v, fn}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (v FilteredVisitor) Visit(fn VisitorFunc) error {
|
||||||
|
return v.visitor.Visit(func(info *Info, err error) error {
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
for _, filter := range v.filters {
|
||||||
|
ok, err := filter(info, nil)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
if !ok {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return fn(info, nil)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
func FilterBySelector(s labels.Selector) FilterFunc {
|
||||||
|
return func(info *Info, err error) (bool, error) {
|
||||||
|
if err != nil {
|
||||||
|
return false, err
|
||||||
|
}
|
||||||
|
a, err := meta.Accessor(info.Object)
|
||||||
|
if err != nil {
|
||||||
|
return false, err
|
||||||
|
}
|
||||||
|
if !s.Matches(labels.Set(a.GetLabels())) {
|
||||||
|
return false, nil
|
||||||
|
}
|
||||||
|
return true, nil
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user