mirror of https://github.com/linkerd/linkerd2.git
Make wait flag configurable for check and dashboard (#1654)
Signed-off-by: Alena Varkockova <varkockova.a@gmail.com>
This commit is contained in:
parent
f550431278
commit
8ab9b4981b
|
@ -4,6 +4,7 @@ import (
|
|||
"fmt"
|
||||
"io"
|
||||
"os"
|
||||
"time"
|
||||
|
||||
"github.com/linkerd/linkerd2/pkg/healthcheck"
|
||||
"github.com/spf13/cobra"
|
||||
|
@ -18,7 +19,7 @@ type checkOptions struct {
|
|||
versionOverride string
|
||||
preInstallOnly bool
|
||||
dataPlaneOnly bool
|
||||
wait bool
|
||||
wait time.Duration
|
||||
namespace string
|
||||
}
|
||||
|
||||
|
@ -27,7 +28,7 @@ func newCheckOptions() *checkOptions {
|
|||
versionOverride: "",
|
||||
preInstallOnly: false,
|
||||
dataPlaneOnly: false,
|
||||
wait: true,
|
||||
wait: 300 * time.Second,
|
||||
namespace: "",
|
||||
}
|
||||
}
|
||||
|
@ -62,7 +63,7 @@ non-zero exit code.`,
|
|||
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", options.wait, "Retry and wait for some checks to succeed if they don't pass the first time")
|
||||
cmd.PersistentFlags().DurationVar(&options.wait, "wait", options.wait, "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
|
||||
|
@ -88,7 +89,7 @@ func configureAndRunChecks(options *checkOptions) {
|
|||
KubeConfig: kubeconfigPath,
|
||||
APIAddr: apiAddr,
|
||||
VersionOverride: options.versionOverride,
|
||||
ShouldRetry: options.wait,
|
||||
RetryDeadline: time.Now().Add(options.wait),
|
||||
ShouldCheckKubeVersion: true,
|
||||
ShouldCheckControlPlaneVersion: !(options.preInstallOnly || options.dataPlaneOnly),
|
||||
ShouldCheckDataPlaneVersion: options.dataPlaneOnly,
|
||||
|
|
|
@ -3,6 +3,7 @@ package cmd
|
|||
import (
|
||||
"fmt"
|
||||
"os"
|
||||
"time"
|
||||
|
||||
"github.com/linkerd/linkerd2/pkg/k8s"
|
||||
"github.com/pkg/browser"
|
||||
|
@ -24,14 +25,14 @@ const (
|
|||
type dashboardOptions struct {
|
||||
dashboardProxyPort int
|
||||
dashboardShow string
|
||||
wait bool
|
||||
wait time.Duration
|
||||
}
|
||||
|
||||
func newDashboardOptions() *dashboardOptions {
|
||||
return &dashboardOptions{
|
||||
dashboardProxyPort: 0,
|
||||
dashboardShow: showLinkerd,
|
||||
wait: true,
|
||||
wait: 300 * time.Second,
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -70,7 +71,7 @@ func newCmdDashboard() *cobra.Command {
|
|||
}
|
||||
|
||||
// ensure we can connect to the public API before starting the proxy
|
||||
validatedPublicAPIClient(options.wait)
|
||||
validatedPublicAPIClient(time.Now().Add(options.wait))
|
||||
|
||||
fmt.Printf("Linkerd dashboard available at:\n%s\n", url.String())
|
||||
fmt.Printf("Grafana dashboard available at:\n%s\n", grafanaUrl.String())
|
||||
|
@ -111,7 +112,7 @@ func newCmdDashboard() *cobra.Command {
|
|||
// This is identical to what `kubectl proxy --help` reports, `--port 0` indicates a random port.
|
||||
cmd.PersistentFlags().IntVarP(&options.dashboardProxyPort, "port", "p", options.dashboardProxyPort, "The port on which to run the proxy (when set to 0, a random port will be used)")
|
||||
cmd.PersistentFlags().StringVar(&options.dashboardShow, "show", options.dashboardShow, "Open a dashboard in a browser or show URLs in the CLI (one of: linkerd, grafana, url)")
|
||||
cmd.PersistentFlags().BoolVar(&options.wait, "wait", options.wait, "Wait for dashboard to become available if it's not available when the command is run")
|
||||
cmd.PersistentFlags().DurationVar(&options.wait, "wait", options.wait, "Wait for dashboard to become available if it's not available when the command is run")
|
||||
|
||||
return cmd
|
||||
}
|
||||
|
|
|
@ -5,6 +5,7 @@ import (
|
|||
"errors"
|
||||
"fmt"
|
||||
"os"
|
||||
"time"
|
||||
|
||||
pb "github.com/linkerd/linkerd2/controller/gen/public"
|
||||
"github.com/linkerd/linkerd2/pkg/k8s"
|
||||
|
@ -55,7 +56,7 @@ Only pod resources (aka pods, po) are supported.`,
|
|||
return fmt.Errorf("invalid resource type %s, valid types: %s", friendlyName, k8s.Pod)
|
||||
}
|
||||
|
||||
podNames, err := getPods(validatedPublicAPIClient(false), options)
|
||||
podNames, err := getPods(validatedPublicAPIClient(time.Time{}), options)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
|
|
@ -77,7 +77,7 @@ func init() {
|
|||
// checks to determine if the client can successfully connect to the API. If the
|
||||
// checks fail, then CLI will print an error and exit. If the shouldRetry param
|
||||
// is specified, then the CLI will print a message to stderr and retry.
|
||||
func validatedPublicAPIClient(shouldRetry bool) pb.ApiClient {
|
||||
func validatedPublicAPIClient(retryDeadline time.Time) pb.ApiClient {
|
||||
checks := []healthcheck.Checks{
|
||||
healthcheck.KubernetesAPIChecks,
|
||||
healthcheck.LinkerdAPIChecks,
|
||||
|
@ -87,7 +87,7 @@ func validatedPublicAPIClient(shouldRetry bool) pb.ApiClient {
|
|||
ControlPlaneNamespace: controlPlaneNamespace,
|
||||
KubeConfig: kubeconfigPath,
|
||||
APIAddr: apiAddr,
|
||||
ShouldRetry: shouldRetry,
|
||||
RetryDeadline: retryDeadline,
|
||||
})
|
||||
|
||||
exitOnError := func(result *healthcheck.CheckResult) {
|
||||
|
|
|
@ -105,7 +105,7 @@ If no resource name is specified, displays stats about all resources of the spec
|
|||
return fmt.Errorf("error creating metrics request while making stats request: %v", err)
|
||||
}
|
||||
|
||||
output, err := requestStatsFromAPI(validatedPublicAPIClient(false), req, options)
|
||||
output, err := requestStatsFromAPI(validatedPublicAPIClient(time.Time{}), req, options)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
|
|
@ -7,6 +7,7 @@ import (
|
|||
"os"
|
||||
"strings"
|
||||
"text/tabwriter"
|
||||
"time"
|
||||
|
||||
"github.com/linkerd/linkerd2/controller/api/util"
|
||||
pb "github.com/linkerd/linkerd2/controller/gen/public"
|
||||
|
@ -103,7 +104,7 @@ func newCmdTap() *cobra.Command {
|
|||
return fmt.Errorf("output format \"%s\" not recognized", options.output)
|
||||
}
|
||||
|
||||
return requestTapByResourceFromAPI(os.Stdout, validatedPublicAPIClient(false), req, wide)
|
||||
return requestTapByResourceFromAPI(os.Stdout, validatedPublicAPIClient(time.Time{}), req, wide)
|
||||
},
|
||||
}
|
||||
|
||||
|
|
|
@ -131,7 +131,7 @@ func newCmdTop() *cobra.Command {
|
|||
return err
|
||||
}
|
||||
|
||||
return getTrafficByResourceFromAPI(os.Stdout, validatedPublicAPIClient(false), req, options)
|
||||
return getTrafficByResourceFromAPI(os.Stdout, validatedPublicAPIClient(time.Time{}), req, options)
|
||||
},
|
||||
}
|
||||
|
||||
|
|
|
@ -66,12 +66,12 @@ var (
|
|||
)
|
||||
|
||||
type checker struct {
|
||||
category string
|
||||
description string
|
||||
fatal bool
|
||||
retry bool
|
||||
check func() error
|
||||
checkRPC func() (*healthcheckPb.SelfCheckResponse, error)
|
||||
category string
|
||||
description string
|
||||
fatal bool
|
||||
retryDeadline time.Time
|
||||
check func() error
|
||||
checkRPC func() (*healthcheckPb.SelfCheckResponse, error)
|
||||
}
|
||||
|
||||
type CheckResult struct {
|
||||
|
@ -89,7 +89,7 @@ type HealthCheckOptions struct {
|
|||
KubeConfig string
|
||||
APIAddr string
|
||||
VersionOverride string
|
||||
ShouldRetry bool
|
||||
RetryDeadline time.Time
|
||||
ShouldCheckKubeVersion bool
|
||||
ShouldCheckControlPlaneVersion bool
|
||||
ShouldCheckDataPlaneVersion bool
|
||||
|
@ -263,10 +263,10 @@ func (hc *HealthChecker) addLinkerdAPIChecks() {
|
|||
})
|
||||
|
||||
hc.checkers = append(hc.checkers, &checker{
|
||||
category: LinkerdAPICategory,
|
||||
description: "control plane pods are ready",
|
||||
retry: hc.ShouldRetry,
|
||||
fatal: true,
|
||||
category: LinkerdAPICategory,
|
||||
description: "control plane pods are ready",
|
||||
retryDeadline: hc.RetryDeadline,
|
||||
fatal: true,
|
||||
check: func() error {
|
||||
var err error
|
||||
hc.controlPlanePods, err = hc.kubeAPI.GetPodsByNamespace(hc.httpClient, hc.ControlPlaneNamespace)
|
||||
|
@ -316,10 +316,10 @@ func (hc *HealthChecker) addLinkerdDataPlaneChecks() {
|
|||
}
|
||||
|
||||
hc.checkers = append(hc.checkers, &checker{
|
||||
category: LinkerdDataPlaneCategory,
|
||||
description: "data plane proxies are ready",
|
||||
retry: hc.ShouldRetry,
|
||||
fatal: true,
|
||||
category: LinkerdDataPlaneCategory,
|
||||
description: "data plane proxies are ready",
|
||||
retryDeadline: hc.RetryDeadline,
|
||||
fatal: true,
|
||||
check: func() error {
|
||||
var err error
|
||||
hc.dataPlanePods, err = hc.kubeAPI.GetPodsByControllerNamespace(
|
||||
|
@ -336,10 +336,10 @@ func (hc *HealthChecker) addLinkerdDataPlaneChecks() {
|
|||
})
|
||||
|
||||
hc.checkers = append(hc.checkers, &checker{
|
||||
category: LinkerdDataPlaneCategory,
|
||||
description: "data plane proxy metrics are present in Prometheus",
|
||||
retry: hc.ShouldRetry,
|
||||
fatal: false,
|
||||
category: LinkerdDataPlaneCategory,
|
||||
description: "data plane proxy metrics are present in Prometheus",
|
||||
retryDeadline: hc.RetryDeadline,
|
||||
fatal: false,
|
||||
check: func() error {
|
||||
req := &pb.ListPodsRequest{}
|
||||
if hc.DataPlaneNamespace != "" {
|
||||
|
@ -462,11 +462,6 @@ func (hc *HealthChecker) RunChecks(observer checkObserver) bool {
|
|||
}
|
||||
|
||||
func (hc *HealthChecker) runCheck(c *checker, observer checkObserver) bool {
|
||||
var retries int
|
||||
if c.retry {
|
||||
retries = maxRetries
|
||||
}
|
||||
|
||||
for {
|
||||
err := c.check()
|
||||
checkResult := &CheckResult{
|
||||
|
@ -475,8 +470,7 @@ func (hc *HealthChecker) runCheck(c *checker, observer checkObserver) bool {
|
|||
Err: err,
|
||||
}
|
||||
|
||||
if err != nil && retries > 0 {
|
||||
retries--
|
||||
if err != nil && time.Now().Before(c.retryDeadline) {
|
||||
checkResult.Retry = true
|
||||
observer(checkResult)
|
||||
time.Sleep(retryWindow)
|
||||
|
|
|
@ -6,6 +6,7 @@ import (
|
|||
"reflect"
|
||||
"strings"
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
"github.com/linkerd/linkerd2/controller/api/public"
|
||||
healthcheckPb "github.com/linkerd/linkerd2/controller/gen/common/healthcheck"
|
||||
|
@ -24,6 +25,7 @@ func TestHealthChecker(t *testing.T) {
|
|||
check: func() error {
|
||||
return nil
|
||||
},
|
||||
retryDeadline: time.Time{},
|
||||
}
|
||||
|
||||
passingCheck2 := &checker{
|
||||
|
@ -32,6 +34,7 @@ func TestHealthChecker(t *testing.T) {
|
|||
check: func() error {
|
||||
return nil
|
||||
},
|
||||
retryDeadline: time.Time{},
|
||||
}
|
||||
|
||||
failingCheck := &checker{
|
||||
|
@ -40,6 +43,7 @@ func TestHealthChecker(t *testing.T) {
|
|||
check: func() error {
|
||||
return fmt.Errorf("error")
|
||||
},
|
||||
retryDeadline: time.Time{},
|
||||
}
|
||||
|
||||
passingRPCClient := public.MockApiClient{
|
||||
|
@ -61,6 +65,7 @@ func TestHealthChecker(t *testing.T) {
|
|||
return passingRPCClient.SelfCheck(context.Background(),
|
||||
&healthcheckPb.SelfCheckRequest{})
|
||||
},
|
||||
retryDeadline: time.Time{},
|
||||
}
|
||||
|
||||
failingRPCClient := public.MockApiClient{
|
||||
|
@ -83,6 +88,7 @@ func TestHealthChecker(t *testing.T) {
|
|||
return failingRPCClient.SelfCheck(context.Background(),
|
||||
&healthcheckPb.SelfCheckRequest{})
|
||||
},
|
||||
retryDeadline: time.Time{},
|
||||
}
|
||||
|
||||
fatalCheck := &checker{
|
||||
|
@ -92,6 +98,7 @@ func TestHealthChecker(t *testing.T) {
|
|||
check: func() error {
|
||||
return fmt.Errorf("fatal")
|
||||
},
|
||||
retryDeadline: time.Time{},
|
||||
}
|
||||
|
||||
t.Run("Notifies observer of all results", func(t *testing.T) {
|
||||
|
@ -214,9 +221,9 @@ func TestHealthChecker(t *testing.T) {
|
|||
returnError := true
|
||||
|
||||
retryCheck := &checker{
|
||||
category: "cat7",
|
||||
description: "desc7",
|
||||
retry: true,
|
||||
category: "cat7",
|
||||
description: "desc7",
|
||||
retryDeadline: time.Now().Add(100 * time.Second),
|
||||
check: func() error {
|
||||
if returnError {
|
||||
returnError = false
|
||||
|
|
Loading…
Reference in New Issue