Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -48,3 +48,5 @@ go.work
.Trashes
ehthumbs.db
Thumbs.db

vendor/
34 changes: 18 additions & 16 deletions cmd/non-admin/backup/describe.go
Original file line number Diff line number Diff line change
Expand Up @@ -72,7 +72,7 @@ func NewDescribeCommand(f client.Factory, use string) *cobra.Command {
}

// Print in Velero-style format
printNonAdminBackupDetails(cmd, &nab, kbClient, backupName, userNamespace, effectiveTimeout)
printNonAdminBackupDetails(cmd, &nab, kbClient, backupName, userNamespace, effectiveTimeout, details)

// Add detailed output if --details flag is set
if details {
Expand All @@ -98,7 +98,7 @@ func NewDescribeCommand(f client.Factory, use string) *cobra.Command {
}

// printNonAdminBackupDetails prints backup details in Velero admin describe format
func printNonAdminBackupDetails(cmd *cobra.Command, nab *nacv1alpha1.NonAdminBackup, kbClient kbclient.Client, backupName string, userNamespace string, timeout time.Duration) {
func printNonAdminBackupDetails(cmd *cobra.Command, nab *nacv1alpha1.NonAdminBackup, kbClient kbclient.Client, backupName string, userNamespace string, timeout time.Duration, showDetails bool) {
out := cmd.OutOrStdout()

// Get Velero backup reference if available
Expand Down Expand Up @@ -322,22 +322,24 @@ func printNonAdminBackupDetails(cmd *cobra.Command, nab *nacv1alpha1.NonAdminBac

fmt.Fprintf(out, "\n")

// Fetch and display Resource List
ctx, cancel := context.WithTimeout(context.Background(), timeout)
defer cancel()
// Fetch and display Resource List (only if showDetails is true)
if showDetails {
ctx, cancel := context.WithTimeout(context.Background(), timeout)
defer cancel()

resourceList, err := shared.ProcessDownloadRequest(ctx, kbClient, shared.DownloadRequestOptions{
BackupName: backupName,
DataType: "BackupResourceList",
Namespace: userNamespace,
HTTPTimeout: timeout,
})
resourceList, err := shared.ProcessDownloadRequest(ctx, kbClient, shared.DownloadRequestOptions{
BackupName: backupName,
DataType: "BackupResourceList",
Namespace: userNamespace,
HTTPTimeout: timeout,
})

if err == nil && resourceList != "" {
if formattedList := formatResourceList(resourceList); formattedList != "" {
fmt.Fprintf(out, "Resource List:\n")
fmt.Fprintf(out, "%s\n", formattedList)
fmt.Fprintf(out, "\n")
if err == nil && resourceList != "" {
if formattedList := formatResourceList(resourceList); formattedList != "" {
fmt.Fprintf(out, "Resource List:\n")
fmt.Fprintf(out, "%s\n", formattedList)
fmt.Fprintf(out, "\n")
}
}
}

Expand Down
2 changes: 1 addition & 1 deletion cmd/non-admin/backup/get.go
Original file line number Diff line number Diff line change
Expand Up @@ -20,11 +20,11 @@ import (
"fmt"
"time"

"github.com/migtools/oadp-cli/cmd/non-admin/output"
"github.com/migtools/oadp-cli/cmd/shared"
nacv1alpha1 "github.com/migtools/oadp-non-admin/api/v1alpha1"
"github.com/spf13/cobra"
"github.com/vmware-tanzu/velero/pkg/client"
"github.com/vmware-tanzu/velero/pkg/cmd/util/output"
kbclient "sigs.k8s.io/controller-runtime/pkg/client"
)

Expand Down
2 changes: 1 addition & 1 deletion cmd/non-admin/bsl/bsl.go
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@ func NewBSLCommand(f client.Factory) *cobra.Command {
}

c.AddCommand(
NewCreateCommand(f),
NewCreateCommand(f, "create"),
NewGetCommand(f, "get"),
)

Expand Down
4 changes: 2 additions & 2 deletions cmd/non-admin/bsl/create.go
Original file line number Diff line number Diff line change
Expand Up @@ -36,11 +36,11 @@ import (
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
)

func NewCreateCommand(f client.Factory) *cobra.Command {
func NewCreateCommand(f client.Factory, use string) *cobra.Command {
o := NewCreateOptions()

c := &cobra.Command{
Use: "create NAME",
Use: use + " NAME",
Short: "Create a non-admin backup storage location",
Args: cobra.ExactArgs(1),
Run: func(c *cobra.Command, args []string) {
Expand Down
2 changes: 1 addition & 1 deletion cmd/non-admin/bsl/get.go
Original file line number Diff line number Diff line change
Expand Up @@ -21,11 +21,11 @@ import (
"fmt"
"time"

"github.com/migtools/oadp-cli/cmd/non-admin/output"
"github.com/migtools/oadp-cli/cmd/shared"
nacv1alpha1 "github.com/migtools/oadp-non-admin/api/v1alpha1"
"github.com/spf13/cobra"
"github.com/vmware-tanzu/velero/pkg/client"
"github.com/vmware-tanzu/velero/pkg/cmd/util/output"
kbclient "sigs.k8s.io/controller-runtime/pkg/client"
)

Expand Down
148 changes: 148 additions & 0 deletions cmd/non-admin/output/output.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,148 @@
/*
Copyright 2025 The OADP CLI 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 output

import (
"bytes"
"fmt"
"io"

nacv1alpha1 "github.com/migtools/oadp-non-admin/api/v1alpha1"
"github.com/pkg/errors"
"github.com/spf13/cobra"
"github.com/spf13/pflag"
velerov1api "github.com/vmware-tanzu/velero/pkg/apis/velero/v1"
velerooutput "github.com/vmware-tanzu/velero/pkg/cmd/util/output"
"k8s.io/apimachinery/pkg/api/meta"
"k8s.io/apimachinery/pkg/runtime"
"k8s.io/apimachinery/pkg/runtime/serializer"
)

// NonAdminScheme returns a runtime.Scheme with NonAdmin types registered
func NonAdminScheme() *runtime.Scheme {
scheme := runtime.NewScheme()

// Add NonAdmin types
if err := nacv1alpha1.AddToScheme(scheme); err != nil {
panic(fmt.Sprintf("failed to add NonAdmin types to scheme: %v", err))
}

// Add Velero types for compatibility
if err := velerov1api.AddToScheme(scheme); err != nil {
panic(fmt.Sprintf("failed to add Velero types to scheme: %v", err))
}

return scheme
}

// BindFlags wraps Velero's BindFlags to add output flags
func BindFlags(flags *pflag.FlagSet) {
velerooutput.BindFlags(flags)
}

// ClearOutputFlagDefault wraps Velero's ClearOutputFlagDefault
func ClearOutputFlagDefault(cmd *cobra.Command) {
velerooutput.ClearOutputFlagDefault(cmd)
}

// PrintWithFormat prints the provided object in the format specified by
// the command's flags. This is a custom implementation for nonadmin commands
// that supports NonAdmin CRD types (NonAdminBackup, NonAdminRestore, etc.)
func PrintWithFormat(c *cobra.Command, obj runtime.Object) (bool, error) {
format := velerooutput.GetOutputFlagValue(c)
if format == "" {
return false, nil
}

switch format {
case "json", "yaml":
return printEncoded(obj, format)
case "table":
// Table format is not supported by this function
// The caller should handle table printing
return false, nil
}

return false, errors.Errorf("unsupported output format %q; valid values are 'table', 'json', and 'yaml'", format)
}

func printEncoded(obj runtime.Object, format string) (bool, error) {
// assume we're printing obj
toPrint := obj

if meta.IsListType(obj) {
list, _ := meta.ExtractList(obj)
if len(list) == 1 {
// if obj was a list and there was only 1 item, just print that 1 instead of a list
toPrint = list[0]
}
}

encoded, err := encode(toPrint, format)
if err != nil {
return false, err
}

fmt.Println(string(encoded))

return true, nil
}

func encode(obj runtime.Object, format string) ([]byte, error) {
buf := new(bytes.Buffer)

if err := encodeTo(obj, format, buf); err != nil {
return nil, err
}
return buf.Bytes(), nil
}

func encodeTo(obj runtime.Object, format string, w io.Writer) error {
encoder, err := encoderFor(format, obj)
if err != nil {
return err
}

return errors.WithStack(encoder.Encode(obj, w))
}

func encoderFor(format string, obj runtime.Object) (runtime.Encoder, error) {
var encoder runtime.Encoder

// Use NonAdminScheme instead of Velero's scheme
codecFactory := serializer.NewCodecFactory(NonAdminScheme())

desiredMediaType := fmt.Sprintf("application/%s", format)
serializerInfo, found := runtime.SerializerInfoForMediaType(codecFactory.SupportedMediaTypes(), desiredMediaType)
if !found {
return nil, errors.Errorf("unable to locate an encoder for %q", desiredMediaType)
}
if serializerInfo.PrettySerializer != nil {
encoder = serializerInfo.PrettySerializer
} else {
encoder = serializerInfo.Serializer
}

if !obj.GetObjectKind().GroupVersionKind().Empty() {
return encoder, nil
}

// Use the appropriate GroupVersion for encoding
// For NonAdmin types, use nacv1alpha1.GroupVersion
encoder = codecFactory.EncoderForVersion(encoder, nacv1alpha1.GroupVersion)
return encoder, nil
}
Loading
Loading