Make wait flag configurable for check and dashboard (#1654)

Signed-off-by: Alena Varkockova <varkockova.a@gmail.com>
This commit is contained in:
Alena Varkockova 2018-09-19 19:42:29 +02:00 committed by Kevin Lingerfelt
parent f550431278
commit 8ab9b4981b
9 changed files with 48 additions and 43 deletions

View File

@ -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,

View File

@ -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
}

View File

@ -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
}

View File

@ -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) {

View File

@ -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
}

View File

@ -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)
},
}

View File

@ -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)
},
}

View File

@ -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)

View File

@ -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