...

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

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

     1  package cmd
     2  
     3  import (
     4  	"encoding/json"
     5  	"errors"
     6  	"fmt"
     7  	"os"
     8  	"strconv"
     9  	"strings"
    10  
    11  	"sigs.k8s.io/yaml"
    12  
    13  	"github.com/linkerd/linkerd2-proxy-api/go/inbound"
    14  	"github.com/linkerd/linkerd2-proxy-api/go/outbound"
    15  	pkgcmd "github.com/linkerd/linkerd2/pkg/cmd"
    16  	"github.com/linkerd/linkerd2/pkg/k8s"
    17  	"github.com/spf13/cobra"
    18  	"go.opencensus.io/plugin/ocgrpc"
    19  	"google.golang.org/grpc"
    20  	"google.golang.org/grpc/credentials/insecure"
    21  )
    22  
    23  const (
    24  	policyPort       = 8090
    25  	policyDeployment = "linkerd-destination"
    26  )
    27  
    28  func newCmdPolicy() *cobra.Command {
    29  	options := newEndpointsOptions()
    30  	var (
    31  		namespace = "default"
    32  		output    = "yaml"
    33  	)
    34  
    35  	example := `  # get the inbound policy for pod emoji-6d66d87995-bvrnn on port 8080
    36    linkerd diagnostics policy -n emojivoto po/emoji-6d66d87995-bvrnn 8080
    37  
    38    # get the outbound policy for Service emoji-svc on port 8080
    39    linkerd diagnostics policy -n emojivoto svc/emoji-svc 8080`
    40  
    41  	cmd := &cobra.Command{
    42  		Use:   "policy [flags] resource port",
    43  		Short: "Introspect Linkerd's policy state",
    44  		Long: `Introspect Linkerd's policy state.
    45  
    46  This command provides debug information about the internal state of the
    47  control-plane's policy controller. It queries the same control-plane
    48  endpoint as the linkerd-proxy's, and returns the policies associated with the
    49  given resource. If the resource is a Pod, inbound policy for that Pod is
    50  displayed. If the resource is a Service, outbound policy for that Service is
    51  displayed.`,
    52  		Example: example,
    53  		Args:    cobra.ExactArgs(2),
    54  		RunE: func(cmd *cobra.Command, args []string) error {
    55  			err := options.validate()
    56  			if err != nil {
    57  				return err
    58  			}
    59  
    60  			k8sAPI, err := k8s.NewAPI(kubeconfigPath, kubeContext, impersonate, impersonateGroup, 0)
    61  			if err != nil {
    62  				return err
    63  			}
    64  
    65  			if apiAddr == "" {
    66  				var portForward *k8s.PortForward
    67  				var err error
    68  				if options.destinationPod == "" {
    69  					portForward, err = k8s.NewPortForward(
    70  						cmd.Context(),
    71  						k8sAPI,
    72  						controlPlaneNamespace,
    73  						policyDeployment,
    74  						"localhost",
    75  						0,
    76  						policyPort,
    77  						false,
    78  					)
    79  				} else {
    80  					portForward, err = k8s.NewPodPortForward(k8sAPI, controlPlaneNamespace, options.destinationPod, "localhost", 0, policyPort, false)
    81  				}
    82  				if err != nil {
    83  					return err
    84  				}
    85  
    86  				apiAddr = portForward.AddressAndPort()
    87  				if err = portForward.Init(); err != nil {
    88  					return err
    89  				}
    90  			}
    91  
    92  			conn, err := grpc.NewClient(apiAddr, grpc.WithTransportCredentials(insecure.NewCredentials()), grpc.WithStatsHandler(&ocgrpc.ClientHandler{}))
    93  			if err != nil {
    94  				return err
    95  			}
    96  			defer conn.Close()
    97  
    98  			elems := strings.Split(args[0], "/")
    99  
   100  			if len(elems) == 1 {
   101  				return errors.New("resource type and name are required")
   102  			}
   103  
   104  			if len(elems) != 2 {
   105  				return fmt.Errorf("invalid resource string: %s", args[0])
   106  			}
   107  			typ, err := k8s.CanonicalResourceNameFromFriendlyName(elems[0])
   108  			if err != nil {
   109  				return err
   110  			}
   111  			name := elems[1]
   112  
   113  			port, err := strconv.ParseUint(args[1], 10, 32)
   114  			if err != nil {
   115  				return err
   116  			}
   117  
   118  			var result interface{}
   119  
   120  			if typ == k8s.Pod {
   121  				client := inbound.NewInboundServerPoliciesClient(conn)
   122  
   123  				result, err = client.GetPort(cmd.Context(), &inbound.PortSpec{
   124  					Workload: fmt.Sprintf("%s:%s", namespace, name),
   125  					Port:     uint32(port),
   126  				})
   127  				if err != nil {
   128  					return err
   129  				}
   130  
   131  			} else if typ == k8s.Service {
   132  				client := outbound.NewOutboundPoliciesClient(conn)
   133  
   134  				result, err = client.Get(cmd.Context(), &outbound.TrafficSpec{
   135  					SourceWorkload: options.contextToken,
   136  					Target:         &outbound.TrafficSpec_Authority{Authority: fmt.Sprintf("%s.%s.svc:%d", name, namespace, port)},
   137  				})
   138  				if err != nil {
   139  					return err
   140  				}
   141  			} else {
   142  				return fmt.Errorf("invalid resource type %s; must be one of Pod or Service", args[0])
   143  			}
   144  
   145  			var out []byte
   146  			switch output {
   147  			case "json":
   148  				out, err = json.MarshalIndent(result, "", "  ")
   149  				if err != nil {
   150  					fmt.Fprint(os.Stderr, err)
   151  					os.Exit(1)
   152  				}
   153  			case "yaml":
   154  				out, err = yaml.Marshal(result)
   155  				if err != nil {
   156  					fmt.Fprint(os.Stderr, err)
   157  					os.Exit(1)
   158  				}
   159  			default:
   160  				return errors.New("output must be one of: yaml, json")
   161  			}
   162  
   163  			_, err = fmt.Print(string(out))
   164  			return err
   165  		},
   166  	}
   167  
   168  	cmd.PersistentFlags().StringVar(&options.destinationPod, "destination-pod", "", "Target a specific destination Pod when there are multiple running")
   169  	cmd.PersistentFlags().StringVar(&options.contextToken, "token", "default:diagnostics", "Token to use when querying the policy service")
   170  	cmd.PersistentFlags().StringVarP(&namespace, "namespace", "n", namespace, "Namespace of resource")
   171  	cmd.PersistentFlags().StringVarP(&output, "output", "o", output, "Output format. One of: yaml, json")
   172  
   173  	pkgcmd.ConfigureOutputFlagCompletion(cmd)
   174  
   175  	return cmd
   176  }
   177  

View as plain text