Skip to content

Commit 9ddc04d

Browse files
authored
Merge pull request kubernetes#5677 from hetznercloud/arm
Add support for Hetzner Cloud Arm Server Types
2 parents 76fc21e + 6e94d1a commit 9ddc04d

31 files changed

+466
-250
lines changed

cluster-autoscaler/cloudprovider/hetzner/hcloud-go/hcloud/action.go

Lines changed: 43 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -197,7 +197,24 @@ func (c *ActionClient) AllWithOpts(ctx context.Context, opts ActionListOpts) ([]
197197
return allActions, nil
198198
}
199199

200-
// WatchOverallProgress watches several actions' progress until they complete with success or error.
200+
// WatchOverallProgress watches several actions' progress until they complete
201+
// with success or error. This watching happens in a goroutine and updates are
202+
// provided through the two returned channels:
203+
//
204+
// - The first channel receives percentage updates of the progress, based on
205+
// the number of completed versus total watched actions. The return value
206+
// is an int between 0 and 100.
207+
// - The second channel returned receives errors for actions that did not
208+
// complete successfully, as well as any errors that happened while
209+
// querying the API.
210+
//
211+
// By default the method keeps watching until all actions have finished
212+
// processing. If you want to be able to cancel the method or configure a
213+
// timeout, use the [context.Context]. Once the method has stopped watching,
214+
// both returned channels are closed.
215+
//
216+
// WatchOverallProgress uses the [WithPollBackoffFunc] of the [Client] to wait
217+
// until sending the next request.
201218
func (c *ActionClient) WatchOverallProgress(ctx context.Context, actions []*Action) (<-chan int, <-chan error) {
202219
errCh := make(chan error, len(actions))
203220
progressCh := make(chan int)
@@ -212,15 +229,15 @@ func (c *ActionClient) WatchOverallProgress(ctx context.Context, actions []*Acti
212229
watchIDs[action.ID] = struct{}{}
213230
}
214231

215-
ticker := time.NewTicker(c.client.pollInterval)
216-
defer ticker.Stop()
232+
retries := 0
233+
217234
for {
218235
select {
219236
case <-ctx.Done():
220237
errCh <- ctx.Err()
221238
return
222-
case <-ticker.C:
223-
break
239+
case <-time.After(c.client.pollBackoffFunc(retries)):
240+
retries++
224241
}
225242

226243
opts := ActionListOpts{}
@@ -257,7 +274,24 @@ func (c *ActionClient) WatchOverallProgress(ctx context.Context, actions []*Acti
257274
return progressCh, errCh
258275
}
259276

260-
// WatchProgress watches one action's progress until it completes with success or error.
277+
// WatchProgress watches one action's progress until it completes with success
278+
// or error. This watching happens in a goroutine and updates are provided
279+
// through the two returned channels:
280+
//
281+
// - The first channel receives percentage updates of the progress, based on
282+
// the progress percentage indicated by the API. The return value is an int
283+
// between 0 and 100.
284+
// - The second channel receives any errors that happened while querying the
285+
// API, as well as the error of the action if it did not complete
286+
// successfully, or nil if it did.
287+
//
288+
// By default the method keeps watching until the action has finished
289+
// processing. If you want to be able to cancel the method or configure a
290+
// timeout, use the [context.Context]. Once the method has stopped watching,
291+
// both returned channels are closed.
292+
//
293+
// WatchProgress uses the [WithPollBackoffFunc] of the [Client] to wait until
294+
// sending the next request.
261295
func (c *ActionClient) WatchProgress(ctx context.Context, action *Action) (<-chan int, <-chan error) {
262296
errCh := make(chan error, 1)
263297
progressCh := make(chan int)
@@ -266,16 +300,15 @@ func (c *ActionClient) WatchProgress(ctx context.Context, action *Action) (<-cha
266300
defer close(errCh)
267301
defer close(progressCh)
268302

269-
ticker := time.NewTicker(c.client.pollInterval)
270-
defer ticker.Stop()
303+
retries := 0
271304

272305
for {
273306
select {
274307
case <-ctx.Done():
275308
errCh <- ctx.Err()
276309
return
277-
case <-ticker.C:
278-
break
310+
case <-time.After(c.client.pollBackoffFunc(retries)):
311+
retries++
279312
}
280313

281314
a, _, err := c.GetByID(ctx, action.ID)

cluster-autoscaler/cloudprovider/hetzner/hcloud-go/hcloud/internal/instrumentation/metrics_test.go renamed to cluster-autoscaler/cloudprovider/hetzner/hcloud-go/hcloud/architecture.go

Lines changed: 10 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -14,32 +14,15 @@ See the License for the specific language governing permissions and
1414
limitations under the License.
1515
*/
1616

17-
package instrumentation
17+
package hcloud
1818

19-
import "testing"
19+
// Architecture specifies the architecture of the CPU.
20+
type Architecture string
2021

21-
func Test_preparePath(t *testing.T) {
22-
tests := []struct {
23-
name string
24-
path string
25-
want string
26-
}{
27-
{
28-
"simple test",
29-
"/v1/volumes/123456",
30-
"/volumes/",
31-
},
32-
{
33-
"simple test",
34-
"/v1/volumes/123456/actions/attach",
35-
"/volumes/actions/attach",
36-
},
37-
}
38-
for _, tt := range tests {
39-
t.Run(tt.name, func(t *testing.T) {
40-
if got := preparePathForLabel(tt.path); got != tt.want {
41-
t.Errorf("preparePathForLabel() = %v, want %v", got, tt.want)
42-
}
43-
})
44-
}
45-
}
22+
const (
23+
// ArchitectureX86 is the architecture for Intel/AMD x86 CPUs.
24+
ArchitectureX86 Architecture = "x86"
25+
26+
// ArchitectureARM is the architecture for ARM CPUs.
27+
ArchitectureARM Architecture = "arm"
28+
)

cluster-autoscaler/cloudprovider/hetzner/hcloud-go/hcloud/certificate.go

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -47,10 +47,10 @@ const (
4747
CertificateStatusTypePending CertificateStatusType = "pending"
4848
CertificateStatusTypeFailed CertificateStatusType = "failed"
4949

50-
// only in issuance
50+
// only in issuance.
5151
CertificateStatusTypeCompleted CertificateStatusType = "completed"
5252

53-
// only in renewal
53+
// only in renewal.
5454
CertificateStatusTypeScheduled CertificateStatusType = "scheduled"
5555
CertificateStatusTypeUnavailable CertificateStatusType = "unavailable"
5656
)

cluster-autoscaler/cloudprovider/hetzner/hcloud-go/hcloud/client.go

Lines changed: 37 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,6 @@ import (
2323
"errors"
2424
"fmt"
2525
"io"
26-
"io/ioutil"
2726
"math"
2827
"net/http"
2928
"net/http/httputil"
@@ -34,6 +33,7 @@ import (
3433

3534
"github.com/prometheus/client_golang/prometheus"
3635
"golang.org/x/net/http/httpguts"
36+
3737
"k8s.io/autoscaler/cluster-autoscaler/cloudprovider/hetzner/hcloud-go/hcloud/internal/instrumentation"
3838
"k8s.io/autoscaler/cluster-autoscaler/cloudprovider/hetzner/hcloud-go/hcloud/schema"
3939
)
@@ -59,7 +59,10 @@ func ConstantBackoff(d time.Duration) BackoffFunc {
5959
}
6060

6161
// ExponentialBackoff returns a BackoffFunc which implements an exponential
62-
// backoff using the formula: b^retries * d
62+
// backoff.
63+
// It uses the formula:
64+
//
65+
// b^retries * d
6366
func ExponentialBackoff(b float64, d time.Duration) BackoffFunc {
6467
return func(retries int) time.Duration {
6568
return time.Duration(math.Pow(b, float64(retries))) * d
@@ -71,8 +74,8 @@ type Client struct {
7174
endpoint string
7275
token string
7376
tokenValid bool
74-
pollInterval time.Duration
7577
backoffFunc BackoffFunc
78+
pollBackoffFunc BackoffFunc
7679
httpClient *http.Client
7780
applicationName string
7881
applicationVersion string
@@ -119,15 +122,31 @@ func WithToken(token string) ClientOption {
119122
}
120123
}
121124

122-
// WithPollInterval configures a Client to use the specified interval when polling
123-
// from the API.
125+
// WithPollInterval configures a Client to use the specified interval when
126+
// polling from the API.
127+
//
128+
// Deprecated: Setting the poll interval is deprecated, you can now configure
129+
// [WithPollBackoffFunc] with a [ConstantBackoff] to get the same results. To
130+
// migrate your code, replace your usage like this:
131+
//
132+
// // before
133+
// hcloud.WithPollInterval(2 * time.Second)
134+
// // now
135+
// hcloud.WithPollBackoffFunc(hcloud.ConstantBackoff(2 * time.Second))
124136
func WithPollInterval(pollInterval time.Duration) ClientOption {
137+
return WithPollBackoffFunc(ConstantBackoff(pollInterval))
138+
}
139+
140+
// WithPollBackoffFunc configures a Client to use the specified backoff
141+
// function when polling from the API.
142+
func WithPollBackoffFunc(f BackoffFunc) ClientOption {
125143
return func(client *Client) {
126-
client.pollInterval = pollInterval
144+
client.backoffFunc = f
127145
}
128146
}
129147

130148
// WithBackoffFunc configures a Client to use the specified backoff function.
149+
// The backoff function is used for retrying HTTP requests.
131150
func WithBackoffFunc(f BackoffFunc) ClientOption {
132151
return func(client *Client) {
133152
client.backoffFunc = f
@@ -169,11 +188,11 @@ func WithInstrumentation(registry *prometheus.Registry) ClientOption {
169188
// NewClient creates a new client.
170189
func NewClient(options ...ClientOption) *Client {
171190
client := &Client{
172-
endpoint: Endpoint,
173-
tokenValid: true,
174-
httpClient: &http.Client{},
175-
backoffFunc: ExponentialBackoff(2, 500*time.Millisecond),
176-
pollInterval: 500 * time.Millisecond,
191+
endpoint: Endpoint,
192+
tokenValid: true,
193+
httpClient: &http.Client{},
194+
backoffFunc: ExponentialBackoff(2, 500*time.Millisecond),
195+
pollBackoffFunc: ConstantBackoff(500 * time.Millisecond),
177196
}
178197

179198
for _, option := range options {
@@ -238,7 +257,7 @@ func (c *Client) Do(r *http.Request, v interface{}) (*Response, error) {
238257
var body []byte
239258
var err error
240259
if r.ContentLength > 0 {
241-
body, err = ioutil.ReadAll(r.Body)
260+
body, err = io.ReadAll(r.Body)
242261
if err != nil {
243262
r.Body.Close()
244263
return nil, err
@@ -247,7 +266,7 @@ func (c *Client) Do(r *http.Request, v interface{}) (*Response, error) {
247266
}
248267
for {
249268
if r.ContentLength > 0 {
250-
r.Body = ioutil.NopCloser(bytes.NewReader(body))
269+
r.Body = io.NopCloser(bytes.NewReader(body))
251270
}
252271

253272
if c.debugWriter != nil {
@@ -263,13 +282,13 @@ func (c *Client) Do(r *http.Request, v interface{}) (*Response, error) {
263282
return nil, err
264283
}
265284
response := &Response{Response: resp}
266-
body, err := ioutil.ReadAll(resp.Body)
285+
body, err := io.ReadAll(resp.Body)
267286
if err != nil {
268287
resp.Body.Close()
269288
return response, err
270289
}
271290
resp.Body.Close()
272-
resp.Body = ioutil.NopCloser(bytes.NewReader(body))
291+
resp.Body = io.NopCloser(bytes.NewReader(body))
273292

274293
if c.debugWriter != nil {
275294
dumpResp, err := httputil.DumpResponse(resp, true)
@@ -287,7 +306,7 @@ func (c *Client) Do(r *http.Request, v interface{}) (*Response, error) {
287306
err = errorFromResponse(resp, body)
288307
if err == nil {
289308
err = fmt.Errorf("hcloud: server responded with status code %d", resp.StatusCode)
290-
} else if isRetryable(err) {
309+
} else if isConflict(err) {
291310
c.backoff(retries)
292311
retries++
293312
continue
@@ -306,12 +325,12 @@ func (c *Client) Do(r *http.Request, v interface{}) (*Response, error) {
306325
}
307326
}
308327

309-
func isRetryable(error error) bool {
328+
func isConflict(error error) bool {
310329
err, ok := error.(Error)
311330
if !ok {
312331
return false
313332
}
314-
return err.Code == ErrorCodeRateLimitExceeded || err.Code == ErrorCodeConflict
333+
return err.Code == ErrorCodeConflict
315334
}
316335

317336
func (c *Client) backoff(retries int) {

cluster-autoscaler/cloudprovider/hetzner/hcloud-go/hcloud/error.go

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -44,14 +44,14 @@ const (
4444
ErrorCodeResourceLocked ErrorCode = "resource_locked" // The resource is locked. The caller should contact support
4545
ErrorUnsupportedError ErrorCode = "unsupported_error" // The given resource does not support this
4646

47-
// Server related error codes
47+
// Server related error codes.
4848
ErrorCodeInvalidServerType ErrorCode = "invalid_server_type" // The server type does not fit for the given server or is deprecated
4949
ErrorCodeServerNotStopped ErrorCode = "server_not_stopped" // The action requires a stopped server
5050
ErrorCodeNetworksOverlap ErrorCode = "networks_overlap" // The network IP range overlaps with one of the server networks
5151
ErrorCodePlacementError ErrorCode = "placement_error" // An error during the placement occurred
5252
ErrorCodeServerAlreadyAttached ErrorCode = "server_already_attached" // The server is already attached to the resource
5353

54-
// Load Balancer related error codes
54+
// Load Balancer related error codes.
5555
ErrorCodeIPNotOwned ErrorCode = "ip_not_owned" // The IP you are trying to add as a target is not owned by the Project owner
5656
ErrorCodeSourcePortAlreadyUsed ErrorCode = "source_port_already_used" // The source port you are trying to add is already in use
5757
ErrorCodeCloudResourceIPNotAllowed ErrorCode = "cloud_resource_ip_not_allowed" // The IP you are trying to add as a target belongs to a Hetzner Cloud resource
@@ -62,24 +62,24 @@ const (
6262
ErrorCodeTargetsWithoutUsePrivateIP ErrorCode = "targets_without_use_private_ip" // The Load Balancer has targets that use the public IP instead of the private IP
6363
ErrorCodeLoadBalancerNotAttachedToNetwork ErrorCode = "load_balancer_not_attached_to_network" // The Load Balancer is not attached to a network
6464

65-
// Network related error codes
65+
// Network related error codes.
6666
ErrorCodeIPNotAvailable ErrorCode = "ip_not_available" // The provided Network IP is not available
6767
ErrorCodeNoSubnetAvailable ErrorCode = "no_subnet_available" // No Subnet or IP is available for the Load Balancer/Server within the network
6868
ErrorCodeVSwitchAlreadyUsed ErrorCode = "vswitch_id_already_used" // The given Robot vSwitch ID is already registered in another network
6969

70-
// Volume related error codes
70+
// Volume related error codes.
7171
ErrorCodeNoSpaceLeftInLocation ErrorCode = "no_space_left_in_location" // There is no volume space left in the given location
7272
ErrorCodeVolumeAlreadyAttached ErrorCode = "volume_already_attached" // Volume is already attached to a server, detach first
7373

74-
// Firewall related error codes
74+
// Firewall related error codes.
7575
ErrorCodeFirewallAlreadyApplied ErrorCode = "firewall_already_applied" // Firewall was already applied on resource
7676
ErrorCodeFirewallAlreadyRemoved ErrorCode = "firewall_already_removed" // Firewall was already removed from the resource
7777
ErrorCodeIncompatibleNetworkType ErrorCode = "incompatible_network_type" // The Network type is incompatible for the given resource
7878
ErrorCodeResourceInUse ErrorCode = "resource_in_use" // Firewall must not be in use to be deleted
7979
ErrorCodeServerAlreadyAdded ErrorCode = "server_already_added" // Server added more than one time to resource
8080
ErrorCodeFirewallResourceNotFound ErrorCode = "firewall_resource_not_found" // Resource a firewall should be attached to / detached from not found
8181

82-
// Certificate related error codes
82+
// Certificate related error codes.
8383
ErrorCodeCAARecordDoesNotAllowCA ErrorCode = "caa_record_does_not_allow_ca" // CAA record does not allow certificate authority
8484
ErrorCodeCADNSValidationFailed ErrorCode = "ca_dns_validation_failed" // Certificate Authority: DNS validation failed
8585
ErrorCodeCATooManyAuthorizationsFailedRecently ErrorCode = "ca_too_many_authorizations_failed_recently" // Certificate Authority: Too many authorizations failed recently

cluster-autoscaler/cloudprovider/hetzner/hcloud-go/hcloud/floating_ip.go

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -48,7 +48,7 @@ type FloatingIP struct {
4848
}
4949

5050
// DNSPtrForIP returns the reverse DNS pointer of the IP address.
51-
// Deprecated: Use GetDNSPtrForIP instead
51+
// Deprecated: Use GetDNSPtrForIP instead.
5252
func (f *FloatingIP) DNSPtrForIP(ip net.IP) string {
5353
return f.DNSPtr[ip.String()]
5454
}
@@ -257,10 +257,10 @@ func (c *FloatingIPClient) Create(ctx context.Context, opts FloatingIPCreateOpts
257257
Name: opts.Name,
258258
}
259259
if opts.HomeLocation != nil {
260-
reqBody.HomeLocation = String(opts.HomeLocation.Name)
260+
reqBody.HomeLocation = Ptr(opts.HomeLocation.Name)
261261
}
262262
if opts.Server != nil {
263-
reqBody.Server = Int(opts.Server.ID)
263+
reqBody.Server = Ptr(opts.Server.ID)
264264
}
265265
if opts.Labels != nil {
266266
reqBody.Labels = &opts.Labels

cluster-autoscaler/cloudprovider/hetzner/hcloud-go/hcloud/hcloud.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -18,4 +18,4 @@ limitations under the License.
1818
package hcloud
1919

2020
// Version is the library's version following Semantic Versioning.
21-
const Version = "1.35.0"
21+
const Version = "1.42.0" // x-release-please-version

0 commit comments

Comments
 (0)