diff --git a/cmd/non-admin/bsl/get.go b/cmd/non-admin/bsl/get.go index 5e1a503..c4bfa77 100644 --- a/cmd/non-admin/bsl/get.go +++ b/cmd/non-admin/bsl/get.go @@ -113,16 +113,17 @@ func printNonAdminBSLTable(nabslList *nacv1alpha1.NonAdminBackupStorageLocationL } // Print header - fmt.Printf("%-30s %-15s %-15s %-20s %-10s\n", "NAME", "REQUEST PHASE", "PROVIDER", "BUCKET/PREFIX", "AGE") + fmt.Printf("%-30s %-15s %-15s %-15s %-20s %-10s\n", "NAME", "REQUEST PHASE", "VELERO PHASE", "PROVIDER", "BUCKET/PREFIX", "AGE") // Print each BSL for _, nabsl := range nabslList.Items { status := getBSLStatus(&nabsl) + veleroPhase := getBSLVeleroPhase(&nabsl) provider := getProvider(&nabsl) bucketPrefix := getBucketPrefix(&nabsl) age := formatAge(nabsl.CreationTimestamp.Time) - fmt.Printf("%-30s %-15s %-15s %-20s %-10s\n", nabsl.Name, status, provider, bucketPrefix, age) + fmt.Printf("%-30s %-15s %-15s %-15s %-20s %-10s\n", nabsl.Name, status, veleroPhase, provider, bucketPrefix, age) } return nil @@ -135,6 +136,15 @@ func getBSLStatus(nabsl *nacv1alpha1.NonAdminBackupStorageLocation) string { return "Unknown" } +func getBSLVeleroPhase(nabsl *nacv1alpha1.NonAdminBackupStorageLocation) string { + if nabsl.Status.VeleroBackupStorageLocation != nil && nabsl.Status.VeleroBackupStorageLocation.Status != nil { + if nabsl.Status.VeleroBackupStorageLocation.Status.Phase != "" { + return string(nabsl.Status.VeleroBackupStorageLocation.Status.Phase) + } + } + return "N/A" +} + func getProvider(nabsl *nacv1alpha1.NonAdminBackupStorageLocation) string { if nabsl.Spec.BackupStorageLocationSpec != nil && nabsl.Spec.BackupStorageLocationSpec.Provider != "" { return nabsl.Spec.BackupStorageLocationSpec.Provider diff --git a/cmd/root.go b/cmd/root.go index 40e8263..6105b73 100644 --- a/cmd/root.go +++ b/cmd/root.go @@ -49,7 +49,7 @@ import ( "github.com/vmware-tanzu/velero/pkg/cmd/cli/create" "github.com/vmware-tanzu/velero/pkg/cmd/cli/datamover" "github.com/vmware-tanzu/velero/pkg/cmd/cli/debug" - "github.com/vmware-tanzu/velero/pkg/cmd/cli/delete" + veldelete "github.com/vmware-tanzu/velero/pkg/cmd/cli/delete" "github.com/vmware-tanzu/velero/pkg/cmd/cli/describe" "github.com/vmware-tanzu/velero/pkg/cmd/cli/get" "github.com/vmware-tanzu/velero/pkg/cmd/cli/repo" @@ -349,6 +349,24 @@ func wrapPreRunE(existing func(*cobra.Command, []string) error, additional func( } } +// isNonadminEnabled checks if nonadmin mode is enabled in the VeleroConfig. +// Handles both boolean and string representations since +// `oc oadp client config set nonadmin=true` stores the value as a string. +func isNonadminEnabled(config clientcmd.VeleroConfig) bool { + val, ok := config["nonadmin"] + if !ok { + return false + } + switch v := val.(type) { + case bool: + return v + case string: + return strings.EqualFold(v, "true") + default: + return false + } +} + // NewVeleroRootCommand returns a root command with all Velero CLI subcommands attached. func NewVeleroRootCommand(baseName string) *cobra.Command { @@ -357,6 +375,13 @@ func NewVeleroRootCommand(baseName string) *cobra.Command { fmt.Fprintf(os.Stderr, "WARNING: Error reading config file: %v\n", err) } + // When nonadmin mode is enabled, remove the namespace override so the + // factory uses the current kubeconfig context namespace instead of an + // admin namespace like openshift-adp. + if isNonadminEnabled(config) { + delete(config, clientcmd.ConfigKeyNamespace) + } + // Declare cmdFeatures and cmdColorzied here so we can access them in the PreRun hooks // without doing a chain of calls into the command's FlagSet var cmdFeatures veleroflag.StringArray @@ -401,7 +426,7 @@ func NewVeleroRootCommand(baseName string) *cobra.Command { get.NewCommand(f), describe.NewCommand(f), create.NewCommand(f), - delete.NewCommand(f), + veldelete.NewCommand(f), cliclient.NewCommand(), completion.NewCommand(), repo.NewCommand(f), @@ -437,6 +462,21 @@ func NewVeleroRootCommand(baseName string) *cobra.Command { renameTimeoutFlag(cmd) } + // When nonadmin mode is enabled, remove all admin commands so only + // nonadmin, client (for toggling the config), and help are available. + if isNonadminEnabled(config) { + allowedCmds := map[string]bool{ + "nonadmin": true, + "client": true, + "completion": true, + } + for _, cmd := range c.Commands() { + if !allowedCmds[cmd.Use] { + c.RemoveCommand(cmd) + } + } + } + // Set custom usage template to show "oc oadp" instead of just "oadp" usageTemplate := c.UsageTemplate() usageTemplate = strings.ReplaceAll(usageTemplate, "{{.CommandPath}}", "oc {{.CommandPath}}") diff --git a/cmd/shared/factories.go b/cmd/shared/factories.go index 99f1bae..08af248 100644 --- a/cmd/shared/factories.go +++ b/cmd/shared/factories.go @@ -21,13 +21,32 @@ import ( "fmt" "os" "path/filepath" + "strings" "github.com/vmware-tanzu/velero/pkg/client" ) // ClientConfig represents the structure of the Velero client configuration file type ClientConfig struct { - Namespace string `json:"namespace"` + Namespace string `json:"namespace"` + NonAdmin interface{} `json:"nonadmin,omitempty"` +} + +// IsNonAdmin returns true if the nonadmin configuration is enabled. +// Handles both boolean and string representations since +// `oc oadp client config set nonadmin=true` stores the value as a string. +func (c *ClientConfig) IsNonAdmin() bool { + if c == nil { + return false + } + switch v := c.NonAdmin.(type) { + case bool: + return v + case string: + return strings.EqualFold(v, "true") + default: + return false + } } // CreateVeleroFactory creates a client factory for Velero operations (admin-scoped)