// CreateBootableVolumeServer works like CreateServer but is configured with // one or more block devices defined by passing in []bootfromvolume.BlockDevice. // An error will be returned if a server was unable to be created. func CreateBootableVolumeServer(t *testing.T, client *gophercloud.ServiceClient, blockDevices []bootfromvolume.BlockDevice, choices *clients.AcceptanceTestChoices) (*servers.Server, error) { if testing.Short() { t.Skip("Skipping test that requires server creation in short mode.") } var server *servers.Server networkID, err := GetNetworkIDFromTenantNetworks(t, client, choices.NetworkName) if err != nil { return server, err } name := tools.RandomString("ACPTTEST", 16) t.Logf("Attempting to create bootable volume server: %s", name) serverCreateOpts := servers.CreateOpts{ Name: name, FlavorRef: choices.FlavorID, Networks: []servers.Network{ servers.Network{UUID: networkID}, }, } if blockDevices[0].SourceType == bootfromvolume.SourceImage && blockDevices[0].DestinationType == bootfromvolume.DestinationLocal { serverCreateOpts.ImageRef = blockDevices[0].UUID } server, err = bootfromvolume.Create(client, bootfromvolume.CreateOptsExt{ serverCreateOpts, blockDevices, }).Extract() if err != nil { return server, err } if err := WaitForComputeStatus(client, server, "ACTIVE"); err != nil { return server, err } newServer, err := servers.Get(client, server.ID).Extract() return newServer, nil }
func resourceComputeInstanceV2Create(d *schema.ResourceData, meta interface{}) error { config := meta.(*Config) computeClient, err := config.computeV2Client(GetRegion(d)) 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 } // determine if block_device configuration is correct // this includes valid combinations and required attributes if err := checkBlockDeviceConfig(d); err != nil { return err } // check if floating IP configuration is correct if err := checkInstanceFloatingIPs(d); err != nil { return err } // Build a list of networks with the information given upon creation. // Error out if an invalid network configuration was used. networkDetails, err := getInstanceNetworks(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), } } configDrive := d.Get("config_drive").(bool) 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: &configDrive, 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{ CreateOptsBuilder: createOpts, KeyName: keyName, } } if vL, ok := d.GetOk("block_device"); ok { blockDevices, err := resourceInstanceBlockDevicesV2(d, vL.([]interface{})) if err != nil { return err } createOpts = &bootfromvolume.CreateOptsExt{ CreateOptsBuilder: createOpts, BlockDevice: blockDevices, } } 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{ CreateOptsBuilder: createOpts, SchedulerHints: 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: []string{"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) } // Now that the instance has been created, we need to do an early read on the // networks in order to associate floating IPs _, err = getInstanceNetworksAndAddresses(computeClient, d) // If floating IPs were specified, associate them after the instance has launched. err = associateFloatingIPsToInstance(computeClient, d) if err != nil { return 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(GetRegion(d)); 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) }