Add support for using an existing network for Hetzner

This commit is contained in:
Ciprian Hacman 2022-09-17 11:20:23 +03:00
parent beebcf444b
commit c783aa357d
7 changed files with 75 additions and 39 deletions

View File

@ -92,6 +92,7 @@ func ValidateCluster(c *kops.Cluster, strict bool) field.ErrorList {
allErrs = append(allErrs, field.Forbidden(fieldSpec.Child("hetzner"), "only one cloudProvider option permitted"))
}
optionTaken = true
requiresNetworkCIDR = false
requiresSubnets = false
requiresSubnetCIDR = false
}

View File

@ -34,16 +34,21 @@ func (b *NetworkModelBuilder) Build(c *fi.ModelBuilderContext) error {
network := &hetznertasks.Network{
Name: fi.String(b.ClusterName()),
Lifecycle: b.Lifecycle,
Region: b.Region,
IPRange: b.Cluster.Spec.NetworkCIDR,
// TODO(hakman): Add support for additional subnets?
Subnets: []string{
b.Cluster.Spec.NetworkCIDR,
},
Labels: map[string]string{
hetzner.TagKubernetesClusterName: b.ClusterName(),
},
}
if b.Cluster.Spec.NetworkID == "" {
network.IPRange = b.Cluster.Spec.NetworkCIDR
network.Region = b.Region
network.Subnets = []string{
b.Cluster.Spec.NetworkCIDR,
}
network.Labels = map[string]string{
hetzner.TagKubernetesClusterName: b.ClusterName(),
}
} else {
network.ID = fi.String(b.Cluster.Spec.NetworkID)
}
c.AddTask(network)
return nil

View File

@ -6,8 +6,8 @@ metadata:
name: hcloud
namespace: kube-system
stringData:
token: {{ HCLOUD_TOKEN }}
network: {{ ClusterName }}
token: "{{ HCLOUD_TOKEN }}"
network: "{{ HCLOUD_NETWORK }}"
---
apiVersion: v1
kind: ServiceAccount

View File

@ -199,6 +199,11 @@ func (_ *LoadBalancer) RenderHetzner(t *hetzner.HetznerAPITarget, a, e, changes
return fmt.Errorf("failed to find network for loadbalancer %q", fi.StringValue(e.Name))
}
networkID, err := strconv.Atoi(fi.StringValue(e.Network.ID))
if err != nil {
return fmt.Errorf("failed to convert network ID %q to int: %w", fi.StringValue(e.Network.ID), err)
}
opts := hcloud.LoadBalancerCreateOpts{
Name: fi.StringValue(e.Name),
LoadBalancerType: &hcloud.LoadBalancerType{
@ -221,7 +226,7 @@ func (_ *LoadBalancer) RenderHetzner(t *hetzner.HetznerAPITarget, a, e, changes
},
},
Network: &hcloud.Network{
ID: fi.IntValue(e.Network.ID),
ID: networkID,
},
}

View File

@ -18,6 +18,7 @@ package hetznertasks
import (
"context"
"fmt"
"net"
"strconv"
"time"
@ -34,7 +35,7 @@ type Network struct {
Name *string
Lifecycle fi.Lifecycle
ID *int
ID *string
Region string
IPRange string
Subnets []string
@ -45,41 +46,53 @@ type Network struct {
var _ fi.CompareWithID = &Network{}
func (v *Network) CompareWithID() *string {
return fi.String(strconv.Itoa(fi.IntValue(v.ID)))
return v.ID
}
func (v *Network) Find(c *fi.Context) (*Network, error) {
cloud := c.Cloud.(hetzner.HetznerCloud)
client := cloud.NetworkClient()
// TODO(hakman): Find using label selector
networks, err := client.All(context.TODO())
idOrName := fi.StringValue(v.Name)
if v.ID != nil {
idOrName = fi.StringValue(v.ID)
}
network, _, err := client.Get(context.TODO(), idOrName)
if err != nil {
return nil, err
return nil, fmt.Errorf("failed to find network %q: %w", idOrName, err)
}
for _, network := range networks {
if network.Name == fi.StringValue(v.Name) {
matches := &Network{
Name: fi.String(network.Name),
Lifecycle: v.Lifecycle,
ID: fi.Int(network.ID),
IPRange: network.IPRange.String(),
Labels: network.Labels,
}
matches.Region = v.Region
for _, subnet := range network.Subnets {
if subnet.IPRange != nil {
matches.Region = string(subnet.NetworkZone)
matches.Subnets = append(matches.Subnets, subnet.IPRange.String())
}
}
v.ID = matches.ID
return matches, nil
if network == nil {
if v.ID != nil {
return nil, fmt.Errorf("failed to find network %q", idOrName)
}
return nil, nil
}
return nil, nil
matches := &Network{
Name: v.Name,
Lifecycle: v.Lifecycle,
ID: fi.String(strconv.Itoa(network.ID)),
}
if v.ID == nil {
matches.IPRange = network.IPRange.String()
matches.Labels = network.Labels
matches.Region = v.Region
for _, subnet := range network.Subnets {
if subnet.IPRange != nil {
matches.Region = string(subnet.NetworkZone)
matches.Subnets = append(matches.Subnets, subnet.IPRange.String())
}
}
// Make sure the ID is set (used by other tasks)
v.ID = matches.ID
} else {
// Make sure the ID is numerical
v.ID = matches.ID
}
return matches, nil
}
func (v *Network) Run(c *fi.Context) error {
@ -138,7 +151,7 @@ func (_ *Network) RenderHetzner(t *hetzner.HetznerAPITarget, a, e, changes *Netw
if err != nil {
return err
}
e.ID = fi.Int(network.ID)
e.ID = fi.String(strconv.Itoa(network.ID))
} else {
var err error

View File

@ -22,6 +22,7 @@ import (
"encoding/base64"
"fmt"
"math/rand"
"strconv"
"strings"
"github.com/hetznercloud/hcloud-go/hcloud"
@ -205,6 +206,11 @@ func (_ *ServerGroup) RenderHetzner(t *hetzner.HetznerAPITarget, a, e, changes *
}
userDataHash := safeBytesHash(userDataBytes)
networkID, err := strconv.Atoi(fi.StringValue(e.Network.ID))
if err != nil {
return fmt.Errorf("failed to convert network ID %q to int: %w", fi.StringValue(e.Network.ID), err)
}
for i := 1; i <= expectedCount-actualCount; i++ {
// Append a random/unique ID to the node name
name := fmt.Sprintf("%s-%x", fi.StringValue(e.Name), rand.Int63())
@ -214,7 +220,7 @@ func (_ *ServerGroup) RenderHetzner(t *hetzner.HetznerAPITarget, a, e, changes *
StartAfterCreate: fi.Bool(true),
Networks: []*hcloud.Network{
{
ID: fi.IntValue(e.Network.ID),
ID: networkID,
},
},
Location: &hcloud.Location{

View File

@ -173,6 +173,12 @@ func (tf *TemplateFunctions) AddTo(dest template.FuncMap, secretStore fi.SecretS
dest["HCLOUD_TOKEN"] = func() string {
return os.Getenv("HCLOUD_TOKEN")
}
dest["HCLOUD_NETWORK"] = func() string {
if cluster.Spec.NetworkID != "" {
return cluster.Spec.NetworkID
}
return cluster.Name
}
if featureflag.Spotinst.Enabled() {
if creds, err := spotinst.LoadCredentials(); err == nil {