azure-armrest 0.3.11 → 0.3.12

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 374a82fa5abab25e86c1d55475f91cbcd51f0606
4
- data.tar.gz: 8fb3f44d22dbe3f8d4697c74205d671e04c7be96
3
+ metadata.gz: 5022f64bbe2cfc12d269a9b1ef34eda423076aff
4
+ data.tar.gz: 86f456d2c2e7eb2724599da6d2239f3dc1839e7b
5
5
  SHA512:
6
- metadata.gz: 67130daca26bbfc9b629dd256f65a92412eaebe7b59a832a4f80b032ae0622052c4979640631458609fb466aac204e1f0f678184d5ed13e2e45a69085b885b9d
7
- data.tar.gz: 2539f429201b3d24ad4703bab06b4e7112125dba85aa29a047ab6c1d0843a9a13eaf2ff229b9850ff34695d6b7412c694d3d63bf36d2f493dcff7c4b7ccada96
6
+ metadata.gz: 516af488cfffe832df8e468c19201ab59253130023d0eddc1c0bba2dbe6ddb269b51ff781f5218c6090a37450d8d057f5ccf0083b737941c2830e67988a32f2b
7
+ data.tar.gz: 2ef615e16a7809c5418becdcf17439c9303a3f05119c2a26925319ba16194f028e7599537fb4c940b6a29d0b3833e24a89e05d2aff67fb09f11ae58c978fd16e
data/CHANGES CHANGED
@@ -1,3 +1,12 @@
1
+ = 0.3.12 - 15-Nov-2016
2
+ * Added the Insights::DiagnosticService class.
3
+ * Added the get_from_vm and get_os_disk methods to StorageAccountService.
4
+ * Added the delete_associated_resources method to VirtualMachineService.
5
+ * The output of StorageAccount#blob_properties method now includes the blob
6
+ name and the container name.
7
+ * Added a service_name accessor to the ArmrestService base class.
8
+ * The list_all method in StorageAccountService now supports a filter.
9
+
1
10
  = 0.3.11 - 8-Nov-2016
2
11
  * Fixed the regex for the internal method parse_id_string, making the
3
12
  get_associated_resource method more robust.
data/lib/azure/armrest.rb CHANGED
@@ -39,6 +39,7 @@ require 'azure/armrest/resource_service'
39
39
  require 'azure/armrest/resource_group_service'
40
40
  require 'azure/armrest/resource_provider_service'
41
41
  require 'azure/armrest/insights/alert_service'
42
+ require 'azure/armrest/insights/diagnostic_service'
42
43
  require 'azure/armrest/insights/event_service'
43
44
  require 'azure/armrest/insights/metrics_service'
44
45
  require 'azure/armrest/network/load_balancer_service'
@@ -18,6 +18,9 @@ module Azure
18
18
  # Provider for service specific API calls
19
19
  attr_accessor :provider
20
20
 
21
+ # The service name for the Service class
22
+ attr_accessor :service_name
23
+
21
24
  # The api-version string for this particular service
22
25
  attr_accessor :api_version
23
26
 
@@ -0,0 +1,96 @@
1
+ module Azure
2
+ module Armrest
3
+ module Insights
4
+ # Base class for managing diagnostics
5
+ class DiagnosticService < ArmrestService
6
+ def initialize(armrest_configuration, options = {})
7
+ super(armrest_configuration, 'diagnosticSettings', 'Microsoft.Insights', options)
8
+ end
9
+
10
+ # Get diagnostic information for the given +resource_id+. Note that
11
+ # this information is only available for a limited subset of resources.
12
+ #
13
+ # Example:
14
+ #
15
+ # ids = Azure::Armrest::Insights::DiagnosticService.new(config)
16
+ # nsg = Azure::Armrest::Network::NetworkSecurityGroupService.new(config)
17
+ #
18
+ # sgrp = nsg.get(your_security_group, your_resource_group)
19
+ # p ids.get(sgrp.id)
20
+ #
21
+ def get(resource_id)
22
+ url = build_url(resource_id)
23
+ response = rest_get(url)
24
+ Diagnostic.new(JSON.parse(response))
25
+ end
26
+
27
+ # Create or update a diagnostic setting for the given +resource_id+.
28
+ #
29
+ # Example:
30
+ #
31
+ # # Update network security group log settings
32
+ # ids = Azure::Armrest::Insights::DiagnosticService.new(config)
33
+ # sas = Azure::Armrest::StorageAccountService.new(config)
34
+ # nsg = Azure::Armrest::Network::NetworkSecurityGroupService.new(config)
35
+ #
36
+ # acct = sas.get(your_storage, your_resource_group)
37
+ # sgrp = nsg.get(your_network_security_group, your_resource_group)
38
+ #
39
+ # options = {
40
+ # :properties => {
41
+ # :storageAccountId => acct.id,
42
+ # :logs => [
43
+ # {
44
+ # :category => "NetworkSecurityGroupEvent",
45
+ # :enabled => true,
46
+ # :retentionPolicy => {
47
+ # :enabled => true,
48
+ # :days => 3
49
+ # }
50
+ # },
51
+ # {
52
+ # :category => "NetworkSecurityGroupRuleCounter",
53
+ # :enabled => true,
54
+ # :retentionPolicy => {
55
+ # :enabled => true,
56
+ # :days => 3
57
+ # }
58
+ # }
59
+ # ]
60
+ # }
61
+ # }
62
+ #
63
+ # ids.set(sgrp.id, options)
64
+ #
65
+ def create(resource_id, options = {})
66
+ url = build_url(resource_id)
67
+ body = options.merge(:id => resource_id).to_json
68
+ response = rest_put(url, body)
69
+
70
+ headers = Azure::Armrest::ResponseHeaders.new(response.headers)
71
+ headers.response_code = response.code
72
+
73
+ headers
74
+ end
75
+
76
+ alias update create
77
+ alias set create
78
+
79
+ private
80
+
81
+ def build_url(resource_id)
82
+ url = File.join(
83
+ Azure::Armrest::RESOURCE,
84
+ resource_id,
85
+ 'providers',
86
+ provider,
87
+ 'diagnosticSettings',
88
+ 'service'
89
+ )
90
+
91
+ url + "?api-version=#{api_version}"
92
+ end
93
+ end
94
+ end
95
+ end
96
+ end
@@ -218,6 +218,7 @@ module Azure
218
218
 
219
219
  module Insights
220
220
  class Alert < BaseModel; end
221
+ class Diagnostic < BaseModel; end
221
222
  class Event < BaseModel; end
222
223
  class Metric < BaseModel; end
223
224
  end
@@ -214,7 +214,7 @@ module Azure
214
214
  :ssl_verify => ssl_verify
215
215
  )
216
216
 
217
- BlobProperty.new(response.headers)
217
+ BlobProperty.new(response.headers.merge(:container => container, :name => blob))
218
218
  end
219
219
 
220
220
  # Return a list of blobs for the given +container+ using the given +key+
@@ -32,8 +32,8 @@ module Azure
32
32
 
33
33
  # Same as other resource based list_all methods, but also sets the proxy on each model object.
34
34
  #
35
- def list_all
36
- super.each do |m|
35
+ def list_all(filter = {})
36
+ super(filter).each do |m|
37
37
  m.proxy = configuration.proxy
38
38
  m.ssl_version = configuration.ssl_version
39
39
  m.ssl_verify = configuration.ssl_verify
@@ -203,6 +203,43 @@ module Azure
203
203
  get_private_images(storage_accounts)
204
204
  end
205
205
 
206
+ # Return the storage account for the virtual machine model +vm+.
207
+ #
208
+ def get_from_vm(vm)
209
+ uri = Addressable::URI.parse(vm.properties.storage_profile.os_disk.vhd.uri)
210
+
211
+ # The uri looks like https://foo123.blob.core.windows.net/vhds/something123.vhd
212
+ name = uri.host.split('.').first # storage name, e.g. 'foo123'
213
+
214
+ # Look for the storage account in the VM's resource group first. If
215
+ # it's not found, look through all the storage accounts.
216
+ begin
217
+ acct = get(name, vm.resource_group)
218
+ rescue Azure::Armrest::NotFoundException => err
219
+ acct = list_all(:name => name).first
220
+ raise err unless acct
221
+ end
222
+
223
+ acct
224
+ end
225
+
226
+ # Get information for the underlying VHD file based on the properties
227
+ # of the virtual machine model +vm+.
228
+ #
229
+ def get_os_disk(vm)
230
+ uri = Addressable::URI.parse(vm.properties.storage_profile.os_disk.vhd.uri)
231
+
232
+ # The uri looks like https://foo123.blob.core.windows.net/vhds/something123.vhd
233
+ disk = File.basename(uri.to_s) # disk name, e.g. 'something123.vhd'
234
+ path = File.dirname(uri.path)[1..-1] # container, e.g. 'vhds'
235
+
236
+ acct = get_from_vm(vm)
237
+ keys = list_account_keys(acct.name, acct.resource_group)
238
+ key = keys['key1'] || keys['key2']
239
+
240
+ acct.blob_properties(path, disk, key)
241
+ end
242
+
206
243
  def accounts_by_name
207
244
  @accounts_by_name ||= list_all.each_with_object({}) { |sa, sah| sah[sa.name] = sa }
208
245
  end
@@ -1,5 +1,5 @@
1
1
  module Azure
2
2
  module Armrest
3
- VERSION = '0.3.11'.freeze
3
+ VERSION = '0.3.12'.freeze
4
4
  end
5
5
  end
@@ -121,12 +121,173 @@ module Azure
121
121
  vm_operate('powerOff', vmname, group)
122
122
  end
123
123
 
124
+ # Delete the VM and associated resources. By default, this will
125
+ # delete the VM, its NIC, the associated IP address, and the
126
+ # image files (.vhd and .status) for the VM.
127
+ #
128
+ # If you want to delete other associated resources, such as any
129
+ # attached disks, the VM's underlying storage account, or associated
130
+ # network security groups you must explicitly specify them as an option.
131
+ #
132
+ # An attempt to delete a resource that cannot be deleted because it's
133
+ # still associated with some other resource will be logged and skipped.
134
+ #
135
+ # If the :verbose option is set to true, then additional messages are
136
+ # sent to your configuration log, or stdout if no log was specified.
137
+ #
138
+ # Note that if all of your related resources are in a self-contained
139
+ # resource group, you do not necessarily need this method. You could
140
+ # just delete the resource group itself, which would automatically
141
+ # delete all of its resources.
142
+ #
143
+ def delete_associated_resources(vmname, vmgroup, options = {})
144
+ options = {
145
+ :network_interfaces => true,
146
+ :ip_addresses => true,
147
+ :os_disk => true,
148
+ :network_security_groups => false,
149
+ :storage_account => false,
150
+ :verbose => false
151
+ }.merge(options)
152
+
153
+ Azure::Armrest::Configuration.log ||= STDOUT if options[:verbose]
154
+
155
+ vm = get(vmname, vmgroup)
156
+
157
+ delete_and_wait(self, vmname, vmgroup, options)
158
+
159
+ # Must delete network interfaces first if you want to delete
160
+ # IP addresses or network security groups.
161
+ if options[:network_interfaces] || options[:ip_addresses] || options[:network_security_groups]
162
+ delete_associated_nics(vm, options)
163
+ end
164
+
165
+ if options[:os_disk] || options[:storage_account]
166
+ delete_associated_disk(vm, options)
167
+ end
168
+ end
169
+
124
170
  def model_class
125
171
  VirtualMachineModel
126
172
  end
127
173
 
128
174
  private
129
175
 
176
+ # Deletes any NIC's associated with the VM, and optionally any public IP addresses
177
+ # and network security groups.
178
+ #
179
+ def delete_associated_nics(vm, options)
180
+ nis = Azure::Armrest::Network::NetworkInterfaceService.new(configuration)
181
+ nics = vm.properties.network_profile.network_interfaces.map(&:id)
182
+
183
+ if options[:ip_addresses]
184
+ ips = Azure::Armrest::Network::IpAddressService.new(configuration)
185
+ end
186
+
187
+ if options[:network_security_groups]
188
+ nsgs = Azure::Armrest::Network::NetworkSecurityGroupService.new(configuration)
189
+ end
190
+
191
+ nics.each do |nic_id_string|
192
+ nic = get_associated_resource(nic_id_string)
193
+ delete_and_wait(nis, nic.name, nic.resource_group, options)
194
+
195
+ if options[:ip_addresses]
196
+ nic.properties.ip_configurations.each do |ip|
197
+ ip = get_associated_resource(ip.properties.public_ip_address.id)
198
+ delete_and_wait(ips, ip.name, ip.resource_group, options)
199
+ end
200
+ end
201
+
202
+ if options[:network_security_groups]
203
+ nic.properties.network_security_group
204
+ nsg = get_associated_resource(nic.properties.network_security_group.id)
205
+ delete_and_wait(nsgs, nsg.name, nsg.resource_group, options)
206
+ end
207
+ end
208
+ end
209
+
210
+ # This deletes the OS disk from the storage account that's backing the
211
+ # virtual machine, along with the .status file. This does NOT delete
212
+ # copies of the disk.
213
+ #
214
+ # If the option to delete the entire storage account was selected, then
215
+ # it will not bother with deleting invidual files from the storage
216
+ # account first.
217
+ #
218
+ def delete_associated_disk(vm, options)
219
+ sas = Azure::Armrest::StorageAccountService.new(configuration)
220
+
221
+ storage_account = sas.get_from_vm(vm)
222
+
223
+ # Deleting the storage account does not require deleting the disks
224
+ # first, so skip that if deletion of the storage account was requested.
225
+ if options[:storage_account]
226
+ delete_and_wait(sas, storage_account.name, storage_account.resource_group, options)
227
+ else
228
+ keys = sas.list_account_keys(storage_account.name, storage_account.resource_group)
229
+ key = keys['key1'] || keys['key2']
230
+ disk = sas.get_os_disk(vm)
231
+
232
+ # There's a short delay between deleting the VM and unlocking the underlying
233
+ # .vhd file by Azure. Therefore we sleep up to two minutes while checking.
234
+ if disk.x_ms_lease_status.casecmp('unlocked') != 0
235
+ sleep_time = 0
236
+
237
+ while sleep_time < 120
238
+ sleep 10
239
+ sleep_time += 10
240
+ disk = sas.get_os_disk(vm)
241
+ break if disk.x_ms_lease_status.casecmp('unlocked') != 0
242
+ end
243
+
244
+ # In the unlikely event it did not unlock, just log and skip.
245
+ if disk.x_ms_lease_status.casecmp('unlocked') != 0
246
+ log_message("Unable to delete disk #{disk.container}/#{disk.name}", 'warn')
247
+ return
248
+ end
249
+ end
250
+
251
+ storage_account.delete_blob(disk.container, disk.name, key)
252
+ log_message("Deleted blob #{disk.container}/#{disk.name}") if options[:verbose]
253
+
254
+ begin
255
+ status_file = File.basename(disk.name, '.vhd') + '.status'
256
+ storage_account.delete_blob(disk.container, status_file, key)
257
+ rescue Azure::Armrest::NotFoundException
258
+ # Ignore, does not always exist.
259
+ else
260
+ log_message("Deleted blob #{disk.container}/#{status_file}") if options[:verbose]
261
+ end
262
+ end
263
+ end
264
+
265
+ # Delete a +service+ type resource using its name and resource group,
266
+ # and wait for the operation to complete before returning.
267
+ #
268
+ # If the operation fails because a dependent resource is still attached,
269
+ # then the error is logged (in verbose mode) and ignored.
270
+ #
271
+ def delete_and_wait(service, name, group, options)
272
+ resource_type = service.class.to_s.sub('Service', '').split('::').last
273
+
274
+ log_message("Deleting #{resource_type} #{name}/#{group}") if options[:verbose]
275
+
276
+ headers = service.delete(name, group)
277
+
278
+ loop do
279
+ status = wait(headers)
280
+ break if status.downcase.start_with?('succ') # Succeeded, Success, etc.
281
+ end
282
+
283
+ log_message("Deleted #{resource_type} #{name}/#{group}") if options[:verbose]
284
+ rescue Azure::Armrest::BadRequestException, Azure::Armrest::PreconditionFailedException => err
285
+ if options[:verbose]
286
+ msg = "Unable to delete #{resource_type} #{name}/#{group}, skipping. Message: #{err.message}"
287
+ log_message(msg, 'warn')
288
+ end
289
+ end
290
+
130
291
  def vm_operate(action, vmname, group, options = {})
131
292
  raise ArgumentError, "must specify resource group" unless group
132
293
  raise ArgumentError, "must specify name of the vm" unless vmname
@@ -135,6 +296,15 @@ module Azure
135
296
  rest_post(url)
136
297
  nil
137
298
  end
299
+
300
+ # Simple log messager. Use the Configuration.log if defined.
301
+ def log_message(msg, level = 'info')
302
+ if Azure::Armrest::Configuration.log
303
+ Azure::Armrest::Configuration.log.send(level.to_sym, msg)
304
+ else
305
+ warn msg
306
+ end
307
+ end
138
308
  end
139
309
  end
140
310
  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.3.11
4
+ version: 0.3.12
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: 2016-11-08 00:00:00.000000000 Z
14
+ date: 2016-11-15 00:00:00.000000000 Z
15
15
  dependencies:
16
16
  - !ruby/object:Gem::Dependency
17
17
  name: json
@@ -240,6 +240,7 @@ files:
240
240
  - lib/azure/armrest/configuration.rb
241
241
  - lib/azure/armrest/exception.rb
242
242
  - lib/azure/armrest/insights/alert_service.rb
243
+ - lib/azure/armrest/insights/diagnostic_service.rb
243
244
  - lib/azure/armrest/insights/event_service.rb
244
245
  - lib/azure/armrest/insights/metrics_service.rb
245
246
  - lib/azure/armrest/model/base_model.rb