mirror of https://github.com/k3s-io/k3s
You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
235 lines
6.9 KiB
235 lines
6.9 KiB
/*
|
|
Copyright 2018 The Kubernetes Authors.
|
|
|
|
Licensed under the Apache License, Version 2.0 (the "License");
|
|
you may not use this file except in compliance with the License.
|
|
You may obtain a copy of the License at
|
|
|
|
http://www.apache.org/licenses/LICENSE-2.0
|
|
|
|
Unless required by applicable law or agreed to in writing, software
|
|
distributed under the License is distributed on an "AS IS" BASIS,
|
|
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
See the License for the specific language governing permissions and
|
|
limitations under the License.
|
|
*/
|
|
|
|
package genericclioptions
|
|
|
|
import (
|
|
"github.com/spf13/pflag"
|
|
|
|
"k8s.io/apimachinery/pkg/runtime"
|
|
"k8s.io/cli-runtime/pkg/genericclioptions/resource"
|
|
)
|
|
|
|
// ResourceBuilderFlags are flags for finding resources
|
|
// TODO(juanvallejo): wire --local flag from commands through
|
|
type ResourceBuilderFlags struct {
|
|
FileNameFlags *FileNameFlags
|
|
|
|
LabelSelector *string
|
|
FieldSelector *string
|
|
AllNamespaces *bool
|
|
All *bool
|
|
Local *bool
|
|
IncludeUninitialized *bool
|
|
|
|
Scheme *runtime.Scheme
|
|
Latest bool
|
|
StopOnFirstError bool
|
|
}
|
|
|
|
// NewResourceBuilderFlags returns a default ResourceBuilderFlags
|
|
func NewResourceBuilderFlags() *ResourceBuilderFlags {
|
|
filenames := []string{}
|
|
|
|
return &ResourceBuilderFlags{
|
|
FileNameFlags: &FileNameFlags{
|
|
Usage: "identifying the resource.",
|
|
Filenames: &filenames,
|
|
Recursive: boolPtr(true),
|
|
},
|
|
}
|
|
}
|
|
|
|
func (o *ResourceBuilderFlags) WithFile(recurse bool, files ...string) *ResourceBuilderFlags {
|
|
o.FileNameFlags = &FileNameFlags{
|
|
Usage: "identifying the resource.",
|
|
Filenames: &files,
|
|
Recursive: boolPtr(recurse),
|
|
}
|
|
|
|
return o
|
|
}
|
|
|
|
func (o *ResourceBuilderFlags) WithLabelSelector(selector string) *ResourceBuilderFlags {
|
|
o.LabelSelector = &selector
|
|
return o
|
|
}
|
|
|
|
func (o *ResourceBuilderFlags) WithFieldSelector(selector string) *ResourceBuilderFlags {
|
|
o.FieldSelector = &selector
|
|
return o
|
|
}
|
|
|
|
func (o *ResourceBuilderFlags) WithAllNamespaces(defaultVal bool) *ResourceBuilderFlags {
|
|
o.AllNamespaces = &defaultVal
|
|
return o
|
|
}
|
|
|
|
func (o *ResourceBuilderFlags) WithAll(defaultVal bool) *ResourceBuilderFlags {
|
|
o.All = &defaultVal
|
|
return o
|
|
}
|
|
|
|
func (o *ResourceBuilderFlags) WithLocal(defaultVal bool) *ResourceBuilderFlags {
|
|
o.Local = &defaultVal
|
|
return o
|
|
}
|
|
|
|
// WithUninitialized is using an alpha feature and may be dropped
|
|
func (o *ResourceBuilderFlags) WithUninitialized(defaultVal bool) *ResourceBuilderFlags {
|
|
o.IncludeUninitialized = &defaultVal
|
|
return o
|
|
}
|
|
|
|
func (o *ResourceBuilderFlags) WithScheme(scheme *runtime.Scheme) *ResourceBuilderFlags {
|
|
o.Scheme = scheme
|
|
return o
|
|
}
|
|
|
|
func (o *ResourceBuilderFlags) WithLatest() *ResourceBuilderFlags {
|
|
o.Latest = true
|
|
return o
|
|
}
|
|
|
|
func (o *ResourceBuilderFlags) StopOnError() *ResourceBuilderFlags {
|
|
o.StopOnFirstError = true
|
|
return o
|
|
}
|
|
|
|
// AddFlags registers flags for finding resources
|
|
func (o *ResourceBuilderFlags) AddFlags(flagset *pflag.FlagSet) {
|
|
o.FileNameFlags.AddFlags(flagset)
|
|
|
|
if o.LabelSelector != nil {
|
|
flagset.StringVarP(o.LabelSelector, "selector", "l", *o.LabelSelector, "Selector (label query) to filter on, supports '=', '==', and '!='.(e.g. -l key1=value1,key2=value2)")
|
|
}
|
|
if o.FieldSelector != nil {
|
|
flagset.StringVar(o.FieldSelector, "field-selector", *o.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.")
|
|
}
|
|
if o.AllNamespaces != nil {
|
|
flagset.BoolVar(o.AllNamespaces, "all-namespaces", *o.AllNamespaces, "If present, list the requested object(s) across all namespaces. Namespace in current context is ignored even if specified with --namespace.")
|
|
}
|
|
if o.All != nil {
|
|
flagset.BoolVar(o.All, "all", *o.All, "Select all resources in the namespace of the specified resource types")
|
|
}
|
|
if o.Local != nil {
|
|
flagset.BoolVar(o.Local, "local", *o.Local, "If true, annotation will NOT contact api-server but run locally.")
|
|
}
|
|
if o.IncludeUninitialized != nil {
|
|
flagset.BoolVar(o.IncludeUninitialized, "include-uninitialized", *o.IncludeUninitialized, `If true, the kubectl command applies to uninitialized objects. If explicitly set to false, this flag overrides other flags that make the kubectl commands apply to uninitialized objects, e.g., "--all". Objects with empty metadata.initializers are regarded as initialized.`)
|
|
}
|
|
}
|
|
|
|
// ToBuilder gives you back a resource finder to visit resources that are located
|
|
func (o *ResourceBuilderFlags) ToBuilder(restClientGetter RESTClientGetter, resources []string) ResourceFinder {
|
|
namespace, enforceNamespace, namespaceErr := restClientGetter.ToRawKubeConfigLoader().Namespace()
|
|
|
|
builder := resource.NewBuilder(restClientGetter).
|
|
NamespaceParam(namespace).DefaultNamespace()
|
|
|
|
if o.Scheme != nil {
|
|
builder.WithScheme(o.Scheme, o.Scheme.PrioritizedVersionsAllGroups()...)
|
|
} else {
|
|
builder.Unstructured()
|
|
}
|
|
|
|
if o.FileNameFlags != nil {
|
|
opts := o.FileNameFlags.ToOptions()
|
|
builder.FilenameParam(enforceNamespace, &opts)
|
|
}
|
|
|
|
if o.Local == nil || !*o.Local {
|
|
// resource type/name tuples only work non-local
|
|
if o.All != nil {
|
|
builder.ResourceTypeOrNameArgs(*o.All, resources...)
|
|
} else {
|
|
builder.ResourceTypeOrNameArgs(false, resources...)
|
|
}
|
|
// label selectors only work non-local (for now)
|
|
if o.LabelSelector != nil {
|
|
builder.LabelSelectorParam(*o.LabelSelector)
|
|
}
|
|
// field selectors only work non-local (forever)
|
|
if o.FieldSelector != nil {
|
|
builder.FieldSelectorParam(*o.FieldSelector)
|
|
}
|
|
// latest only works non-local (forever)
|
|
if o.Latest {
|
|
builder.Latest()
|
|
}
|
|
|
|
} else {
|
|
builder.Local()
|
|
|
|
if len(resources) > 0 {
|
|
builder.AddError(resource.LocalResourceError)
|
|
}
|
|
}
|
|
|
|
if o.IncludeUninitialized != nil {
|
|
builder.IncludeUninitialized(*o.IncludeUninitialized)
|
|
}
|
|
|
|
if !o.StopOnFirstError {
|
|
builder.ContinueOnError()
|
|
}
|
|
|
|
return &ResourceFindBuilderWrapper{
|
|
builder: builder.
|
|
Flatten(). // I think we're going to recommend this everywhere
|
|
AddError(namespaceErr),
|
|
}
|
|
}
|
|
|
|
// ResourceFindBuilderWrapper wraps a builder in an interface
|
|
type ResourceFindBuilderWrapper struct {
|
|
builder *resource.Builder
|
|
}
|
|
|
|
// Do finds you resources to check
|
|
func (b *ResourceFindBuilderWrapper) Do() resource.Visitor {
|
|
return b.builder.Do()
|
|
}
|
|
|
|
// ResourceFinder allows mocking the resource builder
|
|
// TODO resource builders needs to become more interfacey
|
|
type ResourceFinder interface {
|
|
Do() resource.Visitor
|
|
}
|
|
|
|
// ResourceFinderFunc is a handy way to make a ResourceFinder
|
|
type ResourceFinderFunc func() resource.Visitor
|
|
|
|
// Do implements ResourceFinder
|
|
func (fn ResourceFinderFunc) Do() resource.Visitor {
|
|
return fn()
|
|
}
|
|
|
|
// ResourceFinderForResult skins a visitor for re-use as a ResourceFinder
|
|
func ResourceFinderForResult(result resource.Visitor) ResourceFinder {
|
|
return ResourceFinderFunc(func() resource.Visitor {
|
|
return result
|
|
})
|
|
}
|
|
|
|
func strPtr(val string) *string {
|
|
return &val
|
|
}
|
|
|
|
func boolPtr(val bool) *bool {
|
|
return &val
|
|
}
|