1 package cmd
2
3 import (
4 "fmt"
5 "os"
6 "regexp"
7 "strings"
8
9 "github.com/fatih/color"
10 "github.com/linkerd/linkerd2/cli/flag"
11 jaeger "github.com/linkerd/linkerd2/jaeger/cmd"
12 multicluster "github.com/linkerd/linkerd2/multicluster/cmd"
13 pkgcmd "github.com/linkerd/linkerd2/pkg/cmd"
14 "github.com/linkerd/linkerd2/pkg/flags"
15 "github.com/linkerd/linkerd2/pkg/healthcheck"
16 viz "github.com/linkerd/linkerd2/viz/cmd"
17 log "github.com/sirupsen/logrus"
18 "github.com/spf13/cobra"
19 )
20
21 const (
22 defaultLinkerdNamespace = "linkerd"
23 defaultCNINamespace = "linkerd-cni"
24 defaultClusterDomain = "cluster.local"
25
26 jsonOutput = healthcheck.JSONOutput
27 tableOutput = healthcheck.TableOutput
28 shortOutput = healthcheck.ShortOutput
29 )
30
31 var (
32
33
34 stdout = color.Output
35 stderr = color.Error
36
37 okStatus = color.New(color.FgGreen, color.Bold).SprintFunc()("\u221A")
38 warnStatus = color.New(color.FgYellow, color.Bold).SprintFunc()("\u203C")
39 failStatus = color.New(color.FgRed, color.Bold).SprintFunc()("\u00D7")
40
41 controlPlaneNamespace string
42 cniNamespace string
43 apiAddr string
44 kubeconfigPath string
45 kubeContext string
46 impersonate string
47 impersonateGroup []string
48 verbose bool
49
50
51
52 alphaNumDash = regexp.MustCompile(`^[a-zA-Z0-9-]+$`)
53 alphaNumDashDot = regexp.MustCompile(`^[\.a-zA-Z0-9-]+$`)
54 alphaNumDashDotSlashColon = regexp.MustCompile(`^[\./a-zA-Z0-9-:]+$`)
55
56
57
58 r = strings.NewReplacer("\t", "", "\n", "")
59 validProxyLogLevel = regexp.MustCompile(r.Replace(`
60 ^(
61 (
62 (trace|debug|warn|info|error)|
63 (\w|::)+|
64 ((\w|::)+=(trace|debug|warn|info|error))
65 )(?:,|$)
66 )+$`))
67 )
68
69
70 var RootCmd = &cobra.Command{
71 Use: "linkerd",
72 Short: "linkerd manages the Linkerd service mesh",
73 Long: `linkerd manages the Linkerd service mesh.`,
74 PersistentPreRunE: func(cmd *cobra.Command, args []string) error {
75
76 if verbose {
77 log.SetLevel(log.DebugLevel)
78 } else {
79 log.SetLevel(log.PanicLevel)
80 }
81
82 controlPlaneNamespaceFromEnv := os.Getenv(flags.EnvOverrideNamespace)
83 if controlPlaneNamespace == defaultLinkerdNamespace && controlPlaneNamespaceFromEnv != "" {
84 controlPlaneNamespace = controlPlaneNamespaceFromEnv
85 }
86
87 if !alphaNumDash.MatchString(controlPlaneNamespace) {
88 return fmt.Errorf("%s is not a valid namespace", controlPlaneNamespace)
89 }
90
91 return nil
92 },
93 }
94
95 func init() {
96 RootCmd.PersistentFlags().StringVarP(&controlPlaneNamespace, "linkerd-namespace", "L",
97 defaultLinkerdNamespace,
98 fmt.Sprintf("Namespace in which Linkerd is installed ($%s)", flags.EnvOverrideNamespace))
99 RootCmd.PersistentFlags().StringVarP(&cniNamespace, "cni-namespace", "", defaultCNINamespace, "Namespace in which the Linkerd CNI plugin is installed")
100 RootCmd.PersistentFlags().StringVar(&kubeconfigPath, "kubeconfig", "", "Path to the kubeconfig file to use for CLI requests")
101 RootCmd.PersistentFlags().StringVar(&kubeContext, "context", "", "Name of the kubeconfig context to use")
102 RootCmd.PersistentFlags().StringVar(&impersonate, "as", "", "Username to impersonate for Kubernetes operations")
103 RootCmd.PersistentFlags().StringArrayVar(&impersonateGroup, "as-group", []string{}, "Group to impersonate for Kubernetes operations")
104 RootCmd.PersistentFlags().StringVar(&apiAddr, "api-addr", "", "Override kubeconfig and communicate directly with the control plane at host:port (mostly for testing)")
105 RootCmd.PersistentFlags().BoolVar(&verbose, "verbose", false, "Turn on debug logging")
106 RootCmd.AddCommand(newCmdAlpha())
107 RootCmd.AddCommand(newCmdCheck())
108 RootCmd.AddCommand(newCmdCompletion())
109 RootCmd.AddCommand(newCmdDiagnostics())
110 RootCmd.AddCommand(newCmdDoc())
111 RootCmd.AddCommand(newCmdIdentity())
112 RootCmd.AddCommand(newCmdInject())
113 RootCmd.AddCommand(newCmdInstall())
114 RootCmd.AddCommand(newCmdInstallCNIPlugin())
115 RootCmd.AddCommand(newCmdProfile())
116 RootCmd.AddCommand(newCmdAuthz())
117 RootCmd.AddCommand(newCmdUninject())
118 RootCmd.AddCommand(newCmdUpgrade())
119 RootCmd.AddCommand(newCmdVersion())
120 RootCmd.AddCommand(newCmdUninstall())
121 RootCmd.AddCommand(newCmdPrune())
122
123
124 RootCmd.AddCommand(jaeger.NewCmdJaeger())
125 RootCmd.AddCommand(multicluster.NewCmdMulticluster())
126 RootCmd.AddCommand(viz.NewCmdViz())
127
128
129 RootCmd.AddCommand(deprecateCmd(viz.NewCmdDashboard()))
130 RootCmd.AddCommand(deprecateCmd(viz.NewCmdEdges()))
131 RootCmd.AddCommand(deprecateCmd(viz.NewCmdRoutes()))
132 RootCmd.AddCommand(deprecateCmd(viz.NewCmdStat()))
133 RootCmd.AddCommand(deprecateCmd(viz.NewCmdTap()))
134 RootCmd.AddCommand(deprecateCmd(viz.NewCmdTop()))
135
136
137 pkgcmd.ConfigureNamespaceFlagCompletion(
138 RootCmd, []string{"linkerd-namespace", "cni-namespace"},
139 kubeconfigPath, impersonate, impersonateGroup, kubeContext)
140
141 pkgcmd.ConfigureKubeContextFlagCompletion(RootCmd, kubeconfigPath)
142 }
143
144 func deprecateCmd(cmd *cobra.Command) *cobra.Command {
145 cmd.Deprecated = fmt.Sprintf("use instead 'linkerd viz %s'\n", cmd.Use)
146 return cmd
147 }
148
149 func flattenFlags(flags ...[]flag.Flag) []flag.Flag {
150 out := []flag.Flag{}
151 for _, f := range flags {
152 out = append(out, f...)
153 }
154 return out
155 }
156
View as plain text