Skip to content

Commit

Permalink
Add HTTP request timeout option to KubeClientSettings
Browse files Browse the repository at this point in the history
The HTTP client used to communicate with the Kubernetes server has a default timeout of 32 seconds. In some cases, this timeout is too low, and causes failures during provider initialization. Add an option to override this timeout value. The timeout value can be overridden in the following ways, in order of precedence:

1. The `kubeClientSettings:timeout` parameter for the Provider
2. The PULUMI_K8S_CLIENT_TIMEOUT environment variable

Note that this is distinct from the timeouts resource option, which controls how long Pulumi will wait for a resource operation to complete.
  • Loading branch information
lblackstone committed May 10, 2023
1 parent 9a7eb6c commit ed50b5d
Show file tree
Hide file tree
Showing 10 changed files with 130 additions and 2 deletions.
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@

- Update Kubernetes client library to v0.27.1 (https://github.com/pulumi/pulumi-kubernetes/pull/2380)
- Increase default client burst and QPS to avoid throttling (https://github.com/pulumi/pulumi-kubernetes/pull/2381)
- Add HTTP request timeout option to KubeClientSettings (https://github.com/pulumi/pulumi-kubernetes/pull/2383)

## 3.27.0 (May 9, 2023)

Expand Down
9 changes: 9 additions & 0 deletions provider/cmd/pulumi-resource-kubernetes/schema.json
Original file line number Diff line number Diff line change
Expand Up @@ -49051,6 +49051,15 @@
"PULUMI_K8S_CLIENT_QPS"
]
}
},
"timeout": {
"type": "integer",
"description": "Maximum time in seconds to wait before cancelling a HTTP request to the Kubernetes server. Default value is 32.",
"defaultInfo": {
"environment": [
"PULUMI_K8S_CLIENT_TIMEOUT"
]
}
}
},
"type": "object"
Expand Down
9 changes: 9 additions & 0 deletions provider/pkg/gen/overlays.go
Original file line number Diff line number Diff line change
Expand Up @@ -467,6 +467,15 @@ var kubeClientSettings = pschema.ComplexTypeSpec{
},
},
},
"timeout": {
Description: "Maximum time in seconds to wait before cancelling a HTTP request to the Kubernetes server. Default value is 32.",
TypeSpec: pschema.TypeSpec{Type: "integer"},
DefaultInfo: &pschema.DefaultSpec{
Environment: []string{
"PULUMI_K8S_CLIENT_TIMEOUT",
},
},
},
},
Type: "object",
},
Expand Down
13 changes: 13 additions & 0 deletions provider/pkg/provider/provider.go
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@ import (
"strconv"
"strings"
"sync"
"time"

jsonpatch "github.com/evanphx/json-patch"
"github.com/golang/protobuf/ptypes/empty"
Expand Down Expand Up @@ -688,6 +689,14 @@ func (k *kubeProvider) Configure(_ context.Context, req *pulumirpc.ConfigureRequ
kubeClientSettings.QPS = &v
}

if timeout := os.Getenv("PULUMI_K8S_CLIENT_TIMEOUT"); timeout != "" && kubeClientSettings.Timeout == nil {
asInt, err := strconv.Atoi(timeout)
if err != nil {
return nil, fmt.Errorf("invalid value specified for PULUMI_K8S_CLIENT_TIMEOUT: %w", err)
}
kubeClientSettings.Timeout = &asInt
}

// Attempt to load the configuration from the provided kubeconfig. If this fails, mark the cluster as unreachable.
if !k.clusterUnreachable {
config, err := kubeconfig.ClientConfig()
Expand All @@ -704,6 +713,10 @@ func (k *kubeProvider) Configure(_ context.Context, req *pulumirpc.ConfigureRequ
config.QPS = float32(*kubeClientSettings.QPS)
logger.V(9).Infof("kube client QPS set to %v", config.QPS)
}
if kubeClientSettings.Timeout != nil {
config.Timeout = time.Duration(*kubeClientSettings.Timeout) * time.Second
logger.V(9).Infof("kube client timeout set to %v", config.Timeout)
}
warningConfig := rest.CopyConfig(config)
warningConfig.WarningHandler = rest.NoWarnings{}
k.config = warningConfig
Expand Down
4 changes: 3 additions & 1 deletion provider/pkg/provider/types.go
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
// Copyright 2016-2021, Pulumi Corporation.
// Copyright 2016-2023, Pulumi Corporation.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
Expand Down Expand Up @@ -37,4 +37,6 @@ type KubeClientSettings struct {
Burst *int `json:"burst"`
// Maximum queries per second (QPS) to the API server from this client. Default value is 5.
QPS *float64 `json:"qps"`
// Maximum time in seconds to wait before cancelling a HTTP request to the Kubernetes server. Default value is 32.
Timeout *int `json:"timeout"`
}
7 changes: 7 additions & 0 deletions sdk/dotnet/Inputs/KubeClientSettingsArgs.cs
Original file line number Diff line number Diff line change
Expand Up @@ -27,10 +27,17 @@ public class KubeClientSettingsArgs : global::Pulumi.ResourceArgs
[Input("qps")]
public Input<double>? Qps { get; set; }

/// <summary>
/// Maximum time in seconds to wait before cancelling a HTTP request to the Kubernetes server. Default value is 32.
/// </summary>
[Input("timeout")]
public Input<int>? Timeout { get; set; }

public KubeClientSettingsArgs()
{
Burst = Utilities.GetEnvInt32("PULUMI_K8S_CLIENT_BURST");
Qps = Utilities.GetEnvDouble("PULUMI_K8S_CLIENT_QPS");
Timeout = Utilities.GetEnvInt32("PULUMI_K8S_CLIENT_TIMEOUT");
}
public static new KubeClientSettingsArgs Empty => new KubeClientSettingsArgs();
}
Expand Down
26 changes: 26 additions & 0 deletions sdk/go/kubernetes/pulumiTypes.go

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Original file line number Diff line number Diff line change
Expand Up @@ -51,11 +51,27 @@ public Optional<Output<Double>> qps() {
return Optional.ofNullable(this.qps);
}

/**
* Maximum time in seconds to wait before cancelling a HTTP request to the Kubernetes server. Default value is 32.
*
*/
@Import(name="timeout")
private @Nullable Output<Integer> timeout;

/**
* @return Maximum time in seconds to wait before cancelling a HTTP request to the Kubernetes server. Default value is 32.
*
*/
public Optional<Output<Integer>> timeout() {
return Optional.ofNullable(this.timeout);
}

private KubeClientSettingsArgs() {}

private KubeClientSettingsArgs(KubeClientSettingsArgs $) {
this.burst = $.burst;
this.qps = $.qps;
this.timeout = $.timeout;
}

public static Builder builder() {
Expand Down Expand Up @@ -118,9 +134,31 @@ public Builder qps(Double qps) {
return qps(Output.of(qps));
}

/**
* @param timeout Maximum time in seconds to wait before cancelling a HTTP request to the Kubernetes server. Default value is 32.
*
* @return builder
*
*/
public Builder timeout(@Nullable Output<Integer> timeout) {
$.timeout = timeout;
return this;
}

/**
* @param timeout Maximum time in seconds to wait before cancelling a HTTP request to the Kubernetes server. Default value is 32.
*
* @return builder
*
*/
public Builder timeout(Integer timeout) {
return timeout(Output.of(timeout));
}

public KubeClientSettingsArgs build() {
$.burst = Codegen.integerProp("burst").output().arg($.burst).env("PULUMI_K8S_CLIENT_BURST").getNullable();
$.qps = Codegen.doubleProp("qps").output().arg($.qps).env("PULUMI_K8S_CLIENT_QPS").getNullable();
$.timeout = Codegen.integerProp("timeout").output().arg($.timeout).env("PULUMI_K8S_CLIENT_TIMEOUT").getNullable();
return $;
}
}
Expand Down
5 changes: 5 additions & 0 deletions sdk/nodejs/types/input.ts
Original file line number Diff line number Diff line change
Expand Up @@ -59,6 +59,10 @@ export interface KubeClientSettings {
* Maximum queries per second (QPS) to the API server from this client. Default value is 5.
*/
qps?: pulumi.Input<number>;
/**
* Maximum time in seconds to wait before cancelling a HTTP request to the Kubernetes server. Default value is 32.
*/
timeout?: pulumi.Input<number>;
}
/**
* kubeClientSettingsProvideDefaults sets the appropriate defaults for KubeClientSettings
Expand All @@ -68,6 +72,7 @@ export function kubeClientSettingsProvideDefaults(val: KubeClientSettings): Kube
...val,
burst: (val.burst) ?? utilities.getEnvNumber("PULUMI_K8S_CLIENT_BURST"),
qps: (val.qps) ?? utilities.getEnvNumber("PULUMI_K8S_CLIENT_QPS"),
timeout: (val.timeout) ?? utilities.getEnvNumber("PULUMI_K8S_CLIENT_TIMEOUT"),
};
}
export namespace admissionregistration {
Expand Down
20 changes: 19 additions & 1 deletion sdk/python/pulumi_kubernetes/_inputs.py
Original file line number Diff line number Diff line change
Expand Up @@ -116,11 +116,13 @@ def repository_config_path(self, value: Optional[pulumi.Input[str]]):
class KubeClientSettingsArgs:
def __init__(__self__, *,
burst: Optional[pulumi.Input[int]] = None,
qps: Optional[pulumi.Input[float]] = None):
qps: Optional[pulumi.Input[float]] = None,
timeout: Optional[pulumi.Input[int]] = None):
"""
Options for tuning the Kubernetes client used by a Provider.
:param pulumi.Input[int] burst: Maximum burst for throttle. Default value is 10.
:param pulumi.Input[float] qps: Maximum queries per second (QPS) to the API server from this client. Default value is 5.
:param pulumi.Input[int] timeout: Maximum time in seconds to wait before cancelling a HTTP request to the Kubernetes server. Default value is 32.
"""
if burst is None:
burst = _utilities.get_env_int('PULUMI_K8S_CLIENT_BURST')
Expand All @@ -130,6 +132,10 @@ def __init__(__self__, *,
qps = _utilities.get_env_float('PULUMI_K8S_CLIENT_QPS')
if qps is not None:
pulumi.set(__self__, "qps", qps)
if timeout is None:
timeout = _utilities.get_env_int('PULUMI_K8S_CLIENT_TIMEOUT')
if timeout is not None:
pulumi.set(__self__, "timeout", timeout)

@property
@pulumi.getter
Expand All @@ -155,4 +161,16 @@ def qps(self) -> Optional[pulumi.Input[float]]:
def qps(self, value: Optional[pulumi.Input[float]]):
pulumi.set(self, "qps", value)

@property
@pulumi.getter
def timeout(self) -> Optional[pulumi.Input[int]]:
"""
Maximum time in seconds to wait before cancelling a HTTP request to the Kubernetes server. Default value is 32.
"""
return pulumi.get(self, "timeout")

@timeout.setter
def timeout(self, value: Optional[pulumi.Input[int]]):
pulumi.set(self, "timeout", value)


0 comments on commit ed50b5d

Please sign in to comment.