Skip to content

Commit 2ce275d

Browse files
authored
fix: add client-side timeouts to hcloud and robot clients (#1058)
1 parent 1aa4980 commit 2ce275d

2 files changed

Lines changed: 23 additions & 39 deletions

File tree

hcloud/cloud.go

Lines changed: 17 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -19,8 +19,10 @@ package hcloud
1919
import (
2020
"context"
2121
"fmt"
22+
"net/http"
2223
"os"
2324
"strings"
25+
"time"
2426

2527
hrobot "github.com/syself/hrobot-go"
2628
corev1 "k8s.io/api/core/v1"
@@ -39,7 +41,8 @@ import (
3941
)
4042

4143
const (
42-
providerName = "hcloud"
44+
providerName = "hcloud"
45+
apiClientTimeout = 15 * time.Second
4346
)
4447

4548
// providerVersion is set by the build process using -ldflags -X.
@@ -70,6 +73,11 @@ func NewCloud(cidr string) (cloudprovider.Interface, error) {
7073
opts := []hcloud.ClientOption{
7174
hcloud.WithToken(cfg.HCloudClient.Token),
7275
hcloud.WithApplication("hcloud-cloud-controller", providerVersion),
76+
hcloud.WithHTTPClient(
77+
&http.Client{
78+
Timeout: apiClientTimeout,
79+
},
80+
),
7381
}
7482

7583
// start metrics server if enabled (enabled by default)
@@ -89,7 +97,13 @@ func NewCloud(cidr string) (cloudprovider.Interface, error) {
8997

9098
var robotClient robot.Client
9199
if cfg.Robot.Enabled {
92-
c := hrobot.NewBasicAuthClient(cfg.Robot.User, cfg.Robot.Password)
100+
c := hrobot.NewBasicAuthClientWithCustomHttpClient(
101+
cfg.Robot.User,
102+
cfg.Robot.Password,
103+
&http.Client{
104+
Timeout: apiClientTimeout,
105+
},
106+
)
93107

94108
robotClient = robot.NewRateLimitedClient(
95109
cfg.Robot.RateLimitWaitTime,
@@ -120,7 +134,7 @@ func NewCloud(cidr string) (cloudprovider.Interface, error) {
120134
}
121135

122136
// Validate that the provided token works, and we have network connectivity to the Hetzner Cloud API
123-
_, _, err = client.Server.List(context.Background(), hcloud.ServerListOpts{})
137+
_, _, err = client.Location.List(context.Background(), hcloud.LocationListOpts{})
124138
if err != nil {
125139
return nil, fmt.Errorf("%s: %w", op, err)
126140
}

hcloud/cloud_test.go

Lines changed: 6 additions & 36 deletions
Original file line numberDiff line numberDiff line change
@@ -91,12 +91,8 @@ func TestNewCloud(t *testing.T) {
9191
"HCLOUD_METRICS_ENABLED", "false",
9292
)
9393
defer resetEnv()
94-
env.Mux.HandleFunc("/servers", func(w http.ResponseWriter, _ *http.Request) {
95-
json.NewEncoder(w).Encode(
96-
schema.ServerListResponse{
97-
Servers: []schema.Server{},
98-
},
99-
)
94+
env.Mux.HandleFunc("/locations", func(w http.ResponseWriter, _ *http.Request) {
95+
json.NewEncoder(w).Encode(schema.LocationListResponse{Locations: []schema.Location{}})
10096
})
10197

10298
_, err := NewCloud(DefaultClusterCIDR)
@@ -113,7 +109,7 @@ func TestNewCloudConnectionNotPossible(t *testing.T) {
113109

114110
_, err := NewCloud(DefaultClusterCIDR)
115111
assert.EqualError(t, err,
116-
`hcloud/newCloud: Get "http://127.0.0.1:4711/v1/servers?": dial tcp 127.0.0.1:4711: connect: connection refused`)
112+
`hcloud/newCloud: Get "http://127.0.0.1:4711/v1/locations?": dial tcp 127.0.0.1:4711: connect: connection refused`)
117113
}
118114

119115
func TestNewCloudInvalidToken(t *testing.T) {
@@ -126,7 +122,7 @@ func TestNewCloudInvalidToken(t *testing.T) {
126122
"HCLOUD_METRICS_ENABLED", "false",
127123
)
128124
defer resetEnv()
129-
env.Mux.HandleFunc("/servers", func(w http.ResponseWriter, _ *http.Request) {
125+
env.Mux.HandleFunc("/locations", func(w http.ResponseWriter, _ *http.Request) {
130126
w.Header().Set("Content-Type", "application/json")
131127
w.WriteHeader(http.StatusUnauthorized)
132128
json.NewEncoder(w).Encode(
@@ -155,34 +151,8 @@ func TestCloud(t *testing.T) {
155151
"ROBOT_PASSWORD", "pass123",
156152
)
157153
defer resetEnv()
158-
env.Mux.HandleFunc("/servers", func(w http.ResponseWriter, _ *http.Request) {
159-
json.NewEncoder(w).Encode(
160-
schema.ServerListResponse{
161-
Servers: []schema.Server{
162-
{
163-
ID: 1,
164-
Name: "test",
165-
Status: "running",
166-
Created: time.Time{},
167-
PublicNet: schema.ServerPublicNet{},
168-
PrivateNet: nil,
169-
ServerType: schema.ServerType{},
170-
IncludedTraffic: 0,
171-
OutgoingTraffic: nil,
172-
IngoingTraffic: nil,
173-
BackupWindow: nil,
174-
RescueEnabled: false,
175-
ISO: nil,
176-
Locked: false,
177-
Datacenter: schema.Datacenter{},
178-
Image: nil,
179-
Protection: schema.ServerProtection{},
180-
Labels: nil,
181-
Volumes: nil,
182-
},
183-
},
184-
},
185-
)
154+
env.Mux.HandleFunc("/locations", func(w http.ResponseWriter, _ *http.Request) {
155+
json.NewEncoder(w).Encode(schema.LocationListResponse{Locations: []schema.Location{}})
186156
})
187157
env.Mux.HandleFunc("/networks/1", func(w http.ResponseWriter, _ *http.Request) {
188158
json.NewEncoder(w).Encode(

0 commit comments

Comments
 (0)