Merge pull request #9720 from Joeavaikath/feature/dynamic-cli-completion

Add dynamic resource autocompletion to Velero CLI
This commit is contained in:
Joseph Antony Vaikath
2026-08-05 08:32:12 -07:00
committed by GitHub
28 changed files with 371 additions and 1 deletions
+1
View File
@@ -0,0 +1 @@
Add dynamic resource autocompletion to Velero CLI
+5
View File
@@ -32,6 +32,7 @@ import (
"github.com/vmware-tanzu/velero/pkg/builder"
"github.com/vmware-tanzu/velero/pkg/client"
"github.com/vmware-tanzu/velero/pkg/cmd"
"github.com/vmware-tanzu/velero/pkg/cmd/cli"
"github.com/vmware-tanzu/velero/pkg/cmd/util/flag"
"github.com/vmware-tanzu/velero/pkg/cmd/util/output"
"github.com/vmware-tanzu/velero/pkg/util/collections"
@@ -75,6 +76,10 @@ func NewCreateCommand(f client.Factory, use string) *cobra.Command {
output.BindFlags(c.Flags())
output.ClearOutputFlagDefault(c)
_ = c.RegisterFlagCompletionFunc("from-schedule", cli.CompleteScheduleNames(f))
_ = c.RegisterFlagCompletionFunc("storage-location", cli.CompleteBackupStorageLocationNames(f))
_ = c.RegisterFlagCompletionFunc("volume-snapshot-locations", cli.CompleteVolumeSnapshotLocationNames(f))
return c
}
+1
View File
@@ -64,6 +64,7 @@ func NewDeleteCommand(f client.Factory, use string) *cobra.Command {
},
}
c.ValidArgsFunction = cli.CompleteBackupNames(f)
o.BindFlags(c.Flags())
return c
+2
View File
@@ -29,6 +29,7 @@ import (
velerov1api "github.com/vmware-tanzu/velero/pkg/apis/velero/v1"
"github.com/vmware-tanzu/velero/pkg/client"
"github.com/vmware-tanzu/velero/pkg/cmd"
"github.com/vmware-tanzu/velero/pkg/cmd/cli"
"github.com/vmware-tanzu/velero/pkg/cmd/util/output"
"github.com/vmware-tanzu/velero/pkg/label"
)
@@ -112,6 +113,7 @@ func NewDescribeCommand(f client.Factory, use string) *cobra.Command {
},
}
c.ValidArgsFunction = cli.CompleteBackupNames(f)
c.Flags().StringVarP(&listOptions.LabelSelector, "selector", "l", listOptions.LabelSelector, "Only show items matching this label selector.")
c.Flags().BoolVar(&details, "details", details, "Display additional detail in the command output.")
c.Flags().BoolVar(&insecureSkipTLSVerify, "insecure-skip-tls-verify", insecureSkipTLSVerify, "If true, the object store's TLS certificate will not be checked for validity. This is insecure and susceptible to man-in-the-middle attacks. Not recommended for production.")
+2
View File
@@ -31,6 +31,7 @@ import (
velerov1api "github.com/vmware-tanzu/velero/pkg/apis/velero/v1"
"github.com/vmware-tanzu/velero/pkg/client"
"github.com/vmware-tanzu/velero/pkg/cmd"
"github.com/vmware-tanzu/velero/pkg/cmd/cli"
"github.com/vmware-tanzu/velero/pkg/cmd/util/cacert"
"github.com/vmware-tanzu/velero/pkg/cmd/util/downloadrequest"
)
@@ -55,6 +56,7 @@ func NewDownloadCommand(f client.Factory) *cobra.Command {
},
}
c.ValidArgsFunction = cli.CompleteBackupNames(f)
o.BindFlags(c.Flags())
return c
+2
View File
@@ -27,6 +27,7 @@ import (
api "github.com/vmware-tanzu/velero/pkg/apis/velero/v1"
"github.com/vmware-tanzu/velero/pkg/client"
"github.com/vmware-tanzu/velero/pkg/cmd"
"github.com/vmware-tanzu/velero/pkg/cmd/cli"
"github.com/vmware-tanzu/velero/pkg/cmd/util/output"
)
@@ -66,6 +67,7 @@ func NewGetCommand(f client.Factory, use string) *cobra.Command {
},
}
c.ValidArgsFunction = cli.CompleteBackupNames(f)
c.Flags().StringVarP(&listOptions.LabelSelector, "selector", "l", listOptions.LabelSelector, "Only show items matching this label selector")
output.BindFlags(c.Flags())
+2
View File
@@ -30,6 +30,7 @@ import (
velerov1api "github.com/vmware-tanzu/velero/pkg/apis/velero/v1"
"github.com/vmware-tanzu/velero/pkg/client"
"github.com/vmware-tanzu/velero/pkg/cmd"
"github.com/vmware-tanzu/velero/pkg/cmd/cli"
"github.com/vmware-tanzu/velero/pkg/cmd/util/cacert"
"github.com/vmware-tanzu/velero/pkg/cmd/util/downloadrequest"
)
@@ -119,6 +120,7 @@ func NewLogsCommand(f client.Factory) *cobra.Command {
},
}
c.ValidArgsFunction = cli.CompleteBackupNames(f)
l.BindFlags(c.Flags())
return c
+1
View File
@@ -62,6 +62,7 @@ func NewDeleteCommand(f client.Factory, use string) *cobra.Command {
},
}
c.ValidArgsFunction = cli.CompleteBackupStorageLocationNames(f)
o.BindFlags(c.Flags())
return c
}
+2
View File
@@ -27,6 +27,7 @@ import (
velerov1api "github.com/vmware-tanzu/velero/pkg/apis/velero/v1"
"github.com/vmware-tanzu/velero/pkg/client"
"github.com/vmware-tanzu/velero/pkg/cmd"
"github.com/vmware-tanzu/velero/pkg/cmd/cli"
"github.com/vmware-tanzu/velero/pkg/cmd/util/output"
)
@@ -89,6 +90,7 @@ func NewGetCommand(f client.Factory, use string) *cobra.Command {
},
}
c.ValidArgsFunction = cli.CompleteBackupStorageLocationNames(f)
c.Flags().BoolVar(&showDefaultOnly, "default", false, "Displays the current default backup storage location.")
c.Flags().StringVarP(&listOptions.LabelSelector, "selector", "l", listOptions.LabelSelector, "Only show items matching this label selector.")
+2
View File
@@ -33,6 +33,7 @@ import (
"github.com/vmware-tanzu/velero/pkg/builder"
"github.com/vmware-tanzu/velero/pkg/client"
"github.com/vmware-tanzu/velero/pkg/cmd"
"github.com/vmware-tanzu/velero/pkg/cmd/cli"
"github.com/vmware-tanzu/velero/pkg/cmd/util/flag"
"github.com/vmware-tanzu/velero/pkg/util/boolptr"
)
@@ -51,6 +52,7 @@ func NewSetCommand(f client.Factory, use string) *cobra.Command {
},
}
c.ValidArgsFunction = cli.CompleteBackupStorageLocationNames(f)
o.BindFlags(c.Flags())
return c
+105
View File
@@ -0,0 +1,105 @@
/*
Copyright The Velero Contributors.
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 cli
import (
"context"
"strings"
"time"
"github.com/spf13/cobra"
"k8s.io/apimachinery/pkg/api/meta"
kbclient "sigs.k8s.io/controller-runtime/pkg/client"
velerov1api "github.com/vmware-tanzu/velero/pkg/apis/velero/v1"
"github.com/vmware-tanzu/velero/pkg/client"
)
// completionFunc is the function signature for cobra's ValidArgsFunction.
type completionFunc = func(cmd *cobra.Command, args []string, toComplete string) ([]string, cobra.ShellCompDirective)
// completeNames builds a completion function for any Velero list type.
// It extracts resource names via apimachinery's meta helpers.
func completeNames(f client.Factory, list kbclient.ObjectList) completionFunc {
return func(cmd *cobra.Command, args []string, toComplete string) ([]string, cobra.ShellCompDirective) {
kbClient, err := f.KubebuilderClient()
if err != nil {
return nil, cobra.ShellCompDirectiveNoFileComp
}
parentCtx := context.Background()
if cmd != nil && cmd.Context() != nil {
parentCtx = cmd.Context()
}
ctx, cancel := context.WithTimeout(parentCtx, 3*time.Second)
defer cancel()
freshObject := list.DeepCopyObject()
freshList, ok := freshObject.(kbclient.ObjectList)
if !ok {
return nil, cobra.ShellCompDirectiveNoFileComp
}
if err := kbClient.List(ctx, freshList, &kbclient.ListOptions{Namespace: f.Namespace()}); err != nil {
return nil, cobra.ShellCompDirectiveNoFileComp
}
items, err := meta.ExtractList(freshList)
if err != nil {
return nil, cobra.ShellCompDirectiveNoFileComp
}
seen := make(map[string]bool, len(args))
for _, a := range args {
seen[a] = true
}
var filtered []string
for _, item := range items {
accessor, err := meta.Accessor(item)
if err != nil {
continue
}
name := accessor.GetName()
if seen[name] {
continue
}
if strings.HasPrefix(name, toComplete) {
filtered = append(filtered, name)
}
}
return filtered, cobra.ShellCompDirectiveNoFileComp
}
}
func CompleteBackupNames(f client.Factory) completionFunc {
return completeNames(f, &velerov1api.BackupList{})
}
func CompleteRestoreNames(f client.Factory) completionFunc {
return completeNames(f, &velerov1api.RestoreList{})
}
func CompleteScheduleNames(f client.Factory) completionFunc {
return completeNames(f, &velerov1api.ScheduleList{})
}
func CompleteBackupStorageLocationNames(f client.Factory) completionFunc {
return completeNames(f, &velerov1api.BackupStorageLocationList{})
}
func CompleteVolumeSnapshotLocationNames(f client.Factory) completionFunc {
return completeNames(f, &velerov1api.VolumeSnapshotLocationList{})
}
func CompleteBackupRepositoryNames(f client.Factory) completionFunc {
return completeNames(f, &velerov1api.BackupRepositoryList{})
}
+212
View File
@@ -0,0 +1,212 @@
/*
Copyright The Velero Contributors.
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 cli
import (
"fmt"
"testing"
"github.com/spf13/cobra"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/apimachinery/pkg/runtime"
kbclient "sigs.k8s.io/controller-runtime/pkg/client"
velerov1api "github.com/vmware-tanzu/velero/pkg/apis/velero/v1"
factorymocks "github.com/vmware-tanzu/velero/pkg/client/mocks"
velerotest "github.com/vmware-tanzu/velero/pkg/test"
)
// TestCompleteNames exercises the core completeNames helper with various list
// types, prefix filters, and edge cases (empty cluster, no match).
func TestCompleteNames(t *testing.T) {
tests := []struct {
name string
objects []runtime.Object
list kbclient.ObjectList
args []string
toComplete string
want []string
}{
{
name: "no resources returns nil",
objects: nil,
list: &velerov1api.BackupList{},
toComplete: "",
want: nil,
},
{
name: "returns all matching names",
objects: []runtime.Object{
&velerov1api.Backup{ObjectMeta: metav1.ObjectMeta{Name: "daily", Namespace: "velero"}},
&velerov1api.Backup{ObjectMeta: metav1.ObjectMeta{Name: "weekly", Namespace: "velero"}},
},
list: &velerov1api.BackupList{},
toComplete: "",
want: []string{"daily", "weekly"},
},
{
name: "filters by prefix",
objects: []runtime.Object{
&velerov1api.Backup{ObjectMeta: metav1.ObjectMeta{Name: "daily", Namespace: "velero"}},
&velerov1api.Backup{ObjectMeta: metav1.ObjectMeta{Name: "weekly", Namespace: "velero"}},
&velerov1api.Backup{ObjectMeta: metav1.ObjectMeta{Name: "daily-full", Namespace: "velero"}},
},
list: &velerov1api.BackupList{},
toComplete: "dai",
want: []string{"daily", "daily-full"},
},
{
name: "no prefix match returns nil",
objects: []runtime.Object{
&velerov1api.Backup{ObjectMeta: metav1.ObjectMeta{Name: "daily", Namespace: "velero"}},
},
list: &velerov1api.BackupList{},
toComplete: "xyz",
want: nil,
},
{
name: "works with RestoreList",
objects: []runtime.Object{
&velerov1api.Restore{ObjectMeta: metav1.ObjectMeta{Name: "restore-1", Namespace: "velero"}},
&velerov1api.Restore{ObjectMeta: metav1.ObjectMeta{Name: "restore-2", Namespace: "velero"}},
},
list: &velerov1api.RestoreList{},
toComplete: "restore-",
want: []string{"restore-1", "restore-2"},
},
{
name: "works with ScheduleList",
objects: []runtime.Object{
&velerov1api.Schedule{ObjectMeta: metav1.ObjectMeta{Name: "nightly", Namespace: "velero"}},
},
list: &velerov1api.ScheduleList{},
toComplete: "",
want: []string{"nightly"},
},
{
name: "works with BackupStorageLocationList",
objects: []runtime.Object{
&velerov1api.BackupStorageLocation{ObjectMeta: metav1.ObjectMeta{Name: "default", Namespace: "velero"}},
&velerov1api.BackupStorageLocation{ObjectMeta: metav1.ObjectMeta{Name: "secondary", Namespace: "velero"}},
},
list: &velerov1api.BackupStorageLocationList{},
toComplete: "s",
want: []string{"secondary"},
},
{
name: "works with VolumeSnapshotLocationList",
objects: []runtime.Object{
&velerov1api.VolumeSnapshotLocation{ObjectMeta: metav1.ObjectMeta{Name: "aws-snap", Namespace: "velero"}},
},
list: &velerov1api.VolumeSnapshotLocationList{},
toComplete: "",
want: []string{"aws-snap"},
},
{
name: "works with BackupRepositoryList",
objects: []runtime.Object{
&velerov1api.BackupRepository{ObjectMeta: metav1.ObjectMeta{Name: "repo-1", Namespace: "velero"}},
},
list: &velerov1api.BackupRepositoryList{},
toComplete: "",
want: []string{"repo-1"},
},
{
name: "excludes already-typed args",
objects: []runtime.Object{
&velerov1api.Backup{ObjectMeta: metav1.ObjectMeta{Name: "daily", Namespace: "velero"}},
&velerov1api.Backup{ObjectMeta: metav1.ObjectMeta{Name: "weekly", Namespace: "velero"}},
&velerov1api.Backup{ObjectMeta: metav1.ObjectMeta{Name: "monthly", Namespace: "velero"}},
},
list: &velerov1api.BackupList{},
args: []string{"daily", "monthly"},
toComplete: "",
want: []string{"weekly"},
},
}
for _, tc := range tests {
t.Run(tc.name, func(t *testing.T) {
kbClient := velerotest.NewFakeControllerRuntimeClient(t, tc.objects...)
f := new(factorymocks.Factory)
f.On("KubebuilderClient").Return(kbClient, nil)
f.On("Namespace").Return("velero")
completionFn := completeNames(f, tc.list)
got, directive := completionFn(&cobra.Command{}, tc.args, tc.toComplete)
assert.Equal(t, cobra.ShellCompDirectiveNoFileComp, directive)
assert.ElementsMatch(t, tc.want, got)
})
}
}
// TestCompleteNames_KubebuilderClientError verifies that a factory error
// (e.g. no kubeconfig) returns nil completions instead of panicking.
func TestCompleteNames_KubebuilderClientError(t *testing.T) {
f := new(factorymocks.Factory)
f.On("KubebuilderClient").Return(nil, fmt.Errorf("connection refused"))
completionFn := completeNames(f, &velerov1api.BackupList{})
got, directive := completionFn(&cobra.Command{}, nil, "")
assert.Equal(t, cobra.ShellCompDirectiveNoFileComp, directive)
assert.Nil(t, got)
}
// TestCompleteWrappers verifies each exported Complete*Names wrapper returns
// only its own resource type. A single fake client holds one object of every
// type, so each wrapper must filter correctly and not leak other kinds.
func TestCompleteWrappers(t *testing.T) {
objects := []runtime.Object{
&velerov1api.Backup{ObjectMeta: metav1.ObjectMeta{Name: "b1", Namespace: "velero"}},
&velerov1api.Restore{ObjectMeta: metav1.ObjectMeta{Name: "r1", Namespace: "velero"}},
&velerov1api.Schedule{ObjectMeta: metav1.ObjectMeta{Name: "s1", Namespace: "velero"}},
&velerov1api.BackupStorageLocation{ObjectMeta: metav1.ObjectMeta{Name: "bsl1", Namespace: "velero"}},
&velerov1api.VolumeSnapshotLocation{ObjectMeta: metav1.ObjectMeta{Name: "vsl1", Namespace: "velero"}},
&velerov1api.BackupRepository{ObjectMeta: metav1.ObjectMeta{Name: "br1", Namespace: "velero"}},
}
kbClient := velerotest.NewFakeControllerRuntimeClient(t, objects...)
f := new(factorymocks.Factory)
f.On("KubebuilderClient").Return(kbClient, nil)
f.On("Namespace").Return("velero")
tests := []struct {
name string
fn completionFunc
expected []string
}{
{"CompleteBackupNames", CompleteBackupNames(f), []string{"b1"}},
{"CompleteRestoreNames", CompleteRestoreNames(f), []string{"r1"}},
{"CompleteScheduleNames", CompleteScheduleNames(f), []string{"s1"}},
{"CompleteBackupStorageLocationNames", CompleteBackupStorageLocationNames(f), []string{"bsl1"}},
{"CompleteVolumeSnapshotLocationNames", CompleteVolumeSnapshotLocationNames(f), []string{"vsl1"}},
{"CompleteBackupRepositoryNames", CompleteBackupRepositoryNames(f), []string{"br1"}},
}
for _, tc := range tests {
t.Run(tc.name, func(t *testing.T) {
got, directive := tc.fn(&cobra.Command{}, nil, "")
require.Equal(t, cobra.ShellCompDirectiveNoFileComp, directive)
assert.Equal(t, tc.expected, got)
})
}
}
+5
View File
@@ -38,6 +38,7 @@ import (
velerov1api "github.com/vmware-tanzu/velero/pkg/apis/velero/v1"
"github.com/vmware-tanzu/velero/pkg/client"
"github.com/vmware-tanzu/velero/pkg/cmd"
"github.com/vmware-tanzu/velero/pkg/cmd/cli"
)
//go:embed cshd-scripts/velero.cshd
@@ -171,6 +172,10 @@ specs of resources created by velero server, and optionally the logs of backup a
},
}
o.bindFlags(c.Flags())
_ = c.RegisterFlagCompletionFunc("backup", cli.CompleteBackupNames(f))
_ = c.RegisterFlagCompletionFunc("restore", cli.CompleteRestoreNames(f))
return c
}
+2
View File
@@ -27,6 +27,7 @@ import (
api "github.com/vmware-tanzu/velero/pkg/apis/velero/v1"
"github.com/vmware-tanzu/velero/pkg/client"
"github.com/vmware-tanzu/velero/pkg/cmd"
"github.com/vmware-tanzu/velero/pkg/cmd/cli"
"github.com/vmware-tanzu/velero/pkg/cmd/util/output"
)
@@ -66,6 +67,7 @@ func NewGetCommand(f client.Factory, use string) *cobra.Command {
},
}
c.ValidArgsFunction = cli.CompleteBackupRepositoryNames(f)
c.Flags().StringVarP(&listOptions.LabelSelector, "selector", "l", listOptions.LabelSelector, "Only show items matching this label selector.")
output.BindFlags(c.Flags())
+4
View File
@@ -36,6 +36,7 @@ import (
api "github.com/vmware-tanzu/velero/pkg/apis/velero/v1"
"github.com/vmware-tanzu/velero/pkg/client"
"github.com/vmware-tanzu/velero/pkg/cmd"
"github.com/vmware-tanzu/velero/pkg/cmd/cli"
"github.com/vmware-tanzu/velero/pkg/cmd/util/flag"
"github.com/vmware-tanzu/velero/pkg/cmd/util/output"
"github.com/vmware-tanzu/velero/pkg/util/boolptr"
@@ -81,6 +82,9 @@ Notes:
output.BindFlags(c.Flags())
output.ClearOutputFlagDefault(c)
_ = c.RegisterFlagCompletionFunc("from-backup", cli.CompleteBackupNames(f))
_ = c.RegisterFlagCompletionFunc("from-schedule", cli.CompleteScheduleNames(f))
return c
}
+1
View File
@@ -61,6 +61,7 @@ func NewDeleteCommand(f client.Factory, use string) *cobra.Command {
cmd.CheckError(Run(o))
},
}
c.ValidArgsFunction = cli.CompleteRestoreNames(f)
o.BindFlags(c.Flags())
return c
}
+2
View File
@@ -29,6 +29,7 @@ import (
velerov1api "github.com/vmware-tanzu/velero/pkg/apis/velero/v1"
"github.com/vmware-tanzu/velero/pkg/client"
"github.com/vmware-tanzu/velero/pkg/cmd"
"github.com/vmware-tanzu/velero/pkg/cmd/cli"
"github.com/vmware-tanzu/velero/pkg/cmd/util/output"
"github.com/vmware-tanzu/velero/pkg/label"
)
@@ -92,6 +93,7 @@ func NewDescribeCommand(f client.Factory, use string) *cobra.Command {
},
}
c.ValidArgsFunction = cli.CompleteRestoreNames(f)
c.Flags().StringVarP(&listOptions.LabelSelector, "selector", "l", listOptions.LabelSelector, "Only show items matching this label selector.")
c.Flags().BoolVar(&details, "details", details, "Display additional detail in the command output.")
c.Flags().BoolVar(&insecureSkipTLSVerify, "insecure-skip-tls-verify", insecureSkipTLSVerify, "If true, the object store's TLS certificate will not be checked for validity. This is insecure and susceptible to man-in-the-middle attacks. Not recommended for production.")
+2
View File
@@ -27,6 +27,7 @@ import (
api "github.com/vmware-tanzu/velero/pkg/apis/velero/v1"
"github.com/vmware-tanzu/velero/pkg/client"
"github.com/vmware-tanzu/velero/pkg/cmd"
"github.com/vmware-tanzu/velero/pkg/cmd/cli"
"github.com/vmware-tanzu/velero/pkg/cmd/util/output"
)
@@ -76,6 +77,7 @@ func NewGetCommand(f client.Factory, use string) *cobra.Command {
},
}
c.ValidArgsFunction = cli.CompleteRestoreNames(f)
c.Flags().StringVarP(&listOptions.LabelSelector, "selector", "l", listOptions.LabelSelector, "Only show items matching this label selector.")
output.BindFlags(c.Flags())
+2
View File
@@ -29,6 +29,7 @@ import (
velerov1api "github.com/vmware-tanzu/velero/pkg/apis/velero/v1"
"github.com/vmware-tanzu/velero/pkg/client"
"github.com/vmware-tanzu/velero/pkg/cmd"
"github.com/vmware-tanzu/velero/pkg/cmd/cli"
"github.com/vmware-tanzu/velero/pkg/cmd/util/cacert"
"github.com/vmware-tanzu/velero/pkg/cmd/util/downloadrequest"
)
@@ -82,6 +83,7 @@ func NewLogsCommand(f client.Factory) *cobra.Command {
},
}
c.ValidArgsFunction = cli.CompleteRestoreNames(f)
c.Flags().DurationVar(&timeout, "timeout", timeout, "How long to wait to receive logs.")
c.Flags().BoolVar(&insecureSkipTLSVerify, "insecure-skip-tls-verify", insecureSkipTLSVerify, "If true, the object store's TLS certificate will not be checked for validity. This is insecure and susceptible to man-in-the-middle attacks. Not recommended for production.")
c.Flags().StringVar(&caCertFile, "cacert", caCertFile, "Path to a certificate bundle to use when verifying TLS connections. If not specified, the CA certificate from the BackupStorageLocation will be used if available.")
+4
View File
@@ -30,6 +30,7 @@ import (
api "github.com/vmware-tanzu/velero/pkg/apis/velero/v1"
"github.com/vmware-tanzu/velero/pkg/client"
"github.com/vmware-tanzu/velero/pkg/cmd"
"github.com/vmware-tanzu/velero/pkg/cmd/cli"
"github.com/vmware-tanzu/velero/pkg/cmd/cli/backup"
"github.com/vmware-tanzu/velero/pkg/cmd/util/output"
)
@@ -77,6 +78,9 @@ example: "@every 2h30m".`,
output.BindFlags(c.Flags())
output.ClearOutputFlagDefault(c)
_ = c.RegisterFlagCompletionFunc("storage-location", cli.CompleteBackupStorageLocationNames(f))
_ = c.RegisterFlagCompletionFunc("volume-snapshot-locations", cli.CompleteVolumeSnapshotLocationNames(f))
return c
}
+1
View File
@@ -62,6 +62,7 @@ func NewDeleteCommand(f client.Factory, use string) *cobra.Command {
},
}
c.ValidArgsFunction = cli.CompleteScheduleNames(f)
o.BindFlags(c.Flags())
return c
}
+2
View File
@@ -28,6 +28,7 @@ import (
v1 "github.com/vmware-tanzu/velero/pkg/apis/velero/v1"
"github.com/vmware-tanzu/velero/pkg/client"
"github.com/vmware-tanzu/velero/pkg/cmd"
"github.com/vmware-tanzu/velero/pkg/cmd/cli"
"github.com/vmware-tanzu/velero/pkg/cmd/util/output"
)
@@ -73,6 +74,7 @@ func NewDescribeCommand(f client.Factory, use string) *cobra.Command {
},
}
c.ValidArgsFunction = cli.CompleteScheduleNames(f)
c.Flags().StringVarP(&listOptions.LabelSelector, "selector", "l", listOptions.LabelSelector, "Only show items matching this label selector.")
return c
+2
View File
@@ -27,6 +27,7 @@ import (
api "github.com/vmware-tanzu/velero/pkg/apis/velero/v1"
"github.com/vmware-tanzu/velero/pkg/client"
"github.com/vmware-tanzu/velero/pkg/cmd"
"github.com/vmware-tanzu/velero/pkg/cmd/cli"
"github.com/vmware-tanzu/velero/pkg/cmd/util/output"
)
@@ -71,6 +72,7 @@ func NewGetCommand(f client.Factory, use string) *cobra.Command {
},
}
c.ValidArgsFunction = cli.CompleteScheduleNames(f)
c.Flags().StringVarP(&listOptions.LabelSelector, "selector", "l", listOptions.LabelSelector, "Only show items matching this label selector.")
output.BindFlags(c.Flags())
+1
View File
@@ -60,6 +60,7 @@ func NewPauseCommand(f client.Factory, use string) *cobra.Command {
},
}
c.ValidArgsFunction = cli.CompleteScheduleNames(f)
o.BindFlags(c.Flags())
pauseOpts.BindFlags(c.Flags())
+1
View File
@@ -49,6 +49,7 @@ func NewUnpauseCommand(f client.Factory, use string) *cobra.Command {
},
}
c.ValidArgsFunction = cli.CompleteScheduleNames(f)
o.BindFlags(c.Flags())
pauseOpts.BindFlags(c.Flags())
+2
View File
@@ -26,6 +26,7 @@ import (
api "github.com/vmware-tanzu/velero/pkg/apis/velero/v1"
"github.com/vmware-tanzu/velero/pkg/client"
"github.com/vmware-tanzu/velero/pkg/cmd"
"github.com/vmware-tanzu/velero/pkg/cmd/cli"
"github.com/vmware-tanzu/velero/pkg/cmd/util/output"
)
@@ -56,6 +57,7 @@ func NewGetCommand(f client.Factory, use string) *cobra.Command {
cmd.CheckError(err)
},
}
c.ValidArgsFunction = cli.CompleteVolumeSnapshotLocationNames(f)
c.Flags().StringVarP(&listOptions.LabelSelector, "selector", "l", listOptions.LabelSelector, "Only show items matching this label selector")
output.BindFlags(c.Flags())
return c
+2
View File
@@ -30,6 +30,7 @@ import (
"github.com/vmware-tanzu/velero/pkg/builder"
"github.com/vmware-tanzu/velero/pkg/client"
"github.com/vmware-tanzu/velero/pkg/cmd"
"github.com/vmware-tanzu/velero/pkg/cmd/cli"
"github.com/vmware-tanzu/velero/pkg/cmd/util/flag"
"github.com/vmware-tanzu/velero/pkg/cmd/util/output"
)
@@ -48,6 +49,7 @@ func NewSetCommand(f client.Factory, use string) *cobra.Command {
},
}
c.ValidArgsFunction = cli.CompleteVolumeSnapshotLocationNames(f)
o.BindFlags(c.Flags())
return c
}
@@ -356,7 +356,7 @@ Run `velero install --help` or see the [Helm chart documentation](https://vmware
### Enabling shell autocompletion
**Velero CLI** provides autocompletion support for `Bash` and `Zsh`, which can save you a lot of typing.
**Velero CLI** provides autocompletion support for `Bash`, `Zsh`, and `Fish`, which can save you a lot of typing. In addition to command and flag names, the CLI dynamically completes resource names (backups, restores, schedules, etc.) by querying the cluster.
Below are the procedures to set up autocompletion for `Bash` (including the difference between `Linux` and `macOS`) and `Zsh`.