azure-armrest 0.3.11 → 0.3.12
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 +4 -4
- data/CHANGES +9 -0
- data/lib/azure/armrest.rb +1 -0
- data/lib/azure/armrest/armrest_service.rb +3 -0
- data/lib/azure/armrest/insights/diagnostic_service.rb +96 -0
- data/lib/azure/armrest/model/base_model.rb +1 -0
- data/lib/azure/armrest/model/storage_account.rb +1 -1
- data/lib/azure/armrest/storage_account_service.rb +39 -2
- data/lib/azure/armrest/version.rb +1 -1
- data/lib/azure/armrest/virtual_machine_service.rb +170 -0
- metadata +3 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 5022f64bbe2cfc12d269a9b1ef34eda423076aff
|
4
|
+
data.tar.gz: 86f456d2c2e7eb2724599da6d2239f3dc1839e7b
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
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'
|
@@ -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
|
@@ -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
|
@@ -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.
|
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-
|
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
|