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,2037 @@
1
+ require 'mtncloud/cli/cli_command'
2
+
3
+ class MtnCloud::Cli::Clouds
4
+ include MtnCloud::Cli::CliCommand
5
+ include MtnCloud::Cli::AccountsHelper
6
+ include MtnCloud::Cli::InfrastructureHelper
7
+ include MtnCloud::Cli::ProvisioningHelper
8
+ include MtnCloud::Cli::WhoamiHelper
9
+ include MtnCloud::Cli::AffinityHelper
10
+
11
+ register_subcommands :list, :count, :get, :add, :update, :remove, :refresh, :security_groups, :apply_security_groups
12
+ register_subcommands :types, :type
13
+ alias_subcommand :'list-types', :types
14
+ alias_subcommand :'get-type', :type
15
+ register_subcommands :wiki, :update_wiki
16
+ register_subcommands({:'update-logo' => :update_logo,:'update-dark-logo' => :update_dark_logo})
17
+ register_subcommands :list_affinity_groups, :get_affinity_group, :update_affinity_group, :add_affinity_group, :remove_affinity_group
18
+ register_subcommands :list_host_vm_groups, :get_host_vm_group, :add_host_vm_group, :update_host_vm_group, :remove_host_vm_group
19
+ #register_subcommands :firewall_disable, :firewall_enable
20
+ alias_subcommand :details, :get
21
+ set_default_subcommand :list
22
+
23
+ def initialize()
24
+ # @appliance_name, @appliance_url = MtnCloud::Cli::Remote.active_appliance
25
+ end
26
+
27
+ def connect(opts)
28
+ @api_client = establish_remote_appliance_connection(opts)
29
+ @clouds_interface = @api_client.clouds
30
+ @groups_interface = @api_client.groups
31
+ @accounts_interface = @api_client.accounts
32
+ @account_users_interface = @api_client.account_users
33
+ @active_group_id = MtnCloud::Cli::Groups.active_groups[@appliance_name]
34
+ end
35
+
36
+ def handle(args)
37
+ handle_subcommand(args)
38
+ end
39
+
40
+ def list(args)
41
+ options={}
42
+ params = {}
43
+ optparse = MtnCloud::Cli::OptionParser.new do |opts|
44
+ opts.banner = subcommand_usage()
45
+ opts.on( '-g', '--group GROUP', "Group Name" ) do |group|
46
+ options[:group] = group
47
+ end
48
+ opts.on( '-t', '--type TYPE', "Cloud Type" ) do |val|
49
+ options[:zone_type] = val
50
+ end
51
+ opts.on('-l', '--labels LABEL', String, "Filter by labels, can match any of the values") do |val|
52
+ add_query_parameter(params, 'labels', parse_labels(val))
53
+ end
54
+ opts.on('--all-labels LABEL', String, "Filter by labels, must match all of the values") do |val|
55
+ add_query_parameter(params, 'allLabels', parse_labels(val))
56
+ end
57
+ opts.on('--include-tenants','--include-tenants', "Include sub tenant clouds") do
58
+ options[:include_tenants] = true
59
+ params['includeTenants'] = true
60
+ end
61
+ opts.on('--tenant TENANT', String, "Tenant Name or ID" ) do |val|
62
+ options[:tenant] = val
63
+ end
64
+ build_standard_list_options(opts, options)
65
+ opts.footer = "List clouds."
66
+ end
67
+ optparse.parse!(args)
68
+ connect(options)
69
+ # verify_args!(args:args, optparse:optparse, count:0)
70
+ if args.count > 0
71
+ options[:phrase] = args.join(" ")
72
+ end
73
+ begin
74
+ if options[:zone_type]
75
+ cloud_type = cloud_type_for_name(options[:zone_type])
76
+ params[:type] = cloud_type['code']
77
+ end
78
+ if !options[:group].nil?
79
+ group = find_group_by_name(options[:group])
80
+ if !group.nil?
81
+ params['groupId'] = group['id']
82
+ end
83
+ end
84
+ if options[:tenant]
85
+ if options[:tenant].to_s !~ /\A\d{1,}\Z/
86
+ account = find_account_by_name_or_id(options[:tenant])
87
+ if account.nil?
88
+ return 1, "Tenant not found by name: #{options[:tenant]}"
89
+ else
90
+ params['tenantId'] = account['id']
91
+ end
92
+ else
93
+ params['tenantId'] = options[:tenant]
94
+ end
95
+ end
96
+ params.merge!(parse_list_options(options))
97
+ @clouds_interface.setopts(options)
98
+ if options[:dry_run]
99
+ print_dry_run @clouds_interface.dry.list(params)
100
+ return 0
101
+ end
102
+
103
+ json_response = @clouds_interface.list(params)
104
+ render_response(json_response, options, 'zones') do
105
+ clouds = json_response['zones']
106
+ title = "Clouds"
107
+ subtitles = []
108
+ if group
109
+ subtitles << "Group: #{group['name']}".strip
110
+ end
111
+ if cloud_type
112
+ subtitles << "Type: #{cloud_type['name']}".strip
113
+ end
114
+ subtitles += parse_list_subtitles(options)
115
+ print_h1 title, subtitles
116
+ if clouds.empty?
117
+ print cyan,"No clouds found.",reset,"\n"
118
+ else
119
+ columns = cloud_list_column_definitions(options).upcase_keys!
120
+ if !options[:include_tenants] && !options[:tenant]
121
+ columns.delete("Tenant")
122
+ end
123
+ print as_pretty_table(clouds, columns, options)
124
+ print_results_pagination(json_response)
125
+ end
126
+ print reset,"\n"
127
+ end
128
+ return 0, nil
129
+ rescue RestClient::Exception => e
130
+ print_rest_exception(e, options)
131
+ exit 1
132
+ end
133
+ end
134
+
135
+ def count(args)
136
+ options = {}
137
+ optparse = MtnCloud::Cli::OptionParser.new do |opts|
138
+ opts.banner = subcommand_usage("[options]")
139
+ build_common_options(opts, options, [:query, :remote, :dry_run])
140
+ opts.footer = "Get the number of clouds."
141
+ end
142
+ optparse.parse!(args)
143
+ connect(options)
144
+ begin
145
+ params = {}
146
+ params.merge!(parse_list_options(options))
147
+ @clouds_interface.setopts(options)
148
+ if options[:dry_run]
149
+ print_dry_run @clouds_interface.dry.list(params)
150
+ return
151
+ end
152
+ json_response = @clouds_interface.list(params)
153
+ # print number only
154
+ if json_response['meta'] && json_response['meta']['total']
155
+ print cyan, json_response['meta']['total'], reset, "\n"
156
+ else
157
+ print yellow, "unknown", reset, "\n"
158
+ end
159
+ rescue RestClient::Exception => e
160
+ print_rest_exception(e, options)
161
+ exit 1
162
+ end
163
+ end
164
+
165
+ def get(args)
166
+ options = {}
167
+ params = {}
168
+ optparse = MtnCloud::Cli::OptionParser.new do |opts|
169
+ opts.banner = subcommand_usage("[name]")
170
+ opts.on('--include-tenants','--include-tenants', "Include sub tenant clouds when finding cloud by name") do
171
+ options[:include_tenants] = true
172
+ end
173
+ build_standard_list_options(opts, options)
174
+ opts.footer = "Get details about a cloud.\n" +
175
+ "[name] is required. This is the name or id of a cloud."
176
+ end
177
+ optparse.parse!(args)
178
+ verify_args!(args:args, optparse:optparse, min:1)
179
+ connect(options)
180
+ params.merge!(parse_query_options(options))
181
+ id_list = parse_id_list(args)
182
+ return run_command_for_each_arg(id_list) do |arg|
183
+ _get(arg, params, options)
184
+ end
185
+ end
186
+
187
+ def _get(id, params, options={})
188
+ cloud = nil
189
+ if id.to_s !~ /\A\d{1,}\Z/
190
+ cloud = find_cloud_by_name_or_id(id, options[:include_tenants])
191
+ id = cloud['id']
192
+ end
193
+ @clouds_interface.setopts(options)
194
+ if options[:dry_run]
195
+ print_dry_run @clouds_interface.dry.get(id.to_i, params)
196
+ return
197
+ end
198
+ json_response = @clouds_interface.get(id, params)
199
+ render_response(json_response, options, 'zone') do
200
+ cloud = json_response['zone']
201
+ cloud_stats = cloud['stats']
202
+ # serverCounts moved to zone.stats.serverCounts
203
+ server_counts = nil
204
+ if cloud_stats
205
+ server_counts = cloud_stats['serverCounts']
206
+ else
207
+ server_counts = json_response['serverCounts'] # legacy
208
+ end
209
+ #cloud_type = cloud_type_for_id(cloud['zoneTypeId'])
210
+ print_h1 "Cloud Details"
211
+ print cyan
212
+ description_cols = {
213
+ "ID" => 'id',
214
+ "Name" => 'name',
215
+ # "Type" => lambda {|it| cloud_type ? cloud_type['name'] : '' },
216
+ "Type" => lambda {|it| it['zoneType'] ? it['zoneType']['name'] : '' },
217
+ "Code" => 'code',
218
+ "Location" => 'location',
219
+ "Labels" => lambda {|it| format_list(it['labels'], '') rescue '' },
220
+ "Region Code" => 'regionCode',
221
+ "Visibility" => lambda {|it| it['visibility'].to_s.capitalize },
222
+ "Groups" => lambda {|it| it['groups'].collect {|g| g.instance_of?(Hash) ? g['name'] : g.to_s }.join(', ') },
223
+ #"Owner" => lambda {|it| it['owner'].instance_of?(Hash) ? it['owner']['name'] : it['ownerId'] },
224
+ "Tenant" => lambda {|it| it['account'].instance_of?(Hash) ? it['account']['name'] : it['accountId'] },
225
+ "Enabled" => lambda {|it| format_boolean(it['enabled']) },
226
+ "Last Sync" => lambda {|it| format_local_dt(it['lastSync']) },
227
+ "Sync Duration" => lambda {|it| format_duration_milliseconds(it['lastSyncDuration']).to_s },
228
+ "Status" => lambda {|it| format_cloud_status(it) },
229
+ }
230
+ print_description_list(description_cols, cloud)
231
+
232
+ print_h2 "Cloud Servers"
233
+ print cyan
234
+ if server_counts
235
+ print "Container Hosts: #{server_counts['containerHost']}".center(20)
236
+ print "Hypervisors: #{server_counts['hypervisor']}".center(20)
237
+ print "Bare Metal: #{server_counts['baremetal']}".center(20)
238
+ print "Virtual Machines: #{server_counts['vm']}".center(20)
239
+ print "Unmanaged: #{server_counts['unmanaged']}".center(20)
240
+ print "\n"
241
+ end
242
+ print reset,"\n"
243
+ end
244
+ return 0, nil
245
+ end
246
+
247
+ def add(args)
248
+ options = {}
249
+ params = {}
250
+ optparse = MtnCloud::Cli::OptionParser.new do |opts|
251
+ opts.banner = subcommand_usage("[name] --group GROUP --type TYPE")
252
+ opts.on( '-g', '--group GROUP', "Group Name" ) do |val|
253
+ params[:group] = val
254
+ end
255
+ opts.on( '-t', '--type TYPE', "Cloud Type" ) do |val|
256
+ params[:zone_type] = val
257
+ end
258
+ opts.on( '-d', '--description DESCRIPTION', "Description (optional)" ) do |desc|
259
+ params[:description] = desc
260
+ end
261
+ opts.on( '--certificate-provider CODE', String, "Certificate Provider. Default is 'internal'" ) do |val|
262
+ params[:certificate_provider] = val
263
+ end
264
+ opts.on('--costing-mode VALUE', String, "Costing Mode can be off,costing,full, Default is off." ) do |val|
265
+ options[:options]['costingMode'] = val
266
+ end
267
+ opts.on('--credential VALUE', String, "Credential ID or \"local\"" ) do |val|
268
+ options[:options]['credential'] = val
269
+ end
270
+ opts.on('-l', '--labels [LIST]', String, "Labels") do |val|
271
+ options[:options]['labels'] = parse_labels(val)
272
+ end
273
+
274
+ build_common_options(opts, options, [:options, :payload, :json, :dry_run, :remote])
275
+ end
276
+ optparse.parse!(args)
277
+ verify_args!(args:args, optparse:optparse, max:1)
278
+ connect(options)
279
+
280
+ begin
281
+ payload = nil
282
+ if options[:payload]
283
+ payload = options[:payload]
284
+ payload.deep_merge!({'zone' => parse_passed_options(options)})
285
+ else
286
+ cloud_payload = {name: args[0], description: params[:description]}
287
+ cloud_payload.deep_merge!(parse_passed_options(options))
288
+ # Group
289
+ # use active group by default
290
+ params[:group] ||= @active_group_id
291
+ if options[:options]['group']
292
+ params[:group] = options[:options]['group']
293
+ end
294
+ group_id = nil
295
+ group = params[:group] ? find_group_by_name_or_id_for_provisioning(params[:group]) : nil
296
+ if group
297
+ group_id = group["id"]
298
+ else
299
+ # print_red_alert "Group not found or specified!"
300
+ # exit 1
301
+ #groups_dropdown = @groups_interface.list({})['groups'].collect {|it| {'name' => it["name"], 'value' => it["id"]} }
302
+ group_prompt = MtnCloud::Cli::OptionTypes.prompt([{'fieldName' => 'group', 'type' => 'select', 'fieldLabel' => 'Group', 'optionSource' => 'groups', 'required' => true, 'description' => 'Select Group.'}],options[:options],@api_client,{})
303
+ group_id = group_prompt['group']
304
+ end
305
+ cloud_payload['groupId'] = group_id
306
+ cloud_payload.delete('group')
307
+ # todo: pass groups as an array instead
308
+
309
+ # Cloud Name
310
+ if args[0]
311
+ cloud_payload['name'] = args[0]
312
+ options[:options]['name'] = args[0] # to skip prompt
313
+ end
314
+ # name_prompt = MtnCloud::Cli::OptionTypes.prompt([{'fieldName' => 'name', 'fieldLabel' => 'Name', 'type' => 'text', 'required' => true}], options[:options])
315
+ # cloud_payload['name'] = name_prompt['name']
316
+
317
+ # Cloud Type
318
+ cloud_type = nil
319
+ if params[:zone_type]
320
+ cloud_type = cloud_type_for_name(params[:zone_type])
321
+ else
322
+ # print_red_alert "Cloud Type not found or specified!"
323
+ # exit 1
324
+ cloud_types_dropdown = cloud_types_for_dropdown
325
+ cloud_type_prompt = MtnCloud::Cli::OptionTypes.prompt([{'fieldName' => 'type', 'type' => 'select', 'fieldLabel' => 'Cloud Type', 'selectOptions' => cloud_types_dropdown, 'required' => true, 'description' => 'Select Cloud Type.'}],options[:options],@api_client,{})
326
+ cloud_type_code = cloud_type_prompt['type']
327
+ cloud_type = cloud_type_for_name(cloud_type_code) # this does work
328
+ end
329
+ if !cloud_type
330
+ print_red_alert "A cloud type is required."
331
+ exit 1
332
+ end
333
+ cloud_payload.delete('type')
334
+ cloud_payload['zoneType'] = {'code' => cloud_type['code']}
335
+
336
+ cloud_payload['config'] ||= {}
337
+ if params[:certificate_provider]
338
+ cloud_payload['config']['certificateProvider'] = params[:certificate_provider]
339
+ else
340
+ cloud_payload['config']['certificateProvider'] = 'internal'
341
+ end
342
+
343
+ all_option_types = add_cloud_option_types(cloud_type)
344
+
345
+ params = MtnCloud::Cli::OptionTypes.prompt(all_option_types, options[:options], @api_client, {zoneTypeId: cloud_type['id']})
346
+ # some optionTypes have fieldContext='zone', so move those to the root level of the zone payload
347
+ if params['zone'].is_a?(Hash)
348
+ cloud_payload.deep_merge!(params.delete('zone'))
349
+ end
350
+ cloud_payload.deep_merge!(params)
351
+ payload = {zone: cloud_payload}
352
+ end
353
+ @clouds_interface.setopts(options)
354
+ if options[:dry_run]
355
+ print_dry_run @clouds_interface.dry.create(payload)
356
+ return
357
+ end
358
+ json_response = @clouds_interface.create(payload)
359
+ cloud = json_response['zone']
360
+ if options[:json]
361
+ puts as_json(json_response, options)
362
+ else
363
+ get([cloud['id']] + (options[:remote] ? ["-r",options[:remote]] : []))
364
+ end
365
+ return 0
366
+ rescue RestClient::Exception => e
367
+ print_rest_exception(e, options)
368
+ exit 1
369
+ end
370
+ end
371
+
372
+ def update(args)
373
+ options = {}
374
+ params = {}
375
+ optparse = MtnCloud::Cli::OptionParser.new do |opts|
376
+ opts.banner = subcommand_usage("[name] [options]")
377
+ # opts.on( '-g', '--group GROUP', "Group Name" ) do |val|
378
+ # params[:group] = val
379
+ # end
380
+ # opts.on( '-t', '--type TYPE', "Cloud Type" ) do |val|
381
+ # params[:zone_type] = val
382
+ # end
383
+ # opts.on( '-d', '--description DESCRIPTION', "Description (optional)" ) do |desc|
384
+ # params[:description] = desc
385
+ # end
386
+ opts.on('-l', '--labels [LIST]', String, "Labels") do |val|
387
+ options[:options]['labels'] = parse_labels(val)
388
+ end
389
+ opts.on('--costing-mode VALUE', String, "Costing Mode can be off, costing, or full. Default is off." ) do |val|
390
+ options[:options]['costingMode'] = val
391
+ end
392
+ opts.on('--credential VALUE', String, "Credential ID or \"local\"" ) do |val|
393
+ options[:options]['credential'] = val
394
+ end
395
+ opts.on('--default-cloud-logos', "Reset logos to default cloud logos, removing any custom logo and dark logo" ) do
396
+ options[:options]['defaultCloudLogos'] = true
397
+ end
398
+
399
+ build_common_options(opts, options, [:options, :payload, :json, :dry_run, :remote])
400
+ end
401
+ optparse.parse!(args)
402
+ if args.count < 1
403
+ puts optparse
404
+ exit 1
405
+ end
406
+ connect(options)
407
+ begin
408
+ cloud = find_cloud_by_name_or_id(args[0])
409
+ return 1 if cloud.nil?
410
+ payload = nil
411
+ if options[:payload]
412
+ payload = options[:payload]
413
+ # support -O OPTION switch on top of --payload
414
+ if options[:options]
415
+ payload['zone'] ||= {}
416
+ payload['zone'].deep_merge!(options[:options].reject {|k,v| k.is_a?(Symbol) })
417
+ end
418
+ else
419
+ cloud_type = cloud_type_for_id(cloud['zoneTypeId'])
420
+ cloud_payload = {}
421
+ all_option_types = update_cloud_option_types(cloud_type)
422
+ #params = MtnCloud::Cli::OptionTypes.no_prompt(all_option_types, options[:options], @api_client, {zoneId: cloud['id'], zoneTypeId: cloud_type['id']})
423
+ params = options[:options] || {}
424
+
425
+ # Credentials (ideally only if value passed in and name can be parsed)
426
+ if options[:options]['credential']
427
+ credential_code = "credential"
428
+ credential_option_type = {'code' => credential_code, 'fieldName' => credential_code, 'fieldLabel' => 'Credentials', 'type' => 'select', 'optionSource' => 'credentials', 'description' => 'Enter an existing credential ID or choose "local"', 'defaultValue' => "local", 'required' => true}
429
+ # supported_credential_types = ['username-keypair', 'username-password', 'username-password-keypair'].compact.flatten.join(",").split(",").collect {|it| it.strip }
430
+ credential_params = {"new" => false, "zoneId" => cloud['id']}
431
+ credential_value = MtnCloud::Cli::OptionTypes.select_prompt(credential_option_type, @api_client, credential_params, true, options[:options][credential_code])
432
+ if !credential_value.to_s.empty?
433
+ if credential_value == "local"
434
+ params[credential_code] = {"type" => credential_value}
435
+ elsif credential_value.to_s =~ /\A\d{1,}\Z/
436
+ params[credential_code] = {"id" => credential_value.to_i}
437
+ end
438
+ end
439
+ end
440
+ if params.empty?
441
+ raise_command_error "Specify at least one option to update.\n#{optparse}"
442
+ end
443
+ # some optionTypes have fieldContext='zone', so move those to the root level of the zone payload
444
+ if params['zone'].is_a?(Hash)
445
+ cloud_payload.merge!(params.delete('zone'))
446
+ end
447
+ if params.key?('labels')
448
+ params['labels'] = parse_labels(params['labels'])
449
+ end
450
+ cloud_payload.merge!(params)
451
+ payload = {zone: cloud_payload}
452
+ end
453
+ @clouds_interface.setopts(options)
454
+ if options[:dry_run]
455
+ print_dry_run @clouds_interface.dry.update(cloud['id'], payload)
456
+ return
457
+ end
458
+ json_response = @clouds_interface.update(cloud['id'], payload)
459
+ if options[:json]
460
+ puts as_json(json_response, options)
461
+ else
462
+ get([cloud['id']] + (options[:remote] ? ["-r",options[:remote]] : []))
463
+ end
464
+ return 0
465
+ rescue RestClient::Exception => e
466
+ print_rest_exception(e, options)
467
+ exit 1
468
+ end
469
+ end
470
+
471
+ def remove(args)
472
+ options = {}
473
+ query_params = {}
474
+ optparse = MtnCloud::Cli::OptionParser.new do |opts|
475
+ opts.banner = subcommand_usage("[name]")
476
+ opts.on('--remove-resources [on|off]', ['on','off'], "Remove Associated Resources. Default is off.") do |val|
477
+ query_params[:removeResources] = val.nil? ? 'on' : val
478
+ end
479
+ opts.on( '-f', '--force', "Force Remove" ) do
480
+ query_params[:force] = 'on'
481
+ end
482
+ build_common_options(opts, options, [:auto_confirm, :quiet, :json, :dry_run, :remote])
483
+ end
484
+ optparse.parse!(args)
485
+ if args.count < 1
486
+ puts optparse
487
+ return
488
+ end
489
+ connect(options)
490
+ begin
491
+ cloud = find_cloud_by_name_or_id(args[0])
492
+ unless options[:yes] || MtnCloud::Cli::OptionTypes.confirm("Are you sure you want to delete the cloud #{cloud['name']}?")
493
+ exit
494
+ end
495
+ @clouds_interface.setopts(options)
496
+ if options[:dry_run]
497
+ print_dry_run @clouds_interface.dry.destroy(cloud['id'], query_params)
498
+ return 0
499
+ end
500
+ json_response = @clouds_interface.destroy(cloud['id'], query_params)
501
+ if options[:json]
502
+ print JSON.pretty_generate(json_response)
503
+ print "\n"
504
+ elsif !options[:quiet]
505
+ print_green_success "Removed cloud #{cloud['name']}"
506
+ #list([])
507
+ end
508
+ return 0
509
+ rescue RestClient::Exception => e
510
+ print_rest_exception(e, options)
511
+ exit 1
512
+ end
513
+ end
514
+
515
+ def refresh(args)
516
+ options = {}
517
+ query_params = {}
518
+ params = {}
519
+ optparse = MtnCloud::Cli::OptionParser.new do |opts|
520
+ opts.banner = subcommand_usage("[cloud] [options]")
521
+ opts.on( '-m', '--mode [daily|costing]', "Refresh Mode. Use this to run the daily or costing jobs instead of the default hourly refresh." ) do |val|
522
+ query_params[:mode] = val
523
+ end
524
+ opts.on( '--rebuild [on|off]', "Rebuild invoices for period. Only applies to mode=costing." ) do |val|
525
+ query_params[:rebuild] = val.to_s == 'on' || val.to_s == 'true' || val.to_s == '1' || val.to_s == ''
526
+ end
527
+ opts.on( '--period PERIOD', "Period in the format YYYYMM to process invoices for. Default is the current period. Only applies to mode=costing." ) do |val|
528
+ query_params[:period] = val.to_s
529
+ end
530
+ opts.on( '-f', '--force', "Force refresh. Useful if the cloud is disabled." ) do
531
+ query_params[:force] = 'true'
532
+ end
533
+ build_common_options(opts, options, [:options, :payload, :json, :dry_run, :remote])
534
+ opts.footer = "Refresh a cloud." + "\n" +
535
+ "[cloud] is required. This is the name or id of a cloud."
536
+ end
537
+ optparse.parse!(args)
538
+ if args.count != 1
539
+ raise_command_error "wrong number of arguments, expected 1 and got (#{args.count}) #{args}\n#{optparse}"
540
+ end
541
+ connect(options)
542
+ begin
543
+ cloud = find_cloud_by_name_or_id(args[0])
544
+ return 1 if cloud.nil?
545
+ passed_options = options[:options] ? options[:options].reject {|k,v| k.is_a?(Symbol) } : {}
546
+ payload = nil
547
+ if options[:payload]
548
+ payload = options[:payload]
549
+ payload.deep_merge!(passed_options) unless passed_options.empty?
550
+ else
551
+ payload = {}
552
+ payload.deep_merge!(passed_options) unless passed_options.empty?
553
+ end
554
+ @clouds_interface.setopts(options)
555
+ if options[:dry_run]
556
+ print_dry_run @clouds_interface.dry.refresh(cloud['id'], query_params, payload)
557
+ return
558
+ end
559
+ json_response = @clouds_interface.refresh(cloud['id'], query_params, payload)
560
+ if options[:json]
561
+ puts as_json(json_response, options)
562
+ else
563
+ print_green_success "Refreshing cloud #{cloud['name']}..."
564
+ #get([cloud['id']] + (options[:remote] ? ["-r",options[:remote]] : []))
565
+ end
566
+ return 0
567
+ rescue RestClient::Exception => e
568
+ print_rest_exception(e, options)
569
+ exit 1
570
+ end
571
+ end
572
+
573
+ # not exposed yet, refresh should be all that's needed.
574
+ def sync(args)
575
+ options = {}
576
+ query_params = {}
577
+ params = {}
578
+ optparse = MtnCloud::Cli::OptionParser.new do |opts|
579
+ opts.banner = subcommand_usage("[name] [options]")
580
+ opts.on( '-f', '--force', "Force Delete" ) do
581
+ query_params[:force] = 'true'
582
+ end
583
+ build_common_options(opts, options, [:options, :payload, :json, :dry_run, :remote])
584
+ opts.footer = "Sync a cloud." + "\n" +
585
+ "[cloud] is required. This is the name or id of a cloud."
586
+ end
587
+ optparse.parse!(args)
588
+ if args.count != 1
589
+ raise_command_error "wrong number of arguments, expected 1 and got (#{args.count}) #{args}\n#{optparse}"
590
+ end
591
+ connect(options)
592
+ begin
593
+ cloud = find_cloud_by_name_or_id(args[0])
594
+ return 1 if cloud.nil?
595
+ passed_options = options[:options] ? options[:options].reject {|k,v| k.is_a?(Symbol) } : {}
596
+ payload = nil
597
+ if options[:payload]
598
+ payload = options[:payload]
599
+ payload.deep_merge!(passed_options) unless passed_options.empty?
600
+ else
601
+ payload = {}
602
+ payload.deep_merge!(passed_options) unless passed_options.empty?
603
+ end
604
+ @clouds_interface.setopts(options)
605
+ if options[:dry_run]
606
+ print_dry_run @clouds_interface.dry.sync(cloud['id'], query_params, payload)
607
+ return
608
+ end
609
+ json_response = @clouds_interface.sync(cloud['id'], query_params, payload)
610
+ if options[:json]
611
+ puts as_json(json_response, options)
612
+ else
613
+ print_green_success "Syncing cloud #{cloud['name']}..."
614
+ #get([cloud['id']] + (options[:remote] ? ["-r",options[:remote]] : []))
615
+ end
616
+ return 0
617
+ rescue RestClient::Exception => e
618
+ print_rest_exception(e, options)
619
+ exit 1
620
+ end
621
+ end
622
+
623
+ def firewall_disable(args)
624
+ options = {}
625
+ clear_or_secgroups_specified = false
626
+ optparse = MtnCloud::Cli::OptionParser.new do |opts|
627
+ opts.banner = subcommand_usage("[name]")
628
+ build_common_options(opts, options, [:json, :dry_run, :remote])
629
+ end
630
+ optparse.parse!(args)
631
+ if args.count < 1
632
+ puts optparse
633
+ return
634
+ end
635
+ connect(options)
636
+ begin
637
+ cloud = find_cloud_by_name_or_id(args[0])
638
+ @clouds_interface.setopts(options)
639
+ if options[:dry_run]
640
+ print_dry_run @clouds_interface.dry.firewall_disable(cloud['id'])
641
+ return
642
+ end
643
+ json_response = @clouds_interface.firewall_disable(cloud['id'])
644
+ if options[:json]
645
+ print JSON.pretty_generate(json_response)
646
+ print "\n"
647
+ return
648
+ end
649
+ security_groups([args[0]])
650
+ rescue RestClient::Exception => e
651
+ print_rest_exception(e, options)
652
+ exit 1
653
+ end
654
+ end
655
+
656
+ def firewall_enable(args)
657
+ options = {}
658
+ clear_or_secgroups_specified = false
659
+ optparse = MtnCloud::Cli::OptionParser.new do |opts|
660
+ opts.banner = subcommand_usage("[name]")
661
+ build_common_options(opts, options, [:json, :dry_run, :remote])
662
+ end
663
+ optparse.parse!(args)
664
+ if args.count < 1
665
+ puts optparse
666
+ return
667
+ end
668
+ connect(options)
669
+ begin
670
+ cloud = find_cloud_by_name_or_id(args[0])
671
+ @clouds_interface.setopts(options)
672
+ if options[:dry_run]
673
+ print_dry_run @clouds_interface.dry.firewall_enable(cloud['id'])
674
+ return
675
+ end
676
+ json_response = @clouds_interface.firewall_enable(cloud['id'])
677
+ if options[:json]
678
+ print JSON.pretty_generate(json_response)
679
+ print "\n"
680
+ return
681
+ end
682
+ security_groups([args[0]])
683
+ rescue RestClient::Exception => e
684
+ print_rest_exception(e, options)
685
+ exit 1
686
+ end
687
+ end
688
+
689
+ def security_groups(args)
690
+ options = {}
691
+ clear_or_secgroups_specified = false
692
+ optparse = MtnCloud::Cli::OptionParser.new do |opts|
693
+ opts.banner = subcommand_usage("[name]")
694
+ build_common_options(opts, options, [:json, :dry_run, :remote])
695
+ end
696
+ optparse.parse!(args)
697
+ if args.count < 1
698
+ puts optparse
699
+ return
700
+ end
701
+ connect(options)
702
+ begin
703
+ cloud = find_cloud_by_name_or_id(args[0])
704
+ zone_id = cloud['id']
705
+ @clouds_interface.setopts(options)
706
+ if options[:dry_run]
707
+ print_dry_run @clouds_interface.dry.security_groups(zone_id)
708
+ return
709
+ end
710
+ json_response = @clouds_interface.security_groups(zone_id)
711
+ if options[:json]
712
+ print JSON.pretty_generate(json_response)
713
+ print "\n"
714
+ return
715
+ end
716
+ securityGroups = json_response['securityGroups']
717
+ print_h1 "Security Groups for Cloud: #{cloud['name']}"
718
+ print cyan
719
+ print_description_list({"Firewall Enabled" => lambda {|it| format_boolean it['firewallEnabled'] } }, json_response)
720
+ if securityGroups.empty?
721
+ print yellow,"\n","No security groups currently applied.",reset,"\n"
722
+ else
723
+ print "\n"
724
+ securityGroups.each do |securityGroup|
725
+ print cyan, "= #{securityGroup['id']} (#{securityGroup['name']}) - (#{securityGroup['description']})\n"
726
+ end
727
+ end
728
+ print reset,"\n"
729
+
730
+ rescue RestClient::Exception => e
731
+ print_rest_exception(e, options)
732
+ exit 1
733
+ end
734
+ end
735
+
736
+ def apply_security_groups(args)
737
+ options = {}
738
+ clear_or_secgroups_specified = false
739
+ optparse = MtnCloud::Cli::OptionParser.new do |opts|
740
+ opts.banner = subcommand_usage("[name] [-s] [--clear]")
741
+ opts.on( '-c', '--clear', "Clear all security groups" ) do
742
+ options[:securityGroupIds] = []
743
+ clear_or_secgroups_specified = true
744
+ end
745
+ opts.on( '-s', '--secgroups SECGROUPS', "Apply the specified comma separated security group ids" ) do |secgroups|
746
+ options[:securityGroupIds] = secgroups.split(",")
747
+ clear_or_secgroups_specified = true
748
+ end
749
+ build_common_options(opts, options, [:json, :dry_run, :remote])
750
+ end
751
+ optparse.parse!(args)
752
+ if !clear_or_secgroups_specified
753
+ puts optparse
754
+ exit
755
+ end
756
+ connect(options)
757
+ begin
758
+ cloud = find_cloud_by_name_or_id(args[0])
759
+ @clouds_interface.setopts(options)
760
+ if options[:dry_run]
761
+ print_dry_run @clouds_interface.dry.apply_security_groups(cloud['id'])
762
+ return
763
+ end
764
+ json_response = @clouds_interface.apply_security_groups(cloud['id'], options)
765
+ if options[:json]
766
+ print JSON.pretty_generate(json_response)
767
+ print "\n"
768
+ return
769
+ end
770
+ security_groups([args[0]])
771
+ rescue RestClient::Exception => e
772
+ print_rest_exception(e, options)
773
+ exit 1
774
+ end
775
+ end
776
+
777
+ def types(args)
778
+ options={}
779
+ params = {}
780
+ optparse = MtnCloud::Cli::OptionParser.new do |opts|
781
+ opts.banner = subcommand_usage("[search]")
782
+ build_standard_list_options(opts, options)
783
+ opts.footer = <<-EOT
784
+ List cloud types.
785
+ EOT
786
+ end
787
+ optparse.parse!(args)
788
+ connect(options)
789
+
790
+ if args.count > 0
791
+ options[:phrase] = args.join(" ")
792
+ end
793
+ params.merge!(parse_list_options(options))
794
+ @clouds_interface.setopts(options)
795
+ if options[:dry_run]
796
+ print_dry_run @clouds_interface.dry.cloud_types({})
797
+ return 0
798
+ end
799
+ json_response = @clouds_interface.cloud_types(params)
800
+
801
+ render_response(json_response, options, 'zoneTypes') do
802
+ cloud_types = json_response['zoneTypes']
803
+ subtitles = []
804
+ subtitles += parse_list_subtitles(options)
805
+ print_h1 "Cloud Types", subtitles, options
806
+ if cloud_types.empty?
807
+ print cyan,"No cloud types found.",reset,"\n"
808
+ else
809
+ print cyan
810
+ cloud_types = cloud_types.select {|it| it['enabled'] }
811
+ rows = cloud_types.collect do |cloud_type|
812
+ {id: cloud_type['id'], name: cloud_type['name'], code: cloud_type['code']}
813
+ end
814
+ #print "\n"
815
+ columns = [:id, :name, :code]
816
+ columns = options[:include_fields] if options[:include_fields]
817
+ print as_pretty_table(rows, columns, options)
818
+ print_results_pagination(json_response)
819
+ print reset,"\n"
820
+ end
821
+ end
822
+ end
823
+
824
+ def type(args)
825
+ options={}
826
+ params = {}
827
+ optparse = MtnCloud::Cli::OptionParser.new do |opts|
828
+ opts.banner = subcommand_usage("[type]")
829
+ build_standard_get_options(opts, options)
830
+ opts.footer = <<-EOT
831
+ Get details about a cloud type.
832
+ [type] is required. This is the name or id of cloud type.
833
+ EOT
834
+ end
835
+ optparse.parse!(args)
836
+ verify_args!(args:args, optparse:optparse, count:1)
837
+ connect(options)
838
+ # construct request
839
+ params.merge!(parse_query_options(options))
840
+ id = args[0]
841
+ cloud_type = nil
842
+ if id.to_s !~ /\A\d{1,}\Z/
843
+ cloud_type = cloud_type_for_name_or_id(id)
844
+ if cloud_type.nil?
845
+ raise_command_error "cloud type not found for name or code '#{id}'"
846
+ end
847
+ id = cloud_type['id']
848
+ end
849
+ # execute request
850
+ @clouds_interface.setopts(options)
851
+ if options[:dry_run]
852
+ print_dry_run @clouds_interface.dry.cloud_type(id.to_i)
853
+ return 0
854
+ end
855
+ json_response = @clouds_interface.cloud_type(id.to_i)
856
+ # render response
857
+ render_response(json_response, options, 'zoneType') do
858
+ cloud_type = json_response['zoneType']
859
+ print_h1 "Cloud Type", [], options
860
+ print cyan
861
+ #columns = rest_type_column_definitions(options)
862
+ columns = {
863
+ "ID" => 'id',
864
+ "Name" => 'name',
865
+ "Code" => 'code',
866
+ "Enabled" => lambda {|it| format_boolean it['enabled'] },
867
+ "Provision" => lambda {|it| format_boolean it['provision'] },
868
+ "Auto Capacity" => lambda {|it| format_boolean it['autoCapacity'] },
869
+ # "Migration Target" => lambda {|it| format_boolean it['migrationTarget'] },
870
+ "Datastores" => lambda {|it| format_boolean it['hasDatastores'] },
871
+ "Networks" => lambda {|it| format_boolean it['hasNetworks'] },
872
+ "Resource Pools" => lambda {|it| format_boolean it['hasResourcePools'] },
873
+ "Security Groups" => lambda {|it| format_boolean it['hasSecurityGroups'] },
874
+ "Containers" => lambda {|it| format_boolean it['hasContainers'] },
875
+ "Bare Metal" => lambda {|it| format_boolean it['hasBareMetal'] },
876
+ "Services" => lambda {|it| format_boolean it['hasServices'] },
877
+ "Functions" => lambda {|it| format_boolean it['hasFunctions'] },
878
+ "Jobs" => lambda {|it| format_boolean it['hasJobs'] },
879
+ "Discovery" => lambda {|it| format_boolean it['hasDiscovery'] },
880
+ "Cloud Init" => lambda {|it| format_boolean it['hasCloudInit'] },
881
+ "Folders" => lambda {|it| format_boolean it['hasFolders'] },
882
+ # "Marketplace" => lambda {|it| format_boolean it['hasMarketplace'] },
883
+ "Public Cloud" => lambda {|it| format_boolean(it['cloud'] == 'public') },
884
+ }
885
+ print_description_list(columns, cloud_type, options)
886
+ # Option Types
887
+ option_types = cloud_type['optionTypes']
888
+ if option_types && option_types.size > 0
889
+ print_h2 "Option Types", options
890
+ print format_option_types_table(option_types, options, "zone")
891
+ end
892
+ print reset,"\n"
893
+ end
894
+ end
895
+
896
+ def wiki(args)
897
+ options = {}
898
+ params = {}
899
+ open_wiki_link = false
900
+ optparse = MtnCloud::Cli::OptionParser.new do |opts|
901
+ opts.banner = subcommand_usage("[cloud]")
902
+ opts.on('--view', '--view', "View wiki page in web browser.") do
903
+ open_wiki_link = true
904
+ end
905
+ build_common_options(opts, options, [:json, :dry_run, :remote])
906
+ opts.footer = "View wiki page details for a cloud." + "\n" +
907
+ "[cloud] is required. This is the name or id of a cloud."
908
+ end
909
+ optparse.parse!(args)
910
+ if args.count != 1
911
+ puts_error "#{MtnCloud::Terminal.angry_prompt}wrong number of arguments. Expected 1 and received #{args.count} #{args.inspect}\n#{optparse}"
912
+ return 1
913
+ end
914
+ connect(options)
915
+
916
+ begin
917
+ cloud = find_cloud_by_name_or_id(args[0])
918
+ return 1 if cloud.nil?
919
+
920
+
921
+ @clouds_interface.setopts(options)
922
+ if options[:dry_run]
923
+ print_dry_run @clouds_interface.dry.wiki(cloud["id"], params)
924
+ return
925
+ end
926
+ json_response = @clouds_interface.wiki(cloud["id"], params)
927
+ page = json_response['page']
928
+
929
+ render_result = render_with_format(json_response, options, 'page')
930
+ return 0 if render_result
931
+
932
+ if page
933
+
934
+ # my_terminal.exec("wiki get #{page['id']}")
935
+
936
+ print_h1 "Cloud Wiki Page: #{cloud['name']}"
937
+ # print_h1 "Wiki Page Details"
938
+ print cyan
939
+
940
+ print_description_list({
941
+ "Page ID" => 'id',
942
+ "Name" => 'name',
943
+ #"Category" => 'category',
944
+ #"Ref Type" => 'refType',
945
+ #"Ref ID" => 'refId',
946
+ #"Owner" => lambda {|it| it['account'] ? it['account']['name'] : '' },
947
+ "Created" => lambda {|it| format_local_dt(it['dateCreated']) },
948
+ "Created By" => lambda {|it| it['createdBy'] ? it['createdBy']['username'] : '' },
949
+ "Updated" => lambda {|it| format_local_dt(it['lastUpdated']) },
950
+ "Updated By" => lambda {|it| it['updatedBy'] ? it['updatedBy']['username'] : '' }
951
+ }, page)
952
+ print reset,"\n"
953
+
954
+ print_h2 "Page Content"
955
+ print cyan, page['content'], reset, "\n"
956
+
957
+ else
958
+ print "\n"
959
+ print cyan, "No wiki page found.", reset, "\n"
960
+ end
961
+ print reset,"\n"
962
+
963
+ if open_wiki_link
964
+ return view_wiki([args[0]])
965
+ end
966
+
967
+ return 0
968
+ rescue RestClient::Exception => e
969
+ print_rest_exception(e, options)
970
+ exit 1
971
+ end
972
+ end
973
+
974
+ def view_wiki(args)
975
+ params = {}
976
+ options = {}
977
+ optparse = MtnCloud::Cli::OptionParser.new do |opts|
978
+ opts.banner = subcommand_usage("[id]")
979
+ build_common_options(opts, options, [:dry_run, :remote])
980
+ opts.footer = "View cloud wiki page in a web browser" + "\n" +
981
+ "[cloud] is required. This is the name or id of a cloud."
982
+ end
983
+ optparse.parse!(args)
984
+ if args.count != 1
985
+ raise_command_error "wrong number of arguments, expected 1 and got (#{args.count}) #{args.join(' ')}\n#{optparse}"
986
+ end
987
+ connect(options)
988
+ begin
989
+ cloud = find_cloud_by_name_or_id(args[0])
990
+ return 1 if cloud.nil?
991
+
992
+ link = "#{@appliance_url}/login/oauth-redirect?access_token=#{@access_token}\\&redirectUri=/infrastructure/clouds/#{cloud['id']}#!wiki"
993
+
994
+ if options[:dry_run]
995
+ puts MtnCloud::Util.open_url_command(link)
996
+ return 0
997
+ end
998
+ return MtnCloud::Util.open_url(link)
999
+ rescue RestClient::Exception => e
1000
+ print_rest_exception(e, options)
1001
+ exit 1
1002
+ end
1003
+ end
1004
+
1005
+ def update_wiki(args)
1006
+ options = {}
1007
+ params = {}
1008
+ optparse = MtnCloud::Cli::OptionParser.new do |opts|
1009
+ opts.banner = subcommand_usage("[cloud] [options]")
1010
+ build_option_type_options(opts, options, update_wiki_page_option_types)
1011
+ opts.on('--file FILE', "File containing the wiki content. This can be used instead of --content") do |filename|
1012
+ full_filename = File.expand_path(filename)
1013
+ if File.exist?(full_filename)
1014
+ params['content'] = File.read(full_filename)
1015
+ else
1016
+ print_red_alert "File not found: #{full_filename}"
1017
+ return 1
1018
+ end
1019
+ # use the filename as the name by default.
1020
+ if !params['name']
1021
+ params['name'] = File.basename(full_filename)
1022
+ end
1023
+ end
1024
+ opts.on(nil, '--clear', "Clear current page content") do |val|
1025
+ params['content'] = ""
1026
+ end
1027
+ build_common_options(opts, options, [:options, :payload, :json, :dry_run, :remote])
1028
+ end
1029
+ optparse.parse!(args)
1030
+ if args.count != 1
1031
+ puts_error "#{MtnCloud::Terminal.angry_prompt}wrong number of arguments. Expected 1 and received #{args.count} #{args.inspect}\n#{optparse}"
1032
+ return 1
1033
+ end
1034
+ connect(options)
1035
+
1036
+ begin
1037
+ cloud = find_cloud_by_name_or_id(args[0])
1038
+ return 1 if cloud.nil?
1039
+ # construct payload
1040
+ passed_options = options[:options] ? options[:options].reject {|k,v| k.is_a?(Symbol) } : {}
1041
+ payload = nil
1042
+ if options[:payload]
1043
+ payload = options[:payload]
1044
+ payload.deep_merge!({'page' => passed_options}) unless passed_options.empty?
1045
+ else
1046
+ payload = {
1047
+ 'page' => {
1048
+ }
1049
+ }
1050
+ # allow arbitrary -O options
1051
+ payload.deep_merge!({'page' => passed_options}) unless passed_options.empty?
1052
+ # prompt for options
1053
+ #params = MtnCloud::Cli::OptionTypes.prompt(update_wiki_page_option_types, options[:options], @api_client, options[:params])
1054
+ #params = passed_options
1055
+ params.deep_merge!(passed_options)
1056
+
1057
+ if params.empty?
1058
+ raise_command_error "Specify at least one option to update.\n#{optparse}"
1059
+ end
1060
+
1061
+ payload.deep_merge!({'page' => params}) unless params.empty?
1062
+ end
1063
+ @clouds_interface.setopts(options)
1064
+ if options[:dry_run]
1065
+ print_dry_run @clouds_interface.dry.update_wiki(cloud["id"], payload)
1066
+ return
1067
+ end
1068
+ json_response = @clouds_interface.update_wiki(cloud["id"], payload)
1069
+
1070
+ if options[:json]
1071
+ puts as_json(json_response, options)
1072
+ else
1073
+ print_green_success "Updated wiki page for cloud #{cloud['name']}"
1074
+ wiki([cloud['id']])
1075
+ end
1076
+ return 0
1077
+ rescue RestClient::Exception => e
1078
+ print_rest_exception(e, options)
1079
+ exit 1
1080
+ end
1081
+ end
1082
+
1083
+ def update_logo(args)
1084
+ options = {}
1085
+ params = {}
1086
+ filename = nil
1087
+ optparse = MtnCloud::Cli::OptionParser.new do|opts|
1088
+ opts.banner = subcommand_usage("[name] [file]")
1089
+ build_common_options(opts, options, [:json, :dry_run, :remote])
1090
+ opts.footer = <<-EOT
1091
+ Update the logo for a cloud.
1092
+ [name] is required. This is the name or id of a cloud.
1093
+ [file] is required. This is the path of the logo file
1094
+ EOT
1095
+ end
1096
+ optparse.parse!(args)
1097
+ verify_args!(args:args, optparse:optparse, count:2)
1098
+ connect(options)
1099
+ layout_id = args[0]
1100
+ filename = args[1]
1101
+ begin
1102
+ cloud = find_cloud_by_name_or_id(args[0])
1103
+ return 1 if cloud.nil?
1104
+ logo_file = nil
1105
+ if filename == 'null'
1106
+ logo_file = 'null' # clear it
1107
+ else
1108
+ filename = File.expand_path(filename)
1109
+ if !File.exist?(filename)
1110
+ print_red_alert "File not found: #{filename}"
1111
+ exit 1
1112
+ end
1113
+ logo_file = File.new(filename, 'rb')
1114
+ end
1115
+ @clouds_interface.setopts(options)
1116
+ if options[:dry_run]
1117
+ print_dry_run @clouds_interface.dry.update_logo(cloud['id'], logo_file)
1118
+ return
1119
+ end
1120
+ json_response = @clouds_interface.update_logo(cloud['id'], logo_file)
1121
+ if options[:json]
1122
+ print JSON.pretty_generate(json_response), "\n"
1123
+ return 0
1124
+ end
1125
+ print_green_success "Updated cloud #{cloud['name']} logo"
1126
+ _get(cloud['id'], params, options)
1127
+ rescue RestClient::Exception => e
1128
+ print_rest_exception(e, options)
1129
+ return 1
1130
+ end
1131
+ end
1132
+
1133
+ def update_dark_logo(args)
1134
+ options = {}
1135
+ params = {}
1136
+ filename = nil
1137
+ optparse = MtnCloud::Cli::OptionParser.new do|opts|
1138
+ opts.banner = subcommand_usage("[name] [file]")
1139
+ build_common_options(opts, options, [:json, :dry_run, :remote])
1140
+ opts.footer = <<-EOT
1141
+ Update the logo for a cloud.
1142
+ [name] is required. This is the name or id of a cloud.
1143
+ [file] is required. This is the path of the dark logo file
1144
+ EOT
1145
+ end
1146
+ optparse.parse!(args)
1147
+ verify_args!(args:args, optparse:optparse, count:2)
1148
+ connect(options)
1149
+ layout_id = args[0]
1150
+ filename = args[1]
1151
+ begin
1152
+ cloud = find_cloud_by_name_or_id(args[0])
1153
+ return 1 if cloud.nil?
1154
+ dark_logo_file = nil
1155
+ if filename == 'null'
1156
+ dark_logo_file = 'null' # clear it
1157
+ else
1158
+ filename = File.expand_path(filename)
1159
+ if !File.exist?(filename)
1160
+ print_red_alert "File not found: #{filename}"
1161
+ exit 1
1162
+ end
1163
+ dark_logo_file = File.new(filename, 'rb')
1164
+ end
1165
+ @clouds_interface.setopts(options)
1166
+ if options[:dry_run]
1167
+ print_dry_run @clouds_interface.dry.update_logo(cloud['id'], nil, dark_logo_file)
1168
+ return
1169
+ end
1170
+ json_response = @clouds_interface.update_logo(cloud['id'], nil, dark_logo_file)
1171
+ if options[:json]
1172
+ print JSON.pretty_generate(json_response), "\n"
1173
+ return 0
1174
+ end
1175
+ print_green_success "Updated cloud #{cloud['name']} dark logo"
1176
+ _get(cloud['id'], params, options)
1177
+ rescue RestClient::Exception => e
1178
+ print_rest_exception(e, options)
1179
+ return 1
1180
+ end
1181
+ end
1182
+
1183
+ def list_affinity_groups(args)
1184
+ options = {}
1185
+ optparse = MtnCloud::Cli::OptionParser.new do |opts|
1186
+ opts.banner = subcommand_usage("[cloud]")
1187
+ build_standard_list_options(opts, options)
1188
+ opts.footer = "List affinity groups for a cloud.\n" +
1189
+ "[cloud] is required. This is the name or id of an existing cloud."
1190
+ end
1191
+
1192
+ optparse.parse!(args)
1193
+ verify_args!(args:args, optparse:optparse, count:1)
1194
+ connect(options)
1195
+
1196
+ cloud = find_cloud_by_name_or_id(args[0])
1197
+ return 1 if cloud.nil?
1198
+ params = {}
1199
+ params.merge!(parse_list_options(options))
1200
+ @clouds_interface.setopts(options)
1201
+ if options[:dry_run]
1202
+ print_dry_run @clouds_interface.dry.list_affinity_groups(cloud['id'], params)
1203
+ return
1204
+ end
1205
+ json_response = @clouds_interface.list_affinity_groups(cloud['id'], params)
1206
+ render_response(json_response, options, 'affinityGroups') do
1207
+ affinity_groups = json_response['affinityGroups']
1208
+ print_h1 "Cloud Affinity Groups: \#{cloud['name']}", parse_list_subtitles(options), options
1209
+ if affinity_groups.empty?
1210
+ print cyan, "No affinity groups found.", reset, "\n"
1211
+ else
1212
+ columns = {
1213
+ "ID" => 'id',
1214
+ "Name" => 'name',
1215
+ "Type" => lambda {|it| format_affinity_type(it['affinityType']) },
1216
+ "VM Group" => lambda {|it| it['vmGroup'] ? (it['vmGroup']['name'] || it['vmGroup']['id']) : '' },
1217
+ "Host Group" => lambda {|it| it['hostGroup'] ? (it['hostGroup']['name'] || it['hostGroup']['id']) : '' },
1218
+ "Resource Pool" => lambda {|it| it['pool'] ? (it['pool']['name'] || it['pool']['id']) : '' },
1219
+ "Visibility" => lambda {|it| it['visibility'].to_s.capitalize },
1220
+ "Servers" => lambda {|it| (it['servers'] || []).size },
1221
+ }.upcase_keys!
1222
+ print as_pretty_table(affinity_groups, columns, options)
1223
+ print_results_pagination(json_response)
1224
+ end
1225
+ print reset, "\n"
1226
+ end
1227
+ return 0, nil
1228
+ end
1229
+
1230
+
1231
+ def get_affinity_group(args)
1232
+ options = {}
1233
+ optparse = MtnCloud::Cli::OptionParser.new do |opts|
1234
+ opts.banner = subcommand_usage( "[cloud] [affinity group]")
1235
+ build_standard_get_options(opts, options)
1236
+ opts.footer = "Get details about a cloud affinity group.\n" +
1237
+ "[cloud] is required. This is the name or id of an existing cloud.\n" +
1238
+ "[affinity group] is required. This is the name or id of an existing affinity group."
1239
+ end
1240
+ optparse.parse!(args)
1241
+ verify_args!(args:args, optparse:optparse, count:2)
1242
+ connect(options)
1243
+
1244
+ cloud = find_cloud_by_name_or_id(args[0])
1245
+ return 1 if cloud.nil?
1246
+ # this finds the affinity group in the cloud api response, then fetches it by ID
1247
+ affinity_group = find_cloud_affinity_group_by_name_or_id(cloud['id'], args[1])
1248
+ if affinity_group.nil?
1249
+ print_red_alert "Affinity Group not found for '#{args[1]}'"
1250
+ exit 1
1251
+ end
1252
+
1253
+ params = {}
1254
+ params.merge!(parse_query_options(options))
1255
+ @clouds_interface.setopts(options)
1256
+ if options[:dry_run]
1257
+ print_dry_run @clouds_interface.dry.get_affinity_group(cloud['id'], affinity_group['id'], params)
1258
+ return
1259
+ end
1260
+ json_response = @clouds_interface.get_affinity_group(cloud['id'], affinity_group['id'], params)
1261
+ render_response(json_response, options, 'affinityGroup') do
1262
+ affinity_group = json_response['affinityGroup']
1263
+ print_h1 "Affinity Group Details", [], options
1264
+ columns = {
1265
+ "ID" => 'id',
1266
+ "Name" => 'name',
1267
+ "Type" => lambda {|it| format_affinity_type(it['affinityType']) },
1268
+ "Resource Pool" => lambda {|it| it['pool'] ? (it['pool']['name'] || it['pool']['id']) : '' },
1269
+ "Visibility" => lambda {|it| it['visibility'].to_s.capitalize },
1270
+ "Servers" => lambda {|it| it['servers'].size() },
1271
+ "Source" => lambda {|it| it['source'] },
1272
+ "Active" => lambda {|it| format_boolean(it['active']) },
1273
+ }
1274
+ print_description_list(columns, affinity_group)
1275
+ if affinity_group['servers'].size > 0
1276
+ print_h2 "Servers", options
1277
+ print as_pretty_table(affinity_group['servers'], [:id, :name], options)
1278
+ end
1279
+ print reset,"\n"
1280
+ end
1281
+ return 0, nil
1282
+
1283
+ end
1284
+
1285
+ def add_affinity_group(args)
1286
+ options = {}
1287
+ optparse = MtnCloud::Cli::OptionParser.new do |opts|
1288
+ opts.banner = subcommand_usage( "[cloud] [name] [options]")
1289
+ build_option_type_options(opts, options, add_cloud_affinity_group_option_types)
1290
+ opts.on('--vm-group ID', String, "VM Group id (for VM-to-Host rules)") do |val|
1291
+ options[:options] ||= {}
1292
+ options[:options]['vmGroup'] = {'id' => val.to_i}
1293
+ end
1294
+ opts.on('--host-group ID', String, "Host Group id (for VM-to-Host rules)") do |val|
1295
+ options[:options] ||= {}
1296
+ options[:options]['hostGroup'] = {'id' => val.to_i}
1297
+ end
1298
+ opts.on('--servers ID1,ID2', Array, "Server ids (for VM-to-VM rules)") do |val|
1299
+ options[:options] ||= {}
1300
+ options[:options]['servers'] = val.map {|s| {'id' => s.to_i}}
1301
+ end
1302
+ add_perms_options(opts, options, ['plans'])
1303
+ build_standard_add_options(opts, options)
1304
+ opts.footer = "Add affinity group to a cloud.\n" +
1305
+ "[cloud] is required. This is the name or id of an existing cloud.\n" +
1306
+ "[name] is required. This is the name of the new affinity group."
1307
+ end
1308
+
1309
+ optparse.parse!(args)
1310
+ verify_args!(args:args, optparse:optparse, min:1, max:2)
1311
+ connect(options)
1312
+
1313
+ begin
1314
+ cloud = find_cloud_by_name_or_id(args[0])
1315
+ return 1 if cloud.nil?
1316
+ if args[1]
1317
+ options[:options]['name'] = args[1]
1318
+ end
1319
+ if options[:payload]
1320
+ payload = options[:payload]
1321
+ # support -O OPTION switch on top of --payload
1322
+ if options[:options]
1323
+ payload ||= {}
1324
+ payload.deep_merge!(options[:options].reject {|k,v| k.is_a?(Symbol) })
1325
+ end
1326
+ else
1327
+ options[:params] ||= {}
1328
+ options[:params].merge!({:cloudId => cloud['id'],:zoneId => cloud['id']})
1329
+ option_types = add_cloud_affinity_group_option_types
1330
+ affinity_group = MtnCloud::Cli::OptionTypes.prompt(option_types, options[:options], @api_client, options[:params])
1331
+
1332
+ preset_servers = options[:options] && options[:options].key?('servers')
1333
+ preset_vmhost = options[:options] && options[:options].key?('vmGroup') && options[:options].key?('hostGroup')
1334
+
1335
+ form_opts = @clouds_interface.affinity_group_form_options(cloud['id']) rescue {}
1336
+ # Capability gate: AffinityGroupsController#formOptions derives
1337
+ # supportsCombinedRules from zoneType.hasHostVmGroups. Use the flag
1338
+ # itself -- the presence of groups is not the same as support for them.
1339
+ supports_combined = form_opts['supportsCombinedRules'] == true
1340
+
1341
+ # Cluster-in-cloud: the 'pool.id' option type above already prompts for
1342
+ # the cluster. Re-query form-options narrowed by that pool so the group
1343
+ # pickers only offer groups from the cluster the rule will belong to.
1344
+ pool_id = affinity_group['pool'].is_a?(Hash) ? affinity_group['pool']['id'] : nil
1345
+ if pool_id && supports_combined
1346
+ form_opts = (@clouds_interface.affinity_group_form_options(cloud['id'], {'poolId' => pool_id}) rescue form_opts)
1347
+ end
1348
+
1349
+ available_vm_groups = filter_by_pool(form_opts['availableVmGroups'] || [], pool_id)
1350
+ available_host_groups = filter_by_pool(form_opts['availableHostGroups'] || [], pool_id)
1351
+
1352
+ if !supports_combined && preset_vmhost
1353
+ print yellow, "This cloud does not support VM-to-Host affinity rules.", reset, "\n"
1354
+ end
1355
+
1356
+ unless preset_servers || preset_vmhost
1357
+ if supports_combined && !available_vm_groups.empty? && !available_host_groups.empty?
1358
+ shape = MtnCloud::Cli::OptionTypes.prompt([{
1359
+ 'fieldName' => 'shape', 'fieldLabel' => 'Rule Shape', 'type' => 'select',
1360
+ 'required' => true, 'defaultValue' => 'vmToVm',
1361
+ 'selectOptions' => [
1362
+ {'name' => 'VM-to-VM (pick servers)', 'value' => 'vmToVm'},
1363
+ {'name' => 'VM-to-Host (pick groups)', 'value' => 'vmToHost'},
1364
+ ]
1365
+ }], options[:options], @api_client, options[:params])['shape']
1366
+ else
1367
+ shape = 'vmToVm'
1368
+ end
1369
+
1370
+ if shape == 'vmToHost'
1371
+ vm_group_id = MtnCloud::Cli::OptionTypes.prompt([{
1372
+ 'fieldName' => 'vmGroup', 'fieldLabel' => 'VM Group', 'type' => 'select', 'required' => true,
1373
+ 'selectOptions' => available_vm_groups.map {|g| {'name' => g['name'], 'value' => g['id']} }
1374
+ }], options[:options], @api_client, options[:params])['vmGroup']
1375
+ host_group_id = MtnCloud::Cli::OptionTypes.prompt([{
1376
+ 'fieldName' => 'hostGroup', 'fieldLabel' => 'Host Group', 'type' => 'select', 'required' => true,
1377
+ 'selectOptions' => available_host_groups.map {|g| {'name' => g['name'], 'value' => g['id']} }
1378
+ }], options[:options], @api_client, options[:params])['hostGroup']
1379
+ affinity_group['vmGroup'] = {'id' => vm_group_id.to_i}
1380
+ affinity_group['hostGroup'] = {'id' => host_group_id.to_i}
1381
+ else
1382
+ server_prompt = MtnCloud::Cli::OptionTypes.prompt([{
1383
+ 'fieldName' => 'servers', 'fieldLabel' => 'Server', 'type' => 'multiTypeahead',
1384
+ 'optionSource' => 'searchServers', 'searchParameter' => 'phrase',
1385
+ 'description' => 'Select servers to be in the affinity group.'
1386
+ }], options[:options], @api_client, options[:params])
1387
+ affinity_group['servers'] = server_prompt['servers'] if server_prompt['servers']
1388
+ end
1389
+ else
1390
+ affinity_group['servers'] = options[:options]['servers'] if preset_servers
1391
+ affinity_group['vmGroup'] = options[:options]['vmGroup'] if preset_vmhost
1392
+ affinity_group['hostGroup'] = options[:options]['hostGroup'] if preset_vmhost
1393
+ end
1394
+
1395
+ # perms
1396
+ perms = prompt_permissions(options, is_master_account ? ['plans'] : ['plans', 'visibility', 'tenants'])
1397
+
1398
+ affinity_group['resourcePermissions'] = perms['resourcePermissions'] unless perms['resourcePermissions'].nil?
1399
+ affinity_group['tenants'] = perms['tenantPermissions'] unless perms['tenantPermissions'].nil? || perms['tenantPermissions']['accounts'].empty?
1400
+ affinity_group['visibility'] = perms['resourcePool']['visibility'] if !perms['resourcePool'].nil? && !perms['resourcePool']['visibility'].nil?
1401
+
1402
+ payload = {'affinityGroup' => affinity_group}
1403
+ end
1404
+
1405
+ @clouds_interface.setopts(options)
1406
+ if options[:dry_run]
1407
+ print_dry_run @clouds_interface.dry.create_affinity_group(cloud['id'], payload)
1408
+ return
1409
+ end
1410
+ json_response = @clouds_interface.create_affinity_group(cloud['id'], payload)
1411
+ if options[:json]
1412
+ puts as_json(json_response)
1413
+ else
1414
+ if json_response['success']
1415
+ if json_response['msg'] == nil
1416
+ print_green_success "Adding affinity group to cloud #{cloud['name']}"
1417
+ else
1418
+ print_green_success json_response['msg']
1419
+ end
1420
+ execution_id = json_response['executionId']
1421
+ if !options[:no_refresh] && execution_id
1422
+ wait_for_execution_request(json_response['executionId'], options.merge({waiting_status:['new', 'pending', 'executing']}))
1423
+ end
1424
+ else
1425
+ print_red_alert "Failed to create cloud affinity group #{json_response['msg']}"
1426
+ end
1427
+ end
1428
+ return 0
1429
+ rescue RestClient::Exception => e
1430
+ handle_affinity_rest_exception(e, options)
1431
+ exit 1
1432
+ end
1433
+ end
1434
+
1435
+ def update_affinity_group(args)
1436
+ options = {}
1437
+ optparse = MtnCloud::Cli::OptionParser.new do |opts|
1438
+ opts.banner = subcommand_usage( "[cloud] [affinity group] [options]")
1439
+ build_option_type_options(opts, options, update_cloud_affinity_group_option_types)
1440
+ add_perms_options(opts, options, ['plans'])
1441
+ build_standard_update_options(opts, options)
1442
+ opts.footer = "Update a cloud affinity group.\n" +
1443
+ "[cloud] is required. This is the name or id of an existing cloud.\n" +
1444
+ "[affinity group] is required. This is the name or id of an existing affinity group."
1445
+ end
1446
+
1447
+ optparse.parse!(args)
1448
+ if args.count != 2
1449
+ raise_command_error "wrong number of arguments, expected 2 and got (#{args.count}) #{args}\n#{optparse}"
1450
+ end
1451
+ connect(options)
1452
+
1453
+ begin
1454
+ cloud = find_cloud_by_name_or_id(args[0])
1455
+ return 1 if cloud.nil?
1456
+ affinity_group = find_cloud_affinity_group_by_name_or_id(cloud['id'], args[1])
1457
+ if affinity_group.nil?
1458
+ print_red_alert "Affinity Group not found by '#{args[1]}'"
1459
+ exit 1
1460
+ end
1461
+ payload = nil
1462
+ if options[:payload]
1463
+ payload = options[:payload]
1464
+ # support -O OPTION switch on top of everything
1465
+ if options[:options]
1466
+ payload.deep_merge!({'affinityGroup' => options[:options].reject {|k,v| k.is_a?(Symbol) }})
1467
+ end
1468
+ else
1469
+ payload = {'affinityGroup' => {}}
1470
+ options[:params] ||= {}
1471
+ options[:params].merge!({:cloudId => cloud['id'],:zoneId => cloud['id']})
1472
+ option_types = update_cloud_affinity_group_option_types
1473
+ v_prompt = MtnCloud::Cli::OptionTypes.no_prompt(option_types, options[:options], @api_client, options[:params])
1474
+ v_prompt.deep_compact!.booleanize!
1475
+ payload.deep_merge!({'affinityGroup' => v_prompt})
1476
+
1477
+ perms = prompt_permissions(options.merge({:no_prompt => true}), is_master_account ? ['plans'] : ['plans', 'visibility', 'tenants'])
1478
+
1479
+ perms_payload = {}
1480
+ perms_payload['resourcePermissions'] = perms['resourcePermissions'] if !perms['resourcePermissions'].nil? && !perms['resourcePermissions'].empty?
1481
+ perms_payload['tenantPermissions'] = perms['tenantPermissions'] if !perms['tenantPermissions'].nil? && !perms['tenantPermissions']['accounts'].empty?
1482
+
1483
+ payload['affinityGroup']['permissions'] = perms_payload if !perms_payload.empty?
1484
+ payload['affinityGroup']['visibility'] = perms['resourcePool']['visibility'] if !perms['resourcePool'].nil? && !perms['resourcePool']['visibility'].nil?
1485
+
1486
+ # support -O OPTION switch on top of everything
1487
+ if options[:options]
1488
+ payload.deep_merge!({'affinityGroup' => options[:options].reject {|k,v| k.is_a?(Symbol) || payload['affinityGroup'].key?(k) }})
1489
+ end
1490
+
1491
+ if payload['affinityGroup'].nil? || payload['affinityGroup'].empty?
1492
+ raise_command_error "Specify at least one option to update.\n#{optparse}"
1493
+ end
1494
+ end
1495
+
1496
+ @clouds_interface.setopts(options)
1497
+ if options[:dry_run]
1498
+ print_dry_run @clouds_interface.dry.update_affinity_group(cloud['id'], affinity_group['id'], payload)
1499
+ return
1500
+ end
1501
+ json_response = @clouds_interface.update_affinity_group(cloud['id'], affinity_group['id'], payload)
1502
+ if options[:json]
1503
+ puts as_json(json_response)
1504
+ elsif !options[:quiet]
1505
+ affinity_group = json_response['affinityGroup']
1506
+ print_green_success "Updated affinity group #{affinity_group['name']}"
1507
+ #get_args = [cloud["id"], affinity_group["id"]] + (options[:remote] ? ["-r",options[:remote]] : [])
1508
+ #get_namespace(get_args)
1509
+ end
1510
+ return 0
1511
+ rescue RestClient::Exception => e
1512
+ print_rest_exception(e, options)
1513
+ exit 1
1514
+ end
1515
+ end
1516
+
1517
+ def remove_affinity_group(args)
1518
+ default_refresh_interval = 5
1519
+ params = {}
1520
+ options = {}
1521
+ optparse = MtnCloud::Cli::OptionParser.new do |opts|
1522
+ opts.banner = subcommand_usage("[cloud] [affinity group]")
1523
+ # opts.on( '-f', '--force', "Force Delete" ) do
1524
+ # params[:force] = 'on'
1525
+ # end
1526
+ # opts.on('--refresh [SECONDS]', String, "Refresh until execution is complete. Default interval is #{default_refresh_interval} seconds.") do |val|
1527
+ # options[:refresh_interval] = val.to_s.empty? ? default_refresh_interval : val.to_f
1528
+ # end
1529
+ # opts.on(nil, '--no-refresh', "Do not refresh" ) do
1530
+ # options[:no_refresh] = true
1531
+ # end
1532
+ build_standard_remove_options(opts, options)
1533
+ opts.footer = "Delete an affinity group from a cloud.\n" +
1534
+ "[cloud] is required. This is the name or id of an existing cloud.\n" +
1535
+ "[affinity group] is required. This is the name or id of an existing affinity group."
1536
+ end
1537
+ optparse.parse!(args)
1538
+ verify_args!(args:args, optparse:optparse, count:2)
1539
+ connect(options)
1540
+ params.merge!(parse_query_options(options))
1541
+
1542
+ cloud = find_cloud_by_name_or_id(args[0])
1543
+ return 1 if cloud.nil?
1544
+
1545
+ affinity_group_id = args[1]
1546
+ if affinity_group_id.empty?
1547
+ raise_command_error "missing required worker parameter"
1548
+ end
1549
+
1550
+ affinity_group = find_cloud_affinity_group_by_name_or_id(cloud['id'], affinity_group_id)
1551
+ if affinity_group.nil?
1552
+ print_red_alert "Affinity Group not found for '#{affinity_group_id}'"
1553
+ return 1
1554
+ end
1555
+ unless options[:yes] || ::MtnCloud::Cli::OptionTypes::confirm("Are you sure you would like to remove the cloud affinity group '#{affinity_group['name'] || affinity_group['id']}'?", options)
1556
+ return 9, "aborted command"
1557
+ end
1558
+
1559
+ @clouds_interface.setopts(options)
1560
+ if options[:dry_run]
1561
+ print_dry_run @clouds_interface.dry.destroy_affinity_group(cloud['id'], affinity_group['id'], params)
1562
+ return
1563
+ end
1564
+ json_response = @clouds_interface.destroy_affinity_group(cloud['id'], affinity_group['id'], params)
1565
+ if options[:json]
1566
+ puts as_json(json_response)
1567
+ else
1568
+ if json_response['success']
1569
+ print_green_success "Removed affinity group #{affinity_group['name']}"
1570
+ execution_id = json_response['executionId']
1571
+ if !options[:no_refresh] && execution_id
1572
+ wait_for_execution_request(execution_id, options.merge({waiting_status:['new', 'pending', 'executing']}))
1573
+ end
1574
+ else
1575
+ print_red_alert "Failed to remove cloud affinity group #{json_response['msg']}"
1576
+ end
1577
+ end
1578
+ return 0, nil
1579
+ end
1580
+
1581
+ def list_host_vm_groups(args)
1582
+ options = {}
1583
+ optparse = MtnCloud::Cli::OptionParser.new do |opts|
1584
+ opts.banner = subcommand_usage("[cloud]")
1585
+ build_standard_list_options(opts, options)
1586
+ opts.footer = "List host/VM groups for a cloud.\n" +
1587
+ "[cloud] is required. This is the name or id of an existing cloud."
1588
+ end
1589
+ optparse.parse!(args)
1590
+ verify_args!(args:args, optparse:optparse, count:1)
1591
+ connect(options)
1592
+
1593
+ cloud = find_cloud_by_name_or_id(args[0])
1594
+ return 1 if cloud.nil?
1595
+ params = {}
1596
+ params.merge!(parse_list_options(options))
1597
+ @clouds_interface.setopts(options)
1598
+ if options[:dry_run]
1599
+ print_dry_run @clouds_interface.dry.list_host_vm_groups(cloud['id'], params)
1600
+ return
1601
+ end
1602
+ json_response = @clouds_interface.list_host_vm_groups(cloud['id'], params)
1603
+ render_response(json_response, options, 'hostVmGroups') do
1604
+ rows = json_response['hostVmGroups'] || []
1605
+ print_h1 "Cloud Host/VM Groups: \#{cloud['name']}", parse_list_subtitles(options), options
1606
+ if rows.empty?
1607
+ print cyan, "No host/VM groups found.", reset, "\n"
1608
+ else
1609
+ columns = {
1610
+ "ID" => 'id',
1611
+ "Name" => 'name',
1612
+ "Type" => lambda {|it| format_host_vm_group_type(it['type']) },
1613
+ "Resource Pool" => lambda {|it| it['pool'] ? (it['pool']['name'] || it['pool']['id']) : '' },
1614
+ "Servers" => lambda {|it| (it['servers'] || []).size },
1615
+ }.upcase_keys!
1616
+ print as_pretty_table(rows, columns, options)
1617
+ print_results_pagination(json_response)
1618
+ end
1619
+ print reset, "\n"
1620
+ end
1621
+ return 0, nil
1622
+ end
1623
+
1624
+ def get_host_vm_group(args)
1625
+ options = {}
1626
+ optparse = MtnCloud::Cli::OptionParser.new do |opts|
1627
+ opts.banner = subcommand_usage("[cloud] [host-vm-group]")
1628
+ build_standard_get_options(opts, options)
1629
+ opts.footer = "Get details about a cloud host/VM group.\n" +
1630
+ "[cloud] is required. This is the name or id of an existing cloud.\n" +
1631
+ "[host-vm-group] is required. This is the name or id of an existing host/VM group."
1632
+ end
1633
+ optparse.parse!(args)
1634
+ verify_args!(args:args, optparse:optparse, count:2)
1635
+ connect(options)
1636
+
1637
+ cloud = find_cloud_by_name_or_id(args[0])
1638
+ return 1 if cloud.nil?
1639
+ host_vm_group = find_cloud_host_vm_group_by_name_or_id(cloud['id'], args[1])
1640
+ if host_vm_group.nil?
1641
+ print_red_alert "Host/VM Group not found for '\#{args[1]}'"
1642
+ exit 1
1643
+ end
1644
+
1645
+ params = {}
1646
+ params.merge!(parse_query_options(options))
1647
+ @clouds_interface.setopts(options)
1648
+ if options[:dry_run]
1649
+ print_dry_run @clouds_interface.dry.get_host_vm_group(cloud['id'], host_vm_group['id'], params)
1650
+ return
1651
+ end
1652
+ json_response = @clouds_interface.get_host_vm_group(cloud['id'], host_vm_group['id'], params)
1653
+ render_response(json_response, options, 'hostVmGroup') do
1654
+ row = json_response['hostVmGroup']
1655
+ print_h1 "Host/VM Group Details", [], options
1656
+ columns = {
1657
+ "ID" => 'id',
1658
+ "Name" => 'name',
1659
+ "Type" => lambda {|it| format_host_vm_group_type(it['type']) },
1660
+ "Resource Pool" => lambda {|it| it['pool'] ? (it['pool']['name'] || it['pool']['id']) : '' },
1661
+ "Visibility" => lambda {|it| it['visibility'].to_s.capitalize },
1662
+ "Servers" => lambda {|it| (it['servers'] || []).size },
1663
+ "Source" => 'source',
1664
+ }
1665
+ print_description_list(columns, row)
1666
+ if row['servers'] && row['servers'].size > 0
1667
+ print_h2 "Servers", options
1668
+ print as_pretty_table(row['servers'], [:id, :name], options)
1669
+ end
1670
+ print reset, "\n"
1671
+ end
1672
+ return 0, nil
1673
+ end
1674
+
1675
+ def add_host_vm_group(args)
1676
+ options = {}
1677
+ optparse = MtnCloud::Cli::OptionParser.new do |opts|
1678
+ opts.banner = subcommand_usage("[cloud] [name] [options]")
1679
+ build_option_type_options(opts, options, add_cloud_host_vm_group_option_types)
1680
+ opts.on('--servers ID1,ID2', Array, "Server ids to add to the group") do |val|
1681
+ options[:options] ||= {}
1682
+ options[:options]['servers'] = val.map {|s| {'id' => s.to_i}}
1683
+ end
1684
+ add_perms_options(opts, options, ['plans'])
1685
+ build_standard_add_options(opts, options)
1686
+ opts.footer = "Add host/VM group to a cloud.\n" +
1687
+ "[cloud] is required. This is the name or id of an existing cloud.\n" +
1688
+ "[name] is required. This is the name of the new host/VM group."
1689
+ end
1690
+ optparse.parse!(args)
1691
+ verify_args!(args:args, optparse:optparse, min:1, max:2)
1692
+ connect(options)
1693
+
1694
+ begin
1695
+ cloud = find_cloud_by_name_or_id(args[0])
1696
+ return 1 if cloud.nil?
1697
+ if args[1]
1698
+ options[:options] ||= {}
1699
+ options[:options]['name'] = args[1]
1700
+ end
1701
+ if options[:payload]
1702
+ payload = options[:payload]
1703
+ payload.deep_merge!(options[:options].reject {|k,v| k.is_a?(Symbol) }) if options[:options]
1704
+ else
1705
+ options[:params] ||= {}
1706
+ options[:params].merge!({:cloudId => cloud['id'], :zoneId => cloud['id']})
1707
+ host_vm_group = MtnCloud::Cli::OptionTypes.prompt(add_cloud_host_vm_group_option_types, options[:options], @api_client, options[:params])
1708
+
1709
+ unless options[:options] && options[:options].key?('servers')
1710
+ # poolId narrows availableServers to the chosen cluster: HOST_GROUP
1711
+ # matches the cluster pool exactly, VM_GROUP walks descendant pools.
1712
+ form_params = {'hostVmGroupType' => host_vm_group['type']}
1713
+ hvg_pool_id = host_vm_group['pool'].is_a?(Hash) ? host_vm_group['pool']['id'] : nil
1714
+ form_params['poolId'] = hvg_pool_id if hvg_pool_id
1715
+ form_opts = @clouds_interface.host_vm_group_form_options(cloud['id'], form_params) rescue {}
1716
+ available = form_opts['availableServers'] || []
1717
+ if available.empty?
1718
+ server_prompt = MtnCloud::Cli::OptionTypes.prompt([{
1719
+ 'fieldName' => 'servers', 'fieldLabel' => 'Server', 'type' => 'multiTypeahead',
1720
+ 'optionSource' => 'searchServers', 'searchParameter' => 'phrase',
1721
+ 'description' => 'Select servers to add to the group.'
1722
+ }], options[:options], @api_client, options[:params])
1723
+ host_vm_group['servers'] = server_prompt['servers'] if server_prompt['servers']
1724
+ else
1725
+ print cyan, "Available Servers:", reset, "\n"
1726
+ available.each {|s| print " \#{s['id']}\t\#{s['name']}\n" }
1727
+ raw = MtnCloud::Cli::OptionTypes.prompt([{
1728
+ 'fieldName' => 'servers', 'fieldLabel' => 'Servers (comma-separated IDs)', 'type' => 'text',
1729
+ 'description' => 'Server IDs to include, comma-separated'
1730
+ }], options[:options], @api_client, options[:params])['servers']
1731
+ selected_ids = raw.to_s.split(',').map(&:strip).reject(&:empty?).map(&:to_i)
1732
+ host_vm_group['servers'] = selected_ids.map {|id| {'id' => id}}
1733
+ end
1734
+ else
1735
+ host_vm_group['servers'] = options[:options]['servers']
1736
+ end
1737
+
1738
+ perms = prompt_permissions(options, is_master_account ? ['plans'] : ['plans', 'visibility', 'tenants'])
1739
+ host_vm_group['resourcePermissions'] = perms['resourcePermissions'] unless perms['resourcePermissions'].nil?
1740
+ host_vm_group['tenants'] = perms['tenantPermissions'] unless perms['tenantPermissions'].nil? || perms['tenantPermissions']['accounts'].empty?
1741
+ host_vm_group['visibility'] = perms['resourcePool']['visibility'] if !perms['resourcePool'].nil? && !perms['resourcePool']['visibility'].nil?
1742
+
1743
+ payload = {'hostVmGroup' => host_vm_group}
1744
+ end
1745
+
1746
+ @clouds_interface.setopts(options)
1747
+ if options[:dry_run]
1748
+ print_dry_run @clouds_interface.dry.create_host_vm_group(cloud['id'], payload)
1749
+ return
1750
+ end
1751
+ json_response = @clouds_interface.create_host_vm_group(cloud['id'], payload)
1752
+ render_response(json_response, options, 'hostVmGroup') do
1753
+ row = json_response['hostVmGroup']
1754
+ print_green_success "Added host/VM group to cloud \#{cloud['name']}"
1755
+ end
1756
+ return 0, nil
1757
+ rescue RestClient::Exception => e
1758
+ print_rest_exception(e, options)
1759
+ exit 1
1760
+ end
1761
+ end
1762
+
1763
+ def update_host_vm_group(args)
1764
+ options = {}
1765
+ optparse = MtnCloud::Cli::OptionParser.new do |opts|
1766
+ opts.banner = subcommand_usage("[cloud] [host-vm-group] [options]")
1767
+ build_option_type_options(opts, options, update_cloud_host_vm_group_option_types)
1768
+ opts.on('--servers ID1,ID2', Array, "Server ids") do |val|
1769
+ options[:options] ||= {}
1770
+ options[:options]['servers'] = val.map {|s| {'id' => s.to_i}}
1771
+ end
1772
+ add_perms_options(opts, options, ['plans'])
1773
+ build_standard_update_options(opts, options)
1774
+ opts.footer = "Update a cloud host/VM group.\n" +
1775
+ "[cloud] is required. This is the name or id of an existing cloud.\n" +
1776
+ "[host-vm-group] is required. This is the name or id of an existing host/VM group."
1777
+ end
1778
+ optparse.parse!(args)
1779
+ verify_args!(args:args, optparse:optparse, count:2)
1780
+ connect(options)
1781
+
1782
+ begin
1783
+ cloud = find_cloud_by_name_or_id(args[0])
1784
+ return 1 if cloud.nil?
1785
+ host_vm_group = find_cloud_host_vm_group_by_name_or_id(cloud['id'], args[1])
1786
+ if host_vm_group.nil?
1787
+ print_red_alert "Host/VM Group not found for '\#{args[1]}'"
1788
+ return 1
1789
+ end
1790
+
1791
+ if options[:payload]
1792
+ payload = options[:payload]
1793
+ payload.deep_merge!(options[:options].reject {|k,v| k.is_a?(Symbol) }) if options[:options]
1794
+ else
1795
+ payload = {'hostVmGroup' => {}}
1796
+ v_prompt = MtnCloud::Cli::OptionTypes.no_prompt(update_cloud_host_vm_group_option_types, options[:options], @api_client, {})
1797
+ payload.deep_merge!({'hostVmGroup' => v_prompt})
1798
+
1799
+ perms = prompt_permissions(options, is_master_account ? ['plans'] : ['plans', 'visibility', 'tenants'])
1800
+ payload['hostVmGroup']['permissions'] = perms['resourcePermissions'] if perms['resourcePermissions']
1801
+ payload['hostVmGroup']['visibility'] = perms['resourcePool']['visibility'] if !perms['resourcePool'].nil? && !perms['resourcePool']['visibility'].nil?
1802
+
1803
+ if options[:options]
1804
+ payload.deep_merge!({'hostVmGroup' => options[:options].reject {|k,v| k.is_a?(Symbol) || payload['hostVmGroup'].key?(k) }})
1805
+ end
1806
+ if payload['hostVmGroup'].empty?
1807
+ raise_command_error "Specify at least one option to update.\n\#{optparse}"
1808
+ end
1809
+ end
1810
+
1811
+ @clouds_interface.setopts(options)
1812
+ if options[:dry_run]
1813
+ print_dry_run @clouds_interface.dry.update_host_vm_group(cloud['id'], host_vm_group['id'], payload)
1814
+ return
1815
+ end
1816
+ json_response = @clouds_interface.update_host_vm_group(cloud['id'], host_vm_group['id'], payload)
1817
+ render_response(json_response, options, 'hostVmGroup') do
1818
+ updated = json_response['hostVmGroup'] || host_vm_group
1819
+ print_green_success "Updated host/VM group \#{updated['name']}"
1820
+ end
1821
+ return 0, nil
1822
+ rescue RestClient::Exception => e
1823
+ print_rest_exception(e, options)
1824
+ exit 1
1825
+ end
1826
+ end
1827
+
1828
+ def remove_host_vm_group(args)
1829
+ options = {}
1830
+ optparse = MtnCloud::Cli::OptionParser.new do |opts|
1831
+ opts.banner = subcommand_usage("[cloud] [host-vm-group]")
1832
+ build_standard_remove_options(opts, options)
1833
+ opts.footer = "Delete a host/VM group from a cloud.\n" +
1834
+ "[cloud] is required. This is the name or id of an existing cloud.\n" +
1835
+ "[host-vm-group] is required. This is the name or id of an existing host/VM group."
1836
+ end
1837
+ optparse.parse!(args)
1838
+ verify_args!(args:args, optparse:optparse, count:2)
1839
+ connect(options)
1840
+
1841
+ cloud = find_cloud_by_name_or_id(args[0])
1842
+ return 1 if cloud.nil?
1843
+ host_vm_group = find_cloud_host_vm_group_by_name_or_id(cloud['id'], args[1])
1844
+ if host_vm_group.nil?
1845
+ print_red_alert "Host/VM Group not found for '\#{args[1]}'"
1846
+ return 1
1847
+ end
1848
+ unless options[:yes] || ::MtnCloud::Cli::OptionTypes.confirm("Are you sure you would like to remove the cloud host/VM group '\#{host_vm_group['name'] || host_vm_group['id']}'?", options)
1849
+ return 9, "aborted command"
1850
+ end
1851
+
1852
+ @clouds_interface.setopts(options)
1853
+ if options[:dry_run]
1854
+ print_dry_run @clouds_interface.dry.destroy_host_vm_group(cloud['id'], host_vm_group['id'])
1855
+ return
1856
+ end
1857
+ begin
1858
+ json_response = @clouds_interface.destroy_host_vm_group(cloud['id'], host_vm_group['id'])
1859
+ render_response(json_response, options) do
1860
+ print_green_success "Removed host/VM group \#{host_vm_group['name']}"
1861
+ end
1862
+ return 0, nil
1863
+ rescue RestClient::Exception => e
1864
+ print_rest_exception(e, options)
1865
+ exit 1
1866
+ end
1867
+ end
1868
+
1869
+
1870
+ private
1871
+
1872
+ def cloud_list_column_definitions(options)
1873
+ {
1874
+ "ID" => 'id',
1875
+ "Name" => 'name',
1876
+ "Tenant" => lambda {|it| it['owner'] ? it['owner']['name'] : '' },
1877
+ "Type" => lambda {|it| it['zoneType'] ? it['zoneType']['name'] : '' },
1878
+ "Labels" => lambda {|it| format_list(it['labels'], '', 3) rescue '' },
1879
+ "Location" => 'location',
1880
+ "Region Code" => lambda {|it| it['regionCode'] },
1881
+ "Groups" => lambda {|it| (it['groups'] || []).collect {|g| g.instance_of?(Hash) ? g['name'] : g.to_s }.join(', ') },
1882
+ "Servers" => lambda {|it| it['serverCount'] },
1883
+ "Status" => lambda {|it| format_cloud_status(it) },
1884
+ }
1885
+ end
1886
+
1887
+ def add_cloud_option_types(cloud_type)
1888
+ # note: Type is selected before this
1889
+ tmp_option_types = [
1890
+ #{'fieldName' => 'zoneType.code', 'fieldLabel' => 'Image Type', 'type' => 'select', 'selectOptions' => cloud_types_for_dropdown, 'required' => true, 'description' => 'Cloud Type.', 'displayOrder' => 0},
1891
+ {'fieldName' => 'name', 'fieldLabel' => 'Name', 'type' => 'text', 'required' => true, 'displayOrder' => 1},
1892
+ {'fieldName' => 'code', 'fieldLabel' => 'Code', 'type' => 'text', 'required' => false, 'displayOrder' => 2},
1893
+ {'shorthand' => '-l', 'optionalValue' => true, 'fieldName' => 'labels', 'fieldLabel' => 'Labels', 'type' => 'text', 'required' => false, 'processValue' => lambda {|val| parse_labels(val) }, 'displayOrder' => 3},
1894
+ {'fieldName' => 'location', 'fieldLabel' => 'Location', 'type' => 'text', 'required' => false, 'displayOrder' => 4},
1895
+ {'fieldName' => 'visibility', 'fieldLabel' => 'Visibility', 'type' => 'select', 'selectOptions' => [{'name' => 'Private', 'value' => 'private'},{'name' => 'Public', 'value' => 'public'}], 'required' => false, 'description' => 'Visibility', 'category' => 'permissions', 'defaultValue' => 'private', 'displayOrder' => 5},
1896
+ {'fieldName' => 'enabled', 'fieldLabel' => 'Enabled', 'type' => 'checkbox', 'required' => false, 'defaultValue' => true, 'displayOrder' => 6},
1897
+ {'fieldName' => 'autoRecoverPowerState', 'fieldLabel' => 'Automatically Power On VMs', 'type' => 'checkbox', 'required' => false, 'defaultValue' => false, 'displayOrder' => 7}
1898
+ ]
1899
+
1900
+ # TODO: Account
1901
+
1902
+ # Details (zoneType.optionTypes)
1903
+
1904
+ if cloud_type && cloud_type['optionTypes'] && cloud_type['code'] != 'standard'
1905
+ if !cloud_type['optionTypes'].find {|opt| opt['type'] == 'credential'}
1906
+ tmp_option_types << {'fieldName' => 'type', 'fieldLabel' => 'Credentials', 'type' => 'credential', 'optionSource' => 'credentials', 'required' => true, 'defaultValue' => 'local', 'config' => {'credentialTypes' => get_cloud_type_credential_types(cloud_type['code'])}, 'displayOrder' => 7}
1907
+ cloud_type['optionTypes'].select {|opt| ['username', 'password', 'serviceUsername', 'servicePassword'].include?(opt['fieldName'])}.each {|opt| opt['localCredential'] = true}
1908
+ end
1909
+ # adjust displayOrder to put these at the end
1910
+ #tmp_option_types = tmp_option_types + cloud_type['optionTypes']
1911
+ cloud_type['optionTypes'].each do |opt|
1912
+ # temp fix for typo
1913
+ opt['optionSource'] = 'credentials' if opt['optionSource'] == 'credentials,'
1914
+ tmp_option_types << opt.merge({'displayOrder' => opt['displayOrder'].to_i + 100})
1915
+ end
1916
+ end
1917
+
1918
+ # TODO:
1919
+ # Advanced Options
1920
+ ## (a whole bunch needed here)
1921
+
1922
+ # Provisioning Options
1923
+
1924
+ ## PROXY (dropdown)
1925
+ ## BYPASS PROXY FOR APPLIANCE URL (checkbox)
1926
+ ## USER DATA LINUX (code)
1927
+
1928
+ return tmp_option_types
1929
+ end
1930
+
1931
+ def update_cloud_option_types(cloud_type)
1932
+ add_cloud_option_types(cloud_type).collect {|it| it['required'] = false; it }
1933
+ end
1934
+
1935
+ def cloud_types_for_dropdown
1936
+ @clouds_interface.cloud_types({max:1000, shallow:true})['zoneTypes'].select {|it| it['enabled'] }.collect {|it| {'name' => it['name'], 'value' => it['code']} }
1937
+ end
1938
+
1939
+ def format_cloud_status(cloud, return_color=cyan)
1940
+ out = ""
1941
+ status_string = cloud['status']
1942
+ if cloud['enabled'] == false
1943
+ out << "#{red}DISABLED#{return_color}"
1944
+ elsif status_string.nil? || status_string.empty? || status_string == "unknown"
1945
+ out << "#{white}UNKNOWN#{return_color}"
1946
+ elsif status_string == 'ok'
1947
+ out << "#{green}#{status_string.upcase}#{return_color}"
1948
+ elsif status_string == 'syncing' || status_string == 'initializing' || status_string == 'removing'
1949
+ out << "#{yellow}#{status_string.upcase}#{return_color}"
1950
+ else
1951
+ out << "#{red}#{status_string ? status_string.upcase : 'N/A'}#{cloud['statusMessage'] ? "#{return_color} - #{cloud['statusMessage']}" : ''}#{return_color}"
1952
+ end
1953
+ out
1954
+ end
1955
+
1956
+ def update_wiki_page_option_types
1957
+ [
1958
+ {'fieldName' => 'name', 'fieldLabel' => 'Name', 'type' => 'text', 'required' => false, 'displayOrder' => 1, 'description' => 'The name of the wiki page for this instance. Default is the instance name.'},
1959
+ #{'fieldName' => 'category', 'fieldLabel' => 'Category', 'type' => 'text', 'required' => false, 'displayOrder' => 2},
1960
+ {'fieldName' => 'content', 'fieldLabel' => 'Content', 'type' => 'textarea', 'required' => false, 'displayOrder' => 3, 'description' => 'The content (markdown) of the wiki page.'}
1961
+ ]
1962
+ end
1963
+
1964
+ def get_cloud_type_credential_types(cloud_type_code)
1965
+ case cloud_type_code
1966
+ when "amazon", "alibaba"
1967
+ ['access-key-secret']
1968
+ when "azure","azurestack"
1969
+ ['client-id-secret']
1970
+ when "google"
1971
+ ['email-private-key']
1972
+ when "softlayer"
1973
+ ['username-api-key']
1974
+ when "digitalocean"
1975
+ ['username-api-key']
1976
+ else
1977
+ ['username-password']
1978
+ end
1979
+ end
1980
+
1981
+ def find_cloud_affinity_group_by_name_or_id(cloud_id, val)
1982
+ if val.to_s =~ /\A\d{1,}\Z/
1983
+ @clouds_interface.get_affinity_group(cloud_id, val)['affinityGroup'] rescue nil
1984
+ else
1985
+ @clouds_interface.list_affinity_groups(cloud_id, {name: val})['affinityGroups'][0]
1986
+ end
1987
+ end
1988
+
1989
+ def add_cloud_affinity_group_option_types
1990
+ [
1991
+ {'fieldName' => 'name', 'fieldLabel' => 'Name', 'type' => 'text', 'required' => true},
1992
+ affinity_type_option_type(required: true, default: 'KEEP_SEPARATE'),
1993
+ {'fieldName' => 'active', 'fieldLabel' => 'Active', 'type' => 'checkbox', 'defaultValue' => true},
1994
+ {'fieldName' => 'pool.id', 'fieldLabel' => 'Cluster', 'type' => 'select', 'optionSourceType' => 'vmware',
1995
+ 'optionSource' => 'vmwareZonePoolClusters', 'description' => 'Select cluster for the affinity group.', 'required' => true},
1996
+ {'fieldName' => 'servers', 'fieldLabel' => 'Server', 'type' => 'multiTypeahead', 'optionSource' => 'searchServers',
1997
+ 'searchParameter' => 'phrase', 'description' => 'Select servers to be in the affinity group.'},
1998
+ ]
1999
+ end
2000
+
2001
+ def update_cloud_affinity_group_option_types
2002
+ [
2003
+ {'fieldName' => 'name', 'fieldLabel' => 'Name', 'type' => 'text'},
2004
+ affinity_type_option_type,
2005
+ {'fieldName' => 'active', 'fieldLabel' => 'Active', 'type' => 'checkbox'},
2006
+ {'fieldName' => 'servers', 'fieldLabel' => 'Server', 'type' => 'multiTypeahead', 'optionSource' => 'searchServers',
2007
+ 'searchParameter' => 'phrase', 'description' => 'Select servers to be in the affinity group.'},
2008
+ ]
2009
+ end
2010
+
2011
+ def find_cloud_host_vm_group_by_name_or_id(cloud_id, val)
2012
+ if val.to_s =~ /\A\d{1,}\Z/
2013
+ @clouds_interface.get_host_vm_group(cloud_id, val)['hostVmGroup'] rescue nil
2014
+ else
2015
+ @clouds_interface.list_host_vm_groups(cloud_id, {name: val})['hostVmGroups'] && @clouds_interface.list_host_vm_groups(cloud_id, {name: val})['hostVmGroups'][0]
2016
+ end
2017
+ end
2018
+
2019
+ def add_cloud_host_vm_group_option_types
2020
+ [
2021
+ {'fieldName' => 'name', 'fieldLabel' => 'Name', 'type' => 'text', 'required' => true},
2022
+ host_vm_group_type_option_type(required: true, default: 'HOST_GROUP'),
2023
+ # A cloud-scoped host/VM group must belong to a single cluster --
2024
+ # HostVmGroupsController#save rejects servers that span clusters. Same
2025
+ # picker the cloud-scoped affinity group form uses.
2026
+ {'fieldName' => 'pool.id', 'fieldLabel' => 'Cluster', 'type' => 'select', 'optionSourceType' => 'vmware',
2027
+ 'optionSource' => 'vmwareZonePoolClusters', 'description' => 'Select cluster for the host/VM group.', 'required' => true},
2028
+ ]
2029
+ end
2030
+
2031
+ def update_cloud_host_vm_group_option_types
2032
+ [
2033
+ {'fieldName' => 'name', 'fieldLabel' => 'Name', 'type' => 'text'},
2034
+ ]
2035
+ end
2036
+
2037
+ end