...

Source file src/github.com/linkerd/linkerd2/cli/cmd/diagnostics_profile.go

Documentation: github.com/linkerd/linkerd2/cli/cmd

     1  package cmd
     2  
     3  import (
     4  	"context"
     5  	"encoding/json"
     6  	"fmt"
     7  	"io"
     8  	"os"
     9  
    10  	destinationPb "github.com/linkerd/linkerd2-proxy-api/go/destination"
    11  	"github.com/linkerd/linkerd2/controller/api/destination"
    12  	pkgcmd "github.com/linkerd/linkerd2/pkg/cmd"
    13  	"github.com/linkerd/linkerd2/pkg/k8s"
    14  	"github.com/spf13/cobra"
    15  	"google.golang.org/grpc"
    16  )
    17  
    18  type diagProfileOptions struct {
    19  	destinationPod string
    20  	contextToken   string
    21  }
    22  
    23  // validate performs all validation on the command-line options.
    24  // It returns the first error encountered, or `nil` if the options are valid.
    25  func (o *diagProfileOptions) validate() error {
    26  	return nil
    27  }
    28  
    29  func newDiagProfileOptions() *diagProfileOptions {
    30  	return &diagProfileOptions{}
    31  }
    32  
    33  func newCmdDiagnosticsProfile() *cobra.Command {
    34  	options := newDiagProfileOptions()
    35  
    36  	example := `  # Get the service profile for the service or endopint at 10.20.2.4:8080
    37    linkerd diagnostics profile 10.20.2.4:8080`
    38  
    39  	cmd := &cobra.Command{
    40  		Use:     "profile [flags] address",
    41  		Aliases: []string{"ep"},
    42  		Short:   "Introspect Linkerd's service discovery state",
    43  		Long: `Introspect Linkerd's service discovery state.
    44  
    45  This command provides debug information about the internal state of the
    46  control-plane's destination controller. It queries the same Destination service
    47  endpoint as the linkerd-proxy's, and returns the profile associated with that
    48  destination.`,
    49  		Example: example,
    50  		Args:    cobra.ExactArgs(1),
    51  		RunE: func(cmd *cobra.Command, args []string) error {
    52  			err := options.validate()
    53  			if err != nil {
    54  				return err
    55  			}
    56  
    57  			var client destinationPb.DestinationClient
    58  			var conn *grpc.ClientConn
    59  			if apiAddr != "" {
    60  				client, conn, err = destination.NewClient(apiAddr)
    61  				if err != nil {
    62  					fmt.Fprintf(os.Stderr, "Error creating destination client: %s\n", err)
    63  					os.Exit(1)
    64  				}
    65  			} else {
    66  				k8sAPI, err := k8s.NewAPI(kubeconfigPath, kubeContext, impersonate, impersonateGroup, 0)
    67  				if err != nil {
    68  					return err
    69  				}
    70  
    71  				client, conn, err = destination.NewExternalClient(cmd.Context(), controlPlaneNamespace, k8sAPI, options.destinationPod)
    72  				if err != nil {
    73  					fmt.Fprintf(os.Stderr, "Error creating destination client: %s\n", err)
    74  					os.Exit(1)
    75  				}
    76  			}
    77  
    78  			defer conn.Close()
    79  
    80  			profile, err := requestProfileFromAPI(client, options.contextToken, args[0])
    81  			if err != nil {
    82  				fmt.Fprintf(os.Stderr, "Destination API error: %s\n", err)
    83  				os.Exit(1)
    84  			}
    85  
    86  			return writeProfileJSON(os.Stdout, profile)
    87  		},
    88  	}
    89  
    90  	cmd.PersistentFlags().StringVar(&options.destinationPod, "destination-pod", "", "Target a specific destination Pod when there are multiple running")
    91  	cmd.PersistentFlags().StringVar(&options.contextToken, "token", "", "The context token to use when making the request to the destination API")
    92  
    93  	pkgcmd.ConfigureOutputFlagCompletion(cmd)
    94  
    95  	return cmd
    96  }
    97  
    98  func requestProfileFromAPI(client destinationPb.DestinationClient, token string, addr string) (*destinationPb.DestinationProfile, error) {
    99  	dest := &destinationPb.GetDestination{
   100  		Path:         addr,
   101  		ContextToken: token,
   102  	}
   103  
   104  	rsp, err := client.GetProfile(context.Background(), dest)
   105  	if err != nil {
   106  		return nil, err
   107  	}
   108  
   109  	return rsp.Recv()
   110  }
   111  
   112  func writeProfileJSON(w io.Writer, profile *destinationPb.DestinationProfile) error {
   113  	b, err := json.MarshalIndent(profile, "", "  ")
   114  	if err != nil {
   115  		return err
   116  	}
   117  
   118  	_, err = fmt.Fprintln(w, string(b))
   119  	return err
   120  }
   121  

View as plain text