// updateVirtualMachines updates virtual machines in the given map by iterating // through the list of instance IDs in order, and updating each corresponding // virtual machine at most once. func (v *azureVolumeSource) updateVirtualMachines( virtualMachines map[instance.Id]*maybeVirtualMachine, instanceIds []instance.Id, ) ([]error, error) { results := make([]error, len(instanceIds)) vmsClient := compute.VirtualMachinesClient{v.env.compute} for i, instanceId := range instanceIds { vm, ok := virtualMachines[instanceId] if !ok { continue } if vm.err != nil { results[i] = vm.err continue } if err := v.env.callAPI(func() (autorest.Response, error) { return vmsClient.CreateOrUpdate( v.env.resourceGroup, to.String(vm.vm.Name), *vm.vm, nil, // abort channel ) }); err != nil { results[i] = err vm.err = err continue } // successfully updated, don't update again delete(virtualMachines, instanceId) } return results, nil }
// 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 }