func resourceArmVirtualMachineCreate(d *schema.ResourceData, meta interface{}) error {
	client := meta.(*ArmClient)
	vmClient := client.vmClient

	log.Printf("[INFO] preparing arguments for Azure ARM Virtual Machine creation.")

	name := d.Get("name").(string)
	location := d.Get("location").(string)
	resGroup := d.Get("resource_group_name").(string)
	tags := d.Get("tags").(map[string]interface{})
	expandedTags := expandTags(tags)

	osDisk, err := expandAzureRmVirtualMachineOsDisk(d)
	if err != nil {
		return err
	}
	storageProfile := compute.StorageProfile{
		OsDisk: osDisk,
	}

	if _, ok := d.GetOk("storage_image_reference"); ok {
		imageRef, err := expandAzureRmVirtualMachineImageReference(d)
		if err != nil {
			return err
		}
		storageProfile.ImageReference = imageRef
	}

	if _, ok := d.GetOk("storage_data_disk"); ok {
		dataDisks, err := expandAzureRmVirtualMachineDataDisk(d)
		if err != nil {
			return err
		}
		storageProfile.DataDisks = &dataDisks
	}

	networkProfile := expandAzureRmVirtualMachineNetworkProfile(d)
	vmSize := d.Get("vm_size").(string)
	properties := compute.VirtualMachineProperties{
		NetworkProfile: &networkProfile,
		HardwareProfile: &compute.HardwareProfile{
			VMSize: compute.VirtualMachineSizeTypes(vmSize),
		},
		StorageProfile: &storageProfile,
	}

	osProfile, err := expandAzureRmVirtualMachineOsProfile(d)
	if err != nil {
		return err
	}
	properties.OsProfile = osProfile

	if v, ok := d.GetOk("availability_set_id"); ok {
		availabilitySet := v.(string)
		availSet := compute.SubResource{
			ID: &availabilitySet,
		}

		properties.AvailabilitySet = &availSet
	}

	vm := compute.VirtualMachine{
		Name:       &name,
		Location:   &location,
		Properties: &properties,
		Tags:       expandedTags,
	}

	if _, ok := d.GetOk("plan"); ok {
		plan, err := expandAzureRmVirtualMachinePlan(d)
		if err != nil {
			return err
		}

		vm.Plan = plan
	}

	_, vmErr := vmClient.CreateOrUpdate(resGroup, name, vm, make(chan struct{}))
	if vmErr != nil {
		return vmErr
	}

	read, err := vmClient.Get(resGroup, name, "")
	if err != nil {
		return err
	}
	if read.ID == nil {
		return fmt.Errorf("Cannot read Virtual Machine %s (resource group %s) ID", name, resGroup)
	}

	d.SetId(*read.ID)

	return resourceArmVirtualMachineRead(d, meta)
}
Exemple #2
0
// createVirtualMachine creates a virtual machine and related resources.
//
// All resources created are tagged with the specified "vmTags", so if
// this function fails then all resources can be deleted by tag.
func createVirtualMachine(
	resourceGroup, location, vmName string,
	vmTags, envTags map[string]string,
	instanceSpec *instances.InstanceSpec,
	instanceConfig *instancecfg.InstanceConfig,
	distributionGroupFunc func() ([]instance.Id, error),
	instancesFunc func([]instance.Id) ([]instance.Instance, error),
	apiPort *int,
	internalNetworkSubnet *network.Subnet,
	nsgID, storageEndpoint, storageAccountName string,
	networkClient network.ManagementClient,
	vmClient compute.VirtualMachinesClient,
	availabilitySetClient compute.AvailabilitySetsClient,
	vmExtensionClient compute.VirtualMachineExtensionsClient,
) (compute.VirtualMachine, error) {

	storageProfile, err := newStorageProfile(
		vmName, instanceConfig.Series,
		instanceSpec, storageEndpoint, storageAccountName,
	)
	if err != nil {
		return compute.VirtualMachine{}, errors.Annotate(err, "creating storage profile")
	}

	osProfile, seriesOS, err := newOSProfile(vmName, instanceConfig)
	if err != nil {
		return compute.VirtualMachine{}, errors.Annotate(err, "creating OS profile")
	}

	networkProfile, err := newNetworkProfile(
		networkClient, vmName, apiPort,
		internalNetworkSubnet, nsgID,
		resourceGroup, location, vmTags,
	)
	if err != nil {
		return compute.VirtualMachine{}, errors.Annotate(err, "creating network profile")
	}

	availabilitySetId, err := createAvailabilitySet(
		availabilitySetClient,
		vmName, resourceGroup, location,
		vmTags, envTags,
		distributionGroupFunc, instancesFunc,
	)
	if err != nil {
		return compute.VirtualMachine{}, errors.Annotate(err, "creating availability set")
	}

	vmArgs := compute.VirtualMachine{
		Location: to.StringPtr(location),
		Tags:     toTagsPtr(vmTags),
		Properties: &compute.VirtualMachineProperties{
			HardwareProfile: &compute.HardwareProfile{
				VMSize: compute.VirtualMachineSizeTypes(
					instanceSpec.InstanceType.Name,
				),
			},
			StorageProfile: storageProfile,
			OsProfile:      osProfile,
			NetworkProfile: networkProfile,
			AvailabilitySet: &compute.SubResource{
				ID: to.StringPtr(availabilitySetId),
			},
		},
	}
	vm, err := vmClient.CreateOrUpdate(resourceGroup, vmName, vmArgs)
	if err != nil {
		return compute.VirtualMachine{}, errors.Annotate(err, "creating virtual machine")
	}

	// On Windows and CentOS, we must add the CustomScript VM
	// extension to run the CustomData script.
	switch seriesOS {
	case os.Windows, os.CentOS:
		if err := createVMExtension(
			vmExtensionClient, seriesOS,
			resourceGroup, vmName, location, vmTags,
		); err != nil {
			return compute.VirtualMachine{}, errors.Annotate(
				err, "creating virtual machine extension",
			)
		}
	}
	return vm, nil
}
Exemple #3
0
func (a AzureClient) CreateVirtualMachine(resourceGroup, name, location, size, availabilitySetID, networkInterfaceID,
	username, sshPublicKey, imageName string, storageAccount *storage.AccountProperties) error {
	log.Info("Creating virtual machine.", logutil.Fields{
		"name":     name,
		"location": location,
		"size":     size,
		"username": username,
		"osImage":  imageName,
	})

	img, err := parseImageName(imageName)
	if err != nil {
		return err
	}

	var (
		osDiskBlobURL = osDiskStorageBlobURL(storageAccount, name)
		sshKeyPath    = fmt.Sprintf("/home/%s/.ssh/authorized_keys", username)
	)
	log.Debugf("OS disk blob will be placed at: %s", osDiskBlobURL)
	log.Debugf("SSH key will be placed at: %s", sshKeyPath)

	_, err = a.virtualMachinesClient().CreateOrUpdate(resourceGroup, name,
		compute.VirtualMachine{
			Location: to.StringPtr(location),
			Properties: &compute.VirtualMachineProperties{
				AvailabilitySet: &compute.SubResource{
					ID: to.StringPtr(availabilitySetID),
				},
				HardwareProfile: &compute.HardwareProfile{
					VMSize: compute.VirtualMachineSizeTypes(size),
				},
				NetworkProfile: &compute.NetworkProfile{
					NetworkInterfaces: &[]compute.NetworkInterfaceReference{
						{
							ID: to.StringPtr(networkInterfaceID),
						},
					},
				},
				OsProfile: &compute.OSProfile{
					ComputerName:  to.StringPtr(name),
					AdminUsername: to.StringPtr(username),
					LinuxConfiguration: &compute.LinuxConfiguration{
						DisablePasswordAuthentication: to.BoolPtr(true),
						SSH: &compute.SSHConfiguration{
							PublicKeys: &[]compute.SSHPublicKey{
								{
									Path:    to.StringPtr(sshKeyPath),
									KeyData: to.StringPtr(sshPublicKey),
								},
							},
						},
					},
				},
				StorageProfile: &compute.StorageProfile{
					ImageReference: &compute.ImageReference{
						Publisher: to.StringPtr(img.publisher),
						Offer:     to.StringPtr(img.offer),
						Sku:       to.StringPtr(img.sku),
						Version:   to.StringPtr(img.version),
					},
					OsDisk: &compute.OSDisk{
						Name:         to.StringPtr(fmt.Sprintf(fmtOSDiskResourceName, name)),
						Caching:      compute.ReadWrite,
						CreateOption: compute.FromImage,
						Vhd: &compute.VirtualHardDisk{
							URI: to.StringPtr(osDiskBlobURL),
						},
					},
				},
			},
		}, nil)
	return err
}
func resourceArmVirtualMachineCreate(d *schema.ResourceData, meta interface{}) error {
	client := meta.(*ArmClient)
	vmClient := client.vmClient

	log.Printf("[INFO] preparing arguments for Azure ARM Virtual Machine creation.")

	name := d.Get("name").(string)
	location := d.Get("location").(string)
	resGroup := d.Get("resource_group_name").(string)
	tags := d.Get("tags").(map[string]interface{})
	expandedTags := expandTags(tags)

	osDisk, err := expandAzureRmVirtualMachineOsDisk(d)
	if err != nil {
		return err
	}
	storageProfile := compute.StorageProfile{
		OsDisk: osDisk,
	}

	if _, ok := d.GetOk("storage_image_reference"); ok {
		imageRef, err := expandAzureRmVirtualMachineImageReference(d)
		if err != nil {
			return err
		}
		storageProfile.ImageReference = imageRef
	}

	if _, ok := d.GetOk("storage_data_disk"); ok {
		dataDisks, err := expandAzureRmVirtualMachineDataDisk(d)
		if err != nil {
			return err
		}
		storageProfile.DataDisks = &dataDisks
	}

	networkProfile := expandAzureRmVirtualMachineNetworkProfile(d)
	vmSize := d.Get("vm_size").(string)
	properties := compute.VirtualMachineProperties{
		NetworkProfile: &networkProfile,
		HardwareProfile: &compute.HardwareProfile{
			VMSize: compute.VirtualMachineSizeTypes(vmSize),
		},
		StorageProfile: &storageProfile,
	}

	osProfile, err := expandAzureRmVirtualMachineOsProfile(d)
	if err != nil {
		return err
	}
	properties.OsProfile = osProfile

	if v, ok := d.GetOk("availability_set_id"); ok {
		availabilitySet := v.(string)
		availSet := compute.SubResource{
			ID: &availabilitySet,
		}

		properties.AvailabilitySet = &availSet
	}

	vm := compute.VirtualMachine{
		Name:       &name,
		Location:   &location,
		Properties: &properties,
		Tags:       expandedTags,
	}

	if _, ok := d.GetOk("plan"); ok {
		plan, err := expandAzureRmVirtualMachinePlan(d)
		if err != nil {
			return err
		}

		vm.Plan = plan
	}

	resp, vmErr := vmClient.CreateOrUpdate(resGroup, name, vm)
	if vmErr != nil {
		return vmErr
	}

	d.SetId(*resp.ID)

	log.Printf("[DEBUG] Waiting for Virtual Machine (%s) to become available", name)
	stateConf := &resource.StateChangeConf{
		Pending:    []string{"Creating", "Updating"},
		Target:     []string{"Succeeded"},
		Refresh:    virtualMachineStateRefreshFunc(client, resGroup, name),
		Timeout:    20 * time.Minute,
		MinTimeout: 10 * time.Second,
	}
	if _, err := stateConf.WaitForState(); err != nil {
		return fmt.Errorf("Error waiting for Virtual Machine (%s) to become available: %s", name, err)
	}

	return resourceArmVirtualMachineRead(d, meta)
}
Exemple #5
0
// createVirtualMachine creates a virtual machine and related resources.
//
// All resources created are tagged with the specified "vmTags", so if
// this function fails then all resources can be deleted by tag.
func (env *azureEnviron) createVirtualMachine(
	vmName string,
	vmTags, envTags map[string]string,
	instanceSpec *instances.InstanceSpec,
	instanceConfig *instancecfg.InstanceConfig,
	storageAccountType string,
) error {

	deploymentsClient := resources.DeploymentsClient{env.resources}

	var apiPort int
	if instanceConfig.Controller != nil {
		apiPortValue := instanceConfig.Controller.Config.APIPort()
		apiPort = apiPortValue
	} else {
		apiPorts := instanceConfig.APIInfo.Ports()
		if len(apiPorts) != 1 {
			return errors.Errorf("expected one API port, found %v", apiPorts)
		}
		apiPort = apiPorts[0]
	}
	resources := networkTemplateResources(env.location, envTags, apiPort)
	resources = append(resources, storageAccountTemplateResource(
		env.location, envTags,
		env.storageAccountName, storageAccountType,
	))

	osProfile, seriesOS, err := newOSProfile(
		vmName, instanceConfig,
		env.provider.config.RandomWindowsAdminPassword,
	)
	if err != nil {
		return errors.Annotate(err, "creating OS profile")
	}
	storageProfile, err := newStorageProfile(vmName, env.storageAccountName, instanceSpec)
	if err != nil {
		return errors.Annotate(err, "creating storage profile")
	}

	var vmDependsOn []string
	var availabilitySetSubResource *compute.SubResource
	availabilitySetName, err := availabilitySetName(
		vmName, vmTags, instanceConfig.Controller != nil,
	)
	if err != nil {
		return errors.Annotate(err, "getting availability set name")
	}
	if availabilitySetName != "" {
		availabilitySetId := fmt.Sprintf(
			`[resourceId('Microsoft.Compute/availabilitySets','%s')]`,
			availabilitySetName,
		)
		resources = append(resources, armtemplates.Resource{
			APIVersion: compute.APIVersion,
			Type:       "Microsoft.Compute/availabilitySets",
			Name:       availabilitySetName,
			Location:   env.location,
			Tags:       envTags,
		})
		availabilitySetSubResource = &compute.SubResource{
			ID: to.StringPtr(availabilitySetId),
		}
		vmDependsOn = append(vmDependsOn, availabilitySetId)
	}

	publicIPAddressName := vmName + "-public-ip"
	publicIPAddressId := fmt.Sprintf(`[resourceId('Microsoft.Network/publicIPAddresses', '%s')]`, publicIPAddressName)
	resources = append(resources, armtemplates.Resource{
		APIVersion: network.APIVersion,
		Type:       "Microsoft.Network/publicIPAddresses",
		Name:       publicIPAddressName,
		Location:   env.location,
		Tags:       vmTags,
		Properties: &network.PublicIPAddressPropertiesFormat{
			PublicIPAllocationMethod: network.Dynamic,
		},
	})

	// Controller and non-controller machines are assigned to separate
	// subnets. This enables us to create controller-specific NSG rules
	// just by targeting the controller subnet.
	subnetName := internalSubnetName
	subnetPrefix := internalSubnetPrefix
	if instanceConfig.Controller != nil {
		subnetName = controllerSubnetName
		subnetPrefix = controllerSubnetPrefix
	}
	subnetId := fmt.Sprintf(
		`[concat(resourceId('Microsoft.Network/virtualNetworks', '%s'), '/subnets/%s')]`,
		internalNetworkName, subnetName,
	)

	privateIP, err := machineSubnetIP(subnetPrefix, instanceConfig.MachineId)
	if err != nil {
		return errors.Annotatef(err, "computing private IP address")
	}
	nicName := vmName + "-primary"
	nicId := fmt.Sprintf(`[resourceId('Microsoft.Network/networkInterfaces', '%s')]`, nicName)
	ipConfigurations := []network.InterfaceIPConfiguration{{
		Name: to.StringPtr("primary"),
		Properties: &network.InterfaceIPConfigurationPropertiesFormat{
			Primary:                   to.BoolPtr(true),
			PrivateIPAddress:          to.StringPtr(privateIP.String()),
			PrivateIPAllocationMethod: network.Static,
			Subnet: &network.Subnet{ID: to.StringPtr(subnetId)},
			PublicIPAddress: &network.PublicIPAddress{
				ID: to.StringPtr(publicIPAddressId),
			},
		},
	}}
	resources = append(resources, armtemplates.Resource{
		APIVersion: network.APIVersion,
		Type:       "Microsoft.Network/networkInterfaces",
		Name:       nicName,
		Location:   env.location,
		Tags:       vmTags,
		Properties: &network.InterfacePropertiesFormat{
			IPConfigurations: &ipConfigurations,
		},
		DependsOn: []string{
			publicIPAddressId,
			fmt.Sprintf(
				`[resourceId('Microsoft.Network/virtualNetworks', '%s')]`,
				internalNetworkName,
			),
		},
	})

	nics := []compute.NetworkInterfaceReference{{
		ID: to.StringPtr(nicId),
		Properties: &compute.NetworkInterfaceReferenceProperties{
			Primary: to.BoolPtr(true),
		},
	}}
	vmDependsOn = append(vmDependsOn, nicId)
	vmDependsOn = append(vmDependsOn, fmt.Sprintf(
		`[resourceId('Microsoft.Storage/storageAccounts', '%s')]`,
		env.storageAccountName,
	))
	resources = append(resources, armtemplates.Resource{
		APIVersion: compute.APIVersion,
		Type:       "Microsoft.Compute/virtualMachines",
		Name:       vmName,
		Location:   env.location,
		Tags:       vmTags,
		Properties: &compute.VirtualMachineProperties{
			HardwareProfile: &compute.HardwareProfile{
				VMSize: compute.VirtualMachineSizeTypes(
					instanceSpec.InstanceType.Name,
				),
			},
			StorageProfile: storageProfile,
			OsProfile:      osProfile,
			NetworkProfile: &compute.NetworkProfile{
				&nics,
			},
			AvailabilitySet: availabilitySetSubResource,
		},
		DependsOn: vmDependsOn,
	})

	// On Windows and CentOS, we must add the CustomScript VM
	// extension to run the CustomData script.
	switch seriesOS {
	case os.Windows, os.CentOS:
		properties, err := vmExtensionProperties(seriesOS)
		if err != nil {
			return errors.Annotate(
				err, "creating virtual machine extension",
			)
		}
		resources = append(resources, armtemplates.Resource{
			APIVersion: compute.APIVersion,
			Type:       "Microsoft.Compute/virtualMachines/extensions",
			Name:       vmName + "/" + extensionName,
			Location:   env.location,
			Tags:       vmTags,
			Properties: properties,
			DependsOn:  []string{"Microsoft.Compute/virtualMachines/" + vmName},
		})
	}

	logger.Debugf("- creating virtual machine deployment")
	template := armtemplates.Template{Resources: resources}
	// NOTE(axw) VMs take a long time to go to "Succeeded", so we do not
	// block waiting for them to be fully provisioned. This means we won't
	// return an error from StartInstance if the VM fails provisioning;
	// we will instead report the error via the instance's status.
	deploymentsClient.ResponseInspector = asyncCreationRespondDecorator(
		deploymentsClient.ResponseInspector,
	)
	if err := createDeployment(
		env.callAPI,
		deploymentsClient,
		env.resourceGroup,
		vmName, // deployment name
		template,
	); err != nil {
		return errors.Trace(err)
	}
	return nil
}
Exemple #6
0
func (clst *azureCluster) configureVirtualMachine(vmName string, osDiskName string,
	nicName string, cloudConfig string, vmSize string, location string,
	iface network.Interface) error {
	hardwareProfile := compute.HardwareProfile{
		VMSize: compute.VirtualMachineSizeTypes(vmSize),
	}

	ifaceRef := compute.NetworkInterfaceReference{
		ID: iface.ID,
	}

	networkProfile := compute.NetworkProfile{
		NetworkInterfaces: &[]compute.NetworkInterfaceReference{ifaceRef},
	}

	storageAccounts, err := clst.listStorageAccounts()
	if err != nil {
		return err
	}

	storageAccount, ok := storageAccounts[location]
	if !ok {
		return errors.New("a storage account is needed for location " + location)
	}

	vhdURI := fmt.Sprintf("http://%s.blob.core.windows.net/vhds/%s.vhd",
		*storageAccount.Name, osDiskName)

	vhd := compute.VirtualHardDisk{
		URI: &vhdURI,
	}

	osDisk := compute.OSDisk{
		Name:         &osDiskName,
		Caching:      compute.ReadWrite,
		CreateOption: compute.FromImage,
		Vhd:          &vhd,
	}

	imageRef := compute.ImageReference{
		Publisher: stringPtr(imagePublisher),
		Offer:     stringPtr(imageOffer),
		Sku:       stringPtr(imageSku),
		Version:   stringPtr(imageVersion),
	}

	storageProfile := compute.StorageProfile{
		ImageReference: &imageRef,
		OsDisk:         &osDisk,
	}

	// We have to set username and password even though we do not need it.
	adminUsername := uuid.NewV4().String()
	adminPassword := uuid.NewV4().String()

	customData := base64.StdEncoding.EncodeToString([]byte(cloudConfig))

	osProfile := compute.OSProfile{
		ComputerName:  &vmName,
		AdminUsername: &adminUsername,
		AdminPassword: &adminPassword,
		CustomData:    &customData,
	}

	properties := compute.VirtualMachineProperties{
		HardwareProfile: &hardwareProfile,
		NetworkProfile:  &networkProfile,
		StorageProfile:  &storageProfile,
		OsProfile:       &osProfile,
	}

	virtualMachine := compute.VirtualMachine{
		Name:       &vmName,
		Location:   &location,
		Properties: &properties,
		Tags:       &map[string]*string{nsTag: &clst.namespace},
	}

	cancel := make(chan struct{})
	_, err = clst.azureClient.vmCreate(resourceGroupName, vmName, virtualMachine,
		cancel)
	return err
}