/
check.go
133 lines (107 loc) · 4.25 KB
/
check.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
package cmd
import (
"fmt"
"io"
"os"
"github.com/linkerd/linkerd2/pkg/healthcheck"
"github.com/spf13/cobra"
)
const (
retryStatus = "[retry]"
failStatus = "[FAIL]"
)
type checkOptions struct {
versionOverride string
preInstallOnly bool
dataPlaneOnly bool
wait bool
namespace string
}
func newCheckOptions() *checkOptions {
return &checkOptions{
versionOverride: "",
preInstallOnly: false,
dataPlaneOnly: false,
wait: false,
namespace: "",
}
}
func newCmdCheck() *cobra.Command {
options := newCheckOptions()
cmd := &cobra.Command{
Use: "check",
Short: "Check the Linkerd installation for potential problems",
Long: `Check the Linkerd installation for potential problems.
The check command will perform a series of checks to validate that the linkerd
CLI and control plane are configured correctly. If the command encounters a
failure it will print additional information about the failure and exit with a
non-zero exit code.`,
Example: ` # Check that the Linkerd control plane is up and running
linkerd check
# Check that the Linkerd control plane can be installed in the "test" namespace
linkerd check --pre --linkerd-namespace test
# Check that the Linkerd data plane proxies in the "app" namespace are up and running
linkerd check --proxy --namespace app`,
Args: cobra.NoArgs,
Run: func(cmd *cobra.Command, args []string) {
configureAndRunChecks(options)
},
}
cmd.Args = cobra.NoArgs
cmd.PersistentFlags().StringVar(&options.versionOverride, "expected-version", options.versionOverride, "Overrides the version used when checking if Linkerd is running the latest version (mostly for testing)")
cmd.PersistentFlags().BoolVar(&options.preInstallOnly, "pre", options.preInstallOnly, "Only run pre-installation checks, to determine if the control plane can be installed")
cmd.PersistentFlags().BoolVar(&options.dataPlaneOnly, "proxy", options.dataPlaneOnly, "Only run data-plane checks, to determine if the data plane is healthy")
cmd.PersistentFlags().BoolVar(&options.wait, "wait", false, "Retry and wait for some checks to succeed if they don't pass the first time")
cmd.PersistentFlags().StringVarP(&options.namespace, "namespace", "n", options.namespace, "Namespace to use for --proxy checks (default: all namespaces)")
return cmd
}
func configureAndRunChecks(options *checkOptions) {
checks := []healthcheck.Checks{healthcheck.KubernetesAPIChecks}
if options.preInstallOnly {
checks = append(checks, healthcheck.LinkerdPreInstallChecks)
} else if options.dataPlaneOnly {
checks = append(checks, healthcheck.LinkerdAPIChecks)
checks = append(checks, healthcheck.LinkerdDataPlaneChecks)
} else {
checks = append(checks, healthcheck.LinkerdAPIChecks)
}
checks = append(checks, healthcheck.LinkerdVersionChecks)
hc := healthcheck.NewHealthChecker(checks, &healthcheck.HealthCheckOptions{
ControlPlaneNamespace: controlPlaneNamespace,
DataPlaneNamespace: options.namespace,
KubeConfig: kubeconfigPath,
APIAddr: apiAddr,
VersionOverride: options.versionOverride,
ShouldRetry: options.wait,
ShouldCheckKubeVersion: true,
ShouldCheckControlPlaneVersion: !(options.preInstallOnly || options.dataPlaneOnly),
ShouldCheckDataPlaneVersion: options.dataPlaneOnly,
})
success := runChecks(os.Stdout, hc)
fmt.Println("")
if !success {
fmt.Printf("Status check results are %s\n", failStatus)
os.Exit(2)
}
fmt.Printf("Status check results are %s\n", okStatus)
}
func runChecks(w io.Writer, hc *healthcheck.HealthChecker) bool {
prettyPrintResults := func(result *healthcheck.CheckResult) {
checkLabel := fmt.Sprintf("%s: %s", result.Category, result.Description)
filler := ""
lineBreak := "\n"
for i := 0; i < lineWidth-len(checkLabel)-len(okStatus)-len(lineBreak); i++ {
filler = filler + "."
}
if result.Retry {
fmt.Fprintf(w, "%s%s%s -- %s%s", checkLabel, filler, retryStatus, result.Err, lineBreak)
return
}
if result.Err != nil {
fmt.Fprintf(w, "%s%s%s -- %s%s", checkLabel, filler, failStatus, result.Err, lineBreak)
return
}
fmt.Fprintf(w, "%s%s%s%s", checkLabel, filler, okStatus, lineBreak)
}
return hc.RunChecks(prettyPrintResults)
}