Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Introduce new flag "--include-uninitialized" to kubectl #50497

Merged
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
268 changes: 268 additions & 0 deletions hack/make-rules/test-cmd-util.sh

Large diffs are not rendered by default.

17 changes: 17 additions & 0 deletions hack/testdata/initializer-clusterrolebinding.yaml
@@ -0,0 +1,17 @@
apiVersion: rbac.authorization.k8s.io/v1beta1
kind: ClusterRoleBinding
metadata:
name: super-admin
initializers:
pending:
- name: podimage.initializer.com
labels:
clusterrolebinding: super
roleRef:
apiGroup: rbac.authorization.k8s.io
kind: ClusterRole
name: admin
subjects:
- apiGroup: rbac.authorization.k8s.io
kind: User
name: super-admin
25 changes: 25 additions & 0 deletions hack/testdata/initializer-deployments.yaml
@@ -0,0 +1,25 @@
apiVersion: extensions/v1beta1
kind: Deployment
metadata:
name: web
initializers:
pending:
- name: podimage.initializer.com
labels:
run: web
spec:
replicas: 5
selector:
matchLabels:
run: web
template:
metadata:
labels:
run: web
spec:
containers:
- image: nginx:1.10
name: web
ports:
- containerPort: 80
protocol: TCP
19 changes: 19 additions & 0 deletions hack/testdata/initializer-redis-master-service.yaml
@@ -0,0 +1,19 @@
apiVersion: v1
kind: Service
metadata:
name: redis-master
labels:
app: redis
role: master
tier: backend
initializers:
pending:
- name: podimage.initializer.com
spec:
ports:
- port: 6379
targetPort: 6379
selector:
app: redis
role: master
tier: backend
7 changes: 5 additions & 2 deletions pkg/kubectl/cmd/annotate.go
Expand Up @@ -128,10 +128,11 @@ func NewCmdAnnotate(f cmdutil.Factory, out io.Writer) *cobra.Command {
ArgAliases: argAliases,
}
cmdutil.AddPrinterFlags(cmd)
cmdutil.AddIncludeUninitializedFlag(cmd)
cmd.Flags().Bool("overwrite", false, "If true, allow annotations to be overwritten, otherwise reject annotation updates that overwrite existing annotations.")
cmd.Flags().Bool("local", false, "If true, annotation will NOT contact api-server but run locally.")
cmd.Flags().StringP("selector", "l", "", "Selector (label query) to filter on, supports '=', '==', and '!='.(e.g. -l key1=value1,key2=value2)")
cmd.Flags().Bool("all", false, "Select all resources in the namespace of the specified resource types")
cmd.Flags().StringP("selector", "l", "", "Selector (label query) to filter on, not including uninitialized ones, supports '=', '==', and '!='.(e.g. -l key1=value1,key2=value2).")
cmd.Flags().Bool("all", false, "Select all resources, including uninitialized ones, in the namespace of the specified resource types.")
cmd.Flags().String("resource-version", "", i18n.T("If non-empty, the annotation update will only succeed if this is the current resource-version for the object. Only valid when specifying a single resource."))
usage := "identifying the resource to update the annotation"
cmdutil.AddFilenameOptionFlags(cmd, &options.FilenameOptions, usage)
Expand Down Expand Up @@ -190,10 +191,12 @@ func (o AnnotateOptions) RunAnnotate(f cmdutil.Factory, cmd *cobra.Command) erro
return err
}

includeUninitialized := cmdutil.ShouldIncludeUninitialized(cmd, false)
b := builder.
ContinueOnError().
NamespaceParam(namespace).DefaultNamespace().
FilenameParam(enforceNamespace, &o.FilenameOptions).
IncludeUninitialized(includeUninitialized).
Flatten()

if !o.local {
Expand Down
16 changes: 11 additions & 5 deletions pkg/kubectl/cmd/apply.go
Expand Up @@ -118,7 +118,7 @@ func NewCmdApply(baseName string, f cmdutil.Factory, out, errOut io.Writer) *cob
cmdutil.AddFilenameOptionFlags(cmd, &options.FilenameOptions, usage)
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().BoolVar(&options.Prune, "prune", false, "Automatically delete resource objects that do not appear in the configs and are created by either apply or create --save-config. Should be used with either -l or --all.")
cmd.Flags().BoolVar(&options.Prune, "prune", false, "Automatically delete resource objects, including the uninitialized ones, that do not appear in the configs and are created by either apply or create --save-config. Should be used with either -l or --all.")
cmd.Flags().BoolVar(&options.Cascade, "cascade", true, "Only relevant during a prune or a force apply. If true, cascade the deletion of the resources managed by pruned or deleted resources (e.g. Pods created by a ReplicationController).")
cmd.Flags().IntVar(&options.GracePeriod, "grace-period", -1, "Only relevant during a prune or a force apply. Period of time in seconds given to pruned or deleted resources to terminate gracefully. Ignored if negative.")
cmd.Flags().BoolVar(&options.Force, "force", false, fmt.Sprintf("Delete and re-create the specified resource, when PATCH encounters conflict and has retried for %d times.", maxPatchRetry))
Expand All @@ -131,6 +131,7 @@ func NewCmdApply(baseName string, f cmdutil.Factory, out, errOut io.Writer) *cob
cmdutil.AddPrinterFlags(cmd)
cmdutil.AddRecordFlag(cmd)
cmdutil.AddInclude3rdPartyFlags(cmd)
cmdutil.AddIncludeUninitializedFlag(cmd)

// apply subcommands
cmd.AddCommand(NewCmdApplyViewLastApplied(f, out, errOut))
Expand Down Expand Up @@ -214,12 +215,17 @@ func RunApply(f cmdutil.Factory, cmd *cobra.Command, out, errOut io.Writer, opti
return err
}

// include the uninitialized objects by default if --prune is true
// unless explicitly set --include-uninitialized=false
includeUninitialized := cmdutil.ShouldIncludeUninitialized(cmd, options.Prune)

r := builder.
Schema(schema).
ContinueOnError().
NamespaceParam(cmdNamespace).DefaultNamespace().
FilenameParam(enforceNamespace, &options.FilenameOptions).
SelectorParam(options.Selector).
IncludeUninitialized(includeUninitialized).
Flatten().
Do()
err = r.Err()
Expand Down Expand Up @@ -381,13 +387,13 @@ func RunApply(f cmdutil.Factory, cmd *cobra.Command, out, errOut io.Writer, opti

for n := range visitedNamespaces {
for _, m := range namespacedRESTMappings {
if err := p.prune(n, m, shortOutput); err != nil {
if err := p.prune(n, m, shortOutput, includeUninitialized); err != nil {
return fmt.Errorf("error pruning namespaced object %v: %v", m.GroupVersionKind, err)
}
}
}
for _, m := range nonNamespacedRESTMappings {
if err := p.prune(metav1.NamespaceNone, m, shortOutput); err != nil {
if err := p.prune(metav1.NamespaceNone, m, shortOutput, includeUninitialized); err != nil {
return fmt.Errorf("error pruning nonNamespaced object %v: %v", m.GroupVersionKind, err)
}
}
Expand Down Expand Up @@ -460,13 +466,13 @@ type pruner struct {
out io.Writer
}

func (p *pruner) prune(namespace string, mapping *meta.RESTMapping, shortOutput bool) error {
func (p *pruner) prune(namespace string, mapping *meta.RESTMapping, shortOutput, includeUninitialized bool) error {
c, err := p.clientFunc(mapping)
if err != nil {
return err
}

objList, err := resource.NewHelper(c, mapping).List(namespace, mapping.GroupVersionKind.Version, p.selector, false)
objList, err := resource.NewHelper(c, mapping).List(namespace, mapping.GroupVersionKind.Version, p.selector, false, includeUninitialized)
if err != nil {
return err
}
Expand Down
3 changes: 2 additions & 1 deletion pkg/kubectl/cmd/apply_edit_last_applied.go
Expand Up @@ -82,7 +82,7 @@ func NewCmdApplyEditLastApplied(f cmdutil.Factory, out, errOut io.Writer) *cobra
Example: applyEditLastAppliedExample,
Run: func(cmd *cobra.Command, args []string) {
options.ChangeCause = f.Command(cmd, false)
if err := options.Complete(f, out, errOut, args); err != nil {
if err := options.Complete(f, out, errOut, args, cmd); err != nil {
cmdutil.CheckErr(err)
}
if err := options.Run(); err != nil {
Expand All @@ -99,6 +99,7 @@ func NewCmdApplyEditLastApplied(f cmdutil.Factory, out, errOut io.Writer) *cobra
cmd.Flags().BoolVar(&options.WindowsLineEndings, "windows-line-endings", runtime.GOOS == "windows",
"Defaults to the line ending native to your platform.")
cmdutil.AddRecordVarFlag(cmd, &options.Record)
cmdutil.AddIncludeUninitializedFlag(cmd)

return cmd
}
2 changes: 1 addition & 1 deletion pkg/kubectl/cmd/create.go
Expand Up @@ -209,7 +209,7 @@ func RunEditOnCreate(f cmdutil.Factory, out, errOut io.Writer, cmd *cobra.Comman
ChangeCause: f.Command(cmd, false),
Include3rdParty: cmdutil.GetFlagBool(cmd, "include-extended-apis"),
}
err := editOptions.Complete(f, out, errOut, []string{})
err := editOptions.Complete(f, out, errOut, []string{}, cmd)
if err != nil {
return err
}
Expand Down
11 changes: 7 additions & 4 deletions pkg/kubectl/cmd/delete.go
Expand Up @@ -133,7 +133,7 @@ func NewCmdDelete(f cmdutil.Factory, out, errOut io.Writer) *cobra.Command {
Example: delete_example,
Run: func(cmd *cobra.Command, args []string) {
cmdutil.CheckErr(cmdutil.ValidateOutputArgs(cmd))
if err := options.Complete(f, out, errOut, args); err != nil {
if err := options.Complete(f, out, errOut, args, cmd); err != nil {
cmdutil.CheckErr(err)
}
if err := options.Validate(cmd); err != nil {
Expand All @@ -149,8 +149,8 @@ func NewCmdDelete(f cmdutil.Factory, out, errOut io.Writer) *cobra.Command {
}
usage := "containing the resource to delete."
cmdutil.AddFilenameOptionFlags(cmd, &options.FilenameOptions, usage)
cmd.Flags().StringVarP(&options.Selector, "selector", "l", "", "Selector (label query) to filter on.")
cmd.Flags().BoolVar(&options.DeleteAll, "all", false, "Select all resources in the namespace of the specified resource types.")
cmd.Flags().StringVarP(&options.Selector, "selector", "l", "", "Selector (label query) to filter on, not including uninitialized ones.")
cmd.Flags().BoolVar(&options.DeleteAll, "all", false, "Delete all resources, including uninitialized ones, in the namespace of the specified resource types.")
cmd.Flags().BoolVar(&options.IgnoreNotFound, "ignore-not-found", false, "Treat \"resource not found\" as a successful delete. Defaults to \"true\" when --all is specified.")
cmd.Flags().BoolVar(&options.Cascade, "cascade", true, "If true, cascade the deletion of the resources managed by this resource (e.g. Pods created by a ReplicationController). Default true.")
cmd.Flags().IntVar(&options.GracePeriod, "grace-period", -1, "Period of time in seconds given to the resource to terminate gracefully. Ignored if negative.")
Expand All @@ -159,10 +159,11 @@ func NewCmdDelete(f cmdutil.Factory, out, errOut io.Writer) *cobra.Command {
cmd.Flags().DurationVar(&options.Timeout, "timeout", 0, "The length of time to wait before giving up on a delete, zero means determine a timeout from the size of the object")
cmdutil.AddOutputVarFlagsForMutation(cmd, &options.Output)
cmdutil.AddInclude3rdPartyVarFlags(cmd, &options.Include3rdParty)
cmdutil.AddIncludeUninitializedFlag(cmd)
return cmd
}

func (o *DeleteOptions) Complete(f cmdutil.Factory, out, errOut io.Writer, args []string) error {
func (o *DeleteOptions) Complete(f cmdutil.Factory, out, errOut io.Writer, args []string, cmd *cobra.Command) error {
cmdNamespace, enforceNamespace, err := f.DefaultNamespace()
if err != nil {
return err
Expand All @@ -180,11 +181,13 @@ func (o *DeleteOptions) Complete(f cmdutil.Factory, out, errOut io.Writer, args
}

o.Mapper = mapper
includeUninitialized := cmdutil.ShouldIncludeUninitialized(cmd, false)
r := builder.
ContinueOnError().
NamespaceParam(cmdNamespace).DefaultNamespace().
FilenameParam(enforceNamespace, &o.FilenameOptions).
SelectorParam(o.Selector).
IncludeUninitialized(includeUninitialized).
SelectAllParam(o.DeleteAll).
ResourceTypeOrNameArgs(false, args...).RequireObject(false).
Flatten().
Expand Down
17 changes: 13 additions & 4 deletions pkg/kubectl/cmd/delete_test.go
Expand Up @@ -26,6 +26,8 @@ import (
"testing"
"time"

"github.com/spf13/cobra"

"k8s.io/apimachinery/pkg/api/errors"
"k8s.io/apimachinery/pkg/api/meta"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
Expand All @@ -41,6 +43,13 @@ import (

var unstructuredSerializer = dynamic.ContentConfig().NegotiatedSerializer

var fakecmd = &cobra.Command{
Use: "delete ([-f FILENAME] | TYPE [(NAME | -l label | --all)])",
Run: func(cmd *cobra.Command, args []string) {
cmdutil.CheckErr(cmdutil.ValidateOutputArgs(cmd))
},
}

func TestDeleteObjectByTuple(t *testing.T) {
initTestErrorHandler(t)
_, _, rc := testData()
Expand Down Expand Up @@ -345,7 +354,7 @@ func TestDeleteObjectNotFound(t *testing.T) {
Cascade: false,
Output: "name",
}
err := options.Complete(f, buf, errBuf, []string{})
err := options.Complete(f, buf, errBuf, []string{}, fakecmd)
if err != nil {
t.Errorf("unexpected error: %v", err)
}
Expand Down Expand Up @@ -426,7 +435,7 @@ func TestDeleteAllNotFound(t *testing.T) {
IgnoreNotFound: false,
Output: "name",
}
err := options.Complete(f, buf, errBuf, []string{"services"})
err := options.Complete(f, buf, errBuf, []string{"services"}, fakecmd)
if err != nil {
t.Errorf("unexpected error: %v", err)
}
Expand Down Expand Up @@ -546,7 +555,7 @@ func TestDeleteMultipleObjectContinueOnMissing(t *testing.T) {
Cascade: false,
Output: "name",
}
err := options.Complete(f, buf, errBuf, []string{})
err := options.Complete(f, buf, errBuf, []string{}, fakecmd)
if err != nil {
t.Errorf("unexpected error: %v", err)
}
Expand Down Expand Up @@ -714,7 +723,7 @@ func TestResourceErrors(t *testing.T) {
Cascade: false,
Output: "name",
}
err := options.Complete(f, buf, errBuf, testCase.args)
err := options.Complete(f, buf, errBuf, testCase.args, fakecmd)
if !testCase.errFn(err) {
t.Errorf("%s: unexpected error: %v", k, err)
continue
Expand Down
7 changes: 7 additions & 0 deletions pkg/kubectl/cmd/describe.go
Expand Up @@ -39,6 +39,7 @@ import (
var (
describe_long = templates.LongDesc(`
Show details of a specific resource or group of resources.
It includes the uninitialized objects, unless --include-uninitialized=false is explicitly set.
This command joins many API calls together to form a detailed description of a
given resource or group of resources.

Expand Down Expand Up @@ -97,6 +98,7 @@ func NewCmdDescribe(f cmdutil.Factory, out, cmdErr io.Writer) *cobra.Command {
cmd.Flags().Bool("all-namespaces", false, "If present, list the requested object(s) across all namespaces. Namespace in current context is ignored even if specified with --namespace.")
cmd.Flags().BoolVar(&describerSettings.ShowEvents, "show-events", true, "If true, display events related to the described object.")
cmdutil.AddInclude3rdPartyFlags(cmd)
cmdutil.AddIncludeUninitializedFlag(cmd)
return cmd
}

Expand All @@ -120,11 +122,16 @@ func RunDescribe(f cmdutil.Factory, out, cmdErr io.Writer, cmd *cobra.Command, a
return err
}

// include the uninitialized objects by default
// unless user explicitly set --include-uninitialized=false
includeUninitialized := cmdutil.ShouldIncludeUninitialized(cmd, true)

r := builder.
ContinueOnError().
NamespaceParam(cmdNamespace).DefaultNamespace().AllNamespaces(allNamespaces).
FilenameParam(enforceNamespace, options).
SelectorParam(selector).
IncludeUninitialized(includeUninitialized).
ResourceTypeOrNameArgs(true, args...).
Flatten().
Do()
Expand Down
3 changes: 2 additions & 1 deletion pkg/kubectl/cmd/edit.go
Expand Up @@ -93,7 +93,7 @@ func NewCmdEdit(f cmdutil.Factory, out, errOut io.Writer) *cobra.Command {
Example: fmt.Sprintf(editExample),
Run: func(cmd *cobra.Command, args []string) {
options.ChangeCause = f.Command(cmd, false)
if err := options.Complete(f, out, errOut, args); err != nil {
if err := options.Complete(f, out, errOut, args, cmd); err != nil {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Have you add the flag to edit command?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@mengqiy No. This is the side effect since options.Complete has been changed. We've not planed adding include-uninitialized flag to kubectl edit. @caesarxuchao @ahmetb Correct me if I'm wrong.

I've added below codes to method Complete(...), so that it will not break current kubectl edit.

if cmd.Flags().Lookup("include-uninitialized") != nil {
        includeUninitialized = cmdutil.GetFlagBool(cmd, "include-uninitialized")
}

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think include-uninitialized should be plumbed to every commands. kubectl edit user should be able to edit the uninitialized objects if they specify --include-uninitialized=true.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

(to clarify again, my understanding is that they should NOT need --include-uninitialized, if they're referring to object by name, i.e. kubectl edit pod/foo)

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes. If the name of the object is provided, kubectl always show it.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

kubectl edit , by default don't include uninitialized objects, unless user explicitly sets --include-uninitialized=true.

@dixudx I think we need that flag per #49035 (comment). Did I miss some something here?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@mengqiy You're right. I forgot to add here. Sorry for that. Will add it later when finishing the tests.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think include-uninitialized should be plumbed to every commands.

@caesarxuchao Currently we've only enabled --include-uninitialized in a few commands. To make it a global flag, we may need to make rules for every subcommand.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@dixudx could you give me some examples of the subcommands that don't support --include-uninitialized?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@caesarxuchao My mistake. Seems we have already supported them well. After a deep search, I found we only need to enable --include-uninitialized for subcommands that would request a group of resources. For a single specific resource, there is no need.

cmdutil.CheckErr(err)
}
if err := options.Run(); err != nil {
Expand All @@ -115,5 +115,6 @@ func NewCmdEdit(f cmdutil.Factory, out, errOut io.Writer) *cobra.Command {
cmdutil.AddApplyAnnotationVarFlags(cmd, &options.ApplyAnnotation)
cmdutil.AddRecordVarFlag(cmd, &options.Record)
cmdutil.AddInclude3rdPartyVarFlags(cmd, &options.Include3rdParty)
cmdutil.AddIncludeUninitializedFlag(cmd)
return cmd
}
17 changes: 15 additions & 2 deletions pkg/kubectl/cmd/get.go
Expand Up @@ -58,7 +58,8 @@ var (

This command will hide resources that have completed, such as pods that are
in the Succeeded or Failed phases. You can see the full results for any
resource by providing the '--show-all' flag.
resource by providing the '--show-all' flag, but this flag does not include
the uninitialized objects by default, unless '--include-uninitialized' is explicitly set.

By specifying the output as 'template' and providing a Go template as the value
of the --template flag, you can filter the attributes of the fetched resources.`)
Expand Down Expand Up @@ -127,7 +128,8 @@ func NewCmdGet(f cmdutil.Factory, out io.Writer, errOut io.Writer) *cobra.Comman
}
cmdutil.AddPrinterFlags(cmd)
cmd.Flags().StringP("selector", "l", "", "Selector (label query) to filter on, supports '=', '==', and '!='.(e.g. -l key1=value1,key2=value2)")
cmd.Flags().BoolP("watch", "w", false, "After listing/getting the requested object, watch for changes.")
cmdutil.AddIncludeUninitializedFlag(cmd)
cmd.Flags().BoolP("watch", "w", false, "After listing/getting the requested object, watch for changes. Uninitialized objects are excluded if no object name is provided.")
cmd.Flags().Bool("watch-only", false, "Watch for changes to the requested object(s), without listing/getting first.")
cmd.Flags().Bool("show-kind", false, "If present, list the resource type for the requested object(s).")
cmd.Flags().Bool("all-namespaces", false, "If present, list the requested object(s) across all namespaces. Namespace in current context is ignored even if specified with --namespace.")
Expand Down Expand Up @@ -201,6 +203,15 @@ func RunGet(f cmdutil.Factory, out, errOut io.Writer, cmd *cobra.Command, args [

// handle watch separately since we cannot watch multiple resource types
isWatch, isWatchOnly := cmdutil.GetFlagBool(cmd, "watch"), cmdutil.GetFlagBool(cmd, "watch-only")

var includeUninitialized bool
if isWatch && len(args) == 2 {
// include the uninitialized one for watching on a single object
// unless explicitly set --include-uninitialized=false
includeUninitialized = true
}
includeUninitialized = cmdutil.ShouldIncludeUninitialized(cmd, includeUninitialized)

if isWatch || isWatchOnly {
builder, err := f.NewUnstructuredBuilder(true)
if err != nil {
Expand All @@ -212,6 +223,7 @@ func RunGet(f cmdutil.Factory, out, errOut io.Writer, cmd *cobra.Command, args [
FilenameParam(enforceNamespace, &options.FilenameOptions).
SelectorParam(selector).
ExportParam(export).
IncludeUninitialized(includeUninitialized).
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is affecting WATCH verb. @caesarxuchao It's not clear to me what the behavior should be.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

kubectl get -w pods foo should include the events of uninitialized foo.
kubectl get -w pods doesn't include uninitialized pods unless --include-uninitialized=true.

ResourceTypeOrNameArgs(true, args...).
SingleResourceType().
Latest().
Expand Down Expand Up @@ -301,6 +313,7 @@ func RunGet(f cmdutil.Factory, out, errOut io.Writer, cmd *cobra.Command, args [
FilenameParam(enforceNamespace, &options.FilenameOptions).
SelectorParam(selector).
ExportParam(export).
IncludeUninitialized(includeUninitialized).
ResourceTypeOrNameArgs(true, args...).
ContinueOnError().
Latest().
Expand Down