class Azure::ResourceManagement::ARMInterface

Attributes

connection[RW]

Public Class Methods

new(params = {}) click to toggle source
Calls superclass method Azure::AzureInterface::new
# File lib/azure/resource_management/ARM_interface.rb, line 46
def initialize(params = {})
  token_provider = if params[:azure_client_secret]
                     MsRestAzure::ApplicationTokenProvider.new(params[:azure_tenant_id], params[:azure_client_id], params[:azure_client_secret])
                   else
                     MsRest::StringTokenProvider.new(params[:token], params[:tokentype])
                   end
  @credentials = MsRest::TokenCredentials.new(token_provider)
  @azure_subscription_id = params[:azure_subscription_id]
  super
end

Public Instance Methods

common_arm_rescue_block(error) click to toggle source
# File lib/azure/resource_management/ARM_interface.rb, line 481
def common_arm_rescue_block(error)
  if error.class == MsRestAzure::AzureOperationError && error.body
    err_json = JSON.parse(error.response.body)
    err_details = err_json["error"]["details"] if err_json["error"]
    if err_details
      err_details.each do |err|
        ui.error(JSON.parse(err["message"])["error"]["message"])
      rescue JSON::ParserError => e
        ui.error(err["message"])
      end
    else
      ui.error(err_json["error"]["message"])
    end
    Chef::Log.debug(error.response.body)
  else
    message = begin
                JSON.parse(error.message)
              rescue JSON::ParserError => e
                error.message
              end
    ui.error(message)
    Chef::Log.debug(message)
  end
rescue Exception => e
  ui.error("Something went wrong. Please use -VV option for more details.")
  Chef::Log.debug(error.backtrace.join("\n").to_s)
end
compute_management_client() click to toggle source
# File lib/azure/resource_management/ARM_interface.rb, line 65
def compute_management_client
  @compute_management_client ||= begin
    compute_management_client = ComputeManagementClient.new(@credentials)
    compute_management_client.subscription_id = @azure_subscription_id
    compute_management_client
  end
end
create_resource_group(params = {}) click to toggle source
# File lib/azure/resource_management/ARM_interface.rb, line 398
def create_resource_group(params = {})
  resource_group = ResourceGroup.new
  resource_group.name = params[:azure_resource_group_name]
  resource_group.location = params[:azure_service_location]

  begin
    resource_group = resource_management_client.resource_groups.create_or_update(resource_group.name, resource_group)
  rescue Exception => e
    Chef::Log.error("Failed to create the Resource Group -- exception being rescued: #{e}")
    common_arm_rescue_block(e)
  end

  resource_group
end
create_server(params = {}) click to toggle source
# File lib/azure/resource_management/ARM_interface.rb, line 317
def create_server(params = {})
  platform(params[:azure_image_reference_offer])
  # resource group creation
  if resource_group_exist?(params[:azure_resource_group_name])
    ui.log("INFO:Resource Group #{params[:azure_resource_group_name]} already exist. Skipping its creation.")
    ui.log("INFO:Adding new VM #{params[:azure_vm_name]} to this resource group.")
  else
    ui.log("Creating ResourceGroup....\n\n")
    resource_group = create_resource_group(params)
    Chef::Log.info("ResourceGroup creation successful.")
    Chef::Log.info("Resource Group name is: #{resource_group.name}")
    Chef::Log.info("Resource Group ID is: #{resource_group.id}")
  end

  # virtual machine creation
  if virtual_machine_exist?(params[:azure_resource_group_name], params[:azure_vm_name])
    ui.log("INFO:Virtual Machine #{params[:azure_vm_name]} already exist under the Resource Group #{params[:azure_resource_group_name]}. Exiting for now.")
  else
    params[:chef_extension_version] = params[:chef_extension_version].nil? ? get_latest_chef_extension_version(params) : params[:chef_extension_version]
    params[:vm_size] = params[:azure_vm_size]
    params[:vnet_config] = create_vnet_config(
      params[:azure_resource_group_name],
      params[:azure_vnet_name],
      params[:azure_vnet_subnet_name]
    )
    if params[:tcp_endpoints]
      params[:tcp_endpoints] = if @platform == "Windows"
                                 params[:tcp_endpoints] + ",3389"
                               else
                                 params[:tcp_endpoints] + ",22,16001"
                               end
      random_no = rand(100..1000)
      params[:azure_sec_group_name] = params[:azure_vm_name] + "_sec_grp_" + random_no.to_s
      if security_group_exist?(params[:azure_resource_group_name], params[:azure_sec_group_name])
        random_no = rand(100..1000)
        params[:azure_sec_group_name] = params[:azure_vm_name] + "_sec_grp_" + random_no.to_s
      end
    end

    ui.log("Creating Virtual Machine....")
    deployment = create_virtual_machine_using_template(params)
    ui.log("Virtual Machine creation successful.") unless deployment.nil?

    unless deployment.nil?
      ui.log("Deployment name is: #{deployment.name}")
      ui.log("Deployment ID is: #{deployment.id}")
      deployment.properties.dependencies.each do |deploy|
        next unless deploy.resource_type == "Microsoft.Compute/virtualMachines"

        if params[:chef_extension_public_param][:extendedLogs] == "true"
          print "\n\nWaiting for the first chef-client run on virtual machine #{deploy.resource_name}"
          fetch_chef_client_logs(params[:azure_resource_group_name],
            deploy.resource_name,
            params[:chef_extension],
            Time.now)
        end

        ui.log("VM Details ...")
        ui.log("-------------------------------")
        ui.log("Virtual Machine name is: #{deploy.resource_name}")
        ui.log("Virtual Machine ID is: #{deploy.id}")
        show_server(deploy.resource_name, params[:azure_resource_group_name])
      end
    end
  end
end
create_virtual_machine_using_template(params) click to toggle source
# File lib/azure/resource_management/ARM_interface.rb, line 413
def create_virtual_machine_using_template(params)
  template = create_deployment_template(params)
  parameters = create_deployment_parameters(params)

  deploy_prop = DeploymentProperties.new
  deploy_prop.template = template
  deploy_prop.parameters = parameters
  deploy_prop.mode = "Incremental"

  deploy_params = Deployment.new
  deploy_params.properties = deploy_prop

  resource_management_client.deployments.create_or_update(params[:azure_resource_group_name], "#{params[:azure_vm_name]}_deploy", deploy_params)
end
create_vm_extension(params) click to toggle source
# File lib/azure/resource_management/ARM_interface.rb, line 428
def create_vm_extension(params)
  vm_ext = VirtualMachineExtension.new
  vm_ext.name = params[:chef_extension]
  vm_ext.location = params[:azure_service_location]
  vm_ext.publisher = params[:chef_extension_publisher]
  vm_ext.virtual_machine_extension_type = params[:chef_extension]
  vm_ext.type_handler_version = params[:chef_extension_version].nil? ? get_latest_chef_extension_version(params) : params[:chef_extension_version]
  vm_ext.auto_upgrade_minor_version = false
  vm_ext.settings = params[:chef_extension_public_param]
  vm_ext.protected_settings = params[:chef_extension_private_param]
  begin
    vm_extension = compute_management_client.virtual_machine_extensions.create_or_update(
      params[:azure_resource_group_name],
      params[:azure_vm_name],
      vm_ext.name,
      vm_ext
    )
  rescue Exception => e
    Chef::Log.error("Failed to create the Virtual Machine Extension -- exception being rescued.")
    common_arm_rescue_block(e)
  end

  vm_extension
end
delete_resource_group(resource_group_name) click to toggle source
# File lib/azure/resource_management/ARM_interface.rb, line 472
def delete_resource_group(resource_group_name)
  ui.info "Resource group deletion takes some time. Please wait ..."

  begin
    server = resource_management_client.resource_groups.delete(resource_group_name)
  end until server.nil?
  puts "\n"
end
delete_server(resource_group_name, vm_name) click to toggle source
# File lib/azure/resource_management/ARM_interface.rb, line 121
def delete_server(resource_group_name, vm_name)
  server = compute_management_client.virtual_machines.get(resource_group_name, vm_name)
  if server && server.name == vm_name
    puts "\n\n"
    msg_pair(ui, "VM Name", server.name)
    msg_pair(ui, "VM Size", server.hardware_profile.vm_size)
    msg_pair(ui, "VM OS", server.storage_profile.os_disk.os_type)
    puts "\n"

    begin
      ui.confirm("Do you really want to delete this server")
    rescue SystemExit   # Need to handle this as confirming with N/n raises SystemExit exception
      server = nil      # Cleanup is implicitly performed in other cloud plugins
      exit!
    end

    ui.info "Deleting .."

    begin
      server_detail = compute_management_client.virtual_machines.delete(resource_group_name, vm_name)
    end until server_detail.nil?

    puts "\n"
    ui.warn "Deleted server #{vm_name}"
  end
end
extension_already_installed?(server) click to toggle source
# File lib/azure/resource_management/ARM_interface.rb, line 453
def extension_already_installed?(server)
  if server.resources
    server.resources.each do |extension|
      return true if extension.virtual_machine_extension_type == "ChefClient" || extension.virtual_machine_extension_type == "LinuxChefClient"
    end
  end
  false
end
fetch_chef_client_logs(resource_group_name, virtual_machine_name, chef_extension_name, fetch_process_start_time, fetch_process_wait_timeout = 30) click to toggle source
# File lib/azure/resource_management/ARM_interface.rb, line 277
def fetch_chef_client_logs(resource_group_name, virtual_machine_name, chef_extension_name, fetch_process_start_time, fetch_process_wait_timeout = 30)
  ## fetch substatus field which contains the chef-client run logs ##
  substatus = fetch_substatus(resource_group_name, virtual_machine_name, chef_extension_name)

  if substatus.nil?
    ## unavailability of the substatus field indicates that chef-client run is not completed yet on the server ##
    fetch_process_wait_time = ((Time.now - fetch_process_start_time) / 60).round
    if fetch_process_wait_time <= fetch_process_wait_timeout
      print ui.color(".", :bold).to_s
      sleep 30
      fetch_chef_client_logs(resource_group_name, virtual_machine_name, chef_extension_name, fetch_process_start_time, fetch_process_wait_timeout)
    else
      ## wait time exceeded 30 minutes timeout ##
      ui.error "\nchef-client run logs could not be fetched since fetch process exceeded wait timeout of #{fetch_process_wait_timeout} minutes.\n"
    end
  else
    ## chef-client run logs becomes available ##
    status = parse_substatus_code(substatus.code, 2)
    message = substatus.message

    puts "\n\n******** Please find the chef-client run details below ********\n\n"
    print "----> chef-client run status: "
    case status
    when "succeeded"
      ## chef-client run succeeded ##
      color = :green
    when "failed"
      ## chef-client run failed ##
      color = :red
    when "transitioning"
      ## chef-client run did not complete within maximum timeout of 30 minutes ##
      ## fetch whatever logs available under the chef-client.log file ##
      color = :yellow
    end
    puts ui.color(status, color, :bold).to_s
    puts "----> chef-client run logs: "
    puts "\n#{message}\n" ## message field of substatus contains the chef-client run logs ##
  end
end
fetch_substatus(resource_group_name, virtual_machine_name, chef_extension_name) click to toggle source
# File lib/azure/resource_management/ARM_interface.rb, line 258
def fetch_substatus(resource_group_name, virtual_machine_name, chef_extension_name)
  substatuses = compute_management_client.virtual_machine_extensions.get(
    resource_group_name,
    virtual_machine_name,
    chef_extension_name,
    expand: "instanceView"
  ).instance_view.substatuses

  return nil if substatuses.nil?

  substatuses.each do |substatus|
    if parse_substatus_code(substatus.code, 1) == "Chef Client run logs"
      return substatus
    end
  end

  nil
end
find_server(resource_group, name) click to toggle source
# File lib/azure/resource_management/ARM_interface.rb, line 207
def find_server(resource_group, name)
  compute_management_client.virtual_machines.get(resource_group, name)
end
get_latest_chef_extension_version(params) click to toggle source
# File lib/azure/resource_management/ARM_interface.rb, line 462
def get_latest_chef_extension_version(params)
  ext_version = compute_management_client.virtual_machine_extension_images.list_versions(
    params[:azure_service_location],
    params[:chef_extension_publisher],
    params[:chef_extension]
  ).last.name
  ext_version_split_values = ext_version.split(".")
  ext_version_split_values[0] + "." + ext_version_split_values[1]
end
list_images() click to toggle source
# File lib/azure/resource_management/ARM_interface.rb, line 89
def list_images; end
list_servers(resource_group_name = nil) click to toggle source
# File lib/azure/resource_management/ARM_interface.rb, line 91
def list_servers(resource_group_name = nil)
  servers = if resource_group_name.nil?
              compute_management_client.virtual_machines.list_all
            else
              compute_management_client.virtual_machines.list(resource_group_name)
            end

  cols = ["VM Name", "Resource Group Name", "Location", "Provisioning State", "OS Type"]
  rows = []

  servers.each do |server|
    rows << server.name.to_s
    rows << server.id.split("/")[4].downcase
    rows << server.location.to_s
    rows << begin
                     state = server.provisioning_state.to_s.downcase
                     case state
                     when "failed"
                       ui.color(state, :red)
                     when "succeeded"
                       ui.color(state, :green)
                     else
                       ui.color(state, :yellow)
                     end
                   end
    rows << server.storage_profile.os_disk.os_type.to_s
  end
  display_list(ui, cols, rows)
end
network_resource_client() click to toggle source
# File lib/azure/resource_management/ARM_interface.rb, line 81
def network_resource_client
  @network_resource_client ||= begin
    network_resource_client = NetworkManagementClient.new(@credentials)
    network_resource_client.subscription_id = @azure_subscription_id
    network_resource_client
  end
end
parse_substatus_code(code, index) click to toggle source
# File lib/azure/resource_management/ARM_interface.rb, line 254
def parse_substatus_code(code, index)
  code.split("/")[index]
end
platform(image_reference) click to toggle source
# File lib/azure/resource_management/ARM_interface.rb, line 243
def platform(image_reference)
  @platform ||= begin
    platform = if image_reference =~ /WindowsServer.*/
                 "Windows"
               else
                 "Linux"
               end
    platform
  end
end
resource_group_exist?(resource_group_name) click to toggle source
# File lib/azure/resource_management/ARM_interface.rb, line 239
def resource_group_exist?(resource_group_name)
  resource_management_client.resource_groups.check_existence(resource_group_name)
end
resource_management_client() click to toggle source
# File lib/azure/resource_management/ARM_interface.rb, line 57
def resource_management_client
  @resource_management_client ||= begin
    resource_management_client = ResourceManagementClient.new(@credentials)
    resource_management_client.subscription_id = @azure_subscription_id
    resource_management_client
  end
end
security_group_exist?(resource_group_name, security_group_name) click to toggle source
# File lib/azure/resource_management/ARM_interface.rb, line 225
def security_group_exist?(resource_group_name, security_group_name)
  network_resource_client.network_security_groups.get(resource_group_name, security_group_name)
  true
rescue MsRestAzure::AzureOperationError => e
  if e.body
    err_json = JSON.parse(e.response.body)
    if err_json["error"]["code"] == "ResourceNotFound"
      false
    else
      raise e
    end
  end
end
show_server(name, resource_group) click to toggle source
# File lib/azure/resource_management/ARM_interface.rb, line 148
def show_server(name, resource_group)
  server = find_server(resource_group, name)
  if server
    network_interface_name = server.network_profile.network_interfaces[0].id.split("/")[-1]
    network_interface_data = network_resource_client.network_interfaces.get(resource_group, network_interface_name)
    public_ip_id_data = network_interface_data.ip_configurations[0].public_ipaddress
    if public_ip_id_data.nil?
      public_ip_data = nil
    else
      public_ip_name = public_ip_id_data.id.split("/")[-1]
      public_ip_data = network_resource_client.public_ipaddresses.get(resource_group, public_ip_name)
    end

    details = []
    details << ui.color("Server Name", :bold, :cyan)
    details << server.name

    details << ui.color("Size", :bold, :cyan)
    details << server.hardware_profile.vm_size

    details << ui.color("Provisioning State", :bold, :cyan)
    details << server.provisioning_state

    details << ui.color("Location", :bold, :cyan)
    details << server.location

    details << ui.color("Publisher", :bold, :cyan)
    details << server.storage_profile.image_reference.publisher

    details << ui.color("Offer", :bold, :cyan)
    details << server.storage_profile.image_reference.offer

    details << ui.color("Sku", :bold, :cyan)
    details << server.storage_profile.image_reference.sku

    details << ui.color("Version", :bold, :cyan)
    details << server.storage_profile.image_reference.version

    details << ui.color("OS Type", :bold, :cyan)
    details << server.storage_profile.os_disk.os_type

    details << ui.color("Public IP address", :bold, :cyan)
    details << if public_ip_data.nil?
                 " -- "
               else
                 public_ip_data.ip_address
               end

    details << ui.color("FQDN", :bold, :cyan)
    details << if public_ip_data.nil? || public_ip_data.dns_settings.nil?
                 " -- "
               else
                 public_ip_data.dns_settings.fqdn
               end

    puts ui.list(details, :columns_across, 2)
  end
end
storage_management_client() click to toggle source
# File lib/azure/resource_management/ARM_interface.rb, line 73
def storage_management_client
  @storage_management_client ||= begin
    storage_management_client = StorageManagementClient.new(@credentials)
    storage_management_client.subscription_id = @azure_subscription_id
    storage_management_client
  end
end
virtual_machine_exist?(resource_group_name, vm_name) click to toggle source
# File lib/azure/resource_management/ARM_interface.rb, line 211
def virtual_machine_exist?(resource_group_name, vm_name)
  compute_management_client.virtual_machines.get(resource_group_name, vm_name)
  true
rescue MsRestAzure::AzureOperationError => e
  if e.body
    err_json = JSON.parse(e.response.body)
    if err_json["error"]["code"] == "ResourceNotFound"
      false
    else
      raise e
    end
  end
end
vm_default_port(params = {}) click to toggle source
# File lib/azure/resource_management/ARM_interface.rb, line 391
def vm_default_port(params = {})
  network_resource_client.network_security_groups.get(
    params[:azure_resource_group_name],
    params[:azure_vm_name]
  ).value!.body.properties.security_rules[0].properties.destination_port_range
end
vm_public_ip(params = {}) click to toggle source
# File lib/azure/resource_management/ARM_interface.rb, line 384
def vm_public_ip(params = {})
  network_resource_client.public_ipaddresses.get(
    params[:azure_resource_group_name],
    params[:azure_vm_name]
  ).value!.body.properties.ip_address
end