class Azure::Armrest::ArmrestService
Abstract base class for the other service classes.
Attributes
The api-version string for this particular service
Configuration
to access azure APIs
Base url with subscription information used for most REST calls.
Configuration
to access azure APIs
Provider for service specific API calls
The service name for the Service class
Public Class Methods
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
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
# 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
# File lib/azure/armrest/armrest_service.rb, line 245 def rest_delete(options) rest_execute(options, :delete) end
# 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
# File lib/azure/armrest/armrest_service.rb, line 233 def rest_get(options) rest_execute(options, :get) end
# File lib/azure/armrest/armrest_service.rb, line 253 def rest_head(options) rest_execute(options, :head) end
# File lib/azure/armrest/armrest_service.rb, line 241 def rest_patch(options) rest_execute(options, :patch) end
# File lib/azure/armrest/armrest_service.rb, line 237 def rest_post(options) rest_execute(options, :post) end
# File lib/azure/armrest/armrest_service.rb, line 249 def rest_put(options) rest_execute(options, :put) end
Public Instance Methods
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
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
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
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
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
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
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 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
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 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
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
# File lib/azure/armrest/armrest_service.rb, line 395 def log(level = "info", msg) RestClient.log.try(level, msg) end
# 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 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
# File lib/azure/armrest/armrest_service.rb, line 338 def rest_delete(url) rest_execute(url, nil, :delete, true, configuration.max_retries) end
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
# File lib/azure/armrest/armrest_service.rb, line 318 def rest_get(url) rest_execute(url, nil, :get, true, configuration.max_retries) end
# 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
# File lib/azure/armrest/armrest_service.rb, line 342 def rest_head(url) rest_execute(url, nil, :head, true, configuration.max_retries) end
# File lib/azure/armrest/armrest_service.rb, line 334 def rest_patch(url, body = '') rest_execute(url, body, :patch, true, configuration.max_retries) end
# File lib/azure/armrest/armrest_service.rb, line 330 def rest_post(url, body = '') rest_execute(url, body, :post, true, configuration.max_retries) end
# File lib/azure/armrest/armrest_service.rb, line 326 def rest_put(url, body = '') rest_execute(url, body, :put, true, configuration.max_retries) end
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
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