From 05aea83271ad22d7d0673d997d5c07a0e6b16acc Mon Sep 17 00:00:00 2001 From: Vincent Bernat Date: Mon, 21 Mar 2016 16:16:04 +0100 Subject: [PATCH] exoscale: add support for CoreOS The egoscale binding for exoscale was limiting the images that could be selected by a user to Ubuntu one only. Enable the use of arbitrary images. For example, the following images are now available: - centos-6.6 - centos-7.1 - coreos-stable-835 - debian-7 - debian-8 - ubuntu-12.04 - ubuntu-14.04 - ubuntu-15.10 The default user for non-Ubuntu images are not "ubuntu". Let the user choose the appropriate user ("core" for CoreOS and "debian" for Debian). CoreOS user are likely to want the ability to provide custom user data as it enables the configuration of the etcd cluster. We add an option to provide custom user data file. Moreover, we remove some of the default options as they are not supported in CoreOS and are useless on Debian/Ubuntu: - Resizing of rootfs is already done on all images by default. - Docker Machine will set the hostname as part of the provisioning. Signed-off-by: Vincent Bernat --- Godeps/Godeps.json | 2 +- docs/drivers/exoscale.md | 6 +- drivers/exoscale/exoscale.go | 69 ++++++++++++------- .../pyr/egoscale/src/egoscale/topology.go | 4 +- 4 files changed, 54 insertions(+), 27 deletions(-) diff --git a/Godeps/Godeps.json b/Godeps/Godeps.json index e524aaa4a6..da45a42e9b 100644 --- a/Godeps/Godeps.json +++ b/Godeps/Godeps.json @@ -293,7 +293,7 @@ }, { "ImportPath": "github.com/pyr/egoscale/src/egoscale", - "Rev": "bbaa67324aeeacc90430c1fe0a9c620d3929512e" + "Rev": "347f81398d2ea1f3eebf1cd27ee3183669e34819" }, { "ImportPath": "github.com/rackspace/gophercloud", diff --git a/docs/drivers/exoscale.md b/docs/drivers/exoscale.md index 87d0fd0b17..3aed5be770 100644 --- a/docs/drivers/exoscale.md +++ b/docs/drivers/exoscale.md @@ -25,7 +25,9 @@ Options: - `--exoscale-disk-size`: Disk size for the host in GB (10, 50, 100, 200, 400). - `--exoscale-image`: Image template (eg. ubuntu-14.04, ubuntu-15.10). - `--exoscale-security-group`: Security group. It will be created if it doesn't exist. -- `--exoscale-availability-zone`: exoscale availability zone. +- `--exoscale-availability-zone`: Exoscale availability zone. +- `--exoscale-ssh-user`: SSH username, which must match the default SSH user for the used image. +- `--exoscale-userdata`: Path to file containing user data for cloud-init. If a custom security group is provided, you need to ensure that you allow TCP ports 22 and 2376 in an ingress rule. Moreover, if you want to use Swarm, also add TCP port 3376. @@ -41,3 +43,5 @@ Environment variables and default values: | `--exoscale-image` | `EXOSCALE_IMAGE` | `ubuntu-15.10` | | `--exoscale-security-group` | `EXOSCALE_SECURITY_GROUP` | `docker-machine` | | `--exoscale-availability-zone` | `EXOSCALE_AVAILABILITY_ZONE` | `ch-gva-2` | +| `--exoscale-ssh-user` | `EXOSCALE_SSH_USER` | `ubuntu` | +| `--exoscale-userdata` | `EXOSCALE_USERDATA` | - | diff --git a/drivers/exoscale/exoscale.go b/drivers/exoscale/exoscale.go index dc88172f66..f9540066f7 100644 --- a/drivers/exoscale/exoscale.go +++ b/drivers/exoscale/exoscale.go @@ -1,12 +1,11 @@ package exoscale import ( - "bytes" "fmt" "io/ioutil" "net" + "os" "strings" - "text/template" "time" "github.com/docker/machine/libmachine/drivers" @@ -29,6 +28,7 @@ type Driver struct { AvailabilityZone string KeyPair string PublicKey string + UserDataFile string ID string `json:"Id"` } @@ -37,6 +37,7 @@ const ( defaultDiskSize = 50 defaultImage = "ubuntu-15.10" defaultAvailabilityZone = "ch-gva-2" + defaultSSHUser = "ubuntu" ) // GetCreateFlags registers the flags this driver adds to @@ -88,6 +89,17 @@ func (d *Driver) GetCreateFlags() []mcnflag.Flag { Value: defaultAvailabilityZone, Usage: "exoscale availibility zone", }, + mcnflag.StringFlag{ + EnvVar: "EXOSCALE_SSH_USER", + Name: "exoscale-ssh-user", + Value: defaultSSHUser, + Usage: "Set the name of the ssh user", + }, + mcnflag.StringFlag{ + EnvVar: "EXOSCALE_USERDATA", + Name: "exoscale-userdata", + Usage: "path to file with cloud-init user-data", + }, } } @@ -109,7 +121,11 @@ func (d *Driver) GetSSHHostname() (string, error) { } func (d *Driver) GetSSHUsername() string { - return "ubuntu" + if d.SSHUser == "" { + d.SSHUser = defaultSSHUser + } + + return d.SSHUser } // DriverName returns the name of the driver @@ -130,6 +146,8 @@ func (d *Driver) SetConfigFromFlags(flags drivers.DriverOptions) error { } d.SecurityGroup = strings.Join(securityGroups, ",") d.AvailabilityZone = flags.String("exoscale-availability-zone") + d.SSHUser = flags.String("exoscale-ssh-user") + d.UserDataFile = flags.String("exoscale-userdata") d.SetSwarmConfigFromFlags(flags) if d.URL == "" { @@ -142,6 +160,16 @@ func (d *Driver) SetConfigFromFlags(flags drivers.DriverOptions) error { return nil } +func (d *Driver) PreCreateCheck() error { + if d.UserDataFile != "" { + if _, err := os.Stat(d.UserDataFile); os.IsNotExist(err) { + return fmt.Errorf("user-data file %s could not be found", d.UserDataFile) + } + } + + return nil +} + func (d *Driver) GetURL() (string, error) { if err := drivers.MustBeRunning(d); err != nil { return "", err @@ -226,6 +254,11 @@ func (d *Driver) createDefaultSecurityGroup(client *egoscale.Client, group strin } func (d *Driver) Create() error { + userdata, err := d.getCloudInit() + if err != nil { + return err + } + log.Infof("Querying exoscale for the requested parameters...") client := egoscale.NewClient(d.URL, d.APIKey, d.APISecretKey) topology, err := client.GetTopology() @@ -291,11 +324,6 @@ func (d *Driver) Create() error { d.KeyPair = keypairName log.Infof("Spawn exoscale host...") - - userdata, err := d.getCloudInit() - if err != nil { - return err - } log.Debugf("Using the following cloud-init file:") log.Debugf("%s", userdata) @@ -422,20 +450,15 @@ func (d *Driver) waitForVM(client *egoscale.Client, jobid string) (*egoscale.Dep // Build a cloud-init user data string that will install and run // docker. func (d *Driver) getCloudInit() (string, error) { - const tpl = `#cloud-config -manage_etc_hosts: true -fqdn: {{ .MachineName }} -resize_rootfs: true -` - var buffer bytes.Buffer + if d.UserDataFile != "" { + buf, err := ioutil.ReadFile(d.UserDataFile) + if err != nil { + return "", err + } + return string(buf), nil + } - tmpl, err := template.New("cloud-init").Parse(tpl) - if err != nil { - return "", err - } - err = tmpl.Execute(&buffer, d) - if err != nil { - return "", err - } - return buffer.String(), nil + return `#cloud-config +manage_etc_hosts: true +`, nil } diff --git a/vendor/github.com/pyr/egoscale/src/egoscale/topology.go b/vendor/github.com/pyr/egoscale/src/egoscale/topology.go index 080788d97e..5eb7b4761d 100644 --- a/vendor/github.com/pyr/egoscale/src/egoscale/topology.go +++ b/vendor/github.com/pyr/egoscale/src/egoscale/topology.go @@ -114,12 +114,12 @@ func (exo *Client) GetImages() (map[string]map[int]string, error) { return nil, err } - re := regexp.MustCompile(`^Linux (?PUbuntu|Debian) (?P[0-9.]+).*$`) + re := regexp.MustCompile(`^Linux (?P.+?) (?P[0-9.]+).*$`) for _, template := range r.Templates { size := int(template.Size / (1024 * 1024 * 1024)) submatch := re.FindStringSubmatch(template.Name) if len(submatch) > 0 { - name := strings.ToLower(submatch[1]) + name := strings.Replace(strings.ToLower(submatch[1]), " ", "-", -1) version := submatch[2] image := fmt.Sprintf("%s-%s", name, version)