Esempio n. 1
0
func (s *StepAllocateIp) Run(state multistep.StateBag) multistep.StepAction {
	ui := state.Get("ui").(packer.Ui)
	config := state.Get("config").(Config)
	server := state.Get("server").(*servers.Server)

	// We need the v2 compute client
	client, err := config.computeV2Client()
	if err != nil {
		err = fmt.Errorf("Error initializing compute client: %s", err)
		state.Put("error", err)
		return multistep.ActionHalt
	}

	var instanceIp floatingip.FloatingIP

	// This is here in case we error out before putting instanceIp into the
	// statebag below, because it is requested by Cleanup()
	state.Put("access_ip", &instanceIp)

	if s.FloatingIp != "" {
		instanceIp.IP = s.FloatingIp
	} else if s.FloatingIpPool != "" {
		ui.Say(fmt.Sprintf("Creating floating IP..."))
		ui.Message(fmt.Sprintf("Pool: %s", s.FloatingIpPool))
		newIp, err := floatingip.Create(client, floatingip.CreateOpts{
			Pool: s.FloatingIpPool,
		}).Extract()
		if err != nil {
			err := fmt.Errorf("Error creating floating ip from pool '%s'", s.FloatingIpPool)
			state.Put("error", err)
			ui.Error(err.Error())
			return multistep.ActionHalt
		}

		instanceIp = *newIp
		ui.Message(fmt.Sprintf("Created floating IP: %s", instanceIp.IP))
	}

	if instanceIp.IP != "" {
		ui.Say(fmt.Sprintf("Associating floating IP with server..."))
		ui.Message(fmt.Sprintf("IP: %s", instanceIp.IP))
		err := floatingip.Associate(client, server.ID, instanceIp.IP).ExtractErr()
		if err != nil {
			err := fmt.Errorf(
				"Error associating floating IP %s with instance: %s",
				instanceIp.IP, err)
			state.Put("error", err)
			ui.Error(err.Error())
			return multistep.ActionHalt
		}

		ui.Message(fmt.Sprintf(
			"Added floating IP %s to instance!", instanceIp.IP))
	}

	state.Put("access_ip", &instanceIp)
	return multistep.ActionContinue
}
Esempio n. 2
0
func (c *GenericClient) assignNovaFloatingIP(d *Driver, floatingIP *FloatingIP) error {
	if floatingIP.Ip == "" {
		f, err := compute_ips.Create(c.Compute, compute_ips.CreateOpts{
			Pool: d.FloatingIPPool,
		}).Extract()
		if err != nil {
			return err
		}
		floatingIP.Ip = f.IP
		floatingIP.Pool = f.Pool
	}
	return compute_ips.Associate(c.Compute, d.MachineId, floatingIP.Ip).Err
}
Esempio n. 3
0
func associateFloatingIP(t *testing.T, client *gophercloud.ServiceClient, serverId string, fip *floatingip.FloatingIP) {
	err := floatingip.Associate(client, serverId, fip.IP).ExtractErr()
	th.AssertNoErr(t, err)
	t.Logf("Associated floating IP %v from instance %v", fip.IP, serverId)
	defer func() {
		err = floatingip.Disassociate(client, serverId, fip.IP).ExtractErr()
		th.AssertNoErr(t, err)
		t.Logf("Disassociated floating IP %v from instance %v", fip.IP, serverId)
	}()
	floatingIp, err := floatingip.Get(client, fip.ID).Extract()
	th.AssertNoErr(t, err)
	t.Logf("Floating IP %v is associated with Fixed IP %v", fip.IP, floatingIp.FixedIP)
}
Esempio n. 4
0
func associateFloatingIPDeprecated(t *testing.T, client *gophercloud.ServiceClient, serverId string, fip *floatingip.FloatingIP) {
	// This form works, but is considered deprecated.
	// See associateFloatingIP or associateFloatingIPFixed
	err := floatingip.Associate(client, serverId, fip.IP).ExtractErr()
	th.AssertNoErr(t, err)
	t.Logf("Associated floating IP %v from instance %v", fip.IP, serverId)
	defer func() {
		err = floatingip.Disassociate(client, serverId, fip.IP).ExtractErr()
		th.AssertNoErr(t, err)
		t.Logf("Disassociated floating IP %v from instance %v", fip.IP, serverId)
	}()
	floatingIp, err := floatingip.Get(client, fip.ID).Extract()
	th.AssertNoErr(t, err)
	t.Logf("Floating IP %v is associated with Fixed IP %v", fip.IP, floatingIp.FixedIP)
}
func resourceComputeInstanceV2Update(d *schema.ResourceData, meta interface{}) error {
	config := meta.(*Config)
	computeClient, err := config.computeV2Client(d.Get("region").(string))
	if err != nil {
		return fmt.Errorf("Error creating OpenStack compute client: %s", err)
	}

	var updateOpts servers.UpdateOpts
	if d.HasChange("name") {
		updateOpts.Name = d.Get("name").(string)
	}
	if d.HasChange("access_ip_v4") {
		updateOpts.AccessIPv4 = d.Get("access_ip_v4").(string)
	}
	if d.HasChange("access_ip_v6") {
		updateOpts.AccessIPv4 = d.Get("access_ip_v6").(string)
	}

	if updateOpts != (servers.UpdateOpts{}) {
		_, err := servers.Update(computeClient, d.Id(), updateOpts).Extract()
		if err != nil {
			return fmt.Errorf("Error updating OpenStack server: %s", err)
		}
	}

	if d.HasChange("metadata") {
		var metadataOpts servers.MetadataOpts
		metadataOpts = make(servers.MetadataOpts)
		newMetadata := d.Get("metadata").(map[string]interface{})
		for k, v := range newMetadata {
			metadataOpts[k] = v.(string)
		}

		_, err := servers.UpdateMetadata(computeClient, d.Id(), metadataOpts).Extract()
		if err != nil {
			return fmt.Errorf("Error updating OpenStack server (%s) metadata: %s", d.Id(), err)
		}
	}

	if d.HasChange("security_groups") {
		oldSGRaw, newSGRaw := d.GetChange("security_groups")
		oldSGSet := oldSGRaw.(*schema.Set)
		newSGSet := newSGRaw.(*schema.Set)
		secgroupsToAdd := newSGSet.Difference(oldSGSet)
		secgroupsToRemove := oldSGSet.Difference(newSGSet)

		log.Printf("[DEBUG] Security groups to add: %v", secgroupsToAdd)

		log.Printf("[DEBUG] Security groups to remove: %v", secgroupsToRemove)

		for _, g := range secgroupsToRemove.List() {
			err := secgroups.RemoveServerFromGroup(computeClient, d.Id(), g.(string)).ExtractErr()
			if err != nil {
				errCode, ok := err.(*gophercloud.UnexpectedResponseCodeError)
				if !ok {
					return fmt.Errorf("Error removing security group from OpenStack server (%s): %s", d.Id(), err)
				}
				if errCode.Actual == 404 {
					continue
				} else {
					return fmt.Errorf("Error removing security group from OpenStack server (%s): %s", d.Id(), err)
				}
			} else {
				log.Printf("[DEBUG] Removed security group (%s) from instance (%s)", g.(string), d.Id())
			}
		}
		for _, g := range secgroupsToAdd.List() {
			err := secgroups.AddServerToGroup(computeClient, d.Id(), g.(string)).ExtractErr()
			if err != nil {
				return fmt.Errorf("Error adding security group to OpenStack server (%s): %s", d.Id(), err)
			}
			log.Printf("[DEBUG] Added security group (%s) to instance (%s)", g.(string), d.Id())
		}

	}

	if d.HasChange("admin_pass") {
		if newPwd, ok := d.Get("admin_pass").(string); ok {
			err := servers.ChangeAdminPassword(computeClient, d.Id(), newPwd).ExtractErr()
			if err != nil {
				return fmt.Errorf("Error changing admin password of OpenStack server (%s): %s", d.Id(), err)
			}
		}
	}

	if d.HasChange("floating_ip") {
		oldFIP, newFIP := d.GetChange("floating_ip")
		log.Printf("[DEBUG] Old Floating IP: %v", oldFIP)
		log.Printf("[DEBUG] New Floating IP: %v", newFIP)
		if oldFIP.(string) != "" {
			log.Printf("[DEBUG] Attemping to disassociate %s from %s", oldFIP, d.Id())
			if err := floatingip.Disassociate(computeClient, d.Id(), oldFIP.(string)).ExtractErr(); err != nil {
				return fmt.Errorf("Error disassociating Floating IP during update: %s", err)
			}
		}

		if newFIP.(string) != "" {
			log.Printf("[DEBUG] Attemping to associate %s to %s", newFIP, d.Id())
			if err := floatingip.Associate(computeClient, d.Id(), newFIP.(string)).ExtractErr(); err != nil {
				return fmt.Errorf("Error associating Floating IP during update: %s", err)
			}
		}
	}

	if d.HasChange("volume") {
		// ensure the volume configuration is correct
		if err := checkVolumeConfig(d); err != nil {
			return err
		}

		// old attachments and new attachments
		oldAttachments, newAttachments := d.GetChange("volume")

		// for each old attachment, detach the volume
		oldAttachmentSet := oldAttachments.(*schema.Set).List()
		if blockClient, err := config.blockStorageV1Client(d.Get("region").(string)); err != nil {
			return err
		} else {
			if err := detachVolumesFromInstance(computeClient, blockClient, d.Id(), oldAttachmentSet); err != nil {
				return err
			}
		}

		// for each new attachment, attach the volume
		newAttachmentSet := newAttachments.(*schema.Set).List()
		if blockClient, err := config.blockStorageV1Client(d.Get("region").(string)); err != nil {
			return err
		} else {
			if err := attachVolumesToInstance(computeClient, blockClient, d.Id(), newAttachmentSet); err != nil {
				return err
			}
		}

		d.SetPartial("volume")
	}

	if d.HasChange("flavor_id") || d.HasChange("flavor_name") {
		flavorId, err := getFlavorID(computeClient, d)
		if err != nil {
			return err
		}
		resizeOpts := &servers.ResizeOpts{
			FlavorRef: flavorId,
		}
		log.Printf("[DEBUG] Resize configuration: %#v", resizeOpts)
		err = servers.Resize(computeClient, d.Id(), resizeOpts).ExtractErr()
		if err != nil {
			return fmt.Errorf("Error resizing OpenStack server: %s", err)
		}

		// Wait for the instance to finish resizing.
		log.Printf("[DEBUG] Waiting for instance (%s) to finish resizing", d.Id())

		stateConf := &resource.StateChangeConf{
			Pending:    []string{"RESIZE"},
			Target:     "VERIFY_RESIZE",
			Refresh:    ServerV2StateRefreshFunc(computeClient, d.Id()),
			Timeout:    3 * time.Minute,
			Delay:      10 * time.Second,
			MinTimeout: 3 * time.Second,
		}

		_, err = stateConf.WaitForState()
		if err != nil {
			return fmt.Errorf("Error waiting for instance (%s) to resize: %s", d.Id(), err)
		}

		// Confirm resize.
		log.Printf("[DEBUG] Confirming resize")
		err = servers.ConfirmResize(computeClient, d.Id()).ExtractErr()
		if err != nil {
			return fmt.Errorf("Error confirming resize of OpenStack server: %s", err)
		}

		stateConf = &resource.StateChangeConf{
			Pending:    []string{"VERIFY_RESIZE"},
			Target:     "ACTIVE",
			Refresh:    ServerV2StateRefreshFunc(computeClient, d.Id()),
			Timeout:    3 * time.Minute,
			Delay:      10 * time.Second,
			MinTimeout: 3 * time.Second,
		}

		_, err = stateConf.WaitForState()
		if err != nil {
			return fmt.Errorf("Error waiting for instance (%s) to confirm resize: %s", d.Id(), err)
		}
	}

	return resourceComputeInstanceV2Read(d, meta)
}
func resourceComputeInstanceV2Create(d *schema.ResourceData, meta interface{}) error {
	config := meta.(*Config)
	computeClient, err := config.computeV2Client(d.Get("region").(string))
	if err != nil {
		return fmt.Errorf("Error creating OpenStack compute client: %s", err)
	}

	var createOpts servers.CreateOptsBuilder

	// Determines the Image ID using the following rules:
	// If a bootable block_device was specified, ignore the image altogether.
	// If an image_id was specified, use it.
	// If an image_name was specified, look up the image ID, report if error.
	imageId, err := getImageIDFromConfig(computeClient, d)
	if err != nil {
		return err
	}

	flavorId, err := getFlavorID(computeClient, d)
	if err != nil {
		return err
	}

	networkDetails, err := resourceInstanceNetworks(computeClient, d)
	if err != nil {
		return err
	}

	// determine if volume/block_device configuration is correct
	// this includes ensuring volume_ids are set
	// and if only one block_device was specified.
	if err := checkVolumeConfig(d); err != nil {
		return err
	}

	networks := make([]servers.Network, len(networkDetails))
	for i, net := range networkDetails {
		networks[i] = servers.Network{
			UUID:    net["uuid"].(string),
			Port:    net["port"].(string),
			FixedIP: net["fixed_ip_v4"].(string),
		}
	}

	createOpts = &servers.CreateOpts{
		Name:             d.Get("name").(string),
		ImageRef:         imageId,
		FlavorRef:        flavorId,
		SecurityGroups:   resourceInstanceSecGroupsV2(d),
		AvailabilityZone: d.Get("availability_zone").(string),
		Networks:         networks,
		Metadata:         resourceInstanceMetadataV2(d),
		ConfigDrive:      d.Get("config_drive").(bool),
		AdminPass:        d.Get("admin_pass").(string),
		UserData:         []byte(d.Get("user_data").(string)),
		Personality:      resourceInstancePersonalityV2(d),
	}

	if keyName, ok := d.Get("key_pair").(string); ok && keyName != "" {
		createOpts = &keypairs.CreateOptsExt{
			createOpts,
			keyName,
		}
	}

	if vL, ok := d.GetOk("block_device"); ok {
		for _, v := range vL.([]interface{}) {
			blockDeviceRaw := v.(map[string]interface{})
			blockDevice := resourceInstanceBlockDeviceV2(d, blockDeviceRaw)
			createOpts = &bootfromvolume.CreateOptsExt{
				createOpts,
				blockDevice,
			}
			log.Printf("[DEBUG] Create BFV Options: %+v", createOpts)
		}
	}

	schedulerHintsRaw := d.Get("scheduler_hints").(*schema.Set).List()
	if len(schedulerHintsRaw) > 0 {
		log.Printf("[DEBUG] schedulerhints: %+v", schedulerHintsRaw)
		schedulerHints := resourceInstanceSchedulerHintsV2(d, schedulerHintsRaw[0].(map[string]interface{}))
		createOpts = &schedulerhints.CreateOptsExt{
			createOpts,
			schedulerHints,
		}
	}

	log.Printf("[DEBUG] Create Options: %#v", createOpts)

	// If a block_device is used, use the bootfromvolume.Create function as it allows an empty ImageRef.
	// Otherwise, use the normal servers.Create function.
	var server *servers.Server
	if _, ok := d.GetOk("block_device"); ok {
		server, err = bootfromvolume.Create(computeClient, createOpts).Extract()
	} else {
		server, err = servers.Create(computeClient, createOpts).Extract()
	}

	if err != nil {
		return fmt.Errorf("Error creating OpenStack server: %s", err)
	}
	log.Printf("[INFO] Instance ID: %s", server.ID)

	// Store the ID now
	d.SetId(server.ID)

	// Wait for the instance to become running so we can get some attributes
	// that aren't available until later.
	log.Printf(
		"[DEBUG] Waiting for instance (%s) to become running",
		server.ID)

	stateConf := &resource.StateChangeConf{
		Pending:    []string{"BUILD"},
		Target:     "ACTIVE",
		Refresh:    ServerV2StateRefreshFunc(computeClient, server.ID),
		Timeout:    30 * time.Minute,
		Delay:      10 * time.Second,
		MinTimeout: 3 * time.Second,
	}

	_, err = stateConf.WaitForState()
	if err != nil {
		return fmt.Errorf(
			"Error waiting for instance (%s) to become ready: %s",
			server.ID, err)
	}
	floatingIP := d.Get("floating_ip").(string)
	if floatingIP != "" {
		if err := floatingip.Associate(computeClient, server.ID, floatingIP).ExtractErr(); err != nil {
			return fmt.Errorf("Error associating floating IP: %s", err)
		}
	}

	// if volumes were specified, attach them after the instance has launched.
	if v, ok := d.GetOk("volume"); ok {
		vols := v.(*schema.Set).List()
		if blockClient, err := config.blockStorageV1Client(d.Get("region").(string)); err != nil {
			return fmt.Errorf("Error creating OpenStack block storage client: %s", err)
		} else {
			if err := attachVolumesToInstance(computeClient, blockClient, d.Id(), vols); err != nil {
				return err
			}
		}
	}

	return resourceComputeInstanceV2Read(d, meta)
}
Esempio n. 7
0
func main() {
	// step-1
	var authUsername string = "your_auth_username"
	var authPassword string = "your_auth_password"
	var authUrl string = "http://controller:5000"
	var projectName string = "your_project_id"
	var regionName string = "your_region_name"

	authOpts := gophercloud.AuthOptions{
		IdentityEndpoint: authUrl,
		Username:         authUsername,
		Password:         authPassword,
		TenantID:         projectName,
	}
	provider, _ := openstack.AuthenticatedClient(authOpts)
	client, _ := openstack.NewComputeV2(provider, gophercloud.EndpointOpts{
		Region: regionName,
	})

	// step-2
	pager := images.ListDetail(client, images.ListOpts{})
	page, _ := pager.AllPages()
	imageList, _ := images.ExtractImages(page)
	fmt.Println(imageList)

	// step-3
	pager = flavors.ListDetail(client, flavors.ListOpts{})
	page, _ = pager.AllPages()
	flavorList, _ := flavors.ExtractFlavors(page)
	fmt.Println(flavorList)

	// step-4
	imageID := "74e6d1ec-9a08-444c-8518-4f232446386d"
	image, _ := images.Get(client, imageID).Extract()
	fmt.Println(image)

	// step-5
	flavorID := "1"
	flavor, _ := flavors.Get(client, flavorID).Extract()
	fmt.Println(flavor)

	// step-6
	instanceName := "testing"
	testingInstance, _ := servers.Create(client, servers.CreateOpts{
		Name:      instanceName,
		ImageRef:  imageID,
		FlavorRef: flavorID,
	}).Extract()
	fmt.Println(testingInstance)

	// step-7
	pager = servers.List(client, servers.ListOpts{})
	page, _ = pager.AllPages()
	serverList, _ := servers.ExtractServers(page)
	fmt.Println(serverList)

	// step-8
	servers.Delete(client, testingInstance.ID)

	// step-9
	fmt.Println("Checking for existing SSH key pair...")
	keyPairName := "demokey"
	pubKeyFile := "~/.ssh/id_rsa.pub"
	keyPairExists := false

	pager = keypairs.List(client)
	page, _ = pager.AllPages()
	keypairList, _ := keypairs.ExtractKeyPairs(page)
	for _, k := range keypairList {
		if k.Name == keyPairName {
			keyPairExists = true
			break
		}
	}

	if keyPairExists {
		fmt.Println("Keypair " + keyPairName + " already exists. Skipping import.")
	} else {
		fmt.Println("adding keypair...")
		bs, _ := ioutil.ReadFile(pubKeyFile)
		keypairs.Create(client, keypairs.CreateOpts{
			Name:      keyPairName,
			PublicKey: string(bs),
		}).Extract()
	}

	pager = keypairs.List(client)
	page, _ = pager.AllPages()
	keypairList, _ = keypairs.ExtractKeyPairs(page)
	fmt.Println(keypairList)

	// step-10
	fmt.Println("Checking for existing security group...")
	var allInOneSecurityGroup secgroups.SecurityGroup
	securityGroupName := "all-in-one"
	securityGroupExists := false

	pager = secgroups.List(client)
	page, _ = pager.AllPages()
	secgroupList, _ := secgroups.ExtractSecurityGroups(page)
	for _, secGroup := range secgroupList {
		if secGroup.Name == securityGroupName {
			allInOneSecurityGroup = secGroup
			securityGroupExists = true
			break
		}
	}

	if securityGroupExists {
		fmt.Println("Security Group " + allInOneSecurityGroup.Name + " already exists. Skipping creation.")
	} else {
		allInOneSecurityGroup, _ := secgroups.Create(client, secgroups.CreateOpts{
			Name:        securityGroupName,
			Description: "network access for all-in-one application.",
		}).Extract()
		secgroups.CreateRule(client, secgroups.CreateRuleOpts{
			ParentGroupID: allInOneSecurityGroup.ID,
			FromPort:      80,
			ToPort:        80,
			IPProtocol:    "TCP",
			CIDR:          "0.0.0.0/0",
		}).Extract()
		secgroups.CreateRule(client, secgroups.CreateRuleOpts{
			ParentGroupID: allInOneSecurityGroup.ID,
			FromPort:      22,
			ToPort:        22,
			IPProtocol:    "TCP",
			CIDR:          "0.0.0.0/0",
		}).Extract()
	}

	pager = secgroups.List(client)
	page, _ = pager.AllPages()
	secgroupList, _ = secgroups.ExtractSecurityGroups(page)
	fmt.Println(secgroupList)

	// step-11
	userData := `#!/usr/bin/env bash
curl -L -s https://git.openstack.org/cgit/openstack/faafo/plain/contrib/install.sh | bash -s -- \
    -i faafo -i messaging -r api -r worker -r demo
`

	// step-12
	fmt.Println("Checking for existing instance...")
	instanceName = "all-in-one"
	instanceExists := false

	pager = servers.List(client, servers.ListOpts{})
	page, _ = pager.AllPages()
	serverList, _ = servers.ExtractServers(page)
	for _, s := range serverList {
		if s.Name == instanceName {
			testingInstance = &s
			instanceExists = true
			break
		}
	}

	if instanceExists {
		fmt.Println("Instance " + testingInstance.Name + " already exists. Skipping creation.")
	} else {
		opts := servers.CreateOpts{
			Name:           instanceName,
			ImageRef:       image.ID,
			FlavorRef:      flavor.ID,
			SecurityGroups: []string{securityGroupName},
			UserData:       []byte(userData),
		}
		testingInstance, _ = servers.Create(client, keypairs.CreateOptsExt{
			CreateOptsBuilder: opts,
			KeyName:           keyPairName,
		}).Extract()
	}
	servers.WaitForStatus(client, testingInstance.ID, "ACTIVE", 300)

	pager = servers.List(client, servers.ListOpts{})
	page, _ = pager.AllPages()
	serverList, _ = servers.ExtractServers(page)
	fmt.Println(serverList)

	// step-13
	var privateIP string
	for t, addrs := range testingInstance.Addresses {
		if t != "private" || len(privateIP) != 0 {
			continue
		}
		addrs, ok := addrs.([]interface{})
		if !ok {
			continue
		}
		for _, addr := range addrs {
			a, ok := addr.(map[string]interface{})
			if !ok || a["version"].(float64) != 4 {
				continue
			}
			ip, ok := a["addr"].(string)
			if ok && len(ip) != 0 {
				privateIP = ip
				fmt.Println("Private IP found: " + privateIP)
				break
			}
		}
	}

	// step-14
	var publicIP string
	for t, addrs := range testingInstance.Addresses {
		if t != "public" || len(publicIP) != 0 {
			continue
		}
		addrs, ok := addrs.([]interface{})
		if !ok {
			continue
		}
		for _, addr := range addrs {
			a, ok := addr.(map[string]interface{})
			if !ok || a["version"].(float64) != 4 {
				continue
			}
			ip, ok := a["addr"].(string)
			if ok && len(ip) != 0 {
				publicIP = ip
				fmt.Println("Public IP found: " + publicIP)
				break
			}
		}
	}

	// step-15
	fmt.Println("Checking for unused Floating IP...")
	var unusedFloatingIP string
	pager = floatingip.List(client)
	page, _ = pager.AllPages()
	floatingIPList, _ := floatingip.ExtractFloatingIPs(page)
	for _, ip := range floatingIPList {
		if ip.InstanceID == "" {
			unusedFloatingIP = ip.IP
			break
		}
	}

	networkClient, _ := openstack.NewNetworkV2(provider, gophercloud.EndpointOpts{
		Region: regionName,
	})

	pager = networks.List(networkClient, networks.ListOpts{})
	page, _ = pager.AllPages()
	poolList, _ := external.ExtractList(page)
	for _, pool := range poolList {
		if len(unusedFloatingIP) != 0 || !pool.External {
			continue
		}
		fmt.Println("Allocating new Floating IP from pool: " + pool.Name)
		f, _ := floatingip.Create(client, floatingip.CreateOpts{Pool: pool.Name}).Extract()
		unusedFloatingIP = f.IP
	}

	// step-16
	if len(publicIP) != 0 {
		fmt.Println("Instance " + testingInstance.Name + " already has a public ip. Skipping attachment.")
	} else {
		floatingip.Associate(client, testingInstance.ID, unusedFloatingIP)
	}

	// step-17
	var actualIPAddress string
	if len(publicIP) != 0 {
		actualIPAddress = publicIP
	} else if len(unusedFloatingIP) != 0 {
		actualIPAddress = unusedFloatingIP
	} else {
		actualIPAddress = privateIP
	}

	fmt.Println("The Fractals app will be deployed to http://" + actualIPAddress)
}
func resourceComputeInstanceV2Create(d *schema.ResourceData, meta interface{}) error {
	config := meta.(*Config)
	computeClient, err := config.computeV2Client(d.Get("region").(string))
	if err != nil {
		return fmt.Errorf("Error creating OpenStack compute client: %s", err)
	}

	var createOpts servers.CreateOptsBuilder

	imageId, err := getImageID(computeClient, d)
	if err != nil {
		return err
	}

	flavorId, err := getFlavorID(computeClient, d)
	if err != nil {
		return err
	}

	networkDetails, err := resourceInstanceNetworks(computeClient, d)
	if err != nil {
		return err
	}

	networks := make([]servers.Network, len(networkDetails))
	for i, net := range networkDetails {
		networks[i] = servers.Network{
			UUID:    net["uuid"].(string),
			Port:    net["port"].(string),
			FixedIP: net["fixed_ip_v4"].(string),
		}
	}

	createOpts = &servers.CreateOpts{
		Name:             d.Get("name").(string),
		ImageRef:         imageId,
		FlavorRef:        flavorId,
		SecurityGroups:   resourceInstanceSecGroupsV2(d),
		AvailabilityZone: d.Get("availability_zone").(string),
		Networks:         networks,
		Metadata:         resourceInstanceMetadataV2(d),
		ConfigDrive:      d.Get("config_drive").(bool),
		AdminPass:        d.Get("admin_pass").(string),
		UserData:         []byte(d.Get("user_data").(string)),
	}

	if keyName, ok := d.Get("key_pair").(string); ok && keyName != "" {
		createOpts = &keypairs.CreateOptsExt{
			createOpts,
			keyName,
		}
	}

	if blockDeviceRaw, ok := d.Get("block_device").(map[string]interface{}); ok && blockDeviceRaw != nil {
		blockDevice := resourceInstanceBlockDeviceV2(d, blockDeviceRaw)
		createOpts = &bootfromvolume.CreateOptsExt{
			createOpts,
			blockDevice,
		}
	}

	schedulerHintsRaw := d.Get("scheduler_hints").(*schema.Set).List()
	if len(schedulerHintsRaw) > 0 {
		log.Printf("[DEBUG] schedulerhints: %+v", schedulerHintsRaw)
		schedulerHints := resourceInstanceSchedulerHintsV2(d, schedulerHintsRaw[0].(map[string]interface{}))
		createOpts = &schedulerhints.CreateOptsExt{
			createOpts,
			schedulerHints,
		}
	}

	log.Printf("[DEBUG] Create Options: %#v", createOpts)
	server, err := servers.Create(computeClient, createOpts).Extract()
	if err != nil {
		return fmt.Errorf("Error creating OpenStack server: %s", err)
	}
	log.Printf("[INFO] Instance ID: %s", server.ID)

	// Store the ID now
	d.SetId(server.ID)

	// Wait for the instance to become running so we can get some attributes
	// that aren't available until later.
	log.Printf(
		"[DEBUG] Waiting for instance (%s) to become running",
		server.ID)

	stateConf := &resource.StateChangeConf{
		Pending:    []string{"BUILD"},
		Target:     "ACTIVE",
		Refresh:    ServerV2StateRefreshFunc(computeClient, server.ID),
		Timeout:    10 * time.Minute,
		Delay:      10 * time.Second,
		MinTimeout: 3 * time.Second,
	}

	_, err = stateConf.WaitForState()
	if err != nil {
		return fmt.Errorf(
			"Error waiting for instance (%s) to become ready: %s",
			server.ID, err)
	}
	floatingIP := d.Get("floating_ip").(string)
	if floatingIP != "" {
		if err := floatingip.Associate(computeClient, server.ID, floatingIP).ExtractErr(); err != nil {
			return fmt.Errorf("Error associating floating IP: %s", err)
		}
	}

	// were volume attachments specified?
	if v := d.Get("volume"); v != nil {
		vols := v.(*schema.Set).List()
		if len(vols) > 0 {
			if blockClient, err := config.blockStorageV1Client(d.Get("region").(string)); err != nil {
				return fmt.Errorf("Error creating OpenStack block storage client: %s", err)
			} else {
				if err := attachVolumesToInstance(computeClient, blockClient, d.Id(), vols); err != nil {
					return err
				}
			}
		}
	}

	return resourceComputeInstanceV2Read(d, meta)
}