Example #1
0
// Create a single server
func (vp *vultrProvider) createServer(options providers.CreateInstanceOptions) (string, error) {
	// Find SSH key ID
	var sshid string
	if len(options.SSHKeyNames) > 0 {
		var err error
		sshid, err = vp.findSSHKeyID(options.SSHKeyNames[0])
		if err != nil {
			return "", maskAny(err)
		}
	}
	// Fetch SSH keys
	sshKeys, err := providers.FetchSSHKeys(options.SSHKeyGithubAccount)
	if err != nil {
		return "", maskAny(err)
	}

	// Create cloud-config
	// user-data
	ccOpts := options.NewCloudConfigOptions()
	ccOpts.PrivateIPv4 = "$private_ipv4"
	ccOpts.SshKeys = sshKeys
	userData, err := templates.Render(cloudConfigTemplate, ccOpts)
	if err != nil {
		return "", maskAny(err)
	}

	name := options.InstanceName
	opts := &lib.ServerOptions{
		IPV6:              true,
		PrivateNetworking: true,
		SSHKey:            sshid,
		UserData:          userData,
	}
	regionID, err := strconv.Atoi(options.RegionID)
	if err != nil {
		return "", maskAny(err)
	}
	planID, err := strconv.Atoi(options.TypeID)
	if err != nil {
		return "", maskAny(err)
	}
	osID, err := strconv.Atoi(options.ImageID)
	if err != nil {
		return "", maskAny(err)
	}
	server, err := vp.client.CreateServer(name, regionID, planID, osID, opts)
	if err != nil {
		vp.Logger.Debugf("CreateServer failed: %#v", err)
		return "", maskAny(err)
	}
	vp.Logger.Infof("Created server %s %s\n", server.ID, server.Name)

	return server.ID, nil
}
Example #2
0
// bootstrapServer copies etcd & fleet into the instances and runs the scaleway bootstrap script.
// It then reboots the instances and waits until it is active again.
func (vp *scalewayProvider) bootstrapServer(instance providers.ClusterInstance, options providers.CreateInstanceOptions, machineID string) error {
	if err := vp.copyEtcd(instance); err != nil {
		vp.Logger.Errorf("copy etcd failed: %#v", err)
		return maskAny(err)
	}
	if err := vp.copyFleet(instance); err != nil {
		vp.Logger.Errorf("copy fleet failed: %#v", err)
		return maskAny(err)
	}

	// Bootstrap
	bootstrapOptions := struct {
		ScalewayProviderConfig
		providers.CreateInstanceOptions
		MachineID string
	}{
		ScalewayProviderConfig: vp.ScalewayProviderConfig,
		CreateInstanceOptions:  options,
		MachineID:              machineID,
	}
	bootstrap, err := templates.Render(bootstrapTemplate, bootstrapOptions)
	if err != nil {
		return maskAny(err)
	}
	vp.Logger.Infof("Running bootstrap on %s. This may take a while...", instance.Name)
	if err := instance.RunScript(vp.Logger, bootstrap, "/root/pulcy-bootstrap.sh"); err != nil {
		// Failed expected because of a reboot
		vp.Logger.Debugf("bootstrap failed (expected): %#v", err)
	}

	vp.Logger.Infof("Done running bootstrap on %s, rebooting...", instance.Name)
	if err := vp.client.PostServerAction(instance.ID, "reboot"); err != nil {
		vp.Logger.Errorf("reboot failed: %#v", err)
		return maskAny(err)
	}
	time.Sleep(time.Second * 5)
	if _, err := vp.waitUntilServerActive(instance.ID, false); err != nil {
		return maskAny(err)
	}

	vp.Logger.Infof("Created server %s %s\n", instance.ID, instance.Name)

	return nil
}
Example #3
0
// createAndStartServer creates a new server and starts it.
// It then waits until the instance is active.
func (vp *scalewayProvider) createAndStartServer(options providers.CreateInstanceOptions) (providers.ClusterInstance, error) {
	zeroInstance := providers.ClusterInstance{}

	// Validate input
	if options.TincIpv4 == "" {
		return zeroInstance, maskAny(fmt.Errorf("TincIpv4 is empty"))
	}

	// Fetch SSH keys
	sshKeys, err := providers.FetchSSHKeys(options.SSHKeyGithubAccount)
	if err != nil {
		return zeroInstance, maskAny(err)
	}

	// Create cloud-config
	// user-data
	ccOpts := options.NewCloudConfigOptions()
	ccOpts.PrivateIPv4 = "$private_ipv4"
	ccOpts.SshKeys = sshKeys
	_ /*userData*/, err = templates.Render(cloudConfigTemplate, ccOpts)
	if err != nil {
		return zeroInstance, maskAny(err)
	}

	var arch string
	switch options.TypeID[:2] {
	case "C1":
		arch = "arm"
	case "C2", "VC":
		arch = "x86_64"
	}

	// Find image
	imageID, err := vp.getImageID(options.ImageID, arch)
	if err != nil {
		vp.Logger.Errorf("getImageID failed: %#v", err)
		return zeroInstance, maskAny(err)
	}

	name := options.InstanceName
	image := &imageID
	dynamicIPRequired := !vp.NoIPv4
	//bootscript := ""

	volID := ""
	/*if options.TypeID != commercialTypeVC1 {
		volDef := api.ScalewayVolumeDefinition{
			Name:         vp.volumeName(name),
			Size:         volumeSize,
			Type:         volumeType,
			Organization: vp.organization,
		}
		volID, err = vp.client.PostVolume(volDef)
		if err != nil {
			vp.Logger.Errorf("PostVolume failed: %#v", err)
			return zeroInstance, maskAny(err)
		}
	}*/

	publicIPIdentifier := ""
	if options.RoleLoadBalancer && vp.ReserveLoadBalancerIP {
		ip, err := vp.getFreeIP()
		if err != nil {
			return zeroInstance, maskAny(err)
		}
		publicIPIdentifier = ip.ID
	}

	opts := api.ScalewayServerDefinition{
		Name:              name,
		Image:             image,
		Volumes:           map[string]string{},
		DynamicIPRequired: &dynamicIPRequired,
		//Bootscript:        &bootscript,
		Tags: []string{
			options.ClusterInfo.ID,
			options.TincIpv4,
		},
		Organization:   vp.Organization,
		CommercialType: options.TypeID,
		PublicIP:       publicIPIdentifier,
		EnableIPV6:     vp.EnableIPV6,
	}
	if volID != "" {
		opts.Volumes["0"] = volID
	}
	vp.Logger.Debugf("Creating server %s: %#v\n", name, opts)
	id, err := vp.client.PostServer(opts)
	if err != nil {
		vp.Logger.Errorf("PostServer failed: %#v", err)
		// Delete volume
		if volID != "" {
			if err := vp.client.DeleteVolume(volID); err != nil {
				vp.Logger.Errorf("DeleteVolume failed: %#v", err)
			}
		}
		return zeroInstance, maskAny(err)
	}

	// Start server
	if err := vp.client.PostServerAction(id, "poweron"); err != nil {
		vp.Logger.Errorf("poweron failed: %#v", err)
		return zeroInstance, maskAny(err)
	}

	// Wait until server starts
	server, err := vp.waitUntilServerActive(id, true)
	if err != nil {
		return zeroInstance, maskAny(err)
	}

	// Download & copy fleet,etcd
	instance := vp.clusterInstance(server, true)
	return instance, nil
}
Example #4
0
// Create an entire cluster
func (vp *vagrantProvider) CreateCluster(log *logging.Logger, options providers.CreateClusterOptions, dnsProvider providers.DnsProvider) error {
	// Ensure folder exists
	if err := os.MkdirAll(vp.folder, fileMode|os.ModeDir); err != nil {
		return maskAny(err)
	}

	if _, err := os.Stat(filepath.Join(vp.folder, ".vagrant")); err == nil {
		return maskAny(fmt.Errorf("Vagrant in %s already exists", vp.folder))
	}

	parts := strings.Split(options.ImageID, "-")
	if len(parts) != 2 || parts[0] != "coreos" {
		return maskAny(fmt.Errorf("Invalid image ID, expected 'coreos-alpha|beta|stable', got '%s'", options.ImageID))
	}
	updateChannel := parts[1]

	vopts := struct {
		InstanceCount int
		UpdateChannel string
	}{
		InstanceCount: options.InstanceCount,
		UpdateChannel: updateChannel,
	}
	vp.instanceCount = options.InstanceCount

	// Vagrantfile
	content, err := templates.Render(vagrantFileTemplate, vopts)
	if err != nil {
		return maskAny(err)
	}
	if err := ioutil.WriteFile(filepath.Join(vp.folder, vagrantFileName), []byte(content), fileMode); err != nil {
		return maskAny(err)
	}

	// config.rb
	content, err = templates.Render(configTemplate, vopts)
	if err != nil {
		return maskAny(err)
	}
	if err := ioutil.WriteFile(filepath.Join(vp.folder, configFileName), []byte(content), fileMode); err != nil {
		return maskAny(err)
	}

	// Fetch SSH keys
	sshKeys, err := providers.FetchSSHKeys(options.SSHKeyGithubAccount)
	if err != nil {
		return maskAny(err)
	}
	// Fetch vagrant insecure private key
	insecureKey, err := fetchVagrantInsecureSSHKey()
	if err != nil {
		return maskAny(err)
	}
	sshKeys = append(sshKeys, insecureKey)

	// user-data
	isCore := true
	isLB := true
	instanceOptions, err := options.NewCreateInstanceOptions(isCore, isLB, 0)
	if err != nil {
		return maskAny(err)
	}
	opts := instanceOptions.NewCloudConfigOptions()
	opts.PrivateIPv4 = "$private_ipv4"
	opts.SshKeys = sshKeys

	content, err = templates.Render(cloudConfigTemplate, opts)
	if err != nil {
		return maskAny(err)
	}
	if err := ioutil.WriteFile(filepath.Join(vp.folder, userDataFileName), []byte(content), fileMode); err != nil {
		return maskAny(err)
	}

	// Start
	cmd := exec.Command("vagrant", "up")
	cmd.Dir = vp.folder
	cmd.Stdout = os.Stdout
	cmd.Stderr = os.Stderr
	cmd.Stdin = os.Stdin
	if err := cmd.Run(); err != nil {
		return maskAny(err)
	}

	// Run initial setup
	instances, err := vp.GetInstances(providers.ClusterInfo{})
	if err != nil {
		return maskAny(err)
	}
	clusterMembers, err := instances.AsClusterMemberList(log, nil)
	if err != nil {
		return maskAny(err)
	}
	for index, instance := range instances {
		iso := providers.InitialSetupOptions{
			ClusterMembers: clusterMembers,
			FleetMetadata:  instanceOptions.CreateFleetMetadata(index),
		}
		if err := instance.InitialSetup(log, instanceOptions, iso, vp); err != nil {
			return maskAny(err)
		}
	}

	return nil
}
Example #5
0
func (dp *doProvider) CreateInstance(log *logging.Logger, options providers.CreateInstanceOptions, dnsProvider providers.DnsProvider) (providers.ClusterInstance, error) {
	client := NewDOClient(dp.token)

	keys := []godo.DropletCreateSSHKey{}
	listedKeys, err := KeyList(client)
	if err != nil {
		return providers.ClusterInstance{}, maskAny(err)
	}
	for _, key := range options.SSHKeyNames {
		k := findKeyID(key, listedKeys)
		if k == nil {
			return providers.ClusterInstance{}, maskAny(errors.New("Key not found"))
		}
		keys = append(keys, godo.DropletCreateSSHKey{ID: k.ID})
	}

	opts := options.NewCloudConfigOptions()
	opts.PrivateIPv4 = "$private_ipv4"

	cloudConfig, err := templates.Render(cloudConfigTemplate, opts)
	if err != nil {
		return providers.ClusterInstance{}, maskAny(err)
	}

	request := &godo.DropletCreateRequest{
		Name:              options.InstanceName,
		Region:            options.RegionID,
		Size:              options.TypeID,
		Image:             godo.DropletCreateImage{Slug: options.ImageID},
		SSHKeys:           keys,
		Backups:           false,
		IPv6:              true,
		PrivateNetworking: true,
		UserData:          cloudConfig,
	}

	// Create droplet
	dp.Logger.Infof("Creating droplet: %s, %s, %s", request.Region, request.Size, options.ImageID)
	dp.Logger.Debugf(cloudConfig)
	createDroplet, _, err := client.Droplets.Create(request)
	if err != nil {
		return providers.ClusterInstance{}, maskAny(err)
	}

	// Wait for active
	dp.Logger.Infof("Waiting for droplet '%s'", createDroplet.Name)
	droplet, err := dp.waitUntilDropletActive(createDroplet.ID)
	if err != nil {
		return providers.ClusterInstance{}, maskAny(err)
	}

	privateIpv4 := getIpv4(*droplet, "private")
	publicIpv4 := getIpv4(*droplet, "public")
	publicIpv6 := getIpv6(*droplet, "public")
	if err := providers.RegisterInstance(dp.Logger, dnsProvider, options, createDroplet.Name, options.RegisterInstance, options.RoleLoadBalancer, options.RoleLoadBalancer, publicIpv4, publicIpv6, privateIpv4); err != nil {
		return providers.ClusterInstance{}, maskAny(err)
	}

	dp.Logger.Infof("Droplet '%s' is ready", createDroplet.Name)

	return dp.clusterInstance(*droplet), nil
}