azurex 0.6.6 → 0.6.7
Sign up to get free protection for your applications and to get access to all the features.
- 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
|
|