github.com/argoproj/argo-cd/v2@v2.10.9/pkg/apiclient/application/forwarder_overwrite.go (about)

     1  package application
     2  
     3  import (
     4  	"context"
     5  	"errors"
     6  	"fmt"
     7  	gohttp "net/http"
     8  	"strings"
     9  
    10  	"github.com/argoproj/argo-cd/v2/util/kube"
    11  
    12  	"github.com/argoproj/pkg/grpc/http"
    13  	"github.com/grpc-ecosystem/grpc-gateway/runtime"
    14  
    15  	// nolint:staticcheck
    16  	"github.com/golang/protobuf/proto"
    17  
    18  	"github.com/argoproj/argo-cd/v2/pkg/apis/application/v1alpha1"
    19  )
    20  
    21  // appFields is a map of fields that can be selected from an application.
    22  // The manually maintained list is required because application list response might include thousands of applications
    23  // and JSON based field handling is too slow.
    24  var appFields = map[string]func(app *v1alpha1.Application) interface{}{
    25  	"metadata.name":              func(app *v1alpha1.Application) interface{} { return app.Name },
    26  	"metadata.namespace":         func(app *v1alpha1.Application) interface{} { return app.Namespace },
    27  	"metadata.annotations":       func(app *v1alpha1.Application) interface{} { return app.Annotations },
    28  	"metadata.labels":            func(app *v1alpha1.Application) interface{} { return app.Labels },
    29  	"metadata.creationTimestamp": func(app *v1alpha1.Application) interface{} { return app.CreationTimestamp },
    30  	"metadata.deletionTimestamp": func(app *v1alpha1.Application) interface{} { return app.DeletionTimestamp },
    31  	"spec":                       func(app *v1alpha1.Application) interface{} { return app.Spec },
    32  	"status.sync.status":         func(app *v1alpha1.Application) interface{} { return app.Status.Sync.Status },
    33  	"status.health":              func(app *v1alpha1.Application) interface{} { return app.Status.Health },
    34  	"status.summary":             func(app *v1alpha1.Application) interface{} { return app.Status.Summary },
    35  	"status.operationState.startedAt": func(app *v1alpha1.Application) interface{} {
    36  		if app.Status.OperationState != nil {
    37  			return app.Status.OperationState.StartedAt
    38  		}
    39  		return nil
    40  	},
    41  	"status.operationState.finishedAt": func(app *v1alpha1.Application) interface{} {
    42  		if app.Status.OperationState != nil {
    43  			return app.Status.OperationState.FinishedAt
    44  		}
    45  		return nil
    46  	},
    47  	"status.resources": func(app *v1alpha1.Application) interface{} {
    48  		if len(app.Status.Resources) > 0 {
    49  			return app.Status.Resources
    50  		}
    51  		return nil
    52  	},
    53  	"operation.sync": func(app *v1alpha1.Application) interface{} {
    54  		if app.Operation != nil {
    55  			return app.Operation.Sync
    56  		}
    57  		return nil
    58  	},
    59  	"status.operationState.phase": func(app *v1alpha1.Application) interface{} {
    60  		if app.Status.OperationState != nil {
    61  			return app.Status.OperationState.Phase
    62  		}
    63  		return nil
    64  	},
    65  	"status.operationState.operation.sync": func(app *v1alpha1.Application) interface{} {
    66  		if app.Status.OperationState != nil {
    67  			return app.Status.OperationState.SyncResult
    68  		}
    69  		return nil
    70  	},
    71  }
    72  
    73  func processApplicationListField(v interface{}, fields map[string]interface{}, exclude bool) (interface{}, error) {
    74  	if appList, ok := v.(*v1alpha1.ApplicationList); ok {
    75  		var items []map[string]interface{}
    76  		for _, app := range appList.Items {
    77  			converted := make(map[string]interface{})
    78  			items = append(items, converted)
    79  			for field, fn := range appFields {
    80  				if _, ok := fields["items."+field]; ok == exclude {
    81  					continue
    82  				}
    83  				value := fn(&app)
    84  				if value == nil {
    85  					continue
    86  				}
    87  				parts := strings.Split(field, ".")
    88  				item := converted
    89  				for i := 0; i < len(parts); i++ {
    90  					subField := parts[i]
    91  					if i == len(parts)-1 {
    92  						item[subField] = value
    93  					} else {
    94  						if _, ok := item[subField]; !ok {
    95  							item[subField] = make(map[string]interface{})
    96  						}
    97  						nestedMap, ok := item[subField].(map[string]interface{})
    98  						if !ok {
    99  							return nil, fmt.Errorf("field %s is not a map", field)
   100  						}
   101  						item = nestedMap
   102  					}
   103  				}
   104  			}
   105  		}
   106  		return map[string]interface{}{
   107  			"items":    items,
   108  			"metadata": appList.ListMeta,
   109  		}, nil
   110  	}
   111  	return nil, errors.New("not an application list")
   112  }
   113  
   114  func init() {
   115  	logsForwarder := func(ctx context.Context, mux *runtime.ServeMux, marshaler runtime.Marshaler, w gohttp.ResponseWriter, req *gohttp.Request, recv func() (proto.Message, error), opts ...func(context.Context, gohttp.ResponseWriter, proto.Message) error) {
   116  		if req.URL.Query().Get("download") == "true" {
   117  			w.Header().Set("Content-Type", "application/octet-stream")
   118  			fileName := "log"
   119  			if container := req.URL.Query().Get("container"); len(container) > 0 && kube.IsValidResourceName(container) {
   120  				fileName = container
   121  			}
   122  			w.Header().Set("Content-Disposition", fmt.Sprintf(`attachment;filename="%s.txt"`, fileName))
   123  			for {
   124  				msg, err := recv()
   125  				if err != nil {
   126  					_, _ = w.Write([]byte(err.Error()))
   127  					return
   128  				}
   129  				if logEntry, ok := msg.(*LogEntry); ok {
   130  					if logEntry.GetLast() {
   131  						return
   132  					}
   133  					if _, err = w.Write([]byte(logEntry.GetContent() + "\n")); err != nil {
   134  						return
   135  					}
   136  				}
   137  			}
   138  		} else {
   139  			http.StreamForwarder(ctx, mux, marshaler, w, req, recv, opts...)
   140  		}
   141  	}
   142  	forward_ApplicationService_PodLogs_0 = logsForwarder
   143  	forward_ApplicationService_PodLogs_1 = logsForwarder
   144  	forward_ApplicationService_WatchResourceTree_0 = http.StreamForwarder
   145  	forward_ApplicationService_Watch_0 = http.NewStreamForwarder(func(message proto.Message) (string, error) {
   146  		event, ok := message.(*v1alpha1.ApplicationWatchEvent)
   147  		if !ok {
   148  			return "", errors.New("unexpected message type")
   149  		}
   150  		return event.Application.Name, nil
   151  	})
   152  	forward_ApplicationService_List_0 = http.UnaryForwarderWithFieldProcessor(processApplicationListField)
   153  	forward_ApplicationService_ManagedResources_0 = http.UnaryForwarder
   154  }