mirror of https://github.com/linkerd/linkerd2.git
Consolidate timeouts for `linkerd check` (#2191)
Consolidate timeouts for `linkerd check` - Moved the creation of contexts from inside the methods targeted by the checks into a single place in the runCheck() and runCheckRPC() methods where the context is built using a hard-coded timeout of 30 seconds. - k8s' client-go doesn't allow passing along contexts, but it let's us setting the Timeout manually. - Reworded the description for the --wait option. Signed-off-by: Alejandro Pedraza <alejandro@buoyant.io>
This commit is contained in:
parent
66070c26f4
commit
2a7654ce78
|
|
@ -63,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().DurationVar(&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, "Maximum allowed time for all tests to pass")
|
||||
cmd.PersistentFlags().StringVarP(&options.namespace, "namespace", "n", options.namespace, "Namespace to use for --proxy checks (default: all namespaces)")
|
||||
cmd.PersistentFlags().BoolVar(&options.singleNamespace, "single-namespace", options.singleNamespace, "When running pre-installation checks (--pre), only check the permissions required to operate the control plane in a single namespace")
|
||||
|
||||
|
|
|
|||
|
|
@ -2,6 +2,7 @@ package cmd
|
|||
|
||||
import (
|
||||
"bytes"
|
||||
"context"
|
||||
"fmt"
|
||||
"io/ioutil"
|
||||
"testing"
|
||||
|
|
@ -15,10 +16,10 @@ func TestCheckStatus(t *testing.T) {
|
|||
[]healthcheck.CategoryID{},
|
||||
&healthcheck.Options{},
|
||||
)
|
||||
hc.Add("category", "check1", "", func() error {
|
||||
hc.Add("category", "check1", "", func(context.Context) error {
|
||||
return nil
|
||||
})
|
||||
hc.Add("category", "check2", "http://linkerd.io/hint-url", func() error {
|
||||
hc.Add("category", "check2", "http://linkerd.io/hint-url", func(context.Context) error {
|
||||
return fmt.Errorf("This should contain instructions for fail")
|
||||
})
|
||||
|
||||
|
|
|
|||
|
|
@ -1,9 +1,11 @@
|
|||
package cmd
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"io"
|
||||
"os"
|
||||
"time"
|
||||
|
||||
"github.com/linkerd/linkerd2/controller/api/public"
|
||||
pb "github.com/linkerd/linkerd2/controller/gen/public"
|
||||
|
|
@ -65,7 +67,9 @@ func configureAndRunVersion(
|
|||
os.Exit(1)
|
||||
}
|
||||
|
||||
serverVersion, err := healthcheck.GetServerVersion(client)
|
||||
ctx, cancel := context.WithTimeout(context.Background(), 5*time.Second)
|
||||
defer cancel()
|
||||
serverVersion, err := healthcheck.GetServerVersion(ctx, client)
|
||||
if err != nil {
|
||||
serverVersion = defaultVersionString
|
||||
}
|
||||
|
|
|
|||
|
|
@ -102,8 +102,8 @@ const (
|
|||
)
|
||||
|
||||
var (
|
||||
maxRetries = 60
|
||||
retryWindow = 5 * time.Second
|
||||
requestTimeout = 30 * time.Second
|
||||
clusterZoneSuffix = []string{"svc", "cluster", "local"}
|
||||
)
|
||||
|
||||
|
|
@ -130,12 +130,12 @@ type checker struct {
|
|||
|
||||
// check is the function that's called to execute the check; if the function
|
||||
// returns an error, the check fails
|
||||
check func() error
|
||||
check func(context.Context) error
|
||||
|
||||
// checkRPC is an alternative to check that can be used to perform a remote
|
||||
// check using the SelfCheck gRPC endpoint; check status is based on the value
|
||||
// of the gRPC response
|
||||
checkRPC func() (*healthcheckPb.SelfCheckResponse, error)
|
||||
checkRPC func(context.Context) (*healthcheckPb.SelfCheckResponse, error)
|
||||
}
|
||||
|
||||
// CheckResult encapsulates a check's identifying information and output
|
||||
|
|
@ -222,8 +222,15 @@ func (hc *HealthChecker) allCategories() []category {
|
|||
description: "can initialize the client",
|
||||
hintURL: "https://linkerd.io/2/faq/#k8s-api",
|
||||
fatal: true,
|
||||
check: func() (err error) {
|
||||
check: func(context.Context) (err error) {
|
||||
hc.kubeAPI, err = k8s.NewAPI(hc.KubeConfig, hc.KubeContext)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
// k8s' client-go doesn't support injecting context
|
||||
// https://github.com/kubernetes/kubernetes/issues/46503
|
||||
// but we can set the timeout manually
|
||||
hc.kubeAPI.Timeout = requestTimeout
|
||||
return
|
||||
},
|
||||
},
|
||||
|
|
@ -231,12 +238,12 @@ func (hc *HealthChecker) allCategories() []category {
|
|||
description: "can query the Kubernetes API",
|
||||
hintURL: "https://linkerd.io/2/faq/#k8s-api",
|
||||
fatal: true,
|
||||
check: func() (err error) {
|
||||
check: func(ctx context.Context) (err error) {
|
||||
hc.httpClient, err = hc.kubeAPI.NewClient()
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
hc.kubeVersion, err = hc.kubeAPI.GetVersionInfo(hc.httpClient)
|
||||
hc.kubeVersion, err = hc.kubeAPI.GetVersionInfo(ctx, hc.httpClient)
|
||||
return
|
||||
},
|
||||
},
|
||||
|
|
@ -248,7 +255,7 @@ func (hc *HealthChecker) allCategories() []category {
|
|||
{
|
||||
description: "is running the minimum Kubernetes API version",
|
||||
hintURL: "https://linkerd.io/2/faq/#k8s-version",
|
||||
check: func() error {
|
||||
check: func(context.Context) error {
|
||||
return hc.kubeAPI.CheckVersion(hc.kubeVersion)
|
||||
},
|
||||
},
|
||||
|
|
@ -260,35 +267,35 @@ func (hc *HealthChecker) allCategories() []category {
|
|||
{
|
||||
description: "control plane namespace does not already exist",
|
||||
hintURL: "https://linkerd.io/2/faq/#pre-ns",
|
||||
check: func() error {
|
||||
return hc.checkNamespace(hc.ControlPlaneNamespace, false)
|
||||
check: func(ctx context.Context) error {
|
||||
return hc.checkNamespace(ctx, hc.ControlPlaneNamespace, false)
|
||||
},
|
||||
},
|
||||
{
|
||||
description: "can create Namespaces",
|
||||
hintURL: "https://linkerd.io/2/faq/#pre-k8s-cluster-k8s",
|
||||
check: func() error {
|
||||
check: func(context.Context) error {
|
||||
return hc.checkCanCreate("", "", "v1", "Namespace")
|
||||
},
|
||||
},
|
||||
{
|
||||
description: "can create ClusterRoles",
|
||||
hintURL: "https://linkerd.io/2/faq/#pre-k8s-cluster-k8s",
|
||||
check: func() error {
|
||||
check: func(context.Context) error {
|
||||
return hc.checkCanCreate("", "rbac.authorization.k8s.io", "v1beta1", "ClusterRole")
|
||||
},
|
||||
},
|
||||
{
|
||||
description: "can create ClusterRoleBindings",
|
||||
hintURL: "https://linkerd.io/2/faq/#pre-k8s-cluster-k8s",
|
||||
check: func() error {
|
||||
check: func(context.Context) error {
|
||||
return hc.checkCanCreate("", "rbac.authorization.k8s.io", "v1beta1", "ClusterRoleBinding")
|
||||
},
|
||||
},
|
||||
{
|
||||
description: "can create CustomResourceDefinitions",
|
||||
hintURL: "https://linkerd.io/2/faq/#pre-k8s-cluster-k8s",
|
||||
check: func() error {
|
||||
check: func(context.Context) error {
|
||||
return hc.checkCanCreate(hc.ControlPlaneNamespace, "apiextensions.k8s.io", "v1beta1", "CustomResourceDefinition")
|
||||
},
|
||||
},
|
||||
|
|
@ -300,21 +307,21 @@ func (hc *HealthChecker) allCategories() []category {
|
|||
{
|
||||
description: "control plane namespace exists",
|
||||
hintURL: "https://linkerd.io/2/faq/#pre-single-ns",
|
||||
check: func() error {
|
||||
return hc.checkNamespace(hc.ControlPlaneNamespace, true)
|
||||
check: func(ctx context.Context) error {
|
||||
return hc.checkNamespace(ctx, hc.ControlPlaneNamespace, true)
|
||||
},
|
||||
},
|
||||
{
|
||||
description: "can create Roles",
|
||||
hintURL: "https://linkerd.io/2/faq/#pre-k8s-cluster-k8s",
|
||||
check: func() error {
|
||||
check: func(context.Context) error {
|
||||
return hc.checkCanCreate(hc.ControlPlaneNamespace, "rbac.authorization.k8s.io", "v1beta1", "Role")
|
||||
},
|
||||
},
|
||||
{
|
||||
description: "can create RoleBindings",
|
||||
hintURL: "https://linkerd.io/2/faq/#pre-k8s-cluster-k8s",
|
||||
check: func() error {
|
||||
check: func(context.Context) error {
|
||||
return hc.checkCanCreate(hc.ControlPlaneNamespace, "rbac.authorization.k8s.io", "v1beta1", "RoleBinding")
|
||||
},
|
||||
},
|
||||
|
|
@ -326,28 +333,28 @@ func (hc *HealthChecker) allCategories() []category {
|
|||
{
|
||||
description: "can create ServiceAccounts",
|
||||
hintURL: "https://linkerd.io/2/faq/#pre-k8s",
|
||||
check: func() error {
|
||||
check: func(context.Context) error {
|
||||
return hc.checkCanCreate(hc.ControlPlaneNamespace, "", "v1", "ServiceAccount")
|
||||
},
|
||||
},
|
||||
{
|
||||
description: "can create Services",
|
||||
hintURL: "https://linkerd.io/2/faq/#pre-k8s",
|
||||
check: func() error {
|
||||
check: func(context.Context) error {
|
||||
return hc.checkCanCreate(hc.ControlPlaneNamespace, "", "v1", "Service")
|
||||
},
|
||||
},
|
||||
{
|
||||
description: "can create Deployments",
|
||||
hintURL: "https://linkerd.io/2/faq/#pre-k8s",
|
||||
check: func() error {
|
||||
check: func(context.Context) error {
|
||||
return hc.checkCanCreate(hc.ControlPlaneNamespace, "extensions", "v1beta1", "Deployments")
|
||||
},
|
||||
},
|
||||
{
|
||||
description: "can create ConfigMaps",
|
||||
hintURL: "https://linkerd.io/2/faq/#pre-k8s",
|
||||
check: func() error {
|
||||
check: func(context.Context) error {
|
||||
return hc.checkCanCreate(hc.ControlPlaneNamespace, "", "v1", "ConfigMap")
|
||||
},
|
||||
},
|
||||
|
|
@ -360,8 +367,8 @@ func (hc *HealthChecker) allCategories() []category {
|
|||
description: "control plane namespace exists",
|
||||
hintURL: "https://linkerd.io/2/faq/#l5d-existence-ns",
|
||||
fatal: true,
|
||||
check: func() error {
|
||||
return hc.checkNamespace(hc.ControlPlaneNamespace, true)
|
||||
check: func(ctx context.Context) error {
|
||||
return hc.checkNamespace(ctx, hc.ControlPlaneNamespace, true)
|
||||
},
|
||||
},
|
||||
{
|
||||
|
|
@ -369,9 +376,9 @@ func (hc *HealthChecker) allCategories() []category {
|
|||
hintURL: "https://linkerd.io/2/faq/#l5d-existence-controller",
|
||||
retryDeadline: hc.RetryDeadline,
|
||||
fatal: true,
|
||||
check: func() error {
|
||||
check: func(ctx context.Context) error {
|
||||
var err error
|
||||
hc.controlPlanePods, err = hc.kubeAPI.GetPodsByNamespace(hc.httpClient, hc.ControlPlaneNamespace)
|
||||
hc.controlPlanePods, err = hc.kubeAPI.GetPodsByNamespace(ctx, hc.httpClient, hc.ControlPlaneNamespace)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
|
@ -382,7 +389,7 @@ func (hc *HealthChecker) allCategories() []category {
|
|||
description: "can initialize the client",
|
||||
hintURL: "https://linkerd.io/2/faq/#l5d-existence-client",
|
||||
fatal: true,
|
||||
check: func() (err error) {
|
||||
check: func(context.Context) (err error) {
|
||||
if hc.APIAddr != "" {
|
||||
hc.apiClient, err = public.NewInternalClient(hc.ControlPlaneNamespace, hc.APIAddr)
|
||||
} else {
|
||||
|
|
@ -396,8 +403,8 @@ func (hc *HealthChecker) allCategories() []category {
|
|||
hintURL: "https://linkerd.io/2/faq/#l5d-existence-api",
|
||||
retryDeadline: hc.RetryDeadline,
|
||||
fatal: true,
|
||||
check: func() (err error) {
|
||||
hc.serverVersion, err = GetServerVersion(hc.apiClient)
|
||||
check: func(ctx context.Context) (err error) {
|
||||
hc.serverVersion, err = GetServerVersion(ctx, hc.apiClient)
|
||||
return
|
||||
},
|
||||
},
|
||||
|
|
@ -411,9 +418,9 @@ func (hc *HealthChecker) allCategories() []category {
|
|||
hintURL: "https://linkerd.io/2/faq/#l5d-api-control-ready",
|
||||
retryDeadline: hc.RetryDeadline,
|
||||
fatal: true,
|
||||
check: func() error {
|
||||
check: func(ctx context.Context) error {
|
||||
var err error
|
||||
hc.controlPlanePods, err = hc.kubeAPI.GetPodsByNamespace(hc.httpClient, hc.ControlPlaneNamespace)
|
||||
hc.controlPlanePods, err = hc.kubeAPI.GetPodsByNamespace(ctx, hc.httpClient, hc.ControlPlaneNamespace)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
|
@ -425,9 +432,7 @@ func (hc *HealthChecker) allCategories() []category {
|
|||
hintURL: "https://linkerd.io/2/faq/#l5d-api-control-api",
|
||||
fatal: true,
|
||||
retryDeadline: hc.RetryDeadline,
|
||||
checkRPC: func() (*healthcheckPb.SelfCheckResponse, error) {
|
||||
ctx, cancel := context.WithTimeout(context.Background(), 5*time.Second)
|
||||
defer cancel()
|
||||
checkRPC: func(ctx context.Context) (*healthcheckPb.SelfCheckResponse, error) {
|
||||
return hc.apiClient.SelfCheck(ctx, &healthcheckPb.SelfCheckRequest{})
|
||||
},
|
||||
},
|
||||
|
|
@ -440,7 +445,7 @@ func (hc *HealthChecker) allCategories() []category {
|
|||
description: "no invalid service profiles",
|
||||
hintURL: "https://linkerd.io/2/faq/#l5d-sp",
|
||||
warning: true,
|
||||
check: func() error {
|
||||
check: func(context.Context) error {
|
||||
return hc.validateServiceProfiles()
|
||||
},
|
||||
},
|
||||
|
|
@ -452,7 +457,7 @@ func (hc *HealthChecker) allCategories() []category {
|
|||
{
|
||||
description: "can determine the latest version",
|
||||
hintURL: "https://linkerd.io/2/faq/#l5d-version-latest",
|
||||
check: func() (err error) {
|
||||
check: func(ctx context.Context) (err error) {
|
||||
if hc.VersionOverride != "" {
|
||||
hc.latestVersions, err = version.NewChannels(hc.VersionOverride)
|
||||
} else {
|
||||
|
|
@ -472,7 +477,7 @@ func (hc *HealthChecker) allCategories() []category {
|
|||
}
|
||||
}
|
||||
}
|
||||
hc.latestVersions, err = version.GetLatestVersions(uuid, "cli")
|
||||
hc.latestVersions, err = version.GetLatestVersions(ctx, uuid, "cli")
|
||||
}
|
||||
return
|
||||
},
|
||||
|
|
@ -481,7 +486,7 @@ func (hc *HealthChecker) allCategories() []category {
|
|||
description: "cli is up-to-date",
|
||||
hintURL: "https://linkerd.io/2/faq/#l5d-version-cli",
|
||||
warning: true,
|
||||
check: func() error {
|
||||
check: func(context.Context) error {
|
||||
return hc.latestVersions.Match(version.Version)
|
||||
},
|
||||
},
|
||||
|
|
@ -494,7 +499,7 @@ func (hc *HealthChecker) allCategories() []category {
|
|||
description: "control plane is up-to-date",
|
||||
hintURL: "https://linkerd.io/2/faq/#l5d-version-control",
|
||||
warning: true,
|
||||
check: func() error {
|
||||
check: func(context.Context) error {
|
||||
return hc.latestVersions.Match(hc.serverVersion)
|
||||
},
|
||||
},
|
||||
|
|
@ -502,7 +507,7 @@ func (hc *HealthChecker) allCategories() []category {
|
|||
description: "control plane and cli versions match",
|
||||
hintURL: "https://linkerd.io/2/faq/#l5d-version-control",
|
||||
warning: true,
|
||||
check: func() error {
|
||||
check: func(context.Context) error {
|
||||
if hc.serverVersion != version.Version {
|
||||
return fmt.Errorf("control plane running %s but cli running %s", hc.serverVersion, version.Version)
|
||||
}
|
||||
|
|
@ -518,8 +523,8 @@ func (hc *HealthChecker) allCategories() []category {
|
|||
description: "data plane namespace exists",
|
||||
hintURL: "https://linkerd.io/2/faq/#l5d-data-plane-exists",
|
||||
fatal: true,
|
||||
check: func() error {
|
||||
return hc.checkNamespace(hc.DataPlaneNamespace, true)
|
||||
check: func(ctx context.Context) error {
|
||||
return hc.checkNamespace(ctx, hc.DataPlaneNamespace, true)
|
||||
},
|
||||
},
|
||||
{
|
||||
|
|
@ -527,8 +532,8 @@ func (hc *HealthChecker) allCategories() []category {
|
|||
hintURL: "https://linkerd.io/2/faq/#l5d-data-plane-ready",
|
||||
retryDeadline: hc.RetryDeadline,
|
||||
fatal: true,
|
||||
check: func() error {
|
||||
pods, err := hc.getDataPlanePods()
|
||||
check: func(ctx context.Context) error {
|
||||
pods, err := hc.getDataPlanePods(ctx)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
|
@ -540,8 +545,8 @@ func (hc *HealthChecker) allCategories() []category {
|
|||
description: "data plane proxy metrics are present in Prometheus",
|
||||
hintURL: "https://linkerd.io/2/faq/#l5d-data-plane-prom",
|
||||
retryDeadline: hc.RetryDeadline,
|
||||
check: func() error {
|
||||
pods, err := hc.getDataPlanePods()
|
||||
check: func(ctx context.Context) error {
|
||||
pods, err := hc.getDataPlanePods(ctx)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
|
@ -553,8 +558,8 @@ func (hc *HealthChecker) allCategories() []category {
|
|||
description: "data plane is up-to-date",
|
||||
hintURL: "https://linkerd.io/2/faq/#l5d-data-plane-version",
|
||||
warning: true,
|
||||
check: func() error {
|
||||
pods, err := hc.getDataPlanePods()
|
||||
check: func(ctx context.Context) error {
|
||||
pods, err := hc.getDataPlanePods(ctx)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
|
@ -572,8 +577,8 @@ func (hc *HealthChecker) allCategories() []category {
|
|||
description: "data plane and cli versions match",
|
||||
hintURL: "https://linkerd.io/2/faq/#l5d-data-plane-cli-version",
|
||||
warning: true,
|
||||
check: func() error {
|
||||
pods, err := hc.getDataPlanePods()
|
||||
check: func(ctx context.Context) error {
|
||||
pods, err := hc.getDataPlanePods(ctx)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
|
@ -594,7 +599,7 @@ func (hc *HealthChecker) allCategories() []category {
|
|||
// Add adds an arbitrary checker. This should only be used for testing. For
|
||||
// production code, pass in the desired set of checks when calling
|
||||
// NewHeathChecker.
|
||||
func (hc *HealthChecker) Add(categoryID CategoryID, description string, hintURL string, check func() error) {
|
||||
func (hc *HealthChecker) Add(categoryID CategoryID, description string, hintURL string, check func(context.Context) error) {
|
||||
hc.addCategory(
|
||||
category{
|
||||
id: categoryID,
|
||||
|
|
@ -656,7 +661,9 @@ func (hc *HealthChecker) RunChecks(observer checkObserver) bool {
|
|||
|
||||
func (hc *HealthChecker) runCheck(categoryID CategoryID, c *checker, observer checkObserver) bool {
|
||||
for {
|
||||
err := c.check()
|
||||
ctx, cancel := context.WithTimeout(context.Background(), requestTimeout)
|
||||
defer cancel()
|
||||
err := c.check(ctx)
|
||||
checkResult := &CheckResult{
|
||||
Category: categoryID,
|
||||
Description: c.description,
|
||||
|
|
@ -681,7 +688,9 @@ func (hc *HealthChecker) runCheck(categoryID CategoryID, c *checker, observer ch
|
|||
}
|
||||
|
||||
func (hc *HealthChecker) runCheckRPC(categoryID CategoryID, c *checker, observer checkObserver) bool {
|
||||
checkRsp, err := c.checkRPC()
|
||||
ctx, cancel := context.WithTimeout(context.Background(), requestTimeout)
|
||||
defer cancel()
|
||||
checkRsp, err := c.checkRPC(ctx)
|
||||
observer(&CheckResult{
|
||||
Category: categoryID,
|
||||
Description: c.description,
|
||||
|
|
@ -719,8 +728,8 @@ func (hc *HealthChecker) PublicAPIClient() pb.ApiClient {
|
|||
return hc.apiClient
|
||||
}
|
||||
|
||||
func (hc *HealthChecker) checkNamespace(namespace string, shouldExist bool) error {
|
||||
exists, err := hc.kubeAPI.NamespaceExists(hc.httpClient, namespace)
|
||||
func (hc *HealthChecker) checkNamespace(ctx context.Context, namespace string, shouldExist bool) error {
|
||||
exists, err := hc.kubeAPI.NamespaceExists(ctx, hc.httpClient, namespace)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
|
@ -733,7 +742,7 @@ func (hc *HealthChecker) checkNamespace(namespace string, shouldExist bool) erro
|
|||
return nil
|
||||
}
|
||||
|
||||
func (hc *HealthChecker) getDataPlanePods() ([]*pb.Pod, error) {
|
||||
func (hc *HealthChecker) getDataPlanePods(ctx context.Context) ([]*pb.Pod, error) {
|
||||
req := &pb.ListPodsRequest{}
|
||||
if hc.DataPlaneNamespace != "" {
|
||||
req.Selector = &pb.ResourceSelection{
|
||||
|
|
@ -743,7 +752,7 @@ func (hc *HealthChecker) getDataPlanePods() ([]*pb.Pod, error) {
|
|||
}
|
||||
}
|
||||
|
||||
resp, err := hc.apiClient.ListPods(context.Background(), req)
|
||||
resp, err := hc.apiClient.ListPods(ctx, req)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
|
|
|||
|
|
@ -16,14 +16,14 @@ import (
|
|||
)
|
||||
|
||||
func TestHealthChecker(t *testing.T) {
|
||||
nullObserver := func(_ *CheckResult) {}
|
||||
nullObserver := func(*CheckResult) {}
|
||||
|
||||
passingCheck1 := category{
|
||||
id: "cat1",
|
||||
checkers: []checker{
|
||||
checker{
|
||||
description: "desc1",
|
||||
check: func() error {
|
||||
check: func(context.Context) error {
|
||||
return nil
|
||||
},
|
||||
retryDeadline: time.Time{},
|
||||
|
|
@ -36,7 +36,7 @@ func TestHealthChecker(t *testing.T) {
|
|||
checkers: []checker{
|
||||
checker{
|
||||
description: "desc2",
|
||||
check: func() error {
|
||||
check: func(context.Context) error {
|
||||
return nil
|
||||
},
|
||||
retryDeadline: time.Time{},
|
||||
|
|
@ -49,7 +49,7 @@ func TestHealthChecker(t *testing.T) {
|
|||
checkers: []checker{
|
||||
checker{
|
||||
description: "desc3",
|
||||
check: func() error {
|
||||
check: func(context.Context) error {
|
||||
return fmt.Errorf("error")
|
||||
},
|
||||
retryDeadline: time.Time{},
|
||||
|
|
@ -74,7 +74,7 @@ func TestHealthChecker(t *testing.T) {
|
|||
checkers: []checker{
|
||||
checker{
|
||||
description: "desc4",
|
||||
checkRPC: func() (*healthcheckPb.SelfCheckResponse, error) {
|
||||
checkRPC: func(context.Context) (*healthcheckPb.SelfCheckResponse, error) {
|
||||
return passingRPCClient.SelfCheck(context.Background(),
|
||||
&healthcheckPb.SelfCheckRequest{})
|
||||
},
|
||||
|
|
@ -101,7 +101,7 @@ func TestHealthChecker(t *testing.T) {
|
|||
checkers: []checker{
|
||||
checker{
|
||||
description: "desc5",
|
||||
checkRPC: func() (*healthcheckPb.SelfCheckResponse, error) {
|
||||
checkRPC: func(context.Context) (*healthcheckPb.SelfCheckResponse, error) {
|
||||
return failingRPCClient.SelfCheck(context.Background(),
|
||||
&healthcheckPb.SelfCheckRequest{})
|
||||
},
|
||||
|
|
@ -116,7 +116,7 @@ func TestHealthChecker(t *testing.T) {
|
|||
checker{
|
||||
description: "desc6",
|
||||
fatal: true,
|
||||
check: func() error {
|
||||
check: func(context.Context) error {
|
||||
return fmt.Errorf("fatal")
|
||||
},
|
||||
retryDeadline: time.Time{},
|
||||
|
|
@ -249,7 +249,7 @@ func TestHealthChecker(t *testing.T) {
|
|||
checker{
|
||||
description: "desc7",
|
||||
retryDeadline: time.Now().Add(100 * time.Second),
|
||||
check: func() error {
|
||||
check: func(context.Context) error {
|
||||
if returnError {
|
||||
returnError = false
|
||||
return fmt.Errorf("retry")
|
||||
|
|
|
|||
|
|
@ -2,16 +2,12 @@ package healthcheck
|
|||
|
||||
import (
|
||||
"context"
|
||||
"time"
|
||||
|
||||
pb "github.com/linkerd/linkerd2/controller/gen/public"
|
||||
)
|
||||
|
||||
// GetServerVersion returns the Linkerd Public API server version
|
||||
func GetServerVersion(apiClient pb.ApiClient) (string, error) {
|
||||
ctx, cancel := context.WithTimeout(context.Background(), 5*time.Second)
|
||||
defer cancel()
|
||||
|
||||
func GetServerVersion(ctx context.Context, apiClient pb.ApiClient) (string, error) {
|
||||
rsp, err := apiClient.Version(ctx, &pb.Empty{})
|
||||
if err != nil {
|
||||
return "", err
|
||||
|
|
|
|||
|
|
@ -1,8 +1,10 @@
|
|||
package healthcheck
|
||||
|
||||
import (
|
||||
"context"
|
||||
"errors"
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
"github.com/linkerd/linkerd2/controller/api/public"
|
||||
pb "github.com/linkerd/linkerd2/controller/gen/public"
|
||||
|
|
@ -24,7 +26,9 @@ func TestGetServerVersion(t *testing.T) {
|
|||
ReleaseVersion: expectedServerVersion,
|
||||
}
|
||||
|
||||
version, err := GetServerVersion(mockClient)
|
||||
ctx, cancel := context.WithTimeout(context.Background(), 5*time.Second)
|
||||
defer cancel()
|
||||
version, err := GetServerVersion(ctx, mockClient)
|
||||
if err != nil {
|
||||
t.Fatalf("GetServerVersion returned unexpected error: %s", err)
|
||||
}
|
||||
|
|
@ -39,7 +43,9 @@ func TestGetServerVersion(t *testing.T) {
|
|||
mockClient := &public.MockAPIClient{}
|
||||
mockClient.ErrorToReturn = errors.New("expected")
|
||||
|
||||
_, err := GetServerVersion(mockClient)
|
||||
ctx, cancel := context.WithTimeout(context.Background(), 5*time.Second)
|
||||
defer cancel()
|
||||
_, err := GetServerVersion(ctx, mockClient)
|
||||
if err != mockClient.ErrorToReturn {
|
||||
t.Fatalf("GetServerVersion returned unexpected error: %s", err)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -7,7 +7,6 @@ import (
|
|||
"io/ioutil"
|
||||
"net/http"
|
||||
"net/url"
|
||||
"time"
|
||||
|
||||
"k8s.io/api/core/v1"
|
||||
"k8s.io/apimachinery/pkg/version"
|
||||
|
|
@ -38,10 +37,7 @@ func (kubeAPI *KubernetesAPI) NewClient() (*http.Client, error) {
|
|||
}
|
||||
|
||||
// GetVersionInfo returns version.Info for the Kubernetes cluster.
|
||||
func (kubeAPI *KubernetesAPI) GetVersionInfo(client *http.Client) (*version.Info, error) {
|
||||
ctx, cancel := context.WithTimeout(context.Background(), 5*time.Second)
|
||||
defer cancel()
|
||||
|
||||
func (kubeAPI *KubernetesAPI) GetVersionInfo(ctx context.Context, client *http.Client) (*version.Info, error) {
|
||||
rsp, err := kubeAPI.getRequest(ctx, client, "/version")
|
||||
if err != nil {
|
||||
return nil, err
|
||||
|
|
@ -80,10 +76,7 @@ func (kubeAPI *KubernetesAPI) CheckVersion(versionInfo *version.Info) error {
|
|||
}
|
||||
|
||||
// NamespaceExists validates whether a given namespace exists.
|
||||
func (kubeAPI *KubernetesAPI) NamespaceExists(client *http.Client, namespace string) (bool, error) {
|
||||
ctx, cancel := context.WithTimeout(context.Background(), 5*time.Second)
|
||||
defer cancel()
|
||||
|
||||
func (kubeAPI *KubernetesAPI) NamespaceExists(ctx context.Context, client *http.Client, namespace string) (bool, error) {
|
||||
rsp, err := kubeAPI.getRequest(ctx, client, "/api/v1/namespaces/"+namespace)
|
||||
if err != nil {
|
||||
return false, err
|
||||
|
|
@ -98,14 +91,11 @@ func (kubeAPI *KubernetesAPI) NamespaceExists(client *http.Client, namespace str
|
|||
}
|
||||
|
||||
// GetPodsByNamespace returns all pods in a given namespace
|
||||
func (kubeAPI *KubernetesAPI) GetPodsByNamespace(client *http.Client, namespace string) ([]v1.Pod, error) {
|
||||
return kubeAPI.getPods(client, "/api/v1/namespaces/"+namespace+"/pods")
|
||||
func (kubeAPI *KubernetesAPI) GetPodsByNamespace(ctx context.Context, client *http.Client, namespace string) ([]v1.Pod, error) {
|
||||
return kubeAPI.getPods(ctx, client, "/api/v1/namespaces/"+namespace+"/pods")
|
||||
}
|
||||
|
||||
func (kubeAPI *KubernetesAPI) getPods(client *http.Client, path string) ([]v1.Pod, error) {
|
||||
ctx, cancel := context.WithTimeout(context.Background(), 5*time.Second)
|
||||
defer cancel()
|
||||
|
||||
func (kubeAPI *KubernetesAPI) getPods(ctx context.Context, client *http.Client, path string) ([]v1.Pod, error) {
|
||||
rsp, err := kubeAPI.getRequest(ctx, client, path)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
|
|
|
|||
|
|
@ -1,6 +1,7 @@
|
|||
package k8s
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"io/ioutil"
|
||||
"net"
|
||||
|
|
@ -8,6 +9,7 @@ import (
|
|||
"net/url"
|
||||
"os"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
v1 "k8s.io/api/core/v1"
|
||||
"k8s.io/client-go/kubernetes"
|
||||
|
|
@ -56,7 +58,9 @@ func NewPortForward(
|
|||
return nil, err
|
||||
}
|
||||
|
||||
pods, err := kubeAPI.GetPodsByNamespace(client, namespace)
|
||||
ctx, cancel := context.WithTimeout(context.Background(), 30*time.Second)
|
||||
defer cancel()
|
||||
pods, err := kubeAPI.GetPodsByNamespace(ctx, client, namespace)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
|
|
|||
|
|
@ -7,7 +7,6 @@ import (
|
|||
"fmt"
|
||||
"io/ioutil"
|
||||
"net/http"
|
||||
"time"
|
||||
)
|
||||
|
||||
// Channels provides an interface to interact with a set of release channels.
|
||||
|
|
@ -59,20 +58,17 @@ func (c Channels) Match(actualVersion string) error {
|
|||
|
||||
// GetLatestVersions performs an online request to check for the latest Linkerd
|
||||
// release channels.
|
||||
func GetLatestVersions(uuid string, source string) (Channels, error) {
|
||||
func GetLatestVersions(ctx context.Context, uuid string, source string) (Channels, error) {
|
||||
url := fmt.Sprintf(versionCheckURL, Version, uuid, source)
|
||||
return getLatestVersions(http.DefaultClient, url, uuid, source)
|
||||
return getLatestVersions(ctx, http.DefaultClient, url, uuid, source)
|
||||
}
|
||||
|
||||
func getLatestVersions(client *http.Client, url string, uuid string, source string) (Channels, error) {
|
||||
func getLatestVersions(ctx context.Context, client *http.Client, url string, uuid string, source string) (Channels, error) {
|
||||
req, err := http.NewRequest("GET", url, nil)
|
||||
if err != nil {
|
||||
return Channels{}, err
|
||||
}
|
||||
|
||||
ctx, cancel := context.WithTimeout(context.Background(), 5*time.Second)
|
||||
defer cancel()
|
||||
|
||||
rsp, err := client.Do(req.WithContext(ctx))
|
||||
if err != nil {
|
||||
return Channels{}, err
|
||||
|
|
|
|||
|
|
@ -1,12 +1,14 @@
|
|||
package version
|
||||
|
||||
import (
|
||||
"context"
|
||||
"encoding/json"
|
||||
"errors"
|
||||
"fmt"
|
||||
"net/http"
|
||||
"net/http/httptest"
|
||||
"testing"
|
||||
"time"
|
||||
)
|
||||
|
||||
func TestGetLatestVersions(t *testing.T) {
|
||||
|
|
@ -68,7 +70,9 @@ func TestGetLatestVersions(t *testing.T) {
|
|||
)
|
||||
defer ts.Close()
|
||||
|
||||
latest, err := getLatestVersions(ts.Client(), ts.URL, "uuid", "source")
|
||||
ctx, cancel := context.WithTimeout(context.Background(), 5*time.Second)
|
||||
defer cancel()
|
||||
latest, err := getLatestVersions(ctx, ts.Client(), ts.URL, "uuid", "source")
|
||||
if (err == nil && tc.err != nil) ||
|
||||
(err != nil && tc.err == nil) ||
|
||||
((err != nil && tc.err != nil) && (err.Error() != tc.err.Error())) {
|
||||
|
|
|
|||
Loading…
Reference in New Issue