mtncloud-cli 1.0.0

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 (499) hide show
  1. checksums.yaml +7 -0
  2. data/.dockerignore +20 -0
  3. data/.github/pull_request_template.md +14 -0
  4. data/.github/workflows/ci.yml +56 -0
  5. data/.github/workflows/release.yml +46 -0
  6. data/.gitignore +25 -0
  7. data/CLAUDE.md +24 -0
  8. data/CONTRIBUTING.md +91 -0
  9. data/Dockerfile +19 -0
  10. data/Gemfile +4 -0
  11. data/LICENSE.txt +23 -0
  12. data/README.md +187 -0
  13. data/Rakefile +26 -0
  14. data/bin/mcs +3 -0
  15. data/bin/mtncloud +27 -0
  16. data/lib/mtncloud/api/account_groups_interface.rb +48 -0
  17. data/lib/mtncloud/api/account_users_interface.rb +68 -0
  18. data/lib/mtncloud/api/accounts_interface.rb +9 -0
  19. data/lib/mtncloud/api/activity_interface.rb +9 -0
  20. data/lib/mtncloud/api/affinity_groups_interface.rb +46 -0
  21. data/lib/mtncloud/api/api_client.rb +1091 -0
  22. data/lib/mtncloud/api/appliance_settings_interface.rb +49 -0
  23. data/lib/mtncloud/api/approvals_interface.rb +32 -0
  24. data/lib/mtncloud/api/apps_interface.rb +180 -0
  25. data/lib/mtncloud/api/archive_buckets_interface.rb +116 -0
  26. data/lib/mtncloud/api/archive_files_interface.rb +173 -0
  27. data/lib/mtncloud/api/audit_interface.rb +9 -0
  28. data/lib/mtncloud/api/auth_interface.rb +58 -0
  29. data/lib/mtncloud/api/backup_jobs_interface.rb +13 -0
  30. data/lib/mtncloud/api/backup_restores_interface.rb +27 -0
  31. data/lib/mtncloud/api/backup_results_interface.rb +32 -0
  32. data/lib/mtncloud/api/backup_service_types_interface.rb +9 -0
  33. data/lib/mtncloud/api/backup_services_interface.rb +9 -0
  34. data/lib/mtncloud/api/backup_settings_interface.rb +20 -0
  35. data/lib/mtncloud/api/backup_types_interface.rb +9 -0
  36. data/lib/mtncloud/api/backups_interface.rb +21 -0
  37. data/lib/mtncloud/api/billing_interface.rb +34 -0
  38. data/lib/mtncloud/api/blueprints_interface.rb +70 -0
  39. data/lib/mtncloud/api/body_io.rb +22 -0
  40. data/lib/mtncloud/api/budgets_interface.rb +48 -0
  41. data/lib/mtncloud/api/catalog_item_types_interface.rb +29 -0
  42. data/lib/mtncloud/api/certificate_types_interface.rb +14 -0
  43. data/lib/mtncloud/api/certificates_interface.rb +9 -0
  44. data/lib/mtncloud/api/clients_interface.rb +41 -0
  45. data/lib/mtncloud/api/cloud_datastores_interface.rb +48 -0
  46. data/lib/mtncloud/api/cloud_folders_interface.rb +41 -0
  47. data/lib/mtncloud/api/cloud_policies_interface.rb +41 -0
  48. data/lib/mtncloud/api/cloud_resource_pools_interface.rb +66 -0
  49. data/lib/mtncloud/api/clouds_interface.rb +217 -0
  50. data/lib/mtncloud/api/clusters_interface.rb +471 -0
  51. data/lib/mtncloud/api/containers_interface.rb +145 -0
  52. data/lib/mtncloud/api/credential_types_interface.rb +9 -0
  53. data/lib/mtncloud/api/credentials_interface.rb +9 -0
  54. data/lib/mtncloud/api/custom_instance_types_interface.rb +99 -0
  55. data/lib/mtncloud/api/cypher_interface.rb +51 -0
  56. data/lib/mtncloud/api/dashboard_interface.rb +14 -0
  57. data/lib/mtncloud/api/datastores_interface.rb +21 -0
  58. data/lib/mtncloud/api/deploy_interface.rb +44 -0
  59. data/lib/mtncloud/api/deployments_interface.rb +79 -0
  60. data/lib/mtncloud/api/distributed_workers_interface.rb +41 -0
  61. data/lib/mtncloud/api/email_templates_interface.rb +53 -0
  62. data/lib/mtncloud/api/environments_interface.rb +48 -0
  63. data/lib/mtncloud/api/execute_schedules_interface.rb +71 -0
  64. data/lib/mtncloud/api/execution_request_interface.rb +27 -0
  65. data/lib/mtncloud/api/file_copy_request_interface.rb +68 -0
  66. data/lib/mtncloud/api/forgot_password_interface.rb +17 -0
  67. data/lib/mtncloud/api/group_policies_interface.rb +41 -0
  68. data/lib/mtncloud/api/groups_interface.rb +73 -0
  69. data/lib/mtncloud/api/guidance_interface.rb +44 -0
  70. data/lib/mtncloud/api/guidance_settings_interface.rb +17 -0
  71. data/lib/mtncloud/api/health_interface.rb +100 -0
  72. data/lib/mtncloud/api/host_vm_groups_interface.rb +37 -0
  73. data/lib/mtncloud/api/hub_interface.rb +25 -0
  74. data/lib/mtncloud/api/image_builder_boot_scripts_interface.rb +41 -0
  75. data/lib/mtncloud/api/image_builder_image_builds_interface.rb +73 -0
  76. data/lib/mtncloud/api/image_builder_interface.rb +20 -0
  77. data/lib/mtncloud/api/image_builder_preseed_scripts_interface.rb +41 -0
  78. data/lib/mtncloud/api/instance_types_interface.rb +20 -0
  79. data/lib/mtncloud/api/instances_interface.rb +453 -0
  80. data/lib/mtncloud/api/integration_types_interface.rb +14 -0
  81. data/lib/mtncloud/api/integrations_interface.rb +74 -0
  82. data/lib/mtncloud/api/invoice_line_items_interface.rb +9 -0
  83. data/lib/mtncloud/api/invoices_interface.rb +28 -0
  84. data/lib/mtncloud/api/jobs_interface.rb +83 -0
  85. data/lib/mtncloud/api/key_pairs_interface.rb +57 -0
  86. data/lib/mtncloud/api/library_cluster_layouts_interface.rb +47 -0
  87. data/lib/mtncloud/api/library_cluster_packages_interface.rb +60 -0
  88. data/lib/mtncloud/api/library_container_scripts_interface.rb +43 -0
  89. data/lib/mtncloud/api/library_container_templates_interface.rb +43 -0
  90. data/lib/mtncloud/api/library_container_types_interface.rb +59 -0
  91. data/lib/mtncloud/api/library_container_upgrades_interface.rb +60 -0
  92. data/lib/mtncloud/api/library_instance_types_interface.rb +74 -0
  93. data/lib/mtncloud/api/library_layouts_interface.rb +69 -0
  94. data/lib/mtncloud/api/library_operating_systems_interface.rb +63 -0
  95. data/lib/mtncloud/api/library_spec_template_types_interface.rb +43 -0
  96. data/lib/mtncloud/api/library_spec_templates_interface.rb +43 -0
  97. data/lib/mtncloud/api/license_interface.rb +30 -0
  98. data/lib/mtncloud/api/load_balancer_monitors_interface.rb +9 -0
  99. data/lib/mtncloud/api/load_balancer_pool_nodes_interface.rb +8 -0
  100. data/lib/mtncloud/api/load_balancer_pools_interface.rb +9 -0
  101. data/lib/mtncloud/api/load_balancer_pools_secondary_interface.rb +9 -0
  102. data/lib/mtncloud/api/load_balancer_profiles_interface.rb +9 -0
  103. data/lib/mtncloud/api/load_balancer_types_interface.rb +9 -0
  104. data/lib/mtncloud/api/load_balancer_virtual_servers_interface.rb +18 -0
  105. data/lib/mtncloud/api/load_balancers_interface.rb +14 -0
  106. data/lib/mtncloud/api/log_settings_interface.rb +44 -0
  107. data/lib/mtncloud/api/logs_interface.rb +37 -0
  108. data/lib/mtncloud/api/migrations_interface.rb +49 -0
  109. data/lib/mtncloud/api/monitoring_alerts_interface.rb +39 -0
  110. data/lib/mtncloud/api/monitoring_apps_interface.rb +69 -0
  111. data/lib/mtncloud/api/monitoring_checks_interface.rb +103 -0
  112. data/lib/mtncloud/api/monitoring_contacts_interface.rb +41 -0
  113. data/lib/mtncloud/api/monitoring_groups_interface.rb +77 -0
  114. data/lib/mtncloud/api/monitoring_incidents_interface.rb +107 -0
  115. data/lib/mtncloud/api/monitoring_interface.rb +35 -0
  116. data/lib/mtncloud/api/monitoring_settings_interface.rb +21 -0
  117. data/lib/mtncloud/api/network_dhcp_relays_interface.rb +36 -0
  118. data/lib/mtncloud/api/network_dhcp_servers_interface.rb +36 -0
  119. data/lib/mtncloud/api/network_domain_records_interface.rb +41 -0
  120. data/lib/mtncloud/api/network_domains_interface.rb +41 -0
  121. data/lib/mtncloud/api/network_edge_clusters_interface.rb +26 -0
  122. data/lib/mtncloud/api/network_floating_ips_interface.rb +40 -0
  123. data/lib/mtncloud/api/network_groups_interface.rb +41 -0
  124. data/lib/mtncloud/api/network_pool_ips_interface.rb +41 -0
  125. data/lib/mtncloud/api/network_pool_server_types_interface.rb +9 -0
  126. data/lib/mtncloud/api/network_pool_servers_interface.rb +48 -0
  127. data/lib/mtncloud/api/network_pools_interface.rb +41 -0
  128. data/lib/mtncloud/api/network_proxies_interface.rb +41 -0
  129. data/lib/mtncloud/api/network_routers_interface.rb +181 -0
  130. data/lib/mtncloud/api/network_security_server_types_interface.rb +9 -0
  131. data/lib/mtncloud/api/network_security_servers_interface.rb +27 -0
  132. data/lib/mtncloud/api/network_server_groups_interface.rb +7 -0
  133. data/lib/mtncloud/api/network_server_types_interface.rb +9 -0
  134. data/lib/mtncloud/api/network_servers_interface.rb +102 -0
  135. data/lib/mtncloud/api/network_services_interface.rb +63 -0
  136. data/lib/mtncloud/api/network_static_routes_interface.rb +36 -0
  137. data/lib/mtncloud/api/network_subnets_interface.rb +42 -0
  138. data/lib/mtncloud/api/network_types_interface.rb +20 -0
  139. data/lib/mtncloud/api/networks_interface.rb +48 -0
  140. data/lib/mtncloud/api/option_type_forms_interface.rb +9 -0
  141. data/lib/mtncloud/api/option_type_lists_interface.rb +53 -0
  142. data/lib/mtncloud/api/option_types_interface.rb +41 -0
  143. data/lib/mtncloud/api/options_interface.rb +17 -0
  144. data/lib/mtncloud/api/packages_interface.rb +112 -0
  145. data/lib/mtncloud/api/ping_interface.rb +22 -0
  146. data/lib/mtncloud/api/plugins_interface.rb +22 -0
  147. data/lib/mtncloud/api/policies_interface.rb +56 -0
  148. data/lib/mtncloud/api/power_schedules_interface.rb +71 -0
  149. data/lib/mtncloud/api/price_sets_interface.rb +39 -0
  150. data/lib/mtncloud/api/prices_interface.rb +71 -0
  151. data/lib/mtncloud/api/processes_interface.rb +40 -0
  152. data/lib/mtncloud/api/projects_interface.rb +33 -0
  153. data/lib/mtncloud/api/provision_types_interface.rb +24 -0
  154. data/lib/mtncloud/api/provisioning_license_types_interface.rb +31 -0
  155. data/lib/mtncloud/api/provisioning_licenses_interface.rb +60 -0
  156. data/lib/mtncloud/api/provisioning_settings_interface.rb +26 -0
  157. data/lib/mtncloud/api/read_interface.rb +24 -0
  158. data/lib/mtncloud/api/reports_interface.rb +70 -0
  159. data/lib/mtncloud/api/resource_pool_groups_interface.rb +51 -0
  160. data/lib/mtncloud/api/rest_interface.rb +37 -0
  161. data/lib/mtncloud/api/roles_interface.rb +151 -0
  162. data/lib/mtncloud/api/scale_thresholds_interface.rb +9 -0
  163. data/lib/mtncloud/api/search_interface.rb +13 -0
  164. data/lib/mtncloud/api/secondary_read_interface.rb +25 -0
  165. data/lib/mtncloud/api/secondary_rest_interface.rb +42 -0
  166. data/lib/mtncloud/api/security_group_rules_interface.rb +35 -0
  167. data/lib/mtncloud/api/security_groups_interface.rb +56 -0
  168. data/lib/mtncloud/api/security_package_types_interface.rb +9 -0
  169. data/lib/mtncloud/api/security_packages_interface.rb +9 -0
  170. data/lib/mtncloud/api/security_scans_interface.rb +9 -0
  171. data/lib/mtncloud/api/server_devices_interface.rb +30 -0
  172. data/lib/mtncloud/api/server_types_interface.rb +20 -0
  173. data/lib/mtncloud/api/servers_interface.rb +230 -0
  174. data/lib/mtncloud/api/service_catalog_interface.rb +89 -0
  175. data/lib/mtncloud/api/service_plans_interface.rb +62 -0
  176. data/lib/mtncloud/api/setup_interface.rb +46 -0
  177. data/lib/mtncloud/api/snapshots_interface.rb +19 -0
  178. data/lib/mtncloud/api/storage_datastores_interface.rb +44 -0
  179. data/lib/mtncloud/api/storage_providers_interface.rb +151 -0
  180. data/lib/mtncloud/api/storage_server_types_interface.rb +14 -0
  181. data/lib/mtncloud/api/storage_servers_interface.rb +9 -0
  182. data/lib/mtncloud/api/storage_volume_types_interface.rb +9 -0
  183. data/lib/mtncloud/api/storage_volumes_interface.rb +24 -0
  184. data/lib/mtncloud/api/subnet_types_interface.rb +20 -0
  185. data/lib/mtncloud/api/subnets_interface.rb +41 -0
  186. data/lib/mtncloud/api/support_bundles_interface.rb +46 -0
  187. data/lib/mtncloud/api/system_types_interface.rb +13 -0
  188. data/lib/mtncloud/api/systems_interface.rb +55 -0
  189. data/lib/mtncloud/api/task_sets_interface.rb +52 -0
  190. data/lib/mtncloud/api/tasks_interface.rb +66 -0
  191. data/lib/mtncloud/api/tokens_interface.rb +39 -0
  192. data/lib/mtncloud/api/usage_interface.rb +18 -0
  193. data/lib/mtncloud/api/user_groups_interface.rb +59 -0
  194. data/lib/mtncloud/api/user_settings_interface.rb +90 -0
  195. data/lib/mtncloud/api/user_sources_interface.rb +99 -0
  196. data/lib/mtncloud/api/users_interface.rb +33 -0
  197. data/lib/mtncloud/api/vdi_allocations_interface.rb +9 -0
  198. data/lib/mtncloud/api/vdi_apps_interface.rb +9 -0
  199. data/lib/mtncloud/api/vdi_gateways_interface.rb +9 -0
  200. data/lib/mtncloud/api/vdi_interface.rb +28 -0
  201. data/lib/mtncloud/api/vdi_pools_interface.rb +19 -0
  202. data/lib/mtncloud/api/virtual_images_interface.rb +210 -0
  203. data/lib/mtncloud/api/virtual_servers_interface.rb +9 -0
  204. data/lib/mtncloud/api/virtual_switches_interface.rb +9 -0
  205. data/lib/mtncloud/api/whitelabel_settings_interface.rb +57 -0
  206. data/lib/mtncloud/api/whoami_interface.rb +13 -0
  207. data/lib/mtncloud/api/wiki_interface.rb +48 -0
  208. data/lib/mtncloud/api.rb +12 -0
  209. data/lib/mtncloud/benchmarking.rb +259 -0
  210. data/lib/mtncloud/cli/cli_command.rb +2281 -0
  211. data/lib/mtncloud/cli/cli_registry.rb +337 -0
  212. data/lib/mtncloud/cli/commands/access_token_command.rb +201 -0
  213. data/lib/mtncloud/cli/commands/account_groups_command.rb +530 -0
  214. data/lib/mtncloud/cli/commands/activity_command.rb +149 -0
  215. data/lib/mtncloud/cli/commands/affinity_groups_command.rb +554 -0
  216. data/lib/mtncloud/cli/commands/alias_command.rb +278 -0
  217. data/lib/mtncloud/cli/commands/appliance_settings_command.rb +382 -0
  218. data/lib/mtncloud/cli/commands/approvals_command.rb +236 -0
  219. data/lib/mtncloud/cli/commands/apps.rb +2549 -0
  220. data/lib/mtncloud/cli/commands/archives_command.rb +2161 -0
  221. data/lib/mtncloud/cli/commands/audit.rb +188 -0
  222. data/lib/mtncloud/cli/commands/backup_jobs_command.rb +366 -0
  223. data/lib/mtncloud/cli/commands/backup_restores_command.rb +144 -0
  224. data/lib/mtncloud/cli/commands/backup_results_command.rb +149 -0
  225. data/lib/mtncloud/cli/commands/backup_services_command.rb +44 -0
  226. data/lib/mtncloud/cli/commands/backup_settings_command.rb +184 -0
  227. data/lib/mtncloud/cli/commands/backup_types_command.rb +53 -0
  228. data/lib/mtncloud/cli/commands/backups_command.rb +674 -0
  229. data/lib/mtncloud/cli/commands/benchmark_command.rb +458 -0
  230. data/lib/mtncloud/cli/commands/blueprints_command.rb +2297 -0
  231. data/lib/mtncloud/cli/commands/boot_scripts_command.rb +379 -0
  232. data/lib/mtncloud/cli/commands/budgets_command.rb +754 -0
  233. data/lib/mtncloud/cli/commands/cat_command.rb +45 -0
  234. data/lib/mtncloud/cli/commands/catalog_item_types_command.rb +858 -0
  235. data/lib/mtncloud/cli/commands/certificates_command.rb +575 -0
  236. data/lib/mtncloud/cli/commands/change_password_command.rb +132 -0
  237. data/lib/mtncloud/cli/commands/clients_command.rb +331 -0
  238. data/lib/mtncloud/cli/commands/cloud_datastores_command.rb +543 -0
  239. data/lib/mtncloud/cli/commands/cloud_folders_command.rb +512 -0
  240. data/lib/mtncloud/cli/commands/cloud_resource_pools_command.rb +870 -0
  241. data/lib/mtncloud/cli/commands/clouds.rb +2037 -0
  242. data/lib/mtncloud/cli/commands/clouds_types.rb +140 -0
  243. data/lib/mtncloud/cli/commands/cluster_types.rb +179 -0
  244. data/lib/mtncloud/cli/commands/clusters.rb +5855 -0
  245. data/lib/mtncloud/cli/commands/coloring_command.rb +82 -0
  246. data/lib/mtncloud/cli/commands/containers_command.rb +967 -0
  247. data/lib/mtncloud/cli/commands/credential_types_command.rb +36 -0
  248. data/lib/mtncloud/cli/commands/credentials_command.rb +124 -0
  249. data/lib/mtncloud/cli/commands/curl_command.rb +168 -0
  250. data/lib/mtncloud/cli/commands/cypher_command.rb +587 -0
  251. data/lib/mtncloud/cli/commands/dashboard_command.rb +300 -0
  252. data/lib/mtncloud/cli/commands/debug_command.rb +75 -0
  253. data/lib/mtncloud/cli/commands/deploy.rb +485 -0
  254. data/lib/mtncloud/cli/commands/deployments.rb +923 -0
  255. data/lib/mtncloud/cli/commands/deploys.rb +485 -0
  256. data/lib/mtncloud/cli/commands/distributed_workers_command.rb +282 -0
  257. data/lib/mtncloud/cli/commands/echo_command.rb +61 -0
  258. data/lib/mtncloud/cli/commands/edit_profile_command.rb +57 -0
  259. data/lib/mtncloud/cli/commands/edit_rc_command.rb +77 -0
  260. data/lib/mtncloud/cli/commands/email_templates_command.rb +373 -0
  261. data/lib/mtncloud/cli/commands/environments_command.rb +401 -0
  262. data/lib/mtncloud/cli/commands/execute_schedules_command.rb +735 -0
  263. data/lib/mtncloud/cli/commands/execution_request_command.rb +333 -0
  264. data/lib/mtncloud/cli/commands/exit_command.rb +34 -0
  265. data/lib/mtncloud/cli/commands/file_copy_request_command.rb +352 -0
  266. data/lib/mtncloud/cli/commands/forgot_password.rb +133 -0
  267. data/lib/mtncloud/cli/commands/get_prompt_command.rb +36 -0
  268. data/lib/mtncloud/cli/commands/groups.rb +818 -0
  269. data/lib/mtncloud/cli/commands/guidance_command.rb +529 -0
  270. data/lib/mtncloud/cli/commands/guidance_settings.rb +148 -0
  271. data/lib/mtncloud/cli/commands/health_command.rb +1046 -0
  272. data/lib/mtncloud/cli/commands/history_command.rb +60 -0
  273. data/lib/mtncloud/cli/commands/host_vm_groups_command.rb +423 -0
  274. data/lib/mtncloud/cli/commands/hosts.rb +2986 -0
  275. data/lib/mtncloud/cli/commands/hub.rb +215 -0
  276. data/lib/mtncloud/cli/commands/image_builder_command.rb +1197 -0
  277. data/lib/mtncloud/cli/commands/instance_types.rb +163 -0
  278. data/lib/mtncloud/cli/commands/instances.rb +5813 -0
  279. data/lib/mtncloud/cli/commands/integrations_command.rb +1412 -0
  280. data/lib/mtncloud/cli/commands/invoices_command.rb +1151 -0
  281. data/lib/mtncloud/cli/commands/jobs_command.rb +998 -0
  282. data/lib/mtncloud/cli/commands/key_pairs.rb +470 -0
  283. data/lib/mtncloud/cli/commands/library_cluster_layouts_command.rb +901 -0
  284. data/lib/mtncloud/cli/commands/library_cluster_packages_command.rb +552 -0
  285. data/lib/mtncloud/cli/commands/library_container_scripts_command.rb +446 -0
  286. data/lib/mtncloud/cli/commands/library_container_templates_command.rb +526 -0
  287. data/lib/mtncloud/cli/commands/library_container_types_command.rb +698 -0
  288. data/lib/mtncloud/cli/commands/library_forms_command.rb +625 -0
  289. data/lib/mtncloud/cli/commands/library_instance_types_command.rb +668 -0
  290. data/lib/mtncloud/cli/commands/library_layouts_command.rb +849 -0
  291. data/lib/mtncloud/cli/commands/library_operating_systems_command.rb +671 -0
  292. data/lib/mtncloud/cli/commands/library_option_lists_command.rb +503 -0
  293. data/lib/mtncloud/cli/commands/library_option_types_command.rb +329 -0
  294. data/lib/mtncloud/cli/commands/library_spec_templates_command.rb +547 -0
  295. data/lib/mtncloud/cli/commands/library_upgrades_command.rb +596 -0
  296. data/lib/mtncloud/cli/commands/license.rb +475 -0
  297. data/lib/mtncloud/cli/commands/load_balancer_monitors.rb +70 -0
  298. data/lib/mtncloud/cli/commands/load_balancer_pool_nodes.rb +87 -0
  299. data/lib/mtncloud/cli/commands/load_balancer_pools.rb +129 -0
  300. data/lib/mtncloud/cli/commands/load_balancer_profiles.rb +64 -0
  301. data/lib/mtncloud/cli/commands/load_balancer_types.rb +38 -0
  302. data/lib/mtncloud/cli/commands/load_balancer_virtual_servers.rb +147 -0
  303. data/lib/mtncloud/cli/commands/load_balancers.rb +189 -0
  304. data/lib/mtncloud/cli/commands/log_level_command.rb +54 -0
  305. data/lib/mtncloud/cli/commands/log_settings_command.rb +443 -0
  306. data/lib/mtncloud/cli/commands/login.rb +148 -0
  307. data/lib/mtncloud/cli/commands/logout.rb +63 -0
  308. data/lib/mtncloud/cli/commands/logs_command.rb +140 -0
  309. data/lib/mtncloud/cli/commands/man_command.rb +409 -0
  310. data/lib/mtncloud/cli/commands/migrations.rb +453 -0
  311. data/lib/mtncloud/cli/commands/monitoring_alerts_command.rb +791 -0
  312. data/lib/mtncloud/cli/commands/monitoring_apps_command.rb +716 -0
  313. data/lib/mtncloud/cli/commands/monitoring_checks_command.rb +766 -0
  314. data/lib/mtncloud/cli/commands/monitoring_contacts_command.rb +339 -0
  315. data/lib/mtncloud/cli/commands/monitoring_groups_command.rb +674 -0
  316. data/lib/mtncloud/cli/commands/monitoring_incidents_command.rb +835 -0
  317. data/lib/mtncloud/cli/commands/monitoring_settings.rb +212 -0
  318. data/lib/mtncloud/cli/commands/network_dhcp_relays_command.rb +375 -0
  319. data/lib/mtncloud/cli/commands/network_dhcp_servers_command.rb +366 -0
  320. data/lib/mtncloud/cli/commands/network_domains_command.rb +896 -0
  321. data/lib/mtncloud/cli/commands/network_edge_clusters_command.rb +288 -0
  322. data/lib/mtncloud/cli/commands/network_firewalls_command.rb +783 -0
  323. data/lib/mtncloud/cli/commands/network_floating_ips.rb +147 -0
  324. data/lib/mtncloud/cli/commands/network_groups_command.rb +654 -0
  325. data/lib/mtncloud/cli/commands/network_pool_server_types.rb +20 -0
  326. data/lib/mtncloud/cli/commands/network_pool_servers_command.rb +318 -0
  327. data/lib/mtncloud/cli/commands/network_pools_command.rb +903 -0
  328. data/lib/mtncloud/cli/commands/network_proxies_command.rb +578 -0
  329. data/lib/mtncloud/cli/commands/network_routers_command.rb +2628 -0
  330. data/lib/mtncloud/cli/commands/network_security_server_types.rb +20 -0
  331. data/lib/mtncloud/cli/commands/network_server_groups_command.rb +222 -0
  332. data/lib/mtncloud/cli/commands/network_server_types_command.rb +20 -0
  333. data/lib/mtncloud/cli/commands/network_servers_command.rb +398 -0
  334. data/lib/mtncloud/cli/commands/network_services_command.rb +198 -0
  335. data/lib/mtncloud/cli/commands/network_static_routes_command.rb +451 -0
  336. data/lib/mtncloud/cli/commands/network_transport_zones_command.rb +412 -0
  337. data/lib/mtncloud/cli/commands/networks_command.rb +1692 -0
  338. data/lib/mtncloud/cli/commands/open_command.rb +30 -0
  339. data/lib/mtncloud/cli/commands/options.rb +231 -0
  340. data/lib/mtncloud/cli/commands/packages_command.rb +822 -0
  341. data/lib/mtncloud/cli/commands/ping.rb +242 -0
  342. data/lib/mtncloud/cli/commands/plugins.rb +214 -0
  343. data/lib/mtncloud/cli/commands/policies_command.rb +990 -0
  344. data/lib/mtncloud/cli/commands/power_schedules_command.rb +731 -0
  345. data/lib/mtncloud/cli/commands/preseed_scripts_command.rb +378 -0
  346. data/lib/mtncloud/cli/commands/price_sets_command.rb +557 -0
  347. data/lib/mtncloud/cli/commands/prices_command.rb +692 -0
  348. data/lib/mtncloud/cli/commands/processes_command.rb +469 -0
  349. data/lib/mtncloud/cli/commands/projects_command.rb +537 -0
  350. data/lib/mtncloud/cli/commands/provisioning_licenses_command.rb +509 -0
  351. data/lib/mtncloud/cli/commands/provisioning_settings_command.rb +238 -0
  352. data/lib/mtncloud/cli/commands/recent_activity_command.rb +171 -0
  353. data/lib/mtncloud/cli/commands/remote.rb +1818 -0
  354. data/lib/mtncloud/cli/commands/reports_command.rb +724 -0
  355. data/lib/mtncloud/cli/commands/resource_pool_groups_command.rb +586 -0
  356. data/lib/mtncloud/cli/commands/rm_command.rb +14 -0
  357. data/lib/mtncloud/cli/commands/roles.rb +3120 -0
  358. data/lib/mtncloud/cli/commands/scale_thresholds.rb +103 -0
  359. data/lib/mtncloud/cli/commands/search_command.rb +184 -0
  360. data/lib/mtncloud/cli/commands/security_group_rules.rb +230 -0
  361. data/lib/mtncloud/cli/commands/security_groups.rb +1294 -0
  362. data/lib/mtncloud/cli/commands/security_package_types.rb +32 -0
  363. data/lib/mtncloud/cli/commands/security_packages.rb +84 -0
  364. data/lib/mtncloud/cli/commands/security_scans.rb +107 -0
  365. data/lib/mtncloud/cli/commands/self_service_command.rb +17 -0
  366. data/lib/mtncloud/cli/commands/server_devices_command.rb +207 -0
  367. data/lib/mtncloud/cli/commands/service_catalog_command.rb +1528 -0
  368. data/lib/mtncloud/cli/commands/service_plans_command.rb +895 -0
  369. data/lib/mtncloud/cli/commands/set_prompt_command.rb +51 -0
  370. data/lib/mtncloud/cli/commands/setup.rb +423 -0
  371. data/lib/mtncloud/cli/commands/shell.rb +717 -0
  372. data/lib/mtncloud/cli/commands/sleep_command.rb +43 -0
  373. data/lib/mtncloud/cli/commands/snapshots.rb +156 -0
  374. data/lib/mtncloud/cli/commands/source_command.rb +30 -0
  375. data/lib/mtncloud/cli/commands/ssl_verification_command.rb +47 -0
  376. data/lib/mtncloud/cli/commands/storage_datastores.rb +457 -0
  377. data/lib/mtncloud/cli/commands/storage_providers_command.rb +1401 -0
  378. data/lib/mtncloud/cli/commands/storage_server_types.rb +45 -0
  379. data/lib/mtncloud/cli/commands/storage_servers.rb +116 -0
  380. data/lib/mtncloud/cli/commands/storage_volume_types.rb +45 -0
  381. data/lib/mtncloud/cli/commands/storage_volumes.rb +236 -0
  382. data/lib/mtncloud/cli/commands/subnets_command.rb +819 -0
  383. data/lib/mtncloud/cli/commands/support_bundles_command.rb +606 -0
  384. data/lib/mtncloud/cli/commands/systems.rb +1203 -0
  385. data/lib/mtncloud/cli/commands/tasks.rb +1391 -0
  386. data/lib/mtncloud/cli/commands/tee_command.rb +14 -0
  387. data/lib/mtncloud/cli/commands/tenants_command.rb +315 -0
  388. data/lib/mtncloud/cli/commands/tokens_command.rb +391 -0
  389. data/lib/mtncloud/cli/commands/update_command.rb +46 -0
  390. data/lib/mtncloud/cli/commands/usage_command.rb +203 -0
  391. data/lib/mtncloud/cli/commands/user_groups_command.rb +512 -0
  392. data/lib/mtncloud/cli/commands/user_settings_command.rb +849 -0
  393. data/lib/mtncloud/cli/commands/user_sources_command.rb +1065 -0
  394. data/lib/mtncloud/cli/commands/users.rb +897 -0
  395. data/lib/mtncloud/cli/commands/vdi_allocations_command.rb +159 -0
  396. data/lib/mtncloud/cli/commands/vdi_apps_command.rb +317 -0
  397. data/lib/mtncloud/cli/commands/vdi_command.rb +359 -0
  398. data/lib/mtncloud/cli/commands/vdi_gateways_command.rb +290 -0
  399. data/lib/mtncloud/cli/commands/vdi_pools_command.rb +574 -0
  400. data/lib/mtncloud/cli/commands/version_command.rb +38 -0
  401. data/lib/mtncloud/cli/commands/view.rb +107 -0
  402. data/lib/mtncloud/cli/commands/virtual_images.rb +1362 -0
  403. data/lib/mtncloud/cli/commands/virtual_switches_command.rb +336 -0
  404. data/lib/mtncloud/cli/commands/whitelabel_settings_command.rb +653 -0
  405. data/lib/mtncloud/cli/commands/whoami.rb +323 -0
  406. data/lib/mtncloud/cli/commands/wiki_command.rb +448 -0
  407. data/lib/mtncloud/cli/commands/workflows.rb +1022 -0
  408. data/lib/mtncloud/cli/credentials.rb +482 -0
  409. data/lib/mtncloud/cli/dot_file.rb +180 -0
  410. data/lib/mtncloud/cli/error_handler.rb +307 -0
  411. data/lib/mtncloud/cli/errors.rb +53 -0
  412. data/lib/mtncloud/cli/expression_parser.rb +153 -0
  413. data/lib/mtncloud/cli/mixins/accounts_helper.rb +484 -0
  414. data/lib/mtncloud/cli/mixins/affinity_helper.rb +118 -0
  415. data/lib/mtncloud/cli/mixins/backups_helper.rb +200 -0
  416. data/lib/mtncloud/cli/mixins/deployments_helper.rb +163 -0
  417. data/lib/mtncloud/cli/mixins/execution_request_helper.rb +50 -0
  418. data/lib/mtncloud/cli/mixins/infrastructure_helper.rb +966 -0
  419. data/lib/mtncloud/cli/mixins/jobs_helper.rb +202 -0
  420. data/lib/mtncloud/cli/mixins/library_helper.rb +539 -0
  421. data/lib/mtncloud/cli/mixins/load_balancers_helper.rb +176 -0
  422. data/lib/mtncloud/cli/mixins/logs_helper.rb +131 -0
  423. data/lib/mtncloud/cli/mixins/monitoring_helper.rb +876 -0
  424. data/lib/mtncloud/cli/mixins/networks_helper.rb +62 -0
  425. data/lib/mtncloud/cli/mixins/operations_helper.rb +41 -0
  426. data/lib/mtncloud/cli/mixins/option_source_helper.rb +254 -0
  427. data/lib/mtncloud/cli/mixins/print_helper.rb +1631 -0
  428. data/lib/mtncloud/cli/mixins/processes_helper.rb +286 -0
  429. data/lib/mtncloud/cli/mixins/prompt_helper.rb +136 -0
  430. data/lib/mtncloud/cli/mixins/provisioning_helper.rb +2963 -0
  431. data/lib/mtncloud/cli/mixins/remote_helper.rb +139 -0
  432. data/lib/mtncloud/cli/mixins/rest_command.rb +994 -0
  433. data/lib/mtncloud/cli/mixins/secondary_rest_command.rb +700 -0
  434. data/lib/mtncloud/cli/mixins/storage_servers_helper.rb +93 -0
  435. data/lib/mtncloud/cli/mixins/storage_volumes_helper.rb +76 -0
  436. data/lib/mtncloud/cli/mixins/vdi_helper.rb +246 -0
  437. data/lib/mtncloud/cli/mixins/whoami_helper.rb +73 -0
  438. data/lib/mtncloud/cli/option_parser.rb +127 -0
  439. data/lib/mtncloud/cli/option_types.rb +1622 -0
  440. data/lib/mtncloud/cli/version.rb +6 -0
  441. data/lib/mtncloud/cli.rb +105 -0
  442. data/lib/mtncloud/currency.rb +184 -0
  443. data/lib/mtncloud/ext/hash.rb +109 -0
  444. data/lib/mtncloud/ext/nil_class.rb +5 -0
  445. data/lib/mtncloud/ext/rest_client.rb +37 -0
  446. data/lib/mtncloud/ext/string.rb +66 -0
  447. data/lib/mtncloud/formatters.rb +511 -0
  448. data/lib/mtncloud/logging.rb +185 -0
  449. data/lib/mtncloud/morpkg.rb +119 -0
  450. data/lib/mtncloud/rest_client.rb +104 -0
  451. data/lib/mtncloud/routes.rb +304 -0
  452. data/lib/mtncloud/terminal.rb +528 -0
  453. data/lib/mtncloud/util.rb +29 -0
  454. data/lib/mtncloud.rb +5 -0
  455. data/mtncloud-cli.gemspec +38 -0
  456. data/test/api/affinity_groups_interface_test.rb +43 -0
  457. data/test/api/clients_interface_test.rb +23 -0
  458. data/test/api/clouds_interface_test.rb +67 -0
  459. data/test/api/containers_interface_test.rb +68 -0
  460. data/test/api/host_vm_groups_interface_test.rb +35 -0
  461. data/test/api/instances_interface_test.rb +22 -0
  462. data/test/api/network_routers_interface_test.rb +22 -0
  463. data/test/api/systems_interface_test.rb +26 -0
  464. data/test/api/whoami_interface_test.rb +14 -0
  465. data/test/branding_test.rb +160 -0
  466. data/test/cli/access_token_test.rb +36 -0
  467. data/test/cli/affinity_groups_cloud_cluster_scope_test.rb +270 -0
  468. data/test/cli/affinity_groups_cluster_scope_test.rb +171 -0
  469. data/test/cli/affinity_groups_test.rb +57 -0
  470. data/test/cli/affinity_groups_violations_scope_test.rb +141 -0
  471. data/test/cli/affinity_helper_test.rb +367 -0
  472. data/test/cli/auth_test.rb +88 -0
  473. data/test/cli/backups_test.rb +212 -0
  474. data/test/cli/cli_test.rb +48 -0
  475. data/test/cli/clients_test.rb +45 -0
  476. data/test/cli/clusters_uuid_test.rb +146 -0
  477. data/test/cli/containers_test.rb +92 -0
  478. data/test/cli/distributed_workers_test.rb +68 -0
  479. data/test/cli/help_test.rb +25 -0
  480. data/test/cli/host_vm_groups_cluster_scope_test.rb +187 -0
  481. data/test/cli/host_vm_groups_test.rb +63 -0
  482. data/test/cli/infrastructure_helper_cluster_resolver_test.rb +250 -0
  483. data/test/cli/instances_test.rb +37 -0
  484. data/test/cli/man_test.rb +14 -0
  485. data/test/cli/migrations_test.rb +39 -0
  486. data/test/cli/network_routers_test.rb +65 -0
  487. data/test/cli/remote_test.rb +89 -0
  488. data/test/cli/roles_test.rb +47 -0
  489. data/test/cli/shell_test.rb +81 -0
  490. data/test/cli/storage_volumes_test.rb +79 -0
  491. data/test/cli/systems_test.rb +206 -0
  492. data/test/cli/version_test.rb +23 -0
  493. data/test/cli/view_test.rb +55 -0
  494. data/test/cli/whoami_test.rb +17 -0
  495. data/test/mtncloud_test.rb +16 -0
  496. data/test/test_case.rb +342 -0
  497. data/test/test_config.rb +137 -0
  498. data/test/test_data_helper.rb +97 -0
  499. metadata +807 -0
@@ -0,0 +1,1362 @@
1
+ require 'mtncloud/cli/cli_command'
2
+
3
+ # JD: I don't think a lot of this has ever worked, fix it up.
4
+
5
+ class MtnCloud::Cli::VirtualImages
6
+ include MtnCloud::Cli::CliCommand
7
+ include MtnCloud::Cli::ProvisioningHelper
8
+
9
+ register_subcommands :list, :get, :add, :add_file, :remove_file, :update, :remove,
10
+ :convert, {:types => :virtual_image_types}, :download
11
+ register_subcommands :list_locations, :get_location, :remove_location
12
+
13
+ # def initialize()
14
+ # # @appliance_name, @appliance_url = MtnCloud::Cli::Remote.active_appliance
15
+ # end
16
+
17
+ def connect(opts)
18
+ @api_client = establish_remote_appliance_connection(opts)
19
+ @virtual_images_interface = @api_client.virtual_images
20
+ end
21
+
22
+ def handle(args)
23
+ handle_subcommand(args)
24
+ end
25
+
26
+ def list(args)
27
+ params = {}
28
+ options = {}
29
+ optparse = MtnCloud::Cli::OptionParser.new do |opts|
30
+ opts.banner = subcommand_usage()
31
+ opts.on( '-t', '--type IMAGE_TYPE', "Image Type" ) do |val|
32
+ options[:imageType] = val.downcase
33
+ end
34
+ opts.on('--all', "All Images" ) do
35
+ options[:filterType] = 'All'
36
+ end
37
+ opts.on('--user', "User Images" ) do
38
+ options[:filterType] = 'User'
39
+ end
40
+ opts.on('--system', "System Images" ) do
41
+ options[:filterType] = 'System'
42
+ end
43
+ opts.on('--synced', "Synced Images" ) do
44
+ options[:filterType] = 'Synced'
45
+ end
46
+ opts.on('-l', '--labels LABEL', String, "Filter by labels, can match any of the values") do |val|
47
+ add_query_parameter(params, 'labels', parse_labels(val))
48
+ end
49
+ opts.on('--all-labels LABEL', String, "Filter by labels, must match all of the values") do |val|
50
+ add_query_parameter(params, 'allLabels', parse_labels(val))
51
+ end
52
+ opts.on('--tags Name=Value',String, "Filter by tags (metadata name value pairs).") do |val|
53
+ val.split(",").each do |value_pair|
54
+ k,v = value_pair.strip.split("=")
55
+ options[:tags] ||= {}
56
+ options[:tags][k] ||= []
57
+ options[:tags][k] << (v || '')
58
+ end
59
+ end
60
+ opts.on('-a', '--details', "Show more details." ) do
61
+ options[:details] = true
62
+ end
63
+ build_standard_list_options(opts, options)
64
+ opts.footer = "List virtual images. Default list applies User filter"
65
+ end
66
+ optparse.parse!(args)
67
+ connect(options)
68
+ # verify_args!(args:args, optparse:optparse, count:0)
69
+ if args.count > 0
70
+ options[:phrase] = args.join(" ")
71
+ end
72
+ params.merge!(parse_list_options(options))
73
+ if options[:imageType]
74
+ params[:imageType] = options[:imageType]
75
+ end
76
+ if options[:filterType]
77
+ params[:filterType] = options[:filterType]
78
+ end
79
+ if options[:tags]
80
+ options[:tags].each do |k,v|
81
+ params['tags.' + k] = v
82
+ end
83
+ end
84
+ @virtual_images_interface.setopts(options)
85
+ if options[:dry_run]
86
+ print_dry_run @virtual_images_interface.dry.list(params)
87
+ return
88
+ end
89
+ json_response = @virtual_images_interface.list(params)
90
+ images = json_response['virtualImages']
91
+ render_response(json_response, options, 'virtualImages') do
92
+ get_available_virtual_image_types() # preload
93
+ title = "Virtual Images"
94
+ subtitles = parse_list_subtitles(options)
95
+ if options[:imageType]
96
+ subtitles << "Image Type: #{options[:imageType]}".strip
97
+ end
98
+ if options[:filterType]
99
+ subtitles << "Image Type: #{options[:filterType]}".strip
100
+ end
101
+ if params[:phrase]
102
+ subtitles << "Search: #{params[:phrase]}".strip
103
+ end
104
+ print_h1 title, subtitles
105
+ if images.empty?
106
+ print cyan,"No virtual images found.",reset,"\n"
107
+ else
108
+ virtual_image_column_definitions = {
109
+ "ID" => 'id',
110
+ "Name" => 'name',
111
+ "Labels" => lambda {|it| format_list(it['labels'], '', 3) rescue '' },
112
+ "Type" => lambda {|it|
113
+ # yick, api should return the type with every virtualImage
114
+ image_type = virtual_image_type_for_name_or_code(it['imageType'])
115
+ image_type ? "#{image_type['name']}" : it['imageType']
116
+ },
117
+ "Operating System" => lambda {|it| it['osType'] ? it['osType']['name'] : "" },
118
+ "Storage" => lambda {|it| !it['storageProvider'].nil? ? it['storageProvider']['name'] : 'Default' },
119
+ "Size" => lambda {|it| it['rawSize'].nil? ? 'Unknown' : "#{Filesize.from("#{it['rawSize']} B").pretty}" },
120
+ "Visibility" => lambda {|it| it['visibility'] },
121
+ # "Tenant" => lambda {|it| it['account'].instance_of?(Hash) ? it['account']['name'] : it['ownerId'] },
122
+ "Tenants" => lambda {|it| format_list(it['accounts'].collect {|a| a['name'] }, '', 3) rescue '' },
123
+ "Source" => lambda {|it| format_virtual_image_source(it) },
124
+ "Created" => lambda {|it| format_local_dt(it['dateCreated']) },
125
+ "Updated" => lambda {|it| format_local_dt(it['lastUpdated']) },
126
+ "Tags" => lambda {|it| it['tags'] ? it['tags'].collect {|m| "#{m['name']}: #{m['value']}" }.join(', ') : '' },
127
+ }
128
+ if json_response['multiTenant'] != true
129
+ virtual_image_column_definitions.delete("Visibility")
130
+ virtual_image_column_definitions.delete("Tenants")
131
+ end
132
+ if options[:details] != true
133
+ virtual_image_column_definitions.delete("Tags")
134
+ virtual_image_column_definitions.delete("Created")
135
+ virtual_image_column_definitions.delete("Updated")
136
+ end
137
+ print as_pretty_table(images, virtual_image_column_definitions.upcase_keys!, options)
138
+ print_results_pagination(json_response)
139
+ end
140
+ print reset,"\n"
141
+ end
142
+ if images.empty?
143
+ return -1, "no virtual images found"
144
+ else
145
+ return 0, nil
146
+ end
147
+ end
148
+
149
+ def get(args)
150
+ params = {}
151
+ options = {}
152
+ optparse = MtnCloud::Cli::OptionParser.new do |opts|
153
+ opts.banner = subcommand_usage("[image]")
154
+ opts.on('-a', '--details', "Show more details." ) do
155
+ options[:details] = true
156
+ end
157
+ opts.on('--tags LIST', String, "Metadata tags in the format 'name:value, name:value'") do |val|
158
+ options[:tags] = val
159
+ end
160
+ build_standard_get_options(opts, options)
161
+ opts.footer = <<-EOT
162
+ Get details about a virtual image.
163
+ [image] is required. This is the name or id of a virtual image.
164
+ EOT
165
+ end
166
+ optparse.parse!(args)
167
+ verify_args!(args:args, optparse:optparse, min:1)
168
+ connect(options)
169
+ id_list = parse_id_list(args)
170
+ # lookup IDs if names are given
171
+ id_list = id_list.collect do |id|
172
+ if id.to_s =~ /\A\d{1,}\Z/
173
+ id
174
+ else
175
+ image = find_virtual_image_by_name_or_id(id)
176
+ return 1, "virtual image not found for name '#{id}'" if image.nil?
177
+ image['id']
178
+ end
179
+ end
180
+ return run_command_for_each_arg(id_list) do |arg|
181
+ _get(arg, params, options)
182
+ end
183
+ end
184
+
185
+ def _get(id, params, options)
186
+ @virtual_images_interface.setopts(options)
187
+ if options[:dry_run]
188
+ print_dry_run @virtual_images_interface.dry.get(id.to_i)
189
+ return
190
+ end
191
+ json_response = @virtual_images_interface.get(id.to_i)
192
+ image = json_response['virtualImage']
193
+ image_config = image['config'] || {}
194
+ image_volumes = image['volumes'] || []
195
+ image_locations = image['locations'] || []
196
+ image_files = json_response['cloudFiles'] || json_response['files']
197
+ image_type = virtual_image_type_for_name_or_code(image['imageType'])
198
+ image_type_display = image_type ? "#{image_type['name']}" : image['imageType']
199
+ render_response(json_response, options, 'virtualImage') do
200
+ get_available_virtual_image_types() # preload
201
+ print_h1 "Virtual Image Details", [], options
202
+ description_cols = {
203
+ "ID" => 'id',
204
+ "Name" => 'name',
205
+ "Labels" => lambda {|it| format_list(it['labels']) },
206
+ "Type" => lambda {|it| image_type_display },
207
+ "Operating System" => lambda {|it| it['osType'] ? it['osType']['name'] : "" },
208
+ "Storage" => lambda {|it| !image['storageProvider'].nil? ? image['storageProvider']['name'] : 'Default' },
209
+ "Size" => lambda {|it| image['rawSize'].nil? ? 'Unknown' : "#{Filesize.from("#{image['rawSize']} B").pretty}" },
210
+ "Azure Publisher" => lambda {|it| image_config['publisher'] },
211
+ "Azure Offer" => lambda {|it| image_config['offer'] },
212
+ "Azure Sku" => lambda {|it| image_config['sku'] },
213
+ "Azure Version" => lambda {|it| image_config['version'] },
214
+ "Source" => lambda {|it| format_virtual_image_source(it) },
215
+ "Tags" => lambda {|it| it['tags'] ? it['tags'].collect {|m| "#{m['name']}: #{m['value']}" }.join(', ') : '' },
216
+ "Created" => lambda {|it| format_local_dt(it['dateCreated']) },
217
+ "Updated" => lambda {|it| format_local_dt(it['lastUpdated']) }
218
+ }
219
+ description_cols.delete("Tags") if image['tags'].nil? || image['tags'].empty?
220
+ if image['imageType'] == "azure-reference" || image['imageType'] == "azure"
221
+ description_cols.delete("Size")
222
+ description_cols.delete("Storage")
223
+ description_cols["Source"] = lambda {|it| "#{bold}#{cyan}AZURE#{reset}#{cyan}" }
224
+ else
225
+ description_cols.delete("Azure Publisher")
226
+ description_cols.delete("Azure Sku")
227
+ description_cols.delete("Azure Offer")
228
+ description_cols.delete("Azure Version")
229
+ end
230
+ advanced_description_cols = {
231
+ #"OS Type" => lambda {|it| it['osType'] ? it['osType']['name'] : "" }, # displayed above as Operating System
232
+ "Min Memory" => lambda {|it| it['minRam'].to_i != 0 ? Filesize.from("#{it['minRam']} B").pretty : "" },
233
+ "Min Disk" => lambda {|it| it['minDisk'].to_i != 0 ? Filesize.from("#{it['minDisk']} B").pretty : "" },
234
+ "Cloud Init?" => lambda {|it| format_boolean it['osType'] },
235
+ "Install Agent?" => lambda {|it| format_boolean it['osType'] },
236
+ "SSH Username" => lambda {|it| it['sshUsername'] },
237
+ "SSH Password" => lambda {|it| it['sshPassword'] },
238
+ "User Data" => lambda {|it| it['userData'] },
239
+ "Owner" => lambda {|it| it['tenant'].instance_of?(Hash) ? it['tenant']['name'] : it['ownerId'] },
240
+ "Visibility" => lambda {|it| it['visibility'].to_s.capitalize },
241
+ "Tenants" => lambda {|it| format_tenants(it['accounts']) },
242
+ "Auto Join Domain?" => lambda {|it| format_boolean it['isAutoJoinDomain'] },
243
+ "VirtIO Drivers Loaded?" => lambda {|it| format_boolean it['virtioSupported'] },
244
+ "VM Tools Installed?" => lambda {|it| format_boolean it['vmToolsInstalled'] },
245
+ "Force Guest Customization?" => lambda {|it| format_boolean it['isForceCustomization'] },
246
+ "Trial Version" => lambda {|it| format_boolean it['trialVersion'] },
247
+ "Sysprep Enabled?" => lambda {|it| format_boolean it['isSysprep'] },
248
+ }
249
+ if options[:details]
250
+ description_cols.merge!(advanced_description_cols)
251
+ end
252
+ print_description_list(description_cols, image)
253
+
254
+ if image_volumes && !image_volumes.empty?
255
+ print_h2 "Volumes", options
256
+ image_volume_rows = image_volumes.collect do |image_volume|
257
+ {name: image_volume['name'], size: Filesize.from("#{image_volume['rawSize']} B").pretty}
258
+ end
259
+ print cyan
260
+ print as_pretty_table(image_volume_rows, [:name, :size])
261
+ print cyan
262
+ # print "\n", reset
263
+ end
264
+
265
+ if image_files && !image_files.empty?
266
+ print_h2 "Files (#{image_files.size})"
267
+ # image_files.each {|image_file|
268
+ # pretty_filesize = Filesize.from("#{image_file['size']} B").pretty
269
+ # print cyan," = #{image_file['name']} [#{pretty_filesize}]", "\n"
270
+ # }
271
+ # size property changed to GB to match volumes
272
+ # contentLength is bytes
273
+ image_file_rows = image_files.collect do |image_file|
274
+ {filename: image_file['name'], size: Filesize.from("#{image_file['contentLength'] || image_file['size']} B").pretty}
275
+ end
276
+ print cyan
277
+ print as_pretty_table(image_file_rows, [:filename, :size])
278
+ # print reset,"\n"
279
+ end
280
+
281
+ if image_locations && !image_locations.empty?
282
+ print_h2 "Locations", options
283
+ print as_pretty_table(image_locations, virtual_image_location_list_column_definitions.upcase_keys!, options)
284
+ end
285
+
286
+ if options[:details] && image_config && !image_config.empty?
287
+ print_h2 "Config", options
288
+ print cyan
289
+ print as_description_list(image_config, image_config.keys, options)
290
+ # print "\n", reset
291
+ end
292
+
293
+ print reset,"\n"
294
+ end
295
+ return 0, nil
296
+ end
297
+
298
+ def update(args)
299
+ image_name = args[0]
300
+ options = {}
301
+ tenants_list = nil
302
+ optparse = MtnCloud::Cli::OptionParser.new do |opts|
303
+ opts.banner = subcommand_usage("[image] [options]")
304
+ opts.on('--tenants LIST', Array, "Tenant Access, comma separated list of account IDs") do |list|
305
+ if list.size == 1 && list[0] == 'null' # hacky way to clear it
306
+ tenants_list = []
307
+ else
308
+ tenants_list = list.collect {|it| it.to_s.strip.empty? ? nil : it.to_s.strip }.compact.uniq
309
+ end
310
+ end
311
+ opts.on('-l', '--labels [LIST]', String, "Labels") do |val|
312
+ options[:options]['labels'] = parse_labels(val)
313
+ end
314
+ opts.on('--tags LIST', String, "Tags in the format 'name:value, name:value'. This will add and remove tags.") do |val|
315
+ options[:tags] = val
316
+ end
317
+ opts.on('--add-tags TAGS', String, "Add Tags in the format 'name:value, name:value'. This will only add/update tags.") do |val|
318
+ options[:add_tags] = val
319
+ end
320
+ opts.on('--remove-tags TAGS', String, "Remove Tags in the format 'name, name:value'. This removes tags, the :value component is optional and must match if passed.") do |val|
321
+ options[:remove_tags] = val
322
+ end
323
+ build_common_options(opts, options, [:options, :payload, :json, :dry_run, :remote])
324
+ opts.footer = "Update a virtual image." + "\n" +
325
+ "[image] is required. This is the name or id of a virtual image."
326
+ end
327
+ optparse.parse!(args)
328
+ verify_args!(args:args, optparse:optparse, count:1)
329
+
330
+ connect(options)
331
+
332
+ virtual_image = find_virtual_image_by_name_or_id(image_name)
333
+ return 1 if virtual_image.nil?
334
+
335
+ passed_options = parse_passed_options(options)
336
+ payload = nil
337
+ if options[:payload]
338
+ payload = options[:payload]
339
+ payload.deep_merge!({virtual_image_object_key => passed_options}) unless passed_options.empty?
340
+ else
341
+ virtual_image_payload = passed_options
342
+ if tenants_list
343
+ virtual_image_payload['accounts'] = tenants_list
344
+ end
345
+ # metadata tags
346
+ if options[:tags]
347
+ virtual_image_payload['tags'] = parse_metadata(options[:tags])
348
+ else
349
+ # tags = prompt_metadata(options)
350
+ # payload[virtual_image_object_key]['tags'] = tags of tags
351
+ end
352
+ # metadata tags
353
+ if options[:add_tags]
354
+ virtual_image_payload['addTags'] = parse_metadata(options[:add_tags])
355
+ end
356
+ if options[:remove_tags]
357
+ virtual_image_payload['removeTags'] = parse_metadata(options[:remove_tags])
358
+ end
359
+ if virtual_image_payload.empty?
360
+ raise_command_error "Specify at least one option to update.\n#{optparse}"
361
+ end
362
+ payload = {'virtualImage' => virtual_image_payload}
363
+ end
364
+ @virtual_images_interface.setopts(options)
365
+ if options[:dry_run]
366
+ print_dry_run @virtual_images_interface.dry.update(virtual_image['id'], payload)
367
+ return
368
+ end
369
+ json_response = @virtual_images_interface.update(virtual_image['id'], payload)
370
+ render_response(json_response, options, 'virtualImage') do
371
+ print_green_success "Updated virtual image #{virtual_image['name']}"
372
+ _get(virtual_image["id"], {}, options)
373
+ end
374
+ return 0, nil
375
+
376
+ end
377
+
378
+ def convert(args)
379
+ image_name = args[0]
380
+ options = {}
381
+ # storageProviderId, format, name
382
+ optparse = MtnCloud::Cli::OptionParser.new do |opts|
383
+ opts.banner = subcommand_usage("[image] [options]")
384
+ # opts.on('-n', '--name NAME', String, "Name (optional) of the new converted image. Default is name of the original image.") do |val|
385
+ # options[:options]['name'] = val
386
+ # end
387
+ # opts.on('-f', '--format FORMAT', String, "Format (optional). Default is 'qcow2'") do |val|
388
+ # options[:options]['format'] = val
389
+ # end
390
+ # opts.on('--storageProvider VALUE', String, "Storage Provider ID (optional). Default is storage provider of the original image.") do |val|
391
+ # options[:options]['storageProvider'] = val.to_s
392
+ # end
393
+ build_option_type_options(opts, options, convert_virtual_image_option_types)
394
+ build_common_options(opts, options, [:options, :payload, :json, :dry_run, :remote])
395
+ opts.footer = "Convert a virtual image to a new format." + "\n" +
396
+ "[image] is required. This is the name or id of a virtual image."
397
+ end
398
+ optparse.parse!(args)
399
+ verify_args!(args:args, optparse:optparse, min:1, max:4)
400
+
401
+ connect(options)
402
+
403
+ virtual_image = find_virtual_image_by_name_or_id(image_name)
404
+ return 1, "Virtual image not found for #{image_name}" if virtual_image.nil?
405
+
406
+ passed_options = parse_passed_options(options)
407
+ payload = nil
408
+ if options[:payload]
409
+ payload = options[:payload]
410
+ payload.deep_merge!({virtual_image_object_key => passed_options}) unless passed_options.empty?
411
+ else
412
+ virtual_image_payload = passed_options
413
+ source_format = virtual_image['imageType']
414
+ v_prompt = MtnCloud::Cli::OptionTypes.prompt(convert_virtual_image_option_types(source_format), options[:options], @api_client, {'virtualImageId': virtual_image['id']})
415
+ v_prompt.deep_compact!
416
+ virtual_image_payload.deep_merge!(v_prompt)
417
+ # support "storageProviderId" too
418
+ if virtual_image_payload['storageProviderId']
419
+ virtual_image_payload['storageProvider'] = virtual_image_payload.delete('storageProviderId')
420
+ end
421
+ # convert "storageProvider":1 to "storageProvider": {"id":1}
422
+ if virtual_image_payload['storageProvider'] && !virtual_image_payload['storageProvider'].is_a?(Hash)
423
+ virtual_image_payload['storageProvider'] = {'id' => virtual_image_payload['storageProvider'].to_i }
424
+ end
425
+ payload = virtual_image_payload
426
+ end
427
+ @virtual_images_interface.setopts(options)
428
+ if options[:dry_run]
429
+ print_dry_run @virtual_images_interface.dry.convert(virtual_image['id'], payload)
430
+ return
431
+ end
432
+ json_response = @virtual_images_interface.convert(virtual_image['id'], payload)
433
+ render_response(json_response, options, 'virtualImage') do
434
+ print_green_success "Updated virtual image #{virtual_image['name']}"
435
+ _get(virtual_image["id"], {}, options)
436
+ end
437
+ return 0, nil
438
+ end
439
+
440
+ def virtual_image_types(args)
441
+ options = {}
442
+ optparse = MtnCloud::Cli::OptionParser.new do |opts|
443
+ opts.banner = subcommand_usage()
444
+ build_common_options(opts, options, [:json, :dry_run, :remote])
445
+ end
446
+ optparse.parse!(args)
447
+ connect(options)
448
+ begin
449
+ params = {}
450
+ @virtual_images_interface.setopts(options)
451
+ if options[:dry_run]
452
+ print_dry_run @virtual_images_interface.dry.virtual_image_types(params)
453
+ return
454
+ end
455
+ json_response = @virtual_images_interface.virtual_image_types(params)
456
+ if options[:json]
457
+ print JSON.pretty_generate(json_response)
458
+ else
459
+ image_types = json_response['virtualImageTypes']
460
+ print_h1 "Virtual Image Types"
461
+ if image_types.nil? || image_types.empty?
462
+ print cyan,"No image types found.",reset,"\n"
463
+ else
464
+ rows = image_types.collect do |lb_type|
465
+ {name: lb_type['name'], code: lb_type['code']}
466
+ end
467
+ puts as_pretty_table(rows, [:name, :code], options)
468
+ end
469
+ return 0
470
+ end
471
+ rescue RestClient::Exception => e
472
+ print_rest_exception(e, options)
473
+ exit 1
474
+ end
475
+ end
476
+
477
+ def add(args)
478
+ image_type_name = nil
479
+ file_url = nil
480
+ file_name = nil
481
+ tenants_list = nil
482
+ options = {}
483
+ optparse = MtnCloud::Cli::OptionParser.new do |opts|
484
+ opts.banner = subcommand_usage("[name] -t TYPE")
485
+ opts.on( '-t', '--type TYPE', "Virtual Image Type" ) do |val|
486
+ image_type_name = val
487
+ end
488
+ opts.on( '--filename NAME', "Image File Name. Specify a name for the uploaded file." ) do |val|
489
+ file_name = val
490
+ end
491
+ opts.on( '-U', '--url URL', "Image File URL. This can be used instead of uploading local files." ) do |val|
492
+ file_url = val
493
+ end
494
+ opts.on( '-c', '--cloud CLOUD', "Cloud to scope image to, certain types require a cloud to be selected, eg. Azure Reference" ) do |val|
495
+ # options[:cloud] = val
496
+ options[:options]['cloud'] = val
497
+ end
498
+ opts.on( '--azure-offer OFFER', String, "Azure Reference offer value, only applies to Azure Reference" ) do |val|
499
+ options[:options]['offer'] = val
500
+ end
501
+ opts.on( '--azure-sku SKU', String, "Azure SKU value, only applies to Azure Reference" ) do |val|
502
+ options[:options]['sku'] = val
503
+ end
504
+ opts.on( '--azure-version VERSION', String, "Azure Version value, only applies to Azure Reference" ) do |val|
505
+ options[:options]['version'] = val
506
+ end
507
+ opts.on('--tenants LIST', Array, "Tenant Access, comma separated list of account IDs") do |list|
508
+ if list.size == 1 && list[0] == 'null' # hacky way to clear it
509
+ tenants_list = []
510
+ else
511
+ tenants_list = list.collect {|it| it.to_s.strip.empty? ? nil : it.to_s.strip }.compact.uniq
512
+ end
513
+ end
514
+ opts.on('-l', '--labels [LIST]', String, "Labels") do |val|
515
+ options[:options]['labels'] = parse_labels(val)
516
+ end
517
+ opts.on('--tags LIST', String, "Metadata tags in the format 'name:value, name:value'") do |val|
518
+ options[:tags] = val
519
+ end
520
+ # build_option_type_options(opts, options, add_virtual_image_option_types)
521
+ # build_option_type_options(opts, options, add_virtual_image_advanced_option_types)
522
+ build_standard_add_options(opts, options)
523
+
524
+ opts.footer = "Create a virtual image."
525
+ end
526
+ optparse.parse!(args)
527
+ # if args.count < 1
528
+ # puts optparse
529
+ # exit 1
530
+ # end
531
+ image_name = args[0]
532
+ connect(options)
533
+
534
+ # if image_type_name.nil?
535
+ # puts "Virtual Image Type must be specified"
536
+ # puts optparse
537
+ # exit 1
538
+ # end
539
+
540
+ if image_name
541
+ options[:options] ||= {}
542
+ options[:options]['name'] ||= image_name
543
+ end
544
+
545
+ payload = {}
546
+ if options[:payload]
547
+ payload = options[:payload]
548
+ payload.deep_merge!({'virtualImage' => parse_passed_options(options)})
549
+ else
550
+ payload.deep_merge!({'virtualImage' => parse_passed_options(options)})
551
+ virtual_image_payload = {}
552
+ # v_prompt = MtnCloud::Cli::OptionTypes.prompt(add_virtual_image_option_types, options[:options], @api_client, options[:params])
553
+ if image_type_name
554
+ image_type = virtual_image_type_for_name_or_code(image_type_name)
555
+ # fix issue with api returning imageType vmware instead of vmdk
556
+ if image_type.nil? && image_type_name == 'vmware'
557
+ image_type = virtual_image_type_for_name_or_code('vmdk')
558
+ elsif image_type.nil? && image_type_name == 'vmdk'
559
+ image_type = virtual_image_type_for_name_or_code('vmware')
560
+ end
561
+ if image_type.nil?
562
+ print_red_alert "Virtual Image Type not found by code '#{image_type_name}'"
563
+ return 1
564
+ end
565
+ # options[:options] ||= {}
566
+ # options[:options]['imageType'] ||= image_type['code']
567
+ else
568
+ image_type_prompt = MtnCloud::Cli::OptionTypes.prompt([{'fieldName' => 'imageType', 'fieldLabel' => 'Image Type', 'type' => 'select', 'optionSource' => 'virtualImageTypes', 'required' => true, 'description' => 'Select Virtual Image Type.', 'displayOrder' => 2}],options[:options],@api_client,{})
569
+ image_type = virtual_image_type_for_name_or_code(image_type_prompt['imageType'])
570
+ end
571
+
572
+ # azure requires us to search the marketplace to select publisher, cloud, offerm sku
573
+ if image_type['code'] == "azure-reference" || image_type['code'] == "azure"
574
+ cloud_prompt = MtnCloud::Cli::OptionTypes.prompt([{'fieldName' => 'cloud', 'fieldLabel' => 'Cloud', 'type' => 'select', 'optionSource' => 'clouds', 'required' => true, 'description' => 'Select Azure Cloud.', :fmt=>:natural}],options[:options],@api_client, {zoneTypeWhiteList: 'azure'})
575
+ cloud_id = cloud_prompt['cloud'].to_i
576
+
577
+ marketplace_config = prompt_azure_marketplace(cloud_id, options)
578
+ virtual_image_payload['config'] ||= {}
579
+ virtual_image_payload['config'].deep_merge!(marketplace_config)
580
+ end
581
+
582
+ my_option_types = add_virtual_image_option_types(image_type, !file_url)
583
+ # if options[:no_prompt]
584
+ # my_option_types.each do |it|
585
+ # if it['fieldContext'] == 'virtualImageFiles'
586
+ # opt['required'] = false
587
+ # end
588
+ # end
589
+ # end
590
+ v_prompt = MtnCloud::Cli::OptionTypes.prompt(my_option_types, options[:options], @api_client, options[:params])
591
+ v_prompt.deep_compact!
592
+ virtual_image_payload.deep_merge!(v_prompt)
593
+ virtual_image_files = virtual_image_payload.delete('virtualImageFiles')
594
+ upload_type = virtual_image_payload.delete('uploadType') # not used serverside
595
+ virtual_image_payload['imageType'] = image_type['code']
596
+ storage_provider_id = virtual_image_payload.delete('storageProviderId')
597
+ if !storage_provider_id.to_s.empty?
598
+ virtual_image_payload['storageProvider'] = {id: storage_provider_id}
599
+ end
600
+ if tenants_list
601
+ virtual_image_payload['accounts'] = tenants_list
602
+ end
603
+ # metadata tags
604
+ if options[:tags]
605
+ tags = parse_metadata(options[:tags])
606
+ virtual_image_payload['tags'] = tags if tags
607
+ else
608
+ # tags = prompt_metadata(options)
609
+ # virtual_image_payload['tags'] = tags of tags
610
+ end
611
+ # fix issue with api returning imageType vmware instead of vmdk
612
+ if virtual_image_payload && virtual_image_payload['imageType'] == 'vmware'
613
+ virtual_image_payload['imageType'] == 'vmdk'
614
+ end
615
+ # no need to make second request anymore, just include virtualImage.url
616
+ if file_url
617
+ virtual_image_payload['url'] = file_url
618
+ file_url = nil
619
+ end
620
+ #payload = {'virtualImage' => virtual_image_payload}
621
+ payload.deep_merge!({'virtualImage' => virtual_image_payload})
622
+ end
623
+
624
+ @virtual_images_interface.setopts(options)
625
+ if options[:dry_run]
626
+ print_dry_run @virtual_images_interface.dry.create(payload)
627
+ if file_url
628
+ print_dry_run @virtual_images_interface.dry.upload_by_url(":id", file_url, file_name)
629
+ elsif virtual_image_files && !virtual_image_files.empty?
630
+ virtual_image_files.each do |key, filepath|
631
+ print_dry_run @virtual_images_interface.dry.upload(":id", "(Contents of file #{filepath})")
632
+ end
633
+ end
634
+ return
635
+ end
636
+
637
+ json_response = @virtual_images_interface.create(payload)
638
+ virtual_image = json_response['virtualImage']
639
+
640
+ # if options[:json]
641
+ # print JSON.pretty_generate(json_response)
642
+ # elsif !options[:quiet]
643
+ # print "\n", cyan, "Virtual Image #{virtual_image['name']} created successfully", reset, "\n\n"
644
+ # end
645
+
646
+ # now upload the file, do this in the background maybe?
647
+ if file_url
648
+ unless options[:quiet]
649
+ print cyan, "Uploading file by url #{file_url} ...", reset, "\n"
650
+ end
651
+ upload_json_response = @virtual_images_interface.upload_by_url(virtual_image['id'], file_url, file_name)
652
+ # if options[:json]
653
+ # print JSON.pretty_generate(upload_json_response)
654
+ # end
655
+ elsif virtual_image_files && !virtual_image_files.empty?
656
+ virtual_image_files.each do |key, filepath|
657
+ unless options[:quiet]
658
+ print cyan, "Uploading file (#{key}) #{filepath} ...", reset, "\n"
659
+ end
660
+ image_file = File.new(filepath, 'rb')
661
+ upload_json_response = @virtual_images_interface.upload(virtual_image['id'], image_file, file_name)
662
+ # if options[:json]
663
+ # print JSON.pretty_generate(upload_json_response)
664
+ # end
665
+ end
666
+ else
667
+ # puts cyan, "No files uploaded.", reset
668
+ end
669
+
670
+ render_response(json_response, options, 'virtualImage') do
671
+ print_green_success "Added virtual image #{virtual_image['name']}"
672
+ return _get(virtual_image["id"], {}, options)
673
+ end
674
+ return 0, nil
675
+
676
+ end
677
+
678
+ def add_file(args)
679
+ file_url = nil
680
+ file_name = nil
681
+ do_gzip = false
682
+ options = {}
683
+ optparse = MtnCloud::Cli::OptionParser.new do |opts|
684
+ opts.banner = subcommand_usage("[image] [filepath]")
685
+ opts.on('--filename FILENAME', String, "Filename for uploaded file. Derived from [filepath] by default." ) do |val|
686
+ file_name = val
687
+ end
688
+ opts.on( '-U', '--url URL', "Image File URL. This can be used instead of [filepath]" ) do |val|
689
+ file_url = val
690
+ end
691
+ opts.on( nil, '--gzip', "Compress uploaded file" ) do
692
+ do_gzip = true
693
+ end
694
+ build_common_options(opts, options, [:json, :dry_run, :quiet, :remote])
695
+ opts.footer = "Upload a virtual image file." + "\n" +
696
+ "[image] is required. This is the name or id of a virtual image." + "\n" +
697
+ "[filepath] or --url is required. This is location of the virtual image file."
698
+ end
699
+ optparse.parse!(args)
700
+ image_name = args[0]
701
+ filepath = nil
702
+ if file_url
703
+ if args.count < 1
704
+ puts optparse
705
+ exit 1
706
+ end
707
+ else
708
+ if args.count < 2
709
+ puts optparse
710
+ exit 1
711
+ end
712
+ filepath = args[1]
713
+ end
714
+
715
+ connect(options)
716
+
717
+ begin
718
+ image = find_virtual_image_by_name_or_id(image_name)
719
+ return 1 if image.nil?
720
+ @virtual_images_interface.setopts(options)
721
+ if file_url
722
+ if options[:dry_run]
723
+ print_dry_run @virtual_images_interface.dry.upload_by_url(image['id'], file_url, file_name)
724
+ return
725
+ end
726
+ unless options[:quiet]
727
+ print cyan, "Uploading file by url #{file_url} ...", reset, "\n"
728
+ end
729
+ json_response = @virtual_images_interface.upload_by_url(image['id'], file_url, file_name)
730
+ if options[:json]
731
+ print JSON.pretty_generate(json_response)
732
+ elsif !options[:quiet]
733
+ print "\n", cyan, "Virtual Image #{image['name']} successfully updated.", reset, "\n\n"
734
+ get([image['id']])
735
+ end
736
+ else
737
+ image_file = File.new(filepath, 'rb')
738
+ if options[:dry_run]
739
+ print_dry_run @virtual_images_interface.dry.upload(image['id'], image_file, file_name, do_gzip)
740
+ return
741
+ end
742
+ unless options[:quiet]
743
+ print cyan, "Uploading file #{filepath} ...", reset, "\n"
744
+ end
745
+ json_response = @virtual_images_interface.upload(image['id'], image_file, file_name, do_gzip)
746
+ if options[:json]
747
+ print JSON.pretty_generate(json_response)
748
+ elsif !options[:quiet]
749
+ print "\n", cyan, "Virtual Image #{image['name']} successfully updated.", reset, "\n\n"
750
+ get([image['id']])
751
+ end
752
+ end
753
+
754
+ rescue RestClient::Exception => e
755
+ print_rest_exception(e, options)
756
+ exit 1
757
+ end
758
+ end
759
+
760
+ def remove_file(args)
761
+ options = {}
762
+ optparse = MtnCloud::Cli::OptionParser.new do |opts|
763
+ opts.banner = subcommand_usage("[image] [filename]")
764
+ build_common_options(opts, options, [:auto_confirm, :json, :dry_run, :remote])
765
+ end
766
+ optparse.parse!(args)
767
+ if args.count < 2
768
+ puts optparse
769
+ exit 1
770
+ end
771
+ image_name = args[0]
772
+ filename = args[1]
773
+ connect(options)
774
+ begin
775
+ image = find_virtual_image_by_name_or_id(image_name)
776
+ return 1 if image.nil?
777
+ unless options[:yes] || MtnCloud::Cli::OptionTypes.confirm("Are you sure you want to delete the virtual image filename #{filename}?")
778
+ return 9, "aborted"
779
+ end
780
+ @virtual_images_interface.setopts(options)
781
+ if options[:dry_run]
782
+ print_dry_run @virtual_images_interface.dry.destroy_file(image['id'], filename)
783
+ return
784
+ end
785
+ json_response = @virtual_images_interface.destroy_file(image['id'], filename)
786
+ if options[:json]
787
+ print JSON.pretty_generate(json_response)
788
+ else
789
+ print "\n", cyan, "Virtual Image #{image['name']} filename #{filename} removed", reset, "\n\n"
790
+ end
791
+ rescue RestClient::Exception => e
792
+ print_rest_exception(e, options)
793
+ exit 1
794
+ end
795
+ end
796
+
797
+ def remove(args)
798
+ params = {}
799
+ options = {}
800
+ optparse = MtnCloud::Cli::OptionParser.new do |opts|
801
+ opts.banner = subcommand_usage("[image] [location]")
802
+ opts.on('--remove-from-cloud [true|false]', String, "Remove from all clouds. Default is true.") do |val|
803
+ options[:options]['removeFromCloud'] = ['','true','on'].include?(val.to_s)
804
+ end
805
+ build_standard_remove_options(opts, options)
806
+ opts.footer = <<-EOT
807
+ Delete a virtual image.
808
+ [image] is required. This is the name or id of a virtual image.
809
+ EOT
810
+ end
811
+ optparse.parse!(args)
812
+ verify_args!(args:args, optparse:optparse, count:1)
813
+ connect(options)
814
+ image = find_virtual_image_by_name_or_id(args[0])
815
+ return 1, "virtual image not found for '#{args[0]}'" if image.nil?
816
+ params.merge!(parse_query_options(options))
817
+ # Delete prompt
818
+ # [ X ] Remove from all clouds
819
+ v_prompt = MtnCloud::Cli::OptionTypes.prompt([{'fieldName' => 'removeFromCloud', 'fieldLabel' => 'Remove from all clouds', 'type' => 'checkbox', 'defaultValue' => true, 'required' => true, 'description' => "Remove from all clouds"}], options[:options], @api_client)
820
+ remove_from_cloud = v_prompt['removeFromCloud'].to_s == 'true' || v_prompt['removeFromCloud'].to_s == 'on'
821
+ params['removeFromCloud'] = remove_from_cloud
822
+
823
+ # Delete confirmation
824
+ unless options[:yes] || MtnCloud::Cli::OptionTypes.confirm("Are you sure you want to delete the virtual image #{image['name']}?")
825
+ return 9, "aborted"
826
+ end
827
+
828
+ @virtual_images_interface.setopts(options)
829
+ if options[:dry_run]
830
+ print_dry_run @virtual_images_interface.dry.destroy(image['id'], params)
831
+ return
832
+ end
833
+ json_response = @virtual_images_interface.destroy(image['id'], params)
834
+ render_response(json_response, options) do
835
+ print_green_success "Removed virtual image #{image['name']}"
836
+ end
837
+ return 0, nil
838
+ end
839
+
840
+ def list_locations(args)
841
+ params = {}
842
+ options = {}
843
+ optparse = MtnCloud::Cli::OptionParser.new do |opts|
844
+ opts.banner = subcommand_usage("[image]")
845
+ build_standard_list_options(opts, options)
846
+ opts.footer = <<-EOT
847
+ List virtual image locations for a specific virtual image.
848
+ [image] is required. This is the name or id of a virtual image.
849
+ EOT
850
+ end
851
+ optparse.parse!(args)
852
+ verify_args!(args:args, optparse:optparse, min:1)
853
+ if args.count > 1
854
+ options[:phrase] = args[1..-1].join(" ")
855
+ end
856
+ connect(options)
857
+ image = find_virtual_image_by_name_or_id(args[0])
858
+ return 1, "virtual image not found for '#{args[0]}'" if image.nil?
859
+ params.merge!(parse_list_options(options))
860
+ @virtual_images_interface.setopts(options)
861
+ if options[:dry_run]
862
+ print_dry_run @virtual_images_interface.dry.list_locations(image['id'], params)
863
+ return
864
+ end
865
+ json_response = @virtual_images_interface.list_locations(image['id'], params)
866
+ records = json_response['locations']
867
+ render_response(json_response, options, 'virtualImages') do
868
+ title = "Virtual Image Locations"
869
+ subtitles = parse_list_subtitles(options)
870
+ print_h1 title, subtitles
871
+ if records.empty?
872
+ print cyan,"No virtual image locations found.",reset,"\n"
873
+ else
874
+ print as_pretty_table(records, virtual_image_location_list_column_definitions.upcase_keys!, options)
875
+ print_results_pagination(json_response)
876
+ end
877
+ print reset,"\n"
878
+ end
879
+ return 0, nil
880
+ end
881
+
882
+ def get_location(args)
883
+ params = {}
884
+ options = {}
885
+ optparse = MtnCloud::Cli::OptionParser.new do |opts|
886
+ opts.banner = subcommand_usage("[image] [location]")
887
+ build_standard_remove_options(opts, options)
888
+ opts.footer = <<-EOT
889
+ Get details about a virtual image location.
890
+ [image] is required. This is the name or id of a virtual image.
891
+ [location] is required. This is the name or id of a virtual image location.
892
+ EOT
893
+ end
894
+ optparse.parse!(args)
895
+ verify_args!(args:args, optparse:optparse, count:2)
896
+ connect(options)
897
+ image = find_virtual_image_by_name_or_id(args[0])
898
+ return 1, "virtual image not found for '#{args[0]}'" if image.nil?
899
+ location = find_virtual_image_location_by_name_or_id(image['id'], args[1])
900
+ return 1, "location not found for '#{args[1]}'" if location.nil?
901
+ params.merge!(parse_query_options(options))
902
+ @virtual_images_interface.setopts(options)
903
+ if options[:dry_run]
904
+ print_dry_run @virtual_images_interface.dry.get_location(image['id'], location['id'])
905
+ return 0, nil
906
+ end
907
+ # json_response = @virtual_images_interface.get(image['id'], location['id'])
908
+ json_response = {'location' => location} # skip redundant request
909
+ render_response(json_response, options, 'location') do
910
+ location = json_response['location']
911
+ volumes = location['volumes'] || []
912
+ print_h1 "Virtual Image Location Details", [], options
913
+ print_description_list(virtual_image_location_column_definitions, location, options)
914
+ if volumes && !volumes.empty?
915
+ print_h2 "Volumes", options
916
+ volume_rows = volumes.collect do |volume|
917
+ {name: volume['name'], size: Filesize.from("#{volume['rawSize']} B").pretty}
918
+ end
919
+ print cyan
920
+ print as_pretty_table(volume_rows, [:name, :size], options)
921
+ print cyan
922
+ # print "\n", reset
923
+ end
924
+ print reset,"\n"
925
+ end
926
+ return 0, nil
927
+ end
928
+
929
+ def remove_location(args)
930
+ params = {}
931
+ options = {}
932
+ optparse = MtnCloud::Cli::OptionParser.new do |opts|
933
+ opts.banner = subcommand_usage("[image] [location]")
934
+ opts.on('--remove-from-cloud [true|false]', String, "Remove from cloud. Default is true.") do |val|
935
+ options[:options]['removeFromCloud'] = ['','true','on'].include?(val.to_s)
936
+ end
937
+ build_standard_remove_options(opts, options)
938
+ opts.footer = <<-EOT
939
+ Delete a virtual image location.
940
+ [image] is required. This is the name or id of a virtual image.
941
+ [location] is required. This is the name or id of a virtual image location.
942
+ EOT
943
+ end
944
+ optparse.parse!(args)
945
+ verify_args!(args:args, optparse:optparse, count:2)
946
+ connect(options)
947
+ image = find_virtual_image_by_name_or_id(args[0])
948
+ return 1, "virtual image not found for '#{args[0]}'" if image.nil?
949
+ location = find_virtual_image_location_by_name_or_id(image['id'], args[1])
950
+ return 1, "location not found for '#{args[1]}'" if location.nil?
951
+
952
+ params.merge!(parse_query_options(options))
953
+
954
+ # Delete prompt
955
+ # [ X ] Remove from cloud
956
+ v_prompt = MtnCloud::Cli::OptionTypes.prompt([{'fieldName' => 'removeFromCloud', 'fieldLabel' => 'Remove from cloud', 'type' => 'checkbox', 'defaultValue' => true, 'required' => true, 'description' => "Remove from cloud"}], options[:options], @api_client)
957
+ remove_from_cloud = v_prompt['removeFromCloud'].to_s == 'true' || v_prompt['removeFromCloud'].to_s == 'on'
958
+ params['removeFromCloud'] = remove_from_cloud
959
+
960
+ # Delete confirmation
961
+ unless options[:yes] || MtnCloud::Cli::OptionTypes.confirm("Are you sure you want to delete the virtual image location #{location['id']}?")
962
+ return 9, "aborted"
963
+ end
964
+
965
+ @virtual_images_interface.setopts(options)
966
+ if options[:dry_run]
967
+ print_dry_run @virtual_images_interface.dry.destroy_location(image['id'], location['id'], params)
968
+ return
969
+ end
970
+ json_response = @virtual_images_interface.destroy_location(image['id'], location['id'], params)
971
+ render_response(json_response, options) do
972
+ print_green_success "Removed virtual image location #{location['id']}"
973
+ end
974
+ return 0, nil
975
+ end
976
+
977
+ def download(args)
978
+ full_command_string = "#{command_name} download #{args.join(' ')}".strip
979
+ options = {}
980
+ outfile = nil
981
+ do_overwrite = false
982
+ do_mkdir = false
983
+ optparse = MtnCloud::Cli::OptionParser.new do |opts|
984
+ opts.banner = subcommand_usage("[image] [local-file]")
985
+ opts.on( '-f', '--force', "Overwrite existing [local-file] if it exists." ) do
986
+ do_overwrite = true
987
+ # do_mkdir = true
988
+ end
989
+ opts.on( '-p', '--mkdir', "Create missing directories for [local-file] if they do not exist." ) do
990
+ do_mkdir = true
991
+ end
992
+ build_common_options(opts, options, [:dry_run, :quiet])
993
+ opts.footer = "Download a virtual image as a .zip file.\n" +
994
+ "[image] is required. This is the name or id of a virtual image.\n" +
995
+ "[local-file] is required. This is the full local filepath for the downloaded zip file."
996
+ end
997
+ optparse.parse!(args)
998
+ verify_args!(args:args, optparse:optparse, count:2)
999
+ connect(options)
1000
+
1001
+ virtual_image = find_virtual_image_by_name_or_id(args[0])
1002
+ return 1 if virtual_image.nil?
1003
+ outfile = args[1]
1004
+ # if outfile.end_with?(".zip")
1005
+ # print_red_alert "[local-file] is invalid. It must use extension .zip: #{outfile}"
1006
+ # return 1
1007
+ # end
1008
+ outfile = File.expand_path(outfile)
1009
+ if Dir.exist?(outfile)
1010
+ raise_command_error "[local-file] is invalid. It is the name of an existing directory: #{outfile}", args, optparse
1011
+ end
1012
+ destination_dir = File.dirname(outfile)
1013
+ if !Dir.exist?(destination_dir)
1014
+ if do_mkdir
1015
+ print cyan,"Creating local directory #{destination_dir}",reset,"\n"
1016
+ FileUtils.mkdir_p(destination_dir)
1017
+ else
1018
+ raise_command_error "[local-file] is invalid. Directory not found: #{destination_dir}", args, optparse
1019
+ end
1020
+ end
1021
+ if File.exist?(outfile)
1022
+ if do_overwrite
1023
+ # uhh need to be careful wih the passed filepath here..
1024
+ # don't delete, just overwrite.
1025
+ # File.delete(outfile)
1026
+ else
1027
+ raise_command_error "[local-file] is invalid. File already exists: #{outfile}", "Use -f to overwrite the existing file.", args, optparse
1028
+ end
1029
+ end
1030
+
1031
+ @virtual_images_interface.setopts(options)
1032
+ if options[:dry_run]
1033
+ print_dry_run @virtual_images_interface.dry.download_chunked(virtual_image['id'], outfile), full_command_string
1034
+ return 0, nil
1035
+ end
1036
+ if !options[:quiet]
1037
+ print cyan + "Downloading archive file #{virtual_image['name']} to #{outfile} ... "
1038
+ end
1039
+
1040
+ http_response = @virtual_images_interface.download_chunked(virtual_image['id'], outfile)
1041
+
1042
+ # FileUtils.chmod(0600, outfile)
1043
+ success = http_response.code.to_i == 200
1044
+ if success
1045
+ if !options[:quiet]
1046
+ print green + "SUCCESS" + reset + "\n"
1047
+ end
1048
+ return 0, nil
1049
+ else
1050
+ if !options[:quiet]
1051
+ print red + "ERROR" + reset + " HTTP #{http_response.code}" + "\n"
1052
+ end
1053
+ # F it, just remove a bad result
1054
+ if File.exist?(outfile) && File.file?(outfile)
1055
+ MtnCloud::Logging::DarkPrinter.puts "Deleting bad file download: #{outfile}" if MtnCloud::Logging.debug?
1056
+ File.delete(outfile)
1057
+ end
1058
+ if options[:debug]
1059
+ puts_error http_response.inspect
1060
+ end
1061
+ return 1, "Error downloading file"
1062
+ end
1063
+ end
1064
+
1065
+ private
1066
+
1067
+ def find_virtual_image_by_name_or_id(val)
1068
+ if val.to_s =~ /\A\d{1,}\Z/
1069
+ return find_virtual_image_by_id(val)
1070
+ else
1071
+ return find_virtual_image_by_name(val)
1072
+ end
1073
+ end
1074
+
1075
+ def find_virtual_image_by_id(id)
1076
+ begin
1077
+ json_response = @virtual_images_interface.get(id.to_i)
1078
+ return json_response['virtualImage']
1079
+ rescue RestClient::Exception => e
1080
+ if e.response && e.response.code == 404
1081
+ print_red_alert "Virtual Image not found by id #{id}"
1082
+ return nil
1083
+ else
1084
+ raise e
1085
+ end
1086
+ end
1087
+ end
1088
+
1089
+ def find_virtual_image_by_name(name)
1090
+ json_results = @virtual_images_interface.list({name: name.to_s})
1091
+ records = json_results['virtualImages']
1092
+ if records.empty?
1093
+ print_red_alert "Virtual Image not found by name #{name}"
1094
+ return nil
1095
+ elsif records.size > 1
1096
+ print_red_alert "More than one Virtual Image found by name '#{name}'"
1097
+ print_error "\n"
1098
+ puts_error as_pretty_table(records, [:id, :name], {color:red})
1099
+ print_red_alert "Try using ID instead"
1100
+ print_error reset,"\n"
1101
+ return nil
1102
+ else
1103
+ virtual_image = records[0]
1104
+ end
1105
+ return virtual_image
1106
+ end
1107
+
1108
+
1109
+ def get_available_virtual_image_types(refresh=false)
1110
+ if !@available_virtual_image_types || refresh
1111
+ @available_virtual_image_types = @virtual_images_interface.virtual_image_types['virtualImageTypes'] # || []
1112
+ end
1113
+ return @available_virtual_image_types
1114
+ end
1115
+
1116
+ def virtual_image_type_for_name_or_code(name)
1117
+ return get_available_virtual_image_types().find { |z| z['name'].downcase == name.downcase || z['code'].downcase == name.downcase}
1118
+ end
1119
+
1120
+ def add_virtual_image_option_types(image_type = nil, include_file_selection=true)
1121
+
1122
+ # todo: make api provide virtualImageType and its optionTypes.
1123
+ tmp_option_types = [
1124
+ {'fieldName' => 'name', 'fieldLabel' => 'Name', 'type' => 'text', 'required' => true, 'displayOrder' => 1},
1125
+ #{'fieldName' => 'imageType', 'fieldLabel' => 'Image Type', 'type' => 'select', 'optionSource' => 'virtualImageTypes', 'required' => true, 'description' => 'Select Virtual Image Type.', 'displayOrder' => 2},
1126
+ {'fieldName' => 'osType', 'fieldLabel' => 'Operating System', 'type' => 'select', 'optionSource' => 'osTypes', 'required' => false, 'description' => 'Select Operating System.', 'displayOrder' => 3},
1127
+ {'fieldName' => 'minRamGB', 'fieldLabel' => 'Minimum Memory (GB)', 'type' => 'number', 'required' => false, 'description' => 'Minimum Memory (GB)', 'displayOrder' => 4},
1128
+ # {'fieldName' => 'minDiskGB', 'fieldLabel' => 'Minimum Disk (GB)', 'type' => 'number', 'required' => false, 'description' => 'Minimum Memory (GB)', 'displayOrder' => 4},
1129
+ {'fieldName' => 'isCloudInit', 'fieldLabel' => 'Cloud Init Enabled?', 'type' => 'checkbox', 'defaultValue' => 'off', 'required' => false, 'description' => 'Cloud Init Enabled?', 'displayOrder' => 5},
1130
+ {'fieldName' => 'installAgent', 'fieldLabel' => 'Install Agent?', 'type' => 'checkbox', 'defaultValue' => 'off', 'required' => false, 'description' => 'Install Agent?', 'displayOrder' => 6},
1131
+ {'fieldName' => 'sshUsername', 'fieldLabel' => 'SSH Username', 'type' => 'text', 'required' => false, 'description' => 'Enter an SSH Username', 'displayOrder' => 7},
1132
+ {'fieldName' => 'sshPassword', 'fieldLabel' => 'SSH Password', 'type' => 'password', 'required' => false, 'description' => 'Enter an SSH Password', 'displayOrder' => 8},
1133
+ {'fieldName' => 'storageProviderId', 'type' => 'select', 'fieldLabel' => 'Bucket', 'optionSource' => 'storageProviders', 'required' => false, 'description' => 'Select Storage Provider.', 'displayOrder' => 9},
1134
+ {'fieldName' => 'userData', 'fieldLabel' => 'Cloud-Init User Data', 'type' => 'textarea', 'required' => false, 'displayOrder' => 10},
1135
+ {'fieldName' => 'visibility', 'fieldLabel' => 'Visibility', 'type' => 'select', 'selectOptions' => [{'name' => 'Private', 'value' => 'private'},{'name' => 'Public', 'value' => 'public'}], 'required' => false, 'description' => 'Visibility', 'category' => 'permissions', 'defaultValue' => 'private', 'displayOrder' => 40},
1136
+ {'fieldName' => 'isAutoJoinDomain', 'fieldLabel' => 'Auto Join Domain?', 'type' => 'checkbox', 'defaultValue' => 'off', 'required' => false, 'description' => 'Auto Join Domain?', 'category' => 'advanced', 'displayOrder' => 40},
1137
+ {'fieldName' => 'virtioSupported', 'fieldLabel' => 'VirtIO Drivers Loaded?', 'type' => 'checkbox', 'defaultValue' => 'on', 'required' => false, 'description' => 'VirtIO Drivers Loaded?', 'category' => 'advanced', 'displayOrder' => 40},
1138
+ {'fieldName' => 'vmToolsInstalled', 'fieldLabel' => 'VM Tools Installed?', 'type' => 'checkbox', 'defaultValue' => 'on', 'required' => false, 'description' => 'VM Tools Installed?', 'category' => 'advanced', 'displayOrder' => 40},
1139
+ {'fieldName' => 'isForceCustomization', 'fieldLabel' => 'Force Guest Customization?', 'type' => 'checkbox', 'defaultValue' => 'off', 'required' => false, 'description' => 'Force Guest Customization?', 'category' => 'advanced', 'displayOrder' => 40},
1140
+ {'fieldName' => 'trialVersion', 'fieldLabel' => 'Trial Version', 'type' => 'checkbox', 'defaultValue' => 'off', 'required' => false, 'description' => 'Trial Version', 'category' => 'advanced', 'displayOrder' => 40},
1141
+ {'fieldName' => 'isSysprep', 'fieldLabel' => 'Sysprep Enabled?', 'type' => 'checkbox', 'defaultValue' => 'off', 'required' => false, 'description' => 'Sysprep Enabled?', 'category' => 'advanced', 'displayOrder' => 40}
1142
+ ]
1143
+
1144
+ image_type_code = image_type ? image_type['code'] : nil
1145
+ if image_type_code
1146
+ if image_type_code == 'ami'
1147
+ tmp_option_types << {'fieldName' => 'externalId', 'fieldLabel' => 'AMI id', 'type' => 'text', 'required' => false, 'displayOrder' => 11}
1148
+ if include_file_selection
1149
+ tmp_option_types << {'fieldName' => 'imageFile', 'fieldLabel' => 'Image File', 'type' => 'file', 'required' => false, 'displayOrder' => 12}
1150
+ end
1151
+ elsif image_type_code == 'vmware' || image_type_code == 'vmdk'
1152
+ if include_file_selection
1153
+ tmp_option_types << {'fieldContext' => 'virtualImageFiles', 'fieldName' => 'imageFile', 'fieldLabel' => 'OVF File', 'type' => 'file', 'required' => false, 'displayOrder' => 11}
1154
+ tmp_option_types << {'fieldContext' => 'virtualImageFiles', 'fieldName' => 'imageDescriptorFile', 'fieldLabel' => 'VMDK File', 'type' => 'file', 'required' => false, 'displayOrder' => 12}
1155
+ end
1156
+ elsif image_type_code == 'pxe'
1157
+ tmp_option_types << {'fieldName' => 'config.menu', 'fieldLabel' => 'Menu', 'type' => 'text', 'required' => false, 'displayOrder' => 11}
1158
+ tmp_option_types << {'fieldName' => 'imagePath', 'fieldLabel' => 'Image Path', 'type' => 'text', 'required' => true, 'displayOrder' => 12}
1159
+ tmp_option_types.reject! {|opt| ['isCloudInit', 'installAgent', 'sshUsername', 'sshPassword'].include?(opt['fieldName'])}
1160
+ elsif image_type_code == 'azure' || image_type_code == 'azure-reference'
1161
+ # Azure Marketplace Prompt happens elsewhere
1162
+ tmp_option_types.reject! {|opt| ['storageProviderId', 'userData', 'sshUsername', 'sshPassword'].include?(opt['fieldName'])}
1163
+ else
1164
+ if include_file_selection
1165
+ tmp_option_types << {'code' => 'virtualImage.uploadType', 'fieldName' => 'uploadType', 'fieldLabel' => 'Create Image ID', 'type' => 'select', 'selectOptions' => [{'name' => 'File', 'value' => 'file'},{'name' => 'URL/Path', 'value' => 'url'},{'name' => 'None', 'value' => 'none'}], 'defaultValue' => 'file', 'required' => false, 'description' => 'Choose upload type: file, url or none', 'displayOrder' => 11}
1166
+ tmp_option_types << {'dependsOnCode' => 'virtualImage.uploadType:file', 'fieldContext' => 'virtualImageFiles', 'fieldName' => 'imageFile', 'fieldLabel' => 'Image File', 'type' => 'file', 'required' => false, 'description' => 'Choose an image file to upload', 'displayOrder' => 12}
1167
+ tmp_option_types << {'dependsOnCode' => 'virtualImage.uploadType:url', 'fieldName' => 'url', 'fieldLabel' => 'URL/Path', 'type' => 'text', 'required' => false, 'description' => 'Enter URL/Path to virtual image file(s)', 'displayOrder' => 13}
1168
+ end
1169
+ end
1170
+ end
1171
+
1172
+ return tmp_option_types
1173
+ end
1174
+
1175
+ def update_virtual_image_option_types(image_type = nil)
1176
+ list = add_virtual_image_option_types(image_type)
1177
+ list.each {|it|
1178
+ it.delete('required')
1179
+ it.delete('defaultValue')
1180
+ }
1181
+ list
1182
+ end
1183
+
1184
+ def convert_virtual_image_option_types(source_format=nil)
1185
+ [
1186
+ {'shorthand' => '-f', 'fieldName' => 'format', 'type' => 'select', 'fieldLabel' => 'Format', 'selectOptions' => get_convert_image_formats(source_format), 'required' => true, 'defaultValue' => (source_format == 'qcow2' ? nil : 'qcow2')},
1187
+ {'shorthand' => '-b', 'fieldName' => 'storageProviderId', 'type' => 'select', 'fieldLabel' => 'Bucket', 'optionSource' => 'storageProviders', 'required' => false, 'description' => 'Select Storage Provider Bucket or File Share.'},
1188
+ {'shorthand' => '-n', 'fieldName' => 'name', 'fieldLabel' => 'Name', 'type' => 'text', 'required' => false}
1189
+ ]
1190
+ end
1191
+
1192
+ def convert_source_types
1193
+ ["raw","qcow2","vmdk",'vmware', "vhd","ovf"]
1194
+ end
1195
+
1196
+ def convert_destination_types
1197
+ #["raw", "qcow2", "vmdk",'vmware',"vhd","ovf"]
1198
+ convert_source_types
1199
+ end
1200
+
1201
+ def get_convert_image_formats(source_format=nil)
1202
+ categories = [
1203
+ {'name' => 'QCOW2', 'value' => 'qcow2'},
1204
+ {'name' => 'VMDK', 'value' => 'ovf'},
1205
+ {'name' => 'VHD', 'value' => 'vhd'},
1206
+ {'name' => 'Raw', 'value' => 'raw'}
1207
+ ]
1208
+ # if source format (imageType) is not in the list, then no options
1209
+ # else reject the current value
1210
+ if source_format
1211
+ if !convert_source_types.include?(source_format.to_s.downcase)
1212
+ categories = []
1213
+ else
1214
+ categories = categories.select {|it| it['value'] != source_format.to_s.downcase }
1215
+ end
1216
+ end
1217
+ return categories
1218
+ end
1219
+
1220
+ def format_tenants(accounts)
1221
+ if accounts && accounts.size > 0
1222
+ accounts = accounts.sort {|a,b| a['name'] <=> b['name'] }.uniq {|it| it['id'] }
1223
+ account_ids = accounts.collect {|it| it['id'] }
1224
+ account_names = accounts.collect {|it| it['name'] }
1225
+ "(#{account_ids.join(',')}) #{account_names.join(',')}"
1226
+ else
1227
+ ""
1228
+ end
1229
+ end
1230
+
1231
+ def prompt_azure_marketplace(cloud_id, options)
1232
+ rtn = {}
1233
+ publisher_value, offer_value, sku_value, version_value = nil, nil, nil, nil
1234
+
1235
+ # Marketplace Publisher & Offer
1236
+ marketplace_api_params = {'zoneId' => cloud_id}
1237
+ v_prompt = nil
1238
+ # API endpoints moved from /api/options to /api/options/azure...
1239
+ begin
1240
+ v_prompt = MtnCloud::Cli::OptionTypes.prompt([{'fieldName' => 'offer', 'fieldLabel' => 'Azure Marketplace Offer', 'type' => 'typeahead', 'optionSourceType' => 'azure', 'optionSource' => 'searchAzureMarketplace', 'required' => true, 'description' => "Select Azure Marketplace Offer."}], options[:options],@api_client, marketplace_api_params)
1241
+ rescue => ex
1242
+ MtnCloud::Logging::DarkPrinter.puts "Failed to load azure marketplace offers, trying older endpoint" if MtnCloud::Logging.debug?
1243
+ v_prompt = MtnCloud::Cli::OptionTypes.prompt([{'fieldName' => 'offer', 'fieldLabel' => 'Azure Marketplace Offer', 'type' => 'typeahead', 'optionSource' => 'searchAzureMarketplace', 'required' => true, 'description' => "Select Azure Marketplace Offer."}], options[:options],@api_client, marketplace_api_params)
1244
+ end
1245
+ # offer_value = v_prompt['marketplace']
1246
+ # actually need both offer and publisher of these to query correctly..sigh
1247
+ marketplace_option = MtnCloud::Cli::OptionTypes.get_last_select()
1248
+ offer_value = marketplace_option['offer']
1249
+ publisher_value = marketplace_option['publisher']
1250
+
1251
+ # SKU & VERSION
1252
+ if options[:options] && options[:options]['sku'] && options[:options]['version']
1253
+ # the value to match on is actually sku|version
1254
+ options[:options]['sku'] = options[:options]['sku'] + '|' + options[:options]['version']
1255
+ end
1256
+ sku_api_params = {'zoneId' => cloud_id, publisher: publisher_value, offer: offer_value}
1257
+ begin
1258
+ v_prompt = MtnCloud::Cli::OptionTypes.prompt([{'fieldName' => 'sku', 'fieldLabel' => 'Azure Marketplace SKU', 'type' => 'select', 'optionSourceType' => 'azure', 'optionSource' => 'searchAzureMarketplaceSkus', 'required' => true, 'description' => "Select Azure Marketplace SKU and Version, the format is SKU|Version"}], options[:options],@api_client, sku_api_params)
1259
+ rescue => ex
1260
+ MtnCloud::Logging::DarkPrinter.puts "Failed to load azure marketplace offers, trying older endpoint" if MtnCloud::Logging.debug?
1261
+ v_prompt = MtnCloud::Cli::OptionTypes.prompt([{'fieldName' => 'sku', 'fieldLabel' => 'Azure Marketplace SKU', 'type' => 'select', 'optionSource' => 'searchAzureMarketplaceSkus', 'required' => true, 'description' => "Select Azure Marketplace SKU and Version, the format is SKU|Version"}], options[:options],@api_client, sku_api_params)
1262
+ end
1263
+ # marketplace_option = MtnCloud::Cli::OptionTypes.get_last_select()
1264
+ # sku_value = marketplace_option['sku']
1265
+ # version_value = marketplace_option['version']
1266
+ sku_value = v_prompt['sku']
1267
+ if sku_value && sku_value.include?("|")
1268
+ sku_value, version_value = sku_value.split("|")
1269
+ end
1270
+
1271
+ rtn['publisher'] = publisher_value
1272
+ rtn['offer'] = offer_value
1273
+ rtn['sku'] = sku_value
1274
+ rtn['version'] = version_value
1275
+ return rtn
1276
+ end
1277
+
1278
+ def format_virtual_image_source(virtual_image, return_color=cyan)
1279
+ out = ""
1280
+ if virtual_image['userUploaded']
1281
+ # out << "#{green}UPLOADED#{return_color}"
1282
+ out << "#{cyan}UPLOADED#{return_color}"
1283
+ elsif virtual_image['systemImage']
1284
+ out << "#{cyan}SYSTEM#{return_color}"
1285
+ else
1286
+ out << "#{cyan}SYNCED#{return_color}"
1287
+ end
1288
+ out
1289
+ end
1290
+
1291
+
1292
+ ## Virtual Image Locations
1293
+
1294
+ def virtual_image_location_object_key
1295
+ "location"
1296
+ end
1297
+
1298
+ def virtual_image_location_list_key
1299
+ "locations"
1300
+ end
1301
+
1302
+ def find_virtual_image_location_by_name_or_id(virtual_image_id, val)
1303
+ if val.to_s =~ /\A\d{1,}\Z/
1304
+ return find_virtual_image_location_by_id(virtual_image_id, val)
1305
+ else
1306
+ return find_virtual_image_location_by_name(virtual_image_id, val)
1307
+ end
1308
+ end
1309
+
1310
+ def virtual_image_location_list_column_definitions
1311
+ virtual_image_location_column_definitions
1312
+ end
1313
+
1314
+ def virtual_image_location_column_definitions
1315
+ {
1316
+ "ID" => 'id',
1317
+ "Name" => 'imageName',
1318
+ "Cloud" => lambda {|it| it['cloud']['name'] rescue '' },
1319
+ "Public" => lambda {|it| format_boolean(it['isPublic']) },
1320
+ "Region" => lambda {|it| it['imageRegion'] },
1321
+ "External ID" => lambda {|it| it['externalId'] },
1322
+ "Price Plan" => lambda {|it| it['pricePlan'] ? it['pricePlan']['name'] : nil },
1323
+ # "Virtual Image" => lambda {|it| it['virtualImage']['name'] rescue '' },
1324
+ # "Created" => lambda {|it| format_local_dt(it['dateCreated']) },
1325
+ # "Updated" => lambda {|it| format_local_dt(it['lastUpdated']) }
1326
+ }
1327
+ end
1328
+
1329
+
1330
+ def find_virtual_image_location_by_id(virtual_image_id, id)
1331
+ begin
1332
+ json_response = @virtual_images_interface.get_location(virtual_image_id, id.to_i)
1333
+ return json_response[virtual_image_location_object_key]
1334
+ rescue RestClient::Exception => e
1335
+ if e.response && e.response.code == 404
1336
+ print_red_alert "Virtual Image Location not found by id '#{id}'"
1337
+ else
1338
+ raise e
1339
+ end
1340
+ end
1341
+ end
1342
+
1343
+ def find_virtual_image_location_by_name(virtual_image_id, name)
1344
+ json_response = @virtual_images_interface.list_locations(virtual_image_id, {imageName: name.to_s})
1345
+ virtual_image_locations = json_response[virtual_image_location_list_key]
1346
+ if virtual_image_locations.empty?
1347
+ print_red_alert "Virtual Image Location not found by name '#{name}'"
1348
+ return nil
1349
+ elsif virtual_image_locations.size > 1
1350
+ print_red_alert "#{virtual_image_locations.size} Virtual Image Locations found by name '#{name}'"
1351
+ print_error "\n"
1352
+ puts_error as_pretty_table(virtual_image_locations, {"ID" => 'id', "NAME" => 'imageName'}, {color:red})
1353
+ print_red_alert "Try using ID instead"
1354
+ print_error reset,"\n"
1355
+ return nil
1356
+ else
1357
+ return virtual_image_locations[0]
1358
+ end
1359
+ end
1360
+
1361
+
1362
+ end