diff --git a/hack/import-restrictions.yaml b/hack/import-restrictions.yaml index c053eb45251..19e12ac1e94 100644 --- a/hack/import-restrictions.yaml +++ b/hack/import-restrictions.yaml @@ -24,6 +24,7 @@ # TODO this one should be tightened. We depend on it for testing, but we should instead create our own scheme - k8s.io/api/core/v1 - k8s.io/kubernetes/pkg/kubectl/genericclioptions/printers + - k8s.io/kubernetes/pkg/kubectl/genericclioptions/resource - baseImportPath: "./vendor/k8s.io/apimachinery/" allowedImports: diff --git a/pkg/kubectl/cmd/delete.go b/pkg/kubectl/cmd/delete.go index 2f2bd91508a..e98f0451a98 100644 --- a/pkg/kubectl/cmd/delete.go +++ b/pkg/kubectl/cmd/delete.go @@ -275,7 +275,7 @@ func (o *DeleteOptions) DeleteResult(r *resource.Result) error { effectiveTimeout = 168 * time.Hour } waitOptions := kubectlwait.WaitOptions{ - ResourceFinder: kubectlwait.ResourceFinderForResult(o.Result), + ResourceFinder: genericclioptions.ResourceFinderForResult(o.Result), DynamicClient: o.DynamicClient, Timeout: effectiveTimeout, diff --git a/pkg/kubectl/cmd/wait/BUILD b/pkg/kubectl/cmd/wait/BUILD index ce1253f61eb..0f13739b86c 100644 --- a/pkg/kubectl/cmd/wait/BUILD +++ b/pkg/kubectl/cmd/wait/BUILD @@ -2,11 +2,7 @@ load("@io_bazel_rules_go//go:def.bzl", "go_library", "go_test") go_library( name = "go_default_library", - srcs = [ - "fakeresourcefinder.go", - "flags.go", - "wait.go", - ], + srcs = ["wait.go"], importpath = "k8s.io/kubernetes/pkg/kubectl/cmd/wait", visibility = ["//visibility:public"], deps = [ @@ -15,7 +11,6 @@ go_library( "//pkg/kubectl/genericclioptions/printers:go_default_library", "//pkg/kubectl/genericclioptions/resource:go_default_library", "//vendor/github.com/spf13/cobra:go_default_library", - "//vendor/github.com/spf13/pflag:go_default_library", "//vendor/k8s.io/apimachinery/pkg/api/errors:go_default_library", "//vendor/k8s.io/apimachinery/pkg/apis/meta/v1:go_default_library", "//vendor/k8s.io/apimachinery/pkg/apis/meta/v1/unstructured:go_default_library", diff --git a/pkg/kubectl/cmd/wait/wait.go b/pkg/kubectl/cmd/wait/wait.go index e75d5f418dc..9ccf3cb735e 100644 --- a/pkg/kubectl/cmd/wait/wait.go +++ b/pkg/kubectl/cmd/wait/wait.go @@ -42,7 +42,7 @@ import ( type WaitFlags struct { RESTClientGetter genericclioptions.RESTClientGetter PrintFlags *genericclioptions.PrintFlags - ResourceBuilderFlags *ResourceBuilderFlags + ResourceBuilderFlags *genericclioptions.ResourceBuilderFlags Timeout time.Duration ForCondition string @@ -55,7 +55,7 @@ func NewWaitFlags(restClientGetter genericclioptions.RESTClientGetter, streams g return &WaitFlags{ RESTClientGetter: restClientGetter, PrintFlags: genericclioptions.NewPrintFlags("condition met"), - ResourceBuilderFlags: NewResourceBuilderFlags(), + ResourceBuilderFlags: genericclioptions.NewResourceBuilderFlags(), Timeout: 30 * time.Second, @@ -151,7 +151,7 @@ func conditionFuncFor(condition string) (ConditionFunc, error) { // WaitOptions is a set of options that allows you to wait. This is the object reflects the runtime needs of a wait // command, making the logic itself easy to unit test with our existing mocks. type WaitOptions struct { - ResourceFinder ResourceFinder + ResourceFinder genericclioptions.ResourceFinder DynamicClient dynamic.Interface Timeout time.Duration diff --git a/pkg/kubectl/cmd/wait/wait_test.go b/pkg/kubectl/cmd/wait/wait_test.go index 6ef63357bd5..77d98e8d459 100644 --- a/pkg/kubectl/cmd/wait/wait_test.go +++ b/pkg/kubectl/cmd/wait/wait_test.go @@ -219,7 +219,7 @@ func TestWaitForDeletion(t *testing.T) { t.Run(test.name, func(t *testing.T) { fakeClient := test.fakeClient() o := &WaitOptions{ - ResourceFinder: NewSimpleResourceFinder(test.info), + ResourceFinder: genericclioptions.NewSimpleResourceFinder(test.info), DynamicClient: fakeClient, Timeout: test.timeout, @@ -451,7 +451,7 @@ func TestWaitForCondition(t *testing.T) { t.Run(test.name, func(t *testing.T) { fakeClient := test.fakeClient() o := &WaitOptions{ - ResourceFinder: NewSimpleResourceFinder(test.info), + ResourceFinder: genericclioptions.NewSimpleResourceFinder(test.info), DynamicClient: fakeClient, Timeout: test.timeout, diff --git a/pkg/kubectl/genericclioptions/BUILD b/pkg/kubectl/genericclioptions/BUILD index 66867c87ec5..24f95b3373c 100644 --- a/pkg/kubectl/genericclioptions/BUILD +++ b/pkg/kubectl/genericclioptions/BUILD @@ -3,6 +3,8 @@ load("@io_bazel_rules_go//go:def.bzl", "go_library", "go_test") go_library( name = "go_default_library", srcs = [ + "builder_flags.go", + "builder_flags_fake.go", "config_flags.go", "config_flags_fake.go", "doc.go", @@ -16,6 +18,7 @@ go_library( visibility = ["//visibility:public"], deps = [ "//pkg/kubectl/genericclioptions/printers:go_default_library", + "//pkg/kubectl/genericclioptions/resource:go_default_library", "//vendor/github.com/evanphx/json-patch:go_default_library", "//vendor/github.com/spf13/cobra:go_default_library", "//vendor/github.com/spf13/pflag:go_default_library", diff --git a/pkg/kubectl/cmd/wait/flags.go b/pkg/kubectl/genericclioptions/builder_flags.go similarity index 66% rename from pkg/kubectl/cmd/wait/flags.go rename to pkg/kubectl/genericclioptions/builder_flags.go index 824a8af8db6..2fc1dcf5fae 100644 --- a/pkg/kubectl/cmd/wait/flags.go +++ b/pkg/kubectl/genericclioptions/builder_flags.go @@ -14,14 +14,13 @@ See the License for the specific language governing permissions and limitations under the License. */ -package wait +package genericclioptions import ( "strings" "github.com/spf13/cobra" "github.com/spf13/pflag" - "k8s.io/kubernetes/pkg/kubectl/genericclioptions" "k8s.io/kubernetes/pkg/kubectl/genericclioptions/resource" ) @@ -29,15 +28,15 @@ import ( type ResourceBuilderFlags struct { FilenameOptions resource.FilenameOptions - LabelSelector string - FieldSelector string - AllNamespaces bool Namespace string ExplicitNamespace bool - // TODO add conditional support. These are false for now. - All bool - Local bool + LabelSelector *string + FieldSelector *string + AllNamespaces *bool + + All *bool + Local *bool } // NewResourceBuilderFlags returns a default ResourceBuilderFlags @@ -46,6 +45,13 @@ func NewResourceBuilderFlags() *ResourceBuilderFlags { FilenameOptions: resource.FilenameOptions{ Recursive: true, }, + + LabelSelector: str_ptr(""), + FieldSelector: str_ptr(""), + AllNamespaces: bool_ptr(false), + + All: bool_ptr(false), + Local: bool_ptr(false), } } @@ -59,23 +65,44 @@ func (o *ResourceBuilderFlags) AddFlags(flagset *pflag.FlagSet) { flagset.SetAnnotation("filename", cobra.BashCompFilenameExt, annotations) flagset.BoolVar(&o.FilenameOptions.Recursive, "recursive", o.FilenameOptions.Recursive, "Process the directory used in -f, --filename recursively. Useful when you want to manage related manifests organized within the same directory.") - flagset.StringVarP(&o.LabelSelector, "selector", "l", o.LabelSelector, "Selector (label query) to filter on, supports '=', '==', and '!='.(e.g. -l key1=value1,key2=value2)") - 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.") - 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.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.") + } } // ToBuilder gives you back a resource finder to visit resources that are located -func (o *ResourceBuilderFlags) ToBuilder(restClientGetter genericclioptions.RESTClientGetter, resources []string) ResourceFinder { +func (o *ResourceBuilderFlags) ToBuilder(restClientGetter RESTClientGetter, resources []string) ResourceFinder { namespace, enforceNamespace, namespaceErr := restClientGetter.ToRawKubeConfigLoader().Namespace() + labelSelector := "" + if o.LabelSelector != nil { + labelSelector = *o.LabelSelector + } + + fieldSelector := "" + if o.FieldSelector != nil { + fieldSelector = *o.FieldSelector + } + + allResources := false + if o.All != nil { + allResources = *o.All + } + return &ResourceFindBuilderWrapper{ builder: resource.NewBuilder(restClientGetter). Unstructured(). NamespaceParam(namespace).DefaultNamespace(). FilenameParam(enforceNamespace, &o.FilenameOptions). - LabelSelectorParam(o.LabelSelector). - FieldSelectorParam(o.FieldSelector). - ResourceTypeOrNameArgs(o.All, resources...). + LabelSelectorParam(labelSelector). + FieldSelectorParam(fieldSelector). + ResourceTypeOrNameArgs(allResources, resources...). Latest(). Flatten(). AddError(namespaceErr), @@ -112,3 +139,11 @@ func ResourceFinderForResult(result resource.Visitor) ResourceFinder { return result }) } + +func str_ptr(val string) *string { + return &val +} + +func bool_ptr(val bool) *bool { + return &val +} diff --git a/pkg/kubectl/cmd/wait/fakeresourcefinder.go b/pkg/kubectl/genericclioptions/builder_flags_fake.go similarity index 98% rename from pkg/kubectl/cmd/wait/fakeresourcefinder.go rename to pkg/kubectl/genericclioptions/builder_flags_fake.go index 591dea27ef4..15137c9e797 100644 --- a/pkg/kubectl/cmd/wait/fakeresourcefinder.go +++ b/pkg/kubectl/genericclioptions/builder_flags_fake.go @@ -14,7 +14,7 @@ See the License for the specific language governing permissions and limitations under the License. */ -package wait +package genericclioptions import ( "k8s.io/kubernetes/pkg/kubectl/genericclioptions/resource"