azurex 0.6.6 → 0.6.7
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/.gitignore +3 -1
- data/Gemfile +1 -1
- data/README.md +2 -0
- data/lib/azure.rb +3 -0
- data/lib/azure/base_management/management_http_request.rb +3 -3
- data/lib/azure/cloud_service_management/cloud_service_management_service.rb +1 -9
- data/lib/azure/core/utility.rb +0 -71
- data/lib/azure/storage_management/serialization.rb +9 -12
- data/lib/azure/storage_management/storage_account.rb +1 -0
- data/lib/azure/storage_management/storage_management_service.rb +15 -18
- data/lib/azure/version.rb +1 -1
- data/lib/azure/virtual_machine_image_management/serialization.rb +15 -1
- data/lib/azure/virtual_machine_image_management/virtual_machine_image_management_service.rb +31 -2
- data/lib/azure/virtual_machine_management/serialization.rb +1 -1
- data/lib/azure/virtual_machine_management/virtual_machine_management_service.rb +4 -4
- data/lib/core_ext/ip_addr.rb +48 -0
- data/lib/core_ext/string.rb +27 -0
- data/test/fixtures/get_storage_account_properties.xml +6 -4
- data/test/fixtures/list_storage_accounts.xml +2 -0
- data/test/fixtures/list_vmimages.xml +86 -0
- data/test/fixtures/updated_storage_accounts.xml +2 -0
- data/test/integration/affinity_group/Create_Affinity_test.rb +1 -1
- data/test/integration/cloud_service/Cloud_Delete_test.rb +2 -2
- data/test/integration/storage_management/storage_management_test.rb +40 -33
- data/test/integration/vm/VM_Delete_test.rb +1 -1
- data/test/integration/vm_image/virtual_machine_image_test.rb +1 -1
- data/test/unit/cloud_service_management/cloud_service_management_service_test.rb +4 -4
- data/test/unit/core_ext/string_test.rb +11 -0
- data/test/unit/storage_management/serialization_test.rb +12 -13
- data/test/unit/storage_management/storage_management_service_test.rb +26 -40
- data/test/unit/virtual_machine_image_management/serialization_test.rb +17 -1
- data/test/unit/virtual_machine_image_management/virtual_machine_image_management_service_test.rb +113 -8
- data/test/unit/virtual_machine_management/virtual_machine_management_service_test.rb +17 -0
- metadata +6 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 97ea989a0ffca5af37573d3c744b46a0f104d820
|
4
|
+
data.tar.gz: fc1a69389027cb0816ddcce59acdbcdebc797f3a
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: b205dad74df5dd56dae98fcc09dfea3026cfa050681d8719f935296e09a4d538c50d04b35b792927b631cd6f8bb47bb33b5b72161fd5bb72d53e097e2c0947e3
|
7
|
+
data.tar.gz: d6156443d72df0cb806a23d57a82eb8f7fea63d7ed9f7b47d97bd5d4fa0e2b363ebffffe561f56bb3b83bd9783b98a5c371e2ea8b3ce700e43a0e2e6192a65f9
|
data/.gitignore
CHANGED
data/Gemfile
CHANGED
data/README.md
CHANGED
@@ -9,6 +9,8 @@ This repo has the following enhancements over the original:
|
|
9
9
|
* Provision VMs from custom images
|
10
10
|
* More webhooks for cloud services
|
11
11
|
* Access more attributes from virtual machines
|
12
|
+
* CustomData for virtual machines
|
13
|
+
* Support for the A8, A9 and 'D' series VM sizes
|
12
14
|
|
13
15
|
There are three goals for this repo:
|
14
16
|
|
data/lib/azure.rb
CHANGED
@@ -14,6 +14,7 @@
|
|
14
14
|
#--------------------------------------------------------------------------
|
15
15
|
module Azure; end
|
16
16
|
|
17
|
+
# The order that files are required in is important...
|
17
18
|
require 'azure/core'
|
18
19
|
require 'azure/blob/blob_service'
|
19
20
|
require 'azure/queue/queue_service'
|
@@ -37,6 +38,8 @@ require 'azure/cloud_service_management/cloud_service_management_service'
|
|
37
38
|
require 'azure/base_management/location'
|
38
39
|
require 'azure/sql_database_management/sql_database_management_service'
|
39
40
|
require 'azure/virtual_network_management/virtual_network_management_service'
|
41
|
+
require 'core_ext/string'
|
42
|
+
require 'core_ext/ip_addr'
|
40
43
|
|
41
44
|
# add some aliases for convenience
|
42
45
|
Azure::BlobService = Azure::Blob::BlobService
|
@@ -35,7 +35,7 @@ module Azure
|
|
35
35
|
@warn = false
|
36
36
|
content_length = body ? body.bytesize.to_s : '0'
|
37
37
|
@headers = {
|
38
|
-
'x-ms-version' => '2014-
|
38
|
+
'x-ms-version' => '2014-06-01',
|
39
39
|
'Content-Type' => 'application/xml',
|
40
40
|
'Content-Length' => content_length
|
41
41
|
}
|
@@ -156,7 +156,7 @@ module Azure
|
|
156
156
|
#
|
157
157
|
# * +request_id+ - String. x-ms-request-id response header of request
|
158
158
|
#
|
159
|
-
# See: http://msdn.microsoft.com/en-us/library/
|
159
|
+
# See: http://msdn.microsoft.com/en-us/library/azure/ee460783.aspx
|
160
160
|
#
|
161
161
|
# Print Error or Success of Operation.
|
162
162
|
def check_completion(request_id)
|
@@ -241,4 +241,4 @@ module Azure
|
|
241
241
|
end
|
242
242
|
end
|
243
243
|
end
|
244
|
-
end
|
244
|
+
end
|
@@ -297,15 +297,7 @@ module Azure
|
|
297
297
|
# If true, the cloud service is available. If false, the cloud service
|
298
298
|
# does not exist.
|
299
299
|
def get_cloud_service(name)
|
300
|
-
|
301
|
-
flag = false
|
302
|
-
list_cloud_services.each do |cloud_service|
|
303
|
-
if cloud_service.name == name
|
304
|
-
flag = true
|
305
|
-
break
|
306
|
-
end
|
307
|
-
end
|
308
|
-
flag
|
300
|
+
list_cloud_services.select { |x| x.name.casecmp(name) == 0 }.first
|
309
301
|
end
|
310
302
|
|
311
303
|
def get_cloud_service_properties(name)
|
data/lib/azure/core/utility.rb
CHANGED
@@ -117,74 +117,3 @@ module Azure
|
|
117
117
|
end
|
118
118
|
end
|
119
119
|
|
120
|
-
class String
|
121
|
-
{ reset: 0,
|
122
|
-
bold: 1,
|
123
|
-
dark: 2,
|
124
|
-
underline: 4,
|
125
|
-
blink: 5,
|
126
|
-
orange: 6,
|
127
|
-
negative: 7,
|
128
|
-
black: 30,
|
129
|
-
red: 31,
|
130
|
-
green: 32,
|
131
|
-
yellow: 33,
|
132
|
-
blue: 34,
|
133
|
-
magenta: 35,
|
134
|
-
cyan: 36,
|
135
|
-
white: 37,
|
136
|
-
}.each do |key, value|
|
137
|
-
define_method key do
|
138
|
-
"\e[#{value}m" + self + "\e[0m"
|
139
|
-
end
|
140
|
-
end
|
141
|
-
end
|
142
|
-
|
143
|
-
# Code validate private/public IP acceptable ranges.
|
144
|
-
class IPAddr
|
145
|
-
PRIVATE_RANGES = [
|
146
|
-
IPAddr.new('10.0.0.0/8'),
|
147
|
-
IPAddr.new('172.16.0.0/12'),
|
148
|
-
IPAddr.new('192.168.0.0/16')
|
149
|
-
]
|
150
|
-
|
151
|
-
def private?
|
152
|
-
return false unless self.ipv4?
|
153
|
-
PRIVATE_RANGES.each do |ipr|
|
154
|
-
return true if ipr.include?(self)
|
155
|
-
end
|
156
|
-
false
|
157
|
-
end
|
158
|
-
|
159
|
-
def public?
|
160
|
-
!private?
|
161
|
-
end
|
162
|
-
|
163
|
-
class << self
|
164
|
-
def validate_ip_and_prefix(ip, cidr)
|
165
|
-
if cidr.to_s.empty?
|
166
|
-
raise "Cidr is missing for IP '#{ip}'."
|
167
|
-
elsif valid?(ip)
|
168
|
-
raise "Ip address '#{ip}' is invalid."
|
169
|
-
elsif !IPAddr.new(ip).private?
|
170
|
-
raise "Ip Address #{ip} must be private."
|
171
|
-
end
|
172
|
-
end
|
173
|
-
|
174
|
-
def validate_address_space(ip)
|
175
|
-
if ip.split('/').size != 2
|
176
|
-
raise "Cidr is invalid for IP #{ip}."
|
177
|
-
elsif valid?(ip)
|
178
|
-
raise "Address space '#{ip}' is invalid."
|
179
|
-
end
|
180
|
-
end
|
181
|
-
|
182
|
-
def address_prefix(ip, cidr)
|
183
|
-
ip + '/' + cidr.to_s
|
184
|
-
end
|
185
|
-
|
186
|
-
def valid?(ip)
|
187
|
-
(IPAddr.new(ip) rescue nil).nil?
|
188
|
-
end
|
189
|
-
end
|
190
|
-
end
|
@@ -51,11 +51,9 @@ module Azure
|
|
51
51
|
storage_account.name = xml_content(
|
52
52
|
storage_service_xml, 'ServiceName'
|
53
53
|
)
|
54
|
-
|
55
54
|
storage_service_properties = storage_service_xml.css(
|
56
55
|
'StorageServiceProperties'
|
57
56
|
)
|
58
|
-
|
59
57
|
storage_account.description = xml_content(
|
60
58
|
storage_service_properties, 'Description'
|
61
59
|
)
|
@@ -77,6 +75,9 @@ module Azure
|
|
77
75
|
storage_account.geo_replication_enabled = xml_content(
|
78
76
|
storage_service_properties, 'GeoReplicationEnabled'
|
79
77
|
)
|
78
|
+
storage_account.account_type = xml_content(
|
79
|
+
storage_service_properties, 'AccountType'
|
80
|
+
)
|
80
81
|
storage_account.geo_primary_region = xml_content(
|
81
82
|
storage_service_properties, 'GeoPrimaryRegion'
|
82
83
|
)
|
@@ -112,7 +113,7 @@ module Azure
|
|
112
113
|
|
113
114
|
def self.storage_update_to_xml(options)
|
114
115
|
# Cannot update if options is nil or empty
|
115
|
-
fail 'No options specified' if options.
|
116
|
+
fail 'No options specified' if options.empty?
|
116
117
|
|
117
118
|
# Either one of Label, or Description is required.
|
118
119
|
if (options[:label].nil? || options[:label].empty?) &&
|
@@ -129,15 +130,13 @@ module Azure
|
|
129
130
|
when :description, :label
|
130
131
|
is_empty = value.nil? || value.empty?
|
131
132
|
when :geo_replication_enabled
|
132
|
-
is_empty = !(value.
|
133
|
-
|| value.kind_of?(FalseClass))
|
133
|
+
is_empty = !(value.is_a?(TrueClass) || value.is_a?(FalseClass))
|
134
134
|
when :extended_properties
|
135
135
|
value.each do |p, v|
|
136
136
|
is_empty = ((p.nil? || p.empty?) || (v.nil? || v.empty?))
|
137
137
|
break unless is_empty
|
138
138
|
end
|
139
139
|
end
|
140
|
-
|
141
140
|
break unless is_empty
|
142
141
|
end
|
143
142
|
|
@@ -166,18 +165,16 @@ module Azure
|
|
166
165
|
gre = options[:geo_replication_enabled]
|
167
166
|
xml.GeoReplicationEnabled(
|
168
167
|
gre
|
169
|
-
) unless gre.nil
|
170
|
-
|| !(gre.kind_of?(TrueClass) || gre.kind_of?(FalseClass))
|
168
|
+
) unless gre.nil? || !(gre.is_a?(TrueClass) || gre.is_a?(FalseClass))
|
171
169
|
xml.ExtendedProperties do
|
172
170
|
options[:extended_properties].each do |name, value|
|
173
171
|
xml.ExtendedProperty do
|
174
172
|
xml.Name name
|
175
173
|
xml.Value value
|
176
|
-
end unless (name.
|
177
|
-
|| (value.nil? || value.empty?)
|
174
|
+
end unless (name.to_s.empty?) || (value.to_s.empty?)
|
178
175
|
end
|
179
|
-
end unless options[:extended_properties].
|
180
|
-
|
176
|
+
end unless options[:extended_properties].to_s.empty?
|
177
|
+
xml.AccountType options[:account_type] if options[:account_type]
|
181
178
|
end
|
182
179
|
|
183
180
|
def self.storage_account_keys_from_xml(storage_xml)
|
@@ -38,20 +38,9 @@ module Azure
|
|
38
38
|
#
|
39
39
|
# * +name+ - String. Storage account name.
|
40
40
|
#
|
41
|
-
# Returns
|
42
|
-
# If true, the storage account exists. If false, the storage account
|
43
|
-
# does not exist.
|
41
|
+
# Returns an Azure::StorageManagement::StorageAccount instance
|
44
42
|
def get_storage_account(name)
|
45
|
-
|
46
|
-
flag = false
|
47
|
-
storage_accounts = list_storage_accounts
|
48
|
-
storage_accounts.each do |storage|
|
49
|
-
if storage.name == name
|
50
|
-
flag = true
|
51
|
-
break
|
52
|
-
end
|
53
|
-
end
|
54
|
-
flag
|
43
|
+
list_storage_accounts.select { |x| x.name.casecmp(name) == 0 }.first
|
55
44
|
end
|
56
45
|
|
57
46
|
# Public: Gets the properties of the storage account specified.
|
@@ -94,10 +83,14 @@ module Azure
|
|
94
83
|
# * +:extended_properties+ - Hash. Key/Value pairs of extended
|
95
84
|
# properties to add to the storage account. The key is used as the
|
96
85
|
# property name and the value as its value. (optional)
|
86
|
+
# * +:account_type+ - String. Specifies the type of storage account
|
97
87
|
#
|
88
|
+
# See http://msdn.microsoft.com/en-us/library/azure/hh264518.aspx
|
89
|
+
#
|
98
90
|
# Returns None
|
99
91
|
def create_storage_account(name, options = {})
|
100
92
|
raise 'Name not specified' if !name || name.class != String || name.empty?
|
93
|
+
options[:account_type] ||= 'Standard_GRS'
|
101
94
|
if get_storage_account(name)
|
102
95
|
Loggerx.warn "Storage Account #{name} already exists. Skipped..."
|
103
96
|
else
|
@@ -114,7 +107,7 @@ module Azure
|
|
114
107
|
# ==== Attributes
|
115
108
|
#
|
116
109
|
# * +name+ - String. The name of the storage service.
|
117
|
-
# * +options+ - Hash.
|
110
|
+
# * +options+ - Hash. parameters.
|
118
111
|
#
|
119
112
|
# ==== Options
|
120
113
|
#
|
@@ -126,14 +119,17 @@ module Azure
|
|
126
119
|
# Required if no label is provided. If both label and description are
|
127
120
|
# provided, only the label will get updated.
|
128
121
|
# * +:geo_replication_enabled+ - Boolean (TrueClass/FalseClass). Boolean
|
129
|
-
# flag indicating
|
122
|
+
# flag indicating whether to turn Geo replication on or off. (optional)
|
130
123
|
# * +:extended_properties+ - Hash. Key/Value pairs of extended
|
131
124
|
# properties to add to the storage account. The key is used as the
|
132
125
|
# property name and the value as its value. (optional)
|
126
|
+
# * +:account_type+ - String. Specifies the type of storage account
|
127
|
+
#
|
128
|
+
# See http://msdn.microsoft.com/en-us/library/azure/hh264516.aspx
|
133
129
|
#
|
134
130
|
# Returns None
|
135
131
|
# Fails with RuntimeError if invalid options specified
|
136
|
-
def update_storage_account(name, options
|
132
|
+
def update_storage_account(name, options)
|
137
133
|
if get_storage_account name
|
138
134
|
Loggerx.info "Account '#{name}' exists, updating..."
|
139
135
|
body = Serialization.storage_update_to_xml options
|
@@ -152,13 +148,15 @@ module Azure
|
|
152
148
|
#
|
153
149
|
# * +name+ - String. Storage account name.
|
154
150
|
#
|
151
|
+
# See http://msdn.microsoft.com/en-us/library/azure/hh264517.aspx
|
152
|
+
#
|
155
153
|
# Returns: None
|
156
154
|
def delete_storage_account(name)
|
157
155
|
Loggerx.info "Deleting Storage Account #{name}."
|
158
156
|
request_path = "/services/storageservices/#{name}"
|
159
157
|
request = ManagementHttpRequest.new(:delete, request_path)
|
160
158
|
request.call
|
161
|
-
rescue
|
159
|
+
rescue => e
|
162
160
|
e.message
|
163
161
|
end
|
164
162
|
|
@@ -205,7 +203,6 @@ module Azure
|
|
205
203
|
Loggerx.warn "Storage Account '#{name}' does not exist."
|
206
204
|
end
|
207
205
|
end
|
208
|
-
|
209
206
|
end
|
210
207
|
end
|
211
208
|
end
|
data/lib/azure/version.rb
CHANGED
@@ -33,13 +33,27 @@ module Azure
|
|
33
33
|
os_images
|
34
34
|
end
|
35
35
|
|
36
|
+
def self.virtual_machine_vmimages_from_xml(imageXML)
|
37
|
+
os_images = []
|
38
|
+
virtual_machine_images = imageXML.css('VMImages VMImage')
|
39
|
+
virtual_machine_images.each do |image_node|
|
40
|
+
image = VirtualMachineImage.new
|
41
|
+
image.os_type = xml_content(image_node, 'OS')
|
42
|
+
image.name = xml_content(image_node, 'Name')
|
43
|
+
image.category = xml_content(image_node, 'Category')
|
44
|
+
image.locations = xml_content(image_node, 'Location')
|
45
|
+
os_images << image
|
46
|
+
end
|
47
|
+
os_images
|
48
|
+
end
|
49
|
+
|
36
50
|
def self.disks_from_xml(diskXML)
|
37
51
|
os_disks = []
|
38
52
|
disks = diskXML.css('Disks Disk')
|
39
53
|
disks.each do |disk_node|
|
40
54
|
disk = VirtualMachineDisk.new
|
41
55
|
disk.name = xml_content(disk_node, 'Name')
|
42
|
-
disk.os_type = xml_content(disk_node, 'OS')
|
56
|
+
disk.os_type = xml_content(disk_node, 'OSDiskConfiguration OS')
|
43
57
|
disk.attached = !xml_content(disk_node, 'AttachedTo').empty?
|
44
58
|
disk.image = xml_content(disk_node, 'SourceImageName')
|
45
59
|
disk.size = xml_content(disk_node, 'LogicalDiskSizeInGB')
|
@@ -21,15 +21,44 @@ module Azure
|
|
21
21
|
super()
|
22
22
|
end
|
23
23
|
|
24
|
-
# Public: Gets a list of virtual machine images from the server
|
24
|
+
# Public: Gets a list of all virtual machine images from the server both user created images and public images
|
25
|
+
# @param imageType = :public (public images), :private (user generated images). :all (both types)
|
26
|
+
# Returns an array of Azure::VirtualMachineImageManagementService objects
|
27
|
+
def list_virtual_machine_images(imageType=:all)
|
28
|
+
images = Array.new
|
29
|
+
if imageType == :public or imageType == :all
|
30
|
+
public_images = list_public_virtual_machine_images
|
31
|
+
images.concat public_images
|
32
|
+
end
|
33
|
+
|
34
|
+
if imageType == :private or imageType == :all
|
35
|
+
private_images = list_private_virtual_machine_images
|
36
|
+
images.concat private_images
|
37
|
+
end
|
38
|
+
|
39
|
+
images
|
40
|
+
end
|
41
|
+
|
42
|
+
# Public: Gets a list of virtual machine images from the server returns both user generated and public images by default
|
25
43
|
#
|
26
44
|
# Returns an array of Azure::VirtualMachineImageManagementService objects
|
27
|
-
def
|
45
|
+
def list_public_virtual_machine_images
|
28
46
|
request_path = '/services/images'
|
29
47
|
request = ManagementHttpRequest.new(:get, request_path, nil)
|
30
48
|
response = request.call
|
31
49
|
Serialization.virtual_machine_images_from_xml(response)
|
32
50
|
end
|
51
|
+
|
52
|
+
# Public: Gets a list of private virtual machine images from the server
|
53
|
+
#
|
54
|
+
# Returns an array of Azure::VirtualMachineImageManagementService objects
|
55
|
+
def list_private_virtual_machine_images
|
56
|
+
request_path = '/services/vmimages'
|
57
|
+
request = ManagementHttpRequest.new(:get, request_path, nil)
|
58
|
+
response = request.call
|
59
|
+
Serialization.virtual_machine_vmimages_from_xml(response)
|
60
|
+
end
|
61
|
+
|
33
62
|
end
|
34
63
|
|
35
64
|
class VirtualMachineDiskManagementService < BaseManagementService
|
@@ -183,7 +183,7 @@ module Azure
|
|
183
183
|
def self.add_custom_data(xml, options)
|
184
184
|
if options[:custom_data]
|
185
185
|
custom_data = options[:custom_data]
|
186
|
-
unless custom_data.
|
186
|
+
unless custom_data.resembles_base64?
|
187
187
|
custom_data = Base64.encode64(custom_data)
|
188
188
|
end
|
189
189
|
xml.CustomData custom_data
|
@@ -112,7 +112,7 @@ module Azure
|
|
112
112
|
validate_deployment_params(params, options)
|
113
113
|
options[:deployment_name] ||= options[:cloud_service_name]
|
114
114
|
Loggerx.info 'Creating deploymnent...'
|
115
|
-
options[:cloud_service_name] ||= generate_cloud_service_name(params[:vm_name])
|
115
|
+
options[:cloud_service_name] ||= generate_cloud_service_name(params[:vm_name])
|
116
116
|
optionals = {}
|
117
117
|
if options[:virtual_network_name]
|
118
118
|
virtual_network_service = Azure::VirtualNetworkManagementService.new
|
@@ -122,7 +122,7 @@ module Azure
|
|
122
122
|
else
|
123
123
|
vnet = virtual_networks.first
|
124
124
|
if !vnet.affinity_group.empty?
|
125
|
-
|
125
|
+
optionals[:affinity_group_name] = vnet.affinity_group
|
126
126
|
else
|
127
127
|
optionals[:location] = vnet.location
|
128
128
|
end
|
@@ -543,9 +543,9 @@ module Azure
|
|
543
543
|
end
|
544
544
|
|
545
545
|
def validate_role_size(vm_size)
|
546
|
-
valid_role_sizes = %w(ExtraSmall Small Medium Large ExtraLarge A5 A6 A7 Basic_A0 Basic_A1 Basic_A2 Basic_A3 Basic_A4)
|
546
|
+
valid_role_sizes = %w(ExtraSmall Small Medium Large ExtraLarge A5 A6 A7 A8 A9 Basic_A0 Basic_A1 Basic_A2 Basic_A3 Basic_A4 Standard_D1 Standard_D2 Standard_D3 Standard_D4 Standard_D11 Standard_D12 Standard_D13 Standard_D14)
|
547
547
|
if vm_size && !valid_role_sizes.include?(vm_size)
|
548
|
-
Loggerx.error_with_exit "Value '#{vm_size}' specified for parameter 'vm_size' is invalid. Allowed values are 'ExtraSmall
|
548
|
+
Loggerx.error_with_exit "Value '#{vm_size}' specified for parameter 'vm_size' is invalid. Allowed values are 'ExtraSmall Small Medium Large ExtraLarge A5 A6 A7 A8 A9 Basic_A0 Basic_A1 Basic_A2 Basic_A3 Basic_A4 Standard_D1 Standard_D2 Standard_D3 Standard_D4 Standard_D11 Standard_D12 Standard_D13 Standard_D14'"
|
549
549
|
end
|
550
550
|
end
|
551
551
|
|