func (d *Driver) Create() error {
	cloudInit, 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)

	resp, err := client.RequestWithContext(context.TODO(), &egoscale.ListZones{
		Name: d.AvailabilityZone,
	})
	if err != nil {
		return err
	}

	zones := resp.(*egoscale.ListZonesResponse)
	if len(zones.Zone) != 1 {
		return fmt.Errorf("Availability zone %v doesn't exist",
			d.AvailabilityZone)
	}
	zone := zones.Zone[0].ID
	log.Debugf("Availability zone %v = %s", d.AvailabilityZone, zone)

	// Image
	template := egoscale.Template{
		IsFeatured: true,
		ZoneID:     "1", // GVA2
	}

	templates, err := client.ListWithContext(context.TODO(), &template)
	if err != nil {
		return err
	}

	image := strings.ToLower(d.Image)
	re := regexp.MustCompile(`^Linux (?P<name>.+?) (?P<version>[0-9.]+)\b`)

	for _, t := range templates {
		tpl := t.(*egoscale.Template)

		// Keep only 10GiB images
		if tpl.Size>>30 != 10 {
			continue
		}

		fullname := strings.ToLower(tpl.Name)
		if image == fullname {
			template = *tpl
			break
		}

		submatch := re.FindStringSubmatch(tpl.Name)
		if len(submatch) > 0 {
			name := strings.Replace(strings.ToLower(submatch[1]), " ", "-", -1)
			version := submatch[2]
			shortname := fmt.Sprintf("%s-%s", name, version)

			if image == shortname {
				template = *tpl
				break
			}
		}
	}
	if template.ID == "" {
		return fmt.Errorf("Unable to find image %v", d.Image)
	}

	// Reading the username from the template
	if name, ok := template.Details["username"]; ok {
		d.SSHUser = name
	}
	log.Debugf("Image %v(10) = %s (%s)", d.Image, template.ID, d.SSHUser)

	// Profile UUID
	resp, err = client.RequestWithContext(context.TODO(), &egoscale.ListServiceOfferings{
		Name: d.InstanceProfile,
	})
	if err != nil {
		return err
	}
	profiles := resp.(*egoscale.ListServiceOfferingsResponse)
	if len(profiles.ServiceOffering) != 1 {
		return fmt.Errorf("Unable to find the %s profile",
			d.InstanceProfile)
	}
	profile := profiles.ServiceOffering[0].ID
	log.Debugf("Profile %v = %s", d.InstanceProfile, profile)

	// Security groups
	sgs := make([]string, 0, len(d.SecurityGroups))
	for _, group := range d.SecurityGroups {
		if group == "" {
			continue
		}

		sg := &egoscale.SecurityGroup{Name: group}
		if err := client.Get(sg); err != nil {
			if _, ok := err.(*egoscale.ErrorResponse); !ok {
				return err
			}
			log.Infof("Security group %v does not exist. Creating it...", group)
			securityGroup, err := d.createDefaultSecurityGroup(group)
			if err != nil {
				return err
			}
			sg.ID = securityGroup.ID
		}

		log.Debugf("Security group %v = %s", group, sg.ID)
		sgs = append(sgs, sg.ID)
	}

	// Affinity Groups
	ags := make([]string, 0, len(d.AffinityGroups))
	for _, group := range d.AffinityGroups {
		if group == "" {
			continue
		}
		ag := &egoscale.AffinityGroup{Name: group}
		if err := client.Get(ag); err != nil {
			if _, ok := err.(*egoscale.ErrorResponse); !ok {
				return err
			}
			log.Infof("Affinity Group %v does not exist, create it", group)
			affinityGroup, err := d.createDefaultAffinityGroup(group)
			if err != nil {
				return err
			}
			ag.ID = affinityGroup.ID
		}
		log.Debugf("Affinity group %v = %s", group, ag.ID)
		ags = append(ags, ag.ID)
	}

	// SSH key pair
	if d.SSHKey == "" {
		var keyPairName string
		keyPairName = fmt.Sprintf("docker-machine-%s", d.MachineName)
		log.Infof("Generate an SSH keypair...")
		resp, err := client.RequestWithContext(context.TODO(), &egoscale.CreateSSHKeyPair{
			Name: keyPairName,
		})
		if err != nil {
			return fmt.Errorf("SSH Key pair creation failed %s", err)
		}
		keyPair := resp.(*egoscale.CreateSSHKeyPairResponse).KeyPair
		if err = os.MkdirAll(filepath.Dir(d.GetSSHKeyPath()), 0750); err != nil {
			return fmt.Errorf("Cannot create the folder to store the SSH private key. %s", err)
		}
		if err = ioutil.WriteFile(d.GetSSHKeyPath(), []byte(keyPair.PrivateKey), 0600); err != nil {
			return fmt.Errorf("SSH private key could not be written. %s", err)
		}
		d.KeyPair = keyPairName
	} else {
		log.Infof("Importing SSH key from %s", d.SSHKey)

		sshKey := d.SSHKey
		if strings.HasPrefix(sshKey, "~/") {
			usr, _ := user.Current()
			sshKey = filepath.Join(usr.HomeDir, sshKey[2:])
		} else {
			var err error
			if sshKey, err = filepath.Abs(sshKey); err != nil {
				return err
			}
		}

		// Sending the SSH public key through the cloud-init config
		pubKey, err := ioutil.ReadFile(sshKey + ".pub")
		if err != nil {
			return fmt.Errorf("Cannot read SSH public key %s", err)
		}

		sshAuthorizedKeys := `
ssh_authorized_keys:
- `
		cloudInit = bytes.Join([][]byte{cloudInit, []byte(sshAuthorizedKeys), pubKey}, []byte(""))

		// Copying the private key into docker-machine
		if err := mcnutils.CopyFile(sshKey, d.GetSSHKeyPath()); err != nil {
			return fmt.Errorf("Unable to copy SSH file: %s", err)
		}
		if err := os.Chmod(d.GetSSHKeyPath(), 0600); err != nil {
			return fmt.Errorf("Unable to set permissions on the SSH file: %s", err)
		}
	}

	log.Infof("Spawn exoscale host...")
	log.Debugf("Using the following cloud-init file:")
	log.Debugf("%s", string(cloudInit))

	// Base64 encode the userdata
	d.UserData = cloudInit
	encodedUserData := base64.StdEncoding.EncodeToString(d.UserData)

	req := &egoscale.DeployVirtualMachine{
		TemplateID:        template.ID,
		ServiceOfferingID: profile,
		UserData:          encodedUserData,
		ZoneID:            zone,
		Name:              d.MachineName,
		KeyPair:           d.KeyPair,
		DisplayName:       d.MachineName,
		RootDiskSize:      d.DiskSize,
		SecurityGroupIDs:  sgs,
		AffinityGroupIDs:  ags,
	}
	log.Infof("Deploy %#v", req)
	resp, err = client.RequestWithContext(context.TODO(), req)
	if err != nil {
		return err
	}

	vm := resp.(*egoscale.DeployVirtualMachineResponse).VirtualMachine

	IPAddress := vm.Nic[0].IPAddress
	if IPAddress != nil {
		d.IPAddress = IPAddress.String()
	}
	d.ID = vm.ID
	log.Infof("IP Address: %v, SSH User: %v", d.IPAddress, d.GetSSHUsername())

	if vm.PasswordEnabled {
		d.Password = vm.Password
	}

	// Destroy the SSH key from CloudStack
	if d.KeyPair != "" {
		if err := drivers.WaitForSSH(d); err != nil {
			return err
		}

		key := &egoscale.SSHKeyPair{
			Name: d.KeyPair,
		}
		if err := client.DeleteWithContext(context.TODO(), key); err != nil {
			return err
		}
		d.KeyPair = ""
	}

	return nil
}
func (d *Driver) Create() error {
	cloudInit, 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)

	resp, err := client.RequestWithContext(context.TODO(), &egoscale.ListZones{
		Name: d.AvailabilityZone,
	})
	if err != nil {
		return err
	}

	zones := resp.(*egoscale.ListZonesResponse)
	if len(zones.Zone) != 1 {
		return fmt.Errorf("Availability zone %v doesn't exist",
			d.AvailabilityZone)
	}
	zone := zones.Zone[0].ID
	log.Debugf("Availability zone %v = %s", d.AvailabilityZone, zone)

	
	template := egoscale.Template{
		IsFeatured: true,
		ZoneID:     "1", 
	}

	templates, err := client.ListWithContext(context.TODO(), &template)
	if err != nil {
		return err
	}

	image := strings.ToLower(d.Image)
	re := regexp.MustCompile(`^Linux (?P<name>.+?) (?P<version>[0-9.]+)\b`)

	for _, t := range templates {
		tpl := t.(*egoscale.Template)

		
		if tpl.Size>>30 != 10 {
			continue
		}

		fullname := strings.ToLower(tpl.Name)
		if image == fullname {
			template = *tpl
			break
		}

		submatch := re.FindStringSubmatch(tpl.Name)
		if len(submatch) > 0 {
			name := strings.Replace(strings.ToLower(submatch[1]), " ", "-", -1)
			version := submatch[2]
			shortname := fmt.Sprintf("%s-%s", name, version)

			if image == shortname {
				template = *tpl
				break
			}
		}
	}
	if template.ID == "" {
		return fmt.Errorf("Unable to find image %v", d.Image)
	}

	
	if name, ok := template.Details["username"]; ok {
		d.SSHUser = name
	}
	log.Debugf("Image %v(10) = %s (%s)", d.Image, template.ID, d.SSHUser)

	
	resp, err = client.RequestWithContext(context.TODO(), &egoscale.ListServiceOfferings{
		Name: d.InstanceProfile,
	})
	if err != nil {
		return err
	}
	profiles := resp.(*egoscale.ListServiceOfferingsResponse)
	if len(profiles.ServiceOffering) != 1 {
		return fmt.Errorf("Unable to find the %s profile",
			d.InstanceProfile)
	}
	profile := profiles.ServiceOffering[0].ID
	log.Debugf("Profile %v = %s", d.InstanceProfile, profile)

	
	sgs := make([]string, 0, len(d.SecurityGroups))
	for _, group := range d.SecurityGroups {
		if group == "" {
			continue
		}

		sg := &egoscale.SecurityGroup{Name: group}
		if err := client.Get(sg); err != nil {
			if _, ok := err.(*egoscale.ErrorResponse); !ok {
				return err
			}
			log.Infof("Security group %v does not exist. Creating it...", group)
			securityGroup, err := d.createDefaultSecurityGroup(group)
			if err != nil {
				return err
			}
			sg.ID = securityGroup.ID
		}

		log.Debugf("Security group %v = %s", group, sg.ID)
		sgs = append(sgs, sg.ID)
	}

	
	ags := make([]string, 0, len(d.AffinityGroups))
	for _, group := range d.AffinityGroups {
		if group == "" {
			continue
		}
		ag := &egoscale.AffinityGroup{Name: group}
		if err := client.Get(ag); err != nil {
			if _, ok := err.(*egoscale.ErrorResponse); !ok {
				return err
			}
			log.Infof("Affinity Group %v does not exist, create it", group)
			affinityGroup, err := d.createDefaultAffinityGroup(group)
			if err != nil {
				return err
			}
			ag.ID = affinityGroup.ID
		}
		log.Debugf("Affinity group %v = %s", group, ag.ID)
		ags = append(ags, ag.ID)
	}

	
	if d.SSHKey == "" {
		var keyPairName string
		keyPairName = fmt.Sprintf("docker-machine-%s", d.MachineName)
		log.Infof("Generate an SSH keypair...")
		resp, err := client.RequestWithContext(context.TODO(), &egoscale.CreateSSHKeyPair{
			Name: keyPairName,
		})
		if err != nil {
			return fmt.Errorf("SSH Key pair creation failed %s", err)
		}
		keyPair := resp.(*egoscale.CreateSSHKeyPairResponse).KeyPair
		if err = os.MkdirAll(filepath.Dir(d.GetSSHKeyPath()), 0750); err != nil {
			return fmt.Errorf("Cannot create the folder to store the SSH private key. %s", err)
		}
		if err = ioutil.WriteFile(d.GetSSHKeyPath(), []byte(keyPair.PrivateKey), 0600); err != nil {
			return fmt.Errorf("SSH private key could not be written. %s", err)
		}
		d.KeyPair = keyPairName
	} else {
		log.Infof("Importing SSH key from %s", d.SSHKey)

		sshKey := d.SSHKey
		if strings.HasPrefix(sshKey, "~/") {
			usr, _ := user.Current()
			sshKey = filepath.Join(usr.HomeDir, sshKey[2:])
		} else {
			var err error
			if sshKey, err = filepath.Abs(sshKey); err != nil {
				return err
			}
		}

		
		pubKey, err := ioutil.ReadFile(sshKey + ".pub")
		if err != nil {
			return fmt.Errorf("Cannot read SSH public key %s", err)
		}

		sshAuthorizedKeys := `
ssh_authorized_keys:
- `
		cloudInit = bytes.Join([][]byte{cloudInit, []byte(sshAuthorizedKeys), pubKey}, []byte(""))

		
		if err := mcnutils.CopyFile(sshKey, d.GetSSHKeyPath()); err != nil {
			return fmt.Errorf("Unable to copy SSH file: %s", err)
		}
		if err := os.Chmod(d.GetSSHKeyPath(), 0600); err != nil {
			return fmt.Errorf("Unable to set permissions on the SSH file: %s", err)
		}
	}

	log.Infof("Spawn exoscale host...")
	log.Debugf("Using the following cloud-init file:")
	log.Debugf("%s", string(cloudInit))

	
	d.UserData = cloudInit
	encodedUserData := base64.StdEncoding.EncodeToString(d.UserData)

	req := &egoscale.DeployVirtualMachine{
		TemplateID:        template.ID,
		ServiceOfferingID: profile,
		UserData:          encodedUserData,
		ZoneID:            zone,
		Name:              d.MachineName,
		KeyPair:           d.KeyPair,
		DisplayName:       d.MachineName,
		RootDiskSize:      d.DiskSize,
		SecurityGroupIDs:  sgs,
		AffinityGroupIDs:  ags,
	}
	log.Infof("Deploy %#v", req)
	resp, err = client.RequestWithContext(context.TODO(), req)
	if err != nil {
		return err
	}

	vm := resp.(*egoscale.DeployVirtualMachineResponse).VirtualMachine

	IPAddress := vm.Nic[0].IPAddress
	if IPAddress != nil {
		d.IPAddress = IPAddress.String()
	}
	d.ID = vm.ID
	log.Infof("IP Address: %v, SSH User: %v", d.IPAddress, d.GetSSHUsername())

	if vm.PasswordEnabled {
		d.Password = vm.Password
	}

	
	if d.KeyPair != "" {
		if err := drivers.WaitForSSH(d); err != nil {
			return err
		}

		key := &egoscale.SSHKeyPair{
			Name: d.KeyPair,
		}
		if err := client.DeleteWithContext(context.TODO(), key); err != nil {
			return err
		}
		d.KeyPair = ""
	}

	return nil
}
func ( d * Driver ) Create ( ) error { cloudInit , err := d . getCloudInit ( ) if err != nil { return err } log . Infof ( " " ) client := egoscale . NewClient ( d . URL , d . APIKey , d . APISecretKey ) resp , err := client . RequestWithContext ( context . TODO ( ) , & egoscale . ListZones { Name : d . AvailabilityZone , } ) if err != nil { return err } zones := resp . ( * egoscale . ListZonesResponse ) if len ( zones . Zone ) != 1 { return fmt . Errorf ( " " , d . AvailabilityZone ) } zone := zones . Zone [ 0 ] . ID log . Debugf ( " " , d . AvailabilityZone , zone ) // Image template := egoscale . Template { IsFeatured : true , ZoneID : " " , // GVA2 } templates , err := client . ListWithContext ( context . TODO ( ) , & template ) if err != nil { return err } image := strings . ToLower ( d . Image ) re := regexp . MustCompile ( `^Linux (?P<name>.+?) (?P<version>[0-9.]+)\b` ) for _ , t := range templates { tpl := t . ( * egoscale . Template ) // Keep only 10GiB images if tpl . Size >> 30 != 10 { continue } fullname := strings . ToLower ( tpl . Name ) if image == fullname { template = * tpl break } submatch := re . FindStringSubmatch ( tpl . Name ) if len ( submatch ) > 0 { name := strings . Replace ( strings . ToLower ( submatch [ 1 ] ) , " " , " " , - 1 ) version := submatch [ 2 ] shortname := fmt . Sprintf ( " " , name , version ) if image == shortname { template = * tpl break } } } if template . ID == " " { return fmt . Errorf ( " " , d . Image ) } // Reading the username from the template if name , ok := template . Details [ " " ] ; ok { d . SSHUser = name } log . Debugf ( " " , d . Image , template . ID , d . SSHUser ) // Profile UUID resp , err = client . RequestWithContext ( context . TODO ( ) , & egoscale . ListServiceOfferings { Name : d . InstanceProfile , } ) if err != nil { return err } profiles := resp . ( * egoscale . ListServiceOfferingsResponse ) if len ( profiles . ServiceOffering ) != 1 { return fmt . Errorf ( " " , d . InstanceProfile ) } profile := profiles . ServiceOffering [ 0 ] . ID log . Debugf ( " " , d . InstanceProfile , profile ) // Security groups sgs := make ( [ ] string , 0 , len ( d . SecurityGroups ) ) for _ , group := range d . SecurityGroups { if group == " " { continue } sg := & egoscale . SecurityGroup { Name : group } if err := client . Get ( sg ) ; err != nil { if _ , ok := err . ( * egoscale . ErrorResponse ) ; ! ok { return err } log . Infof ( " " , group ) securityGroup , err := d . createDefaultSecurityGroup ( group ) if err != nil { return err } sg . ID = securityGroup . ID } log . Debugf ( " " , group , sg . ID ) sgs = append ( sgs , sg . ID ) } // Affinity Groups ags := make ( [ ] string , 0 , len ( d . AffinityGroups ) ) for _ , group := range d . AffinityGroups { if group == " " { continue } ag := & egoscale . AffinityGroup { Name : group } if err := client . Get ( ag ) ; err != nil { if _ , ok := err . ( * egoscale . ErrorResponse ) ; ! ok { return err } log . Infof ( " " , group ) affinityGroup , err := d . createDefaultAffinityGroup ( group ) if err != nil { return err } ag . ID = affinityGroup . ID } log . Debugf ( " " , group , ag . ID ) ags = append ( ags , ag . ID ) } // SSH key pair if d . SSHKey == " " { var keyPairName string keyPairName = fmt . Sprintf ( " " , d . MachineName ) log . Infof ( " " ) resp , err := client . RequestWithContext ( context . TODO ( ) , & egoscale . CreateSSHKeyPair { Name : keyPairName , } ) if err != nil { return fmt . Errorf ( " " , err ) } keyPair := resp . ( * egoscale . CreateSSHKeyPairResponse ) . KeyPair if err = os . MkdirAll ( filepath . Dir ( d . GetSSHKeyPath ( ) ) , 0750 ) ; err != nil { return fmt . Errorf ( " " , err ) } if err = ioutil . WriteFile ( d . GetSSHKeyPath ( ) , [ ] byte ( keyPair . PrivateKey ) , 0600 ) ; err != nil { return fmt . Errorf ( " " , err ) } d . KeyPair = keyPairName } else { log . Infof ( " " , d . SSHKey ) sshKey := d . SSHKey if strings . HasPrefix ( sshKey , " " ) { usr , _ := user . Current ( ) sshKey = filepath . Join ( usr . HomeDir , sshKey [ 2 : ] ) } else { var err error if sshKey , err = filepath . Abs ( sshKey ) ; err != nil { return err } } // Sending the SSH public key through the cloud-init config pubKey , err := ioutil . ReadFile ( sshKey + " " ) if err != nil { return fmt . Errorf ( " " , err ) } sshAuthorizedKeys := `
ssh_authorized_keys:
- ` cloudInit = bytes . Join ( [ ] [ ] byte { cloudInit , [ ] byte ( sshAuthorizedKeys ) , pubKey } , [ ] byte ( " " ) ) // Copying the private key into docker-machine if err := mcnutils . CopyFile ( sshKey , d . GetSSHKeyPath ( ) ) ; err != nil { return fmt . Errorf ( " " , err ) } if err := os . Chmod ( d . GetSSHKeyPath ( ) , 0600 ) ; err != nil { return fmt . Errorf ( " " , err ) } } log . Infof ( " " ) log . Debugf ( " " ) log . Debugf ( " " , string ( cloudInit ) ) // Base64 encode the userdata d . UserData = cloudInit encodedUserData := base64 . StdEncoding . EncodeToString ( d . UserData ) req := & egoscale . DeployVirtualMachine { TemplateID : template . ID , ServiceOfferingID : profile , UserData : encodedUserData , ZoneID : zone , Name : d . MachineName , KeyPair : d . KeyPair , DisplayName : d . MachineName , RootDiskSize : d . DiskSize , SecurityGroupIDs : sgs , AffinityGroupIDs : ags , } log . Infof ( " " , req ) resp , err = client . RequestWithContext ( context . TODO ( ) , req ) if err != nil { return err } vm := resp . ( * egoscale . DeployVirtualMachineResponse ) . VirtualMachine IPAddress := vm . Nic [ 0 ] . IPAddress if IPAddress != nil { d . IPAddress = IPAddress . String ( ) } d . ID = vm . ID log . Infof ( " " , d . IPAddress , d . GetSSHUsername ( ) ) if vm . PasswordEnabled { d . Password = vm . Password } // Destroy the SSH key from CloudStack if d . KeyPair != " " { if err := drivers . WaitForSSH ( d ) ; err != nil { return err } key := & egoscale . SSHKeyPair { Name : d . KeyPair , } if err := client . DeleteWithContext ( context . TODO ( ) , key ) ; err != nil { return err } d . KeyPair = " " } return nil }
// Create creates the VM instance acting as the docker host
Create creates the VM instance acting as the docker host