mirror of
https://github.com/vmware-tanzu/velero.git
synced 2026-08-15 11:46:06 +00:00
Merge pull request #9720 from Joeavaikath/feature/dynamic-cli-completion
Add dynamic resource autocompletion to Velero CLI
This commit is contained in:
@@ -0,0 +1 @@
|
||||
Add dynamic resource autocompletion to Velero CLI
|
||||
@@ -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
|
||||
}
|
||||
|
||||
|
||||
@@ -64,6 +64,7 @@ func NewDeleteCommand(f client.Factory, use string) *cobra.Command {
|
||||
},
|
||||
}
|
||||
|
||||
c.ValidArgsFunction = cli.CompleteBackupNames(f)
|
||||
o.BindFlags(c.Flags())
|
||||
|
||||
return c
|
||||
|
||||
@@ -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.")
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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())
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -62,6 +62,7 @@ func NewDeleteCommand(f client.Factory, use string) *cobra.Command {
|
||||
},
|
||||
}
|
||||
|
||||
c.ValidArgsFunction = cli.CompleteBackupStorageLocationNames(f)
|
||||
o.BindFlags(c.Flags())
|
||||
return c
|
||||
}
|
||||
|
||||
@@ -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.")
|
||||
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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{})
|
||||
}
|
||||
@@ -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)
|
||||
})
|
||||
}
|
||||
}
|
||||
@@ -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
|
||||
}
|
||||
|
||||
|
||||
@@ -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())
|
||||
|
||||
@@ -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
|
||||
}
|
||||
|
||||
|
||||
@@ -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
|
||||
}
|
||||
|
||||
@@ -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.")
|
||||
|
||||
@@ -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())
|
||||
|
||||
@@ -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.")
|
||||
|
||||
@@ -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
|
||||
}
|
||||
|
||||
|
||||
@@ -62,6 +62,7 @@ func NewDeleteCommand(f client.Factory, use string) *cobra.Command {
|
||||
},
|
||||
}
|
||||
|
||||
c.ValidArgsFunction = cli.CompleteScheduleNames(f)
|
||||
o.BindFlags(c.Flags())
|
||||
return c
|
||||
}
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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())
|
||||
|
||||
@@ -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())
|
||||
|
||||
|
||||
@@ -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())
|
||||
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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`.
|
||||
|
||||
|
||||
Reference in New Issue
Block a user