From 40d259cbd8b173134a6098adc293b61e3448c20d Mon Sep 17 00:00:00 2001 From: Sergey Shevchenko Date: Thu, 8 Jul 2021 22:03:13 +0300 Subject: [PATCH 1/4] [ca]: Upgrade hcloud-go to 1.28.0 Signed-off-by: Sergey Shevchenko --- .../hetzner/hcloud-go/hcloud/action.go | 125 ++++-- .../hetzner/hcloud-go/hcloud/certificate.go | 179 ++++++-- .../hetzner/hcloud-go/hcloud/client.go | 58 +-- .../hetzner/hcloud-go/hcloud/datacenter.go | 20 +- .../hetzner/hcloud-go/hcloud/error.go | 61 ++- .../hetzner/hcloud-go/hcloud/firewall.go | 383 ++++++++++++++++++ .../hetzner/hcloud-go/hcloud/floating_ip.go | 20 +- .../hetzner/hcloud-go/hcloud/hcloud.go | 18 +- .../hetzner/hcloud-go/hcloud/helper.go | 16 - .../hetzner/hcloud-go/hcloud/image.go | 28 +- .../hetzner/hcloud-go/hcloud/iso.go | 20 +- .../hetzner/hcloud-go/hcloud/load_balancer.go | 115 +++++- .../hcloud-go/hcloud/load_balancer_type.go | 20 +- .../hetzner/hcloud-go/hcloud/location.go | 20 +- .../hetzner/hcloud-go/hcloud/network.go | 37 +- .../hetzner/hcloud-go/hcloud/pricing.go | 24 +- .../hetzner/hcloud-go/hcloud/resource.go | 7 + .../hetzner/hcloud-go/hcloud/schema.go | 286 +++++++++++-- .../hetzner/hcloud-go/hcloud/schema/action.go | 16 - .../hcloud-go/hcloud/schema/certificate.go | 62 +-- .../hcloud-go/hcloud/schema/datacenter.go | 16 - .../hetzner/hcloud-go/hcloud/schema/error.go | 19 +- .../hcloud-go/hcloud/schema/firewall.go | 104 +++++ .../hcloud-go/hcloud/schema/floating_ip.go | 16 - .../hetzner/hcloud-go/hcloud/schema/image.go | 17 +- .../hetzner/hcloud-go/hcloud/schema/iso.go | 16 - .../hcloud-go/hcloud/schema/load_balancer.go | 33 +- .../hcloud/schema/load_balancer_type.go | 16 - .../hcloud-go/hcloud/schema/location.go | 16 - .../hetzner/hcloud-go/hcloud/schema/meta.go | 16 - .../hcloud-go/hcloud/schema/network.go | 20 +- .../hcloud-go/hcloud/schema/pricing.go | 22 +- .../hetzner/hcloud-go/hcloud/schema/server.go | 70 ++-- .../hcloud-go/hcloud/schema/server_type.go | 16 - .../hcloud-go/hcloud/schema/ssh_key.go | 16 - .../hetzner/hcloud-go/hcloud/schema/volume.go | 16 - .../hetzner/hcloud-go/hcloud/server.go | 144 ++++++- .../hetzner/hcloud-go/hcloud/server_type.go | 22 +- .../hetzner/hcloud-go/hcloud/ssh_key.go | 20 +- .../hetzner/hcloud-go/hcloud/testing.go | 18 + .../hetzner/hcloud-go/hcloud/volume.go | 20 +- 41 files changed, 1466 insertions(+), 702 deletions(-) create mode 100644 cluster-autoscaler/cloudprovider/hetzner/hcloud-go/hcloud/firewall.go create mode 100644 cluster-autoscaler/cloudprovider/hetzner/hcloud-go/hcloud/resource.go create mode 100644 cluster-autoscaler/cloudprovider/hetzner/hcloud-go/hcloud/schema/firewall.go create mode 100644 cluster-autoscaler/cloudprovider/hetzner/hcloud-go/hcloud/testing.go diff --git a/cluster-autoscaler/cloudprovider/hetzner/hcloud-go/hcloud/action.go b/cluster-autoscaler/cloudprovider/hetzner/hcloud-go/hcloud/action.go index 79a7e1f846e8..622f7bf44b97 100644 --- a/cluster-autoscaler/cloudprovider/hetzner/hcloud-go/hcloud/action.go +++ b/cluster-autoscaler/cloudprovider/hetzner/hcloud-go/hcloud/action.go @@ -1,19 +1,3 @@ -/* -Copyright 2018 The Kubernetes Authors. - -Licensed under the Apache License, Version 2.0 (the "License"); -you may not use this file except in compliance with the License. -You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - -Unless required by applicable law or agreed to in writing, software -distributed under the License is distributed on an "AS IS" BASIS, -WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -See the License for the specific language governing permissions and -limitations under the License. -*/ - package hcloud import ( @@ -22,7 +6,7 @@ import ( "net/url" "time" - "k8s.io/autoscaler/cluster-autoscaler/cloudprovider/hetzner/hcloud-go/hcloud/schema" + "github.com/hetznercloud/hcloud-go/hcloud/schema" ) // Action represents an action in the Hetzner Cloud. @@ -112,12 +96,16 @@ func (c *ActionClient) GetByID(ctx context.Context, id int) (*Action, *Response, // ActionListOpts specifies options for listing actions. type ActionListOpts struct { ListOpts + ID []int Status []ActionStatus Sort []string } func (l ActionListOpts) values() url.Values { vals := l.ListOpts.values() + for _, id := range l.ID { + vals.Add("id", fmt.Sprintf("%d", id)) + } for _, status := range l.Status { vals.Add("status", string(status)) } @@ -157,7 +145,7 @@ func (c *ActionClient) All(ctx context.Context) ([]*Action, error) { opts := ActionListOpts{} opts.PerPage = 50 - _, err := c.client.all(func(page int) (*Response, error) { + err := c.client.all(func(page int) (*Response, error) { opts.Page = page actions, resp, err := c.List(ctx, opts) if err != nil { @@ -173,24 +161,97 @@ func (c *ActionClient) All(ctx context.Context) ([]*Action, error) { return allActions, nil } -// WatchProgress watches the action's progress until it completes with success or error. -func (c *ActionClient) WatchProgress(ctx context.Context, action *Action) (<-chan int, <-chan error) { - errCh := make(chan error, 1) +// AllWithOpts returns all actions for the given options. +func (c *ActionClient) AllWithOpts(ctx context.Context, opts ActionListOpts) ([]*Action, error) { + allActions := []*Action{} + + err := c.client.all(func(page int) (*Response, error) { + opts.Page = page + actions, resp, err := c.List(ctx, opts) + if err != nil { + return resp, err + } + allActions = append(allActions, actions...) + return resp, nil + }) + if err != nil { + return nil, err + } + + return allActions, nil +} + +// WatchOverallProgress watches several actions' progress until they complete with success or error. +func (c *ActionClient) WatchOverallProgress(ctx context.Context, actions []*Action) (<-chan int, <-chan error) { + errCh := make(chan error, len(actions)) progressCh := make(chan int) go func() { defer close(errCh) defer close(progressCh) + successIDs := make([]int, 0, len(actions)) + watchIDs := make(map[int]struct{}, len(actions)) + for _, action := range actions { + watchIDs[action.ID] = struct{}{} + } + ticker := time.NewTicker(c.client.pollInterval) - sendProgress := func(p int) { + defer ticker.Stop() + for { select { - case progressCh <- p: - break - default: + case <-ctx.Done(): + errCh <- ctx.Err() + return + case <-ticker.C: break } + + opts := ActionListOpts{} + for watchID := range watchIDs { + opts.ID = append(opts.ID, watchID) + } + + as, err := c.AllWithOpts(ctx, opts) + if err != nil { + errCh <- err + return + } + + for _, a := range as { + switch a.Status { + case ActionStatusRunning: + continue + case ActionStatusSuccess: + delete(watchIDs, a.ID) + successIDs := append(successIDs, a.ID) + sendProgress(progressCh, int(float64(len(actions)-len(successIDs))/float64(len(actions))*100)) + case ActionStatusError: + delete(watchIDs, a.ID) + errCh <- fmt.Errorf("action %d failed: %w", a.ID, a.Error()) + } + } + + if len(watchIDs) == 0 { + return + } } + }() + + return progressCh, errCh +} + +// WatchProgress watches one action's progress until it completes with success or error. +func (c *ActionClient) WatchProgress(ctx context.Context, action *Action) (<-chan int, <-chan error) { + errCh := make(chan error, 1) + progressCh := make(chan int) + + go func() { + defer close(errCh) + defer close(progressCh) + + ticker := time.NewTicker(c.client.pollInterval) + defer ticker.Stop() for { select { @@ -209,10 +270,9 @@ func (c *ActionClient) WatchProgress(ctx context.Context, action *Action) (<-cha switch a.Status { case ActionStatusRunning: - sendProgress(a.Progress) - break + sendProgress(progressCh, a.Progress) case ActionStatusSuccess: - sendProgress(100) + sendProgress(progressCh, 100) errCh <- nil return case ActionStatusError: @@ -224,3 +284,12 @@ func (c *ActionClient) WatchProgress(ctx context.Context, action *Action) (<-cha return progressCh, errCh } + +func sendProgress(progressCh chan int, p int) { + select { + case progressCh <- p: + break + default: + break + } +} diff --git a/cluster-autoscaler/cloudprovider/hetzner/hcloud-go/hcloud/certificate.go b/cluster-autoscaler/cloudprovider/hetzner/hcloud-go/hcloud/certificate.go index 990e698a3716..771a67e8b711 100644 --- a/cluster-autoscaler/cloudprovider/hetzner/hcloud-go/hcloud/certificate.go +++ b/cluster-autoscaler/cloudprovider/hetzner/hcloud-go/hcloud/certificate.go @@ -1,19 +1,3 @@ -/* -Copyright 2018 The Kubernetes Authors. - -Licensed under the Apache License, Version 2.0 (the "License"); -you may not use this file except in compliance with the License. -You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - -Unless required by applicable law or agreed to in writing, software -distributed under the License is distributed on an "AS IS" BASIS, -WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -See the License for the specific language governing permissions and -limitations under the License. -*/ - package hcloud import ( @@ -26,20 +10,84 @@ import ( "strconv" "time" - "k8s.io/autoscaler/cluster-autoscaler/cloudprovider/hetzner/hcloud-go/hcloud/schema" + "github.com/hetznercloud/hcloud-go/hcloud/schema" +) + +// CertificateType is the type of available certificate types. +type CertificateType string + +// Available certificate types. +const ( + CertificateTypeUploaded CertificateType = "uploaded" + CertificateTypeManaged CertificateType = "managed" +) + +// CertificateStatusType is defines the type for the various managed +// certificate status. +type CertificateStatusType string + +// Possible certificate status. +const ( + CertificateStatusTypePending CertificateStatusType = "pending" + CertificateStatusTypeFailed CertificateStatusType = "failed" + + // only in issuance + CertificateStatusTypeCompleted CertificateStatusType = "completed" + + // only in renewal + CertificateStatusTypeScheduled CertificateStatusType = "scheduled" + CertificateStatusTypeUnavailable CertificateStatusType = "unavailable" +) + +// CertificateUsedByRefType is the type of used by references for +// certificates. +type CertificateUsedByRefType string + +// Possible users of certificates. +const ( + CertificateUsedByRefTypeLoadBalancer CertificateUsedByRefType = "load_balancer" ) +// CertificateUsedByRef points to a resource that uses this certificate. +type CertificateUsedByRef struct { + ID int + Type CertificateUsedByRefType +} + +// CertificateStatus indicates the status of a managed certificate. +type CertificateStatus struct { + Issuance CertificateStatusType + Renewal CertificateStatusType + Error *Error +} + +// IsFailed returns true if either the Issuance or the Renewal of a certificate +// failed. In this case the FailureReason field details the nature of the +// failure. +func (st *CertificateStatus) IsFailed() bool { + return st.Issuance == CertificateStatusTypeFailed || st.Renewal == CertificateStatusTypeFailed +} + // Certificate represents an certificate in the Hetzner Cloud. type Certificate struct { ID int Name string Labels map[string]string + Type CertificateType Certificate string Created time.Time NotValidBefore time.Time NotValidAfter time.Time DomainNames []string Fingerprint string + Status *CertificateStatus + UsedBy []CertificateUsedByRef +} + +// CertificateCreateResult is the result of creating a certificate. +type CertificateCreateResult struct { + Certificate *Certificate + Action *Action } // CertificateClient is a client for the Certificates API. @@ -130,7 +178,7 @@ func (c *CertificateClient) All(ctx context.Context) ([]*Certificate, error) { opts := CertificateListOpts{} opts.PerPage = 50 - _, err := c.client.all(func(page int) (*Response, error) { + err := c.client.all(func(page int) (*Response, error) { opts.Page = page Certificate, resp, err := c.List(ctx, opts) if err != nil { @@ -150,7 +198,7 @@ func (c *CertificateClient) All(ctx context.Context) ([]*Certificate, error) { func (c *CertificateClient) AllWithOpts(ctx context.Context, opts CertificateListOpts) ([]*Certificate, error) { var allCertificates []*Certificate - _, err := c.client.all(func(page int) (*Response, error) { + err := c.client.all(func(page int) (*Response, error) { opts.Page = page Certificates, resp, err := c.List(ctx, opts) if err != nil { @@ -169,9 +217,11 @@ func (c *CertificateClient) AllWithOpts(ctx context.Context, opts CertificateLis // CertificateCreateOpts specifies options for creating a new Certificate. type CertificateCreateOpts struct { Name string + Type CertificateType Certificate string PrivateKey string Labels map[string]string + DomainNames []string } // Validate checks if options are valid. @@ -179,6 +229,24 @@ func (o CertificateCreateOpts) Validate() error { if o.Name == "" { return errors.New("missing name") } + switch o.Type { + case "", CertificateTypeUploaded: + return o.validateUploaded() + case CertificateTypeManaged: + return o.validateManaged() + default: + return fmt.Errorf("invalid type: %s", o.Type) + } +} + +func (o CertificateCreateOpts) validateManaged() error { + if len(o.DomainNames) == 0 { + return errors.New("no domain names") + } + return nil +} + +func (o CertificateCreateOpts) validateUploaded() error { if o.Certificate == "" { return errors.New("missing certificate") } @@ -188,34 +256,71 @@ func (o CertificateCreateOpts) Validate() error { return nil } -// Create creates a new certificate. +// Create creates a new certificate uploaded certificate. +// +// Create returns an error for certificates of any other type. Use +// CreateCertificate to create such certificates. func (c *CertificateClient) Create(ctx context.Context, opts CertificateCreateOpts) (*Certificate, *Response, error) { + if !(opts.Type == "" || opts.Type == CertificateTypeUploaded) { + return nil, nil, fmt.Errorf("invalid certificate type: %s", opts.Type) + } + result, resp, err := c.CreateCertificate(ctx, opts) + if err != nil { + return nil, resp, err + } + return result.Certificate, resp, nil +} + +// CreateCertificate creates a new certificate of any type. +func (c *CertificateClient) CreateCertificate( + ctx context.Context, opts CertificateCreateOpts, +) (CertificateCreateResult, *Response, error) { + var ( + action *Action + reqBody schema.CertificateCreateRequest + ) + if err := opts.Validate(); err != nil { - return nil, nil, err + return CertificateCreateResult{}, nil, err } - reqBody := schema.CertificateCreateRequest{ - Name: opts.Name, - Certificate: opts.Certificate, - PrivateKey: opts.PrivateKey, + + reqBody.Name = opts.Name + + switch opts.Type { + case "", CertificateTypeUploaded: + reqBody.Type = string(CertificateTypeUploaded) + reqBody.Certificate = opts.Certificate + reqBody.PrivateKey = opts.PrivateKey + case CertificateTypeManaged: + reqBody.Type = string(CertificateTypeManaged) + reqBody.DomainNames = opts.DomainNames + default: + return CertificateCreateResult{}, nil, fmt.Errorf("invalid certificate type: %v", opts.Type) } + if opts.Labels != nil { reqBody.Labels = &opts.Labels } reqBodyData, err := json.Marshal(reqBody) if err != nil { - return nil, nil, err + return CertificateCreateResult{}, nil, err } req, err := c.client.NewRequest(ctx, "POST", "/certificates", bytes.NewReader(reqBodyData)) if err != nil { - return nil, nil, err + return CertificateCreateResult{}, nil, err } respBody := schema.CertificateCreateResponse{} resp, err := c.client.Do(req, &respBody) if err != nil { - return nil, resp, err + return CertificateCreateResult{}, resp, err } - return CertificateFromSchema(respBody.Certificate), resp, nil + cert := CertificateFromSchema(respBody.Certificate) + if respBody.Action != nil { + action = ActionFromSchema(*respBody.Action) + } + + return CertificateCreateResult{Certificate: cert, Action: action}, resp, nil } // CertificateUpdateOpts specifies options for updating a Certificate. @@ -260,3 +365,19 @@ func (c *CertificateClient) Delete(ctx context.Context, certificate *Certificate } return c.client.Do(req, nil) } + +// RetryIssuance retries the issuance of a failed managed certificate. +func (c *CertificateClient) RetryIssuance(ctx context.Context, certificate *Certificate) (*Action, *Response, error) { + var respBody schema.CertificateIssuanceRetryResponse + + req, err := c.client.NewRequest(ctx, "POST", fmt.Sprintf("/certificates/%d/actions/retry", certificate.ID), nil) + if err != nil { + return nil, nil, err + } + resp, err := c.client.Do(req, &respBody) + if err != nil { + return nil, nil, err + } + action := ActionFromSchema(respBody.Action) + return action, resp, nil +} diff --git a/cluster-autoscaler/cloudprovider/hetzner/hcloud-go/hcloud/client.go b/cluster-autoscaler/cloudprovider/hetzner/hcloud-go/hcloud/client.go index d7bbd8e9c71a..25b713be9ddb 100644 --- a/cluster-autoscaler/cloudprovider/hetzner/hcloud-go/hcloud/client.go +++ b/cluster-autoscaler/cloudprovider/hetzner/hcloud-go/hcloud/client.go @@ -1,19 +1,3 @@ -/* -Copyright 2018 The Kubernetes Authors. - -Licensed under the Apache License, Version 2.0 (the "License"); -you may not use this file except in compliance with the License. -You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - -Unless required by applicable law or agreed to in writing, software -distributed under the License is distributed on an "AS IS" BASIS, -WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -See the License for the specific language governing permissions and -limitations under the License. -*/ - package hcloud import ( @@ -31,7 +15,7 @@ import ( "strings" "time" - "k8s.io/autoscaler/cluster-autoscaler/cloudprovider/hetzner/hcloud-go/hcloud/schema" + "github.com/hetznercloud/hcloud-go/hcloud/schema" ) // Endpoint is the base URL of the API. @@ -77,6 +61,7 @@ type Client struct { Action ActionClient Certificate CertificateClient Datacenter DatacenterClient + Firewall FirewallClient FloatingIP FloatingIPClient Image ImageClient ISO ISOClient @@ -178,6 +163,7 @@ func NewClient(options ...ClientOption) *Client { client.LoadBalancer = LoadBalancerClient{client: client} client.LoadBalancerType = LoadBalancerTypeClient{client: client} client.Certificate = CertificateClient{client: client} + client.Firewall = FirewallClient{client: client} return client } @@ -220,8 +206,7 @@ func (c *Client) Do(r *http.Request, v interface{}) (*Response, error) { } if c.debugWriter != nil { - // To get the response body we need to read it before the request was actually send. https://github.com/golang/go/issues/29792 - dumpReq, err := httputil.DumpRequestOut(r, true) + dumpReq, err := dumpRequest(r) if err != nil { return nil, err } @@ -257,12 +242,10 @@ func (c *Client) Do(r *http.Request, v interface{}) (*Response, error) { err = errorFromResponse(resp, body) if err == nil { err = fmt.Errorf("hcloud: server responded with status code %d", resp.StatusCode) - } else { - if isRetryable(err) { - c.backoff(retries) - retries++ - continue - } + } else if isRetryable(err) { + c.backoff(retries) + retries++ + continue } return response, err } @@ -290,17 +273,17 @@ func (c *Client) backoff(retries int) { time.Sleep(c.backoffFunc(retries)) } -func (c *Client) all(f func(int) (*Response, error)) (*Response, error) { +func (c *Client) all(f func(int) (*Response, error)) error { var ( page = 1 ) for { resp, err := f(page) if err != nil { - return nil, err + return err } if resp.Meta.Pagination == nil || resp.Meta.Pagination.NextPage == 0 { - return resp, nil + return nil } page = resp.Meta.Pagination.NextPage } @@ -317,6 +300,25 @@ func (c *Client) buildUserAgent() { } } +func dumpRequest(r *http.Request) ([]byte, error) { + // Duplicate the request, so we can redact the auth header + rDuplicate := r.Clone(context.Background()) + rDuplicate.Header.Set("Authorization", "REDACTED") + + // To get the request body we need to read it before the request was actually sent. + // See https://github.com/golang/go/issues/29792 + dumpReq, err := httputil.DumpRequestOut(rDuplicate, true) + if err != nil { + return nil, err + } + + // Set original request body to the duplicate created by DumpRequestOut. The request body is not duplicated + // by .Clone() and instead just referenced, so it would be completely read otherwise. + r.Body = rDuplicate.Body + + return dumpReq, nil +} + func errorFromResponse(resp *http.Response, body []byte) error { if !strings.HasPrefix(resp.Header.Get("Content-Type"), "application/json") { return nil diff --git a/cluster-autoscaler/cloudprovider/hetzner/hcloud-go/hcloud/datacenter.go b/cluster-autoscaler/cloudprovider/hetzner/hcloud-go/hcloud/datacenter.go index 9c3c8f583c12..ae8b6c601111 100644 --- a/cluster-autoscaler/cloudprovider/hetzner/hcloud-go/hcloud/datacenter.go +++ b/cluster-autoscaler/cloudprovider/hetzner/hcloud-go/hcloud/datacenter.go @@ -1,19 +1,3 @@ -/* -Copyright 2018 The Kubernetes Authors. - -Licensed under the Apache License, Version 2.0 (the "License"); -you may not use this file except in compliance with the License. -You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - -Unless required by applicable law or agreed to in writing, software -distributed under the License is distributed on an "AS IS" BASIS, -WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -See the License for the specific language governing permissions and -limitations under the License. -*/ - package hcloud import ( @@ -22,7 +6,7 @@ import ( "net/url" "strconv" - "k8s.io/autoscaler/cluster-autoscaler/cloudprovider/hetzner/hcloud-go/hcloud/schema" + "github.com/hetznercloud/hcloud-go/hcloud/schema" ) // Datacenter represents a datacenter in the Hetzner Cloud. @@ -128,7 +112,7 @@ func (c *DatacenterClient) All(ctx context.Context) ([]*Datacenter, error) { opts := DatacenterListOpts{} opts.PerPage = 50 - _, err := c.client.all(func(page int) (*Response, error) { + err := c.client.all(func(page int) (*Response, error) { opts.Page = page datacenters, resp, err := c.List(ctx, opts) if err != nil { diff --git a/cluster-autoscaler/cloudprovider/hetzner/hcloud-go/hcloud/error.go b/cluster-autoscaler/cloudprovider/hetzner/hcloud-go/hcloud/error.go index 0b684dc9bd21..d54de70667d2 100644 --- a/cluster-autoscaler/cloudprovider/hetzner/hcloud-go/hcloud/error.go +++ b/cluster-autoscaler/cloudprovider/hetzner/hcloud-go/hcloud/error.go @@ -1,19 +1,3 @@ -/* -Copyright 2018 The Kubernetes Authors. - -Licensed under the Apache License, Version 2.0 (the "License"); -you may not use this file except in compliance with the License. -You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - -Unless required by applicable law or agreed to in writing, software -distributed under the License is distributed on an "AS IS" BASIS, -WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -See the License for the specific language governing permissions and -limitations under the License. -*/ - package hcloud import "fmt" @@ -37,10 +21,53 @@ const ( ErrorCodeProtected ErrorCode = "protected" // The actions you are trying is protected 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 + + // Server related error codes + ErrorCodeInvalidServerType ErrorCode = "invalid_server_type" // The server type does not fit for the given server or is deprecated + ErrorCodeServerNotStopped ErrorCode = "server_not_stopped" // The action requires a stopped server + ErrorCodeNetworksOverlap ErrorCode = "networks_overlap" // The network IP range overlaps with one of the server networks + ErrorCodePlacementError ErrorCode = "placement_error" // An error during the placement occurred ErrorCodeServerAlreadyAttached ErrorCode = "server_already_attached" // The server is already attached to the resource - // Deprecated error codes + // Load Balancer related error codes + ErrorCodeIPNotOwned ErrorCode = "ip_not_owned" // The IP you are trying to add as a target is not owned by the Project owner + ErrorCodeSourcePortAlreadyUsed ErrorCode = "source_port_already_used" // The source port you are trying to add is already in use + ErrorCodeCloudResourceIPNotAllowed ErrorCode = "cloud_resource_ip_not_allowed" // The IP you are trying to add as a target belongs to a Hetzner Cloud resource + ErrorCodeServerNotAttachedToNetwork ErrorCode = "server_not_attached_to_network" // The server you are trying to add as a target is not attached to the same network as the Load Balancer + ErrorCodeTargetAlreadyDefined ErrorCode = "target_already_defined" // The Load Balancer target you are trying to define is already defined + ErrorCodeInvalidLoadBalancerType ErrorCode = "invalid_load_balancer_type" // The Load Balancer type does not fit for the given Load Balancer + ErrorCodeLoadBalancerAlreadyAttached ErrorCode = "load_balancer_already_attached" // The Load Balancer is already attached to a network + ErrorCodeTargetsWithoutUsePrivateIP ErrorCode = "targets_without_use_private_ip" // The Load Balancer has targets that use the public IP instead of the private IP + ErrorCodeLoadBalancerNotAttachedToNetwork ErrorCode = "load_balancer_not_attached_to_network" // The Load Balancer is not attached to a network + // Network related error codes + ErrorCodeIPNotAvailable ErrorCode = "ip_not_available" // The provided Network IP is not available + ErrorCodeNoSubnetAvailable ErrorCode = "no_subnet_available" // No Subnet or IP is available for the Load Balancer/Server within the network + ErrorCodeVSwitchAlreadyUsed ErrorCode = "vswitch_id_already_used" // The given Robot vSwitch ID is already registered in another network + + // Volume related error codes + ErrorCodeNoSpaceLeftInLocation ErrorCode = "no_space_left_in_location" // There is no volume space left in the given location + ErrorCodeVolumeAlreadyAttached ErrorCode = "volume_already_attached" // Volume is already attached to a server, detach first + + // Firewall related error codes + ErrorCodeFirewallAlreadyApplied ErrorCode = "firewall_already_applied" // Firewall was already applied on resource + ErrorCodeFirewallAlreadyRemoved ErrorCode = "firewall_already_removed" // Firewall was already removed from the resource + ErrorCodeIncompatibleNetworkType ErrorCode = "incompatible_network_type" // The Network type is incompatible for the given resource + ErrorCodeResourceInUse ErrorCode = "resource_in_use" // Firewall must not be in use to be deleted + ErrorCodeServerAlreadyAdded ErrorCode = "server_already_added" // Server added more than one time to resource + + // Certificate related error codes + ErrorCodeCAARecordDoesNotAllowCA ErrorCode = "caa_record_does_not_allow_ca" // CAA record does not allow certificate authority + ErrorCodeCADNSValidationFailed ErrorCode = "ca_dns_validation_failed" // Certificate Authority: DNS validation failed + ErrorCodeCATooManyAuthorizationsFailedRecently ErrorCode = "ca_too_many_authorizations_failed_recently" // Certificate Authority: Too many authorizations failed recently + ErrorCodeCATooManyCertificatedIssuedForRegisteredDomain ErrorCode = "ca_too_many_certificates_issued_for_registered_domain" // Certificate Authority: Too many certificates issued for registered domain + ErrorCodeCATooManyDuplicateCertificates ErrorCode = "ca_too_many_duplicate_certificates" // Certificate Authority: Too many duplicate certificates + ErrorCodeCloudNotVerifyDomainDelegatedToZone ErrorCode = "could_not_verify_domain_delegated_to_zone" // Could not verify domain delegated to zone + ErrorCodeDNSZoneNotFound ErrorCode = "dns_zone_not_found" // DNS zone not found + + // Deprecated error codes // The actual value of this error code is limit_reached. The new error code // rate_limit_exceeded for ratelimiting was introduced before Hetzner Cloud // launched into the public. To make clients using the old error code still diff --git a/cluster-autoscaler/cloudprovider/hetzner/hcloud-go/hcloud/firewall.go b/cluster-autoscaler/cloudprovider/hetzner/hcloud-go/hcloud/firewall.go new file mode 100644 index 000000000000..ee3a80f22878 --- /dev/null +++ b/cluster-autoscaler/cloudprovider/hetzner/hcloud-go/hcloud/firewall.go @@ -0,0 +1,383 @@ +package hcloud + +import ( + "bytes" + "context" + "encoding/json" + "errors" + "fmt" + "net" + "net/url" + "strconv" + "time" + + "github.com/hetznercloud/hcloud-go/hcloud/schema" +) + +// Firewall represents a Firewall in the Hetzner Cloud. +type Firewall struct { + ID int + Name string + Labels map[string]string + Created time.Time + Rules []FirewallRule + AppliedTo []FirewallResource +} + +// FirewallRule represents a Firewall's rules. +type FirewallRule struct { + Direction FirewallRuleDirection + SourceIPs []net.IPNet + DestinationIPs []net.IPNet + Protocol FirewallRuleProtocol + Port *string +} + +// FirewallRuleDirection specifies the direction of a Firewall rule. +type FirewallRuleDirection string + +const ( + // FirewallRuleDirectionIn specifies a rule for inbound traffic. + FirewallRuleDirectionIn FirewallRuleDirection = "in" + + // FirewallRuleDirectionOut specifies a rule for outbound traffic. + FirewallRuleDirectionOut FirewallRuleDirection = "out" +) + +// FirewallRuleProtocol specifies the protocol of a Firewall rule. +type FirewallRuleProtocol string + +const ( + // FirewallRuleProtocolTCP specifies a TCP rule. + FirewallRuleProtocolTCP FirewallRuleProtocol = "tcp" + // FirewallRuleProtocolUDP specifies a UDP rule. + FirewallRuleProtocolUDP FirewallRuleProtocol = "udp" + // FirewallRuleProtocolICMP specifies an ICMP rule. + FirewallRuleProtocolICMP FirewallRuleProtocol = "icmp" + // FirewallRuleProtocolESP specifies an esp rule. + FirewallRuleProtocolESP FirewallRuleProtocol = "esp" + // FirewallRuleProtocolGRE specifies an gre rule. + FirewallRuleProtocolGRE FirewallRuleProtocol = "gre" +) + +// FirewallResourceType specifies the resource to apply a Firewall on. +type FirewallResourceType string + +const ( + // FirewallResourceTypeServer specifies a Server. + FirewallResourceTypeServer FirewallResourceType = "server" + // FirewallResourceTypeLabelSelector specifies a LabelSelector. + FirewallResourceTypeLabelSelector FirewallResourceType = "label_selector" +) + +// FirewallResource represents a resource to apply the new Firewall on. +type FirewallResource struct { + Type FirewallResourceType + Server *FirewallResourceServer + LabelSelector *FirewallResourceLabelSelector +} + +// FirewallResourceServer represents a Server to apply a Firewall on. +type FirewallResourceServer struct { + ID int +} + +// FirewallResourceLabelSelector represents a LabelSelector to apply a Firewall on. +type FirewallResourceLabelSelector struct { + Selector string +} + +// FirewallClient is a client for the Firewalls API. +type FirewallClient struct { + client *Client +} + +// GetByID retrieves a Firewall by its ID. If the Firewall does not exist, nil is returned. +func (c *FirewallClient) GetByID(ctx context.Context, id int) (*Firewall, *Response, error) { + req, err := c.client.NewRequest(ctx, "GET", fmt.Sprintf("/firewalls/%d", id), nil) + if err != nil { + return nil, nil, err + } + + var body schema.FirewallGetResponse + resp, err := c.client.Do(req, &body) + if err != nil { + if IsError(err, ErrorCodeNotFound) { + return nil, resp, nil + } + return nil, nil, err + } + return FirewallFromSchema(body.Firewall), resp, nil +} + +// GetByName retrieves a Firewall by its name. If the Firewall does not exist, nil is returned. +func (c *FirewallClient) GetByName(ctx context.Context, name string) (*Firewall, *Response, error) { + if name == "" { + return nil, nil, nil + } + firewalls, response, err := c.List(ctx, FirewallListOpts{Name: name}) + if len(firewalls) == 0 { + return nil, response, err + } + return firewalls[0], response, err +} + +// Get retrieves a Firewall by its ID if the input can be parsed as an integer, otherwise it +// retrieves a Firewall by its name. If the Firewall does not exist, nil is returned. +func (c *FirewallClient) Get(ctx context.Context, idOrName string) (*Firewall, *Response, error) { + if id, err := strconv.Atoi(idOrName); err == nil { + return c.GetByID(ctx, int(id)) + } + return c.GetByName(ctx, idOrName) +} + +// FirewallListOpts specifies options for listing Firewalls. +type FirewallListOpts struct { + ListOpts + Name string +} + +func (l FirewallListOpts) values() url.Values { + vals := l.ListOpts.values() + if l.Name != "" { + vals.Add("name", l.Name) + } + return vals +} + +// List returns a list of Firewalls for a specific page. +// +// Please note that filters specified in opts are not taken into account +// when their value corresponds to their zero value or when they are empty. +func (c *FirewallClient) List(ctx context.Context, opts FirewallListOpts) ([]*Firewall, *Response, error) { + path := "/firewalls?" + opts.values().Encode() + req, err := c.client.NewRequest(ctx, "GET", path, nil) + if err != nil { + return nil, nil, err + } + + var body schema.FirewallListResponse + resp, err := c.client.Do(req, &body) + if err != nil { + return nil, nil, err + } + firewalls := make([]*Firewall, 0, len(body.Firewalls)) + for _, s := range body.Firewalls { + firewalls = append(firewalls, FirewallFromSchema(s)) + } + return firewalls, resp, nil +} + +// All returns all Firewalls. +func (c *FirewallClient) All(ctx context.Context) ([]*Firewall, error) { + allFirewalls := []*Firewall{} + + opts := FirewallListOpts{} + opts.PerPage = 50 + + err := c.client.all(func(page int) (*Response, error) { + opts.Page = page + firewalls, resp, err := c.List(ctx, opts) + if err != nil { + return resp, err + } + allFirewalls = append(allFirewalls, firewalls...) + return resp, nil + }) + if err != nil { + return nil, err + } + + return allFirewalls, nil +} + +// AllWithOpts returns all Firewalls for the given options. +func (c *FirewallClient) AllWithOpts(ctx context.Context, opts FirewallListOpts) ([]*Firewall, error) { + var allFirewalls []*Firewall + + err := c.client.all(func(page int) (*Response, error) { + opts.Page = page + firewalls, resp, err := c.List(ctx, opts) + if err != nil { + return resp, err + } + allFirewalls = append(allFirewalls, firewalls...) + return resp, nil + }) + if err != nil { + return nil, err + } + + return allFirewalls, nil +} + +// FirewallCreateOpts specifies options for creating a new Firewall. +type FirewallCreateOpts struct { + Name string + Labels map[string]string + Rules []FirewallRule + ApplyTo []FirewallResource +} + +// Validate checks if options are valid. +func (o FirewallCreateOpts) Validate() error { + if o.Name == "" { + return errors.New("missing name") + } + return nil +} + +// FirewallCreateResult is the result of a create Firewall call. +type FirewallCreateResult struct { + Firewall *Firewall + Actions []*Action +} + +// Create creates a new Firewall. +func (c *FirewallClient) Create(ctx context.Context, opts FirewallCreateOpts) (FirewallCreateResult, *Response, error) { + if err := opts.Validate(); err != nil { + return FirewallCreateResult{}, nil, err + } + reqBody := firewallCreateOptsToSchema(opts) + reqBodyData, err := json.Marshal(reqBody) + if err != nil { + return FirewallCreateResult{}, nil, err + } + req, err := c.client.NewRequest(ctx, "POST", "/firewalls", bytes.NewReader(reqBodyData)) + if err != nil { + return FirewallCreateResult{}, nil, err + } + + respBody := schema.FirewallCreateResponse{} + resp, err := c.client.Do(req, &respBody) + if err != nil { + return FirewallCreateResult{}, resp, err + } + result := FirewallCreateResult{ + Firewall: FirewallFromSchema(respBody.Firewall), + Actions: ActionsFromSchema(respBody.Actions), + } + return result, resp, nil +} + +// FirewallUpdateOpts specifies options for updating a Firewall. +type FirewallUpdateOpts struct { + Name string + Labels map[string]string +} + +// Update updates a Firewall. +func (c *FirewallClient) Update(ctx context.Context, firewall *Firewall, opts FirewallUpdateOpts) (*Firewall, *Response, error) { + reqBody := schema.FirewallUpdateRequest{} + if opts.Name != "" { + reqBody.Name = &opts.Name + } + if opts.Labels != nil { + reqBody.Labels = &opts.Labels + } + reqBodyData, err := json.Marshal(reqBody) + if err != nil { + return nil, nil, err + } + + path := fmt.Sprintf("/firewalls/%d", firewall.ID) + req, err := c.client.NewRequest(ctx, "PUT", path, bytes.NewReader(reqBodyData)) + if err != nil { + return nil, nil, err + } + + respBody := schema.FirewallUpdateResponse{} + resp, err := c.client.Do(req, &respBody) + if err != nil { + return nil, resp, err + } + return FirewallFromSchema(respBody.Firewall), resp, nil +} + +// Delete deletes a Firewall. +func (c *FirewallClient) Delete(ctx context.Context, firewall *Firewall) (*Response, error) { + req, err := c.client.NewRequest(ctx, "DELETE", fmt.Sprintf("/firewalls/%d", firewall.ID), nil) + if err != nil { + return nil, err + } + return c.client.Do(req, nil) +} + +// FirewallSetRulesOpts specifies options for setting rules of a Firewall. +type FirewallSetRulesOpts struct { + Rules []FirewallRule +} + +// SetRules sets the rules of a Firewall. +func (c *FirewallClient) SetRules(ctx context.Context, firewall *Firewall, opts FirewallSetRulesOpts) ([]*Action, *Response, error) { + reqBody := firewallSetRulesOptsToSchema(opts) + reqBodyData, err := json.Marshal(reqBody) + if err != nil { + return nil, nil, err + } + + path := fmt.Sprintf("/firewalls/%d/actions/set_rules", firewall.ID) + req, err := c.client.NewRequest(ctx, "POST", path, bytes.NewReader(reqBodyData)) + if err != nil { + return nil, nil, err + } + + var respBody schema.FirewallActionSetRulesResponse + resp, err := c.client.Do(req, &respBody) + if err != nil { + return nil, resp, err + } + return ActionsFromSchema(respBody.Actions), resp, nil +} + +func (c *FirewallClient) ApplyResources(ctx context.Context, firewall *Firewall, resources []FirewallResource) ([]*Action, *Response, error) { + applyTo := make([]schema.FirewallResource, len(resources)) + for i, r := range resources { + applyTo[i] = firewallResourceToSchema(r) + } + + reqBody := schema.FirewallActionApplyToResourcesRequest{ApplyTo: applyTo} + reqBodyData, err := json.Marshal(reqBody) + if err != nil { + return nil, nil, err + } + + path := fmt.Sprintf("/firewalls/%d/actions/apply_to_resources", firewall.ID) + req, err := c.client.NewRequest(ctx, "POST", path, bytes.NewReader(reqBodyData)) + if err != nil { + return nil, nil, err + } + + var respBody schema.FirewallActionApplyToResourcesResponse + resp, err := c.client.Do(req, &respBody) + if err != nil { + return nil, resp, err + } + return ActionsFromSchema(respBody.Actions), resp, nil +} + +func (c *FirewallClient) RemoveResources(ctx context.Context, firewall *Firewall, resources []FirewallResource) ([]*Action, *Response, error) { + removeFrom := make([]schema.FirewallResource, len(resources)) + for i, r := range resources { + removeFrom[i] = firewallResourceToSchema(r) + } + + reqBody := schema.FirewallActionRemoveFromResourcesRequest{RemoveFrom: removeFrom} + reqBodyData, err := json.Marshal(reqBody) + if err != nil { + return nil, nil, err + } + + path := fmt.Sprintf("/firewalls/%d/actions/remove_from_resources", firewall.ID) + req, err := c.client.NewRequest(ctx, "POST", path, bytes.NewReader(reqBodyData)) + if err != nil { + return nil, nil, err + } + + var respBody schema.FirewallActionRemoveFromResourcesResponse + resp, err := c.client.Do(req, &respBody) + if err != nil { + return nil, resp, err + } + return ActionsFromSchema(respBody.Actions), resp, nil +} diff --git a/cluster-autoscaler/cloudprovider/hetzner/hcloud-go/hcloud/floating_ip.go b/cluster-autoscaler/cloudprovider/hetzner/hcloud-go/hcloud/floating_ip.go index a8ef89f7efe7..d8a6d0f5fdcb 100644 --- a/cluster-autoscaler/cloudprovider/hetzner/hcloud-go/hcloud/floating_ip.go +++ b/cluster-autoscaler/cloudprovider/hetzner/hcloud-go/hcloud/floating_ip.go @@ -1,19 +1,3 @@ -/* -Copyright 2018 The Kubernetes Authors. - -Licensed under the Apache License, Version 2.0 (the "License"); -you may not use this file except in compliance with the License. -You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - -Unless required by applicable law or agreed to in writing, software -distributed under the License is distributed on an "AS IS" BASIS, -WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -See the License for the specific language governing permissions and -limitations under the License. -*/ - package hcloud import ( @@ -27,7 +11,7 @@ import ( "strconv" "time" - "k8s.io/autoscaler/cluster-autoscaler/cloudprovider/hetzner/hcloud-go/hcloud/schema" + "github.com/hetznercloud/hcloud-go/hcloud/schema" ) // FloatingIP represents a Floating IP in the Hetzner Cloud. @@ -157,7 +141,7 @@ func (c *FloatingIPClient) All(ctx context.Context) ([]*FloatingIP, error) { func (c *FloatingIPClient) AllWithOpts(ctx context.Context, opts FloatingIPListOpts) ([]*FloatingIP, error) { allFloatingIPs := []*FloatingIP{} - _, err := c.client.all(func(page int) (*Response, error) { + err := c.client.all(func(page int) (*Response, error) { opts.Page = page floatingIPs, resp, err := c.List(ctx, opts) if err != nil { diff --git a/cluster-autoscaler/cloudprovider/hetzner/hcloud-go/hcloud/hcloud.go b/cluster-autoscaler/cloudprovider/hetzner/hcloud-go/hcloud/hcloud.go index 23b5d874cc73..fcdcc54b8b9d 100644 --- a/cluster-autoscaler/cloudprovider/hetzner/hcloud-go/hcloud/hcloud.go +++ b/cluster-autoscaler/cloudprovider/hetzner/hcloud-go/hcloud/hcloud.go @@ -1,21 +1,5 @@ -/* -Copyright 2018 The Kubernetes Authors. - -Licensed under the Apache License, Version 2.0 (the "License"); -you may not use this file except in compliance with the License. -You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - -Unless required by applicable law or agreed to in writing, software -distributed under the License is distributed on an "AS IS" BASIS, -WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -See the License for the specific language governing permissions and -limitations under the License. -*/ - // Package hcloud is a library for the Hetzner Cloud API. package hcloud // Version is the library's version following Semantic Versioning. -const Version = "1.22.0" +const Version = "1.27.0" diff --git a/cluster-autoscaler/cloudprovider/hetzner/hcloud-go/hcloud/helper.go b/cluster-autoscaler/cloudprovider/hetzner/hcloud-go/hcloud/helper.go index 537607883e46..e8e264267cc1 100644 --- a/cluster-autoscaler/cloudprovider/hetzner/hcloud-go/hcloud/helper.go +++ b/cluster-autoscaler/cloudprovider/hetzner/hcloud-go/hcloud/helper.go @@ -1,19 +1,3 @@ -/* -Copyright 2018 The Kubernetes Authors. - -Licensed under the Apache License, Version 2.0 (the "License"); -you may not use this file except in compliance with the License. -You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - -Unless required by applicable law or agreed to in writing, software -distributed under the License is distributed on an "AS IS" BASIS, -WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -See the License for the specific language governing permissions and -limitations under the License. -*/ - package hcloud import "time" diff --git a/cluster-autoscaler/cloudprovider/hetzner/hcloud-go/hcloud/image.go b/cluster-autoscaler/cloudprovider/hetzner/hcloud-go/hcloud/image.go index a20bd5596eb3..0867aac0d822 100644 --- a/cluster-autoscaler/cloudprovider/hetzner/hcloud-go/hcloud/image.go +++ b/cluster-autoscaler/cloudprovider/hetzner/hcloud-go/hcloud/image.go @@ -1,19 +1,3 @@ -/* -Copyright 2018 The Kubernetes Authors. - -Licensed under the Apache License, Version 2.0 (the "License"); -you may not use this file except in compliance with the License. -You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - -Unless required by applicable law or agreed to in writing, software -distributed under the License is distributed on an "AS IS" BASIS, -WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -See the License for the specific language governing permissions and -limitations under the License. -*/ - package hcloud import ( @@ -25,7 +9,7 @@ import ( "strconv" "time" - "k8s.io/autoscaler/cluster-autoscaler/cloudprovider/hetzner/hcloud-go/hcloud/schema" + "github.com/hetznercloud/hcloud-go/hcloud/schema" ) // Image represents an Image in the Hetzner Cloud. @@ -48,6 +32,7 @@ type Image struct { Protection ImageProtection Deprecated time.Time // The zero value denotes the image is not deprecated. Labels map[string]string + Deleted time.Time } // IsDeprecated returns whether the image is deprecated. @@ -55,6 +40,11 @@ func (image *Image) IsDeprecated() bool { return !image.Deprecated.IsZero() } +// IsDeleted returns whether the image is deleted. +func (image *Image) IsDeleted() bool { + return !image.Deleted.IsZero() +} + // ImageProtection represents the protection level of an image. type ImageProtection struct { Delete bool @@ -70,6 +60,8 @@ const ( ImageTypeBackup ImageType = "backup" // ImageTypeSystem represents a system image. ImageTypeSystem ImageType = "system" + // ImageTypeApp represents a one click app image. + ImageTypeApp ImageType = "app" ) // ImageStatus specifies the status of an image. @@ -192,7 +184,7 @@ func (c *ImageClient) All(ctx context.Context) ([]*Image, error) { func (c *ImageClient) AllWithOpts(ctx context.Context, opts ImageListOpts) ([]*Image, error) { allImages := []*Image{} - _, err := c.client.all(func(page int) (*Response, error) { + err := c.client.all(func(page int) (*Response, error) { opts.Page = page images, resp, err := c.List(ctx, opts) if err != nil { diff --git a/cluster-autoscaler/cloudprovider/hetzner/hcloud-go/hcloud/iso.go b/cluster-autoscaler/cloudprovider/hetzner/hcloud-go/hcloud/iso.go index 4932e44c3304..b3d97bade711 100644 --- a/cluster-autoscaler/cloudprovider/hetzner/hcloud-go/hcloud/iso.go +++ b/cluster-autoscaler/cloudprovider/hetzner/hcloud-go/hcloud/iso.go @@ -1,19 +1,3 @@ -/* -Copyright 2018 The Kubernetes Authors. - -Licensed under the Apache License, Version 2.0 (the "License"); -you may not use this file except in compliance with the License. -You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - -Unless required by applicable law or agreed to in writing, software -distributed under the License is distributed on an "AS IS" BASIS, -WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -See the License for the specific language governing permissions and -limitations under the License. -*/ - package hcloud import ( @@ -23,7 +7,7 @@ import ( "strconv" "time" - "k8s.io/autoscaler/cluster-autoscaler/cloudprovider/hetzner/hcloud-go/hcloud/schema" + "github.com/hetznercloud/hcloud-go/hcloud/schema" ) // ISO represents an ISO image in the Hetzner Cloud. @@ -138,7 +122,7 @@ func (c *ISOClient) All(ctx context.Context) ([]*ISO, error) { opts := ISOListOpts{} opts.PerPage = 50 - _, err := c.client.all(func(page int) (*Response, error) { + err := c.client.all(func(page int) (*Response, error) { opts.Page = page isos, resp, err := c.List(ctx, opts) if err != nil { diff --git a/cluster-autoscaler/cloudprovider/hetzner/hcloud-go/hcloud/load_balancer.go b/cluster-autoscaler/cloudprovider/hetzner/hcloud-go/hcloud/load_balancer.go index 3e25feb9f61f..d39512778f10 100644 --- a/cluster-autoscaler/cloudprovider/hetzner/hcloud-go/hcloud/load_balancer.go +++ b/cluster-autoscaler/cloudprovider/hetzner/hcloud-go/hcloud/load_balancer.go @@ -1,19 +1,3 @@ -/* -Copyright 2018 The Kubernetes Authors. - -Licensed under the Apache License, Version 2.0 (the "License"); -you may not use this file except in compliance with the License. -You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - -Unless required by applicable law or agreed to in writing, software -distributed under the License is distributed on an "AS IS" BASIS, -WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -See the License for the specific language governing permissions and -limitations under the License. -*/ - package hcloud import ( @@ -22,11 +6,12 @@ import ( "encoding/json" "fmt" "net" + "net/http" "net/url" "strconv" "time" - "k8s.io/autoscaler/cluster-autoscaler/cloudprovider/hetzner/hcloud-go/hcloud/schema" + "github.com/hetznercloud/hcloud-go/hcloud/schema" ) // LoadBalancer represents a Load Balancer in the Hetzner Cloud. @@ -298,7 +283,7 @@ func (c *LoadBalancerClient) All(ctx context.Context) ([]*LoadBalancer, error) { opts := LoadBalancerListOpts{} opts.PerPage = 50 - _, err := c.client.all(func(page int) (*Response, error) { + err := c.client.all(func(page int) (*Response, error) { opts.Page = page LoadBalancer, resp, err := c.List(ctx, opts) if err != nil { @@ -318,7 +303,7 @@ func (c *LoadBalancerClient) All(ctx context.Context) ([]*LoadBalancer, error) { func (c *LoadBalancerClient) AllWithOpts(ctx context.Context, opts LoadBalancerListOpts) ([]*LoadBalancer, error) { var allLoadBalancers []*LoadBalancer - _, err := c.client.all(func(page int) (*Response, error) { + err := c.client.all(func(page int) (*Response, error) { opts.Page = page LoadBalancers, resp, err := c.List(ctx, opts) if err != nil { @@ -947,3 +932,95 @@ func (c *LoadBalancerClient) ChangeType(ctx context.Context, loadBalancer *LoadB } return ActionFromSchema(respBody.Action), resp, nil } + +// LoadBalancerMetricType is the type of available metrics for Load Balancers. +type LoadBalancerMetricType string + +// Available types of Load Balancer metrics. See Hetzner Cloud API +// documentation for details. +const ( + LoadBalancerMetricOpenConnections LoadBalancerMetricType = "open_connections" + LoadBalancerMetricConnectionsPerSecond LoadBalancerMetricType = "connections_per_second" + LoadBalancerMetricRequestsPerSecond LoadBalancerMetricType = "requests_per_second" + LoadBalancerMetricBandwidth LoadBalancerMetricType = "bandwidth" +) + +// LoadBalancerGetMetricsOpts configures the call to get metrics for a Load +// Balancer. +type LoadBalancerGetMetricsOpts struct { + Types []LoadBalancerMetricType + Start time.Time + End time.Time + Step int +} + +func (o *LoadBalancerGetMetricsOpts) addQueryParams(req *http.Request) error { + query := req.URL.Query() + + if len(o.Types) == 0 { + return fmt.Errorf("no metric types specified") + } + for _, typ := range o.Types { + query.Add("type", string(typ)) + } + + if o.Start.IsZero() { + return fmt.Errorf("no start time specified") + } + query.Add("start", o.Start.Format(time.RFC3339)) + + if o.End.IsZero() { + return fmt.Errorf("no end time specified") + } + query.Add("end", o.End.Format(time.RFC3339)) + + if o.Step > 0 { + query.Add("step", strconv.Itoa(o.Step)) + } + req.URL.RawQuery = query.Encode() + + return nil +} + +// LoadBalancerMetrics contains the metrics requested for a Load Balancer. +type LoadBalancerMetrics struct { + Start time.Time + End time.Time + Step float64 + TimeSeries map[string][]LoadBalancerMetricsValue +} + +// LoadBalancerMetricsValue represents a single value in a time series of metrics. +type LoadBalancerMetricsValue struct { + Timestamp float64 + Value string +} + +// GetMetrics obtains metrics for a Load Balancer. +func (c *LoadBalancerClient) GetMetrics( + ctx context.Context, lb *LoadBalancer, opts LoadBalancerGetMetricsOpts, +) (*LoadBalancerMetrics, *Response, error) { + var respBody schema.LoadBalancerGetMetricsResponse + + if lb == nil { + return nil, nil, fmt.Errorf("illegal argument: load balancer is nil") + } + + path := fmt.Sprintf("/load_balancers/%d/metrics", lb.ID) + req, err := c.client.NewRequest(ctx, "GET", path, nil) + if err != nil { + return nil, nil, fmt.Errorf("new request: %v", err) + } + if err := opts.addQueryParams(req); err != nil { + return nil, nil, fmt.Errorf("add query params: %v", err) + } + resp, err := c.client.Do(req, &respBody) + if err != nil { + return nil, nil, fmt.Errorf("get metrics: %v", err) + } + ms, err := loadBalancerMetricsFromSchema(&respBody) + if err != nil { + return nil, nil, fmt.Errorf("convert response body: %v", err) + } + return ms, resp, nil +} diff --git a/cluster-autoscaler/cloudprovider/hetzner/hcloud-go/hcloud/load_balancer_type.go b/cluster-autoscaler/cloudprovider/hetzner/hcloud-go/hcloud/load_balancer_type.go index d3bae99873ad..73800048fde7 100644 --- a/cluster-autoscaler/cloudprovider/hetzner/hcloud-go/hcloud/load_balancer_type.go +++ b/cluster-autoscaler/cloudprovider/hetzner/hcloud-go/hcloud/load_balancer_type.go @@ -1,19 +1,3 @@ -/* -Copyright 2018 The Kubernetes Authors. - -Licensed under the Apache License, Version 2.0 (the "License"); -you may not use this file except in compliance with the License. -You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - -Unless required by applicable law or agreed to in writing, software -distributed under the License is distributed on an "AS IS" BASIS, -WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -See the License for the specific language governing permissions and -limitations under the License. -*/ - package hcloud import ( @@ -22,7 +6,7 @@ import ( "net/url" "strconv" - "k8s.io/autoscaler/cluster-autoscaler/cloudprovider/hetzner/hcloud-go/hcloud/schema" + "github.com/hetznercloud/hcloud-go/hcloud/schema" ) // LoadBalancerType represents a LoadBalancer type in the Hetzner Cloud. @@ -125,7 +109,7 @@ func (c *LoadBalancerTypeClient) All(ctx context.Context) ([]*LoadBalancerType, opts := LoadBalancerTypeListOpts{} opts.PerPage = 50 - _, err := c.client.all(func(page int) (*Response, error) { + err := c.client.all(func(page int) (*Response, error) { opts.Page = page LoadBalancerTypes, resp, err := c.List(ctx, opts) if err != nil { diff --git a/cluster-autoscaler/cloudprovider/hetzner/hcloud-go/hcloud/location.go b/cluster-autoscaler/cloudprovider/hetzner/hcloud-go/hcloud/location.go index e767455baea6..05f42329bc8c 100644 --- a/cluster-autoscaler/cloudprovider/hetzner/hcloud-go/hcloud/location.go +++ b/cluster-autoscaler/cloudprovider/hetzner/hcloud-go/hcloud/location.go @@ -1,19 +1,3 @@ -/* -Copyright 2018 The Kubernetes Authors. - -Licensed under the Apache License, Version 2.0 (the "License"); -you may not use this file except in compliance with the License. -You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - -Unless required by applicable law or agreed to in writing, software -distributed under the License is distributed on an "AS IS" BASIS, -WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -See the License for the specific language governing permissions and -limitations under the License. -*/ - package hcloud import ( @@ -22,7 +6,7 @@ import ( "net/url" "strconv" - "k8s.io/autoscaler/cluster-autoscaler/cloudprovider/hetzner/hcloud-go/hcloud/schema" + "github.com/hetznercloud/hcloud-go/hcloud/schema" ) // Location represents a location in the Hetzner Cloud. @@ -125,7 +109,7 @@ func (c *LocationClient) All(ctx context.Context) ([]*Location, error) { opts := LocationListOpts{} opts.PerPage = 50 - _, err := c.client.all(func(page int) (*Response, error) { + err := c.client.all(func(page int) (*Response, error) { opts.Page = page locations, resp, err := c.List(ctx, opts) if err != nil { diff --git a/cluster-autoscaler/cloudprovider/hetzner/hcloud-go/hcloud/network.go b/cluster-autoscaler/cloudprovider/hetzner/hcloud-go/hcloud/network.go index 7b9876a0fd78..2f39d858645a 100644 --- a/cluster-autoscaler/cloudprovider/hetzner/hcloud-go/hcloud/network.go +++ b/cluster-autoscaler/cloudprovider/hetzner/hcloud-go/hcloud/network.go @@ -1,19 +1,3 @@ -/* -Copyright 2018 The Kubernetes Authors. - -Licensed under the Apache License, Version 2.0 (the "License"); -you may not use this file except in compliance with the License. -You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - -Unless required by applicable law or agreed to in writing, software -distributed under the License is distributed on an "AS IS" BASIS, -WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -See the License for the specific language governing permissions and -limitations under the License. -*/ - package hcloud import ( @@ -27,7 +11,7 @@ import ( "strconv" "time" - "k8s.io/autoscaler/cluster-autoscaler/cloudprovider/hetzner/hcloud-go/hcloud/schema" + "github.com/hetznercloud/hcloud-go/hcloud/schema" ) // NetworkZone specifies a network zone. @@ -43,8 +27,9 @@ type NetworkSubnetType string // List of available network subnet types. const ( - NetworkSubnetTypeCloud NetworkSubnetType = "cloud" - NetworkSubnetTypeServer NetworkSubnetType = "server" + NetworkSubnetTypeCloud NetworkSubnetType = "cloud" + NetworkSubnetTypeServer NetworkSubnetType = "server" + NetworkSubnetTypeVSwitch NetworkSubnetType = "vswitch" ) // Network represents a network in the Hetzner Cloud. @@ -66,6 +51,7 @@ type NetworkSubnet struct { IPRange *net.IPNet NetworkZone NetworkZone Gateway net.IP + VSwitchID int } // NetworkRoute represents a route of a network. @@ -169,7 +155,7 @@ func (c *NetworkClient) All(ctx context.Context) ([]*Network, error) { func (c *NetworkClient) AllWithOpts(ctx context.Context, opts NetworkListOpts) ([]*Network, error) { var allNetworks []*Network - _, err := c.client.all(func(page int) (*Response, error) { + err := c.client.all(func(page int) (*Response, error) { opts.Page = page Networks, resp, err := c.List(ctx, opts) if err != nil { @@ -257,11 +243,15 @@ func (c *NetworkClient) Create(ctx context.Context, opts NetworkCreateOpts) (*Ne IPRange: opts.IPRange.String(), } for _, subnet := range opts.Subnets { - reqBody.Subnets = append(reqBody.Subnets, schema.NetworkSubnet{ + s := schema.NetworkSubnet{ Type: string(subnet.Type), IPRange: subnet.IPRange.String(), NetworkZone: string(subnet.NetworkZone), - }) + } + if subnet.VSwitchID != 0 { + s.VSwitchID = subnet.VSwitchID + } + reqBody.Subnets = append(reqBody.Subnets, s) } for _, route := range opts.Routes { reqBody.Routes = append(reqBody.Routes, schema.NetworkRoute{ @@ -332,6 +322,9 @@ func (c *NetworkClient) AddSubnet(ctx context.Context, network *Network, opts Ne if opts.Subnet.IPRange != nil { reqBody.IPRange = opts.Subnet.IPRange.String() } + if opts.Subnet.VSwitchID != 0 { + reqBody.VSwitchID = opts.Subnet.VSwitchID + } reqBodyData, err := json.Marshal(reqBody) if err != nil { return nil, nil, err diff --git a/cluster-autoscaler/cloudprovider/hetzner/hcloud-go/hcloud/pricing.go b/cluster-autoscaler/cloudprovider/hetzner/hcloud-go/hcloud/pricing.go index e8a2fff35031..ca2cb42046bf 100644 --- a/cluster-autoscaler/cloudprovider/hetzner/hcloud-go/hcloud/pricing.go +++ b/cluster-autoscaler/cloudprovider/hetzner/hcloud-go/hcloud/pricing.go @@ -1,25 +1,9 @@ -/* -Copyright 2018 The Kubernetes Authors. - -Licensed under the Apache License, Version 2.0 (the "License"); -you may not use this file except in compliance with the License. -You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - -Unless required by applicable law or agreed to in writing, software -distributed under the License is distributed on an "AS IS" BASIS, -WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -See the License for the specific language governing permissions and -limitations under the License. -*/ - package hcloud import ( "context" - "k8s.io/autoscaler/cluster-autoscaler/cloudprovider/hetzner/hcloud-go/hcloud/schema" + "github.com/hetznercloud/hcloud-go/hcloud/schema" ) // Pricing specifies pricing information for various resources. @@ -30,6 +14,7 @@ type Pricing struct { ServerBackup ServerBackupPricing ServerTypes []ServerTypePricing LoadBalancerTypes []LoadBalancerTypePricing + Volume VolumePricing } // Price represents a price. Net amount, gross amount, as well as VAT rate are @@ -57,6 +42,11 @@ type TrafficPricing struct { PerTB Price } +// VolumePricing provides pricing information for a Volume. +type VolumePricing struct { + PerGBMonthly Price +} + // ServerBackupPricing provides pricing information for server backups. type ServerBackupPricing struct { Percentage string diff --git a/cluster-autoscaler/cloudprovider/hetzner/hcloud-go/hcloud/resource.go b/cluster-autoscaler/cloudprovider/hetzner/hcloud-go/hcloud/resource.go new file mode 100644 index 000000000000..8a734dfd69da --- /dev/null +++ b/cluster-autoscaler/cloudprovider/hetzner/hcloud-go/hcloud/resource.go @@ -0,0 +1,7 @@ +package hcloud + +// Resource defines the schema of a resource. +type Resource struct { + ID int + Type string +} diff --git a/cluster-autoscaler/cloudprovider/hetzner/hcloud-go/hcloud/schema.go b/cluster-autoscaler/cloudprovider/hetzner/hcloud-go/hcloud/schema.go index f238aea35a3e..940fefc2c636 100644 --- a/cluster-autoscaler/cloudprovider/hetzner/hcloud-go/hcloud/schema.go +++ b/cluster-autoscaler/cloudprovider/hetzner/hcloud-go/hcloud/schema.go @@ -1,27 +1,12 @@ -/* -Copyright 2018 The Kubernetes Authors. - -Licensed under the Apache License, Version 2.0 (the "License"); -you may not use this file except in compliance with the License. -You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - -Unless required by applicable law or agreed to in writing, software -distributed under the License is distributed on an "AS IS" BASIS, -WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -See the License for the specific language governing permissions and -limitations under the License. -*/ - package hcloud import ( + "fmt" "net" "strconv" "time" - "k8s.io/autoscaler/cluster-autoscaler/cloudprovider/hetzner/hcloud-go/hcloud/schema" + "github.com/hetznercloud/hcloud-go/hcloud/schema" ) // This file provides converter functions to convert models in the @@ -55,9 +40,9 @@ func ActionFromSchema(s schema.Action) *Action { // ActionsFromSchema converts a slice of schema.Action to a slice of Action. func ActionsFromSchema(s []schema.Action) []*Action { - var actions []*Action - for _, a := range s { - actions = append(actions, ActionFromSchema(a)) + actions := make([]*Action, len(s)) + for i, a := range s { + actions[i] = ActionFromSchema(a) } return actions } @@ -199,6 +184,13 @@ func ServerPublicNetFromSchema(s schema.ServerPublicNet) ServerPublicNet { for _, id := range s.FloatingIPs { publicNet.FloatingIPs = append(publicNet.FloatingIPs, &FloatingIP{ID: id}) } + for _, fw := range s.Firewalls { + publicNet.Firewalls = append(publicNet.Firewalls, + &ServerFirewallStatus{ + Firewall: Firewall{ID: fw.ID}, + Status: FirewallStatus(fw.Status)}, + ) + } return publicNet } @@ -299,6 +291,7 @@ func ImageFromSchema(s schema.Image) *Image { Delete: s.Protection.Delete, }, Deprecated: s.Deprecated, + Deleted: s.Deleted, } if s.Name != nil { i.Name = *s.Name @@ -387,6 +380,7 @@ func NetworkSubnetFromSchema(s schema.NetworkSubnet) NetworkSubnet { Type: NetworkSubnetType(s.Type), NetworkZone: NetworkZone(s.NetworkZone), Gateway: net.ParseIP(s.Gateway), + VSwitchID: s.VSwitchID, } _, sn.IPRange, _ = net.ParseCIDR(s.IPRange) return sn @@ -562,6 +556,7 @@ func CertificateFromSchema(s schema.Certificate) *Certificate { c := &Certificate{ ID: s.ID, Name: s.Name, + Type: CertificateType(s.Type), Certificate: s.Certificate, Created: s.Created, NotValidBefore: s.NotValidBefore, @@ -569,12 +564,26 @@ func CertificateFromSchema(s schema.Certificate) *Certificate { DomainNames: s.DomainNames, Fingerprint: s.Fingerprint, } + if s.Status != nil { + c.Status = &CertificateStatus{ + Issuance: CertificateStatusType(s.Status.Issuance), + Renewal: CertificateStatusType(s.Status.Renewal), + } + if s.Status.Error != nil { + certErr := ErrorFromSchema(*s.Status.Error) + c.Status.Error = &certErr + } + } if len(s.Labels) > 0 { - c.Labels = make(map[string]string) + c.Labels = s.Labels } - for key, value := range s.Labels { - c.Labels[key] = value + if len(s.UsedBy) > 0 { + c.UsedBy = make([]CertificateUsedByRef, len(s.UsedBy)) + for i, ref := range s.UsedBy { + c.UsedBy[i] = CertificateUsedByRef{ID: ref.ID, Type: CertificateUsedByRefType(ref.Type)} + } } + return c } @@ -597,8 +606,7 @@ func ErrorFromSchema(s schema.Error) Error { Message: s.Message, } - switch d := s.Details.(type) { - case schema.ErrorDetailsInvalidInput: + if d, ok := s.Details.(schema.ErrorDetailsInvalidInput); ok { details := ErrorDetailsInvalidInput{ Fields: []ErrorDetailsInvalidInputField{}, } @@ -643,6 +651,14 @@ func PricingFromSchema(s schema.Pricing) Pricing { ServerBackup: ServerBackupPricing{ Percentage: s.ServerBackup.Percentage, }, + Volume: VolumePricing{ + PerGBMonthly: Price{ + Currency: s.Currency, + VATRate: s.VATRate, + Net: s.Volume.PricePerGBPerMonth.Net, + Gross: s.Volume.PricePerGBPerMonth.Gross, + }, + }, } for _, serverType := range s.ServerTypes { var pricings []ServerTypeLocationPricing @@ -701,6 +717,53 @@ func PricingFromSchema(s schema.Pricing) Pricing { return p } +// FirewallFromSchema converts a schema.Firewall to a Firewall. +func FirewallFromSchema(s schema.Firewall) *Firewall { + f := &Firewall{ + ID: s.ID, + Name: s.Name, + Labels: map[string]string{}, + Created: s.Created, + } + for key, value := range s.Labels { + f.Labels[key] = value + } + for _, res := range s.AppliedTo { + r := FirewallResource{Type: FirewallResourceType(res.Type)} + switch r.Type { + case FirewallResourceTypeLabelSelector: + r.LabelSelector = &FirewallResourceLabelSelector{Selector: res.LabelSelector.Selector} + case FirewallResourceTypeServer: + r.Server = &FirewallResourceServer{ID: res.Server.ID} + } + f.AppliedTo = append(f.AppliedTo, r) + } + for _, rule := range s.Rules { + sourceIPs := []net.IPNet{} + for _, sourceIP := range rule.SourceIPs { + _, mask, err := net.ParseCIDR(sourceIP) + if err == nil && mask != nil { + sourceIPs = append(sourceIPs, *mask) + } + } + destinationIPs := []net.IPNet{} + for _, destinationIP := range rule.DestinationIPs { + _, mask, err := net.ParseCIDR(destinationIP) + if err == nil && mask != nil { + destinationIPs = append(destinationIPs, *mask) + } + } + f.Rules = append(f.Rules, FirewallRule{ + Direction: FirewallRuleDirection(rule.Direction), + SourceIPs: sourceIPs, + DestinationIPs: destinationIPs, + Protocol: FirewallRuleProtocol(rule.Protocol), + Port: rule.Port, + }) + } + return f +} + func loadBalancerCreateOptsToSchema(opts LoadBalancerCreateOpts) schema.LoadBalancerCreateRequest { req := schema.LoadBalancerCreateRequest{ Name: opts.Name, @@ -760,8 +823,10 @@ func loadBalancerCreateOptsToSchema(opts LoadBalancerCreateOpts) schema.LoadBala StickySessions: service.HTTP.StickySessions, CookieName: service.HTTP.CookieName, } - if sec := service.HTTP.CookieLifetime.Seconds(); sec != 0 { - schemaService.HTTP.CookieLifetime = Int(int(sec)) + if service.HTTP.CookieLifetime != nil { + if sec := service.HTTP.CookieLifetime.Seconds(); sec != 0 { + schemaService.HTTP.CookieLifetime = Int(int(sec)) + } } if service.HTTP.Certificates != nil { certificates := []int{} @@ -906,3 +971,170 @@ func loadBalancerUpdateServiceOptsToSchema(opts LoadBalancerUpdateServiceOpts) s } return req } + +func firewallCreateOptsToSchema(opts FirewallCreateOpts) schema.FirewallCreateRequest { + req := schema.FirewallCreateRequest{ + Name: opts.Name, + } + if opts.Labels != nil { + req.Labels = &opts.Labels + } + for _, rule := range opts.Rules { + schemaRule := schema.FirewallRule{ + Direction: string(rule.Direction), + Protocol: string(rule.Protocol), + Port: rule.Port, + } + switch rule.Direction { + case FirewallRuleDirectionOut: + schemaRule.DestinationIPs = make([]string, len(rule.DestinationIPs)) + for i, destinationIP := range rule.DestinationIPs { + schemaRule.DestinationIPs[i] = destinationIP.String() + } + case FirewallRuleDirectionIn: + schemaRule.SourceIPs = make([]string, len(rule.SourceIPs)) + for i, sourceIP := range rule.SourceIPs { + schemaRule.SourceIPs[i] = sourceIP.String() + } + } + req.Rules = append(req.Rules, schemaRule) + } + for _, res := range opts.ApplyTo { + schemaFirewallResource := schema.FirewallResource{ + Type: string(res.Type), + } + switch res.Type { + case FirewallResourceTypeServer: + schemaFirewallResource.Server = &schema.FirewallResourceServer{ + ID: res.Server.ID, + } + case FirewallResourceTypeLabelSelector: + schemaFirewallResource.LabelSelector = &schema.FirewallResourceLabelSelector{Selector: res.LabelSelector.Selector} + } + + req.ApplyTo = append(req.ApplyTo, schemaFirewallResource) + } + return req +} + +func firewallSetRulesOptsToSchema(opts FirewallSetRulesOpts) schema.FirewallActionSetRulesRequest { + req := schema.FirewallActionSetRulesRequest{Rules: []schema.FirewallRule{}} + for _, rule := range opts.Rules { + schemaRule := schema.FirewallRule{ + Direction: string(rule.Direction), + Protocol: string(rule.Protocol), + Port: rule.Port, + } + switch rule.Direction { + case FirewallRuleDirectionOut: + schemaRule.DestinationIPs = make([]string, len(rule.DestinationIPs)) + for i, destinationIP := range rule.DestinationIPs { + schemaRule.DestinationIPs[i] = destinationIP.String() + } + case FirewallRuleDirectionIn: + schemaRule.SourceIPs = make([]string, len(rule.SourceIPs)) + for i, sourceIP := range rule.SourceIPs { + schemaRule.SourceIPs[i] = sourceIP.String() + } + } + req.Rules = append(req.Rules, schemaRule) + } + return req +} + +func firewallResourceToSchema(resource FirewallResource) schema.FirewallResource { + s := schema.FirewallResource{ + Type: string(resource.Type), + } + switch resource.Type { + case FirewallResourceTypeLabelSelector: + s.LabelSelector = &schema.FirewallResourceLabelSelector{Selector: resource.LabelSelector.Selector} + case FirewallResourceTypeServer: + s.Server = &schema.FirewallResourceServer{ID: resource.Server.ID} + } + return s +} + +func serverMetricsFromSchema(s *schema.ServerGetMetricsResponse) (*ServerMetrics, error) { + ms := ServerMetrics{ + Start: s.Metrics.Start, + End: s.Metrics.End, + Step: s.Metrics.Step, + } + + timeSeries := make(map[string][]ServerMetricsValue) + for tsName, v := range s.Metrics.TimeSeries { + vals := make([]ServerMetricsValue, len(v.Values)) + + for i, rawVal := range v.Values { + var val ServerMetricsValue + + tup, ok := rawVal.([]interface{}) + if !ok { + return nil, fmt.Errorf("failed to convert value to tuple: %v", rawVal) + } + if len(tup) != 2 { + return nil, fmt.Errorf("invalid tuple size: %d: %v", len(tup), rawVal) + } + ts, ok := tup[0].(float64) + if !ok { + return nil, fmt.Errorf("convert to float64: %v", tup[0]) + } + val.Timestamp = ts + + v, ok := tup[1].(string) + if !ok { + return nil, fmt.Errorf("not a string: %v", tup[1]) + } + val.Value = v + vals[i] = val + } + + timeSeries[tsName] = vals + } + ms.TimeSeries = timeSeries + + return &ms, nil +} + +func loadBalancerMetricsFromSchema(s *schema.LoadBalancerGetMetricsResponse) (*LoadBalancerMetrics, error) { + ms := LoadBalancerMetrics{ + Start: s.Metrics.Start, + End: s.Metrics.End, + Step: s.Metrics.Step, + } + + timeSeries := make(map[string][]LoadBalancerMetricsValue) + for tsName, v := range s.Metrics.TimeSeries { + vals := make([]LoadBalancerMetricsValue, len(v.Values)) + + for i, rawVal := range v.Values { + var val LoadBalancerMetricsValue + + tup, ok := rawVal.([]interface{}) + if !ok { + return nil, fmt.Errorf("failed to convert value to tuple: %v", rawVal) + } + if len(tup) != 2 { + return nil, fmt.Errorf("invalid tuple size: %d: %v", len(tup), rawVal) + } + ts, ok := tup[0].(float64) + if !ok { + return nil, fmt.Errorf("convert to float64: %v", tup[0]) + } + val.Timestamp = ts + + v, ok := tup[1].(string) + if !ok { + return nil, fmt.Errorf("not a string: %v", tup[1]) + } + val.Value = v + vals[i] = val + } + + timeSeries[tsName] = vals + } + ms.TimeSeries = timeSeries + + return &ms, nil +} diff --git a/cluster-autoscaler/cloudprovider/hetzner/hcloud-go/hcloud/schema/action.go b/cluster-autoscaler/cloudprovider/hetzner/hcloud-go/hcloud/schema/action.go index 1de4764ef29a..df4d7cf71b8f 100644 --- a/cluster-autoscaler/cloudprovider/hetzner/hcloud-go/hcloud/schema/action.go +++ b/cluster-autoscaler/cloudprovider/hetzner/hcloud-go/hcloud/schema/action.go @@ -1,19 +1,3 @@ -/* -Copyright 2018 The Kubernetes Authors. - -Licensed under the Apache License, Version 2.0 (the "License"); -you may not use this file except in compliance with the License. -You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - -Unless required by applicable law or agreed to in writing, software -distributed under the License is distributed on an "AS IS" BASIS, -WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -See the License for the specific language governing permissions and -limitations under the License. -*/ - package schema import "time" diff --git a/cluster-autoscaler/cloudprovider/hetzner/hcloud-go/hcloud/schema/certificate.go b/cluster-autoscaler/cloudprovider/hetzner/hcloud-go/hcloud/schema/certificate.go index 447962969cd4..a81b807a2939 100644 --- a/cluster-autoscaler/cloudprovider/hetzner/hcloud-go/hcloud/schema/certificate.go +++ b/cluster-autoscaler/cloudprovider/hetzner/hcloud-go/hcloud/schema/certificate.go @@ -1,34 +1,33 @@ -/* -Copyright 2018 The Kubernetes Authors. - -Licensed under the Apache License, Version 2.0 (the "License"); -you may not use this file except in compliance with the License. -You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - -Unless required by applicable law or agreed to in writing, software -distributed under the License is distributed on an "AS IS" BASIS, -WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -See the License for the specific language governing permissions and -limitations under the License. -*/ - package schema import "time" +// CertificateUsedByRef defines the schema of a resource using a certificate. +type CertificateUsedByRef struct { + ID int `json:"id"` + Type string `json:"type"` +} + +type CertificateStatusRef struct { + Issuance string `json:"issuance"` + Renewal string `json:"renewal"` + Error *Error `json:"error,omitempty"` +} + // Certificate defines the schema of an certificate. type Certificate struct { - ID int `json:"id"` - Name string `json:"name"` - Labels map[string]string `json:"labels"` - Certificate string `json:"certificate"` - Created time.Time `json:"created"` - NotValidBefore time.Time `json:"not_valid_before"` - NotValidAfter time.Time `json:"not_valid_after"` - DomainNames []string `json:"domain_names"` - Fingerprint string `json:"fingerprint"` + ID int `json:"id"` + Name string `json:"name"` + Labels map[string]string `json:"labels"` + Type string `json:"type"` + Certificate string `json:"certificate"` + Created time.Time `json:"created"` + NotValidBefore time.Time `json:"not_valid_before"` + NotValidAfter time.Time `json:"not_valid_after"` + DomainNames []string `json:"domain_names"` + Fingerprint string `json:"fingerprint"` + Status *CertificateStatusRef `json:"status"` + UsedBy []CertificateUsedByRef `json:"used_by"` } // CertificateListResponse defines the schema of the response when @@ -46,14 +45,17 @@ type CertificateGetResponse struct { // CertificateCreateRequest defines the schema of the request to create a certificate. type CertificateCreateRequest struct { Name string `json:"name"` - Certificate string `json:"certificate"` - PrivateKey string `json:"private_key"` + Type string `json:"type"` + DomainNames []string `json:"domain_names,omitempty"` + Certificate string `json:"certificate,omitempty"` + PrivateKey string `json:"private_key,omitempty"` Labels *map[string]string `json:"labels,omitempty"` } // CertificateCreateResponse defines the schema of the response when creating a certificate. type CertificateCreateResponse struct { Certificate Certificate `json:"certificate"` + Action *Action `json:"action"` } // CertificateUpdateRequest defines the schema of the request to update a certificate. @@ -66,3 +68,9 @@ type CertificateUpdateRequest struct { type CertificateUpdateResponse struct { Certificate Certificate `json:"certificate"` } + +// CertificateIssuanceRetryResponse defines the schema for the response of the +// retry issuance endpoint. +type CertificateIssuanceRetryResponse struct { + Action Action `json:"action"` +} diff --git a/cluster-autoscaler/cloudprovider/hetzner/hcloud-go/hcloud/schema/datacenter.go b/cluster-autoscaler/cloudprovider/hetzner/hcloud-go/hcloud/schema/datacenter.go index 3e939e72002b..3e8178e89a03 100644 --- a/cluster-autoscaler/cloudprovider/hetzner/hcloud-go/hcloud/schema/datacenter.go +++ b/cluster-autoscaler/cloudprovider/hetzner/hcloud-go/hcloud/schema/datacenter.go @@ -1,19 +1,3 @@ -/* -Copyright 2018 The Kubernetes Authors. - -Licensed under the Apache License, Version 2.0 (the "License"); -you may not use this file except in compliance with the License. -You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - -Unless required by applicable law or agreed to in writing, software -distributed under the License is distributed on an "AS IS" BASIS, -WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -See the License for the specific language governing permissions and -limitations under the License. -*/ - package schema // Datacenter defines the schema of a datacenter. diff --git a/cluster-autoscaler/cloudprovider/hetzner/hcloud-go/hcloud/schema/error.go b/cluster-autoscaler/cloudprovider/hetzner/hcloud-go/hcloud/schema/error.go index bf02bd06db31..2d5cf5ddd833 100644 --- a/cluster-autoscaler/cloudprovider/hetzner/hcloud-go/hcloud/schema/error.go +++ b/cluster-autoscaler/cloudprovider/hetzner/hcloud-go/hcloud/schema/error.go @@ -1,19 +1,3 @@ -/* -Copyright 2018 The Kubernetes Authors. - -Licensed under the Apache License, Version 2.0 (the "License"); -you may not use this file except in compliance with the License. -You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - -Unless required by applicable law or agreed to in writing, software -distributed under the License is distributed on an "AS IS" BASIS, -WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -See the License for the specific language governing permissions and -limitations under the License. -*/ - package schema import "encoding/json" @@ -33,8 +17,7 @@ func (e *Error) UnmarshalJSON(data []byte) (err error) { if err = json.Unmarshal(data, alias); err != nil { return } - switch e.Code { - case "invalid_input": + if e.Code == "invalid_input" { details := ErrorDetailsInvalidInput{} if err = json.Unmarshal(e.DetailsRaw, &details); err != nil { return diff --git a/cluster-autoscaler/cloudprovider/hetzner/hcloud-go/hcloud/schema/firewall.go b/cluster-autoscaler/cloudprovider/hetzner/hcloud-go/hcloud/schema/firewall.go new file mode 100644 index 000000000000..93c906657ca9 --- /dev/null +++ b/cluster-autoscaler/cloudprovider/hetzner/hcloud-go/hcloud/schema/firewall.go @@ -0,0 +1,104 @@ +package schema + +import "time" + +// Firewall defines the schema of a Firewall. +type Firewall struct { + ID int `json:"id"` + Name string `json:"name"` + Labels map[string]string `json:"labels"` + Created time.Time `json:"created"` + Rules []FirewallRule `json:"rules"` + AppliedTo []FirewallResource `json:"applied_to"` +} + +// FirewallRule defines the schema of a Firewall rule. +type FirewallRule struct { + Direction string `json:"direction"` + SourceIPs []string `json:"source_ips,omitempty"` + DestinationIPs []string `json:"destination_ips,omitempty"` + Protocol string `json:"protocol"` + Port *string `json:"port,omitempty"` +} + +// FirewallListResponse defines the schema of the response when listing Firewalls. +type FirewallListResponse struct { + Firewalls []Firewall `json:"firewalls"` +} + +// FirewallGetResponse defines the schema of the response when retrieving a single Firewall. +type FirewallGetResponse struct { + Firewall Firewall `json:"firewall"` +} + +// FirewallCreateRequest defines the schema of the request to create a Firewall. +type FirewallCreateRequest struct { + Name string `json:"name"` + Labels *map[string]string `json:"labels,omitempty"` + Rules []FirewallRule `json:"rules,omitempty"` + ApplyTo []FirewallResource `json:"apply_to,omitempty"` +} + +// FirewallResource defines the schema of a resource to apply the new Firewall on. +type FirewallResource struct { + Type string `json:"type"` + Server *FirewallResourceServer `json:"server,omitempty"` + LabelSelector *FirewallResourceLabelSelector `json:"label_selector,omitempty"` +} + +// FirewallResourceLabelSelector defines the schema of a LabelSelector to apply a Firewall on. +type FirewallResourceLabelSelector struct { + Selector string `json:"selector"` +} + +// FirewallResourceServer defines the schema of a Server to apply a Firewall on. +type FirewallResourceServer struct { + ID int `json:"id"` +} + +// FirewallCreateResponse defines the schema of the response when creating a Firewall. +type FirewallCreateResponse struct { + Firewall Firewall `json:"firewall"` + Actions []Action `json:"actions"` +} + +// FirewallUpdateRequest defines the schema of the request to update a Firewall. +type FirewallUpdateRequest struct { + Name *string `json:"name,omitempty"` + Labels *map[string]string `json:"labels,omitempty"` +} + +// FirewallUpdateResponse defines the schema of the response when updating a Firewall. +type FirewallUpdateResponse struct { + Firewall Firewall `json:"firewall"` +} + +// FirewallActionSetRulesRequest defines the schema of the request when setting Firewall rules. +type FirewallActionSetRulesRequest struct { + Rules []FirewallRule `json:"rules"` +} + +// FirewallActionSetRulesResponse defines the schema of the response when setting Firewall rules. +type FirewallActionSetRulesResponse struct { + Actions []Action `json:"actions"` +} + +// FirewallActionApplyToResourcesRequest defines the schema of the request when applying a Firewall on resources. +type FirewallActionApplyToResourcesRequest struct { + ApplyTo []FirewallResource `json:"apply_to"` +} + +// FirewallActionApplyToResourcesResponse defines the schema of the response when applying a Firewall on resources. +type FirewallActionApplyToResourcesResponse struct { + Actions []Action `json:"actions"` +} + +// FirewallActionRemoveFromResourcesRequest defines the schema of the request when removing a Firewall from resources. +type FirewallActionRemoveFromResourcesRequest struct { + RemoveFrom []FirewallResource `json:"remove_from"` +} + +// FirewallActionRemoveFromResourcesResponse defines the schema of the response when removing a Firewall from resources. +type FirewallActionRemoveFromResourcesResponse struct { + Actions []Action `json:"actions"` +} diff --git a/cluster-autoscaler/cloudprovider/hetzner/hcloud-go/hcloud/schema/floating_ip.go b/cluster-autoscaler/cloudprovider/hetzner/hcloud-go/hcloud/schema/floating_ip.go index d734e3664d0a..37295dad9c1c 100644 --- a/cluster-autoscaler/cloudprovider/hetzner/hcloud-go/hcloud/schema/floating_ip.go +++ b/cluster-autoscaler/cloudprovider/hetzner/hcloud-go/hcloud/schema/floating_ip.go @@ -1,19 +1,3 @@ -/* -Copyright 2018 The Kubernetes Authors. - -Licensed under the Apache License, Version 2.0 (the "License"); -you may not use this file except in compliance with the License. -You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - -Unless required by applicable law or agreed to in writing, software -distributed under the License is distributed on an "AS IS" BASIS, -WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -See the License for the specific language governing permissions and -limitations under the License. -*/ - package schema import "time" diff --git a/cluster-autoscaler/cloudprovider/hetzner/hcloud-go/hcloud/schema/image.go b/cluster-autoscaler/cloudprovider/hetzner/hcloud-go/hcloud/schema/image.go index 989c6ade995a..7a3be88751d6 100644 --- a/cluster-autoscaler/cloudprovider/hetzner/hcloud-go/hcloud/schema/image.go +++ b/cluster-autoscaler/cloudprovider/hetzner/hcloud-go/hcloud/schema/image.go @@ -1,19 +1,3 @@ -/* -Copyright 2018 The Kubernetes Authors. - -Licensed under the Apache License, Version 2.0 (the "License"); -you may not use this file except in compliance with the License. -You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - -Unless required by applicable law or agreed to in writing, software -distributed under the License is distributed on an "AS IS" BASIS, -WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -See the License for the specific language governing permissions and -limitations under the License. -*/ - package schema import "time" @@ -35,6 +19,7 @@ type Image struct { RapidDeploy bool `json:"rapid_deploy"` Protection ImageProtection `json:"protection"` Deprecated time.Time `json:"deprecated"` + Deleted time.Time `json:"deleted"` Labels map[string]string `json:"labels"` } diff --git a/cluster-autoscaler/cloudprovider/hetzner/hcloud-go/hcloud/schema/iso.go b/cluster-autoscaler/cloudprovider/hetzner/hcloud-go/hcloud/schema/iso.go index 764f0fc26391..e41046896999 100644 --- a/cluster-autoscaler/cloudprovider/hetzner/hcloud-go/hcloud/schema/iso.go +++ b/cluster-autoscaler/cloudprovider/hetzner/hcloud-go/hcloud/schema/iso.go @@ -1,19 +1,3 @@ -/* -Copyright 2018 The Kubernetes Authors. - -Licensed under the Apache License, Version 2.0 (the "License"); -you may not use this file except in compliance with the License. -You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - -Unless required by applicable law or agreed to in writing, software -distributed under the License is distributed on an "AS IS" BASIS, -WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -See the License for the specific language governing permissions and -limitations under the License. -*/ - package schema import "time" diff --git a/cluster-autoscaler/cloudprovider/hetzner/hcloud-go/hcloud/schema/load_balancer.go b/cluster-autoscaler/cloudprovider/hetzner/hcloud-go/hcloud/schema/load_balancer.go index 0dc559906635..b9dbaa9a7eae 100644 --- a/cluster-autoscaler/cloudprovider/hetzner/hcloud-go/hcloud/schema/load_balancer.go +++ b/cluster-autoscaler/cloudprovider/hetzner/hcloud-go/hcloud/schema/load_balancer.go @@ -1,19 +1,3 @@ -/* -Copyright 2018 The Kubernetes Authors. - -Licensed under the Apache License, Version 2.0 (the "License"); -you may not use this file except in compliance with the License. -You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - -Unless required by applicable law or agreed to in writing, software -distributed under the License is distributed on an "AS IS" BASIS, -WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -See the License for the specific language governing permissions and -limitations under the License. -*/ - package schema import "time" @@ -400,3 +384,20 @@ type LoadBalancerActionChangeTypeRequest struct { type LoadBalancerActionChangeTypeResponse struct { Action Action `json:"action"` } + +// LoadBalancerGetMetricsResponse defines the schema of the response when +// requesting metrics for a Load Balancer. +type LoadBalancerGetMetricsResponse struct { + Metrics struct { + Start time.Time `json:"start"` + End time.Time `json:"end"` + Step float64 `json:"step"` + TimeSeries map[string]LoadBalancerTimeSeriesVals `json:"time_series"` + } `json:"metrics"` +} + +// LoadBalancerTimeSeriesVals contains the values for a Load Balancer time +// series. +type LoadBalancerTimeSeriesVals struct { + Values []interface{} `json:"values"` +} diff --git a/cluster-autoscaler/cloudprovider/hetzner/hcloud-go/hcloud/schema/load_balancer_type.go b/cluster-autoscaler/cloudprovider/hetzner/hcloud-go/hcloud/schema/load_balancer_type.go index 815273841508..b0baf048914d 100644 --- a/cluster-autoscaler/cloudprovider/hetzner/hcloud-go/hcloud/schema/load_balancer_type.go +++ b/cluster-autoscaler/cloudprovider/hetzner/hcloud-go/hcloud/schema/load_balancer_type.go @@ -1,19 +1,3 @@ -/* -Copyright 2018 The Kubernetes Authors. - -Licensed under the Apache License, Version 2.0 (the "License"); -you may not use this file except in compliance with the License. -You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - -Unless required by applicable law or agreed to in writing, software -distributed under the License is distributed on an "AS IS" BASIS, -WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -See the License for the specific language governing permissions and -limitations under the License. -*/ - package schema // LoadBalancerType defines the schema of a LoadBalancer type. diff --git a/cluster-autoscaler/cloudprovider/hetzner/hcloud-go/hcloud/schema/location.go b/cluster-autoscaler/cloudprovider/hetzner/hcloud-go/hcloud/schema/location.go index 16ea709c8436..3dd58ad5e291 100644 --- a/cluster-autoscaler/cloudprovider/hetzner/hcloud-go/hcloud/schema/location.go +++ b/cluster-autoscaler/cloudprovider/hetzner/hcloud-go/hcloud/schema/location.go @@ -1,19 +1,3 @@ -/* -Copyright 2018 The Kubernetes Authors. - -Licensed under the Apache License, Version 2.0 (the "License"); -you may not use this file except in compliance with the License. -You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - -Unless required by applicable law or agreed to in writing, software -distributed under the License is distributed on an "AS IS" BASIS, -WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -See the License for the specific language governing permissions and -limitations under the License. -*/ - package schema // Location defines the schema of a location. diff --git a/cluster-autoscaler/cloudprovider/hetzner/hcloud-go/hcloud/schema/meta.go b/cluster-autoscaler/cloudprovider/hetzner/hcloud-go/hcloud/schema/meta.go index e527a2f45a22..9b06cda8c6d3 100644 --- a/cluster-autoscaler/cloudprovider/hetzner/hcloud-go/hcloud/schema/meta.go +++ b/cluster-autoscaler/cloudprovider/hetzner/hcloud-go/hcloud/schema/meta.go @@ -1,19 +1,3 @@ -/* -Copyright 2018 The Kubernetes Authors. - -Licensed under the Apache License, Version 2.0 (the "License"); -you may not use this file except in compliance with the License. -You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - -Unless required by applicable law or agreed to in writing, software -distributed under the License is distributed on an "AS IS" BASIS, -WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -See the License for the specific language governing permissions and -limitations under the License. -*/ - package schema // Meta defines the schema of meta information which may be included diff --git a/cluster-autoscaler/cloudprovider/hetzner/hcloud-go/hcloud/schema/network.go b/cluster-autoscaler/cloudprovider/hetzner/hcloud-go/hcloud/schema/network.go index f473f228723e..87e184d9525c 100644 --- a/cluster-autoscaler/cloudprovider/hetzner/hcloud-go/hcloud/schema/network.go +++ b/cluster-autoscaler/cloudprovider/hetzner/hcloud-go/hcloud/schema/network.go @@ -1,19 +1,3 @@ -/* -Copyright 2018 The Kubernetes Authors. - -Licensed under the Apache License, Version 2.0 (the "License"); -you may not use this file except in compliance with the License. -You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - -Unless required by applicable law or agreed to in writing, software -distributed under the License is distributed on an "AS IS" BASIS, -WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -See the License for the specific language governing permissions and -limitations under the License. -*/ - package schema import "time" @@ -36,7 +20,8 @@ type NetworkSubnet struct { Type string `json:"type"` IPRange string `json:"ip_range"` NetworkZone string `json:"network_zone"` - Gateway string `json:"gateway"` + Gateway string `json:"gateway,omitempty"` + VSwitchID int `json:"vswitch_id,omitempty"` } // NetworkRoute represents a route of a network. @@ -107,6 +92,7 @@ type NetworkActionAddSubnetRequest struct { IPRange string `json:"ip_range,omitempty"` NetworkZone string `json:"network_zone"` Gateway string `json:"gateway"` + VSwitchID int `json:"vswitch_id,omitempty"` } // NetworkActionAddSubnetResponse defines the schema of the response when diff --git a/cluster-autoscaler/cloudprovider/hetzner/hcloud-go/hcloud/schema/pricing.go b/cluster-autoscaler/cloudprovider/hetzner/hcloud-go/hcloud/schema/pricing.go index 248e352b023d..5126be5ad896 100644 --- a/cluster-autoscaler/cloudprovider/hetzner/hcloud-go/hcloud/schema/pricing.go +++ b/cluster-autoscaler/cloudprovider/hetzner/hcloud-go/hcloud/schema/pricing.go @@ -1,19 +1,3 @@ -/* -Copyright 2018 The Kubernetes Authors. - -Licensed under the Apache License, Version 2.0 (the "License"); -you may not use this file except in compliance with the License. -You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - -Unless required by applicable law or agreed to in writing, software -distributed under the License is distributed on an "AS IS" BASIS, -WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -See the License for the specific language governing permissions and -limitations under the License. -*/ - package schema // Pricing defines the schema for pricing information. @@ -26,6 +10,7 @@ type Pricing struct { ServerBackup PricingServerBackup `json:"server_backup"` ServerTypes []PricingServerType `json:"server_types"` LoadBalancerTypes []PricingLoadBalancerType `json:"load_balancer_types"` + Volume PricingVolume `json:"volume"` } // Price defines the schema of a single price with net and gross amount. @@ -49,6 +34,11 @@ type PricingTraffic struct { PricePerTB Price `json:"price_per_tb"` } +// PricingVolume defines the schema of pricing information for a Volume. +type PricingVolume struct { + PricePerGBPerMonth Price `json:"price_per_gb_month"` +} + // PricingServerBackup defines the schema of pricing information for server backups. type PricingServerBackup struct { Percentage string `json:"percentage"` diff --git a/cluster-autoscaler/cloudprovider/hetzner/hcloud-go/hcloud/schema/server.go b/cluster-autoscaler/cloudprovider/hetzner/hcloud-go/hcloud/schema/server.go index 649f2ce7e033..29dd020ac466 100644 --- a/cluster-autoscaler/cloudprovider/hetzner/hcloud-go/hcloud/schema/server.go +++ b/cluster-autoscaler/cloudprovider/hetzner/hcloud-go/hcloud/schema/server.go @@ -1,19 +1,3 @@ -/* -Copyright 2018 The Kubernetes Authors. - -Licensed under the Apache License, Version 2.0 (the "License"); -you may not use this file except in compliance with the License. -You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - -Unless required by applicable law or agreed to in writing, software -distributed under the License is distributed on an "AS IS" BASIS, -WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -See the License for the specific language governing permissions and -limitations under the License. -*/ - package schema import "time" @@ -54,6 +38,7 @@ type ServerPublicNet struct { IPv4 ServerPublicNetIPv4 `json:"ipv4"` IPv6 ServerPublicNetIPv6 `json:"ipv6"` FloatingIPs []int `json:"floating_ips"` + Firewalls []ServerFirewall `json:"firewalls"` } // ServerPublicNetIPv4 defines the schema of a server's public @@ -79,6 +64,13 @@ type ServerPublicNetIPv6DNSPtr struct { DNSPtr string `json:"dns_ptr"` } +// ServerFirewall defines the schema of a Server's Firewalls on +// a certain network interface. +type ServerFirewall struct { + ID int `json:"id"` + Status string `json:"status"` +} + // ServerPrivateNet defines the schema of a server's private network information. type ServerPrivateNet struct { Network int `json:"network"` @@ -102,18 +94,24 @@ type ServerListResponse struct { // ServerCreateRequest defines the schema for the request to // create a server. type ServerCreateRequest struct { - Name string `json:"name"` - ServerType interface{} `json:"server_type"` // int or string - Image interface{} `json:"image"` // int or string - SSHKeys []int `json:"ssh_keys,omitempty"` - Location string `json:"location,omitempty"` - Datacenter string `json:"datacenter,omitempty"` - UserData string `json:"user_data,omitempty"` - StartAfterCreate *bool `json:"start_after_create,omitempty"` - Labels *map[string]string `json:"labels,omitempty"` - Automount *bool `json:"automount,omitempty"` - Volumes []int `json:"volumes,omitempty"` - Networks []int `json:"networks,omitempty"` + Name string `json:"name"` + ServerType interface{} `json:"server_type"` // int or string + Image interface{} `json:"image"` // int or string + SSHKeys []int `json:"ssh_keys,omitempty"` + Location string `json:"location,omitempty"` + Datacenter string `json:"datacenter,omitempty"` + UserData string `json:"user_data,omitempty"` + StartAfterCreate *bool `json:"start_after_create,omitempty"` + Labels *map[string]string `json:"labels,omitempty"` + Automount *bool `json:"automount,omitempty"` + Volumes []int `json:"volumes,omitempty"` + Networks []int `json:"networks,omitempty"` + Firewalls []ServerCreateFirewalls `json:"firewalls,omitempty"` +} + +// ServerCreateFirewall defines which Firewalls to apply when creating a Server. +type ServerCreateFirewalls struct { + Firewall int `json:"firewall"` } // ServerCreateResponse defines the schema of the response when @@ -381,3 +379,19 @@ type ServerActionChangeAliasIPsRequest struct { type ServerActionChangeAliasIPsResponse struct { Action Action `json:"action"` } + +// ServerGetMetricsResponse defines the schema of the response when requesting +// metrics for a server. +type ServerGetMetricsResponse struct { + Metrics struct { + Start time.Time `json:"start"` + End time.Time `json:"end"` + Step float64 `json:"step"` + TimeSeries map[string]ServerTimeSeriesVals `json:"time_series"` + } `json:"metrics"` +} + +// ServerTimeSeriesVals contains the values for a Server time series. +type ServerTimeSeriesVals struct { + Values []interface{} `json:"values"` +} diff --git a/cluster-autoscaler/cloudprovider/hetzner/hcloud-go/hcloud/schema/server_type.go b/cluster-autoscaler/cloudprovider/hetzner/hcloud-go/hcloud/schema/server_type.go index 75be7ad7bba0..5d4f10b035d5 100644 --- a/cluster-autoscaler/cloudprovider/hetzner/hcloud-go/hcloud/schema/server_type.go +++ b/cluster-autoscaler/cloudprovider/hetzner/hcloud-go/hcloud/schema/server_type.go @@ -1,19 +1,3 @@ -/* -Copyright 2018 The Kubernetes Authors. - -Licensed under the Apache License, Version 2.0 (the "License"); -you may not use this file except in compliance with the License. -You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - -Unless required by applicable law or agreed to in writing, software -distributed under the License is distributed on an "AS IS" BASIS, -WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -See the License for the specific language governing permissions and -limitations under the License. -*/ - package schema // ServerType defines the schema of a server type. diff --git a/cluster-autoscaler/cloudprovider/hetzner/hcloud-go/hcloud/schema/ssh_key.go b/cluster-autoscaler/cloudprovider/hetzner/hcloud-go/hcloud/schema/ssh_key.go index b061e0d06541..f230b3ddd122 100644 --- a/cluster-autoscaler/cloudprovider/hetzner/hcloud-go/hcloud/schema/ssh_key.go +++ b/cluster-autoscaler/cloudprovider/hetzner/hcloud-go/hcloud/schema/ssh_key.go @@ -1,19 +1,3 @@ -/* -Copyright 2018 The Kubernetes Authors. - -Licensed under the Apache License, Version 2.0 (the "License"); -you may not use this file except in compliance with the License. -You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - -Unless required by applicable law or agreed to in writing, software -distributed under the License is distributed on an "AS IS" BASIS, -WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -See the License for the specific language governing permissions and -limitations under the License. -*/ - package schema import "time" diff --git a/cluster-autoscaler/cloudprovider/hetzner/hcloud-go/hcloud/schema/volume.go b/cluster-autoscaler/cloudprovider/hetzner/hcloud-go/hcloud/schema/volume.go index 4cef9aef5ef5..ad745ea97e6a 100644 --- a/cluster-autoscaler/cloudprovider/hetzner/hcloud-go/hcloud/schema/volume.go +++ b/cluster-autoscaler/cloudprovider/hetzner/hcloud-go/hcloud/schema/volume.go @@ -1,19 +1,3 @@ -/* -Copyright 2018 The Kubernetes Authors. - -Licensed under the Apache License, Version 2.0 (the "License"); -you may not use this file except in compliance with the License. -You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - -Unless required by applicable law or agreed to in writing, software -distributed under the License is distributed on an "AS IS" BASIS, -WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -See the License for the specific language governing permissions and -limitations under the License. -*/ - package schema import "time" diff --git a/cluster-autoscaler/cloudprovider/hetzner/hcloud-go/hcloud/server.go b/cluster-autoscaler/cloudprovider/hetzner/hcloud-go/hcloud/server.go index f7bbe06d6593..8d593c060769 100644 --- a/cluster-autoscaler/cloudprovider/hetzner/hcloud-go/hcloud/server.go +++ b/cluster-autoscaler/cloudprovider/hetzner/hcloud-go/hcloud/server.go @@ -1,19 +1,3 @@ -/* -Copyright 2018 The Kubernetes Authors. - -Licensed under the Apache License, Version 2.0 (the "License"); -you may not use this file except in compliance with the License. -You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - -Unless required by applicable law or agreed to in writing, software -distributed under the License is distributed on an "AS IS" BASIS, -WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -See the License for the specific language governing permissions and -limitations under the License. -*/ - package hcloud import ( @@ -23,11 +7,12 @@ import ( "errors" "fmt" "net" + "net/http" "net/url" "strconv" "time" - "k8s.io/autoscaler/cluster-autoscaler/cloudprovider/hetzner/hcloud-go/hcloud/schema" + "github.com/hetznercloud/hcloud-go/hcloud/schema" ) // Server represents a server in the Hetzner Cloud. @@ -91,11 +76,23 @@ const ( ServerStatusUnknown ServerStatus = "unknown" ) +// FirewallStatus specifies a Firewall's status. +type FirewallStatus string + +const ( + // FirewallStatusPending is the status when a Firewall is pending. + FirewallStatusPending FirewallStatus = "pending" + + // FirewallStatusApplied is the status when a Firewall is applied. + FirewallStatusApplied FirewallStatus = "applied" +) + // ServerPublicNet represents a server's public network. type ServerPublicNet struct { IPv4 ServerPublicNetIPv4 IPv6 ServerPublicNetIPv6 FloatingIPs []*FloatingIP + Firewalls []*ServerFirewallStatus } // ServerPublicNetIPv4 represents a server's public IPv4 address. @@ -105,7 +102,7 @@ type ServerPublicNetIPv4 struct { DNSPtr string } -// ServerPublicNetIPv6 represents a server's public IPv6 network and address. +// ServerPublicNetIPv6 represents a Server's public IPv6 network and address. type ServerPublicNetIPv6 struct { IP net.IP Network *net.IPNet @@ -113,7 +110,7 @@ type ServerPublicNetIPv6 struct { DNSPtr map[string]string } -// ServerPrivateNet defines the schema of a server's private network information. +// ServerPrivateNet defines the schema of a Server's private network information. type ServerPrivateNet struct { Network *Network IP net.IP @@ -126,6 +123,13 @@ func (s *ServerPublicNetIPv6) DNSPtrForIP(ip net.IP) string { return s.DNSPtr[ip.String()] } +// ServerFirewallStatus represents a Firewall and its status on a Server's +// network interface. +type ServerFirewallStatus struct { + Firewall Firewall + Status FirewallStatus +} + // ServerRescueType represents rescue types. type ServerRescueType string @@ -230,7 +234,7 @@ func (c *ServerClient) All(ctx context.Context) ([]*Server, error) { func (c *ServerClient) AllWithOpts(ctx context.Context, opts ServerListOpts) ([]*Server, error) { allServers := []*Server{} - _, err := c.client.all(func(page int) (*Response, error) { + err := c.client.all(func(page int) (*Response, error) { opts.Page = page servers, resp, err := c.List(ctx, opts) if err != nil { @@ -260,6 +264,12 @@ type ServerCreateOpts struct { Automount *bool Volumes []*Volume Networks []*Network + Firewalls []*ServerCreateFirewall +} + +// ServerCreateFirewall defines which Firewalls to apply when creating a Server. +type ServerCreateFirewall struct { + Firewall Firewall } // Validate checks if options are valid. @@ -320,7 +330,11 @@ func (c *ServerClient) Create(ctx context.Context, opts ServerCreateOpts) (Serve for _, network := range opts.Networks { reqBody.Networks = append(reqBody.Networks, network.ID) } - + for _, firewall := range opts.Firewalls { + reqBody.Firewalls = append(reqBody.Firewalls, schema.ServerCreateFirewalls{ + Firewall: firewall.Firewall.ID, + }) + } if opts.Location != nil { if opts.Location.ID != 0 { reqBody.Location = strconv.Itoa(opts.Location.ID) @@ -968,3 +982,91 @@ func (c *ServerClient) ChangeAliasIPs(ctx context.Context, server *Server, opts } return ActionFromSchema(respBody.Action), resp, err } + +// ServerMetricType is the type of available metrics for servers. +type ServerMetricType string + +// Available types of server metrics. See Hetzner Cloud API documentation for +// details. +const ( + ServerMetricCPU ServerMetricType = "cpu" + ServerMetricDisk ServerMetricType = "disk" + ServerMetricNetwork ServerMetricType = "network" +) + +// ServerGetMetricsOpts configures the call to get metrics for a Server. +type ServerGetMetricsOpts struct { + Types []ServerMetricType + Start time.Time + End time.Time + Step int +} + +func (o *ServerGetMetricsOpts) addQueryParams(req *http.Request) error { + query := req.URL.Query() + + if len(o.Types) == 0 { + return fmt.Errorf("no metric types specified") + } + for _, typ := range o.Types { + query.Add("type", string(typ)) + } + + if o.Start.IsZero() { + return fmt.Errorf("no start time specified") + } + query.Add("start", o.Start.Format(time.RFC3339)) + + if o.End.IsZero() { + return fmt.Errorf("no end time specified") + } + query.Add("end", o.End.Format(time.RFC3339)) + + if o.Step > 0 { + query.Add("step", strconv.Itoa(o.Step)) + } + req.URL.RawQuery = query.Encode() + + return nil +} + +// ServerMetrics contains the metrics requested for a Server. +type ServerMetrics struct { + Start time.Time + End time.Time + Step float64 + TimeSeries map[string][]ServerMetricsValue +} + +// ServerMetricsValue represents a single value in a time series of metrics. +type ServerMetricsValue struct { + Timestamp float64 + Value string +} + +// GetMetrics obtains metrics for Server. +func (c *ServerClient) GetMetrics(ctx context.Context, server *Server, opts ServerGetMetricsOpts) (*ServerMetrics, *Response, error) { + var respBody schema.ServerGetMetricsResponse + + if server == nil { + return nil, nil, fmt.Errorf("illegal argument: server is nil") + } + + path := fmt.Sprintf("/servers/%d/metrics", server.ID) + req, err := c.client.NewRequest(ctx, "GET", path, nil) + if err != nil { + return nil, nil, fmt.Errorf("new request: %v", err) + } + if err := opts.addQueryParams(req); err != nil { + return nil, nil, fmt.Errorf("add query params: %v", err) + } + resp, err := c.client.Do(req, &respBody) + if err != nil { + return nil, nil, fmt.Errorf("get metrics: %v", err) + } + ms, err := serverMetricsFromSchema(&respBody) + if err != nil { + return nil, nil, fmt.Errorf("convert response body: %v", err) + } + return ms, resp, nil +} diff --git a/cluster-autoscaler/cloudprovider/hetzner/hcloud-go/hcloud/server_type.go b/cluster-autoscaler/cloudprovider/hetzner/hcloud-go/hcloud/server_type.go index b32b124aa5d2..a681d0918e18 100644 --- a/cluster-autoscaler/cloudprovider/hetzner/hcloud-go/hcloud/server_type.go +++ b/cluster-autoscaler/cloudprovider/hetzner/hcloud-go/hcloud/server_type.go @@ -1,19 +1,3 @@ -/* -Copyright 2018 The Kubernetes Authors. - -Licensed under the Apache License, Version 2.0 (the "License"); -you may not use this file except in compliance with the License. -You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - -Unless required by applicable law or agreed to in writing, software -distributed under the License is distributed on an "AS IS" BASIS, -WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -See the License for the specific language governing permissions and -limitations under the License. -*/ - package hcloud import ( @@ -22,7 +6,7 @@ import ( "net/url" "strconv" - "k8s.io/autoscaler/cluster-autoscaler/cloudprovider/hetzner/hcloud-go/hcloud/schema" + "github.com/hetznercloud/hcloud-go/hcloud/schema" ) // ServerType represents a server type in the Hetzner Cloud. @@ -56,7 +40,7 @@ const ( // CPUTypeShared is the type for shared CPU. CPUTypeShared CPUType = "shared" - //CPUTypeDedicated is the type for dedicated CPU. + // CPUTypeDedicated is the type for dedicated CPU. CPUTypeDedicated CPUType = "dedicated" ) @@ -148,7 +132,7 @@ func (c *ServerTypeClient) All(ctx context.Context) ([]*ServerType, error) { opts := ServerTypeListOpts{} opts.PerPage = 50 - _, err := c.client.all(func(page int) (*Response, error) { + err := c.client.all(func(page int) (*Response, error) { opts.Page = page serverTypes, resp, err := c.List(ctx, opts) if err != nil { diff --git a/cluster-autoscaler/cloudprovider/hetzner/hcloud-go/hcloud/ssh_key.go b/cluster-autoscaler/cloudprovider/hetzner/hcloud-go/hcloud/ssh_key.go index ecba5da65e80..52195e770866 100644 --- a/cluster-autoscaler/cloudprovider/hetzner/hcloud-go/hcloud/ssh_key.go +++ b/cluster-autoscaler/cloudprovider/hetzner/hcloud-go/hcloud/ssh_key.go @@ -1,19 +1,3 @@ -/* -Copyright 2018 The Kubernetes Authors. - -Licensed under the Apache License, Version 2.0 (the "License"); -you may not use this file except in compliance with the License. -You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - -Unless required by applicable law or agreed to in writing, software -distributed under the License is distributed on an "AS IS" BASIS, -WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -See the License for the specific language governing permissions and -limitations under the License. -*/ - package hcloud import ( @@ -26,7 +10,7 @@ import ( "strconv" "time" - "k8s.io/autoscaler/cluster-autoscaler/cloudprovider/hetzner/hcloud-go/hcloud/schema" + "github.com/hetznercloud/hcloud-go/hcloud/schema" ) // SSHKey represents a SSH key in the Hetzner Cloud. @@ -142,7 +126,7 @@ func (c *SSHKeyClient) All(ctx context.Context) ([]*SSHKey, error) { func (c *SSHKeyClient) AllWithOpts(ctx context.Context, opts SSHKeyListOpts) ([]*SSHKey, error) { allSSHKeys := []*SSHKey{} - _, err := c.client.all(func(page int) (*Response, error) { + err := c.client.all(func(page int) (*Response, error) { opts.Page = page sshKeys, resp, err := c.List(ctx, opts) if err != nil { diff --git a/cluster-autoscaler/cloudprovider/hetzner/hcloud-go/hcloud/testing.go b/cluster-autoscaler/cloudprovider/hetzner/hcloud-go/hcloud/testing.go new file mode 100644 index 000000000000..a3cfb2f0cb02 --- /dev/null +++ b/cluster-autoscaler/cloudprovider/hetzner/hcloud-go/hcloud/testing.go @@ -0,0 +1,18 @@ +package hcloud + +import ( + "testing" + "time" +) + +const apiTimestampFormat = "2006-01-02T15:04:05-07:00" + +func mustParseTime(t *testing.T, layout, value string) time.Time { + t.Helper() + + ts, err := time.Parse(layout, value) + if err != nil { + t.Fatalf("parse time: layout %v: value %v: %v", layout, value, err) + } + return ts +} diff --git a/cluster-autoscaler/cloudprovider/hetzner/hcloud-go/hcloud/volume.go b/cluster-autoscaler/cloudprovider/hetzner/hcloud-go/hcloud/volume.go index 5fc01882f72e..53559365d8e3 100644 --- a/cluster-autoscaler/cloudprovider/hetzner/hcloud-go/hcloud/volume.go +++ b/cluster-autoscaler/cloudprovider/hetzner/hcloud-go/hcloud/volume.go @@ -1,19 +1,3 @@ -/* -Copyright 2018 The Kubernetes Authors. - -Licensed under the Apache License, Version 2.0 (the "License"); -you may not use this file except in compliance with the License. -You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - -Unless required by applicable law or agreed to in writing, software -distributed under the License is distributed on an "AS IS" BASIS, -WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -See the License for the specific language governing permissions and -limitations under the License. -*/ - package hcloud import ( @@ -26,7 +10,7 @@ import ( "strconv" "time" - "k8s.io/autoscaler/cluster-autoscaler/cloudprovider/hetzner/hcloud-go/hcloud/schema" + "github.com/hetznercloud/hcloud-go/hcloud/schema" ) // Volume represents a volume in the Hetzner Cloud. @@ -153,7 +137,7 @@ func (c *VolumeClient) All(ctx context.Context) ([]*Volume, error) { func (c *VolumeClient) AllWithOpts(ctx context.Context, opts VolumeListOpts) ([]*Volume, error) { allVolumes := []*Volume{} - _, err := c.client.all(func(page int) (*Response, error) { + err := c.client.all(func(page int) (*Response, error) { opts.Page = page volumes, resp, err := c.List(ctx, opts) if err != nil { From 598af979c992f8f31f8267d201dd6c1995ff0c6f Mon Sep 17 00:00:00 2001 From: Sergey Shevchenko Date: Thu, 8 Jul 2021 22:03:35 +0300 Subject: [PATCH 2/4] [ca]: Add firewall support for hcloud cloud provider Signed-off-by: Sergey Shevchenko --- .../cloudprovider/hetzner/README.md | 2 ++ .../cloudprovider/hetzner/hetzner_manager.go | 16 +++++++++++++--- .../cloudprovider/hetzner/hetzner_node_group.go | 4 ++++ 3 files changed, 19 insertions(+), 3 deletions(-) diff --git a/cluster-autoscaler/cloudprovider/hetzner/README.md b/cluster-autoscaler/cloudprovider/hetzner/README.md index 76197defe1a2..5fbad46a8787 100644 --- a/cluster-autoscaler/cloudprovider/hetzner/README.md +++ b/cluster-autoscaler/cloudprovider/hetzner/README.md @@ -12,6 +12,8 @@ The cluster autoscaler for Hetzner Cloud scales worker nodes. `HCLOUD_NETWORK` Default empty , The name of the network that is used in the cluster , @see https://docs.hetzner.cloud/#networks +`HCLOUD_FIREWALL` Default empty , The name of the firewall that is used in the cluster , @see https://docs.hetzner.cloud/#firewalls + `HCLOUD_SSH_KEY` Default empty , This SSH Key will have access to the fresh created server, @see https://docs.hetzner.cloud/#ssh-keys Node groups must be defined with the `--nodes=::::` flag. diff --git a/cluster-autoscaler/cloudprovider/hetzner/hetzner_manager.go b/cluster-autoscaler/cloudprovider/hetzner/hetzner_manager.go index f419b139385b..aee95efb31f2 100644 --- a/cluster-autoscaler/cloudprovider/hetzner/hetzner_manager.go +++ b/cluster-autoscaler/cloudprovider/hetzner/hetzner_manager.go @@ -44,6 +44,7 @@ type hetznerManager struct { image *hcloud.Image sshKey *hcloud.SSHKey network *hcloud.Network + firewall *hcloud.Firewall createTimeout time.Duration } @@ -95,9 +96,6 @@ func newManager() (*hetznerManager, error) { image = images[0] } - var network *hcloud.Network - networkName := os.Getenv("HCLOUD_NETWORK") - var sshKey *hcloud.SSHKey sshKeyName := os.Getenv("HCLOUD_SSH_KEY") if sshKeyName != "" { @@ -107,6 +105,8 @@ func newManager() (*hetznerManager, error) { } } + var network *hcloud.Network + networkName := os.Getenv("HCLOUD_NETWORK") if networkName != "" { network, _, err = client.Network.Get(ctx, networkName) if err != nil { @@ -121,6 +121,15 @@ func newManager() (*hetznerManager, error) { createTimeout = time.Duration(v) * time.Minute } + var firewall *hcloud.Firewall + firewallName := os.Getenv("HCLOUD_FIREWALL") + if firewallName != "" { + firewall, _, err = client.Firewall.Get(ctx, firewallName) + if err != nil { + return nil, fmt.Errorf("failed to get firewall error: %s", err) + } + } + m := &hetznerManager{ client: client, nodeGroups: make(map[string]*hetznerNodeGroup), @@ -128,6 +137,7 @@ func newManager() (*hetznerManager, error) { image: image, sshKey: sshKey, network: network, + firewall: firewall, createTimeout: createTimeout, apiCallContext: ctx, } diff --git a/cluster-autoscaler/cloudprovider/hetzner/hetzner_node_group.go b/cluster-autoscaler/cloudprovider/hetzner/hetzner_node_group.go index fcd6d978076e..c292109ca89e 100644 --- a/cluster-autoscaler/cloudprovider/hetzner/hetzner_node_group.go +++ b/cluster-autoscaler/cloudprovider/hetzner/hetzner_node_group.go @@ -365,6 +365,10 @@ func createServer(n *hetznerNodeGroup) error { if n.manager.network != nil { opts.Networks = []*hcloud.Network{n.manager.network} } + if n.manager.firewall != nil { + serverCreateFirewall := &hcloud.ServerCreateFirewall{Firewall: *n.manager.firewall} + opts.Firewalls = []*hcloud.ServerCreateFirewall{serverCreateFirewall} + } serverCreateResult, _, err := n.manager.client.Server.Create(n.manager.apiCallContext, opts) if err != nil { From 1c6a71e3468888fb3f8b210d8d20ba61a49118e8 Mon Sep 17 00:00:00 2001 From: Sergey Shevchenko Date: Mon, 26 Jul 2021 20:23:54 +0300 Subject: [PATCH 3/4] [ca]: Fix incorrect changes in hcloud-go api --- .../hetzner/hcloud-go/hcloud/action.go | 18 +++++++++++++++++- .../hetzner/hcloud-go/hcloud/certificate.go | 18 +++++++++++++++++- .../hetzner/hcloud-go/hcloud/client.go | 18 +++++++++++++++++- .../hetzner/hcloud-go/hcloud/datacenter.go | 18 +++++++++++++++++- .../hetzner/hcloud-go/hcloud/error.go | 16 ++++++++++++++++ .../hetzner/hcloud-go/hcloud/firewall.go | 18 +++++++++++++++++- .../hetzner/hcloud-go/hcloud/floating_ip.go | 18 +++++++++++++++++- .../hetzner/hcloud-go/hcloud/hcloud.go | 16 ++++++++++++++++ .../hetzner/hcloud-go/hcloud/helper.go | 16 ++++++++++++++++ .../hetzner/hcloud-go/hcloud/image.go | 18 +++++++++++++++++- .../hetzner/hcloud-go/hcloud/iso.go | 18 +++++++++++++++++- .../hetzner/hcloud-go/hcloud/load_balancer.go | 18 +++++++++++++++++- .../hcloud-go/hcloud/load_balancer_type.go | 18 +++++++++++++++++- .../hetzner/hcloud-go/hcloud/location.go | 18 +++++++++++++++++- .../hetzner/hcloud-go/hcloud/network.go | 18 +++++++++++++++++- .../hetzner/hcloud-go/hcloud/pricing.go | 18 +++++++++++++++++- .../hetzner/hcloud-go/hcloud/resource.go | 16 ++++++++++++++++ .../hetzner/hcloud-go/hcloud/schema.go | 18 +++++++++++++++++- .../hetzner/hcloud-go/hcloud/schema/action.go | 16 ++++++++++++++++ .../hcloud-go/hcloud/schema/certificate.go | 16 ++++++++++++++++ .../hcloud-go/hcloud/schema/datacenter.go | 16 ++++++++++++++++ .../hetzner/hcloud-go/hcloud/schema/error.go | 16 ++++++++++++++++ .../hcloud-go/hcloud/schema/firewall.go | 16 ++++++++++++++++ .../hcloud-go/hcloud/schema/floating_ip.go | 16 ++++++++++++++++ .../hetzner/hcloud-go/hcloud/schema/image.go | 16 ++++++++++++++++ .../hetzner/hcloud-go/hcloud/schema/iso.go | 16 ++++++++++++++++ .../hcloud-go/hcloud/schema/load_balancer.go | 16 ++++++++++++++++ .../hcloud/schema/load_balancer_type.go | 16 ++++++++++++++++ .../hcloud-go/hcloud/schema/location.go | 16 ++++++++++++++++ .../hetzner/hcloud-go/hcloud/schema/meta.go | 16 ++++++++++++++++ .../hetzner/hcloud-go/hcloud/schema/network.go | 16 ++++++++++++++++ .../hetzner/hcloud-go/hcloud/schema/pricing.go | 16 ++++++++++++++++ .../hetzner/hcloud-go/hcloud/schema/server.go | 16 ++++++++++++++++ .../hcloud-go/hcloud/schema/server_type.go | 16 ++++++++++++++++ .../hetzner/hcloud-go/hcloud/schema/ssh_key.go | 16 ++++++++++++++++ .../hetzner/hcloud-go/hcloud/schema/volume.go | 16 ++++++++++++++++ .../hetzner/hcloud-go/hcloud/server.go | 18 +++++++++++++++++- .../hetzner/hcloud-go/hcloud/server_type.go | 18 +++++++++++++++++- .../hetzner/hcloud-go/hcloud/ssh_key.go | 18 +++++++++++++++++- .../hetzner/hcloud-go/hcloud/testing.go | 16 ++++++++++++++++ .../hetzner/hcloud-go/hcloud/volume.go | 18 +++++++++++++++++- 41 files changed, 674 insertions(+), 18 deletions(-) diff --git a/cluster-autoscaler/cloudprovider/hetzner/hcloud-go/hcloud/action.go b/cluster-autoscaler/cloudprovider/hetzner/hcloud-go/hcloud/action.go index 622f7bf44b97..f6d25227115b 100644 --- a/cluster-autoscaler/cloudprovider/hetzner/hcloud-go/hcloud/action.go +++ b/cluster-autoscaler/cloudprovider/hetzner/hcloud-go/hcloud/action.go @@ -1,3 +1,19 @@ +/* +Copyright 2018 The Kubernetes Authors. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + package hcloud import ( @@ -6,7 +22,7 @@ import ( "net/url" "time" - "github.com/hetznercloud/hcloud-go/hcloud/schema" + "k8s.io/autoscaler/cluster-autoscaler/cloudprovider/hetzner/hcloud-go/hcloud/schema" ) // Action represents an action in the Hetzner Cloud. diff --git a/cluster-autoscaler/cloudprovider/hetzner/hcloud-go/hcloud/certificate.go b/cluster-autoscaler/cloudprovider/hetzner/hcloud-go/hcloud/certificate.go index 771a67e8b711..975eb0951f37 100644 --- a/cluster-autoscaler/cloudprovider/hetzner/hcloud-go/hcloud/certificate.go +++ b/cluster-autoscaler/cloudprovider/hetzner/hcloud-go/hcloud/certificate.go @@ -1,3 +1,19 @@ +/* +Copyright 2018 The Kubernetes Authors. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + package hcloud import ( @@ -10,7 +26,7 @@ import ( "strconv" "time" - "github.com/hetznercloud/hcloud-go/hcloud/schema" + "k8s.io/autoscaler/cluster-autoscaler/cloudprovider/hetzner/hcloud-go/hcloud/schema" ) // CertificateType is the type of available certificate types. diff --git a/cluster-autoscaler/cloudprovider/hetzner/hcloud-go/hcloud/client.go b/cluster-autoscaler/cloudprovider/hetzner/hcloud-go/hcloud/client.go index 25b713be9ddb..9af15d51721e 100644 --- a/cluster-autoscaler/cloudprovider/hetzner/hcloud-go/hcloud/client.go +++ b/cluster-autoscaler/cloudprovider/hetzner/hcloud-go/hcloud/client.go @@ -1,3 +1,19 @@ +/* +Copyright 2018 The Kubernetes Authors. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + package hcloud import ( @@ -15,7 +31,7 @@ import ( "strings" "time" - "github.com/hetznercloud/hcloud-go/hcloud/schema" + "k8s.io/autoscaler/cluster-autoscaler/cloudprovider/hetzner/hcloud-go/hcloud/schema" ) // Endpoint is the base URL of the API. diff --git a/cluster-autoscaler/cloudprovider/hetzner/hcloud-go/hcloud/datacenter.go b/cluster-autoscaler/cloudprovider/hetzner/hcloud-go/hcloud/datacenter.go index ae8b6c601111..05f31d6b0cb7 100644 --- a/cluster-autoscaler/cloudprovider/hetzner/hcloud-go/hcloud/datacenter.go +++ b/cluster-autoscaler/cloudprovider/hetzner/hcloud-go/hcloud/datacenter.go @@ -1,3 +1,19 @@ +/* +Copyright 2018 The Kubernetes Authors. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + package hcloud import ( @@ -6,7 +22,7 @@ import ( "net/url" "strconv" - "github.com/hetznercloud/hcloud-go/hcloud/schema" + "k8s.io/autoscaler/cluster-autoscaler/cloudprovider/hetzner/hcloud-go/hcloud/schema" ) // Datacenter represents a datacenter in the Hetzner Cloud. diff --git a/cluster-autoscaler/cloudprovider/hetzner/hcloud-go/hcloud/error.go b/cluster-autoscaler/cloudprovider/hetzner/hcloud-go/hcloud/error.go index d54de70667d2..be81fbb0bf2b 100644 --- a/cluster-autoscaler/cloudprovider/hetzner/hcloud-go/hcloud/error.go +++ b/cluster-autoscaler/cloudprovider/hetzner/hcloud-go/hcloud/error.go @@ -1,3 +1,19 @@ +/* +Copyright 2018 The Kubernetes Authors. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + package hcloud import "fmt" diff --git a/cluster-autoscaler/cloudprovider/hetzner/hcloud-go/hcloud/firewall.go b/cluster-autoscaler/cloudprovider/hetzner/hcloud-go/hcloud/firewall.go index ee3a80f22878..ca9889ff9a65 100644 --- a/cluster-autoscaler/cloudprovider/hetzner/hcloud-go/hcloud/firewall.go +++ b/cluster-autoscaler/cloudprovider/hetzner/hcloud-go/hcloud/firewall.go @@ -1,3 +1,19 @@ +/* +Copyright 2018 The Kubernetes Authors. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + package hcloud import ( @@ -11,7 +27,7 @@ import ( "strconv" "time" - "github.com/hetznercloud/hcloud-go/hcloud/schema" + "k8s.io/autoscaler/cluster-autoscaler/cloudprovider/hetzner/hcloud-go/hcloud/schema" ) // Firewall represents a Firewall in the Hetzner Cloud. diff --git a/cluster-autoscaler/cloudprovider/hetzner/hcloud-go/hcloud/floating_ip.go b/cluster-autoscaler/cloudprovider/hetzner/hcloud-go/hcloud/floating_ip.go index d8a6d0f5fdcb..37db55192629 100644 --- a/cluster-autoscaler/cloudprovider/hetzner/hcloud-go/hcloud/floating_ip.go +++ b/cluster-autoscaler/cloudprovider/hetzner/hcloud-go/hcloud/floating_ip.go @@ -1,3 +1,19 @@ +/* +Copyright 2018 The Kubernetes Authors. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + package hcloud import ( @@ -11,7 +27,7 @@ import ( "strconv" "time" - "github.com/hetznercloud/hcloud-go/hcloud/schema" + "k8s.io/autoscaler/cluster-autoscaler/cloudprovider/hetzner/hcloud-go/hcloud/schema" ) // FloatingIP represents a Floating IP in the Hetzner Cloud. diff --git a/cluster-autoscaler/cloudprovider/hetzner/hcloud-go/hcloud/hcloud.go b/cluster-autoscaler/cloudprovider/hetzner/hcloud-go/hcloud/hcloud.go index fcdcc54b8b9d..879f39b22463 100644 --- a/cluster-autoscaler/cloudprovider/hetzner/hcloud-go/hcloud/hcloud.go +++ b/cluster-autoscaler/cloudprovider/hetzner/hcloud-go/hcloud/hcloud.go @@ -1,3 +1,19 @@ +/* +Copyright 2018 The Kubernetes Authors. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + // Package hcloud is a library for the Hetzner Cloud API. package hcloud diff --git a/cluster-autoscaler/cloudprovider/hetzner/hcloud-go/hcloud/helper.go b/cluster-autoscaler/cloudprovider/hetzner/hcloud-go/hcloud/helper.go index e8e264267cc1..537607883e46 100644 --- a/cluster-autoscaler/cloudprovider/hetzner/hcloud-go/hcloud/helper.go +++ b/cluster-autoscaler/cloudprovider/hetzner/hcloud-go/hcloud/helper.go @@ -1,3 +1,19 @@ +/* +Copyright 2018 The Kubernetes Authors. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + package hcloud import "time" diff --git a/cluster-autoscaler/cloudprovider/hetzner/hcloud-go/hcloud/image.go b/cluster-autoscaler/cloudprovider/hetzner/hcloud-go/hcloud/image.go index 0867aac0d822..920f094f8a16 100644 --- a/cluster-autoscaler/cloudprovider/hetzner/hcloud-go/hcloud/image.go +++ b/cluster-autoscaler/cloudprovider/hetzner/hcloud-go/hcloud/image.go @@ -1,3 +1,19 @@ +/* +Copyright 2018 The Kubernetes Authors. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + package hcloud import ( @@ -9,7 +25,7 @@ import ( "strconv" "time" - "github.com/hetznercloud/hcloud-go/hcloud/schema" + "k8s.io/autoscaler/cluster-autoscaler/cloudprovider/hetzner/hcloud-go/hcloud/schema" ) // Image represents an Image in the Hetzner Cloud. diff --git a/cluster-autoscaler/cloudprovider/hetzner/hcloud-go/hcloud/iso.go b/cluster-autoscaler/cloudprovider/hetzner/hcloud-go/hcloud/iso.go index b3d97bade711..57679be585bc 100644 --- a/cluster-autoscaler/cloudprovider/hetzner/hcloud-go/hcloud/iso.go +++ b/cluster-autoscaler/cloudprovider/hetzner/hcloud-go/hcloud/iso.go @@ -1,3 +1,19 @@ +/* +Copyright 2018 The Kubernetes Authors. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + package hcloud import ( @@ -7,7 +23,7 @@ import ( "strconv" "time" - "github.com/hetznercloud/hcloud-go/hcloud/schema" + "k8s.io/autoscaler/cluster-autoscaler/cloudprovider/hetzner/hcloud-go/hcloud/schema" ) // ISO represents an ISO image in the Hetzner Cloud. diff --git a/cluster-autoscaler/cloudprovider/hetzner/hcloud-go/hcloud/load_balancer.go b/cluster-autoscaler/cloudprovider/hetzner/hcloud-go/hcloud/load_balancer.go index d39512778f10..0cdc4b223cf6 100644 --- a/cluster-autoscaler/cloudprovider/hetzner/hcloud-go/hcloud/load_balancer.go +++ b/cluster-autoscaler/cloudprovider/hetzner/hcloud-go/hcloud/load_balancer.go @@ -1,3 +1,19 @@ +/* +Copyright 2018 The Kubernetes Authors. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + package hcloud import ( @@ -11,7 +27,7 @@ import ( "strconv" "time" - "github.com/hetznercloud/hcloud-go/hcloud/schema" + "k8s.io/autoscaler/cluster-autoscaler/cloudprovider/hetzner/hcloud-go/hcloud/schema" ) // LoadBalancer represents a Load Balancer in the Hetzner Cloud. diff --git a/cluster-autoscaler/cloudprovider/hetzner/hcloud-go/hcloud/load_balancer_type.go b/cluster-autoscaler/cloudprovider/hetzner/hcloud-go/hcloud/load_balancer_type.go index 73800048fde7..4be70e072d78 100644 --- a/cluster-autoscaler/cloudprovider/hetzner/hcloud-go/hcloud/load_balancer_type.go +++ b/cluster-autoscaler/cloudprovider/hetzner/hcloud-go/hcloud/load_balancer_type.go @@ -1,3 +1,19 @@ +/* +Copyright 2018 The Kubernetes Authors. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + package hcloud import ( @@ -6,7 +22,7 @@ import ( "net/url" "strconv" - "github.com/hetznercloud/hcloud-go/hcloud/schema" + "k8s.io/autoscaler/cluster-autoscaler/cloudprovider/hetzner/hcloud-go/hcloud/schema" ) // LoadBalancerType represents a LoadBalancer type in the Hetzner Cloud. diff --git a/cluster-autoscaler/cloudprovider/hetzner/hcloud-go/hcloud/location.go b/cluster-autoscaler/cloudprovider/hetzner/hcloud-go/hcloud/location.go index 05f42329bc8c..8d0838da842b 100644 --- a/cluster-autoscaler/cloudprovider/hetzner/hcloud-go/hcloud/location.go +++ b/cluster-autoscaler/cloudprovider/hetzner/hcloud-go/hcloud/location.go @@ -1,3 +1,19 @@ +/* +Copyright 2018 The Kubernetes Authors. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + package hcloud import ( @@ -6,7 +22,7 @@ import ( "net/url" "strconv" - "github.com/hetznercloud/hcloud-go/hcloud/schema" + "k8s.io/autoscaler/cluster-autoscaler/cloudprovider/hetzner/hcloud-go/hcloud/schema" ) // Location represents a location in the Hetzner Cloud. diff --git a/cluster-autoscaler/cloudprovider/hetzner/hcloud-go/hcloud/network.go b/cluster-autoscaler/cloudprovider/hetzner/hcloud-go/hcloud/network.go index 2f39d858645a..fa8baff5c67a 100644 --- a/cluster-autoscaler/cloudprovider/hetzner/hcloud-go/hcloud/network.go +++ b/cluster-autoscaler/cloudprovider/hetzner/hcloud-go/hcloud/network.go @@ -1,3 +1,19 @@ +/* +Copyright 2018 The Kubernetes Authors. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + package hcloud import ( @@ -11,7 +27,7 @@ import ( "strconv" "time" - "github.com/hetznercloud/hcloud-go/hcloud/schema" + "k8s.io/autoscaler/cluster-autoscaler/cloudprovider/hetzner/hcloud-go/hcloud/schema" ) // NetworkZone specifies a network zone. diff --git a/cluster-autoscaler/cloudprovider/hetzner/hcloud-go/hcloud/pricing.go b/cluster-autoscaler/cloudprovider/hetzner/hcloud-go/hcloud/pricing.go index ca2cb42046bf..6325bd8330ee 100644 --- a/cluster-autoscaler/cloudprovider/hetzner/hcloud-go/hcloud/pricing.go +++ b/cluster-autoscaler/cloudprovider/hetzner/hcloud-go/hcloud/pricing.go @@ -1,9 +1,25 @@ +/* +Copyright 2018 The Kubernetes Authors. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + package hcloud import ( "context" - "github.com/hetznercloud/hcloud-go/hcloud/schema" + "k8s.io/autoscaler/cluster-autoscaler/cloudprovider/hetzner/hcloud-go/hcloud/schema" ) // Pricing specifies pricing information for various resources. diff --git a/cluster-autoscaler/cloudprovider/hetzner/hcloud-go/hcloud/resource.go b/cluster-autoscaler/cloudprovider/hetzner/hcloud-go/hcloud/resource.go index 8a734dfd69da..2f72428ad040 100644 --- a/cluster-autoscaler/cloudprovider/hetzner/hcloud-go/hcloud/resource.go +++ b/cluster-autoscaler/cloudprovider/hetzner/hcloud-go/hcloud/resource.go @@ -1,3 +1,19 @@ +/* +Copyright 2018 The Kubernetes Authors. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + package hcloud // Resource defines the schema of a resource. diff --git a/cluster-autoscaler/cloudprovider/hetzner/hcloud-go/hcloud/schema.go b/cluster-autoscaler/cloudprovider/hetzner/hcloud-go/hcloud/schema.go index 940fefc2c636..641b762607b1 100644 --- a/cluster-autoscaler/cloudprovider/hetzner/hcloud-go/hcloud/schema.go +++ b/cluster-autoscaler/cloudprovider/hetzner/hcloud-go/hcloud/schema.go @@ -1,3 +1,19 @@ +/* +Copyright 2018 The Kubernetes Authors. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + package hcloud import ( @@ -6,7 +22,7 @@ import ( "strconv" "time" - "github.com/hetznercloud/hcloud-go/hcloud/schema" + "k8s.io/autoscaler/cluster-autoscaler/cloudprovider/hetzner/hcloud-go/hcloud/schema" ) // This file provides converter functions to convert models in the diff --git a/cluster-autoscaler/cloudprovider/hetzner/hcloud-go/hcloud/schema/action.go b/cluster-autoscaler/cloudprovider/hetzner/hcloud-go/hcloud/schema/action.go index df4d7cf71b8f..1de4764ef29a 100644 --- a/cluster-autoscaler/cloudprovider/hetzner/hcloud-go/hcloud/schema/action.go +++ b/cluster-autoscaler/cloudprovider/hetzner/hcloud-go/hcloud/schema/action.go @@ -1,3 +1,19 @@ +/* +Copyright 2018 The Kubernetes Authors. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + package schema import "time" diff --git a/cluster-autoscaler/cloudprovider/hetzner/hcloud-go/hcloud/schema/certificate.go b/cluster-autoscaler/cloudprovider/hetzner/hcloud-go/hcloud/schema/certificate.go index a81b807a2939..cafb726619d9 100644 --- a/cluster-autoscaler/cloudprovider/hetzner/hcloud-go/hcloud/schema/certificate.go +++ b/cluster-autoscaler/cloudprovider/hetzner/hcloud-go/hcloud/schema/certificate.go @@ -1,3 +1,19 @@ +/* +Copyright 2018 The Kubernetes Authors. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + package schema import "time" diff --git a/cluster-autoscaler/cloudprovider/hetzner/hcloud-go/hcloud/schema/datacenter.go b/cluster-autoscaler/cloudprovider/hetzner/hcloud-go/hcloud/schema/datacenter.go index 3e8178e89a03..3e939e72002b 100644 --- a/cluster-autoscaler/cloudprovider/hetzner/hcloud-go/hcloud/schema/datacenter.go +++ b/cluster-autoscaler/cloudprovider/hetzner/hcloud-go/hcloud/schema/datacenter.go @@ -1,3 +1,19 @@ +/* +Copyright 2018 The Kubernetes Authors. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + package schema // Datacenter defines the schema of a datacenter. diff --git a/cluster-autoscaler/cloudprovider/hetzner/hcloud-go/hcloud/schema/error.go b/cluster-autoscaler/cloudprovider/hetzner/hcloud-go/hcloud/schema/error.go index 2d5cf5ddd833..8b15a8e99182 100644 --- a/cluster-autoscaler/cloudprovider/hetzner/hcloud-go/hcloud/schema/error.go +++ b/cluster-autoscaler/cloudprovider/hetzner/hcloud-go/hcloud/schema/error.go @@ -1,3 +1,19 @@ +/* +Copyright 2018 The Kubernetes Authors. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + package schema import "encoding/json" diff --git a/cluster-autoscaler/cloudprovider/hetzner/hcloud-go/hcloud/schema/firewall.go b/cluster-autoscaler/cloudprovider/hetzner/hcloud-go/hcloud/schema/firewall.go index 93c906657ca9..da94e9f7e997 100644 --- a/cluster-autoscaler/cloudprovider/hetzner/hcloud-go/hcloud/schema/firewall.go +++ b/cluster-autoscaler/cloudprovider/hetzner/hcloud-go/hcloud/schema/firewall.go @@ -1,3 +1,19 @@ +/* +Copyright 2018 The Kubernetes Authors. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + package schema import "time" diff --git a/cluster-autoscaler/cloudprovider/hetzner/hcloud-go/hcloud/schema/floating_ip.go b/cluster-autoscaler/cloudprovider/hetzner/hcloud-go/hcloud/schema/floating_ip.go index 37295dad9c1c..d734e3664d0a 100644 --- a/cluster-autoscaler/cloudprovider/hetzner/hcloud-go/hcloud/schema/floating_ip.go +++ b/cluster-autoscaler/cloudprovider/hetzner/hcloud-go/hcloud/schema/floating_ip.go @@ -1,3 +1,19 @@ +/* +Copyright 2018 The Kubernetes Authors. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + package schema import "time" diff --git a/cluster-autoscaler/cloudprovider/hetzner/hcloud-go/hcloud/schema/image.go b/cluster-autoscaler/cloudprovider/hetzner/hcloud-go/hcloud/schema/image.go index 7a3be88751d6..99d1e7aed197 100644 --- a/cluster-autoscaler/cloudprovider/hetzner/hcloud-go/hcloud/schema/image.go +++ b/cluster-autoscaler/cloudprovider/hetzner/hcloud-go/hcloud/schema/image.go @@ -1,3 +1,19 @@ +/* +Copyright 2018 The Kubernetes Authors. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + package schema import "time" diff --git a/cluster-autoscaler/cloudprovider/hetzner/hcloud-go/hcloud/schema/iso.go b/cluster-autoscaler/cloudprovider/hetzner/hcloud-go/hcloud/schema/iso.go index e41046896999..764f0fc26391 100644 --- a/cluster-autoscaler/cloudprovider/hetzner/hcloud-go/hcloud/schema/iso.go +++ b/cluster-autoscaler/cloudprovider/hetzner/hcloud-go/hcloud/schema/iso.go @@ -1,3 +1,19 @@ +/* +Copyright 2018 The Kubernetes Authors. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + package schema import "time" diff --git a/cluster-autoscaler/cloudprovider/hetzner/hcloud-go/hcloud/schema/load_balancer.go b/cluster-autoscaler/cloudprovider/hetzner/hcloud-go/hcloud/schema/load_balancer.go index b9dbaa9a7eae..bf3a2525819e 100644 --- a/cluster-autoscaler/cloudprovider/hetzner/hcloud-go/hcloud/schema/load_balancer.go +++ b/cluster-autoscaler/cloudprovider/hetzner/hcloud-go/hcloud/schema/load_balancer.go @@ -1,3 +1,19 @@ +/* +Copyright 2018 The Kubernetes Authors. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + package schema import "time" diff --git a/cluster-autoscaler/cloudprovider/hetzner/hcloud-go/hcloud/schema/load_balancer_type.go b/cluster-autoscaler/cloudprovider/hetzner/hcloud-go/hcloud/schema/load_balancer_type.go index b0baf048914d..815273841508 100644 --- a/cluster-autoscaler/cloudprovider/hetzner/hcloud-go/hcloud/schema/load_balancer_type.go +++ b/cluster-autoscaler/cloudprovider/hetzner/hcloud-go/hcloud/schema/load_balancer_type.go @@ -1,3 +1,19 @@ +/* +Copyright 2018 The Kubernetes Authors. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + package schema // LoadBalancerType defines the schema of a LoadBalancer type. diff --git a/cluster-autoscaler/cloudprovider/hetzner/hcloud-go/hcloud/schema/location.go b/cluster-autoscaler/cloudprovider/hetzner/hcloud-go/hcloud/schema/location.go index 3dd58ad5e291..16ea709c8436 100644 --- a/cluster-autoscaler/cloudprovider/hetzner/hcloud-go/hcloud/schema/location.go +++ b/cluster-autoscaler/cloudprovider/hetzner/hcloud-go/hcloud/schema/location.go @@ -1,3 +1,19 @@ +/* +Copyright 2018 The Kubernetes Authors. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + package schema // Location defines the schema of a location. diff --git a/cluster-autoscaler/cloudprovider/hetzner/hcloud-go/hcloud/schema/meta.go b/cluster-autoscaler/cloudprovider/hetzner/hcloud-go/hcloud/schema/meta.go index 9b06cda8c6d3..e527a2f45a22 100644 --- a/cluster-autoscaler/cloudprovider/hetzner/hcloud-go/hcloud/schema/meta.go +++ b/cluster-autoscaler/cloudprovider/hetzner/hcloud-go/hcloud/schema/meta.go @@ -1,3 +1,19 @@ +/* +Copyright 2018 The Kubernetes Authors. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + package schema // Meta defines the schema of meta information which may be included diff --git a/cluster-autoscaler/cloudprovider/hetzner/hcloud-go/hcloud/schema/network.go b/cluster-autoscaler/cloudprovider/hetzner/hcloud-go/hcloud/schema/network.go index 87e184d9525c..7ca287a1337d 100644 --- a/cluster-autoscaler/cloudprovider/hetzner/hcloud-go/hcloud/schema/network.go +++ b/cluster-autoscaler/cloudprovider/hetzner/hcloud-go/hcloud/schema/network.go @@ -1,3 +1,19 @@ +/* +Copyright 2018 The Kubernetes Authors. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + package schema import "time" diff --git a/cluster-autoscaler/cloudprovider/hetzner/hcloud-go/hcloud/schema/pricing.go b/cluster-autoscaler/cloudprovider/hetzner/hcloud-go/hcloud/schema/pricing.go index 5126be5ad896..3cb8c099ee11 100644 --- a/cluster-autoscaler/cloudprovider/hetzner/hcloud-go/hcloud/schema/pricing.go +++ b/cluster-autoscaler/cloudprovider/hetzner/hcloud-go/hcloud/schema/pricing.go @@ -1,3 +1,19 @@ +/* +Copyright 2018 The Kubernetes Authors. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + package schema // Pricing defines the schema for pricing information. diff --git a/cluster-autoscaler/cloudprovider/hetzner/hcloud-go/hcloud/schema/server.go b/cluster-autoscaler/cloudprovider/hetzner/hcloud-go/hcloud/schema/server.go index 29dd020ac466..d04be6319fc2 100644 --- a/cluster-autoscaler/cloudprovider/hetzner/hcloud-go/hcloud/schema/server.go +++ b/cluster-autoscaler/cloudprovider/hetzner/hcloud-go/hcloud/schema/server.go @@ -1,3 +1,19 @@ +/* +Copyright 2018 The Kubernetes Authors. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + package schema import "time" diff --git a/cluster-autoscaler/cloudprovider/hetzner/hcloud-go/hcloud/schema/server_type.go b/cluster-autoscaler/cloudprovider/hetzner/hcloud-go/hcloud/schema/server_type.go index 5d4f10b035d5..75be7ad7bba0 100644 --- a/cluster-autoscaler/cloudprovider/hetzner/hcloud-go/hcloud/schema/server_type.go +++ b/cluster-autoscaler/cloudprovider/hetzner/hcloud-go/hcloud/schema/server_type.go @@ -1,3 +1,19 @@ +/* +Copyright 2018 The Kubernetes Authors. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + package schema // ServerType defines the schema of a server type. diff --git a/cluster-autoscaler/cloudprovider/hetzner/hcloud-go/hcloud/schema/ssh_key.go b/cluster-autoscaler/cloudprovider/hetzner/hcloud-go/hcloud/schema/ssh_key.go index f230b3ddd122..b061e0d06541 100644 --- a/cluster-autoscaler/cloudprovider/hetzner/hcloud-go/hcloud/schema/ssh_key.go +++ b/cluster-autoscaler/cloudprovider/hetzner/hcloud-go/hcloud/schema/ssh_key.go @@ -1,3 +1,19 @@ +/* +Copyright 2018 The Kubernetes Authors. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + package schema import "time" diff --git a/cluster-autoscaler/cloudprovider/hetzner/hcloud-go/hcloud/schema/volume.go b/cluster-autoscaler/cloudprovider/hetzner/hcloud-go/hcloud/schema/volume.go index ad745ea97e6a..4cef9aef5ef5 100644 --- a/cluster-autoscaler/cloudprovider/hetzner/hcloud-go/hcloud/schema/volume.go +++ b/cluster-autoscaler/cloudprovider/hetzner/hcloud-go/hcloud/schema/volume.go @@ -1,3 +1,19 @@ +/* +Copyright 2018 The Kubernetes Authors. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + package schema import "time" diff --git a/cluster-autoscaler/cloudprovider/hetzner/hcloud-go/hcloud/server.go b/cluster-autoscaler/cloudprovider/hetzner/hcloud-go/hcloud/server.go index 8d593c060769..77984fd63d3c 100644 --- a/cluster-autoscaler/cloudprovider/hetzner/hcloud-go/hcloud/server.go +++ b/cluster-autoscaler/cloudprovider/hetzner/hcloud-go/hcloud/server.go @@ -1,3 +1,19 @@ +/* +Copyright 2018 The Kubernetes Authors. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + package hcloud import ( @@ -12,7 +28,7 @@ import ( "strconv" "time" - "github.com/hetznercloud/hcloud-go/hcloud/schema" + "k8s.io/autoscaler/cluster-autoscaler/cloudprovider/hetzner/hcloud-go/hcloud/schema" ) // Server represents a server in the Hetzner Cloud. diff --git a/cluster-autoscaler/cloudprovider/hetzner/hcloud-go/hcloud/server_type.go b/cluster-autoscaler/cloudprovider/hetzner/hcloud-go/hcloud/server_type.go index a681d0918e18..6234a9a30fcf 100644 --- a/cluster-autoscaler/cloudprovider/hetzner/hcloud-go/hcloud/server_type.go +++ b/cluster-autoscaler/cloudprovider/hetzner/hcloud-go/hcloud/server_type.go @@ -1,3 +1,19 @@ +/* +Copyright 2018 The Kubernetes Authors. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + package hcloud import ( @@ -6,7 +22,7 @@ import ( "net/url" "strconv" - "github.com/hetznercloud/hcloud-go/hcloud/schema" + "k8s.io/autoscaler/cluster-autoscaler/cloudprovider/hetzner/hcloud-go/hcloud/schema" ) // ServerType represents a server type in the Hetzner Cloud. diff --git a/cluster-autoscaler/cloudprovider/hetzner/hcloud-go/hcloud/ssh_key.go b/cluster-autoscaler/cloudprovider/hetzner/hcloud-go/hcloud/ssh_key.go index 52195e770866..bba78de3dcad 100644 --- a/cluster-autoscaler/cloudprovider/hetzner/hcloud-go/hcloud/ssh_key.go +++ b/cluster-autoscaler/cloudprovider/hetzner/hcloud-go/hcloud/ssh_key.go @@ -1,3 +1,19 @@ +/* +Copyright 2018 The Kubernetes Authors. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + package hcloud import ( @@ -10,7 +26,7 @@ import ( "strconv" "time" - "github.com/hetznercloud/hcloud-go/hcloud/schema" + "k8s.io/autoscaler/cluster-autoscaler/cloudprovider/hetzner/hcloud-go/hcloud/schema" ) // SSHKey represents a SSH key in the Hetzner Cloud. diff --git a/cluster-autoscaler/cloudprovider/hetzner/hcloud-go/hcloud/testing.go b/cluster-autoscaler/cloudprovider/hetzner/hcloud-go/hcloud/testing.go index a3cfb2f0cb02..03e9302dcd45 100644 --- a/cluster-autoscaler/cloudprovider/hetzner/hcloud-go/hcloud/testing.go +++ b/cluster-autoscaler/cloudprovider/hetzner/hcloud-go/hcloud/testing.go @@ -1,3 +1,19 @@ +/* +Copyright 2018 The Kubernetes Authors. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + package hcloud import ( diff --git a/cluster-autoscaler/cloudprovider/hetzner/hcloud-go/hcloud/volume.go b/cluster-autoscaler/cloudprovider/hetzner/hcloud-go/hcloud/volume.go index 53559365d8e3..03ed776e0f29 100644 --- a/cluster-autoscaler/cloudprovider/hetzner/hcloud-go/hcloud/volume.go +++ b/cluster-autoscaler/cloudprovider/hetzner/hcloud-go/hcloud/volume.go @@ -1,3 +1,19 @@ +/* +Copyright 2018 The Kubernetes Authors. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + package hcloud import ( @@ -10,7 +26,7 @@ import ( "strconv" "time" - "github.com/hetznercloud/hcloud-go/hcloud/schema" + "k8s.io/autoscaler/cluster-autoscaler/cloudprovider/hetzner/hcloud-go/hcloud/schema" ) // Volume represents a volume in the Hetzner Cloud. From 97e93742fae2b860dab96d35a68a67393bf8e11e Mon Sep 17 00:00:00 2001 From: Sergey Shevchenko Date: Fri, 18 Mar 2022 15:59:27 +0400 Subject: [PATCH 4/4] [ca]: Upgrade hcloud-go to 1.33.1 Signed-off-by: Sergey Shevchenko --- .../hetzner/hcloud-go/hcloud/client.go | 38 ++- .../hetzner/hcloud-go/hcloud/error.go | 32 ++- .../hetzner/hcloud-go/hcloud/firewall.go | 1 + .../hetzner/hcloud-go/hcloud/floating_ip.go | 62 +++-- .../hetzner/hcloud-go/hcloud/hcloud.go | 2 +- .../internal/instrumentation/metrics.go | 102 +++++++ .../internal/instrumentation/metrics_test.go | 45 +++ .../hetzner/hcloud-go/hcloud/load_balancer.go | 54 +++- .../hcloud-go/hcloud/metadata/client.go | 149 ++++++++++ .../hetzner/hcloud-go/hcloud/network.go | 1 + .../hcloud-go/hcloud/placement_group.go | 259 ++++++++++++++++++ .../hetzner/hcloud-go/hcloud/pricing.go | 14 + .../hetzner/hcloud-go/hcloud/rdns.go | 62 +++++ .../hetzner/hcloud-go/hcloud/schema.go | 64 ++++- .../hcloud-go/hcloud/schema/firewall.go | 1 + .../hcloud-go/hcloud/schema/load_balancer.go | 19 +- .../hcloud/schema/placement_group.go | 56 ++++ .../hcloud-go/hcloud/schema/pricing.go | 14 + .../hetzner/hcloud-go/hcloud/schema/server.go | 20 ++ .../hetzner/hcloud-go/hcloud/server.go | 104 +++++-- .../cloudprovider/hetzner/hetzner_manager.go | 3 +- 21 files changed, 1033 insertions(+), 69 deletions(-) create mode 100644 cluster-autoscaler/cloudprovider/hetzner/hcloud-go/hcloud/internal/instrumentation/metrics.go create mode 100644 cluster-autoscaler/cloudprovider/hetzner/hcloud-go/hcloud/internal/instrumentation/metrics_test.go create mode 100644 cluster-autoscaler/cloudprovider/hetzner/hcloud-go/hcloud/metadata/client.go create mode 100644 cluster-autoscaler/cloudprovider/hetzner/hcloud-go/hcloud/placement_group.go create mode 100644 cluster-autoscaler/cloudprovider/hetzner/hcloud-go/hcloud/rdns.go create mode 100644 cluster-autoscaler/cloudprovider/hetzner/hcloud-go/hcloud/schema/placement_group.go diff --git a/cluster-autoscaler/cloudprovider/hetzner/hcloud-go/hcloud/client.go b/cluster-autoscaler/cloudprovider/hetzner/hcloud-go/hcloud/client.go index 9af15d51721e..b85cd4617ed8 100644 --- a/cluster-autoscaler/cloudprovider/hetzner/hcloud-go/hcloud/client.go +++ b/cluster-autoscaler/cloudprovider/hetzner/hcloud-go/hcloud/client.go @@ -31,6 +31,10 @@ import ( "strings" "time" + "k8s.io/autoscaler/cluster-autoscaler/cloudprovider/hetzner/hcloud-go/hcloud/internal/instrumentation" + + "github.com/prometheus/client_golang/prometheus" + "k8s.io/autoscaler/cluster-autoscaler/cloudprovider/hetzner/hcloud-go/hcloud/schema" ) @@ -64,15 +68,16 @@ func ExponentialBackoff(b float64, d time.Duration) BackoffFunc { // Client is a client for the Hetzner Cloud API. type Client struct { - endpoint string - token string - pollInterval time.Duration - backoffFunc BackoffFunc - httpClient *http.Client - applicationName string - applicationVersion string - userAgent string - debugWriter io.Writer + endpoint string + token string + pollInterval time.Duration + backoffFunc BackoffFunc + httpClient *http.Client + applicationName string + applicationVersion string + userAgent string + debugWriter io.Writer + instrumentationRegistry *prometheus.Registry Action ActionClient Certificate CertificateClient @@ -90,6 +95,8 @@ type Client struct { ServerType ServerTypeClient SSHKey SSHKeyClient Volume VolumeClient + PlacementGroup PlacementGroupClient + RDNS RDNSClient } // A ClientOption is used to configure a Client. @@ -149,6 +156,13 @@ func WithHTTPClient(httpClient *http.Client) ClientOption { } } +// WithInstrumentation configures a Client to collect metrics about the performed HTTP requests. +func WithInstrumentation(registry *prometheus.Registry) ClientOption { + return func(client *Client) { + client.instrumentationRegistry = registry + } +} + // NewClient creates a new client. func NewClient(options ...ClientOption) *Client { client := &Client{ @@ -163,6 +177,10 @@ func NewClient(options ...ClientOption) *Client { } client.buildUserAgent() + if client.instrumentationRegistry != nil { + i := instrumentation.New("api", client.instrumentationRegistry) + client.httpClient.Transport = i.InstrumentedRoundTripper() + } client.Action = ActionClient{client: client} client.Datacenter = DatacenterClient{client: client} @@ -180,6 +198,8 @@ func NewClient(options ...ClientOption) *Client { client.LoadBalancerType = LoadBalancerTypeClient{client: client} client.Certificate = CertificateClient{client: client} client.Firewall = FirewallClient{client: client} + client.PlacementGroup = PlacementGroupClient{client: client} + client.RDNS = RDNSClient{client: client} return client } diff --git a/cluster-autoscaler/cloudprovider/hetzner/hcloud-go/hcloud/error.go b/cluster-autoscaler/cloudprovider/hetzner/hcloud-go/hcloud/error.go index be81fbb0bf2b..49407e574801 100644 --- a/cluster-autoscaler/cloudprovider/hetzner/hcloud-go/hcloud/error.go +++ b/cluster-autoscaler/cloudprovider/hetzner/hcloud-go/hcloud/error.go @@ -16,7 +16,10 @@ limitations under the License. package hcloud -import "fmt" +import ( + "fmt" + "net" +) // ErrorCode represents an error code returned from the API. type ErrorCode string @@ -68,11 +71,12 @@ const ( ErrorCodeVolumeAlreadyAttached ErrorCode = "volume_already_attached" // Volume is already attached to a server, detach first // Firewall related error codes - ErrorCodeFirewallAlreadyApplied ErrorCode = "firewall_already_applied" // Firewall was already applied on resource - ErrorCodeFirewallAlreadyRemoved ErrorCode = "firewall_already_removed" // Firewall was already removed from the resource - ErrorCodeIncompatibleNetworkType ErrorCode = "incompatible_network_type" // The Network type is incompatible for the given resource - ErrorCodeResourceInUse ErrorCode = "resource_in_use" // Firewall must not be in use to be deleted - ErrorCodeServerAlreadyAdded ErrorCode = "server_already_added" // Server added more than one time to resource + ErrorCodeFirewallAlreadyApplied ErrorCode = "firewall_already_applied" // Firewall was already applied on resource + ErrorCodeFirewallAlreadyRemoved ErrorCode = "firewall_already_removed" // Firewall was already removed from the resource + ErrorCodeIncompatibleNetworkType ErrorCode = "incompatible_network_type" // The Network type is incompatible for the given resource + ErrorCodeResourceInUse ErrorCode = "resource_in_use" // Firewall must not be in use to be deleted + ErrorCodeServerAlreadyAdded ErrorCode = "server_already_added" // Server added more than one time to resource + ErrorCodeFirewallResourceNotFound ErrorCode = "firewall_resource_not_found" // Resource a firewall should be attached to / detached from not found // Certificate related error codes ErrorCodeCAARecordDoesNotAllowCA ErrorCode = "caa_record_does_not_allow_ca" // CAA record does not allow certificate authority @@ -119,3 +123,19 @@ func IsError(err error, code ErrorCode) bool { apiErr, ok := err.(Error) return ok && apiErr.Code == code } + +type InvalidIPError struct { + IP string +} + +func (e InvalidIPError) Error() string { + return fmt.Sprintf("could not parse ip address %s", e.IP) +} + +type DNSNotFoundError struct { + IP net.IP +} + +func (e DNSNotFoundError) Error() string { + return fmt.Sprintf("dns for ip %s not found", e.IP.String()) +} diff --git a/cluster-autoscaler/cloudprovider/hetzner/hcloud-go/hcloud/firewall.go b/cluster-autoscaler/cloudprovider/hetzner/hcloud-go/hcloud/firewall.go index ca9889ff9a65..b69b734c385c 100644 --- a/cluster-autoscaler/cloudprovider/hetzner/hcloud-go/hcloud/firewall.go +++ b/cluster-autoscaler/cloudprovider/hetzner/hcloud-go/hcloud/firewall.go @@ -47,6 +47,7 @@ type FirewallRule struct { DestinationIPs []net.IPNet Protocol FirewallRuleProtocol Port *string + Description *string } // FirewallRuleDirection specifies the direction of a Firewall rule. diff --git a/cluster-autoscaler/cloudprovider/hetzner/hcloud-go/hcloud/floating_ip.go b/cluster-autoscaler/cloudprovider/hetzner/hcloud-go/hcloud/floating_ip.go index 37db55192629..ad86d7c242f2 100644 --- a/cluster-autoscaler/cloudprovider/hetzner/hcloud-go/hcloud/floating_ip.go +++ b/cluster-autoscaler/cloudprovider/hetzner/hcloud-go/hcloud/floating_ip.go @@ -48,6 +48,7 @@ type FloatingIP struct { } // DNSPtrForIP returns the reverse DNS pointer of the IP address. +// Deprecated: Use GetDNSPtrForIP instead func (f *FloatingIP) DNSPtrForIP(ip net.IP) string { return f.DNSPtr[ip.String()] } @@ -66,6 +67,43 @@ const ( FloatingIPTypeIPv6 FloatingIPType = "ipv6" ) +// changeDNSPtr changes or resets the reverse DNS pointer for a IP address. +// Pass a nil ptr to reset the reverse DNS pointer to its default value. +func (f *FloatingIP) changeDNSPtr(ctx context.Context, client *Client, ip net.IP, ptr *string) (*Action, *Response, error) { + reqBody := schema.FloatingIPActionChangeDNSPtrRequest{ + IP: ip.String(), + DNSPtr: ptr, + } + reqBodyData, err := json.Marshal(reqBody) + if err != nil { + return nil, nil, err + } + + path := fmt.Sprintf("/floating_ips/%d/actions/change_dns_ptr", f.ID) + req, err := client.NewRequest(ctx, "POST", path, bytes.NewReader(reqBodyData)) + if err != nil { + return nil, nil, err + } + + respBody := schema.FloatingIPActionChangeDNSPtrResponse{} + resp, err := client.Do(req, &respBody) + if err != nil { + return nil, resp, err + } + return ActionFromSchema(respBody.Action), resp, nil +} + +// GetDNSPtrForIP searches for the dns assigned to the given IP address. +// It returns an error if there is no dns set for the given IP address. +func (f *FloatingIP) GetDNSPtrForIP(ip net.IP) (string, error) { + dns, ok := f.DNSPtr[ip.String()] + if !ok { + return "", DNSNotFoundError{ip} + } + + return dns, nil +} + // FloatingIPClient is a client for the Floating IP API. type FloatingIPClient struct { client *Client @@ -341,27 +379,11 @@ func (c *FloatingIPClient) Unassign(ctx context.Context, floatingIP *FloatingIP) // ChangeDNSPtr changes or resets the reverse DNS pointer for a Floating IP address. // Pass a nil ptr to reset the reverse DNS pointer to its default value. func (c *FloatingIPClient) ChangeDNSPtr(ctx context.Context, floatingIP *FloatingIP, ip string, ptr *string) (*Action, *Response, error) { - reqBody := schema.FloatingIPActionChangeDNSPtrRequest{ - IP: ip, - DNSPtr: ptr, + netIP := net.ParseIP(ip) + if netIP == nil { + return nil, nil, InvalidIPError{ip} } - reqBodyData, err := json.Marshal(reqBody) - if err != nil { - return nil, nil, err - } - - path := fmt.Sprintf("/floating_ips/%d/actions/change_dns_ptr", floatingIP.ID) - req, err := c.client.NewRequest(ctx, "POST", path, bytes.NewReader(reqBodyData)) - if err != nil { - return nil, nil, err - } - - respBody := schema.FloatingIPActionChangeDNSPtrResponse{} - resp, err := c.client.Do(req, &respBody) - if err != nil { - return nil, resp, err - } - return ActionFromSchema(respBody.Action), resp, nil + return floatingIP.changeDNSPtr(ctx, c.client, net.ParseIP(ip), ptr) } // FloatingIPChangeProtectionOpts specifies options for changing the resource protection level of a Floating IP. diff --git a/cluster-autoscaler/cloudprovider/hetzner/hcloud-go/hcloud/hcloud.go b/cluster-autoscaler/cloudprovider/hetzner/hcloud-go/hcloud/hcloud.go index 879f39b22463..ac2d5cb28e38 100644 --- a/cluster-autoscaler/cloudprovider/hetzner/hcloud-go/hcloud/hcloud.go +++ b/cluster-autoscaler/cloudprovider/hetzner/hcloud-go/hcloud/hcloud.go @@ -18,4 +18,4 @@ limitations under the License. package hcloud // Version is the library's version following Semantic Versioning. -const Version = "1.27.0" +const Version = "1.32.0" diff --git a/cluster-autoscaler/cloudprovider/hetzner/hcloud-go/hcloud/internal/instrumentation/metrics.go b/cluster-autoscaler/cloudprovider/hetzner/hcloud-go/hcloud/internal/instrumentation/metrics.go new file mode 100644 index 000000000000..844ba87083fc --- /dev/null +++ b/cluster-autoscaler/cloudprovider/hetzner/hcloud-go/hcloud/internal/instrumentation/metrics.go @@ -0,0 +1,102 @@ +/* +Copyright 2018 The Kubernetes Authors. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package instrumentation + +import ( + "fmt" + "net/http" + "regexp" + "strconv" + "strings" + + "github.com/prometheus/client_golang/prometheus" + "github.com/prometheus/client_golang/prometheus/promhttp" +) + +type Instrumenter struct { + subsystemIdentifier string // will be used as part of the metric name (hcloud__requests_total) + instrumentationRegistry *prometheus.Registry +} + +// New creates a new Instrumenter. The subsystemIdentifier will be used as part of the metric names (e.g. hcloud__requests_total) +func New(subsystemIdentifier string, instrumentationRegistry *prometheus.Registry) *Instrumenter { + return &Instrumenter{subsystemIdentifier: subsystemIdentifier, instrumentationRegistry: instrumentationRegistry} +} + +// InstrumentedRoundTripper returns an instrumented round tripper. +func (i *Instrumenter) InstrumentedRoundTripper() http.RoundTripper { + inFlightRequestsGauge := prometheus.NewGauge(prometheus.GaugeOpts{ + Name: fmt.Sprintf("hcloud_%s_in_flight_requests", i.subsystemIdentifier), + Help: fmt.Sprintf("A gauge of in-flight requests to the hcloud %s.", i.subsystemIdentifier), + }) + + requestsPerEndpointCounter := prometheus.NewCounterVec( + prometheus.CounterOpts{ + Name: fmt.Sprintf("hcloud_%s_requests_total", i.subsystemIdentifier), + Help: fmt.Sprintf("A counter for requests to the hcloud %s per endpoint.", i.subsystemIdentifier), + }, + []string{"code", "method", "api_endpoint"}, + ) + + requestLatencyHistogram := prometheus.NewHistogramVec( + prometheus.HistogramOpts{ + Name: fmt.Sprintf("hcloud_%s_request_duration_seconds", i.subsystemIdentifier), + Help: fmt.Sprintf("A histogram of request latencies to the hcloud %s .", i.subsystemIdentifier), + Buckets: prometheus.DefBuckets, + }, + []string{"method"}, + ) + + i.instrumentationRegistry.MustRegister(requestsPerEndpointCounter, requestLatencyHistogram, inFlightRequestsGauge) + + return promhttp.InstrumentRoundTripperInFlight(inFlightRequestsGauge, + promhttp.InstrumentRoundTripperDuration(requestLatencyHistogram, + i.instrumentRoundTripperEndpoint(requestsPerEndpointCounter, + http.DefaultTransport, + ), + ), + ) +} + +// instrumentRoundTripperEndpoint implements a hcloud specific round tripper to count requests per API endpoint +// numeric IDs are removed from the URI Path. +// Sample: +// /volumes/1234/actions/attach --> /volumes/actions/attach +func (i *Instrumenter) instrumentRoundTripperEndpoint(counter *prometheus.CounterVec, next http.RoundTripper) promhttp.RoundTripperFunc { + return func(r *http.Request) (*http.Response, error) { + resp, err := next.RoundTrip(r) + if err == nil { + statusCode := strconv.Itoa(resp.StatusCode) + counter.WithLabelValues(statusCode, strings.ToLower(resp.Request.Method), preparePathForLabel(resp.Request.URL.Path)).Inc() + } + return resp, err + } +} + +func preparePathForLabel(path string) string { + path = strings.ToLower(path) + + // replace all numbers and chars that are not a-z, / or _ + reg := regexp.MustCompile("[^a-z/_]+") + path = reg.ReplaceAllString(path, "") + + // replace all artifacts of number replacement (//) + path = strings.ReplaceAll(path, "//", "/") + + // replace the /v/ that indicated the API version + return strings.Replace(path, "/v/", "/", 1) +} diff --git a/cluster-autoscaler/cloudprovider/hetzner/hcloud-go/hcloud/internal/instrumentation/metrics_test.go b/cluster-autoscaler/cloudprovider/hetzner/hcloud-go/hcloud/internal/instrumentation/metrics_test.go new file mode 100644 index 000000000000..a8651f2e5234 --- /dev/null +++ b/cluster-autoscaler/cloudprovider/hetzner/hcloud-go/hcloud/internal/instrumentation/metrics_test.go @@ -0,0 +1,45 @@ +/* +Copyright 2018 The Kubernetes Authors. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package instrumentation + +import "testing" + +func Test_preparePath(t *testing.T) { + tests := []struct { + name string + path string + want string + }{ + { + "simple test", + "/v1/volumes/123456", + "/volumes/", + }, + { + "simple test", + "/v1/volumes/123456/actions/attach", + "/volumes/actions/attach", + }, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + if got := preparePathForLabel(tt.path); got != tt.want { + t.Errorf("preparePathForLabel() = %v, want %v", got, tt.want) + } + }) + } +} diff --git a/cluster-autoscaler/cloudprovider/hetzner/hcloud-go/hcloud/load_balancer.go b/cluster-autoscaler/cloudprovider/hetzner/hcloud-go/hcloud/load_balancer.go index 0cdc4b223cf6..c6eadb717729 100644 --- a/cluster-autoscaler/cloudprovider/hetzner/hcloud-go/hcloud/load_balancer.go +++ b/cluster-autoscaler/cloudprovider/hetzner/hcloud-go/hcloud/load_balancer.go @@ -58,12 +58,14 @@ type LoadBalancerPublicNet struct { // LoadBalancerPublicNetIPv4 represents a Load Balancer's public IPv4 address. type LoadBalancerPublicNetIPv4 struct { - IP net.IP + IP net.IP + DNSPtr string } // LoadBalancerPublicNetIPv6 represents a Load Balancer's public IPv6 address. type LoadBalancerPublicNetIPv6 struct { - IP net.IP + IP net.IP + DNSPtr string } // LoadBalancerPrivateNet represents a Load Balancer's private network. @@ -211,6 +213,44 @@ type LoadBalancerProtection struct { Delete bool } +// changeDNSPtr changes or resets the reverse DNS pointer for a IP address. +// Pass a nil ptr to reset the reverse DNS pointer to its default value. +func (lb *LoadBalancer) changeDNSPtr(ctx context.Context, client *Client, ip net.IP, ptr *string) (*Action, *Response, error) { + reqBody := schema.LoadBalancerActionChangeDNSPtrRequest{ + IP: ip.String(), + DNSPtr: ptr, + } + reqBodyData, err := json.Marshal(reqBody) + if err != nil { + return nil, nil, err + } + + path := fmt.Sprintf("/load_balancers/%d/actions/change_dns_ptr", lb.ID) + req, err := client.NewRequest(ctx, "POST", path, bytes.NewReader(reqBodyData)) + if err != nil { + return nil, nil, err + } + + respBody := schema.LoadBalancerActionChangeDNSPtrResponse{} + resp, err := client.Do(req, &respBody) + if err != nil { + return nil, resp, err + } + return ActionFromSchema(respBody.Action), resp, nil +} + +// GetDNSPtrForIP searches for the dns assigned to the given IP address. +// It returns an error if there is no dns set for the given IP address. +func (lb *LoadBalancer) GetDNSPtrForIP(ip net.IP) (string, error) { + if net.IP.Equal(lb.PublicNet.IPv4.IP, ip) { + return lb.PublicNet.IPv4.DNSPtr, nil + } else if net.IP.Equal(lb.PublicNet.IPv6.IP, ip) { + return lb.PublicNet.IPv6.DNSPtr, nil + } + + return "", DNSNotFoundError{ip} +} + // LoadBalancerClient is a client for the Load Balancers API. type LoadBalancerClient struct { client *Client @@ -1040,3 +1080,13 @@ func (c *LoadBalancerClient) GetMetrics( } return ms, resp, nil } + +// ChangeDNSPtr changes or resets the reverse DNS pointer for a Load Balancer. +// Pass a nil ptr to reset the reverse DNS pointer to its default value. +func (c *LoadBalancerClient) ChangeDNSPtr(ctx context.Context, lb *LoadBalancer, ip string, ptr *string) (*Action, *Response, error) { + netIP := net.ParseIP(ip) + if netIP == nil { + return nil, nil, InvalidIPError{ip} + } + return lb.changeDNSPtr(ctx, c.client, net.ParseIP(ip), ptr) +} diff --git a/cluster-autoscaler/cloudprovider/hetzner/hcloud-go/hcloud/metadata/client.go b/cluster-autoscaler/cloudprovider/hetzner/hcloud-go/hcloud/metadata/client.go new file mode 100644 index 000000000000..e96577f76e1d --- /dev/null +++ b/cluster-autoscaler/cloudprovider/hetzner/hcloud-go/hcloud/metadata/client.go @@ -0,0 +1,149 @@ +/* +Copyright 2018 The Kubernetes Authors. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package metadata + +import ( + "io/ioutil" + "net" + "net/http" + "strconv" + "strings" + + "github.com/prometheus/client_golang/prometheus" + + "k8s.io/autoscaler/cluster-autoscaler/cloudprovider/hetzner/hcloud-go/hcloud/internal/instrumentation" +) + +const Endpoint = "http://169.254.169.254/hetzner/v1/metadata" + +// Client is a client for the Hetzner Cloud Server Metadata Endpoints. +type Client struct { + endpoint string + + httpClient *http.Client + instrumentationRegistry *prometheus.Registry +} + +// A ClientOption is used to configure a Client. +type ClientOption func(*Client) + +// WithEndpoint configures a Client to use the specified Metadata API endpoint. +func WithEndpoint(endpoint string) ClientOption { + return func(client *Client) { + client.endpoint = strings.TrimRight(endpoint, "/") + } +} + +// WithHTTPClient configures a Client to perform HTTP requests with httpClient. +func WithHTTPClient(httpClient *http.Client) ClientOption { + return func(client *Client) { + client.httpClient = httpClient + } +} + +// WithInstrumentation configures a Client to collect metrics about the performed HTTP requests. +func WithInstrumentation(registry *prometheus.Registry) ClientOption { + return func(client *Client) { + client.instrumentationRegistry = registry + } +} + +// NewClient creates a new client. +func NewClient(options ...ClientOption) *Client { + client := &Client{ + endpoint: Endpoint, + httpClient: &http.Client{}, + } + + for _, option := range options { + option(client) + } + + if client.instrumentationRegistry != nil { + i := instrumentation.New("metadata", client.instrumentationRegistry) + client.httpClient.Transport = i.InstrumentedRoundTripper() + } + return client +} + +// NewRequest creates an HTTP request against the API. The returned request +// is assigned with ctx and has all necessary headers set (auth, user agent, etc.). +func (c *Client) get(path string) (string, error) { + url := c.endpoint + path + resp, err := c.httpClient.Get(url) + if err != nil { + return "", err + } + body, err := ioutil.ReadAll(resp.Body) + if err != nil { + return "", err + } + resp.Body.Close() + return string(body), nil +} + +// IsHcloudServer checks if the currently called server is a hcloud server by calling a metadata endpoint +// if the endpoint answers with a non-empty value this method returns true, otherwise false +func (c *Client) IsHcloudServer() bool { + hostname, err := c.Hostname() + if err != nil { + return false + } + if len(hostname) > 0 { + return true + } + return false +} + +// Hostname returns the hostname of the server that did the request to the Metadata server +func (c *Client) Hostname() (string, error) { + return c.get("/hostname") +} + +// InstanceID returns the ID of the server that did the request to the Metadata server +func (c *Client) InstanceID() (int, error) { + resp, err := c.get("/instance-id") + if err != nil { + return 0, err + } + return strconv.Atoi(resp) +} + +// PublicIPv4 returns the Public IPv4 of the server that did the request to the Metadata server +func (c *Client) PublicIPv4() (net.IP, error) { + resp, err := c.get("/public-ipv4") + if err != nil { + return nil, err + } + return net.ParseIP(resp), nil +} + +// Region returns the Network Zone of the server that did the request to the Metadata server +func (c *Client) Region() (string, error) { + return c.get("/region") +} + +// AvailabilityZone returns the datacenter of the server that did the request to the Metadata server +func (c *Client) AvailabilityZone() (string, error) { + return c.get("/availability-zone") +} + +// PrivateNetworks returns details about the private networks the server is attached to +// Returns YAML (unparsed) +func (c *Client) PrivateNetworks() (string, error) { + return c.get("/private-networks") +} diff --git a/cluster-autoscaler/cloudprovider/hetzner/hcloud-go/hcloud/network.go b/cluster-autoscaler/cloudprovider/hetzner/hcloud-go/hcloud/network.go index fa8baff5c67a..25bc67713ad3 100644 --- a/cluster-autoscaler/cloudprovider/hetzner/hcloud-go/hcloud/network.go +++ b/cluster-autoscaler/cloudprovider/hetzner/hcloud-go/hcloud/network.go @@ -36,6 +36,7 @@ type NetworkZone string // List of available Network Zones. const ( NetworkZoneEUCentral NetworkZone = "eu-central" + NetworkZoneUSEast NetworkZone = "us-east" ) // NetworkSubnetType specifies a type of a subnet. diff --git a/cluster-autoscaler/cloudprovider/hetzner/hcloud-go/hcloud/placement_group.go b/cluster-autoscaler/cloudprovider/hetzner/hcloud-go/hcloud/placement_group.go new file mode 100644 index 000000000000..9dbe6b87371f --- /dev/null +++ b/cluster-autoscaler/cloudprovider/hetzner/hcloud-go/hcloud/placement_group.go @@ -0,0 +1,259 @@ +/* +Copyright 2018 The Kubernetes Authors. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package hcloud + +import ( + "bytes" + "context" + "encoding/json" + "errors" + "fmt" + "net/url" + "strconv" + "time" + + "k8s.io/autoscaler/cluster-autoscaler/cloudprovider/hetzner/hcloud-go/hcloud/schema" +) + +// PlacementGroup represents a Placement Group in the Hetzner Cloud. +type PlacementGroup struct { + ID int + Name string + Labels map[string]string + Created time.Time + Servers []int + Type PlacementGroupType +} + +// PlacementGroupType specifies the type of a Placement Group +type PlacementGroupType string + +const ( + // PlacementGroupTypeSpread spreads all servers in the group on different vhosts + PlacementGroupTypeSpread PlacementGroupType = "spread" +) + +// PlacementGroupClient is a client for the Placement Groups API. +type PlacementGroupClient struct { + client *Client +} + +// GetByID retrieves a PlacementGroup by its ID. If the PlacementGroup does not exist, nil is returned. +func (c *PlacementGroupClient) GetByID(ctx context.Context, id int) (*PlacementGroup, *Response, error) { + req, err := c.client.NewRequest(ctx, "GET", fmt.Sprintf("/placement_groups/%d", id), nil) + if err != nil { + return nil, nil, err + } + + var body schema.PlacementGroupGetResponse + resp, err := c.client.Do(req, &body) + if err != nil { + if IsError(err, ErrorCodeNotFound) { + return nil, resp, nil + } + return nil, nil, err + } + return PlacementGroupFromSchema(body.PlacementGroup), resp, nil +} + +// GetByName retrieves a PlacementGroup by its name. If the PlacementGroup does not exist, nil is returned. +func (c *PlacementGroupClient) GetByName(ctx context.Context, name string) (*PlacementGroup, *Response, error) { + if name == "" { + return nil, nil, nil + } + placementGroups, response, err := c.List(ctx, PlacementGroupListOpts{Name: name}) + if len(placementGroups) == 0 { + return nil, response, err + } + return placementGroups[0], response, err +} + +// Get retrieves a PlacementGroup by its ID if the input can be parsed as an integer, otherwise it +// retrieves a PlacementGroup by its name. If the PlacementGroup does not exist, nil is returned. +func (c *PlacementGroupClient) Get(ctx context.Context, idOrName string) (*PlacementGroup, *Response, error) { + if id, err := strconv.Atoi(idOrName); err == nil { + return c.GetByID(ctx, int(id)) + } + return c.GetByName(ctx, idOrName) +} + +// PlacementGroupListOpts specifies options for listing PlacementGroup. +type PlacementGroupListOpts struct { + ListOpts + Name string + Type PlacementGroupType +} + +func (l PlacementGroupListOpts) values() url.Values { + vals := l.ListOpts.values() + if l.Name != "" { + vals.Add("name", l.Name) + } + if l.Type != "" { + vals.Add("type", string(l.Type)) + } + return vals +} + +// List returns a list of PlacementGroups for a specific page. +// +// Please note that filters specified in opts are not taken into account +// when their value corresponds to their zero value or when they are empty. +func (c *PlacementGroupClient) List(ctx context.Context, opts PlacementGroupListOpts) ([]*PlacementGroup, *Response, error) { + path := "/placement_groups?" + opts.values().Encode() + req, err := c.client.NewRequest(ctx, "GET", path, nil) + if err != nil { + return nil, nil, err + } + + var body schema.PlacementGroupListResponse + resp, err := c.client.Do(req, &body) + if err != nil { + return nil, nil, err + } + placementGroups := make([]*PlacementGroup, 0, len(body.PlacementGroups)) + for _, g := range body.PlacementGroups { + placementGroups = append(placementGroups, PlacementGroupFromSchema(g)) + } + return placementGroups, resp, nil +} + +// All returns all PlacementGroups. +func (c *PlacementGroupClient) All(ctx context.Context) ([]*PlacementGroup, error) { + opts := PlacementGroupListOpts{ + ListOpts: ListOpts{ + PerPage: 50, + }, + } + + return c.AllWithOpts(ctx, opts) +} + +// AllWithOpts returns all PlacementGroups for the given options. +func (c *PlacementGroupClient) AllWithOpts(ctx context.Context, opts PlacementGroupListOpts) ([]*PlacementGroup, error) { + var allPlacementGroups []*PlacementGroup + + err := c.client.all(func(page int) (*Response, error) { + opts.Page = page + placementGroups, resp, err := c.List(ctx, opts) + if err != nil { + return resp, err + } + allPlacementGroups = append(allPlacementGroups, placementGroups...) + return resp, nil + }) + if err != nil { + return nil, err + } + + return allPlacementGroups, nil +} + +// PlacementGroupCreateOpts specifies options for creating a new PlacementGroup. +type PlacementGroupCreateOpts struct { + Name string + Labels map[string]string + Type PlacementGroupType +} + +// Validate checks if options are valid +func (o PlacementGroupCreateOpts) Validate() error { + if o.Name == "" { + return errors.New("missing name") + } + return nil +} + +// PlacementGroupCreateResult is the result of a create PlacementGroup call. +type PlacementGroupCreateResult struct { + PlacementGroup *PlacementGroup + Action *Action +} + +// Create creates a new PlacementGroup +func (c *PlacementGroupClient) Create(ctx context.Context, opts PlacementGroupCreateOpts) (PlacementGroupCreateResult, *Response, error) { + if err := opts.Validate(); err != nil { + return PlacementGroupCreateResult{}, nil, err + } + reqBody := placementGroupCreateOptsToSchema(opts) + reqBodyData, err := json.Marshal(reqBody) + if err != nil { + return PlacementGroupCreateResult{}, nil, err + } + req, err := c.client.NewRequest(ctx, "POST", "/placement_groups", bytes.NewReader(reqBodyData)) + if err != nil { + return PlacementGroupCreateResult{}, nil, err + } + + respBody := schema.PlacementGroupCreateResponse{} + resp, err := c.client.Do(req, &respBody) + if err != nil { + return PlacementGroupCreateResult{}, nil, err + } + result := PlacementGroupCreateResult{ + PlacementGroup: PlacementGroupFromSchema(respBody.PlacementGroup), + } + if respBody.Action != nil { + result.Action = ActionFromSchema(*respBody.Action) + } + + return result, resp, nil +} + +// PlacementGroupUpdateOpts specifies options for updating a PlacementGroup. +type PlacementGroupUpdateOpts struct { + Name string + Labels map[string]string +} + +// Update updates a PlacementGroup. +func (c *PlacementGroupClient) Update(ctx context.Context, placementGroup *PlacementGroup, opts PlacementGroupUpdateOpts) (*PlacementGroup, *Response, error) { + reqBody := schema.PlacementGroupUpdateRequest{} + if opts.Name != "" { + reqBody.Name = &opts.Name + } + if opts.Labels != nil { + reqBody.Labels = &opts.Labels + } + reqBodyData, err := json.Marshal(reqBody) + if err != nil { + return nil, nil, err + } + + path := fmt.Sprintf("/placement_groups/%d", placementGroup.ID) + req, err := c.client.NewRequest(ctx, "PUT", path, bytes.NewReader(reqBodyData)) + if err != nil { + return nil, nil, err + } + + respBody := schema.PlacementGroupUpdateResponse{} + resp, err := c.client.Do(req, &respBody) + if err != nil { + return nil, resp, err + } + + return PlacementGroupFromSchema(respBody.PlacementGroup), resp, nil +} + +// Delete deletes a PlacementGroup. +func (c *PlacementGroupClient) Delete(ctx context.Context, placementGroup *PlacementGroup) (*Response, error) { + req, err := c.client.NewRequest(ctx, "DELETE", fmt.Sprintf("/placement_groups/%d", placementGroup.ID), nil) + if err != nil { + return nil, err + } + return c.client.Do(req, nil) +} diff --git a/cluster-autoscaler/cloudprovider/hetzner/hcloud-go/hcloud/pricing.go b/cluster-autoscaler/cloudprovider/hetzner/hcloud-go/hcloud/pricing.go index 6325bd8330ee..ad2bcbe3bfd4 100644 --- a/cluster-autoscaler/cloudprovider/hetzner/hcloud-go/hcloud/pricing.go +++ b/cluster-autoscaler/cloudprovider/hetzner/hcloud-go/hcloud/pricing.go @@ -26,6 +26,7 @@ import ( type Pricing struct { Image ImagePricing FloatingIP FloatingIPPricing + FloatingIPs []FloatingIPTypePricing Traffic TrafficPricing ServerBackup ServerBackupPricing ServerTypes []ServerTypePricing @@ -53,6 +54,19 @@ type FloatingIPPricing struct { Monthly Price } +// FloatingIPTypePricing provides pricing information for Floating IPs per Type. +type FloatingIPTypePricing struct { + Type FloatingIPType + Pricings []FloatingIPTypeLocationPricing +} + +// FloatingIPTypeLocationPricing provides pricing information for a Floating IP type +// at a location. +type FloatingIPTypeLocationPricing struct { + Location *Location + Monthly Price +} + // TrafficPricing provides pricing information for traffic. type TrafficPricing struct { PerTB Price diff --git a/cluster-autoscaler/cloudprovider/hetzner/hcloud-go/hcloud/rdns.go b/cluster-autoscaler/cloudprovider/hetzner/hcloud-go/hcloud/rdns.go new file mode 100644 index 000000000000..d7cbf0b0db6b --- /dev/null +++ b/cluster-autoscaler/cloudprovider/hetzner/hcloud-go/hcloud/rdns.go @@ -0,0 +1,62 @@ +/* +Copyright 2018 The Kubernetes Authors. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package hcloud + +import ( + "context" + "fmt" + "net" +) + +// RDNSSupporter defines functions to change and lookup reverse dns entries. +// currently implemented by Server, FloatingIP and LoadBalancer +type RDNSSupporter interface { + // changeDNSPtr changes or resets the reverse DNS pointer for a IP address. + // Pass a nil ptr to reset the reverse DNS pointer to its default value. + changeDNSPtr(ctx context.Context, client *Client, ip net.IP, ptr *string) (*Action, *Response, error) + // GetDNSPtrForIP searches for the dns assigned to the given IP address. + // It returns an error if there is no dns set for the given IP address. + GetDNSPtrForIP(ip net.IP) (string, error) +} + +// RDNSClient simplifys the handling objects which support reverse dns entries. +type RDNSClient struct { + client *Client +} + +// ChangeDNSPtr changes or resets the reverse DNS pointer for a IP address. +// Pass a nil ptr to reset the reverse DNS pointer to its default value. +func (c *RDNSClient) ChangeDNSPtr(ctx context.Context, rdns RDNSSupporter, ip net.IP, ptr *string) (*Action, *Response, error) { + return rdns.changeDNSPtr(ctx, c.client, ip, ptr) +} + +// SupportsRDNS checks if the object supports reverse dns functions. +func SupportsRDNS(i interface{}) bool { + _, ok := i.(RDNSSupporter) + return ok +} + +// RDNSLookup searches for the dns assigned to the given IP address. +// It returns an error if the object does not support reverse dns or if there is no dns set for the given IP address. +func RDNSLookup(i interface{}, ip net.IP) (string, error) { + rdns, ok := i.(RDNSSupporter) + if !ok { + return "", fmt.Errorf("%+v does not support RDNS", i) + } + + return rdns.GetDNSPtrForIP(ip) +} diff --git a/cluster-autoscaler/cloudprovider/hetzner/hcloud-go/hcloud/schema.go b/cluster-autoscaler/cloudprovider/hetzner/hcloud-go/hcloud/schema.go index 641b762607b1..2baa4202b7ce 100644 --- a/cluster-autoscaler/cloudprovider/hetzner/hcloud-go/hcloud/schema.go +++ b/cluster-autoscaler/cloudprovider/hetzner/hcloud-go/hcloud/schema.go @@ -188,6 +188,9 @@ func ServerFromSchema(s schema.Server) *Server { for _, privNet := range s.PrivateNet { server.PrivateNet = append(server.PrivateNet, ServerPrivateNetFromSchema(privNet)) } + if s.PlacementGroup != nil { + server.PlacementGroup = PlacementGroupFromSchema(*s.PlacementGroup) + } return server } @@ -446,10 +449,12 @@ func LoadBalancerFromSchema(s schema.LoadBalancer) *LoadBalancer { PublicNet: LoadBalancerPublicNet{ Enabled: s.PublicNet.Enabled, IPv4: LoadBalancerPublicNetIPv4{ - IP: net.ParseIP(s.PublicNet.IPv4.IP), + IP: net.ParseIP(s.PublicNet.IPv4.IP), + DNSPtr: s.PublicNet.IPv4.DNSPtr, }, IPv6: LoadBalancerPublicNetIPv6{ - IP: net.ParseIP(s.PublicNet.IPv6.IP), + IP: net.ParseIP(s.PublicNet.IPv6.IP), + DNSPtr: s.PublicNet.IPv6.DNSPtr, }, }, Location: LocationFromSchema(s.Location), @@ -676,6 +681,22 @@ func PricingFromSchema(s schema.Pricing) Pricing { }, }, } + for _, floatingIPType := range s.FloatingIPs { + var pricings []FloatingIPTypeLocationPricing + for _, price := range floatingIPType.Prices { + p := FloatingIPTypeLocationPricing{ + Location: &Location{Name: price.Location}, + Monthly: Price{ + Currency: s.Currency, + VATRate: s.VATRate, + Net: price.PriceMonthly.Net, + Gross: price.PriceMonthly.Gross, + }, + } + pricings = append(pricings, p) + } + p.FloatingIPs = append(p.FloatingIPs, FloatingIPTypePricing{Type: FloatingIPType(floatingIPType.Type), Pricings: pricings}) + } for _, serverType := range s.ServerTypes { var pricings []ServerTypeLocationPricing for _, price := range serverType.Prices { @@ -775,11 +796,36 @@ func FirewallFromSchema(s schema.Firewall) *Firewall { DestinationIPs: destinationIPs, Protocol: FirewallRuleProtocol(rule.Protocol), Port: rule.Port, + Description: rule.Description, }) } return f } +// PlacementGroupFromSchema converts a schema.PlacementGroup to a PlacementGroup. +func PlacementGroupFromSchema(s schema.PlacementGroup) *PlacementGroup { + g := &PlacementGroup{ + ID: s.ID, + Name: s.Name, + Labels: s.Labels, + Created: s.Created, + Servers: s.Servers, + Type: PlacementGroupType(s.Type), + } + return g +} + +func placementGroupCreateOptsToSchema(opts PlacementGroupCreateOpts) schema.PlacementGroupCreateRequest { + req := schema.PlacementGroupCreateRequest{ + Name: opts.Name, + Type: string(opts.Type), + } + if opts.Labels != nil { + req.Labels = &opts.Labels + } + return req +} + func loadBalancerCreateOptsToSchema(opts LoadBalancerCreateOpts) schema.LoadBalancerCreateRequest { req := schema.LoadBalancerCreateRequest{ Name: opts.Name, @@ -997,9 +1043,10 @@ func firewallCreateOptsToSchema(opts FirewallCreateOpts) schema.FirewallCreateRe } for _, rule := range opts.Rules { schemaRule := schema.FirewallRule{ - Direction: string(rule.Direction), - Protocol: string(rule.Protocol), - Port: rule.Port, + Direction: string(rule.Direction), + Protocol: string(rule.Protocol), + Port: rule.Port, + Description: rule.Description, } switch rule.Direction { case FirewallRuleDirectionOut: @@ -1037,9 +1084,10 @@ func firewallSetRulesOptsToSchema(opts FirewallSetRulesOpts) schema.FirewallActi req := schema.FirewallActionSetRulesRequest{Rules: []schema.FirewallRule{}} for _, rule := range opts.Rules { schemaRule := schema.FirewallRule{ - Direction: string(rule.Direction), - Protocol: string(rule.Protocol), - Port: rule.Port, + Direction: string(rule.Direction), + Protocol: string(rule.Protocol), + Port: rule.Port, + Description: rule.Description, } switch rule.Direction { case FirewallRuleDirectionOut: diff --git a/cluster-autoscaler/cloudprovider/hetzner/hcloud-go/hcloud/schema/firewall.go b/cluster-autoscaler/cloudprovider/hetzner/hcloud-go/hcloud/schema/firewall.go index da94e9f7e997..6c32bb05bf43 100644 --- a/cluster-autoscaler/cloudprovider/hetzner/hcloud-go/hcloud/schema/firewall.go +++ b/cluster-autoscaler/cloudprovider/hetzner/hcloud-go/hcloud/schema/firewall.go @@ -35,6 +35,7 @@ type FirewallRule struct { DestinationIPs []string `json:"destination_ips,omitempty"` Protocol string `json:"protocol"` Port *string `json:"port,omitempty"` + Description *string `json:"description,omitempty"` } // FirewallListResponse defines the schema of the response when listing Firewalls. diff --git a/cluster-autoscaler/cloudprovider/hetzner/hcloud-go/hcloud/schema/load_balancer.go b/cluster-autoscaler/cloudprovider/hetzner/hcloud-go/hcloud/schema/load_balancer.go index bf3a2525819e..f50b2b592939 100644 --- a/cluster-autoscaler/cloudprovider/hetzner/hcloud-go/hcloud/schema/load_balancer.go +++ b/cluster-autoscaler/cloudprovider/hetzner/hcloud-go/hcloud/schema/load_balancer.go @@ -43,11 +43,13 @@ type LoadBalancerPublicNet struct { } type LoadBalancerPublicNetIPv4 struct { - IP string `json:"ip"` + IP string `json:"ip"` + DNSPtr string `json:"dns_ptr"` } type LoadBalancerPublicNetIPv6 struct { - IP string `json:"ip"` + IP string `json:"ip"` + DNSPtr string `json:"dns_ptr"` } type LoadBalancerPrivateNet struct { @@ -417,3 +419,16 @@ type LoadBalancerGetMetricsResponse struct { type LoadBalancerTimeSeriesVals struct { Values []interface{} `json:"values"` } + +// LoadBalancerActionChangeDNSPtrRequest defines the schema for the request to +// change a Load Balancer reverse DNS pointer. +type LoadBalancerActionChangeDNSPtrRequest struct { + IP string `json:"ip"` + DNSPtr *string `json:"dns_ptr"` +} + +// LoadBalancerActionChangeDNSPtrResponse defines the schema of the response when +// creating a change_dns_ptr Floating IP action. +type LoadBalancerActionChangeDNSPtrResponse struct { + Action Action `json:"action"` +} diff --git a/cluster-autoscaler/cloudprovider/hetzner/hcloud-go/hcloud/schema/placement_group.go b/cluster-autoscaler/cloudprovider/hetzner/hcloud-go/hcloud/schema/placement_group.go new file mode 100644 index 000000000000..a13a8d5b4f31 --- /dev/null +++ b/cluster-autoscaler/cloudprovider/hetzner/hcloud-go/hcloud/schema/placement_group.go @@ -0,0 +1,56 @@ +/* +Copyright 2018 The Kubernetes Authors. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package schema + +import "time" + +type PlacementGroup struct { + ID int `json:"id"` + Name string `json:"name"` + Labels map[string]string `json:"labels"` + Created time.Time `json:"created"` + Servers []int `json:"servers"` + Type string `json:"type"` +} + +type PlacementGroupListResponse struct { + PlacementGroups []PlacementGroup `json:"placement_groups"` +} + +type PlacementGroupGetResponse struct { + PlacementGroup PlacementGroup `json:"placement_group"` +} + +type PlacementGroupCreateRequest struct { + Name string `json:"name"` + Labels *map[string]string `json:"labels,omitempty"` + Type string `json:"type"` +} + +type PlacementGroupCreateResponse struct { + PlacementGroup PlacementGroup `json:"placement_group"` + Action *Action `json:"action"` +} + +type PlacementGroupUpdateRequest struct { + Name *string `json:"name,omitempty"` + Labels *map[string]string `json:"labels,omitempty"` +} + +type PlacementGroupUpdateResponse struct { + PlacementGroup PlacementGroup `json:"placement_group"` +} diff --git a/cluster-autoscaler/cloudprovider/hetzner/hcloud-go/hcloud/schema/pricing.go b/cluster-autoscaler/cloudprovider/hetzner/hcloud-go/hcloud/schema/pricing.go index 3cb8c099ee11..5e8b80c09630 100644 --- a/cluster-autoscaler/cloudprovider/hetzner/hcloud-go/hcloud/schema/pricing.go +++ b/cluster-autoscaler/cloudprovider/hetzner/hcloud-go/hcloud/schema/pricing.go @@ -22,6 +22,7 @@ type Pricing struct { VATRate string `json:"vat_rate"` Image PricingImage `json:"image"` FloatingIP PricingFloatingIP `json:"floating_ip"` + FloatingIPs []PricingFloatingIPType `json:"floating_ips"` Traffic PricingTraffic `json:"traffic"` ServerBackup PricingServerBackup `json:"server_backup"` ServerTypes []PricingServerType `json:"server_types"` @@ -45,6 +46,19 @@ type PricingFloatingIP struct { PriceMonthly Price `json:"price_monthly"` } +// PricingFloatingIPType defines the schema of pricing information for a Floating IP per type. +type PricingFloatingIPType struct { + Type string `json:"type"` + Prices []PricingFloatingIPTypePrice `json:"prices"` +} + +// PricingFloatingIPTypePrice defines the schema of pricing information for a Floating IP +// type at a location. +type PricingFloatingIPTypePrice struct { + Location string `json:"location"` + PriceMonthly Price `json:"price_monthly"` +} + // PricingTraffic defines the schema of pricing information for traffic. type PricingTraffic struct { PricePerTB Price `json:"price_per_tb"` diff --git a/cluster-autoscaler/cloudprovider/hetzner/hcloud-go/hcloud/schema/server.go b/cluster-autoscaler/cloudprovider/hetzner/hcloud-go/hcloud/schema/server.go index d04be6319fc2..2ac327381512 100644 --- a/cluster-autoscaler/cloudprovider/hetzner/hcloud-go/hcloud/schema/server.go +++ b/cluster-autoscaler/cloudprovider/hetzner/hcloud-go/hcloud/schema/server.go @@ -40,6 +40,7 @@ type Server struct { Labels map[string]string `json:"labels"` Volumes []int `json:"volumes"` PrimaryDiskSize int `json:"primary_disk_size"` + PlacementGroup *PlacementGroup `json:"placement_group"` } // ServerProtection defines the schema of a server's resource protection. @@ -123,6 +124,7 @@ type ServerCreateRequest struct { Volumes []int `json:"volumes,omitempty"` Networks []int `json:"networks,omitempty"` Firewalls []ServerCreateFirewalls `json:"firewalls,omitempty"` + PlacementGroup int `json:"placement_group,omitempty"` } // ServerCreateFirewall defines which Firewalls to apply when creating a Server. @@ -411,3 +413,21 @@ type ServerGetMetricsResponse struct { type ServerTimeSeriesVals struct { Values []interface{} `json:"values"` } + +// ServerActionAddToPlacementGroupRequest defines the schema for the request to +// add a server to a placement group. +type ServerActionAddToPlacementGroupRequest struct { + PlacementGroup int `json:"placement_group"` +} + +// ServerActionAddToPlacementGroupResponse defines the schema of the response when +// creating an add_to_placement_group server action. +type ServerActionAddToPlacementGroupResponse struct { + Action Action `json:"action"` +} + +// ServerActionRemoveFromPlacementGroupResponse defines the schema of the response when +// creating a remove_from_placement_group server action. +type ServerActionRemoveFromPlacementGroupResponse struct { + Action Action `json:"action"` +} diff --git a/cluster-autoscaler/cloudprovider/hetzner/hcloud-go/hcloud/server.go b/cluster-autoscaler/cloudprovider/hetzner/hcloud-go/hcloud/server.go index 77984fd63d3c..79783fd94325 100644 --- a/cluster-autoscaler/cloudprovider/hetzner/hcloud-go/hcloud/server.go +++ b/cluster-autoscaler/cloudprovider/hetzner/hcloud-go/hcloud/server.go @@ -53,6 +53,7 @@ type Server struct { Labels map[string]string Volumes []*Volume PrimaryDiskSize int + PlacementGroup *PlacementGroup } // ServerProtection represents the protection level of a server. @@ -156,6 +157,44 @@ const ( ServerRescueTypeFreeBSD64 ServerRescueType = "freebsd64" ) +// changeDNSPtr changes or resets the reverse DNS pointer for a IP address. +// Pass a nil ptr to reset the reverse DNS pointer to its default value. +func (s *Server) changeDNSPtr(ctx context.Context, client *Client, ip net.IP, ptr *string) (*Action, *Response, error) { + reqBody := schema.ServerActionChangeDNSPtrRequest{ + IP: ip.String(), + DNSPtr: ptr, + } + reqBodyData, err := json.Marshal(reqBody) + if err != nil { + return nil, nil, err + } + + path := fmt.Sprintf("/servers/%d/actions/change_dns_ptr", s.ID) + req, err := client.NewRequest(ctx, "POST", path, bytes.NewReader(reqBodyData)) + if err != nil { + return nil, nil, err + } + + respBody := schema.ServerActionChangeDNSPtrResponse{} + resp, err := client.Do(req, &respBody) + if err != nil { + return nil, resp, err + } + return ActionFromSchema(respBody.Action), resp, nil +} + +// GetDNSPtrForIP searches for the dns assigned to the given IP address. +// It returns an error if there is no dns set for the given IP address. +func (s *Server) GetDNSPtrForIP(ip net.IP) (string, error) { + if net.IP.Equal(s.PublicNet.IPv4.IP, ip) { + return s.PublicNet.IPv4.DNSPtr, nil + } else if dns, ok := s.PublicNet.IPv6.DNSPtr[ip.String()]; ok { + return dns, nil + } + + return "", DNSNotFoundError{ip} +} + // ServerClient is a client for the servers API. type ServerClient struct { client *Client @@ -281,6 +320,7 @@ type ServerCreateOpts struct { Volumes []*Volume Networks []*Network Firewalls []*ServerCreateFirewall + PlacementGroup *PlacementGroup } // ServerCreateFirewall defines which Firewalls to apply when creating a Server. @@ -365,6 +405,9 @@ func (c *ServerClient) Create(ctx context.Context, opts ServerCreateOpts) (Serve reqBody.Datacenter = opts.Datacenter.Name } } + if opts.PlacementGroup != nil { + reqBody.PlacementGroup = opts.PlacementGroup.ID + } reqBodyData, err := json.Marshal(reqBody) if err != nil { return ServerCreateResult{}, nil, err @@ -819,27 +862,11 @@ func (c *ServerClient) ChangeType(ctx context.Context, server *Server, opts Serv // ChangeDNSPtr changes or resets the reverse DNS pointer for a server IP address. // Pass a nil ptr to reset the reverse DNS pointer to its default value. func (c *ServerClient) ChangeDNSPtr(ctx context.Context, server *Server, ip string, ptr *string) (*Action, *Response, error) { - reqBody := schema.ServerActionChangeDNSPtrRequest{ - IP: ip, - DNSPtr: ptr, - } - reqBodyData, err := json.Marshal(reqBody) - if err != nil { - return nil, nil, err - } - - path := fmt.Sprintf("/servers/%d/actions/change_dns_ptr", server.ID) - req, err := c.client.NewRequest(ctx, "POST", path, bytes.NewReader(reqBodyData)) - if err != nil { - return nil, nil, err + netIP := net.ParseIP(ip) + if netIP == nil { + return nil, nil, InvalidIPError{ip} } - - respBody := schema.ServerActionChangeDNSPtrResponse{} - resp, err := c.client.Do(req, &respBody) - if err != nil { - return nil, resp, err - } - return ActionFromSchema(respBody.Action), resp, nil + return server.changeDNSPtr(ctx, c.client, net.ParseIP(ip), ptr) } // ServerChangeProtectionOpts specifies options for changing the resource protection level of a server. @@ -1086,3 +1113,40 @@ func (c *ServerClient) GetMetrics(ctx context.Context, server *Server, opts Serv } return ms, resp, nil } + +func (c *ServerClient) AddToPlacementGroup(ctx context.Context, server *Server, placementGroup *PlacementGroup) (*Action, *Response, error) { + reqBody := schema.ServerActionAddToPlacementGroupRequest{ + PlacementGroup: placementGroup.ID, + } + reqBodyData, err := json.Marshal(reqBody) + if err != nil { + return nil, nil, err + } + path := fmt.Sprintf("/servers/%d/actions/add_to_placement_group", server.ID) + req, err := c.client.NewRequest(ctx, "POST", path, bytes.NewReader(reqBodyData)) + if err != nil { + return nil, nil, err + } + + respBody := schema.ServerActionAddToPlacementGroupResponse{} + resp, err := c.client.Do(req, &respBody) + if err != nil { + return nil, resp, err + } + return ActionFromSchema(respBody.Action), resp, err +} + +func (c *ServerClient) RemoveFromPlacementGroup(ctx context.Context, server *Server) (*Action, *Response, error) { + path := fmt.Sprintf("/servers/%d/actions/remove_from_placement_group", server.ID) + req, err := c.client.NewRequest(ctx, "POST", path, nil) + if err != nil { + return nil, nil, err + } + + respBody := schema.ServerActionRemoveFromPlacementGroupResponse{} + resp, err := c.client.Do(req, &respBody) + if err != nil { + return nil, resp, err + } + return ActionFromSchema(respBody.Action), resp, err +} diff --git a/cluster-autoscaler/cloudprovider/hetzner/hetzner_manager.go b/cluster-autoscaler/cloudprovider/hetzner/hetzner_manager.go index aee95efb31f2..9cbf373df73b 100644 --- a/cluster-autoscaler/cloudprovider/hetzner/hetzner_manager.go +++ b/cluster-autoscaler/cloudprovider/hetzner/hetzner_manager.go @@ -27,6 +27,7 @@ import ( "time" apiv1 "k8s.io/api/core/v1" + "k8s.io/autoscaler/cluster-autoscaler/cloudprovider/hetzner/hcloud-go/hcloud" ) @@ -137,7 +138,7 @@ func newManager() (*hetznerManager, error) { image: image, sshKey: sshKey, network: network, - firewall: firewall, + firewall: firewall, createTimeout: createTimeout, apiCallContext: ctx, }