Skip to content

feat(hcloud): select the location randomly from a given list #89

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 1 commit into
base: master
Choose a base branch
from
Open
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
57 changes: 42 additions & 15 deletions driver.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ package main
import (
"context"
"fmt"
"math/rand"
"net"
"os"
"strings"
Expand All @@ -29,8 +30,8 @@ type Driver struct {
cachedImage *hcloud.Image
Type string
cachedType *hcloud.ServerType
Location string
cachedLocation *hcloud.Location
Locations []string
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Personally I think the final location should still be in Location, as there are some downstream projects that depend on the 'public' data of the driver.

Keeping the location pool around in a separate public field seems like the best downward-compatible solution IMHO, that would still allow downstream tools to support this option in the future.

cachedLocations []*hcloud.Location
KeyID int
cachedKey *hcloud.SSHKey
IsExistingKey bool
Expand Down Expand Up @@ -63,7 +64,7 @@ const (
flagImage = "hetzner-image"
flagImageID = "hetzner-image-id"
flagType = "hetzner-server-type"
flagLocation = "hetzner-server-location"
flagLocations = "hetzner-server-locations"
flagExKeyID = "hetzner-existing-key-id"
flagExKeyPath = "hetzner-existing-key-path"
flagUserData = "hetzner-user-data"
Expand Down Expand Up @@ -133,11 +134,11 @@ func (d *Driver) GetCreateFlags() []mcnflag.Flag {
Usage: "Server type to create",
Value: defaultType,
},
mcnflag.StringFlag{
EnvVar: "HETZNER_LOCATION",
Name: flagLocation,
mcnflag.StringSliceFlag{
EnvVar: "HETZNER_LOCATIONS",
Name: flagLocations,
Usage: "Location to create machine at",
Value: "",
Value: []string{},
},
mcnflag.IntFlag{
EnvVar: "HETZNER_EXISTING_KEY_ID",
Expand Down Expand Up @@ -249,7 +250,7 @@ func (d *Driver) setConfigFromFlagsImpl(opts drivers.DriverOptions) error {
d.AccessToken = opts.String(flagAPIToken)
d.Image = opts.String(flagImage)
d.ImageID = opts.Int(flagImageID)
d.Location = opts.String(flagLocation)
d.Locations = opts.StringSlice(flagLocations)
d.Type = opts.String(flagType)
d.KeyID = opts.Int(flagExKeyID)
d.IsExistingKey = d.KeyID != 0
Expand Down Expand Up @@ -357,6 +358,7 @@ func (d *Driver) PreCreateCheck() error {
key.Fingerprint != ssh.FingerprintSHA256(pubk) {
return errors.Errorf("remote key %d does not match local key %s", d.KeyID, d.originalKey)
}
fmt.Println("hello")
}

if _, err := d.getType(); err != nil {
Expand Down Expand Up @@ -880,17 +882,42 @@ func (d *Driver) copySSHKeyPair(src string) error {
return nil
}

func (d *Driver) getLocation() (*hcloud.Location, error) {
if d.cachedLocation != nil {
return d.cachedLocation, nil
func (d *Driver) getLocations() ([]*hcloud.Location, error) {
if len(d.cachedLocations) > 0 {
return d.cachedLocations, nil
}

locations := []*hcloud.Location{}

for _, locationName := range d.Locations {
location, _, err := d.getClient().Location.GetByName(context.Background(), locationName)

if err != nil {
return []*hcloud.Location{location}, errors.Wrap(err, "could not get location by name")
}

locations = append(locations, location)
}

location, _, err := d.getClient().Location.GetByName(context.Background(), d.Location)
d.cachedLocations = locations
return locations, nil
}

func (d *Driver) getRandomLocation() (*hcloud.Location, error) {
locations, err := d.getLocations()
if err != nil {
return location, errors.Wrap(err, "could not get location by name")
return nil, err
}
d.cachedLocation = location
return location, nil

s := rand.NewSource(time.Now().Unix())
r := rand.New(s)
location := r.Intn(len(locations))

return locations[location], nil
}

func (d *Driver) getLocation() (*hcloud.Location, error) {
return d.getRandomLocation()
}

func (d *Driver) getType() (*hcloud.ServerType, error) {
Expand Down