azure-armrest 0.2.10 → 0.3.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,54 @@
1
+ module Azure
2
+ module Armrest
3
+ module Billing
4
+ class UsageService < ArmrestService
5
+ # Creates and returns a new UsageService object.
6
+ #
7
+ def initialize(configuration, options = {})
8
+ options = options.merge('api_version' => '2015-06-01-preview')
9
+ super(configuration, 'subscriptions', 'Microsoft.Commerce', options)
10
+ end
11
+
12
+ # List usage details. The +options+ hash may include the following
13
+ # filters:
14
+ #
15
+ # :reportedStartTime # e.g. 2016-05-30T00:00:00Z. Mandatory.
16
+ # :reportedEndTime # e.g. 2016-06-01T00:00:00Z. Mandatory.
17
+ # :aggregationGranularity # Either 'Daily' or 'Hourly'. Default is Daily.
18
+ # :showDetails # Either true or false. Default is true.
19
+ # :continuationToken # Token received from previous call. No default.
20
+ #
21
+ # The :reportedStartTime and :reportedEndTime values should be in
22
+ # UTC + iso8601 format. For "Daily" aggregation, the time should be set
23
+ # to midnight. For "Hourly" aggregation, only the hour should be
24
+ # set, with minutes and seconds set to "00".
25
+ #
26
+ def list(options = {})
27
+ url = build_url(options)
28
+ response = rest_get(url)
29
+ JSON.parse(response)['value'].map { |hash| Azure::Armrest::Usage.new(hash) }
30
+ end
31
+
32
+ private
33
+
34
+ def build_url(options = {})
35
+ url = File.join(
36
+ Azure::Armrest::COMMON_URI,
37
+ configuration.subscription_id,
38
+ 'providers',
39
+ @provider,
40
+ 'UsageAggregates'
41
+ )
42
+
43
+ url << "?api-version=#{@api_version}"
44
+
45
+ options.each do |key, value|
46
+ url << "&#{key}=#{value}"
47
+ end
48
+
49
+ url
50
+ end
51
+ end
52
+ end
53
+ end
54
+ end
@@ -0,0 +1,258 @@
1
+ module Azure
2
+ module Armrest
3
+ class Configuration
4
+ # Clear all class level caches. Typically used for testing only.
5
+ def self.clear_caches
6
+ # Used to store unique token information.
7
+ @token_cache = Hash.new { |h, k| h[k] = [] }
8
+ end
9
+
10
+ clear_caches # Clear caches at load time.
11
+
12
+ # Retrieve the cached token for a configuration.
13
+ # Return both the token and its expiration date, or nil if not cached
14
+ def self.retrieve_token(configuration)
15
+ @token_cache[configuration.hash]
16
+ end
17
+
18
+ # Cache the token for a configuration that a token has been fetched from Azure
19
+ def self.cache_token(configuration)
20
+ raise ArgumentError, "Configuration does not have a token" if configuration.token.nil?
21
+ @token_cache[configuration.hash] = [configuration.token, configuration.token_expiration]
22
+ end
23
+
24
+ # The api-version string
25
+ attr_accessor :api_version
26
+
27
+ # The client ID used to gather token information.
28
+ attr_accessor :client_id
29
+
30
+ # The client key used to gather token information.
31
+ attr_accessor :client_key
32
+
33
+ # The tenant ID used to gather token information.
34
+ attr_accessor :tenant_id
35
+
36
+ # The subscription ID used for each http request.
37
+ attr_accessor :subscription_id
38
+
39
+ # The resource group used for http requests.
40
+ attr_accessor :resource_group
41
+
42
+ # The grant type. The default is client_credentials.
43
+ attr_accessor :grant_type
44
+
45
+ # The content type specified for http requests. The default is 'application/json'
46
+ attr_accessor :content_type
47
+
48
+ # The accept type specified for http request results. The default is 'application/json'
49
+ attr_accessor :accept
50
+
51
+ # Proxy to be used for all http requests.
52
+ attr_accessor :proxy
53
+
54
+ # SSL version to be used for all http requests.
55
+ attr_accessor :ssl_version
56
+
57
+ # SSL verify mode for all http requests.
58
+ attr_accessor :ssl_verify
59
+
60
+ # Namespace providers, their resource types, locations and supported api-version strings.
61
+ attr_reader :providers
62
+
63
+ # Yields a new Azure::Armrest::Configuration objects. Note that you must
64
+ # specify a client_id, client_key, tenant_id and subscription_id. All other
65
+ # parameters are optional.
66
+ #
67
+ # Example:
68
+ #
69
+ # config = Azure::Armrest::Configuration.new(
70
+ # :client_id => 'xxxx',
71
+ # :client_key => 'yyyy',
72
+ # :tenant_id => 'zzzz',
73
+ # :subscription_id => 'abcd'
74
+ # )
75
+ #
76
+ # If you specify a :resource_group, that group will be used for resource
77
+ # group based service class requests. Otherwise, you will need to specify
78
+ # a resource group for most service methods.
79
+ #
80
+ # Although you can specify an :api_version, it is typically overridden
81
+ # by individual service classes.
82
+ #
83
+ def initialize(args)
84
+ # Use defaults, and override with provided arguments
85
+ options = {
86
+ :api_version => '2015-01-01',
87
+ :accept => 'application/json',
88
+ :content_type => 'application/json',
89
+ :grant_type => 'client_credentials',
90
+ :proxy => ENV['http_proxy'],
91
+ :ssl_version => 'TLSv1',
92
+ }.merge(args.symbolize_keys)
93
+
94
+ user_token = options.delete(:token)
95
+ user_token_expiration = options.delete(:token_expiration)
96
+
97
+ options.each { |key, value| send("#{key}=", value) }
98
+
99
+ unless client_id && client_key && tenant_id && subscription_id
100
+ raise ArgumentError, "client_id, client_key, tenant_id and subscription_id must all be specified"
101
+ end
102
+
103
+ if user_token && user_token_expiration
104
+ set_token(user_token, user_token_expiration)
105
+ elsif user_token || user_token_expiration
106
+ raise ArgumentError, "token and token_expiration must be both specified"
107
+ end
108
+
109
+ # Allows for URI objects or Strings.
110
+ @proxy = @proxy.to_s if @proxy
111
+
112
+ @providers = fetch_providers
113
+ set_provider_api_versions
114
+ end
115
+
116
+ def hash
117
+ [tenant_id, client_id, client_key].join('_').hash
118
+ end
119
+
120
+ def eql?(other)
121
+ return true if equal?(other)
122
+ return false unless self.class == other.class
123
+ tenant_id == other.tenant_id && client_id == other.client_id && client_key == other.client_key
124
+ end
125
+
126
+ # Returns the token for the current cache key, or sets it if it does not
127
+ # exist or it has expired.
128
+ #
129
+ def token
130
+ ensure_token
131
+ @token
132
+ end
133
+
134
+ # Set the token value and expiration time.
135
+ #
136
+ def set_token(token, token_expiration)
137
+ validate_token_time(token_expiration)
138
+
139
+ @token, @token_expiration = token, token_expiration.utc
140
+ self.class.cache_token(self)
141
+ end
142
+
143
+ # Returns the expiration datetime of the current token
144
+ #
145
+ def token_expiration
146
+ ensure_token
147
+ @token_expiration
148
+ end
149
+
150
+ # Return the default api version for the given provider and service
151
+ def provider_default_api_version(provider, service)
152
+ @provider_api_versions[provider.downcase][service.downcase]
153
+ end
154
+
155
+ # The name of the file or handle used to log http requests.
156
+ #--
157
+ # We have to do a little extra work here to convert a possible
158
+ # file handle to a file name.
159
+ #
160
+ def self.log
161
+ file = RestClient.log.instance_variable_get("@target_file")
162
+ file || RestClient.log
163
+ end
164
+
165
+ # Sets the log to +output+, which can be a file or a handle.
166
+ #
167
+ def self.log=(output)
168
+ RestClient.log = output
169
+ end
170
+
171
+ private
172
+
173
+ def ensure_token
174
+ @token, @token_expiration = self.class.retrieve_token(self) if @token.nil?
175
+ fetch_token if @token.nil? || Time.now.utc > @token_expiration
176
+ end
177
+
178
+ # Don't allow tokens from the past to be set.
179
+ #
180
+ def validate_token_time(time)
181
+ if time.utc < Time.now.utc
182
+ raise ArgumentError, 'token_expiration date invalid'
183
+ end
184
+ end
185
+
186
+ # Build a one-time lookup hash that sets the appropriate api-version
187
+ # string for a given provider and resource type. If possible, select
188
+ # a non-preview version that is not set in the future. Otherwise, just
189
+ # just the most recent one.
190
+ #
191
+ def set_provider_api_versions
192
+ # A lookup table for getting api-version strings per provider and service.
193
+ @provider_api_versions = Hash.new { |hash, key| hash[key] = {} }
194
+
195
+ providers.each do |rp|
196
+ rp.resource_types.each do |rt|
197
+ if rt.api_versions.any? { |v| v !~ /preview/i && Time.parse(v).utc <= Time.now.utc }
198
+ api_version = rt.api_versions.reject do |version|
199
+ version =~ /preview/i || Time.parse(version).utc > Time.now.utc
200
+ end.first
201
+ else
202
+ api_version = rt.api_versions.first
203
+ end
204
+
205
+ namespace = rp['namespace'].downcase # Avoid name collision
206
+ resource_type = rt.resource_type.downcase
207
+
208
+ @provider_api_versions[namespace][resource_type] = api_version
209
+ end
210
+ end
211
+ end
212
+
213
+ def fetch_providers
214
+ uri = Addressable::URI.join(Azure::Armrest::RESOURCE, 'providers')
215
+ uri.query = "api-version=#{api_version}"
216
+
217
+ response = ArmrestService.send(
218
+ :rest_get,
219
+ :url => uri.to_s,
220
+ :proxy => proxy,
221
+ :ssl_version => ssl_version,
222
+ :ssl_verify => ssl_verify,
223
+ :headers => {
224
+ :content_type => content_type,
225
+ :authorization => token
226
+ }
227
+ )
228
+
229
+ JSON.parse(response.body)['value'].map { |hash| Azure::Armrest::ResourceProvider.new(hash) }
230
+ end
231
+
232
+ def fetch_token
233
+ token_url = File.join(Azure::Armrest::AUTHORITY, tenant_id, 'oauth2/token')
234
+
235
+ response = JSON.parse(
236
+ ArmrestService.send(
237
+ :rest_post,
238
+ :url => token_url,
239
+ :proxy => proxy,
240
+ :ssl_version => ssl_version,
241
+ :ssl_verify => ssl_verify,
242
+ :payload => {
243
+ :grant_type => grant_type,
244
+ :client_id => client_id,
245
+ :client_secret => client_key,
246
+ :resource => Azure::Armrest::RESOURCE
247
+ }
248
+ )
249
+ )
250
+
251
+ @token = 'Bearer ' + response['access_token']
252
+ @token_expiration = Time.now.utc + response['expires_in'].to_i
253
+
254
+ self.class.cache_token(self)
255
+ end
256
+ end
257
+ end
258
+ end
@@ -4,30 +4,15 @@ module Azure
4
4
  attr_accessor :cause
5
5
  attr_writer :message
6
6
 
7
- # Create a new Armrest::Exception object. The +message+ should be an
8
- # error string, while +cause_exception+ is typically set to the
9
- # raw RestClient exception.
10
- #
11
- # You will not typically use this object directly.
12
- #
13
7
  def initialize(message = nil, cause_exception = nil)
14
8
  @message = message
15
9
  @cause = cause_exception
16
10
  end
17
11
 
18
- # The stringified version (message) of the exception.
19
- #
20
12
  def to_s
21
- if cause
22
- "#{message} (cause: #{cause})"
23
- else
24
- message
25
- end
13
+ message
26
14
  end
27
15
 
28
- # The error message or, if the message is not set, the name of the
29
- # exception class.
30
- #
31
16
  def message
32
17
  @message || self.class.name
33
18
  end
@@ -36,24 +21,16 @@ module Azure
36
21
  class ApiException < Exception
37
22
  attr_accessor :code
38
23
 
39
- # Create a new ApiException class. The +code+ is the error code.
40
- #
41
- # This class serves as the parent
42
24
  def initialize(code, message, cause_exception)
43
25
  @code = code
44
26
  super(message, cause_exception)
45
27
  end
46
28
 
47
- # A stringified version of the error. If self is a plain ApiException,
48
- # then the cause is included to aid in debugging.
49
- #
50
29
  def to_s
51
- "[#{code}] #{super}"
30
+ "[#{code}] #{message}"
52
31
  end
53
32
  end
54
33
 
55
- # A list of predefined exceptions that we wrap around RestClient exceptions.
56
-
57
34
  class ResourceNotFoundException < ApiException; end
58
35
 
59
36
  class BadRequestException < ApiException; end
@@ -64,5 +41,7 @@ module Azure
64
41
 
65
42
  class GatewayTimeoutException < ApiException; end
66
43
 
44
+ class TooManyRequestsException < ApiException; end
45
+
67
46
  end
68
47
  end
@@ -89,11 +89,30 @@ module Azure
89
89
  @json
90
90
  end
91
91
 
92
+ def inspect_method_list
93
+ methods(false).reject { |m| m.to_s.end_with?('=') }
94
+ end
95
+ private :inspect_method_list
96
+
92
97
  def inspect
93
- string = "<#{self.class} "
94
- method_list = methods(false).select { |m| !m.to_s.include?('=') }
95
- string << method_list.map { |m| "#{m}=#{send(m).inspect}" }.join(', ')
96
- string << '>'
98
+ Kernel.instance_method(:to_s).bind(self).call.chomp!('>') <<
99
+ ' ' <<
100
+ inspect_method_list.map { |m| "#{m}=#{send(m).inspect}" }.join(', ') <<
101
+ '>'
102
+ end
103
+
104
+ def pretty_print(q)
105
+ q.object_address_group(self) {
106
+ q.seplist(inspect_method_list, lambda { q.text ',' }) {|v|
107
+ q.breakable
108
+ q.text v.to_s
109
+ q.text '='
110
+ q.group(1) {
111
+ q.breakable ''
112
+ q.pp(send(v))
113
+ }
114
+ }
115
+ }
97
116
  end
98
117
 
99
118
  def ==(other)
@@ -173,6 +192,7 @@ module Azure
173
192
  class ResourceGroup < BaseModel; end
174
193
  class ResourceProvider < BaseModel; end
175
194
  class Sku < BaseModel; end
195
+ class Usage < BaseModel; end
176
196
 
177
197
  class StorageAccount < BaseModel; end
178
198
  class StorageAccountKey < StorageAccount
@@ -169,7 +169,8 @@ module Azure
169
169
 
170
170
  headers = build_headers(url, key, :blob, :verb => 'HEAD')
171
171
 
172
- response = ArmrestService.rest_head(
172
+ response = ArmrestService.send(
173
+ :rest_head,
173
174
  :url => url,
174
175
  :headers => headers,
175
176
  :proxy => proxy,
@@ -192,7 +193,8 @@ module Azure
192
193
 
193
194
  headers = build_headers(url, key)
194
195
 
195
- response = ArmrestService.rest_get(
196
+ response = ArmrestService.send(
197
+ :rest_get,
196
198
  :url => url,
197
199
  :headers => headers,
198
200
  :proxy => proxy,
@@ -283,7 +285,8 @@ module Azure
283
285
 
284
286
  headers = build_headers(dst_url, key, :blob, options)
285
287
 
286
- response = ArmrestService.rest_put(
288
+ response = ArmrestService.send(
289
+ :rest_put,
287
290
  :url => dst_url,
288
291
  :payload => '',
289
292
  :headers => headers,
@@ -305,7 +308,8 @@ module Azure
305
308
 
306
309
  headers = build_headers(url, key, :blob, :verb => 'DELETE')
307
310
 
308
- response = ArmrestService.rest_delete(
311
+ ArmrestService.send(
312
+ :rest_delete,
309
313
  :url => url,
310
314
  :headers => headers,
311
315
  :proxy => proxy,
@@ -335,7 +339,8 @@ module Azure
335
339
  options = options.merge(data)
336
340
  headers = build_headers(url, key, :blob, options)
337
341
 
338
- response = ArmrestService.rest_put(
342
+ response = ArmrestService.send(
343
+ :rest_put,
339
344
  :url => url,
340
345
  :payload => '',
341
346
  :headers => headers,
@@ -355,7 +360,8 @@ module Azure
355
360
 
356
361
  headers = build_headers(url, key, :blob, :verb => 'PUT')
357
362
 
358
- response = ArmrestService.rest_put(
363
+ response = ArmrestService.send(
364
+ :rest_put,
359
365
  :url => url,
360
366
  :payload => '',
361
367
  :headers => headers,
@@ -432,7 +438,8 @@ module Azure
432
438
 
433
439
  headers = build_headers(url, key, :blob, additional_headers)
434
440
 
435
- ArmrestService.rest_get(
441
+ ArmrestService.send(
442
+ :rest_get,
436
443
  :url => url,
437
444
  :headers => headers,
438
445
  :proxy => proxy,
@@ -486,7 +493,8 @@ module Azure
486
493
  url = File.join(properties.primary_endpoints.blob, *args) + "?#{query}"
487
494
  headers = build_headers(url, key, 'blob')
488
495
 
489
- ArmrestService.rest_get(
496
+ ArmrestService.send(
497
+ :rest_get,
490
498
  :url => url,
491
499
  :headers => headers,
492
500
  :proxy => proxy,
@@ -508,7 +516,8 @@ module Azure
508
516
  url << "?#{query}"
509
517
  end
510
518
 
511
- ArmrestService.rest_get(
519
+ ArmrestService.send(
520
+ :rest_get,
512
521
  :url => url,
513
522
  :headers => headers,
514
523
  :proxy => proxy,