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 <Vincent.Bernat@exoscale.ch>
This commit is contained in:
Vincent Bernat 2016-03-21 16:16:04 +01:00
parent e536ed6738
commit 05aea83271
4 changed files with 54 additions and 27 deletions

2
Godeps/Godeps.json generated
View File

@ -293,7 +293,7 @@
},
{
"ImportPath": "github.com/pyr/egoscale/src/egoscale",
"Rev": "bbaa67324aeeacc90430c1fe0a9c620d3929512e"
"Rev": "347f81398d2ea1f3eebf1cd27ee3183669e34819"
},
{
"ImportPath": "github.com/rackspace/gophercloud",

View File

@ -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` | - |

View File

@ -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
}

View File

@ -114,12 +114,12 @@ func (exo *Client) GetImages() (map[string]map[int]string, error) {
return nil, err
}
re := regexp.MustCompile(`^Linux (?P<name>Ubuntu|Debian) (?P<version>[0-9.]+).*$`)
re := regexp.MustCompile(`^Linux (?P<name>.+?) (?P<version>[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)