azure-armrest 0.8.4 → 0.8.5

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 9addd4499d546f9fb5eb12b5e454046709164836
4
- data.tar.gz: 3ccf69833fe525244581ed5e68b4e73503044bfd
3
+ metadata.gz: 271d67cb70166d8d00b30c234d1ecb6f26cfaaf5
4
+ data.tar.gz: adfdb6724dd8ca45b8314ba48537ff2ad229f469
5
5
  SHA512:
6
- metadata.gz: 63a3a2109b5d66e4de0f381d03d283bfdeef576c35bdf5b367c1fb473a67ea1bd36a21e97ee1d195222c1d3eab0812038dc48797cebb800fc8163d20f137d632
7
- data.tar.gz: 2e304ffabb9f08ca194fc5baed83a567acf007e2de0f2543e09a7886367b8e10b59abfe14519810d2c85def97675bb1fa55c4b022b15f6d252f7d59a684c8dc2
6
+ metadata.gz: ae90f2ed141868131b93df713ddae8e54b559ffd503da223fc3d6a9daad01cb3bf1b14d0c87e6ffc54156933407b93268d964dadf65b5a22cadfa1831a755ced
7
+ data.tar.gz: 4a0da229be85bd145421d215cfa064e7cebf745fe754b058f9d2a54fc2c0140ffff3492854877168e6b815b304dad0aa72c8588582e6dd990e98f7775e1981ff
data/.rubocop_local.yml CHANGED
@@ -0,0 +1,3 @@
1
+ Style/MethodCallWithArgsParentheses:
2
+ IgnoredMethods:
3
+ - attr_from_hash
data/CHANGES CHANGED
@@ -1,3 +1,6 @@
1
+ = 0.8.5 - 10-Oct-2017
2
+ * Backported the light model changes from 0.9.0.
3
+
1
4
  = 0.8.4 - 2-Oct-2017
2
5
  * Logging bug fix in StorageAccount#all_blobs method.
3
6
  * Modified the StorageAccountService#list_all_private_image method. It now
@@ -16,9 +16,9 @@ module Azure
16
16
  # using +klass+ to generate the list elements. In addition, both the
17
17
  # response headers and continuation token are set.
18
18
  #
19
- def create_from_response(response, klass = nil)
19
+ def create_from_response(response, klass = nil, skip_accessors_definition = false)
20
20
  json_response = JSON.parse(response)
21
- array = new(json_response['value'].map { |hash| klass.new(hash) })
21
+ array = new(json_response['value'].map { |hash| klass.new(hash, skip_accessors_definition) })
22
22
 
23
23
  array.response_code = response.code
24
24
  array.response_headers = response.headers
@@ -357,13 +357,13 @@ module Azure
357
357
  end
358
358
 
359
359
  # Make additional calls and concatenate the results if a continuation URL is found.
360
- def get_all_results(response)
361
- results = Azure::Armrest::ArmrestCollection.create_from_response(response, model_class)
360
+ def get_all_results(response, skip_accessors_definition = false)
361
+ results = Azure::Armrest::ArmrestCollection.create_from_response(response, model_class, skip_accessors_definition)
362
362
  nextlink = results.next_link
363
363
 
364
364
  while nextlink
365
365
  response = rest_get_without_encoding(nextlink)
366
- more = Azure::Armrest::ArmrestCollection.create_from_response(response, model_class)
366
+ more = Azure::Armrest::ArmrestCollection.create_from_response(response, model_class, skip_accessors_definition)
367
367
  results.concat(more)
368
368
  nextlink = more.next_link
369
369
  end
@@ -23,6 +23,58 @@ module Azure
23
23
 
24
24
  attr_hash :tags
25
25
 
26
+ # Defines attr_reader methods for the given set of attributes and
27
+ # expected hash key. Used to define methods that can be used internally
28
+ # that avoid needing to use methods defined from
29
+ # `add_accessor_methods`/`__setobj__`
30
+ #
31
+ # Example:
32
+ # class Vm < Azure::ArmRest::BaseModel
33
+ # attr_from_hash :name => :Name
34
+ # end
35
+ #
36
+ # json_string = {'name' => 'Deathstar'}
37
+ #
38
+ # vm = Vm.new(json_string)
39
+ # vm.name_from_hash
40
+ # #=> "Deathstar"
41
+ #
42
+ # # If the attr_from_hash can also support multiple attrs in a single
43
+ # # call, and nested params
44
+ #
45
+ # class Host < Azure::ArmRest::BaseModel
46
+ # attr_from_hash :name => :Name,
47
+ # :address => [:Properties, :ipAddress],
48
+ # end
49
+ #
50
+ # json_string = {'name' => 'Hoth', :Properties => {:ipAddress => '123.123.123.123'}}
51
+ #
52
+ # host = Host.new(json_string)
53
+ # host.name_from_hash
54
+ # #=> "Hoth"
55
+ # host.address_from_hash
56
+ # #=> "123.123.123.123"
57
+ #
58
+ def self.attr_from_hash(attrs = {})
59
+ file, line, _ = caller.first.split(":")
60
+ attrs.each do |attr_name, keys|
61
+ keys = Array(keys)
62
+ first_key = keys.shift
63
+ method_def = [
64
+ "def #{attr_name}_from_hash",
65
+ " return @#{attr_name}_from_hash if defined?(@#{attr_name}_from_hash)",
66
+ " @#{attr_name}_from_hash = __getobj__[:#{first_key}] || __getobj__[\"#{first_key}\"]",
67
+ "end"
68
+ ]
69
+ keys.each do |hash_key|
70
+ method_def.insert(-2, " @#{attr_name}_from_hash = @#{attr_name}_from_hash[:#{hash_key}] || @#{attr_name}_from_hash[\"#{hash_key}\"]")
71
+ end
72
+ class_eval(method_def.join("; "), file, line.to_i)
73
+ end
74
+ end
75
+
76
+ private_class_method :attr_from_hash
77
+
26
78
  attr_accessor :response_headers
27
79
  attr_accessor :response_code
28
80
 
@@ -48,7 +100,7 @@ module Azure
48
100
  # # Or you can get back the original JSON if necessary.
49
101
  # person.to_json # => Returns original JSON
50
102
  #
51
- def initialize(json)
103
+ def initialize(json, skip_accessors_definition = false)
52
104
  # Find the exclusion list for the model of next level (@embed_model)
53
105
  # '#' is the separator between levels. Remove attributes
54
106
  # before the first separator.
@@ -63,15 +115,24 @@ module Azure
63
115
  @json = json
64
116
  end
65
117
 
66
- __setobj__(@hash.dup)
118
+ @hashobj = @hash.dup
119
+ __setobj__ unless skip_accessors_definition
67
120
  end
68
121
 
69
122
  def resource_group
70
- @resource_group ||= id[/resourcegroups\/(.*?[^\/]+)?/i, 1] rescue nil
123
+ @resource_group ||= begin
124
+ id_from_hash[/resourcegroups\/(.*?[^\/]+)?/i, 1]
125
+ rescue
126
+ nil
127
+ end
71
128
  end
72
129
 
73
130
  def subscription_id
74
- @subscription_id ||= id[/subscriptions\/(.*?[^\/]+)?/i, 1] rescue nil
131
+ @subscription_id ||= begin
132
+ id_from_hash[/subscriptions\/(.*?[^\/]+)?/i, 1]
133
+ rescue
134
+ nil
135
+ end
75
136
  end
76
137
 
77
138
  attr_writer :resource_group
@@ -148,21 +209,29 @@ module Azure
148
209
  @hashobj
149
210
  end
150
211
 
212
+ # Do not use this method directly.
213
+ #
214
+ # Will only attempt to fetch the id from the @hashobj once, so even it it
215
+ # is nil, it will cache that value, and return that on subsequent calls.
216
+ def id_from_hash
217
+ return @id_from_hash if defined?(@id_from_hash)
218
+ @id_from_hash = __getobj__[:id] || __getobj__["id"]
219
+ end
220
+
151
221
  # Create snake_case accessor methods for all hash attributes
152
222
  # Use _alias if an accessor conflicts with existing methods
153
- def __setobj__(obj)
154
- @hashobj = obj
223
+ def __setobj__
155
224
  excl_list = self.class.send(:excl_list)
156
- obj.each do |key, value|
225
+ @hashobj.each do |key, value|
157
226
  snake = key.to_s.tr(' ', '_').underscore
158
227
  snake.tr!('.', '_')
159
228
 
160
229
  unless excl_list.include?(snake) # Must deal with nested models
161
230
  if value.kind_of?(Array)
162
231
  newval = value.map { |elem| elem.kind_of?(Hash) ? nested_object(snake.camelize.singularize, elem) : elem }
163
- obj[key] = newval
232
+ @hashobj[key] = newval
164
233
  elsif value.kind_of?(Hash)
165
- obj[key] = nested_object(snake.camelize, value)
234
+ @hashobj[key] = nested_object(snake.camelize, value)
166
235
  end
167
236
  end
168
237
 
@@ -212,8 +281,11 @@ module Azure
212
281
 
213
282
  class StorageAccount < BaseModel; end
214
283
  class StorageAccountKey < StorageAccount
215
- def key1; key_name == 'key1' ? value : nil; end
216
- def key2; key_name == 'key2' ? value : nil; end
284
+ attr_from_hash :key_name => :keyName,
285
+ :value => :value
286
+
287
+ def key1; key_name_from_hash == 'key1' ? value_from_hash : nil; end
288
+ def key2; key_name_from_hash == 'key2' ? value_from_hash : nil; end
217
289
  def key; key1 || key2; end
218
290
  end
219
291
 
@@ -5,10 +5,18 @@ require 'nokogiri'
5
5
  module Azure
6
6
  module Armrest
7
7
  class StorageAccount < BaseModel
8
+ attr_from_hash :name => :name,
9
+ :blob_endpoint => [:properties, :primaryEndpoints, :blob]
10
+
8
11
  # Classes used to wrap container and blob information.
9
- class Container < BaseModel; end
12
+ class Container < BaseModel
13
+ attr_from_hash :name => :Name
14
+ end
10
15
  class ContainerProperty < BaseModel; end
11
- class Blob < BaseModel; end
16
+ class Blob < BaseModel
17
+ attr_from_hash :name => :Name,
18
+ :lease_state => [:Properties, :LeaseState]
19
+ end
12
20
  class BlobProperty < BaseModel; end
13
21
  class PrivateImage < BlobProperty; end
14
22
  class BlobServiceProperty < BaseModel; end
@@ -34,7 +42,7 @@ module Azure
34
42
  # The parent configuration object
35
43
  attr_accessor :configuration
36
44
 
37
- def initialize(json)
45
+ def initialize(json, skip_accessors_definition = false)
38
46
  super
39
47
  @storage_api_version = '2016-05-31'
40
48
  end
@@ -424,14 +432,20 @@ module Azure
424
432
  raise ArgumentError, "No access key specified" unless key
425
433
 
426
434
  query = "comp=list"
427
- options.each { |okey, ovalue| query += "&#{okey}=#{[ovalue].flatten.join(',')}" }
435
+ skip_defs = options[:skip_accessors_definition]
436
+
437
+ options.each do |okey, ovalue|
438
+ unless okey == :skip_accessors_definition
439
+ query += "&#{okey}=#{[ovalue].flatten.join(',')}"
440
+ end
441
+ end
428
442
 
429
443
  response = blob_response(key, query)
430
444
 
431
445
  doc = Nokogiri::XML(response.body)
432
446
 
433
447
  results = doc.xpath('//Containers/Container').collect do |element|
434
- Container.new(Hash.from_xml(element.to_s)['Container'])
448
+ Container.new(Hash.from_xml(element.to_s)['Container'], skip_defs)
435
449
  end
436
450
 
437
451
  results.concat(next_marker_results(doc, :containers, key, options))
@@ -468,7 +482,7 @@ module Azure
468
482
  def blob_properties(container, blob, key = access_key, options = {})
469
483
  raise ArgumentError, "No access key specified" unless key
470
484
 
471
- url = File.join(properties.primary_endpoints.blob, container, blob)
485
+ url = File.join(blob_endpoint_from_hash, container, blob)
472
486
  url += "?snapshot=" + options[:date] if options[:date]
473
487
 
474
488
  headers = build_headers(url, key, :blob, :verb => 'HEAD')
@@ -482,7 +496,7 @@ module Azure
482
496
  :ssl_verify => configuration.ssl_verify
483
497
  )
484
498
 
485
- BlobProperty.new(response.headers.merge(:container => container, :name => blob))
499
+ BlobProperty.new(response.headers.merge(:container => container, :name => blob), options[:skip_accessors_definition])
486
500
  end
487
501
 
488
502
  # Update the given +blob+ in +container+ with the provided options. The
@@ -559,7 +573,13 @@ module Azure
559
573
  raise ArgumentError, "No access key specified" unless key
560
574
 
561
575
  query = "restype=container&comp=list"
562
- options.each { |okey, ovalue| query += "&#{okey}=#{[ovalue].flatten.join(',')}" }
576
+ skip_defs = options[:skip_accessors_definition]
577
+
578
+ options.each do |okey, ovalue|
579
+ unless okey == :skip_accessors_definition
580
+ query += "&#{okey}=#{[ovalue].flatten.join(',')}"
581
+ end
582
+ end
563
583
 
564
584
  response = blob_response(key, query, container)
565
585
 
@@ -567,7 +587,7 @@ module Azure
567
587
 
568
588
  results = doc.xpath('//Blobs/Blob').collect do |node|
569
589
  hash = Hash.from_xml(node.to_s)['Blob'].merge(:container => container)
570
- hash.key?('Snapshot') ? BlobSnapshot.new(hash) : Blob.new(hash)
590
+ hash.key?('Snapshot') ? BlobSnapshot.new(hash, skip_defs) : Blob.new(hash, skip_defs)
571
591
  end
572
592
 
573
593
  results.concat(next_marker_results(doc, :blobs, container, key, options))
@@ -582,10 +602,13 @@ module Azure
582
602
 
583
603
  array = []
584
604
  mutex = Mutex.new
605
+ opts = {
606
+ :skip_accessors_definition => options[:skip_accessors_definition]
607
+ }
585
608
 
586
- Parallel.each(containers(key), :in_threads => max_threads) do |container|
609
+ Parallel.each(containers(key, opts), :in_threads => max_threads) do |container|
587
610
  begin
588
- mutex.synchronize { array.concat(blobs(container.name, key, options)) }
611
+ mutex.synchronize { array.concat(blobs(container.name_from_hash, key, options)) }
589
612
  rescue Errno::ECONNREFUSED, Azure::Armrest::TimeoutException => err
590
613
  msg = "Unable to gather blob information for #{container.name}: #{err}"
591
614
  Azure::Armrest::Configuration.log.try(:log, Logger::WARN, msg)
@@ -938,7 +961,7 @@ module Azure
938
961
  # the url and submit an http request.
939
962
  #
940
963
  def blob_response(key, query, *args)
941
- url = File.join(properties.primary_endpoints.blob, *args) + "?#{query}"
964
+ url = File.join(blob_endpoint_from_hash, *args) + "?#{query}"
942
965
  headers = build_headers(url, key, 'blob')
943
966
 
944
967
  ArmrestService.send(
@@ -97,8 +97,9 @@ module Azure
97
97
  url = build_url
98
98
  url = yield(url) || url if block_given?
99
99
 
100
+ skip_accessors_definition = filter.delete(:skip_accessors_definition) || false
100
101
  response = rest_get(url)
101
- results = get_all_results(response)
102
+ results = get_all_results(response, skip_accessors_definition)
102
103
 
103
104
  if filter.empty?
104
105
  results
@@ -106,7 +107,11 @@ module Azure
106
107
  results.select do |obj|
107
108
  filter.all? do |method_name, value|
108
109
  if value.kind_of?(String)
109
- obj.public_send(method_name).casecmp(value).zero?
110
+ if skip_accessors_definition
111
+ obj[method_name.to_s].casecmp(value).zero?
112
+ else
113
+ obj.public_send(method_name).casecmp(value).zero?
114
+ end
110
115
  else
111
116
  obj.public_send(method_name) == value
112
117
  end
@@ -104,7 +104,7 @@ module Azure
104
104
  #
105
105
  # If you want a plain hash, use the list_account_keys method instead.
106
106
  #
107
- def list_account_key_objects(account_name, group = configuration.resource_group)
107
+ def list_account_key_objects(account_name, group = configuration.resource_group, skip_accessors_definition = false)
108
108
  validate_resource_group(group)
109
109
 
110
110
  unless recent_api_version?
@@ -113,7 +113,7 @@ module Azure
113
113
 
114
114
  url = build_url(group, account_name, 'listKeys')
115
115
  response = rest_post(url)
116
- JSON.parse(response.body)['keys'].map { |hash| StorageAccountKey.new(hash) }
116
+ JSON.parse(response.body)['keys'].map { |hash| StorageAccountKey.new(hash, skip_accessors_definition) }
117
117
  end
118
118
 
119
119
  alias list_storage_account_key_objects list_account_key_objects
@@ -172,7 +172,7 @@ module Azure
172
172
  # Note that for string values the comparison is caseless.
173
173
  #
174
174
  def list_all_private_images(filter = {})
175
- storage_accounts = list_all(filter)
175
+ storage_accounts = list_all(filter.merge(:skip_accessors_definition => true))
176
176
  get_private_images(storage_accounts)
177
177
  end
178
178
 
@@ -187,7 +187,7 @@ module Azure
187
187
  # sas.list_private_images(your_resource_group)
188
188
  #
189
189
  def list_private_images(group = configuration.resource_group)
190
- storage_accounts = list(group)
190
+ storage_accounts = list(group, true)
191
191
  get_private_images(storage_accounts)
192
192
  end
193
193
 
@@ -273,30 +273,36 @@ module Azure
273
273
 
274
274
  Parallel.each(storage_accounts, :in_threads => configuration.max_threads) do |storage_account|
275
275
  begin
276
- key = get_account_key(storage_account)
276
+ key = get_account_key(storage_account, true)
277
277
  rescue Azure::Armrest::ApiException
278
278
  next # Most likely due to incomplete or failed provisioning.
279
279
  else
280
280
  storage_account.access_key = key
281
281
  end
282
282
 
283
- storage_account.containers.each do |container|
284
- next if container.name =~ /^bootdiagnostics/i
285
- storage_account.blobs(container.name).each do |blob|
286
- next unless File.extname(blob.name).casecmp('.vhd').zero?
287
- next unless blob.properties.lease_state.casecmp('available').zero?
283
+ init_opts = { :skip_accessors_definition => true }
284
+ storage_account.containers(storage_account.access_key, init_opts).each do |container|
285
+ next if container.name_from_hash =~ /^bootdiagnostics/i
286
+ storage_account.blobs(container.name_from_hash, storage_account.access_key, init_opts).each do |blob|
287
+ next unless File.extname(blob.name_from_hash).casecmp('.vhd').zero?
288
+ next unless blob.lease_state_from_hash.casecmp('available').zero?
288
289
 
289
290
  # In rare cases the endpoint will be unreachable. Warn and move on.
290
291
  begin
291
- blob_properties = storage_account.blob_properties(blob.container, blob.name)
292
+ blob_properties = storage_account.blob_properties(
293
+ blob[:container],
294
+ blob.name_from_hash,
295
+ storage_account.access_key,
296
+ :skip_accessors_definition => true
297
+ )
292
298
  rescue Errno::ECONNREFUSED, Azure::Armrest::TimeoutException => err
293
299
  msg = "Unable to collect blob properties for #{blob.name}/#{blob.container}: #{err}"
294
300
  log('warn', msg)
295
301
  next
296
302
  end
297
303
 
298
- next unless blob_properties.respond_to?(:x_ms_meta_microsoftazurecompute_osstate)
299
- next unless blob_properties.x_ms_meta_microsoftazurecompute_osstate.casecmp('generalized').zero?
304
+ next unless blob_properties[:x_ms_meta_microsoftazurecompute_osstate]
305
+ next unless blob_properties[:x_ms_meta_microsoftazurecompute_osstate].casecmp('generalized').zero?
300
306
 
301
307
  mutex.synchronize do
302
308
  results << blob_to_private_image_object(storage_account, blob, blob_properties)
@@ -315,11 +321,11 @@ module Azure
315
321
  hash = blob.to_h.merge(
316
322
  :storage_account => storage_account.to_h,
317
323
  :blob_properties => blob_properties.to_h,
318
- :operating_system => blob_properties.try(:x_ms_meta_microsoftazurecompute_ostype),
324
+ :operating_system => blob_properties[:x_ms_meta_microsoftazurecompute_ostype],
319
325
  :uri => File.join(
320
- storage_account.properties.primary_endpoints.blob,
321
- blob.container,
322
- blob.name
326
+ storage_account.blob_endpoint_from_hash,
327
+ blob[:container],
328
+ blob.name_from_hash
323
329
  )
324
330
  )
325
331
 
@@ -329,11 +335,11 @@ module Azure
329
335
  # Get the key for the given +storage_acct+ using the appropriate method
330
336
  # depending on the api-version.
331
337
  #
332
- def get_account_key(storage_acct)
338
+ def get_account_key(storage_acct, skip_accessors_definition = false)
333
339
  if recent_api_version?
334
- list_account_key_objects(storage_acct.name, storage_acct.resource_group).first.key
340
+ list_account_key_objects(storage_acct.name_from_hash, storage_acct.resource_group, skip_accessors_definition).first.key
335
341
  else
336
- list_account_keys(storage_acct.name, storage_acct.resource_group).fetch('key1')
342
+ list_account_keys(storage_acct.name_from_hash, storage_acct.resource_group).fetch('key1')
337
343
  end
338
344
  end
339
345
 
@@ -1,6 +1,6 @@
1
1
  module Azure
2
2
  module Armrest
3
3
  # The version of the azure-armrest library.
4
- VERSION = '0.8.4'.freeze
4
+ VERSION = '0.8.5'.freeze
5
5
  end
6
6
  end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: azure-armrest
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.8.4
4
+ version: 0.8.5
5
5
  platform: ruby
6
6
  authors:
7
7
  - Daniel J. Berger
@@ -11,7 +11,7 @@ authors:
11
11
  autorequire:
12
12
  bindir: bin
13
13
  cert_chain: []
14
- date: 2017-10-02 00:00:00.000000000 Z
14
+ date: 2017-10-10 00:00:00.000000000 Z
15
15
  dependencies:
16
16
  - !ruby/object:Gem::Dependency
17
17
  name: json
@@ -302,7 +302,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
302
302
  version: '0'
303
303
  requirements: []
304
304
  rubyforge_project:
305
- rubygems_version: 2.6.11
305
+ rubygems_version: 2.6.14
306
306
  signing_key:
307
307
  specification_version: 4
308
308
  summary: An interface for ARM/JSON Azure REST API