Skip to content

Commit

Permalink
Merge pull request kubernetes#5001 from glehmann/hetzner-primary-ip
Browse files Browse the repository at this point in the history
Hetzner public IPv4 and IPv6 configuration
  • Loading branch information
k8s-ci-robot authored Aug 9, 2022
2 parents 1485808 + c77ef8a commit 1a49826
Show file tree
Hide file tree
Showing 28 changed files with 728 additions and 16 deletions.
4 changes: 4 additions & 0 deletions cluster-autoscaler/cloudprovider/hetzner/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,10 @@ The cluster autoscaler for Hetzner Cloud scales worker nodes.

`HCLOUD_SSH_KEY` Default empty , This SSH Key will have access to the fresh created server, @see https://docs.hetzner.cloud/#ssh-keys

`HCLOUD_PUBLIC_IPV4` Default true , Whether the server is created with a public IPv4 address or not, @see https://docs.hetzner.cloud/#primary-ips

`HCLOUD_PUBLIC_IPV6` Default true , Whether the server is created with a public IPv6 address or not, @see https://docs.hetzner.cloud/#primary-ips

Node groups must be defined with the `--nodes=<min-servers>:<max-servers>:<instance-type>:<region>:<name>` flag.

Multiple flags will create multiple node pools. For example:
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -154,13 +154,17 @@ func (c *CertificateClient) Get(ctx context.Context, idOrName string) (*Certific
type CertificateListOpts struct {
ListOpts
Name string
Sort []string
}

func (l CertificateListOpts) values() url.Values {
vals := l.ListOpts.values()
if l.Name != "" {
vals.Add("name", l.Name)
}
for _, sort := range l.Sort {
vals.Add("sort", sort)
}
return vals
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ import (
"bytes"
"context"
"encoding/json"
"errors"
"fmt"
"io"
"io/ioutil"
Expand All @@ -31,10 +32,9 @@ import (
"strings"
"time"

"k8s.io/autoscaler/cluster-autoscaler/cloudprovider/hetzner/hcloud-go/hcloud/internal/instrumentation"

"github.com/prometheus/client_golang/prometheus"

"golang.org/x/net/http/httpguts"
"k8s.io/autoscaler/cluster-autoscaler/cloudprovider/hetzner/hcloud-go/hcloud/internal/instrumentation"
"k8s.io/autoscaler/cluster-autoscaler/cloudprovider/hetzner/hcloud-go/hcloud/schema"
)

Expand Down Expand Up @@ -70,6 +70,7 @@ func ExponentialBackoff(b float64, d time.Duration) BackoffFunc {
type Client struct {
endpoint string
token string
tokenValid bool
pollInterval time.Duration
backoffFunc BackoffFunc
httpClient *http.Client
Expand Down Expand Up @@ -97,6 +98,7 @@ type Client struct {
Volume VolumeClient
PlacementGroup PlacementGroupClient
RDNS RDNSClient
PrimaryIP PrimaryIPClient
}

// A ClientOption is used to configure a Client.
Expand All @@ -113,6 +115,7 @@ func WithEndpoint(endpoint string) ClientOption {
func WithToken(token string) ClientOption {
return func(client *Client) {
client.token = token
client.tokenValid = httpguts.ValidHeaderFieldValue(token)
}
}

Expand Down Expand Up @@ -167,6 +170,7 @@ func WithInstrumentation(registry *prometheus.Registry) ClientOption {
func NewClient(options ...ClientOption) *Client {
client := &Client{
endpoint: Endpoint,
tokenValid: true,
httpClient: &http.Client{},
backoffFunc: ExponentialBackoff(2, 500*time.Millisecond),
pollInterval: 500 * time.Millisecond,
Expand Down Expand Up @@ -200,6 +204,7 @@ func NewClient(options ...ClientOption) *Client {
client.Firewall = FirewallClient{client: client}
client.PlacementGroup = PlacementGroupClient{client: client}
client.RDNS = RDNSClient{client: client}
client.PrimaryIP = PrimaryIPClient{client: client}

return client
}
Expand All @@ -213,9 +218,13 @@ func (c *Client) NewRequest(ctx context.Context, method, path string, body io.Re
return nil, err
}
req.Header.Set("User-Agent", c.userAgent)
if c.token != "" {

if !c.tokenValid {
return nil, errors.New("Authorization token contains invalid characters")
} else if c.token != "" {
req.Header.Set("Authorization", fmt.Sprintf("Bearer %s", c.token))
}

if body != nil {
req.Header.Set("Content-Type", "application/json")
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -88,13 +88,17 @@ func (c *DatacenterClient) Get(ctx context.Context, idOrName string) (*Datacente
type DatacenterListOpts struct {
ListOpts
Name string
Sort []string
}

func (l DatacenterListOpts) values() url.Values {
vals := l.ListOpts.values()
if l.Name != "" {
vals.Add("name", l.Name)
}
for _, sort := range l.Sort {
vals.Add("sort", sort)
}
return vals
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -41,7 +41,8 @@ const (
ErrorCodeMaintenance ErrorCode = "maintenance" // Cannot perform operation due to maintenance
ErrorCodeConflict ErrorCode = "conflict" // The resource has changed during the request, please retry
ErrorCodeRobotUnavailable ErrorCode = "robot_unavailable" // Robot was not available. The caller may retry the operation after a short delay
ErrorUnsupportedError ErrorCode = "unsupported_error" // The gives resource does not support this
ErrorCodeResourceLocked ErrorCode = "resource_locked" // The resource is locked. The caller should contact support
ErrorUnsupportedError ErrorCode = "unsupported_error" // The given resource does not support this

// Server related error codes
ErrorCodeInvalidServerType ErrorCode = "invalid_server_type" // The server type does not fit for the given server or is deprecated
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -152,13 +152,17 @@ func (c *FirewallClient) Get(ctx context.Context, idOrName string) (*Firewall, *
type FirewallListOpts struct {
ListOpts
Name string
Sort []string
}

func (l FirewallListOpts) values() url.Values {
vals := l.ListOpts.values()
if l.Name != "" {
vals.Add("name", l.Name)
}
for _, sort := range l.Sort {
vals.Add("sort", sort)
}
return vals
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -153,13 +153,17 @@ func (c *FloatingIPClient) Get(ctx context.Context, idOrName string) (*FloatingI
type FloatingIPListOpts struct {
ListOpts
Name string
Sort []string
}

func (l FloatingIPListOpts) values() url.Values {
vals := l.ListOpts.values()
if l.Name != "" {
vals.Add("name", l.Name)
}
for _, sort := range l.Sort {
vals.Add("sort", sort)
}
return vals
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -18,4 +18,4 @@ limitations under the License.
package hcloud

// Version is the library's version following Semantic Versioning.
const Version = "1.32.0"
const Version = "1.35.0"
Original file line number Diff line number Diff line change
Expand Up @@ -98,13 +98,17 @@ func (c *ISOClient) Get(ctx context.Context, idOrName string) (*ISO, *Response,
type ISOListOpts struct {
ListOpts
Name string
Sort []string
}

func (l ISOListOpts) values() url.Values {
vals := l.ListOpts.values()
if l.Name != "" {
vals.Add("name", l.Name)
}
for _, sort := range l.Sort {
vals.Add("sort", sort)
}
return vals
}

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
package hcloud

import (
"fmt"
"regexp"
)

var keyRegexp = regexp.MustCompile(
`^([a-z0-9A-Z]((?:[\-_.]|[a-z0-9A-Z]){0,253}[a-z0-9A-Z])?/)?[a-z0-9A-Z]((?:[\-_.]|[a-z0-9A-Z]|){0,62}[a-z0-9A-Z])?$`)
var valueRegexp = regexp.MustCompile(`^([a-z0-9A-Z](?:[\-_.]|[a-z0-9A-Z]){0,62})?[a-z0-9A-Z]$`)

func ValidateResourceLabels(labels map[string]interface{}) (bool, error) {
for k, v := range labels {
if match := keyRegexp.MatchString(k); !match {
return false, fmt.Errorf("label key '%s' is not correctly formatted", k)
}

if match := valueRegexp.MatchString(v.(string)); !match {
return false, fmt.Errorf("label value '%s' (key: %s) is not correctly formatted", v, k)
}
}
return true, nil
}
Original file line number Diff line number Diff line change
Expand Up @@ -299,13 +299,17 @@ func (c *LoadBalancerClient) Get(ctx context.Context, idOrName string) (*LoadBal
type LoadBalancerListOpts struct {
ListOpts
Name string
Sort []string
}

func (l LoadBalancerListOpts) values() url.Values {
vals := l.ListOpts.values()
if l.Name != "" {
vals.Add("name", l.Name)
}
for _, sort := range l.Sort {
vals.Add("sort", sort)
}
return vals
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -85,13 +85,17 @@ func (c *LoadBalancerTypeClient) Get(ctx context.Context, idOrName string) (*Loa
type LoadBalancerTypeListOpts struct {
ListOpts
Name string
Sort []string
}

func (l LoadBalancerTypeListOpts) values() url.Values {
vals := l.ListOpts.values()
if l.Name != "" {
vals.Add("name", l.Name)
}
for _, sort := range l.Sort {
vals.Add("sort", sort)
}
return vals
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -85,13 +85,17 @@ func (c *LocationClient) Get(ctx context.Context, idOrName string) (*Location, *
type LocationListOpts struct {
ListOpts
Name string
Sort []string
}

func (l LocationListOpts) values() url.Values {
vals := l.ListOpts.values()
if l.Name != "" {
vals.Add("name", l.Name)
}
for _, sort := range l.Sort {
vals.Add("sort", sort)
}
return vals
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ limitations under the License.
package metadata

import (
"fmt"
"io/ioutil"
"net"
"net/http"
Expand Down Expand Up @@ -88,12 +89,16 @@ func (c *Client) get(path string) (string, error) {
if err != nil {
return "", err
}
body, err := ioutil.ReadAll(resp.Body)
defer resp.Body.Close()
bodyBytes, err := ioutil.ReadAll(resp.Body)
if err != nil {
return "", err
}
resp.Body.Close()
return string(body), nil
body := string(bodyBytes)
if resp.StatusCode < 200 || resp.StatusCode >= 300 {
return body, fmt.Errorf("response status was %d", resp.StatusCode)
}
return body, nil
}

// IsHcloudServer checks if the currently called server is a hcloud server by calling a metadata endpoint
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -130,13 +130,17 @@ func (c *NetworkClient) Get(ctx context.Context, idOrName string) (*Network, *Re
type NetworkListOpts struct {
ListOpts
Name string
Sort []string
}

func (l NetworkListOpts) values() url.Values {
vals := l.ListOpts.values()
if l.Name != "" {
vals.Add("name", l.Name)
}
for _, sort := range l.Sort {
vals.Add("sort", sort)
}
return vals
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -96,6 +96,7 @@ type PlacementGroupListOpts struct {
ListOpts
Name string
Type PlacementGroupType
Sort []string
}

func (l PlacementGroupListOpts) values() url.Values {
Expand All @@ -106,6 +107,9 @@ func (l PlacementGroupListOpts) values() url.Values {
if l.Type != "" {
vals.Add("type", string(l.Type))
}
for _, sort := range l.Sort {
vals.Add("sort", sort)
}
return vals
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@ type Pricing struct {
Image ImagePricing
FloatingIP FloatingIPPricing
FloatingIPs []FloatingIPTypePricing
PrimaryIPs []PrimaryIPPricing
Traffic TrafficPricing
ServerBackup ServerBackupPricing
ServerTypes []ServerTypePricing
Expand All @@ -44,6 +45,14 @@ type Price struct {
Gross string
}

// PrimaryIPPrice represents a price. Net amount and gross amount are
// specified as strings and it is the user's responsibility to convert them to
// appropriate types for calculations.
type PrimaryIPPrice struct {
Net string
Gross string
}

// ImagePricing provides pricing information for imaegs.
type ImagePricing struct {
PerGBMonth Price
Expand All @@ -60,6 +69,20 @@ type FloatingIPTypePricing struct {
Pricings []FloatingIPTypeLocationPricing
}

// PrimaryIPTypePricing defines the schema of pricing information for a primary IP
// type at a datacenter.
type PrimaryIPTypePricing struct {
Datacenter string
Hourly PrimaryIPPrice
Monthly PrimaryIPPrice
}

// PrimaryIPTypePricing provides pricing information for PrimaryIPs
type PrimaryIPPricing struct {
Type string
Pricings []PrimaryIPTypePricing
}

// FloatingIPTypeLocationPricing provides pricing information for a Floating IP type
// at a location.
type FloatingIPTypeLocationPricing struct {
Expand Down
Loading

0 comments on commit 1a49826

Please sign in to comment.