github.com/argoproj/argo-cd/v3@v3.2.1/cmd/argocd/commands/admin/generatespec_utils.go (about)

     1  package admin
     2  
     3  import (
     4  	"encoding/json"
     5  	"errors"
     6  	"fmt"
     7  	"io"
     8  	"os"
     9  
    10  	"github.com/argoproj/gitops-engine/pkg/utils/kube"
    11  	corev1 "k8s.io/api/core/v1"
    12  	"sigs.k8s.io/yaml"
    13  
    14  	utilio "github.com/argoproj/argo-cd/v3/util/io"
    15  )
    16  
    17  func getOutWriter(inline bool, filePath string) (io.Writer, io.Closer, error) {
    18  	if !inline {
    19  		return os.Stdout, utilio.NopCloser, nil
    20  	}
    21  
    22  	if filePath == "" {
    23  		return nil, nil, errors.New("the file path must be specified using flag '--file'")
    24  	}
    25  
    26  	err := os.Rename(filePath, filePath+".back")
    27  	if err != nil {
    28  		return nil, nil, err
    29  	}
    30  
    31  	fileOut, err := os.Create(filePath)
    32  	if err != nil {
    33  		return nil, nil, err
    34  	}
    35  	return fileOut, fileOut, nil
    36  }
    37  
    38  // PrintResources prints a single resource in YAML or JSON format to stdout according to the output format
    39  func PrintResources(output string, out io.Writer, resources ...any) error {
    40  	for i, resource := range resources {
    41  		if secret, ok := resource.(*corev1.Secret); ok {
    42  			convertSecretData(secret)
    43  		}
    44  		filteredResource, err := omitFields(resource)
    45  		if err != nil {
    46  			return fmt.Errorf("error omitting filtered fields from the resource: %w", err)
    47  		}
    48  		resources[i] = filteredResource
    49  	}
    50  	var obj any = resources
    51  	if len(resources) == 1 {
    52  		obj = resources[0]
    53  	}
    54  
    55  	switch output {
    56  	case "json":
    57  		jsonBytes, err := json.MarshalIndent(obj, "", "  ")
    58  		if err != nil {
    59  			return fmt.Errorf("error marshaling json: %w", err)
    60  		}
    61  
    62  		_, _ = fmt.Fprintln(out, string(jsonBytes))
    63  	case "yaml":
    64  		yamlBytes, err := yaml.Marshal(obj)
    65  		if err != nil {
    66  			return fmt.Errorf("error marshaling yaml: %w", err)
    67  		}
    68  		// marshaled YAML already ends with the new line character
    69  		_, _ = fmt.Fprint(out, string(yamlBytes))
    70  	default:
    71  		return fmt.Errorf("unknown output format: %s", output)
    72  	}
    73  	return nil
    74  }
    75  
    76  // omit fields such as status, creationTimestamp and metadata.namespace in k8s objects
    77  func omitFields(resource any) (any, error) {
    78  	jsonBytes, err := json.Marshal(resource)
    79  	if err != nil {
    80  		return nil, err
    81  	}
    82  
    83  	toMap := make(map[string]any)
    84  	err = json.Unmarshal(jsonBytes, &toMap)
    85  	if err != nil {
    86  		return nil, err
    87  	}
    88  
    89  	delete(toMap, "status")
    90  	if v, ok := toMap["metadata"]; ok {
    91  		if metadata, ok := v.(map[string]any); ok {
    92  			delete(metadata, "creationTimestamp")
    93  			delete(metadata, "namespace")
    94  		}
    95  	}
    96  	return toMap, nil
    97  }
    98  
    99  // convertSecretData converts kubernetes secret's data to stringData
   100  func convertSecretData(secret *corev1.Secret) {
   101  	secret.Kind = kube.SecretKind
   102  	secret.APIVersion = "v1"
   103  	secret.StringData = map[string]string{}
   104  	for k, v := range secret.Data {
   105  		secret.StringData[k] = string(v)
   106  	}
   107  	secret.Data = map[string][]byte{}
   108  }