class Azure::Armrest::ArmrestService

Abstract base class for the other service classes.

Attributes

api_version[RW]

The api-version string for this particular service

armrest_configuration[RW]

Configuration to access azure APIs

base_url[RW]

Base url with subscription information used for most REST calls.

configuration[RW]

Configuration to access azure APIs

provider[RW]

Provider for service specific API calls

service_name[RW]

The service name for the Service class

Public Class Methods

configure(options) click to toggle source

Returns a new Armrest::Configuration object.

This method is deprecated, but is provided for backwards compatibility.

# File lib/azure/armrest/armrest_service.rb, line 35
def self.configure(options)
  Azure::Armrest::Configuration.new(options)
end
new(armrest_configuration, service_name, default_provider, options) click to toggle source

Do not instantiate directly. This is an abstract base class from which all other service classes should subclass, and call super within their own constructors.

# File lib/azure/armrest/armrest_service.rb, line 43
def initialize(armrest_configuration, service_name, default_provider, options)
  @armrest_configuration = armrest_configuration
  @service_name = service_name
  @provider = options[:provider] || default_provider

  if configuration.subscription_id.nil?
    raise ArgumentError, 'subscription_id must be specified for this Service class'
  end

  # Base URL used for REST calls. Modify within method calls as needed.
  @base_url = File.join(
    configuration.environment.resource_url,
    'subscriptions',
    configuration.subscription_id
  )

  set_service_api_version(options, service_name)
end

Private Class Methods

raise_api_exception(err) click to toggle source
# File lib/azure/armrest/armrest_service.rb, line 257
def raise_api_exception(err)
  begin
    content_type_header = err.response.headers[:content_type]

    response = case content_type_header.match(%r{(application/\w+)})[1]
               when "application/json"
                 JSON.parse(err.http_body)
               when "application/xml"
                 # The XML document that is returned has Error, Code, and Message
                 # so we need to downcase the keys to stay consistent with the
                 # parsed-json hash.
                 Hash.from_xml(err.http_body).deep_transform_keys(&:downcase)
               end

    code    = response['error']['code']
    message = response['error']['message']
  rescue
    code    = err.try(:http_code) || err.try(:code)
    message = err.try(:http_body) || err.try(:message)
  end

  exception_type = Azure::Armrest::EXCEPTION_MAP[err.http_code]

  # If this is an exception that doesn't map directly to an HTTP code
  # then parse it the exception class name and re-raise it as our own.
  if exception_type.nil?
    begin
      klass = "Azure::Armrest::" + err.class.to_s.split("::").last + "Exception"
      exception_type = const_get(klass)
    rescue NameError
      exception_type = Azure::Armrest::ApiException
    end
  end

  raise exception_type.new(code, message, err)
end
rest_delete(options) click to toggle source
# File lib/azure/armrest/armrest_service.rb, line 245
def rest_delete(options)
  rest_execute(options, :delete)
end
rest_execute(options, http_method = :get, encode = true, max_retries = 3) click to toggle source
# File lib/azure/armrest/armrest_service.rb, line 211
def rest_execute(options, http_method = :get, encode = true, max_retries = 3)
  tries ||= 0
  url = encode ? Addressable::URI.encode(options[:url]) : options[:url]
  options = options.merge(:method => http_method, :url => url)
  RestClient::Request.execute(options)
rescue RestClient::Exception => err
  if [409, 429, 500, 502, 503, 504].include?(err.http_code)
    tries += 1
    if tries <= max_retries
      msg = "A rate limit or server side issue has occurred [#{err.http_code}]. Retry number #{tries}."
      Azure::Armrest::Configuration.log.try(:log, Logger::WARN, msg)
      sleep_time = (err.response.headers[:retry_after] || 30).to_i
      sleep_time = 5 if sleep_time < 5     # 5 second minimum
      sleep_time = 120 if sleep_time > 120 # 2 minute maximum
      sleep(sleep_time)
      retry
    end
  end

  raise_api_exception(err)
end
rest_get(options) click to toggle source
# File lib/azure/armrest/armrest_service.rb, line 233
def rest_get(options)
  rest_execute(options, :get)
end
rest_head(options) click to toggle source
# File lib/azure/armrest/armrest_service.rb, line 253
def rest_head(options)
  rest_execute(options, :head)
end
rest_patch(options) click to toggle source
# File lib/azure/armrest/armrest_service.rb, line 241
def rest_patch(options)
  rest_execute(options, :patch)
end
rest_post(options) click to toggle source
# File lib/azure/armrest/armrest_service.rb, line 237
def rest_post(options)
  rest_execute(options, :post)
end
rest_put(options) click to toggle source
# File lib/azure/armrest/armrest_service.rb, line 249
def rest_put(options)
  rest_execute(options, :put)
end

Public Instance Methods

geo_locations(provider)
Alias for: get_provider
get_provider(provider) click to toggle source

Returns information about the specific provider namespace.

# File lib/azure/armrest/armrest_service.rb, line 72
def get_provider(provider)
  configuration.providers.find { |rp| rp.namespace.casecmp(provider) == 0 }
end
Also aliased as: geo_locations, provider_info
get_subscription(subscription_id = configuration.subscription_id) click to toggle source

Return information for the specified subscription ID, or the subscription ID that was provided in the constructor if none is specified.

# File lib/azure/armrest/armrest_service.rb, line 117
def get_subscription(subscription_id = configuration.subscription_id)
  subs = Azure::Armrest::SubscriptionService.new(configuration)
  subs.get(subscription_id)
end
Also aliased as: subscription_info
list_locations() click to toggle source

Returns a list of Location objects for the current subscription.

# File lib/azure/armrest/armrest_service.rb, line 99
def list_locations
  url = url_with_api_version(configuration.api_version, base_url, 'locations')
  response = rest_get(url)
  Azure::Armrest::ArmrestCollection.create_from_response(response, Location)
end
list_resource_groups() click to toggle source

Returns an array of ResourceGroup objects for the current subscription.

# File lib/azure/armrest/armrest_service.rb, line 142
def list_resource_groups
  Azure::Armrest::ResourceGroupService.new(configuration).list
end
Also aliased as: resource_groups
list_resources(resource_group = nil) click to toggle source

Returns an array of Resource objects for the current subscription. If a resource_group is provided, only list resources for that resource group.

# File lib/azure/armrest/armrest_service.rb, line 129
def list_resources(resource_group = nil)
  if resource_group
    Azure::Armrest::ResourceService.new(configuration).list(resource_group)
  else
    Azure::Armrest::ResourceService.new(configuration).list_all
  end
end
Also aliased as: resources
list_subscriptions() click to toggle source

Returns a list of subscriptions for the current tenant.

# File lib/azure/armrest/armrest_service.rb, line 106
def list_subscriptions
  Azure::Armrest::SubscriptionService.new(configuration).list
end
Also aliased as: subscriptions
locations(provider = nil) click to toggle source

Returns a list of all locations for all resource types of the given provider. If you do not specify a provider, then the locations for all providers will be returned.

If you need individual details on a per-provider basis, use the methods of the ResourceProviderService instead.

Deprecated.

# File lib/azure/armrest/armrest_service.rb, line 89
def locations(provider = nil)
  list = configuration.providers
  list = list.select { |rp| rp.namespace.casecmp(provider) == 0 } if provider
  list.collect { |rp| rp.resource_types.map(&:locations) }.flatten.uniq.sort
end
poll(response) click to toggle source

Poll a resource and return its current operations status. The response argument should be a ResponseHeaders object that contains the :azure_asyncoperation header. It may optionally be an object that returns a URL from a .to_s method.

This is meant to check the status of asynchronous operations, such as create or delete.

# File lib/azure/armrest/armrest_service.rb, line 173
def poll(response)
  return 'Succeeded' if [200, 201].include?(response.response_code)
  url = response.try(:azure_asyncoperation) || response.try(:location)
  response = rest_get(url).body
  unless response.blank?
    status = JSON.parse(response)['status']
  end
  status || 'Succeeded' # assume succeeded otherwise the wait method may hang
end
provider_info(provider)
Alias for: get_provider
resource_groups()
resources(resource_group = nil)
Alias for: list_resources
subscription_info(subscription_id = configuration.subscription_id)
Alias for: get_subscription
subscriptions()
Alias for: list_subscriptions
tags() click to toggle source

Returns a list of tags for the current subscription.

# File lib/azure/armrest/armrest_service.rb, line 151
def tags
  url = url_with_api_version(configuration.api_version, base_url, 'tagNames')
  resp = rest_get(url)
  JSON.parse(resp.body)["value"].map{ |hash| Azure::Armrest::Tag.new(hash) }
end
tenants() click to toggle source

Returns a list of tenants that can be accessed.

# File lib/azure/armrest/armrest_service.rb, line 159
def tenants
  url = url_with_api_version(configuration.api_version, configuration.environment.resource_url, 'tenants')
  resp = rest_get(url)
  JSON.parse(resp.body)['value'].map{ |hash| Azure::Armrest::Tenant.new(hash) }
end
wait(response, max_time = 60, default_interval = 10) click to toggle source

Wait for the given response to return a status of ‘Succeeded’, up to a maximum of max_time seconds, and return the operations status. The first argument must be a ResponseHeaders object that contains the azure_asyncoperation header.

Internally this will poll the response header every :retry_after seconds (or 10 seconds if that header isn’t found), up to a maximum of 60 seconds by default. There is no timeout limit if max_time is 0.

For most resources the max_time argument should be more than sufficient. Certain resources, such as virtual machines, could take longer.

# File lib/azure/armrest/armrest_service.rb, line 195
def wait(response, max_time = 60, default_interval = 10)
  sleep_time = response.respond_to?(:retry_after) ? response.retry_after.to_i : default_interval
  total_time = 0

  until (status = poll(response)) =~ /^succe/i # success or succeeded
    total_time += sleep_time
    break if max_time > 0 && total_time >= max_time
    sleep sleep_time
  end

  status
end

Private Instance Methods

get_all_results(response, skip_accessors_definition = false) click to toggle source

Make additional calls and concatenate the results if a continuation URL is found.

# File lib/azure/armrest/armrest_service.rb, line 377
def get_all_results(response, skip_accessors_definition = false)
  results  = Azure::Armrest::ArmrestCollection.create_from_response(response, model_class, skip_accessors_definition)
  nextlink = results.next_link

  while nextlink
    response = rest_get_without_encoding(nextlink)
    more = Azure::Armrest::ArmrestCollection.create_from_response(response, model_class, skip_accessors_definition)
    results.concat(more)
    nextlink = more.next_link
  end

  results
end
log(level = "info", msg) click to toggle source
# File lib/azure/armrest/armrest_service.rb, line 395
def log(level = "info", msg)
  RestClient.log.try(level, msg)
end
model_class() click to toggle source
# File lib/azure/armrest/armrest_service.rb, line 391
def model_class
  @model_class ||= Object.const_get(self.class.to_s.sub(/Service$/, ''))
end
parse_skip_token(json) click to toggle source

Parse the skip token value out of the nextLink attribute from a response.

# File lib/azure/armrest/armrest_service.rb, line 371
def parse_skip_token(json)
  return nil unless json['nextLink']
  json['nextLink'][/.*?skipToken=(.*?)$/i, 1]
end
rest_delete(url) click to toggle source
# File lib/azure/armrest/armrest_service.rb, line 338
def rest_delete(url)
  rest_execute(url, nil, :delete, true, configuration.max_retries)
end
rest_execute(url, body = nil, http_method = :get, encode = true, max_retries = 3) click to toggle source

REST verb methods

# File lib/azure/armrest/armrest_service.rb, line 299
def rest_execute(url, body = nil, http_method = :get, encode = true, max_retries = 3)
  options = {
    :url         => url,
    :proxy       => configuration.proxy,
    :ssl_version => configuration.ssl_version,
    :ssl_verify  => configuration.ssl_verify,
    :timeout     => configuration.timeout,
    :headers => {
      :accept        => configuration.accept,
      :content_type  => configuration.content_type,
      :authorization => configuration.token
    }
  }

  options[:payload] = body if body

  self.class.send(:rest_execute, options, http_method, encode, max_retries)
end
rest_get(url) click to toggle source
# File lib/azure/armrest/armrest_service.rb, line 318
def rest_get(url)
  rest_execute(url, nil, :get, true, configuration.max_retries)
end
rest_get_without_encoding(url) click to toggle source
# File lib/azure/armrest/armrest_service.rb, line 322
def rest_get_without_encoding(url)
  rest_execute(url, nil, :get, false, configuration.max_retries)
end
rest_head(url) click to toggle source
# File lib/azure/armrest/armrest_service.rb, line 342
def rest_head(url)
  rest_execute(url, nil, :head, true, configuration.max_retries)
end
rest_patch(url, body = '') click to toggle source
# File lib/azure/armrest/armrest_service.rb, line 334
def rest_patch(url, body = '')
  rest_execute(url, body, :patch, true, configuration.max_retries)
end
rest_post(url, body = '') click to toggle source
# File lib/azure/armrest/armrest_service.rb, line 330
def rest_post(url, body = '')
  rest_execute(url, body, :post, true, configuration.max_retries)
end
rest_put(url, body = '') click to toggle source
# File lib/azure/armrest/armrest_service.rb, line 326
def rest_put(url, body = '')
  rest_execute(url, body, :put, true, configuration.max_retries)
end
set_service_api_version(options, service) click to toggle source

Each Azure API call may require different api_version. The api_version in armrest_configuration is used for common methods provided by ArmrestService

The options hash for each service’s constructor can contain key-value pair

api_version => version

This version will be used for the service specific API calls

Otherwise the service specific api_version is looked up from configuration.providers

Finally api_version in armrest_configuration is used if service specific version cannot be determined

# File lib/azure/armrest/armrest_service.rb, line 363
def set_service_api_version(options, service)
  @api_version =
    options['api_version'] ||
    configuration.provider_default_api_version(provider, service) ||
    configuration.api_version
end
url_with_api_version(api_version, *paths) click to toggle source

Take an array of URI elements and join the together with the API version.

# File lib/azure/armrest/armrest_service.rb, line 347
def url_with_api_version(api_version, *paths)
  File.join(*paths) << "?api-version=#{api_version}"
end