class Azure::Armrest::VirtualMachineService

Base class for managing virtual machines

Public Class Methods

new(configuration, options = {}) click to toggle source

Create and return a new VirtualMachineService instance. Most methods for a VirtualMachineService instance will return one or more VirtualMachine instances.

This subclass accepts the additional :provider option as well. The default is ‘Microsoft.Compute’. You may need to set this to ‘Microsoft.ClassicCompute’ for your purposes.

Calls superclass method Azure::Armrest::ArmrestService::new
# File lib/azure/armrest/virtual_machine_service.rb, line 15
def initialize(configuration, options = {})
  super(configuration, 'virtualMachines', 'Microsoft.Compute', options)
end

Public Instance Methods

capture(vmname, options, group = configuration.resource_group) click to toggle source

Captures the vmname and associated disks into a reusable CSM template. The 3rd argument is a hash of options that supports the following keys:

  • vhdPrefix - The prefix in the name of the blobs.

  • destinationContainerName - The name of the container inside which the image will reside.

  • overwriteVhds - Boolean that indicates whether or not to overwrite any VHD’s

    with the same prefix. The default is false.
# File lib/azure/armrest/virtual_machine_service.rb, line 55
def capture(vmname, options, group = configuration.resource_group)
  vm_operate('capture', vmname, group, options)
end
deallocate(vmname, group = configuration.resource_group) click to toggle source

Stop the VM vmname in group and deallocate the tenant in Fabric.

# File lib/azure/armrest/virtual_machine_service.rb, line 61
def deallocate(vmname, group = configuration.resource_group)
  vm_operate('deallocate', vmname, group)
end
delete_associated_resources(vmname, vmgroup, options = {}) click to toggle source

Delete the VM and associated resources. By default, this will delete the VM, its NIC, the associated IP address, and the image files (.vhd and .status) for the VM.

If you want to delete other associated resources, such as any attached disks, the VM’s underlying storage account, or associated network security groups you must explicitly specify them as an option.

An attempt to delete a resource that cannot be deleted because it’s still associated with some other resource will be logged and skipped.

If the :verbose option is set to true, then additional messages are sent to your configuration log, or stdout if no log was specified.

Note that if all of your related resources are in a self-contained resource group, you do not necessarily need this method. You could just delete the resource group itself, which would automatically delete all of its resources.

# File lib/azure/armrest/virtual_machine_service.rb, line 175
def delete_associated_resources(vmname, vmgroup, options = {})
  options = {
    :network_interfaces      => true,
    :ip_addresses            => true,
    :os_disk                 => true,
    :data_disks              => false,
    :network_security_groups => false,
    :storage_account         => false,
    :verbose                 => false
  }.merge(options)

  Azure::Armrest::Configuration.log ||= STDOUT if options[:verbose]

  vm = get(vmname, vmgroup)

  delete_and_wait(self, vmname, vmgroup, options)

  # Must delete network interfaces first if you want to delete
  # IP addresses or network security groups.
  if options[:network_interfaces] || options[:ip_addresses] || options[:network_security_groups]
    delete_associated_nics(vm, options)
  end

  if options[:os_disk] || options[:storage_account]
    delete_associated_disk(vm, options)
  end

  if options[:data_disks]
    delete_associated_data_disks(vm, options)
  end
end
generalize(vmname, group = configuration.resource_group) click to toggle source

Sets the OSState for the vmname in group to ‘Generalized’.

# File lib/azure/armrest/virtual_machine_service.rb, line 67
def generalize(vmname, group = configuration.resource_group)
  vm_operate('generalize', vmname, group)
end
get(vmname, group = configuration.resource_group, options = {}) click to toggle source

Retrieves the settings of the VM named vmname in resource group group, which will default to the same as the name of the VM.

You can also specify any query options. At this time only the :expand => ‘instanceView’ option is supported, but others could be added over time.

For backwards compatibility, the third argument may also be a boolean which will retrieve the model view by default. Set to false if you only want the instance view.

Examples:

vms = VirtualMachineService.new(credentials)

# Standard call, get just the model view
vms.get('some_name', 'some_group')
vms.get('some_name', 'some_group', true) # same

# Get the instance view only
vms.get('some_name', 'some_group', false)

# Get the instance view merged with the model view
vms.get('some_name', 'some_group', :expand => 'instanceView')
# File lib/azure/armrest/virtual_machine_service.rb, line 96
def get(vmname, group = configuration.resource_group, options = {})
  if options.kind_of?(Hash)
    url = build_url(group, vmname, options)
    response = rest_get(url)
    VirtualMachineInstance.new(response)
  else
    options ? super(vmname, group) : get_instance_view(vmname, group)
  end
end
get_instance_view(vmname, group = configuration.resource_group) click to toggle source

Convenient wrapper around the get method that retrieves only the instance view for vmname in resource_group group.

# File lib/azure/armrest/virtual_machine_service.rb, line 117
def get_instance_view(vmname, group = configuration.resource_group)
  raise ArgumentError, "must specify resource group" unless group
  raise ArgumentError, "must specify name of the resource" unless vmname

  url = build_url(group, vmname, 'instanceView')
  response = rest_get(url)
  VirtualMachineInstance.new(response)
end
get_model_view(vmname, group = configuration.resource_group) click to toggle source

Convenient wrapper around the get method that retrieves the model view for vmname in resource_group group without the instance view information.

# File lib/azure/armrest/virtual_machine_service.rb, line 110
def get_model_view(vmname, group = configuration.resource_group)
  get(vmname, group)
end
list_by_location(location, options = {}) click to toggle source

Return a list of virtual machines for the given location.

# File lib/azure/armrest/virtual_machine_service.rb, line 21
def list_by_location(location, options = {})
  url = url_with_api_version(api_version, base_url, 'providers', provider, 'locations', location, service_name)
  response = rest_get(url)
  get_all_results(response, options[:skip_accessors_definition])
end
model_class() click to toggle source
# File lib/azure/armrest/virtual_machine_service.rb, line 207
def model_class
  VirtualMachineModel
end
restart(vmname, group = configuration.resource_group) click to toggle source

Restart the VM vmname for the given group, which will default to the same as the vmname.

This is an asynchronous operation that returns a response object which you can inspect, such as response.code or response.headers.

# File lib/azure/armrest/virtual_machine_service.rb, line 132
def restart(vmname, group = configuration.resource_group)
  vm_operate('restart', vmname, group)
end
series(location) click to toggle source

Return a list of available VM series (aka sizes, flavors, etc), such as “Basic_A1”, though other information is included as well.

# File lib/azure/armrest/virtual_machine_service.rb, line 30
def series(location)
  namespace = 'microsoft.compute'
  version = configuration.provider_default_api_version(namespace, 'locations/vmsizes')

  unless version
    raise ArgumentError, "Unable to find resources for #{namespace}"
  end

  url = url_with_api_version(
    version, base_url, 'providers', provider, 'locations', location, 'vmSizes'
  )

  JSON.parse(rest_get(url))['value'].map{ |hash| VirtualMachineSize.new(hash) }
end
Also aliased as: sizes
sizes(location)
Alias for: series
start(vmname, group = configuration.resource_group) click to toggle source

Start the VM vmname for the given group, which will default to the same as the vmname.

This is an asynchronous operation that returns a response object which you can inspect, such as response.code or response.headers.

# File lib/azure/armrest/virtual_machine_service.rb, line 142
def start(vmname, group = configuration.resource_group)
  vm_operate('start', vmname, group)
end
stop(vmname, group = configuration.resource_group) click to toggle source

Stop the VM vmname for the given group gracefully. However, a forced shutdown will occur after 15 minutes.

This is an asynchronous operation that returns a response object which you can inspect, such as response.code or response.headers.

# File lib/azure/armrest/virtual_machine_service.rb, line 152
def stop(vmname, group = configuration.resource_group)
  vm_operate('powerOff', vmname, group)
end

Private Instance Methods

delete_and_wait(service, name, group, options) click to toggle source

Delete a service type resource using its name and resource group, and wait for the operation to complete before returning.

If the operation fails because a dependent resource is still attached, then the error is logged (in verbose mode) and ignored.

# File lib/azure/armrest/virtual_machine_service.rb, line 341
def delete_and_wait(service, name, group, options)
  resource_type = service.class.to_s.sub('Service', '').split('::').last

  log("Deleting #{resource_type} #{name}/#{group}") if options[:verbose]

  wait(service.delete(name, group), 0)

  log("Deleted #{resource_type} #{name}/#{group}") if options[:verbose]
rescue Azure::Armrest::BadRequestException, Azure::Armrest::PreconditionFailedException => err
  if options[:verbose]
    msg = "Unable to delete #{resource_type} #{name}/#{group}, skipping. Message: #{err.message}"
    log('warn', msg)
  end
end
delete_associated_data_disks(vm, options) click to toggle source

This deletes any attached data disks that are associated with the virtual machine. Note that this should only happen after the VM has been deleted.

# File lib/azure/armrest/virtual_machine_service.rb, line 272
def delete_associated_data_disks(vm, options)
  sds = Azure::Armrest::Storage::DiskService.new(configuration)
  data_disks = vm.properties.storage_profile.try(:data_disks)

  data_disks&.each do |data_disk|
    disk = sds.get_by_id(data_disk.managed_disk.id)
    delete_and_wait(sds, disk.name, disk.resource_group, options)
  end
end
delete_associated_disk(vm, options) click to toggle source

This deletes the OS disk from the storage account that’s backing the virtual machine, along with the .status file. This does NOT delete copies of the disk.

If the option to delete the entire storage account was selected, then it will not bother with deleting invidual files from the storage account first.

# File lib/azure/armrest/virtual_machine_service.rb, line 260
def delete_associated_disk(vm, options)
  if vm.managed_disk?
    delete_managed_storage(vm, options)
  else
    delete_unmanaged_storage(vm, options)
  end
end
delete_associated_nics(vm, options) click to toggle source

Deletes any NIC’s associated with the VM, and optionally any public IP addresses and network security groups.

# File lib/azure/armrest/virtual_machine_service.rb, line 216
def delete_associated_nics(vm, options)
  nis = Azure::Armrest::Network::NetworkInterfaceService.new(configuration)
  nics = vm.properties.network_profile.network_interfaces.map(&:id)

  if options[:ip_addresses]
    ips = Azure::Armrest::Network::IpAddressService.new(configuration)
  end

  if options[:network_security_groups]
    nsgs = Azure::Armrest::Network::NetworkSecurityGroupService.new(configuration)
  end

  nics.each do |nic_id_string|
    nic = get_by_id(nic_id_string)
    delete_and_wait(nis, nic.name, nic.resource_group, options)

    if options[:ip_addresses]
      nic.properties.ip_configurations.each do |ipconfig|
        address = ipconfig.properties.try(:public_ip_address)

        if address
          ip = get_by_id(address.id)
          delete_and_wait(ips, ip.name, ip.resource_group, options)
        end
      end
    end

    if options[:network_security_groups]
      if nic.properties.respond_to?(:network_security_group)
        nsg = get_by_id(nic.properties.network_security_group.id)
        delete_and_wait(nsgs, nsg.name, nsg.resource_group, options)
      end
    end
  end
end
delete_managed_storage(vm, options) click to toggle source
# File lib/azure/armrest/virtual_machine_service.rb, line 282
def delete_managed_storage(vm, options)
  sds = Azure::Armrest::Storage::DiskService.new(configuration)
  disk = sds.get_by_id(vm.properties.storage_profile.os_disk.managed_disk.id)
  delete_and_wait(sds, disk.name, disk.resource_group, options)
end
delete_unmanaged_storage(vm, options) click to toggle source
# File lib/azure/armrest/virtual_machine_service.rb, line 288
def delete_unmanaged_storage(vm, options)
  sas = Azure::Armrest::StorageAccountService.new(configuration)

  storage_account = sas.get_from_vm(vm)

  # Deleting the storage account does not require deleting the disks
  # first, so skip that if deletion of the storage account was requested.
  if options[:storage_account]
    delete_and_wait(sas, storage_account.name, storage_account.resource_group, options)
  else
    keys = sas.list_account_keys(storage_account.name, storage_account.resource_group)
    key  = keys['key1'] || keys['key2']
    disk = sas.get_os_disk(vm)

    # There's a short delay between deleting the VM and unlocking the underlying
    # .vhd file by Azure. Therefore we sleep up to two minutes while checking.
    if disk.x_ms_lease_status.casecmp('unlocked') != 0
      sleep_time = 0

      while sleep_time < 120
        sleep 10
        sleep_time += 10
        disk = sas.get_os_disk(vm)
        break if disk.x_ms_lease_status.casecmp('unlocked') != 0
      end

      # In the unlikely event it did not unlock, just log and skip.
      if disk.x_ms_lease_status.casecmp('unlocked') != 0
        log('warn', "Unable to delete disk #{disk.container}/#{disk.name}")
        return
      end
    end

    storage_account.delete_blob(disk.container, disk.name, key)
    log("Deleted blob #{disk.container}/#{disk.name}") if options[:verbose]

    begin
      status_file = File.basename(disk.name, '.vhd') + '.status'
      storage_account.delete_blob(disk.container, status_file, key)
    rescue Azure::Armrest::NotFoundException
      # Ignore, does not always exist.
    else
      log("Deleted blob #{disk.container}/#{status_file}") if options[:verbose]
    end
  end
end
vm_operate(action, vmname, group, options = {}) click to toggle source
# File lib/azure/armrest/virtual_machine_service.rb, line 356
def vm_operate(action, vmname, group, options = {})
  raise ArgumentError, "must specify resource group" unless group
  raise ArgumentError, "must specify name of the vm" unless vmname

  url = build_url(group, vmname, action)
  response = rest_post(url, options.to_json)

  Azure::Armrest::ResponseHeaders.new(response.headers).tap do |headers|
    headers.response_code = response.code
  end
end