stuartpreston-azure-sdk-for-ruby 0.7.1 → 0.7.2

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.
Files changed (290) hide show
  1. checksums.yaml +4 -4
  2. data/.gitignore +11 -11
  3. data/.travis.yml +10 -10
  4. data/ChangeLog.txt +70 -68
  5. data/Gemfile +15 -15
  6. data/README.md +618 -618
  7. data/Rakefile +133 -133
  8. data/azure.gemspec +44 -44
  9. data/lib/azure.rb +52 -52
  10. data/lib/azure/base_management/affinity_group.rb +32 -32
  11. data/lib/azure/base_management/base_management_service.rb +304 -304
  12. data/lib/azure/base_management/location.rb +27 -27
  13. data/lib/azure/base_management/management_http_request.rb +171 -171
  14. data/lib/azure/base_management/serialization.rb +129 -129
  15. data/lib/azure/base_management/sql_management_http_request.rb +45 -45
  16. data/lib/azure/blob/blob.rb +31 -31
  17. data/lib/azure/blob/blob_service.rb +1423 -1423
  18. data/lib/azure/blob/block.rb +30 -30
  19. data/lib/azure/blob/container.rb +31 -31
  20. data/lib/azure/blob/serialization.rb +284 -284
  21. data/lib/azure/cloud_service_management/cloud_service.rb +38 -38
  22. data/lib/azure/cloud_service_management/cloud_service_management_service.rb +140 -140
  23. data/lib/azure/cloud_service_management/serialization.rb +117 -117
  24. data/lib/azure/core.rb +39 -39
  25. data/lib/azure/core/auth/authorizer.rb +36 -36
  26. data/lib/azure/core/auth/shared_key.rb +110 -110
  27. data/lib/azure/core/auth/shared_key_lite.rb +48 -48
  28. data/lib/azure/core/auth/signer.rb +48 -48
  29. data/lib/azure/core/configuration.rb +211 -211
  30. data/lib/azure/core/error.rb +22 -22
  31. data/lib/azure/core/filtered_service.rb +43 -43
  32. data/lib/azure/core/http/debug_filter.rb +35 -35
  33. data/lib/azure/core/http/http_error.rb +88 -88
  34. data/lib/azure/core/http/http_filter.rb +52 -52
  35. data/lib/azure/core/http/http_request.rb +157 -157
  36. data/lib/azure/core/http/http_response.rb +140 -140
  37. data/lib/azure/core/http/retry_policy.rb +73 -73
  38. data/lib/azure/core/http/signer_filter.rb +33 -33
  39. data/lib/azure/core/service.rb +62 -62
  40. data/lib/azure/core/signed_service.rb +42 -42
  41. data/lib/azure/core/utility.rb +190 -190
  42. data/lib/azure/queue/message.rb +29 -29
  43. data/lib/azure/queue/queue.rb +28 -28
  44. data/lib/azure/queue/queue_service.rb +567 -567
  45. data/lib/azure/queue/serialization.rb +106 -106
  46. data/lib/azure/service/access_policy.rb +25 -25
  47. data/lib/azure/service/cors.rb +11 -11
  48. data/lib/azure/service/cors_rule.rb +15 -15
  49. data/lib/azure/service/enumeration_results.rb +20 -20
  50. data/lib/azure/service/logging.rb +31 -31
  51. data/lib/azure/service/metrics.rb +30 -30
  52. data/lib/azure/service/retention_policy.rb +24 -24
  53. data/lib/azure/service/serialization.rb +297 -297
  54. data/lib/azure/service/signed_identifier.rb +29 -29
  55. data/lib/azure/service/storage_service.rb +82 -82
  56. data/lib/azure/service/storage_service_properties.rb +37 -37
  57. data/lib/azure/service_bus/action.rb +21 -21
  58. data/lib/azure/service_bus/auth/wrap_service.rb +88 -88
  59. data/lib/azure/service_bus/auth/wrap_signer.rb +68 -68
  60. data/lib/azure/service_bus/brokered_message.rb +123 -123
  61. data/lib/azure/service_bus/brokered_message_serializer.rb +159 -159
  62. data/lib/azure/service_bus/correlation_filter.rb +45 -45
  63. data/lib/azure/service_bus/empty_rule_action.rb +29 -29
  64. data/lib/azure/service_bus/false_filter.rb +38 -38
  65. data/lib/azure/service_bus/filter.rb +21 -21
  66. data/lib/azure/service_bus/interval.rb +103 -103
  67. data/lib/azure/service_bus/queue.rb +229 -229
  68. data/lib/azure/service_bus/relay.rb +87 -87
  69. data/lib/azure/service_bus/resource.rb +108 -108
  70. data/lib/azure/service_bus/rule.rb +97 -97
  71. data/lib/azure/service_bus/rule_aspect.rb +34 -34
  72. data/lib/azure/service_bus/serialization.rb +161 -161
  73. data/lib/azure/service_bus/service_bus_service.rb +896 -896
  74. data/lib/azure/service_bus/sql_filter.rb +50 -50
  75. data/lib/azure/service_bus/sql_rule_action.rb +50 -50
  76. data/lib/azure/service_bus/subscription.rb +183 -183
  77. data/lib/azure/service_bus/topic.rb +186 -186
  78. data/lib/azure/service_bus/true_filter.rb +38 -38
  79. data/lib/azure/sql_database_management/serialization.rb +111 -111
  80. data/lib/azure/sql_database_management/sql_database.rb +31 -31
  81. data/lib/azure/sql_database_management/sql_database_management_service.rb +200 -200
  82. data/lib/azure/storage_management/serialization.rb +184 -184
  83. data/lib/azure/storage_management/storage_account.rb +40 -40
  84. data/lib/azure/storage_management/storage_management_service.rb +166 -166
  85. data/lib/azure/table/auth/shared_key.rb +92 -92
  86. data/lib/azure/table/auth/shared_key_lite.rb +44 -44
  87. data/lib/azure/table/batch.rb +329 -329
  88. data/lib/azure/table/batch_response.rb +118 -118
  89. data/lib/azure/table/edmtype.rb +126 -126
  90. data/lib/azure/table/entity.rb +30 -30
  91. data/lib/azure/table/guid.rb +23 -23
  92. data/lib/azure/table/query.rb +111 -111
  93. data/lib/azure/table/serialization.rb +107 -107
  94. data/lib/azure/table/table_service.rb +559 -559
  95. data/lib/azure/version.rb +31 -31
  96. data/lib/azure/virtual_machine_image_management/serialization.rb +66 -66
  97. data/lib/azure/virtual_machine_image_management/virtual_machine_disk.rb +25 -25
  98. data/lib/azure/virtual_machine_image_management/virtual_machine_image.rb +25 -25
  99. data/lib/azure/virtual_machine_image_management/virtual_machine_image_management_service.rb +94 -94
  100. data/lib/azure/virtual_machine_management/serialization.rb +462 -462
  101. data/lib/azure/virtual_machine_management/virtual_machine.rb +45 -45
  102. data/lib/azure/virtual_machine_management/virtual_machine_management_service.rb +588 -588
  103. data/lib/azure/virtual_network_management/serialization.rb +190 -190
  104. data/lib/azure/virtual_network_management/virtual_network.rb +37 -37
  105. data/lib/azure/virtual_network_management/virtual_network_management_service.rb +109 -109
  106. data/test/fixtures/affinity_group.xml +33 -33
  107. data/test/fixtures/all_containers.xml +20 -20
  108. data/test/fixtures/all_tables.xml +22 -22
  109. data/test/fixtures/certificate.pem +21 -21
  110. data/test/fixtures/container_acl.xml +11 -11
  111. data/test/fixtures/create_sql_database_server.xml +1 -1
  112. data/test/fixtures/create_storage_desc_error.xml +5 -5
  113. data/test/fixtures/create_storage_extendedprop_error.xml +8 -8
  114. data/test/fixtures/create_storage_extendedpropname_error.xml +6 -6
  115. data/test/fixtures/create_storage_full_error.xml +6 -6
  116. data/test/fixtures/create_storage_label_error.xml +5 -5
  117. data/test/fixtures/create_storage_location_error.xml +5 -5
  118. data/test/fixtures/create_storage_name_error.xml +6 -6
  119. data/test/fixtures/create_table_response_entry.xml +15 -15
  120. data/test/fixtures/delete_storage_container_error.xml +5 -5
  121. data/test/fixtures/delete_storage_error.xml +5 -5
  122. data/test/fixtures/deployment_error.xml +5 -5
  123. data/test/fixtures/get_storage_account_error.xml +5 -5
  124. data/test/fixtures/get_storage_account_properties.xml +31 -31
  125. data/test/fixtures/get_storage_account_properties_new.xml +31 -31
  126. data/test/fixtures/http_error.xml +5 -5
  127. data/test/fixtures/insert_entity_response_entry.xml +25 -25
  128. data/test/fixtures/list_affinity_groups.xml +22 -22
  129. data/test/fixtures/list_blobs.xml +120 -120
  130. data/test/fixtures/list_block_all_with_none_committed.xml +21 -21
  131. data/test/fixtures/list_blocks_all.xml +22 -22
  132. data/test/fixtures/list_blocks_committed.xml +12 -12
  133. data/test/fixtures/list_cloud_services.xml +38 -38
  134. data/test/fixtures/list_containers.xml +37 -37
  135. data/test/fixtures/list_firewall_management_endpoint.xml +27 -27
  136. data/test/fixtures/list_images.xml +110 -110
  137. data/test/fixtures/list_locations.xml +62 -62
  138. data/test/fixtures/list_page_ranges.xml +10 -10
  139. data/test/fixtures/list_sql_database.xml +36 -36
  140. data/test/fixtures/list_sql_server_firewall.xml +23 -23
  141. data/test/fixtures/list_storage_account_single.xml +24 -24
  142. data/test/fixtures/list_storage_accounts.xml +45 -45
  143. data/test/fixtures/list_virtual_networks.xml +92 -92
  144. data/test/fixtures/logging.xml +11 -11
  145. data/test/fixtures/management_certificate.pem +55 -55
  146. data/test/fixtures/messages.xml +12 -12
  147. data/test/fixtures/metrics.xml +10 -10
  148. data/test/fixtures/privatekey.key +28 -28
  149. data/test/fixtures/query_entities_empty_response.xml +7 -7
  150. data/test/fixtures/query_entities_response.xml +45 -45
  151. data/test/fixtures/queue_service_properties.xml +22 -22
  152. data/test/fixtures/queue_service_properties_original.xml +19 -19
  153. data/test/fixtures/queues.xml +16 -16
  154. data/test/fixtures/retention_policy.xml +5 -5
  155. data/test/fixtures/sb_default_create_queue_response.xml +23 -23
  156. data/test/fixtures/sb_default_create_relay_response.xml +15 -15
  157. data/test/fixtures/sb_default_create_topic_response.xml +18 -18
  158. data/test/fixtures/sb_get_access_token_response.txt +1 -1
  159. data/test/fixtures/sb_queues_runtime_peek_message_response_headers.txt +9 -9
  160. data/test/fixtures/storage_service_properties.xml +54 -54
  161. data/test/fixtures/update_storage_account.xml +16 -16
  162. data/test/fixtures/update_storage_error.xml +4 -4
  163. data/test/fixtures/updated_storage_accounts.xml +52 -52
  164. data/test/fixtures/virtual_machine.xml +113 -113
  165. data/test/fixtures/windows_virtual_machine.xml +106 -106
  166. data/test/integration/affinity_group/Affinity_test.rb +55 -55
  167. data/test/integration/affinity_group/Create_Affinity_test.rb +63 -63
  168. data/test/integration/affinity_group/Delete_Affinity_test.rb +56 -56
  169. data/test/integration/affinity_group/List_Affinity_test.rb +41 -41
  170. data/test/integration/affinity_group/Update_Affinity_test.rb +82 -82
  171. data/test/integration/blob/blob_gb18030_test.rb +199 -199
  172. data/test/integration/blob/blob_metadata_test.rb +75 -75
  173. data/test/integration/blob/blob_pages_test.rb +119 -119
  174. data/test/integration/blob/blob_properties_test.rb +77 -77
  175. data/test/integration/blob/block_blob_test.rb +254 -254
  176. data/test/integration/blob/container/container_acl_test.rb +69 -69
  177. data/test/integration/blob/container/container_metadata_test.rb +50 -50
  178. data/test/integration/blob/container/create_container_test.rb +60 -60
  179. data/test/integration/blob/container/delete_container_test.rb +39 -39
  180. data/test/integration/blob/container/get_container_properties_test.rb +48 -48
  181. data/test/integration/blob/container/list_containers_test.rb +79 -79
  182. data/test/integration/blob/container/root_container_test.rb +53 -53
  183. data/test/integration/blob/copy_blob_test.rb +113 -113
  184. data/test/integration/blob/create_blob_snapshot_test.rb +80 -80
  185. data/test/integration/blob/create_page_blob_test.rb +83 -83
  186. data/test/integration/blob/delete_blob_test.rb +159 -159
  187. data/test/integration/blob/get_blob_test.rb +65 -65
  188. data/test/integration/blob/informative_errors_test.rb +38 -38
  189. data/test/integration/blob/lease/acquire_lease_test.rb +36 -36
  190. data/test/integration/blob/lease/break_lease_test.rb +40 -40
  191. data/test/integration/blob/lease/release_lease_test.rb +40 -40
  192. data/test/integration/blob/lease/renew_lease_test.rb +42 -42
  193. data/test/integration/blob/list_blobs_test.rb +113 -113
  194. data/test/integration/cloud_service/Cloud_Create_test.rb +44 -44
  195. data/test/integration/cloud_service/Cloud_Delete_test.rb +44 -44
  196. data/test/integration/database/create_sql_server_firewall_test.rb +86 -86
  197. data/test/integration/database/create_sql_server_test.rb +53 -53
  198. data/test/integration/database/delete_sql_server_firewall_test.rb +70 -70
  199. data/test/integration/database/delete_sql_server_test.rb +58 -58
  200. data/test/integration/database/list_sql_server_firewall_test.rb +45 -45
  201. data/test/integration/database/list_sql_servers_test.rb +44 -44
  202. data/test/integration/database/reset_password_sql_server_test.rb +55 -55
  203. data/test/integration/location/Location_List_test.rb +39 -39
  204. data/test/integration/queue/clear_messages_test.rb +42 -42
  205. data/test/integration/queue/create_message_test.rb +75 -75
  206. data/test/integration/queue/create_queue_test.rb +50 -50
  207. data/test/integration/queue/delete_message_test.rb +67 -67
  208. data/test/integration/queue/delete_queue_test.rb +45 -45
  209. data/test/integration/queue/informative_errors_test.rb +41 -41
  210. data/test/integration/queue/list_messages_encoded_test.rb +79 -79
  211. data/test/integration/queue/list_messages_test.rb +79 -79
  212. data/test/integration/queue/list_queues_test.rb +44 -44
  213. data/test/integration/queue/peek_messages_test.rb +59 -59
  214. data/test/integration/queue/queue_gb18030_test.rb +131 -131
  215. data/test/integration/queue/queue_metadata_test.rb +40 -40
  216. data/test/integration/queue/update_message_test.rb +74 -74
  217. data/test/integration/service_bus/informative_errors_test.rb +36 -36
  218. data/test/integration/service_bus/queues_scenario_test.rb +200 -200
  219. data/test/integration/service_bus/queues_test.rb +265 -265
  220. data/test/integration/service_bus/relay_test.rb +131 -131
  221. data/test/integration/service_bus/rules_test.rb +144 -144
  222. data/test/integration/service_bus/sb_queue_gb18030_test.rb +182 -182
  223. data/test/integration/service_bus/scenario_test.rb +101 -101
  224. data/test/integration/service_bus/subscriptions_test.rb +211 -211
  225. data/test/integration/service_bus/topics_scenario_test.rb +406 -406
  226. data/test/integration/service_bus/topics_test.rb +129 -129
  227. data/test/integration/storage_management/storage_management_test.rb +160 -160
  228. data/test/integration/table/create_table_test.rb +35 -35
  229. data/test/integration/table/delete_entity_batch_test.rb +106 -106
  230. data/test/integration/table/delete_entity_test.rb +93 -93
  231. data/test/integration/table/delete_table_test.rb +39 -39
  232. data/test/integration/table/get_table_test.rb +36 -36
  233. data/test/integration/table/informative_errors_test.rb +38 -38
  234. data/test/integration/table/insert_entity_batch_test.rb +99 -99
  235. data/test/integration/table/insert_entity_test.rb +87 -87
  236. data/test/integration/table/insert_or_merge_entity_batch_test.rb +158 -158
  237. data/test/integration/table/insert_or_merge_entity_test.rb +142 -142
  238. data/test/integration/table/insert_or_replace_entity_batch_test.rb +151 -151
  239. data/test/integration/table/insert_or_replace_entity_test.rb +136 -136
  240. data/test/integration/table/merge_entity_batch_test.rb +127 -127
  241. data/test/integration/table/merge_entity_test.rb +112 -112
  242. data/test/integration/table/query_entities_test.rb +194 -194
  243. data/test/integration/table/query_tables_test.rb +42 -42
  244. data/test/integration/table/query_test.rb +250 -250
  245. data/test/integration/table/table_acl_test.rb +51 -51
  246. data/test/integration/table/table_gb18030_test.rb +355 -355
  247. data/test/integration/table/update_entity_batch_test.rb +148 -148
  248. data/test/integration/table/update_entity_test.rb +130 -130
  249. data/test/integration/test_helper.rb +42 -42
  250. data/test/integration/vm/VM_Create_test.rb +260 -260
  251. data/test/integration/vm/VM_Delete_test.rb +55 -55
  252. data/test/integration/vm/VM_Operations_test.rb +173 -173
  253. data/test/integration/vm_image/virtual_machine_disk_test.rb +37 -37
  254. data/test/integration/vm_image/virtual_machine_image_test.rb +36 -36
  255. data/test/integration/vnet/Virtual_Network_Create_test.rb +122 -122
  256. data/test/integration/vnet/Virtual_Network_list_test.rb +53 -53
  257. data/test/support/env.rb +19 -19
  258. data/test/support/fixtures.rb +36 -36
  259. data/test/support/name_generator.rb +168 -168
  260. data/test/support/stubs.rb +42 -42
  261. data/test/support/virtual_machine_name_generator.rb +102 -102
  262. data/test/support/virtual_network_helper.rb +73 -73
  263. data/test/test_helper.rb +53 -53
  264. data/test/unit/affinity_group/affinity_group_test.rb +192 -192
  265. data/test/unit/affinity_group/serialization_test.rb +88 -88
  266. data/test/unit/base_management/location_test.rb +57 -57
  267. data/test/unit/blob/blob_service_test.rb +1946 -1946
  268. data/test/unit/cloud_service_management/cloud_service_management_service_test.rb +94 -94
  269. data/test/unit/cloud_service_management/serialization_test.rb +169 -169
  270. data/test/unit/core/auth/shared_key_lite_test.rb +51 -51
  271. data/test/unit/core/auth/shared_key_test.rb +58 -58
  272. data/test/unit/core/auth/signer_test.rb +30 -30
  273. data/test/unit/core/http/http_error_test.rb +57 -57
  274. data/test/unit/core/http/http_request_test.rb +66 -66
  275. data/test/unit/core/http/http_response_test.rb +45 -45
  276. data/test/unit/core/http/retry_policy_test.rb +23 -23
  277. data/test/unit/database/serialization_test.rb +97 -97
  278. data/test/unit/database/sql_database_server_service_test.rb +288 -288
  279. data/test/unit/service/serialization_test.rb +532 -532
  280. data/test/unit/service/storage_service_test.rb +292 -292
  281. data/test/unit/storage_management/serialization_test.rb +232 -232
  282. data/test/unit/storage_management/storage_management_service_test.rb +261 -261
  283. data/test/unit/table/edmtype_test.rb +107 -107
  284. data/test/unit/virtual_machine_image_management/serialization_test.rb +35 -35
  285. data/test/unit/virtual_machine_image_management/virtual_machine_image_management_service_test.rb +65 -65
  286. data/test/unit/virtual_machine_management/serialization_test.rb +258 -258
  287. data/test/unit/virtual_machine_management/virtual_machine_management_service_test.rb +440 -440
  288. data/test/unit/vnet/serialization_test.rb +187 -187
  289. data/test/unit/vnet/virtual_network_management_service_test.rb +131 -131
  290. metadata +34 -27
@@ -1,45 +1,45 @@
1
- #-------------------------------------------------------------------------
2
- # Copyright 2013 Microsoft Open Technologies, Inc.
3
- #
4
- # Licensed under the Apache License, Version 2.0 (the "License");
5
- # you may not use this file except in compliance with the License.
6
- # You may obtain a copy of the License at
7
- # http://www.apache.org/licenses/LICENSE-2.0
8
- #
9
- # Unless required by applicable law or agreed to in writing, software
10
- # distributed under the License is distributed on an "AS IS" BASIS,
11
- # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12
- # See the License for the specific language governing permissions and
13
- # limitations under the License.
14
- #--------------------------------------------------------------------------
15
-
16
- module Azure
17
- module VirtualMachineManagement
18
- class VirtualMachine
19
- def initialize
20
- yield self if block_given?
21
- end
22
-
23
- attr_accessor :cloud_service_name
24
- attr_accessor :status
25
- attr_accessor :ipaddress
26
- attr_accessor :vm_name
27
- attr_accessor :udp_endpoints
28
- attr_accessor :hostname
29
- attr_accessor :deployment_name
30
- attr_accessor :deployment_status
31
- attr_accessor :tcp_endpoints
32
- attr_accessor :role_size
33
- attr_accessor :image
34
- attr_accessor :os_type
35
- attr_accessor :disk_name
36
- attr_accessor :virtual_network_name
37
- attr_accessor :availability_set_name
38
- attr_accessor :media_link
39
- attr_accessor :data_disks
40
- attr_accessor :private_ipaddress
41
- attr_accessor :virtual_network_subnet_name
42
- attr_accessor :subnet
43
- end
44
- end
45
- end
1
+ #-------------------------------------------------------------------------
2
+ # Copyright 2013 Microsoft Open Technologies, Inc.
3
+ #
4
+ # Licensed under the Apache License, Version 2.0 (the "License");
5
+ # you may not use this file except in compliance with the License.
6
+ # You may obtain a copy of the License at
7
+ # http://www.apache.org/licenses/LICENSE-2.0
8
+ #
9
+ # Unless required by applicable law or agreed to in writing, software
10
+ # distributed under the License is distributed on an "AS IS" BASIS,
11
+ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12
+ # See the License for the specific language governing permissions and
13
+ # limitations under the License.
14
+ #--------------------------------------------------------------------------
15
+
16
+ module Azure
17
+ module VirtualMachineManagement
18
+ class VirtualMachine
19
+ def initialize
20
+ yield self if block_given?
21
+ end
22
+
23
+ attr_accessor :cloud_service_name
24
+ attr_accessor :status
25
+ attr_accessor :ipaddress
26
+ attr_accessor :vm_name
27
+ attr_accessor :udp_endpoints
28
+ attr_accessor :hostname
29
+ attr_accessor :deployment_name
30
+ attr_accessor :deployment_status
31
+ attr_accessor :tcp_endpoints
32
+ attr_accessor :role_size
33
+ attr_accessor :image
34
+ attr_accessor :os_type
35
+ attr_accessor :disk_name
36
+ attr_accessor :virtual_network_name
37
+ attr_accessor :availability_set_name
38
+ attr_accessor :media_link
39
+ attr_accessor :data_disks
40
+ attr_accessor :private_ipaddress
41
+ attr_accessor :virtual_network_subnet_name
42
+ attr_accessor :subnet
43
+ end
44
+ end
45
+ end
@@ -1,589 +1,589 @@
1
- #-------------------------------------------------------------------------
2
- # Copyright 2013 Microsoft Open Technologies, Inc.
3
- #
4
- # Licensed under the Apache License, Version 2.0 (the "License");
5
- # you may not use this file except in compliance with the License.
6
- # You may obtain a copy of the License at
7
- # http://www.apache.org/licenses/LICENSE-2.0
8
- #
9
- # Unless required by applicable law or agreed to in writing, software
10
- # distributed under the License is distributed on an "AS IS" BASIS,
11
- # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12
- # See the License for the specific language governing permissions and
13
- # limitations under the License.
14
- #--------------------------------------------------------------------------
15
- require 'azure/virtual_machine_management/serialization'
16
- include Azure::VirtualMachineImageManagement
17
-
18
- module Azure
19
- module VirtualMachineManagement
20
- class VirtualMachineManagementService < BaseManagementService
21
- def initialize
22
- super()
23
- end
24
-
25
- # Public: Get a lists of virtual machines available under the current subscription.
26
- #
27
- # Returns an list of Azure::VirtualMachineManagement::VirtualMachine instances.
28
- def list_virtual_machines(*cloud_service_names)
29
- roles = []
30
- cloud_service_names.flatten!
31
- if cloud_service_names.empty?
32
- cloud_service = Azure::CloudServiceManagementService.new
33
- cloud_service_names = cloud_service.list_cloud_services.map(&:name)
34
- end
35
- cloud_service_names.each do |cloud_service_name|
36
- request_path = "/services/hostedservices/#{cloud_service_name}/deploymentslots/production"
37
- request = ManagementHttpRequest.new(:get, request_path)
38
- request.warn = true
39
- response = request.call
40
- roles << Serialization.virtual_machines_from_xml(response, cloud_service_name)
41
- end
42
- roles.flatten.compact
43
- end
44
-
45
- # Public: Gets a virtual machine based on the provided name and cloud service name.
46
- #
47
- # ==== Attributes
48
- #
49
- # * +name+ - String. Virtual machine name.
50
- # * +cloud_service_name+ - String. Cloud service name.
51
- #
52
- # Returns an Azure::VirtualMachineManagement::VirtualMachine instance.
53
- def get_virtual_machine(name, cloud_service_name)
54
- server = list_virtual_machines(cloud_service_name).select { |x| x.vm_name.casecmp(name) == 0 }
55
- server.first
56
- end
57
-
58
- # Public: Provisions a virtual machine based on the supplied configuration.
59
- #
60
- # ==== Attributes
61
- #
62
- # * +params+ - Hash. parameters.
63
- # * +options+ - Hash. Optional parameters.
64
- # * +add_role+ - true/false. Optional Parameter. Default is false
65
- #
66
- # ==== Params
67
- #
68
- # Accepted key/value pairs are:
69
- # * +:vm_name+ - String. Name of virtual machine.
70
- # * +:vm_user+ - String. User name for the virtual machine instance.
71
- # * +:password+ - String. A description for the hosted service.
72
- # * +:image+ - String. Name of the disk image to use to create the virtual machine.
73
- # * +:location+ - String. The location where the virtual machine will be created.
74
- # * +:affinity_group_name - String. The affinity group name to be used
75
- # for the cloud service and the storage account if these do not exist.
76
- #
77
- # ==== Options
78
- #
79
- # Accepted key/value pairs are:
80
- # * +:storage_account_name+ - String. Name of storage account.
81
- # * +:cloud_service_name+ - String. Name of cloud service.
82
- # * +:deployment_name+ - String. A name for the deployment.
83
- # * +:tcp_endpoints+ - String. Specifies the internal port and external/public port separated by a colon.
84
- # You can map multiple internal and external ports by separating them with a comma.
85
- # * +:ssh_private_key_file+ - String. Path of private key file.
86
- # * +:ssh_certificate_file+ - String. Path of certificate file.
87
- # * +:ssh_port+ - Integer. Specifies the SSH port number.
88
- # * +:winrm_http_port - Integer. Specifies the WinRM HTTP port number.
89
- # * +:winrm_https_port - Integer. Specifies the WinRM HTTPS port number.
90
- # * +:vm_size+ - String. Specifies the size of the virtual machine instance.
91
- # * +:winrm_transport+ - Array. Specifies WINRM transport protocol.
92
- # * +:availability_set_name+ - String. Specifies the availability set name.
93
- #
94
- # ==== add_role
95
- #
96
- # Accepted values are:
97
- # * +false+ - Will add a new deployment in a cloud service.
98
- # * +true+ - Will add a new role to a cloud service. Atleast one
99
- # deployment should exist before you can add a role.
100
- #
101
- # Returns Azure::VirtualMachineManagement::VirtualMachine objects of newly created instance.
102
- #
103
- # See:
104
- # http://msdn.microsoft.com/en-us/library/windowsazure/jj157194.aspx
105
- # http://msdn.microsoft.com/en-us/library/windowsazure/jj157186.aspx
106
- def create_virtual_machine(params, options = {})
107
- image = get_image(params[:image])
108
- options[:os_type] = image.os_type
109
- validate_deployment_params(params, options)
110
- options[:deployment_name] ||= options[:cloud_service_name]
111
- Loggerx.info 'Creating deployment...'
112
- options[:cloud_service_name] ||= generate_cloud_service_name(params[:vm_name])
113
- optionals = {}
114
- if options[:virtual_network_name]
115
- virtual_network_service = Azure::VirtualNetworkManagementService.new
116
- virtual_networks = virtual_network_service.list_virtual_networks.select { |x| x.name == options[:virtual_network_name] }
117
- if virtual_networks.empty?
118
- Loggerx.error_with_exit "Virtual network #{options[:virtual_network_name]} doesn't exists"
119
- else
120
- vnet = virtual_networks.first
121
- if !vnet.affinity_group.empty?
122
- options[:affinity_group_name] = vnet.affinity_group
123
- else
124
- optionals[:location] = vnet.location
125
- end
126
- end
127
- elsif options[:affinity_group_name]
128
- optionals[:affinity_group_name] = options[:affinity_group_name]
129
- else
130
- optionals[:location] = params[:location]
131
- end
132
- cloud_service = Azure::CloudServiceManagementService.new
133
- cloud_service.create_cloud_service(options[:cloud_service_name], optionals)
134
- cloud_service.upload_certificate(options[:cloud_service_name], params[:certificate]) unless params[:certificate].empty?
135
- unless image.category == 'User'
136
- options[:storage_account_name] ||= generate_storage_account_name(params[:vm_name])
137
- Azure::StorageManagementService.new.create_storage_account(options[:storage_account_name], optionals)
138
- end
139
- body = Serialization.deployment_to_xml(params, image, options)
140
- path = "/services/hostedservices/#{options[:cloud_service_name]}/deployments"
141
- Loggerx.info 'Deployment in progress...'
142
- request = ManagementHttpRequest.new(:post, path, body)
143
- request.call
144
- vm = get_virtual_machine(params[:vm_name], options[:cloud_service_name])
145
- # if this is a User image, a second call is required to set the endpoints, this is because
146
- # according to https://msdn.microsoft.com/en-us/library/azure/jj157186.aspx all
147
- # ConfigurationSets parameters (including the NetworkConfiguration type) are ignored
148
- # when the VMImageName is set
149
- if image.category == 'User'
150
- Serialization.endpoints_from_xml(Nokogiri::XML(body), vm)
151
- update_endpoints(vm.vm_name, options[:cloud_service_name], vm.tcp_endpoints + vm.udp_endpoints)
152
- end
153
- vm
154
- rescue Exception => e
155
- e.message
156
- end
157
-
158
- # Public: Add a new role to a cloud service. Atleast one deployment should exist before you can add a role.
159
- #
160
- # ==== Attributes
161
- #
162
- # * +params+ - Hash. parameters.
163
- # * +options+ - Hash. Optional parameters.
164
- #
165
- # ==== Params
166
- #
167
- # Accepted key/value pairs are:
168
- # * +:vm_name+ - String. Name of virtual machine.
169
- # * +:vm_user+ - String. User name for the virtual machine instance.
170
- # * +:password+ - String. A description for the hosted service.
171
- # * +:image+ - String. Name of the disk image to use to create the virtual machine.
172
- # * +:cloud_service_name+ - String. Name of cloud service.
173
- #
174
- # ==== Options
175
- #
176
- # Accepted key/value pairs are:
177
- # * +:storage_account_name+ - String. Name of storage account.
178
- # * +:tcp_endpoints+ - String. Specifies the internal port and external/public port separated by a colon.
179
- # You can map multiple internal and external ports by separating them with a comma.
180
- # * +:ssh_private_key_file+ - String. Path of private key file.
181
- # * +:ssh_certificate_file+ - String. Path of certificate file.
182
- # * +:ssh_port+ - Integer. Specifies the SSH port number.
183
- # * +:winrm_http_port - Integer. Specifies the WinRM HTTP port number.
184
- # * +:winrm_https_port - Integer. Specifies the WinRM HTTPS port number.
185
- # * +:vm_size+ - String. Specifies the size of the virtual machine instance.
186
- # * +:winrm_transport+ - Array. Specifies WINRM transport protocol.
187
- #
188
- # Returns Azure::VirtualMachineManagement::VirtualMachine objects of newly created instance.
189
- #
190
- # See:
191
- # http://msdn.microsoft.com/en-us/library/windowsazure/jj157186.aspx
192
- def add_role(params, options = {})
193
- image = get_image(params[:image])
194
- options[:os_type] = image.os_type
195
- validate_deployment_params(params, options, true)
196
- cloud_service = Azure::CloudServiceManagementService.new
197
- cloud_service = cloud_service.get_cloud_service_properties(params[:cloud_service_name])
198
- deployment_name = cloud_service.deployment_name
199
- Loggerx.error_with_exit "Deployment doesn't exists." if cloud_service && deployment_name.empty?
200
- others = {}
201
- if cloud_service.location
202
- others[:location] = cloud_service.location
203
- elsif cloud_service.affinity_group
204
- others[:affinity_group_name] = cloud_service.affinity_group
205
- end
206
- unless image.category == 'User'
207
- options[:storage_account_name] ||= generate_storage_account_name(params[:vm_name])
208
- Azure::StorageManagementService.new.create_storage_account(options[:storage_account_name], others)
209
- end
210
- Loggerx.info 'Deployment exists, adding role...'
211
- existing_ports = []
212
- cloud_service.virtual_machines[deployment_name.to_sym].each do |vm|
213
- vm.tcp_endpoints.each do |endpoint|
214
- existing_ports << endpoint[:public_port]
215
- end
216
- end
217
- options[:existing_ports] = existing_ports
218
- body = Serialization.role_to_xml(params, image, options).to_xml
219
- path = "/services/hostedservices/#{cloud_service.name}/deployments/#{deployment_name}/roles"
220
- Loggerx.info 'Deployment in progress...'
221
- request = ManagementHttpRequest.new(:post, path, body)
222
- request.call
223
-
224
- vm = get_virtual_machine(params[:vm_name], cloud_service.name)
225
-
226
- # if this is a User image, a second call is required to set the endpoints, this is because
227
- # according to https://msdn.microsoft.com/en-us/library/azure/jj157186.aspx all
228
- # ConfigurationSets parameters (including the NetworkConfiguration type) are ignored
229
- # when the VMImageName is set
230
- if image.category == 'User'
231
- Serialization.endpoints_from_xml(Nokogiri::XML(body), vm)
232
- update_endpoints(vm.vm_name, cloud_service.name, vm.tcp_endpoints + vm.udp_endpoints)
233
- end
234
-
235
- vm
236
- rescue Exception => e
237
- e.message
238
- end
239
-
240
- # Public: Deletes the deployment, cloud service and disk.
241
- #
242
- # ==== Attributes
243
- #
244
- # * +vm_name+ - String. Virtual machine name.
245
- # * +cloud_service_name+ - String. Cloud service name.
246
- #
247
- # See http://msdn.microsoft.com/en-us/library/windowsazure/gg441305.aspx
248
- # See http://msdn.microsoft.com/en-us/library/windowsazure/jj157179.aspx
249
- #
250
- # Returns NONE
251
- def delete_virtual_machine(vm_name, cloud_service_name)
252
- virtual_machines = list_virtual_machines(cloud_service_name)
253
- vm = virtual_machines.select { |x| x.vm_name == vm_name }.first
254
- if vm
255
- if virtual_machines.size == 1
256
- cloud_service = Azure::CloudServiceManagementService.new
257
- cloud_service.delete_cloud_service_deployment(cloud_service_name)
258
- cloud_service.delete_cloud_service(cloud_service_name)
259
- else
260
- path = "/services/hostedservices/#{vm.cloud_service_name}/deployments/#{vm.deployment_name}/roles/#{vm.vm_name}"
261
- Loggerx.info "Deleting virtual machine #{vm_name}. \n"
262
- request = ManagementHttpRequest.new(:delete, path)
263
- request.call
264
- end
265
- Loggerx.info "Waiting for disk to be released.\n"
266
- disk_name = vm.disk_name
267
- disk_management_service = VirtualMachineDiskManagementService.new
268
- # Wait for 180s for disk to be released.
269
- disk = nil
270
- 18.times do
271
- print '# '
272
- disk = disk_management_service.get_virtual_machine_disk(disk_name)
273
- unless disk.attached
274
- print "Disk released.\n"
275
- break
276
- end
277
- sleep 10
278
- end
279
- if disk.attached
280
- Loggerx.error "\nCannot delete disk #{disk_name}."
281
- else
282
- disk_management_service.delete_virtual_machine_disk(disk_name)
283
- end
284
- else
285
- Loggerx.error "Cannot find virtual machine #{vm_name} under cloud service #{cloud_service_name}"
286
- end
287
- rescue
288
- end
289
-
290
- # Public: Shuts down the specified virtual machine.
291
- #
292
- # ==== Attributes
293
- #
294
- # * +name+ - String. Virtual machine name.
295
- # * +cloud_service_name+ - String. Cloud service name.
296
- #
297
- # See http://msdn.microsoft.com/en-us/library/windowsazure/jj157195.aspx
298
- #
299
- # Returns NONE
300
- def shutdown_virtual_machine(vm_name, cloud_service_name)
301
- vm = get_virtual_machine(vm_name, cloud_service_name)
302
- if vm
303
- if %w(StoppedVM StoppedDeallocated).include?(vm.status)
304
- Loggerx.error 'Cannot perform the shutdown operation on a stopped virtual machine.'
305
- elsif vm.deployment_status == 'Running'
306
- path = "/services/hostedservices/#{vm.cloud_service_name}/deployments/#{vm.deployment_name}/roleinstances/#{vm.vm_name}/Operations"
307
- body = Serialization.shutdown_virtual_machine_to_xml
308
- Loggerx.info "Shutting down virtual machine \"#{vm.vm_name}\" ..."
309
- request = ManagementHttpRequest.new(:post, path, body)
310
- request.call
311
- else
312
- Loggerx.error 'Cannot perform the shutdown operation on a stopped deployment.'
313
- end
314
- else
315
- Loggerx.error "Cannot find virtual machine \"#{vm_name}\" under cloud service \"#{cloud_service_name}\". "
316
- end
317
- end
318
-
319
- # Public: Starts the specified virtual machine.
320
- #
321
- # ==== Attributes
322
- #
323
- # * +name+ - String. Virtual machine name.
324
- # * +cloud_service_name+ - String. Cloud service name.
325
- #
326
- # See http://msdn.microsoft.com/en-us/library/windowsazure/jj157189.aspx
327
- #
328
- # Returns NONE
329
- def start_virtual_machine(vm_name, cloud_service_name)
330
- vm = get_virtual_machine(vm_name, cloud_service_name)
331
- if vm
332
- if vm.status == 'ReadyRole'
333
- Loggerx.error 'Cannot perform the start operation on started virtual machine.'
334
- else
335
- path = "/services/hostedservices/#{vm.cloud_service_name}/deployments/#{vm.deployment_name}/roleinstances/#{vm.vm_name}/Operations"
336
- body = Serialization.start_virtual_machine_to_xml
337
- Loggerx.info "Starting virtual machine \"#{vm.vm_name}\" ..."
338
- request = ManagementHttpRequest.new(:post, path, body)
339
- request.call
340
- end
341
- else
342
- Loggerx.error "Cannot find virtual machine \"#{vm_name}\" under cloud service \"#{cloud_service_name}\"."
343
- end
344
- end
345
-
346
- # Public: Restarts the specified virtual machine.
347
- #
348
- # ==== Attributes
349
- #
350
- # * +name+ - String. Virtual machine name.
351
- # * +cloud_service_name+ - String. Cloud service name.
352
- #
353
- # See http://msdn.microsoft.com/en-us/library/windowsazure/jj157197.aspx
354
- #
355
- # Returns NONE
356
- def restart_virtual_machine(vm_name, cloud_service_name)
357
- vm = get_virtual_machine(vm_name, cloud_service_name)
358
- if vm
359
- path = "/services/hostedservices/#{vm.cloud_service_name}/deployments/#{vm.deployment_name}/roleinstances/#{vm.vm_name}/Operations"
360
- body = Serialization.restart_virtual_machine_to_xml
361
- Loggerx.info "Restarting virtual machine \"#{vm.vm_name}\" ..."
362
- request = ManagementHttpRequest.new(:post, path, body)
363
- request.call
364
- else
365
- Loggerx.error "Cannot find virtual machine \"#{vm_name}\" under cloud service \"#{cloud_service_name}\"."
366
- end
367
- end
368
-
369
- # Public: Add/Update endpoints of virtual machine.
370
- #
371
- # ==== Attributes
372
- #
373
- # * +name+ - String. Virtual machine name.
374
- # * +cloud_service_name+ - String. Cloud service name.
375
- # * +input_endpoints+ - Hash. A hash of the name/value pairs for the endpoint.
376
- #
377
- # ==== Endpoint
378
- #
379
- # Accepted key/value pairs are:
380
- # * +:local_port+ - String. Specifies the internal port on which the
381
- # Virtual Machine is listening.
382
- # * +:public_port+ - String. Specifies the external port to use for
383
- # the endpoint.
384
- # * +:name+ - String. Specifies the name of the external endpoint.
385
- # * +load_balancer_name+ - String. Specifies a name for a set of
386
- # load-balanced endpoints.
387
- # * +:protocol+ - String. Specifies the transport protocol
388
- # for the endpoint. Possible values are: TCP, UDP
389
- # * +:direct_server_return+ - String. Specifies whether the endpoint
390
- # uses Direct Server Return. Possible values are: true, false (optional)
391
- # * +:load_balancer - Hash. Contains properties that define the
392
- # endpoint settings that the load balancer uses to monitor the
393
- # availability of the Virtual Machine (optional)
394
- #
395
- # === Load balancer
396
- #
397
- # Accepted key/value pairs are:
398
- # * +:port+ - String. Specifies the internal port on which the
399
- # Virtual Machine is listening.
400
- # * +:protocol+ - String. Specifies the protocol to use to inspect the
401
- # availability status of the virtual machine.
402
- # * +:interval+ - String. Specifies the interval for the load balancer
403
- # probe in seconds. (optional)
404
- # * +:timeout+ - String. Specifies the timeout for the load balancer
405
- # probe in seconds. (optional)
406
- # * +:path+ - String. Specifies the relative path to inspect to
407
- # determine the availability status of the Virtual Machine. (optional)
408
- #
409
- # See http://msdn.microsoft.com/en-us/library/windowsazure/jj157187.aspx
410
- #
411
- # Returns NONE
412
- def update_endpoints(vm_name, cloud_service_name, *input_endpoints)
413
- input_endpoints.flatten!
414
- vm = get_virtual_machine(vm_name, cloud_service_name)
415
- if vm
416
- path = "/services/hostedservices/#{vm.cloud_service_name}/deployments/#{vm.deployment_name}/roles/#{vm_name}"
417
- endpoints = vm.tcp_endpoints + vm.udp_endpoints
418
- input_endpoints.each do |iep|
419
- endpoints.delete_if { |ep| iep[:name].downcase == ep[:name].downcase }
420
- end
421
- endpoints += input_endpoints
422
- body = Serialization.update_role_to_xml(endpoints, vm)
423
- request = ManagementHttpRequest.new(:put, path, body)
424
- Loggerx.info "Updating endpoints of virtual machine #{vm.vm_name} ..."
425
- request.call
426
- else
427
- Loggerx.error "Cannot find virtual machine \"#{vm_name}\" under cloud service \"#{cloud_service_name}\"."
428
- end
429
- end
430
-
431
- # Public: Delete endpoint of virtual machine.
432
- #
433
- # ==== Attributes
434
- #
435
- # * +name+ - String. Virtual machine name.
436
- # * +cloud_service_name+ - String. Cloud service name.
437
- # * +endpoint_name+ - String. Name of endpoint.
438
- #
439
- # See http://msdn.microsoft.com/en-us/library/windowsazure/jj157187.aspx
440
- #
441
- # Returns NONE
442
- def delete_endpoint(vm_name, cloud_service_name, endpoint_name)
443
- vm = get_virtual_machine(vm_name, cloud_service_name)
444
- if vm
445
- path = "/services/hostedservices/#{vm.cloud_service_name}/deployments/#{vm.deployment_name}/roles/#{vm_name}"
446
- endpoints = vm.tcp_endpoints + vm.udp_endpoints
447
- endpoints.delete_if { |ep| endpoint_name.downcase == ep[:name].downcase }
448
- body = Serialization.update_role_to_xml(endpoints, vm)
449
- request = ManagementHttpRequest.new(:put, path, body)
450
- Loggerx.info "Deleting virtual machine endpoint #{endpoint_name} ..."
451
- request.call
452
- else
453
- Loggerx.error "Cannot find virtual machine \"#{vm_name}\" under cloud service \"#{cloud_service_name}\"."
454
- end
455
- end
456
-
457
- # Public: adds a data disk to a virtual machine.
458
- #
459
- # ==== Attributes
460
- #
461
- # * +cloud_service_name+ - String. Cloud service name.
462
- # * +vm_name+ - String. Virtual machine name.
463
- # * +options+ - Hash. Optional parameters.
464
- #
465
- # ==== Options
466
- #
467
- # Accepted key/value pairs in options parameter are:
468
- # * +:import+ - Boolean. if true, then allows to use an existing
469
- # disk by disk name. if false, then create and attach new data disk.
470
- # * +:disk_name+ - String. Specifies the name of the disk.
471
- # Reqruied if using existing disk.
472
- # * +:host_caching+ - String. Specifies the caching behavior of data disk
473
- # The default is ReadOnly. Possible values are: None, ReadOnly, ReadWrite
474
- # * +:disk_label+ - String. Specifies the description of the data disk.
475
- # * +:disk_size+ - String. Specifies the size of disk in GB
476
- #
477
- # See http://msdn.microsoft.com/en-us/library/windowsazure/jj157199.aspx
478
- #
479
- # Returns None
480
- def add_data_disk(vm_name, cloud_service_name, options = {})
481
- options[:import] ||= false
482
- vm = get_virtual_machine(vm_name, cloud_service_name)
483
- if vm
484
- path = "/services/hostedservices/#{cloud_service_name}/deployments/#{vm.deployment_name}/roles/#{vm_name}/DataDisks"
485
- body = Serialization.add_data_disk_to_xml(vm, options)
486
- Loggerx.info "Adding data disk to virtual machine #{vm_name} ..."
487
- request = ManagementHttpRequest.new(:post, path, body)
488
- request.call
489
- else
490
- Loggerx.error "Cannot find virtual machine \"#{vm_name}\" under cloud service \"#{cloud_service_name}\"."
491
- end
492
- end
493
-
494
- private
495
-
496
- # Private: Gets the operating system type of an image.
497
- #
498
- # Returns Linux or Windows
499
- def get_image(image_name)
500
- image_service = Azure::VirtualMachineImageManagementService.new
501
- image = image_service.list_virtual_machine_images.select { |x| x.name.casecmp(image_name.to_s) == 0 }.first
502
- Loggerx.error_with_exit 'The virtual machine image source is not valid.' unless image
503
- image
504
- end
505
-
506
- def generate_cloud_service_name(vm_name)
507
- random_string(vm_name + '-service-')
508
- end
509
-
510
- def generate_storage_account_name(vm_name)
511
- random_string(vm_name + 'storage').gsub(/[^0-9a-z ]/i, '').downcase[0..23]
512
- end
513
-
514
- def validate_deployment_params(params, options, add_role = false)
515
- errors = []
516
- params_keys = %w(vm_name image vm_user)
517
- params_keys += ['password'] if options[:os_type] == 'Windows'
518
- options_keys = []
519
- options_keys = %w(private_key_file certificate_file) if certificate_required?(params, options)
520
- if add_role
521
- params_keys += ['cloud_service_name']
522
- else
523
- params_keys += ['location']
524
- end
525
- params_keys.each do |key|
526
- errors << key if params[key.to_sym].nil?
527
- end
528
-
529
- options_keys.each do |key|
530
- errors << key if options[key.to_sym].nil?
531
- end
532
-
533
- if errors.empty?
534
- validate_location(params[:location]) unless add_role
535
- validate_role_size(options[:vm_size])
536
- params[:certificate] = {}
537
- if certificate_required?(params, options)
538
- begin
539
- params[:certificate][:key] = OpenSSL::PKey.read File.read(options[:private_key_file])
540
- params[:certificate][:cert] = OpenSSL::X509::Certificate.new File.read(options[:certificate_file])
541
- params[:certificate][:fingerprint] = export_fingerprint(params[:certificate][:cert])
542
- rescue Exception => e
543
- Loggerx.error_with_exit e.message
544
- end
545
- end
546
- else
547
- Loggerx.error_with_exit "You did not provide a valid '#{errors.uniq.join(", ")}' value."
548
- end
549
- end
550
-
551
- def certificate_required?(params, options)
552
- if options[:os_type] == 'Linux'
553
- (params[:password].nil? or (!options[:certificate_file].nil? && !options[:private_key_file].nil?))
554
- else
555
- winrm_with_https(options)
556
- end
557
- end
558
-
559
- def winrm_with_https(options)
560
- if options[:os_type] == 'Windows'
561
- options[:winrm_transport] && options[:winrm_transport].include?('https') && options[:certificate_file] && options[:private_key_file]
562
- end
563
- end
564
-
565
- def validate_role_size(vm_size)
566
- valid_role_sizes = %w(
567
- Basic_A0 Basic_A1 Basic_A2 Basic_A3 Basic_A4
568
- ExtraSmall Small Medium Large ExtraLarge A5 A6 A7 A8 A9 A10 A11
569
- Standard_D1 Standard_D2 Standard_D3 Standard_D4 Standard_D11 Standard_D12 Standard_D13 Standard_D14
570
- Standard_DS1 Standard_DS2 Standard_DS3 Standard_DS4 Standard_DS11 Standard_DS12 Standard_DS13 Standard_DS14
571
- Standard_G1 Standard_G2 Standard_G3 Standard_G4 Standard_G5
572
- )
573
- if vm_size && !valid_role_sizes.include?(vm_size)
574
- Loggerx.error_with_exit "Value '#{vm_size}' specified for parameter 'vm_size' is invalid. Allowed values are '#{valid_role_sizes.join(',')}'"
575
- end
576
- end
577
-
578
- def validate_location(location_name)
579
- locations = Azure::BaseManagementService.new.list_locations
580
- location = locations.select { |loc| loc.name.downcase == location_name.downcase }.first
581
- if location.nil?
582
- Loggerx.error_with_exit "Value '#{location_name}' specified for parameter 'location' is invalid. Allowed values are #{locations.map(&:name).join(',')}"
583
- elsif !location.available_services.include?('PersistentVMRole')
584
- Loggerx.error_with_exit "Persistentvmrole not enabled for \"#{location.name}\". Try different location"
585
- end
586
- end
587
- end
588
- end
1
+ #-------------------------------------------------------------------------
2
+ # Copyright 2013 Microsoft Open Technologies, Inc.
3
+ #
4
+ # Licensed under the Apache License, Version 2.0 (the "License");
5
+ # you may not use this file except in compliance with the License.
6
+ # You may obtain a copy of the License at
7
+ # http://www.apache.org/licenses/LICENSE-2.0
8
+ #
9
+ # Unless required by applicable law or agreed to in writing, software
10
+ # distributed under the License is distributed on an "AS IS" BASIS,
11
+ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12
+ # See the License for the specific language governing permissions and
13
+ # limitations under the License.
14
+ #--------------------------------------------------------------------------
15
+ require 'azure/virtual_machine_management/serialization'
16
+ include Azure::VirtualMachineImageManagement
17
+
18
+ module Azure
19
+ module VirtualMachineManagement
20
+ class VirtualMachineManagementService < BaseManagementService
21
+ def initialize
22
+ super()
23
+ end
24
+
25
+ # Public: Get a lists of virtual machines available under the current subscription.
26
+ #
27
+ # Returns an list of Azure::VirtualMachineManagement::VirtualMachine instances.
28
+ def list_virtual_machines(*cloud_service_names)
29
+ roles = []
30
+ cloud_service_names.flatten!
31
+ if cloud_service_names.empty?
32
+ cloud_service = Azure::CloudServiceManagementService.new
33
+ cloud_service_names = cloud_service.list_cloud_services.map(&:name)
34
+ end
35
+ cloud_service_names.each do |cloud_service_name|
36
+ request_path = "/services/hostedservices/#{cloud_service_name}/deploymentslots/production"
37
+ request = ManagementHttpRequest.new(:get, request_path)
38
+ request.warn = true
39
+ response = request.call
40
+ roles << Serialization.virtual_machines_from_xml(response, cloud_service_name)
41
+ end
42
+ roles.flatten.compact
43
+ end
44
+
45
+ # Public: Gets a virtual machine based on the provided name and cloud service name.
46
+ #
47
+ # ==== Attributes
48
+ #
49
+ # * +name+ - String. Virtual machine name.
50
+ # * +cloud_service_name+ - String. Cloud service name.
51
+ #
52
+ # Returns an Azure::VirtualMachineManagement::VirtualMachine instance.
53
+ def get_virtual_machine(name, cloud_service_name)
54
+ server = list_virtual_machines(cloud_service_name).select { |x| x.vm_name.casecmp(name) == 0 }
55
+ server.first
56
+ end
57
+
58
+ # Public: Provisions a virtual machine based on the supplied configuration.
59
+ #
60
+ # ==== Attributes
61
+ #
62
+ # * +params+ - Hash. parameters.
63
+ # * +options+ - Hash. Optional parameters.
64
+ # * +add_role+ - true/false. Optional Parameter. Default is false
65
+ #
66
+ # ==== Params
67
+ #
68
+ # Accepted key/value pairs are:
69
+ # * +:vm_name+ - String. Name of virtual machine.
70
+ # * +:vm_user+ - String. User name for the virtual machine instance.
71
+ # * +:password+ - String. A description for the hosted service.
72
+ # * +:image+ - String. Name of the disk image to use to create the virtual machine.
73
+ # * +:location+ - String. The location where the virtual machine will be created.
74
+ # * +:affinity_group_name - String. The affinity group name to be used
75
+ # for the cloud service and the storage account if these do not exist.
76
+ #
77
+ # ==== Options
78
+ #
79
+ # Accepted key/value pairs are:
80
+ # * +:storage_account_name+ - String. Name of storage account.
81
+ # * +:cloud_service_name+ - String. Name of cloud service.
82
+ # * +:deployment_name+ - String. A name for the deployment.
83
+ # * +:tcp_endpoints+ - String. Specifies the internal port and external/public port separated by a colon.
84
+ # You can map multiple internal and external ports by separating them with a comma.
85
+ # * +:ssh_private_key_file+ - String. Path of private key file.
86
+ # * +:ssh_certificate_file+ - String. Path of certificate file.
87
+ # * +:ssh_port+ - Integer. Specifies the SSH port number.
88
+ # * +:winrm_http_port - Integer. Specifies the WinRM HTTP port number.
89
+ # * +:winrm_https_port - Integer. Specifies the WinRM HTTPS port number.
90
+ # * +:vm_size+ - String. Specifies the size of the virtual machine instance.
91
+ # * +:winrm_transport+ - Array. Specifies WINRM transport protocol.
92
+ # * +:availability_set_name+ - String. Specifies the availability set name.
93
+ #
94
+ # ==== add_role
95
+ #
96
+ # Accepted values are:
97
+ # * +false+ - Will add a new deployment in a cloud service.
98
+ # * +true+ - Will add a new role to a cloud service. Atleast one
99
+ # deployment should exist before you can add a role.
100
+ #
101
+ # Returns Azure::VirtualMachineManagement::VirtualMachine objects of newly created instance.
102
+ #
103
+ # See:
104
+ # http://msdn.microsoft.com/en-us/library/windowsazure/jj157194.aspx
105
+ # http://msdn.microsoft.com/en-us/library/windowsazure/jj157186.aspx
106
+ def create_virtual_machine(params, options = {})
107
+ image = get_image(params[:image])
108
+ options[:os_type] = image.os_type
109
+ validate_deployment_params(params, options)
110
+ options[:deployment_name] ||= options[:cloud_service_name]
111
+ Loggerx.info 'Creating deployment...'
112
+ options[:cloud_service_name] ||= generate_cloud_service_name(params[:vm_name])
113
+ optionals = {}
114
+ if options[:virtual_network_name]
115
+ virtual_network_service = Azure::VirtualNetworkManagementService.new
116
+ virtual_networks = virtual_network_service.list_virtual_networks.select { |x| x.name == options[:virtual_network_name] }
117
+ if virtual_networks.empty?
118
+ Loggerx.error_with_exit "Virtual network #{options[:virtual_network_name]} doesn't exists"
119
+ else
120
+ vnet = virtual_networks.first
121
+ if !vnet.affinity_group.empty?
122
+ options[:affinity_group_name] = vnet.affinity_group
123
+ else
124
+ optionals[:location] = vnet.location
125
+ end
126
+ end
127
+ elsif options[:affinity_group_name]
128
+ optionals[:affinity_group_name] = options[:affinity_group_name]
129
+ else
130
+ optionals[:location] = params[:location]
131
+ end
132
+ cloud_service = Azure::CloudServiceManagementService.new
133
+ cloud_service.create_cloud_service(options[:cloud_service_name], optionals)
134
+ cloud_service.upload_certificate(options[:cloud_service_name], params[:certificate]) unless params[:certificate].empty?
135
+ unless image.category == 'User'
136
+ options[:storage_account_name] ||= generate_storage_account_name(params[:vm_name])
137
+ Azure::StorageManagementService.new.create_storage_account(options[:storage_account_name], optionals)
138
+ end
139
+ body = Serialization.deployment_to_xml(params, image, options)
140
+ path = "/services/hostedservices/#{options[:cloud_service_name]}/deployments"
141
+ Loggerx.info 'Deployment in progress...'
142
+ request = ManagementHttpRequest.new(:post, path, body)
143
+ request.call
144
+ vm = get_virtual_machine(params[:vm_name], options[:cloud_service_name])
145
+ # if this is a User image, a second call is required to set the endpoints, this is because
146
+ # according to https://msdn.microsoft.com/en-us/library/azure/jj157186.aspx all
147
+ # ConfigurationSets parameters (including the NetworkConfiguration type) are ignored
148
+ # when the VMImageName is set
149
+ if image.category == 'User'
150
+ Serialization.endpoints_from_xml(Nokogiri::XML(body), vm)
151
+ update_endpoints(vm.vm_name, options[:cloud_service_name], vm.tcp_endpoints + vm.udp_endpoints)
152
+ end
153
+ vm
154
+ rescue Exception => e
155
+ e.message
156
+ end
157
+
158
+ # Public: Add a new role to a cloud service. Atleast one deployment should exist before you can add a role.
159
+ #
160
+ # ==== Attributes
161
+ #
162
+ # * +params+ - Hash. parameters.
163
+ # * +options+ - Hash. Optional parameters.
164
+ #
165
+ # ==== Params
166
+ #
167
+ # Accepted key/value pairs are:
168
+ # * +:vm_name+ - String. Name of virtual machine.
169
+ # * +:vm_user+ - String. User name for the virtual machine instance.
170
+ # * +:password+ - String. A description for the hosted service.
171
+ # * +:image+ - String. Name of the disk image to use to create the virtual machine.
172
+ # * +:cloud_service_name+ - String. Name of cloud service.
173
+ #
174
+ # ==== Options
175
+ #
176
+ # Accepted key/value pairs are:
177
+ # * +:storage_account_name+ - String. Name of storage account.
178
+ # * +:tcp_endpoints+ - String. Specifies the internal port and external/public port separated by a colon.
179
+ # You can map multiple internal and external ports by separating them with a comma.
180
+ # * +:ssh_private_key_file+ - String. Path of private key file.
181
+ # * +:ssh_certificate_file+ - String. Path of certificate file.
182
+ # * +:ssh_port+ - Integer. Specifies the SSH port number.
183
+ # * +:winrm_http_port - Integer. Specifies the WinRM HTTP port number.
184
+ # * +:winrm_https_port - Integer. Specifies the WinRM HTTPS port number.
185
+ # * +:vm_size+ - String. Specifies the size of the virtual machine instance.
186
+ # * +:winrm_transport+ - Array. Specifies WINRM transport protocol.
187
+ #
188
+ # Returns Azure::VirtualMachineManagement::VirtualMachine objects of newly created instance.
189
+ #
190
+ # See:
191
+ # http://msdn.microsoft.com/en-us/library/windowsazure/jj157186.aspx
192
+ def add_role(params, options = {})
193
+ image = get_image(params[:image])
194
+ options[:os_type] = image.os_type
195
+ validate_deployment_params(params, options, true)
196
+ cloud_service = Azure::CloudServiceManagementService.new
197
+ cloud_service = cloud_service.get_cloud_service_properties(params[:cloud_service_name])
198
+ deployment_name = cloud_service.deployment_name
199
+ Loggerx.error_with_exit "Deployment doesn't exists." if cloud_service && deployment_name.empty?
200
+ others = {}
201
+ if cloud_service.location
202
+ others[:location] = cloud_service.location
203
+ elsif cloud_service.affinity_group
204
+ others[:affinity_group_name] = cloud_service.affinity_group
205
+ end
206
+ unless image.category == 'User'
207
+ options[:storage_account_name] ||= generate_storage_account_name(params[:vm_name])
208
+ Azure::StorageManagementService.new.create_storage_account(options[:storage_account_name], others)
209
+ end
210
+ Loggerx.info 'Deployment exists, adding role...'
211
+ existing_ports = []
212
+ cloud_service.virtual_machines[deployment_name.to_sym].each do |vm|
213
+ vm.tcp_endpoints.each do |endpoint|
214
+ existing_ports << endpoint[:public_port]
215
+ end
216
+ end
217
+ options[:existing_ports] = existing_ports
218
+ body = Serialization.role_to_xml(params, image, options).to_xml
219
+ path = "/services/hostedservices/#{cloud_service.name}/deployments/#{deployment_name}/roles"
220
+ Loggerx.info 'Deployment in progress...'
221
+ request = ManagementHttpRequest.new(:post, path, body)
222
+ request.call
223
+
224
+ vm = get_virtual_machine(params[:vm_name], cloud_service.name)
225
+
226
+ # if this is a User image, a second call is required to set the endpoints, this is because
227
+ # according to https://msdn.microsoft.com/en-us/library/azure/jj157186.aspx all
228
+ # ConfigurationSets parameters (including the NetworkConfiguration type) are ignored
229
+ # when the VMImageName is set
230
+ if image.category == 'User'
231
+ Serialization.endpoints_from_xml(Nokogiri::XML(body), vm)
232
+ update_endpoints(vm.vm_name, cloud_service.name, vm.tcp_endpoints + vm.udp_endpoints)
233
+ end
234
+
235
+ vm
236
+ rescue Exception => e
237
+ e.message
238
+ end
239
+
240
+ # Public: Deletes the deployment, cloud service and disk.
241
+ #
242
+ # ==== Attributes
243
+ #
244
+ # * +vm_name+ - String. Virtual machine name.
245
+ # * +cloud_service_name+ - String. Cloud service name.
246
+ #
247
+ # See http://msdn.microsoft.com/en-us/library/windowsazure/gg441305.aspx
248
+ # See http://msdn.microsoft.com/en-us/library/windowsazure/jj157179.aspx
249
+ #
250
+ # Returns NONE
251
+ def delete_virtual_machine(vm_name, cloud_service_name)
252
+ virtual_machines = list_virtual_machines(cloud_service_name)
253
+ vm = virtual_machines.select { |x| x.vm_name == vm_name }.first
254
+ if vm
255
+ if virtual_machines.size == 1
256
+ cloud_service = Azure::CloudServiceManagementService.new
257
+ cloud_service.delete_cloud_service_deployment(cloud_service_name)
258
+ cloud_service.delete_cloud_service(cloud_service_name)
259
+ else
260
+ path = "/services/hostedservices/#{vm.cloud_service_name}/deployments/#{vm.deployment_name}/roles/#{vm.vm_name}"
261
+ Loggerx.info "Deleting virtual machine #{vm_name}. \n"
262
+ request = ManagementHttpRequest.new(:delete, path)
263
+ request.call
264
+ end
265
+ Loggerx.info "Waiting for disk to be released.\n"
266
+ disk_name = vm.disk_name
267
+ disk_management_service = VirtualMachineDiskManagementService.new
268
+ # Wait for 180s for disk to be released.
269
+ disk = nil
270
+ 18.times do
271
+ print '# '
272
+ disk = disk_management_service.get_virtual_machine_disk(disk_name)
273
+ unless disk.attached
274
+ print "Disk released.\n"
275
+ break
276
+ end
277
+ sleep 10
278
+ end
279
+ if disk.attached
280
+ Loggerx.error "\nCannot delete disk #{disk_name}."
281
+ else
282
+ disk_management_service.delete_virtual_machine_disk(disk_name)
283
+ end
284
+ else
285
+ Loggerx.error "Cannot find virtual machine #{vm_name} under cloud service #{cloud_service_name}"
286
+ end
287
+ rescue
288
+ end
289
+
290
+ # Public: Shuts down the specified virtual machine.
291
+ #
292
+ # ==== Attributes
293
+ #
294
+ # * +name+ - String. Virtual machine name.
295
+ # * +cloud_service_name+ - String. Cloud service name.
296
+ #
297
+ # See http://msdn.microsoft.com/en-us/library/windowsazure/jj157195.aspx
298
+ #
299
+ # Returns NONE
300
+ def shutdown_virtual_machine(vm_name, cloud_service_name)
301
+ vm = get_virtual_machine(vm_name, cloud_service_name)
302
+ if vm
303
+ if %w(StoppedVM StoppedDeallocated).include?(vm.status)
304
+ Loggerx.error 'Cannot perform the shutdown operation on a stopped virtual machine.'
305
+ elsif vm.deployment_status == 'Running'
306
+ path = "/services/hostedservices/#{vm.cloud_service_name}/deployments/#{vm.deployment_name}/roleinstances/#{vm.vm_name}/Operations"
307
+ body = Serialization.shutdown_virtual_machine_to_xml
308
+ Loggerx.info "Shutting down virtual machine \"#{vm.vm_name}\" ..."
309
+ request = ManagementHttpRequest.new(:post, path, body)
310
+ request.call
311
+ else
312
+ Loggerx.error 'Cannot perform the shutdown operation on a stopped deployment.'
313
+ end
314
+ else
315
+ Loggerx.error "Cannot find virtual machine \"#{vm_name}\" under cloud service \"#{cloud_service_name}\". "
316
+ end
317
+ end
318
+
319
+ # Public: Starts the specified virtual machine.
320
+ #
321
+ # ==== Attributes
322
+ #
323
+ # * +name+ - String. Virtual machine name.
324
+ # * +cloud_service_name+ - String. Cloud service name.
325
+ #
326
+ # See http://msdn.microsoft.com/en-us/library/windowsazure/jj157189.aspx
327
+ #
328
+ # Returns NONE
329
+ def start_virtual_machine(vm_name, cloud_service_name)
330
+ vm = get_virtual_machine(vm_name, cloud_service_name)
331
+ if vm
332
+ if vm.status == 'ReadyRole'
333
+ Loggerx.error 'Cannot perform the start operation on started virtual machine.'
334
+ else
335
+ path = "/services/hostedservices/#{vm.cloud_service_name}/deployments/#{vm.deployment_name}/roleinstances/#{vm.vm_name}/Operations"
336
+ body = Serialization.start_virtual_machine_to_xml
337
+ Loggerx.info "Starting virtual machine \"#{vm.vm_name}\" ..."
338
+ request = ManagementHttpRequest.new(:post, path, body)
339
+ request.call
340
+ end
341
+ else
342
+ Loggerx.error "Cannot find virtual machine \"#{vm_name}\" under cloud service \"#{cloud_service_name}\"."
343
+ end
344
+ end
345
+
346
+ # Public: Restarts the specified virtual machine.
347
+ #
348
+ # ==== Attributes
349
+ #
350
+ # * +name+ - String. Virtual machine name.
351
+ # * +cloud_service_name+ - String. Cloud service name.
352
+ #
353
+ # See http://msdn.microsoft.com/en-us/library/windowsazure/jj157197.aspx
354
+ #
355
+ # Returns NONE
356
+ def restart_virtual_machine(vm_name, cloud_service_name)
357
+ vm = get_virtual_machine(vm_name, cloud_service_name)
358
+ if vm
359
+ path = "/services/hostedservices/#{vm.cloud_service_name}/deployments/#{vm.deployment_name}/roleinstances/#{vm.vm_name}/Operations"
360
+ body = Serialization.restart_virtual_machine_to_xml
361
+ Loggerx.info "Restarting virtual machine \"#{vm.vm_name}\" ..."
362
+ request = ManagementHttpRequest.new(:post, path, body)
363
+ request.call
364
+ else
365
+ Loggerx.error "Cannot find virtual machine \"#{vm_name}\" under cloud service \"#{cloud_service_name}\"."
366
+ end
367
+ end
368
+
369
+ # Public: Add/Update endpoints of virtual machine.
370
+ #
371
+ # ==== Attributes
372
+ #
373
+ # * +name+ - String. Virtual machine name.
374
+ # * +cloud_service_name+ - String. Cloud service name.
375
+ # * +input_endpoints+ - Hash. A hash of the name/value pairs for the endpoint.
376
+ #
377
+ # ==== Endpoint
378
+ #
379
+ # Accepted key/value pairs are:
380
+ # * +:local_port+ - String. Specifies the internal port on which the
381
+ # Virtual Machine is listening.
382
+ # * +:public_port+ - String. Specifies the external port to use for
383
+ # the endpoint.
384
+ # * +:name+ - String. Specifies the name of the external endpoint.
385
+ # * +load_balancer_name+ - String. Specifies a name for a set of
386
+ # load-balanced endpoints.
387
+ # * +:protocol+ - String. Specifies the transport protocol
388
+ # for the endpoint. Possible values are: TCP, UDP
389
+ # * +:direct_server_return+ - String. Specifies whether the endpoint
390
+ # uses Direct Server Return. Possible values are: true, false (optional)
391
+ # * +:load_balancer - Hash. Contains properties that define the
392
+ # endpoint settings that the load balancer uses to monitor the
393
+ # availability of the Virtual Machine (optional)
394
+ #
395
+ # === Load balancer
396
+ #
397
+ # Accepted key/value pairs are:
398
+ # * +:port+ - String. Specifies the internal port on which the
399
+ # Virtual Machine is listening.
400
+ # * +:protocol+ - String. Specifies the protocol to use to inspect the
401
+ # availability status of the virtual machine.
402
+ # * +:interval+ - String. Specifies the interval for the load balancer
403
+ # probe in seconds. (optional)
404
+ # * +:timeout+ - String. Specifies the timeout for the load balancer
405
+ # probe in seconds. (optional)
406
+ # * +:path+ - String. Specifies the relative path to inspect to
407
+ # determine the availability status of the Virtual Machine. (optional)
408
+ #
409
+ # See http://msdn.microsoft.com/en-us/library/windowsazure/jj157187.aspx
410
+ #
411
+ # Returns NONE
412
+ def update_endpoints(vm_name, cloud_service_name, *input_endpoints)
413
+ input_endpoints.flatten!
414
+ vm = get_virtual_machine(vm_name, cloud_service_name)
415
+ if vm
416
+ path = "/services/hostedservices/#{vm.cloud_service_name}/deployments/#{vm.deployment_name}/roles/#{vm_name}"
417
+ endpoints = vm.tcp_endpoints + vm.udp_endpoints
418
+ input_endpoints.each do |iep|
419
+ endpoints.delete_if { |ep| iep[:name].downcase == ep[:name].downcase }
420
+ end
421
+ endpoints += input_endpoints
422
+ body = Serialization.update_role_to_xml(endpoints, vm)
423
+ request = ManagementHttpRequest.new(:put, path, body)
424
+ Loggerx.info "Updating endpoints of virtual machine #{vm.vm_name} ..."
425
+ request.call
426
+ else
427
+ Loggerx.error "Cannot find virtual machine \"#{vm_name}\" under cloud service \"#{cloud_service_name}\"."
428
+ end
429
+ end
430
+
431
+ # Public: Delete endpoint of virtual machine.
432
+ #
433
+ # ==== Attributes
434
+ #
435
+ # * +name+ - String. Virtual machine name.
436
+ # * +cloud_service_name+ - String. Cloud service name.
437
+ # * +endpoint_name+ - String. Name of endpoint.
438
+ #
439
+ # See http://msdn.microsoft.com/en-us/library/windowsazure/jj157187.aspx
440
+ #
441
+ # Returns NONE
442
+ def delete_endpoint(vm_name, cloud_service_name, endpoint_name)
443
+ vm = get_virtual_machine(vm_name, cloud_service_name)
444
+ if vm
445
+ path = "/services/hostedservices/#{vm.cloud_service_name}/deployments/#{vm.deployment_name}/roles/#{vm_name}"
446
+ endpoints = vm.tcp_endpoints + vm.udp_endpoints
447
+ endpoints.delete_if { |ep| endpoint_name.downcase == ep[:name].downcase }
448
+ body = Serialization.update_role_to_xml(endpoints, vm)
449
+ request = ManagementHttpRequest.new(:put, path, body)
450
+ Loggerx.info "Deleting virtual machine endpoint #{endpoint_name} ..."
451
+ request.call
452
+ else
453
+ Loggerx.error "Cannot find virtual machine \"#{vm_name}\" under cloud service \"#{cloud_service_name}\"."
454
+ end
455
+ end
456
+
457
+ # Public: adds a data disk to a virtual machine.
458
+ #
459
+ # ==== Attributes
460
+ #
461
+ # * +cloud_service_name+ - String. Cloud service name.
462
+ # * +vm_name+ - String. Virtual machine name.
463
+ # * +options+ - Hash. Optional parameters.
464
+ #
465
+ # ==== Options
466
+ #
467
+ # Accepted key/value pairs in options parameter are:
468
+ # * +:import+ - Boolean. if true, then allows to use an existing
469
+ # disk by disk name. if false, then create and attach new data disk.
470
+ # * +:disk_name+ - String. Specifies the name of the disk.
471
+ # Reqruied if using existing disk.
472
+ # * +:host_caching+ - String. Specifies the caching behavior of data disk
473
+ # The default is ReadOnly. Possible values are: None, ReadOnly, ReadWrite
474
+ # * +:disk_label+ - String. Specifies the description of the data disk.
475
+ # * +:disk_size+ - String. Specifies the size of disk in GB
476
+ #
477
+ # See http://msdn.microsoft.com/en-us/library/windowsazure/jj157199.aspx
478
+ #
479
+ # Returns None
480
+ def add_data_disk(vm_name, cloud_service_name, options = {})
481
+ options[:import] ||= false
482
+ vm = get_virtual_machine(vm_name, cloud_service_name)
483
+ if vm
484
+ path = "/services/hostedservices/#{cloud_service_name}/deployments/#{vm.deployment_name}/roles/#{vm_name}/DataDisks"
485
+ body = Serialization.add_data_disk_to_xml(vm, options)
486
+ Loggerx.info "Adding data disk to virtual machine #{vm_name} ..."
487
+ request = ManagementHttpRequest.new(:post, path, body)
488
+ request.call
489
+ else
490
+ Loggerx.error "Cannot find virtual machine \"#{vm_name}\" under cloud service \"#{cloud_service_name}\"."
491
+ end
492
+ end
493
+
494
+ private
495
+
496
+ # Private: Gets the operating system type of an image.
497
+ #
498
+ # Returns Linux or Windows
499
+ def get_image(image_name)
500
+ image_service = Azure::VirtualMachineImageManagementService.new
501
+ image = image_service.list_virtual_machine_images.select { |x| x.name.casecmp(image_name.to_s) == 0 }.first
502
+ Loggerx.error_with_exit 'The virtual machine image source is not valid.' unless image
503
+ image
504
+ end
505
+
506
+ def generate_cloud_service_name(vm_name)
507
+ random_string(vm_name + '-service-')
508
+ end
509
+
510
+ def generate_storage_account_name(vm_name)
511
+ random_string(vm_name + 'storage').gsub(/[^0-9a-z ]/i, '').downcase[0..23]
512
+ end
513
+
514
+ def validate_deployment_params(params, options, add_role = false)
515
+ errors = []
516
+ params_keys = %w(vm_name image vm_user)
517
+ params_keys += ['password'] if options[:os_type] == 'Windows'
518
+ options_keys = []
519
+ options_keys = %w(private_key_file certificate_file) if certificate_required?(params, options)
520
+ if add_role
521
+ params_keys += ['cloud_service_name']
522
+ else
523
+ params_keys += ['location']
524
+ end
525
+ params_keys.each do |key|
526
+ errors << key if params[key.to_sym].nil?
527
+ end
528
+
529
+ options_keys.each do |key|
530
+ errors << key if options[key.to_sym].nil?
531
+ end
532
+
533
+ if errors.empty?
534
+ validate_location(params[:location]) unless add_role
535
+ validate_role_size(options[:vm_size])
536
+ params[:certificate] = {}
537
+ if certificate_required?(params, options)
538
+ begin
539
+ params[:certificate][:key] = OpenSSL::PKey.read File.read(options[:private_key_file])
540
+ params[:certificate][:cert] = OpenSSL::X509::Certificate.new File.read(options[:certificate_file])
541
+ params[:certificate][:fingerprint] = export_fingerprint(params[:certificate][:cert])
542
+ rescue Exception => e
543
+ Loggerx.error_with_exit e.message
544
+ end
545
+ end
546
+ else
547
+ Loggerx.error_with_exit "You did not provide a valid '#{errors.uniq.join(", ")}' value."
548
+ end
549
+ end
550
+
551
+ def certificate_required?(params, options)
552
+ if options[:os_type] == 'Linux'
553
+ (params[:password].nil? or (!options[:certificate_file].nil? && !options[:private_key_file].nil?))
554
+ else
555
+ winrm_with_https(options)
556
+ end
557
+ end
558
+
559
+ def winrm_with_https(options)
560
+ if options[:os_type] == 'Windows'
561
+ options[:winrm_transport] && options[:winrm_transport].include?('https') && options[:certificate_file] && options[:private_key_file]
562
+ end
563
+ end
564
+
565
+ def validate_role_size(vm_size)
566
+ valid_role_sizes = %w(
567
+ Basic_A0 Basic_A1 Basic_A2 Basic_A3 Basic_A4
568
+ ExtraSmall Small Medium Large ExtraLarge A5 A6 A7 A8 A9 A10 A11
569
+ Standard_D1 Standard_D2 Standard_D3 Standard_D4 Standard_D11 Standard_D12 Standard_D13 Standard_D14
570
+ Standard_DS1 Standard_DS2 Standard_DS3 Standard_DS4 Standard_DS11 Standard_DS12 Standard_DS13 Standard_DS14
571
+ Standard_G1 Standard_G2 Standard_G3 Standard_G4 Standard_G5
572
+ )
573
+ if vm_size && !valid_role_sizes.include?(vm_size)
574
+ Loggerx.error_with_exit "Value '#{vm_size}' specified for parameter 'vm_size' is invalid. Allowed values are '#{valid_role_sizes.join(',')}'"
575
+ end
576
+ end
577
+
578
+ def validate_location(location_name)
579
+ locations = Azure::BaseManagementService.new.list_locations
580
+ location = locations.select { |loc| loc.name.downcase == location_name.downcase }.first
581
+ if location.nil?
582
+ Loggerx.error_with_exit "Value '#{location_name}' specified for parameter 'location' is invalid. Allowed values are #{locations.map(&:name).join(',')}"
583
+ elsif !location.available_services.include?('PersistentVMRole')
584
+ Loggerx.error_with_exit "Persistentvmrole not enabled for \"#{location.name}\". Try different location"
585
+ end
586
+ end
587
+ end
588
+ end
589
589
  end