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,2986 @@
1
+ require 'mtncloud/cli/cli_command'
2
+
3
+ class MtnCloud::Cli::Hosts
4
+ include MtnCloud::Cli::CliCommand
5
+ include MtnCloud::Cli::AccountsHelper
6
+ include MtnCloud::Cli::ProcessesHelper
7
+ include MtnCloud::Cli::ProvisioningHelper
8
+ include MtnCloud::Cli::LogsHelper
9
+ set_command_name :hosts
10
+ set_command_description "View and manage hosts (servers)."
11
+ register_subcommands :list, :count, :get, :view, :stats, :add, :update, :remove, :logs, :start, :stop, :resize, :restart,
12
+ :run_workflow, :make_managed, :upgrade_agent, :snapshots, :software, :software_sync, :update_network_label,
13
+ {:'types' => :list_types},
14
+ {:exec => :execution_request},
15
+ :wiki, :update_wiki,
16
+ :maintenance, :leave_maintenance, :placement,
17
+ :list_devices, :assign_device, :detach_device, :attach_device,
18
+ :snapshot, :create_linked_clone
19
+ alias_subcommand :details, :get
20
+ set_default_subcommand :list
21
+
22
+ def initialize()
23
+ # @appliance_name, @appliance_url = MtnCloud::Cli::Remote.active_appliance
24
+ end
25
+
26
+ def connect(opts)
27
+ @api_client = establish_remote_appliance_connection(opts)
28
+ @accounts_interface = @api_client.accounts
29
+ @account_users_interface = @api_client.account_users
30
+ @clouds_interface = @api_client.clouds
31
+ @options_interface = @api_client.options
32
+ @tasks_interface = @api_client.tasks
33
+ @task_sets_interface = @api_client.task_sets
34
+ @servers_interface = @api_client.servers
35
+ @server_types_interface = @api_client.server_types
36
+ @provision_types_interface = @api_client.provision_types
37
+ @logs_interface = @api_client.logs
38
+ @accounts_interface = @api_client.accounts
39
+ @active_group_id = MtnCloud::Cli::Groups.active_groups[@appliance_name]
40
+ @execution_request_interface = @api_client.execution_request
41
+ @clusters_interface = @api_client.clusters
42
+ end
43
+
44
+ def handle(args)
45
+ handle_subcommand(args)
46
+ end
47
+
48
+ def list(args)
49
+ options = {}
50
+ params = {}
51
+ optparse = MtnCloud::Cli::OptionParser.new do |opts|
52
+ opts.banner = subcommand_usage()
53
+ opts.on( '-g', '--group GROUP', "Group Name or ID" ) do |val|
54
+ options[:group] = val
55
+ end
56
+ opts.on( '-c', '--cloud CLOUD', "Cloud Name or ID" ) do |val|
57
+ options[:cloud] = val
58
+ end
59
+ opts.on( '-M', '--managed', "Show only Managed Servers" ) do |val|
60
+ params[:managed] = true
61
+ end
62
+ opts.on( '-U', '--unmanaged', "Show only Unmanaged Servers" ) do |val|
63
+ params[:managed] = false
64
+ end
65
+ opts.on( '-t', '--type TYPE', "Show only Certain Server Types" ) do |val|
66
+ params[:serverType] = val
67
+ end
68
+ opts.on( '-p', '--power STATE', "Filter by Power Status" ) do |val|
69
+ params[:powerState] = val
70
+ end
71
+ opts.on( '-i', '--ip IPADDRESS', "Filter by IP Address" ) do |val|
72
+ params[:ip] = val
73
+ end
74
+ opts.on( '--cluster CLUSTER', '--cluster CLUSTER', "Filter by Cluster Name or ID" ) do |val|
75
+ # params[:clusterId] = val
76
+ options[:cluster] = val
77
+ end
78
+ opts.on( '--parent HOST', "Parent Host / Hypervisor Name or ID" ) do |val|
79
+ options[:parent_server_id] = val
80
+ end
81
+ opts.on( '--plan NAME', String, "Filter by Plan name(s)" ) do |val|
82
+ # commas used in names a lot so use --plan one --plan two
83
+ params['plan'] ||= []
84
+ params['plan'] << val
85
+ end
86
+ opts.on( '--plan-id ID', String, "Filter by Plan id(s)" ) do |val|
87
+ params['planId'] = parse_id_list(val)
88
+ end
89
+ opts.on( '--plan-code CODE', String, "Filter by Plan code(s)" ) do |val|
90
+ params['planCode'] = parse_id_list(val)
91
+ end
92
+ opts.on('--vm', "Show only virtual machines" ) do
93
+ params[:vm] = true
94
+ end
95
+ opts.on('--hypervisor', "Show only VM Hypervisors" ) do
96
+ params[:vmHypervisor] = true
97
+ end
98
+ opts.on('--container', "Show only Container Hypervisors" ) do
99
+ params[:containerHypervisor] = true
100
+ end
101
+ opts.on('--baremetal', "Show only Baremetal Servers" ) do
102
+ params[:bareMetalHost] = true
103
+ end
104
+ opts.on('--status STATUS', String, "Filter by Status" ) do |val|
105
+ params[:status] = val
106
+ end
107
+ opts.on('--agent', "Show only Servers with the agent installed" ) do
108
+ params[:agentInstalled] = true
109
+ end
110
+ opts.on('--noagent', "Show only Servers with No agent" ) do
111
+ params[:agentInstalled] = false
112
+ end
113
+ opts.on( '--created-by USER', "Created By User Username or ID" ) do |val|
114
+ options[:created_by] = val
115
+ end
116
+ opts.on('--include-tenants','--include-tenants', "Include sub tenant servers. The default is true for this endpoint.") do
117
+ options[:include_tenants] = true
118
+ params['includeTenants'] = true
119
+ end
120
+ opts.on( '--tenant TENANT', "Tenant Name or ID" ) do |val|
121
+ options[:tenant] = val
122
+ end
123
+ opts.on('-l', '--labels LABEL', String, "Filter by labels, can match any of the values") do |val|
124
+ add_query_parameter(params, 'labels', parse_labels(val))
125
+ end
126
+ opts.on('--all-labels LABEL', String, "Filter by labels, must match all of the values") do |val|
127
+ add_query_parameter(params, 'allLabels', parse_labels(val))
128
+ end
129
+ opts.on('--tags Name=Value',String, "Filter by tags.") do |val|
130
+ val.split(",").each do |value_pair|
131
+ k,v = value_pair.strip.split("=")
132
+ options[:tags] ||= {}
133
+ options[:tags][k] ||= []
134
+ options[:tags][k] << (v || '')
135
+ end
136
+ end
137
+ opts.on('--tag-compliant', "Displays only servers that are valid according to applied tag policies. Does not show servers that do not have tag policies." ) do
138
+ params[:tagCompliant] = true
139
+ end
140
+ opts.on('--non-tag-compliant', "Displays only servers with tag compliance warnings." ) do
141
+ params[:tagCompliant] = false
142
+ end
143
+ opts.on('--stats', "Display values for memory and storage usage used / max values." ) do
144
+ options[:stats] = true
145
+ end
146
+ opts.on('-a', '--details', "Display all details: hostname, private ip, plan, stats, etc." ) do
147
+ options[:details] = true
148
+ end
149
+ build_standard_list_options(opts, options)
150
+ opts.footer = "List hosts."
151
+ end
152
+ optparse.parse!(args)
153
+ connect(options)
154
+ # verify_args!(args:args, optparse:optparse, count:0)
155
+ if args.count > 0
156
+ options[:phrase] = args.join(" ")
157
+ end
158
+
159
+ params.merge!(parse_list_options(options))
160
+ account = nil
161
+ if options[:tenant]
162
+ account = find_account_by_name_or_id(options[:tenant])
163
+ if account.nil?
164
+ return 1
165
+ else
166
+ params['accountId'] = account['id']
167
+ end
168
+ end
169
+ group = options[:group] ? find_group_by_name_or_id_for_provisioning(options[:group]) : nil
170
+ if group
171
+ params['siteId'] = group['id']
172
+ end
173
+
174
+ # argh, this doesn't work because group_id is required for options/clouds
175
+ # cloud = options[:cloud] ? find_cloud_by_name_or_id_for_provisioning(group_id, options[:cloud]) : nil
176
+ cloud = options[:cloud] ? find_zone_by_name_or_id(nil, options[:cloud]) : nil
177
+ if cloud
178
+ params['zoneId'] = cloud['id']
179
+ end
180
+
181
+ if options[:created_by]
182
+ created_by_ids = find_all_user_ids(account ? account['id'] : nil, options[:created_by])
183
+ return if created_by_ids.nil?
184
+ params['createdBy'] = created_by_ids
185
+ # params['ownerId'] = created_by_ids # 4.2.1+
186
+ end
187
+
188
+ cluster = nil
189
+ if options[:cluster]
190
+ if options[:cluster].to_s =~ /\A\d{1,}\Z/
191
+ params['clusterId'] = options[:cluster]
192
+ else
193
+ cluster = find_cluster_by_name_or_id(options[:cluster])
194
+ return 1 if cluster.nil?
195
+ params['clusterId'] = cluster['id']
196
+ end
197
+ end
198
+ parent_hosts = nil
199
+ if options[:parent_server_id]
200
+ parent_hosts = parse_id_list(options[:parent_server_id]).collect do |parent_server_id|
201
+ find_host_by_name_or_id(parent_server_id)
202
+ end
203
+ params['parentServerId'] = parent_hosts.collect {|it| it['id'] }
204
+ end
205
+ params['labels'] = options[:labels] if options[:labels]
206
+ if options[:tags] && !options[:tags].empty?
207
+ options[:tags].each do |k,v|
208
+ params['tags.' + k] = v
209
+ end
210
+ end
211
+
212
+ @servers_interface.setopts(options)
213
+ if options[:dry_run]
214
+ print_dry_run @servers_interface.dry.list(params)
215
+ return
216
+ end
217
+ json_response = @servers_interface.list(params)
218
+
219
+ # merge stats to be nice here..
220
+ all_stats = json_response['stats']
221
+ if options[:include_fields] || options[:all_fields]
222
+ if json_response['servers']
223
+ if all_stats
224
+ json_response['servers'].each do |it|
225
+ it['stats'] ||= all_stats[it['id'].to_s] || all_stats[it['id']]
226
+ end
227
+ end
228
+ end
229
+ end
230
+ render_response(json_response, options, "servers") do
231
+
232
+ servers = json_response['servers']
233
+ multi_tenant = json_response['multiTenant'] == true
234
+ title = "Hosts"
235
+ subtitles = []
236
+ if account
237
+ subtitles << "Tenant: #{account['name']}".strip
238
+ end
239
+ if group
240
+ subtitles << "Group: #{group['name']}".strip
241
+ end
242
+ if cloud
243
+ subtitles << "Cloud: #{cloud['name']}".strip
244
+ end
245
+ if cluster
246
+ subtitles << "Cluster: #{cluster['name']}".strip
247
+ elsif params['clusterId']
248
+ subtitles << "Cluster: #{params['clusterId']}".strip
249
+ end
250
+ if parent_hosts
251
+ subtitles << "Parent Host: #{parent_hosts.collect {|it| it['name'] }.join(", ")}".strip
252
+ end
253
+ subtitles += parse_list_subtitles(options)
254
+ print_h1 title, subtitles, options
255
+ if servers.empty?
256
+ print cyan,"No hosts found.",reset,"\n"
257
+ else
258
+ # print_servers_table(servers)
259
+ # server returns stats in a separate key stats => {"id" => {} }
260
+ # the id is a string right now..for some reason..
261
+ all_stats = json_response['stats'] || {}
262
+ servers.each do |it|
263
+ found_stats = all_stats[it['id'].to_s] || all_stats[it['id']]
264
+ if found_stats
265
+ if !it['stats']
266
+ it['stats'] = found_stats # || {}
267
+ else
268
+ it['stats'] = found_stats.merge!(it['stats'])
269
+ end
270
+ end
271
+ end
272
+
273
+ rows = servers.collect {|server|
274
+ stats = server['stats']
275
+
276
+ if !stats['maxMemory'] && (stats['usedMemory'] || stats['freeMemory'])
277
+ stats['maxMemory'] = stats['usedMemory'].to_i + stats['freeMemory'].to_i
278
+ end
279
+ cpu_usage_str = !stats ? "" : generate_usage_bar((stats['usedCpu'] || stats['cpuUsage']).to_f, 100, {max_bars: 10})
280
+ memory_usage_str = !stats ? "" : generate_usage_bar(stats['usedMemory'], stats['maxMemory'], {max_bars: 10})
281
+ storage_usage_str = !stats ? "" : generate_usage_bar(stats['usedStorage'], stats['maxStorage'], {max_bars: 10})
282
+ if options[:details] || options[:stats]
283
+ if stats['maxMemory'] && stats['maxMemory'].to_i != 0
284
+ memory_usage_str = memory_usage_str + cyan + format_bytes_short(stats['usedMemory']).strip.rjust(8, ' ') + " / " + format_bytes_short(stats['maxMemory']).strip
285
+ end
286
+ if stats['maxStorage'] && stats['maxStorage'].to_i != 0
287
+ storage_usage_str = storage_usage_str + cyan + format_bytes_short(stats['usedStorage']).strip.rjust(8, ' ') + " / " + format_bytes_short(stats['maxStorage']).strip
288
+ end
289
+ end
290
+ row = {
291
+ id: server['id'],
292
+ name: server['name'],
293
+ external_name: server['externalName'],
294
+ hostname: server['hostname'],
295
+ platform: server['serverOs'] ? server['serverOs']['name'].upcase : 'N/A',
296
+ type: server['computeServerType'] ? server['computeServerType']['name'] : 'unmanaged',
297
+ tenant: server['account'] ? server['account']['name'] : server['accountId'],
298
+ owner: server['owner'] ? server['owner']['username'] : server['owner'],
299
+ cloud: server['zone'] ? server['zone']['name'] : '',
300
+ plan: server['plan'] ? server['plan']['name'] : '',
301
+ ip: server['externalIp'],
302
+ internal_ip: server['internalIp'],
303
+ nodes: server['containers'] ? server['containers'].size : '',
304
+ # status: format_server_status(server, cyan),
305
+ status: (options[:details]||options[:all_fields]) ? format_server_status(server, cyan) : format_server_status_friendly(server, cyan),
306
+ power: format_server_power_state(server, cyan),
307
+ cpu: cpu_usage_str + cyan,
308
+ memory: memory_usage_str + cyan,
309
+ storage: storage_usage_str + cyan,
310
+ created: format_local_dt(server['dateCreated']),
311
+ updated: format_local_dt(server['lastUpdated']),
312
+ }
313
+ row
314
+ }
315
+ # columns = [:id, :name, :type, :cloud, :ip, :internal_ip, :nodes, :status, :power]
316
+ columns = {
317
+ "ID" => :id,
318
+ "Name" => :name,
319
+ "External Name" => :external_name,
320
+ "Hostname" => :hostname,
321
+ "Type" => :type,
322
+ "Cloud" => :cloud,
323
+ "Owner" => :owner,
324
+ "Tenant" => :tenant,
325
+ "Plan" => :plan,
326
+ "IP" => :ip,
327
+ "Private IP" => :internal_ip,
328
+ "Nodes" => :nodes,
329
+ "Status" => :status,
330
+ "Power" => :power,
331
+ "CPU" => :cpu,
332
+ "Memory" => :memory,
333
+ "Storage" => :storage,
334
+ "Created" => :created,
335
+ "Updated" => :updated,
336
+ }
337
+ if options[:details] != true
338
+ columns.delete("External Name")
339
+ columns.delete("Hostname")
340
+ columns.delete("Plan")
341
+ columns.delete("Private IP")
342
+ columns.delete("Power")
343
+ columns.delete("Created")
344
+ columns.delete("Updated")
345
+ end
346
+ # hide External Name if there are none
347
+ if !servers.find {|it| it['externalName'] && it['externalName'] != it['name']}
348
+ columns.delete("External Name")
349
+ end
350
+ if !multi_tenant
351
+ columns.delete("Tenant")
352
+ end
353
+ # columns += [:cpu, :memory, :storage]
354
+ # # custom pretty table columns ...
355
+ # if options[:include_fields]
356
+ # columns = options[:include_fields]
357
+ # end
358
+ print cyan
359
+ print as_pretty_table(rows, columns.upcase_keys!, options)
360
+ print reset
361
+ print_results_pagination(json_response)
362
+ end
363
+ print reset,"\n"
364
+ end
365
+ return 0, nil
366
+ end
367
+
368
+ def count(args)
369
+ params = {}
370
+ options = {}
371
+ optparse = MtnCloud::Cli::OptionParser.new do |opts|
372
+ opts.banner = subcommand_usage("[options]")
373
+ opts.on( '--tenant TENANT', "Tenant Name or ID" ) do |val|
374
+ options[:tenant] = val
375
+ end
376
+ opts.on( '-g', '--group GROUP', "Group Name or ID" ) do |val|
377
+ options[:group] = val
378
+ end
379
+ opts.on( '-c', '--cloud CLOUD', "Cloud Name or ID" ) do |val|
380
+ options[:cloud] = val
381
+ end
382
+ opts.on( '-M', '--managed', "Show only Managed Servers" ) do |val|
383
+ params[:managed] = true
384
+ end
385
+ opts.on( '-U', '--unmanaged', "Show only Unmanaged Servers" ) do |val|
386
+ params[:managed] = false
387
+ end
388
+ opts.on( '-t', '--type TYPE', "Show only Certain Server Types" ) do |val|
389
+ params[:serverType] = val
390
+ end
391
+ opts.on( '-p', '--power STATE', "Filter by Power Status" ) do |val|
392
+ params[:powerState] = val
393
+ end
394
+ opts.on( '-i', '--ip IPADDRESS', "Filter by IP Address" ) do |val|
395
+ params[:ip] = val
396
+ end
397
+ opts.on( '--cluster CLUSTER', '--cluster CLUSTER', "Filter by Cluster Name or ID" ) do |val|
398
+ # params[:clusterId] = val
399
+ options[:cluster] = val
400
+ end
401
+ opts.on( '--parent HOST', "Parent Host / Hypervisor Name or ID" ) do |val|
402
+ options[:parent_server_id] = val
403
+ end
404
+ opts.on('--vm', "Show only virtual machines" ) do
405
+ params[:vm] = true
406
+ end
407
+ opts.on('--hypervisor', "Show only VM Hypervisors" ) do
408
+ params[:vmHypervisor] = true
409
+ end
410
+ opts.on('--container', "Show only Container Hypervisors" ) do
411
+ params[:containerHypervisor] = true
412
+ end
413
+ opts.on('--baremetal', "Show only Baremetal Servers" ) do
414
+ params[:bareMetalHost] = true
415
+ end
416
+ opts.on('--status STATUS', "Filter by Status" ) do |val|
417
+ params[:status] = val
418
+ end
419
+ opts.on('--agent', "Show only Servers with the agent installed" ) do
420
+ params[:agentInstalled] = true
421
+ end
422
+ opts.on('--noagent', "Show only Servers with No agent" ) do
423
+ params[:agentInstalled] = false
424
+ end
425
+ opts.on( '--created-by USER', "Created By User Username or ID" ) do |val|
426
+ options[:created_by] = val
427
+ end
428
+ opts.on( '-s', '--search PHRASE', "Search Phrase" ) do |phrase|
429
+ options[:phrase] = phrase
430
+ end
431
+ build_common_options(opts, options, [:query, :remote, :dry_run])
432
+ opts.footer = "Get the number of hosts."
433
+ end
434
+ optparse.parse!(args)
435
+ connect(options)
436
+ begin
437
+ params.merge!(parse_list_options(options))
438
+ account = nil
439
+ if options[:tenant]
440
+ account = find_account_by_name_or_id(options[:tenant])
441
+ if account.nil?
442
+ return 1
443
+ else
444
+ params['accountId'] = account['id']
445
+ end
446
+ end
447
+ group = options[:group] ? find_group_by_name_or_id_for_provisioning(options[:group]) : nil
448
+ if group
449
+ params['siteId'] = group['id']
450
+ end
451
+
452
+ # argh, this doesn't work because group_id is required for options/clouds
453
+ # cloud = options[:cloud] ? find_cloud_by_name_or_id_for_provisioning(group_id, options[:cloud]) : nil
454
+ cloud = options[:cloud] ? find_zone_by_name_or_id(nil, options[:cloud]) : nil
455
+ if cloud
456
+ params['zoneId'] = cloud['id']
457
+ end
458
+
459
+ if options[:created_by]
460
+ created_by_ids = find_all_user_ids(account ? account['id'] : nil, options[:created_by])
461
+ return if created_by_ids.nil?
462
+ params['createdBy'] = created_by_ids
463
+ # params['ownerId'] = created_by_ids # 4.2.1+
464
+ end
465
+ cluster = nil
466
+ if options[:cluster]
467
+ if options[:cluster].to_s =~ /\A\d{1,}\Z/
468
+ params['clusterId'] = options[:cluster]
469
+ else
470
+ cluster = find_cluster_by_name_or_id(options[:cluster])
471
+ return 1 if cluster.nil?
472
+ params['clusterId'] = cluster['id']
473
+ end
474
+ end
475
+ parent_hosts = nil
476
+ if options[:parent_server_id]
477
+ parent_hosts = parse_id_list(options[:parent_server_id]).collect do |parent_server_id|
478
+ find_host_by_name_or_id(parent_server_id)
479
+ end
480
+ params['parentServerId'] = parent_hosts.collect {|it| it['id'] }
481
+ end
482
+ @servers_interface.setopts(options)
483
+ if options[:dry_run]
484
+ print_dry_run @servers_interface.dry.list(params)
485
+ return
486
+ end
487
+ json_response = @servers_interface.list(params)
488
+ # print number only
489
+ if json_response['meta'] && json_response['meta']['total']
490
+ print cyan, json_response['meta']['total'], reset, "\n"
491
+ else
492
+ print yellow, "unknown", reset, "\n"
493
+ end
494
+ return 0
495
+ rescue RestClient::Exception => e
496
+ print_rest_exception(e, options)
497
+ exit 1
498
+ end
499
+ end
500
+
501
+ def get(args)
502
+ options = {}
503
+ optparse = MtnCloud::Cli::OptionParser.new do |opts|
504
+ opts.banner = subcommand_usage("[name]")
505
+ opts.on( nil, '--costs', "Display Cost and Price" ) do
506
+ options[:include_costs] = true
507
+ end
508
+ opts.on('--refresh [SECONDS]', String, "Refresh until status is provisioned,failed. Default interval is #{default_refresh_interval} seconds.") do |val|
509
+ options[:refresh_until_status] ||= "provisioned,failed"
510
+ if !val.to_s.empty?
511
+ options[:refresh_interval] = val.to_f
512
+ end
513
+ end
514
+ opts.on('--refresh-until STATUS', String, "Refresh until a specified status is reached.") do |val|
515
+ options[:refresh_until_status] = val.to_s.downcase
516
+ end
517
+ opts.on('--include-tenants','--include-tenants', "Include sub tenant servers when finding server by name") do
518
+ options[:include_tenants] = true
519
+ end
520
+ build_standard_get_options(opts, options)
521
+ end
522
+ optparse.parse!(args)
523
+ if args.count < 1
524
+ puts optparse
525
+ exit 1
526
+ end
527
+ connect(options)
528
+ id_list = parse_id_list(args)
529
+ return run_command_for_each_arg(id_list) do |arg|
530
+ _get(arg, options)
531
+ end
532
+ end
533
+
534
+ def _get(arg, options)
535
+ @servers_interface.setopts(options)
536
+ if options[:dry_run]
537
+ if arg.to_s =~ /\A\d{1,}\Z/
538
+ print_dry_run @servers_interface.dry.get(arg.to_i)
539
+ else
540
+ print_dry_run @servers_interface.dry.list({name: arg})
541
+ end
542
+ return
543
+ end
544
+ json_response = nil
545
+ if arg.to_s =~ /\A\d{1,}\Z/
546
+ json_response = @servers_interface.get(arg.to_i)
547
+ else
548
+ server = find_host_by_name_or_id(arg, options[:include_tenants])
549
+ json_response = @servers_interface.get(server['id'])
550
+ # json_response = {"server" => server} need stats
551
+ end
552
+ render_response(json_response, options, "server") do
553
+ server = json_response['server'] || json_response['host'] || {}
554
+ #stats = server['stats'] || json_response['stats'] || {}
555
+ stats = json_response['stats'] || {}
556
+ tags = server['tags'] || server['metadata']
557
+ title = "Host Details"
558
+ print_h1 title, [], options
559
+ print cyan
560
+ server_columns = {
561
+ "ID" => 'id',
562
+ "Name" => 'name',
563
+ "Hostname" => 'hostname',
564
+ "Description" => 'description',
565
+ "Labels" => lambda {|it| format_list(it['labels']) rescue '' },
566
+ "Tags" => lambda {|it| tags ? format_metadata(tags) : '' },
567
+ "Owner" => lambda {|it| it['owner'] ? it['owner']['username'] : '' },
568
+ "Tenant" => lambda {|it| it['account'] ? it['account']['name'] : '' },
569
+ #"Group" => lambda {|it| it['group'] ? it['group']['name'] : '' },
570
+ "Cloud" => lambda {|it| it['zone'] ? it['zone']['name'] : '' },
571
+ "IP" => lambda {|it| it['externalIp'] },
572
+ "Private IP" => lambda {|it| it['internalIp'] },
573
+ "Type" => lambda {|it| it['computeServerType'] ? it['computeServerType']['name'] : 'unmanaged' },
574
+ "Platform" => lambda {|it| it['serverOs'] ? it['serverOs']['name'].upcase : 'N/A' },
575
+ "Plan" => lambda {|it| it['plan'] ? it['plan']['name'] : '' },
576
+ "Cost" => lambda {|it| it['hourlyCost'] ? format_money(it['hourlyCost'], (it['currency'] || 'USD'), {sigdig:15}).to_s + ' per hour' : '' },
577
+ "Price" => lambda {|it| it['hourlyPrice'] ? format_money(it['hourlyPrice'], (it['currency'] || 'USD'), {sigdig:15}).to_s + ' per hour' : '' },
578
+ "Agent" => lambda {|it| it['agentInstalled'] ? "#{server['agentVersion'] || ''} updated at #{format_local_dt(server['lastAgentUpdate'])}" : '(not installed)' },
579
+ "Nodes" => lambda {|it| it['containers'] ? it['containers'].size : 0 },
580
+ # "Status" => lambda {|it| format_server_status(it) },
581
+ # "Power" => lambda {|it| format_server_power_state(it) },
582
+ "Managed" => lambda {|it| it['computeServerType'] ? it['computeServerType']['managed'] : ''},
583
+ "Instance" => lambda {|it| it['instance'] ? it['instance']['name'] : ''},
584
+ "Status" => lambda {|it| format_server_status_friendly(it) } # combo
585
+ }
586
+ server_columns.delete("Hostname") if server['hostname'].to_s.empty? || server['hostname'] == server['name']
587
+ server_columns.delete("IP") if server['externalIp'].to_s.empty?
588
+ server_columns.delete("Private IP") if server['internalIp'].to_s.empty?
589
+ # server_columns.delete("Tenant") if multi_tenant != true
590
+ server_columns.delete("Cost") if server['hourlyCost'].to_f == 0
591
+ server_columns.delete("Price") if server['hourlyPrice'].to_f == 0 || server['hourlyPrice'] == server['hourlyCost']
592
+ server_columns.delete("Labels") if server['labels'].nil? || server['labels'].empty?
593
+ server_columns.delete("Instance") if server['instance'].nil?
594
+
595
+ print_description_list(server_columns, server)
596
+
597
+ if server['statusMessage']
598
+ print_h2 "Status Message", options
599
+ if server['status'] == 'failed'
600
+ print red, server['statusMessage'], reset
601
+ else
602
+ print server['statusMessage']
603
+ end
604
+ print "\n"
605
+ end
606
+ if server['errorMessage']
607
+ print_h2 "Error Message", options
608
+ print red, server['errorMessage'], reset, "\n"
609
+ end
610
+
611
+ print_h2 "Host Usage", options
612
+ print_stats_usage(stats)
613
+
614
+ if options[:include_costs]
615
+ print_h2 "Host Cost"
616
+ cost_columns = {
617
+ "Cost" => lambda {|it| it['hourlyCost'] ? format_money(it['hourlyCost'], (it['currency'] || 'USD'), {sigdig:15}).to_s + ' per hour' : '' },
618
+ "Price" => lambda {|it| it['hourlyPrice'] ? format_money(it['hourlyPrice'], (it['currency'] || 'USD'), {sigdig:15}).to_s + ' per hour' : '' },
619
+ }
620
+ print_description_list(cost_columns, server)
621
+ end
622
+
623
+ print reset, "\n"
624
+
625
+
626
+ # refresh until a status is reached
627
+ if options[:refresh_until_status]
628
+ if options[:refresh_interval].nil? || options[:refresh_interval].to_f < 0
629
+ options[:refresh_interval] = default_refresh_interval
630
+ end
631
+ statuses = options[:refresh_until_status].to_s.downcase.split(",").collect {|s| s.strip }.select {|s| !s.to_s.empty? }
632
+ if !statuses.include?(server['status'])
633
+ print cyan
634
+ print cyan, "Refreshing in #{options[:refresh_interval] > 1 ? options[:refresh_interval].to_i : options[:refresh_interval]} seconds"
635
+ sleep_with_dots(options[:refresh_interval])
636
+ print "\n"
637
+ _get(arg, options)
638
+ end
639
+ end
640
+ end
641
+ return 0, nil
642
+ end
643
+
644
+ def stats(args)
645
+ options = {}
646
+ optparse = MtnCloud::Cli::OptionParser.new do |opts|
647
+ opts.banner = subcommand_usage("[name]")
648
+ build_common_options(opts, options, [:json, :yaml, :csv, :fields, :dry_run, :remote])
649
+ end
650
+ optparse.parse!(args)
651
+ if args.count < 1
652
+ puts optparse
653
+ exit 1
654
+ end
655
+ connect(options)
656
+ ids = args
657
+ id_list = parse_id_list(args)
658
+ return run_command_for_each_arg(id_list) do |arg|
659
+ _stats(arg, options)
660
+ end
661
+ end
662
+
663
+ def _stats(arg, options)
664
+ begin
665
+ @servers_interface.setopts(options)
666
+ if options[:dry_run]
667
+ if arg.to_s =~ /\A\d{1,}\Z/
668
+ print_dry_run @servers_interface.dry.get(arg.to_i)
669
+ else
670
+ print_dry_run @servers_interface.dry.list({name: arg})
671
+ end
672
+ return
673
+ end
674
+ server = find_host_by_name_or_id(arg)
675
+ json_response = @servers_interface.get(server['id'])
676
+ if options[:json]
677
+ puts as_json(json_response, options, "stats")
678
+ return 0
679
+ elsif options[:yaml]
680
+ puts as_yaml(json_response, options, "stats")
681
+ return 0
682
+ elsif options[:csv]
683
+ puts records_as_csv([json_response['stats']], options)
684
+ return 0
685
+ end
686
+ server = json_response['server']
687
+ #stats = server['stats'] || json_response['stats'] || {}
688
+ stats = json_response['stats'] || {}
689
+ title = "Host Stats: #{server['name']} (#{server['computeServerType'] ? server['computeServerType']['name'] : 'unmanaged'})"
690
+ print_h1 title, [], options
691
+ puts cyan + "Power: ".rjust(12) + format_server_power_state(server).to_s
692
+ puts cyan + "Status: ".rjust(12) + format_server_status(server).to_s
693
+ puts cyan + "Nodes: ".rjust(12) + (server['containers'] ? server['containers'].size : '').to_s
694
+ #print_h2 "Host Usage", options
695
+ print_stats_usage(stats, {label_width: 10})
696
+
697
+ print reset, "\n"
698
+ return 0
699
+ rescue RestClient::Exception => e
700
+ print_rest_exception(e, options)
701
+ exit 1
702
+ end
703
+ end
704
+
705
+ def logs(args)
706
+ options = {}
707
+ params = {}
708
+ optparse = MtnCloud::Cli::OptionParser.new do |opts|
709
+ opts.banner = subcommand_usage("[name]")
710
+ opts.on('--start TIMESTAMP','--start TIMESTAMP', "Start timestamp. Default is 30 days ago.") do |val|
711
+ options[:start] = parse_time(val) #.utc.iso8601
712
+ end
713
+ opts.on('--end TIMESTAMP','--end TIMESTAMP', "End timestamp. Default is now.") do |val|
714
+ options[:end] = parse_time(val) #.utc.iso8601
715
+ end
716
+ opts.on('--level VALUE', String, "Log Level. DEBUG,INFO,WARN,ERROR") do |val|
717
+ params['level'] = params['level'] ? [params['level'], val].flatten : [val]
718
+ end
719
+ opts.on('--table', '--table', "Format ouput as a table.") do
720
+ options[:table] = true
721
+ end
722
+ opts.on('-a', '--all', "Display all details: entire message." ) do
723
+ options[:details] = true
724
+ end
725
+ build_common_options(opts, options, [:list, :query, :json, :yaml, :csv, :fields, :dry_run, :remote])
726
+ end
727
+ optparse.parse!(args)
728
+ if args.count < 1
729
+ puts optparse
730
+ exit 1
731
+ end
732
+ connect(options)
733
+ begin
734
+ server = find_host_by_name_or_id(args[0])
735
+ params['level'] = params['level'].collect {|it| it.to_s.upcase }.join('|') if params['level'] # api works with INFO|WARN
736
+ params.merge!(parse_list_options(options))
737
+ params['query'] = params.delete('phrase') if params['phrase']
738
+ params['order'] = params['direction'] unless params['direction'].nil? # old api version expects order instead of direction
739
+ params['startMs'] = (options[:start].to_i * 1000) if options[:start]
740
+ params['endMs'] = (options[:end].to_i * 1000) if options[:end]
741
+ @logs_interface.setopts(options)
742
+ if options[:dry_run]
743
+ print_dry_run @logs_interface.dry.server_logs([server['id']], params)
744
+ return
745
+ end
746
+ json_response = @logs_interface.server_logs([server['id']], params)
747
+ render_result = json_response['logs'] ? render_with_format(json_response, options, 'logs') : render_with_format(json_response, options, 'data')
748
+ return 0 if render_result
749
+
750
+ title = "Host Logs: #{server['name']} (#{server['computeServerType'] ? server['computeServerType']['name'] : 'unmanaged'})"
751
+ subtitles = parse_list_subtitles(options)
752
+ if options[:start]
753
+ subtitles << "Start: #{options[:start]}".strip
754
+ end
755
+ if options[:end]
756
+ subtitles << "End: #{options[:end]}".strip
757
+ end
758
+ if params[:query]
759
+ subtitles << "Search: #{params[:query]}".strip
760
+ end
761
+ # if params['containers']
762
+ # subtitles << "Containers: #{params['containers']}".strip
763
+ # end
764
+ if params['level']
765
+ subtitles << "Level: #{params['level']}"
766
+ end
767
+ print_h1 title, subtitles, options
768
+ logs = json_response['data'] || json_response['logs']
769
+ if logs.empty?
770
+ print "#{cyan}No logs found.#{reset}\n"
771
+ else
772
+ print format_log_records(logs, options)
773
+ print_results_pagination({'meta'=>{'total'=>(json_response['total']['value'] rescue json_response['total']),'size'=>logs.size,'max'=>(json_response['max'] || options[:max]),'offset'=>(json_response['offset'] || options[:offset] || 0)}})
774
+ end
775
+ print reset, "\n"
776
+ return 0
777
+ rescue RestClient::Exception => e
778
+ print_rest_exception(e, options)
779
+ exit 1
780
+ end
781
+ end
782
+
783
+ def add(args)
784
+ options = {}
785
+ optparse = MtnCloud::Cli::OptionParser.new do |opts|
786
+ opts.banner = subcommand_usage("[cloud]", "[name]")
787
+ opts.on( '-g', '--group GROUP', "Group Name or ID" ) do |val|
788
+ options[:group] = val
789
+ end
790
+ opts.on( '-c', '--cloud CLOUD', "Cloud Name or ID" ) do |val|
791
+ options[:cloud] = val
792
+ end
793
+ opts.on( '-t', '--type TYPE', "Server Type Code" ) do |val|
794
+ options[:server_type_code] = val
795
+ end
796
+ opts.on("--security-groups LIST", Integer, "Security Groups, comma separated list of security group IDs") do |val|
797
+ options[:security_groups] = val.split(",").collect {|s| s.strip }.select {|s| !s.to_s.empty? }
798
+ end
799
+ opts.on("--storage-controller ARRAY", String, "Storage Controllers, JSON array of controller configs. Each entry accepts id, busNumber, typeId, typeName, removable, editable.") do |val|
800
+ options[:options] ||= {}
801
+ options[:options]['storageController'] = JSON.parse(val)
802
+ end
803
+ opts.on('--tags LIST', String, "Metadata tags in the format 'ping=pong,flash=bang'") do |val|
804
+ options[:metadata] = val
805
+ end
806
+ opts.on('--metadata [LIST]', String, "Metadata tags in the format 'ping=pong,flash=bang'") do |val|
807
+ options[:metadata] = val
808
+ end
809
+ opts.add_hidden_option('--metadata')
810
+ opts.on('-l', '--labels [LIST]', String, "Labels") do |val|
811
+ options[:options]['labels'] = parse_labels(val)
812
+ end
813
+ opts.on('--refresh [SECONDS]', String, "Refresh until status is running,failed. Default interval is #{default_refresh_interval} seconds.") do |val|
814
+ options[:refresh_interval] = val.to_s.empty? ? default_refresh_interval : val.to_f
815
+ end
816
+ build_common_options(opts, options, [:options, :payload, :json, :dry_run, :quiet, :remote])
817
+ end
818
+ optparse.parse!(args)
819
+ connect(options)
820
+ begin
821
+ passed_options = options[:options] ? options[:options].reject {|k,v| k.is_a?(Symbol) } : {}
822
+ payload = nil
823
+ if options[:payload]
824
+ payload = options[:payload]
825
+ #payload.deep_merge!({'server' => passed_options}) unless passed_options.empty?
826
+ payload.deep_merge!(passed_options) unless passed_options.empty?
827
+ else
828
+ # support old format of `hosts add CLOUD NAME`
829
+ if args[0]
830
+ options[:cloud] = args[0]
831
+ end
832
+ if args[1]
833
+ options[:host_name] = args[1]
834
+ end
835
+ # use active group by default
836
+ options[:group] ||= @active_group_id
837
+
838
+ params = {}
839
+ # Group
840
+ group_id = nil
841
+ group = options[:group] ? find_group_by_name_or_id_for_provisioning(options[:group]) : nil
842
+ if group
843
+ group_id = group["id"]
844
+ else
845
+ # print_red_alert "Group not found or specified!"
846
+ # exit 1
847
+ group_prompt = MtnCloud::Cli::OptionTypes.prompt([{'fieldName' => 'group', 'type' => 'select', 'fieldLabel' => 'Group', 'selectOptions' => get_available_groups(), 'required' => true, 'description' => 'Select Group.'}],options[:options],@api_client,{})
848
+ group_id = group_prompt['group']
849
+ end
850
+
851
+ # Cloud
852
+ cloud_id = nil
853
+ cloud = options[:cloud] ? find_cloud_by_name_or_id_for_provisioning(group_id, options[:cloud]) : nil
854
+ if cloud
855
+ cloud_id = cloud["id"]
856
+ else
857
+ available_clouds = get_available_clouds(group_id)
858
+ if available_clouds.empty?
859
+ print_red_alert "Group #{group['name']} has no available clouds"
860
+ exit 1
861
+ end
862
+ cloud_prompt = MtnCloud::Cli::OptionTypes.prompt([{'fieldName' => 'cloud', 'type' => 'select', 'fieldLabel' => 'Cloud', 'selectOptions' => available_clouds, 'required' => true, 'description' => 'Select Cloud.'}],options[:options],@api_client,{groupId: group_id})
863
+ cloud_id = cloud_prompt['cloud']
864
+ cloud = find_cloud_by_id_for_provisioning(group_id, cloud_id)
865
+ end
866
+
867
+ # Zone Type
868
+ cloud_type = cloud_type_for_id(cloud['zoneTypeId'])
869
+
870
+ # Server Type
871
+ cloud_server_types = cloud_type['serverTypes'].select{|b| b['creatable'] == true && b['containerHypervisor'] == false }.sort { |x,y| x['displayOrder'] <=> y['displayOrder'] }
872
+ if options[:server_type_code]
873
+ server_type_code = options[:server_type_code]
874
+ else
875
+ server_type_options = cloud_server_types.collect {|it| {'name' => it['name'], 'value' => it['code']} }
876
+ v_prompt = MtnCloud::Cli::OptionTypes.prompt([{'fieldName' => 'type', 'type' => 'select', 'fieldLabel' => "Server Type", 'selectOptions' => server_type_options, 'required' => true, 'skipSingleOption' => true, 'description' => 'Choose a server type.'}], options[:options])
877
+ server_type_code = v_prompt['type']
878
+ end
879
+ server_type = cloud_server_types.find {|it| it['code'] == server_type_code }
880
+ if server_type.nil?
881
+ print_red_alert "Server Type #{server_type_code} not found for cloud #{cloud['name']}"
882
+ exit 1
883
+ end
884
+
885
+ # Server Name
886
+ host_name = nil
887
+ if options[:host_name]
888
+ host_name = options[:host_name]
889
+ else
890
+ name_prompt = MtnCloud::Cli::OptionTypes.prompt([{'fieldName' => 'name', 'fieldLabel' => 'Server Name', 'type' => 'text', 'required' => true}], options[:options])
891
+ host_name = name_prompt['name'] || ''
892
+ end
893
+
894
+ payload = {}
895
+ payload.deep_merge!(passed_options) unless passed_options.empty?
896
+ payload.deep_merge!({'server' => {
897
+ 'name' => host_name,
898
+ 'zone' => {'id' => cloud['id']},
899
+ 'computeServerType' => {'id' => server_type['id']},
900
+ }})
901
+
902
+ is_baremetal_host = server_type['bareMetalHost']
903
+
904
+ # Service plans do not apply during BareMetal server imports
905
+ has_service_plans = !is_baremetal_host
906
+
907
+ # uh ok, this actually expects config at root level, sibling of server
908
+ # payload.deep_merge!({'server' => passed_options}) unless passed_options.empty?
909
+ # prompt for service plan
910
+ service_plan = nil
911
+ if has_service_plans
912
+ service_plans_json = @servers_interface.service_plans({ zoneId: cloud['id'], serverTypeId: server_type["id"] })
913
+ service_plans = service_plans_json["plans"]
914
+ service_plans_dropdown = service_plans.collect { |sp| { 'name' => sp["name"], 'value' => sp["id"] } } # already sorted
915
+ plan_prompt = MtnCloud::Cli::OptionTypes.prompt([{ 'fieldName' => 'plan', 'type' => 'select', 'fieldLabel' => 'Plan', 'selectOptions' => service_plans_dropdown, 'required' => true, 'description' => 'Choose the appropriately sized plan for this server' }], options[:options])
916
+ service_plan = service_plans.find { |sp| sp["id"] == plan_prompt['plan'].to_i }
917
+ payload['server']['plan'] = {'id' => service_plan['id']}
918
+ end
919
+
920
+ option_type_list = server_type['optionTypes']
921
+
922
+ # remove cpu and memory option types, which now come from the plan
923
+ option_type_list = reject_service_plan_option_types(option_type_list)
924
+
925
+ # need to GET provision type for optionTypes, and other settings...
926
+ provision_type_code = server_type["provisionType"] ? server_type["provisionType"]["code"] : nil
927
+ provision_type = nil
928
+ if provision_type_code
929
+ provision_type = provision_types_interface.list({code:provision_type_code})['provisionTypes'][0]
930
+ if provision_type.nil?
931
+ print_red_alert "Provision Type not found by code #{provision_type_code}"
932
+ exit 1
933
+ end
934
+ else
935
+ provision_type = get_provision_type_for_zone_type(cloud['zoneType']['id'])
936
+ end
937
+
938
+ # prompt for resource pool
939
+ pool_id = nil
940
+ has_zone_pools = server_type["provisionType"] && server_type["provisionType"]["hasZonePools"]
941
+ if has_zone_pools
942
+ # pluck out the resourcePoolId option type to prompt for..why the heck is this even needed?
943
+ resource_pool_option_type = option_type_list.find {|opt| ['resourcePool','resourcePoolId','azureResourceGroupId'].include?(opt['fieldName']) }
944
+ option_type_list = option_type_list.reject {|opt| ['resourcePool','resourcePoolId','azureResourceGroupId'].include?(opt['fieldName']) }
945
+ resource_pool_option_type ||= {'fieldContext' => 'config', 'fieldName' => 'resourcePool', 'type' => 'select', 'fieldLabel' => 'Resource Pool', 'optionSource' => 'zonePools', 'required' => true, 'skipSingleOption' => true, 'description' => 'Select resource pool.'}
946
+ resource_pool_prompt = MtnCloud::Cli::OptionTypes.prompt([resource_pool_option_type],options[:options],api_client,{groupId: group_id, siteId: group_id, zoneId: cloud_id, cloudId: cloud_id, planId: service_plan ? service_plan["id"] : "", serverTypeId: server_type['id']})
947
+ resource_pool_prompt.deep_compact!
948
+ payload.deep_merge!(resource_pool_prompt)
949
+ if resource_pool_option_type['fieldContext'] && resource_pool_prompt[resource_pool_option_type['fieldContext']]
950
+ pool_id = resource_pool_prompt[resource_pool_option_type['fieldContext']][resource_pool_option_type['fieldName']]
951
+ elsif resource_pool_prompt[resource_pool_option_type['fieldName']]
952
+ pool_id = resource_pool_prompt[resource_pool_option_type['fieldName']]
953
+ end
954
+ end
955
+
956
+ if has_service_plans
957
+ # prompt for volumes
958
+ volumes = prompt_volumes(service_plan, provision_type, options, @api_client, {zoneId: cloud_id, serverTypeId: server_type['id'], siteId: group_id})
959
+ if !volumes.empty?
960
+ payload['volumes'] = volumes
961
+ end
962
+
963
+ if options[:options] && options[:options]['storageController']
964
+ payload['storageController'] = options[:options]['storageController']
965
+ end
966
+
967
+ # plan customizations
968
+ plan_opts = prompt_service_plan_options(service_plan, options, @api_client, {})
969
+ if plan_opts && !plan_opts.empty?
970
+ payload['servicePlanOptions'] = plan_opts
971
+ end
972
+ end
973
+
974
+ # prompt for network interfaces (if supported)
975
+ # Does not apply during BareMetal server imports
976
+ if !is_baremetal_host && server_type["provisionType"] && server_type["provisionType"]["id"] && server_type["provisionType"]["hasNetworks"]
977
+ begin
978
+ network_interfaces = prompt_network_interfaces(cloud['id'], server_type["provisionType"]["id"], pool_id, options)
979
+ if !network_interfaces.empty?
980
+ payload['networkInterfaces'] = network_interfaces
981
+ end
982
+ rescue RestClient::Exception => e
983
+ print yellow,"Unable to load network options. Proceeding...",reset,"\n"
984
+ print_rest_exception(e, options) if MtnCloud::Logging.debug?
985
+ end
986
+ end
987
+
988
+ # Security Groups
989
+ # prompt for multiple security groups
990
+ sg_option_type = option_type_list.find {|opt| ((opt['code'] == 'provisionType.amazon.securityId') || (opt['name'] == 'securityId')) }
991
+ option_type_list = option_type_list.reject {|opt| ((opt['code'] == 'provisionType.amazon.securityId') || (opt['name'] == 'securityId')) }
992
+ # ok.. seed data has changed and serverTypes do not have this optionType anymore...
993
+ if sg_option_type.nil?
994
+ if server_type["provisionType"] && (server_type["provisionType"]["code"] == 'amazon')
995
+ sg_option_type = {'fieldContext' => 'config', 'fieldName' => 'securityId', 'type' => 'select', 'fieldLabel' => 'Security Group', 'optionSource' => 'amazonSecurityGroup', 'required' => true, 'description' => 'Select security group.'}
996
+ end
997
+ end
998
+ has_security_groups = !!sg_option_type
999
+ if options[:security_groups]
1000
+ payload['securityGroups'] = options[:security_groups].collect {|sg_id| {'id' => sg_id} }
1001
+ else
1002
+ if has_security_groups
1003
+ security_groups_array = prompt_security_groups(sg_option_type, {zoneId: cloud_id, poolId: pool_id}, options)
1004
+ if !security_groups_array.empty?
1005
+ payload['securityGroups'] = security_groups_array.collect {|sg_id| {'id' => sg_id} }
1006
+ end
1007
+ end
1008
+ end
1009
+
1010
+ metadata_option_type = option_type_list.find {|type| type['fieldName'] == 'metadata' }
1011
+
1012
+ # Metadata Tags
1013
+ if metadata_option_type
1014
+ if options[:metadata]
1015
+ metadata = parse_metadata(options[:metadata])
1016
+ payload['tags'] = metadata if !metadata.empty?
1017
+ else
1018
+ metadata = prompt_metadata(options)
1019
+ payload['tags'] = metadata if !metadata.empty?
1020
+ end
1021
+ end
1022
+
1023
+ api_params = {}
1024
+ api_params['zoneId'] = cloud['id']
1025
+ api_params['poolId'] = payload['config']['resourcePool'] if (payload['config'] && payload['config']['resourcePool'])
1026
+ if payload['config']
1027
+ api_params.deep_merge!(payload['config'])
1028
+ end
1029
+ #api_params.deep_merge(payload)
1030
+ params = MtnCloud::Cli::OptionTypes.prompt(option_type_list,options[:options],@api_client, api_params)
1031
+ params.booleanize!
1032
+ payload.deep_merge!(params)
1033
+
1034
+ end
1035
+ @servers_interface.setopts(options)
1036
+ if options[:dry_run]
1037
+ print_dry_run @servers_interface.dry.create(payload)
1038
+ return
1039
+ end
1040
+ json_response = @servers_interface.create(payload)
1041
+ if options[:json]
1042
+ print JSON.pretty_generate(json_response)
1043
+ print "\n"
1044
+ elsif !options[:quiet]
1045
+ server_id = json_response["server"]["id"]
1046
+ server_name = json_response["server"]["name"]
1047
+ print_green_success "Provisioning host [#{server_id}] #{server_name}"
1048
+ # print details
1049
+ get_args = [server_id] + (options[:remote] ? ["-r",options[:remote]] : []) + (options[:refresh_interval] ? ['--refresh', options[:refresh_interval].to_s] : [])
1050
+ get(get_args)
1051
+ end
1052
+ rescue RestClient::Exception => e
1053
+ print_rest_exception(e, options)
1054
+ exit 1
1055
+ end
1056
+ end
1057
+
1058
+ def update(args)
1059
+ options = {}
1060
+ params = {}
1061
+ optparse = MtnCloud::Cli::OptionParser.new do |opts|
1062
+ opts.banner = subcommand_usage("[name]")
1063
+ opts.on('--name VALUE', String, "Name") do |val|
1064
+ params['name'] = val == "null" ? nil : val
1065
+ end
1066
+ opts.on('--description VALUE', String, "Description") do |val|
1067
+ params['description'] = val == "null" ? nil : val
1068
+ end
1069
+ opts.on('--ssh-username VALUE', String, "SSH Username") do |val|
1070
+ params['sshUsername'] = val == "null" ? nil : val
1071
+ end
1072
+ opts.on('--ssh-password VALUE', String, "SSH Password") do |val|
1073
+ params['sshPassword'] = val == "null" ? nil : val
1074
+ end
1075
+ opts.on('--ssh-key-pair ID', String, "SSH Key Pair ID") do |val|
1076
+ params['sshKeyPair'] = val == "null" ? nil : {"id" => val.to_i}
1077
+ end
1078
+ opts.on('--power-schedule-type ID', String, "Power Schedule Type ID") do |val|
1079
+ params['powerScheduleType'] = val == "null" ? nil : val
1080
+ end
1081
+ opts.on('-l', '--labels [LIST]', String, "Labels") do |val|
1082
+ params['labels'] = parse_labels(val)
1083
+ end
1084
+ opts.on('--tags LIST', String, "Tags in the format 'name:value, name:value'. This will add and remove tags.") do |val|
1085
+ options[:tags] = val
1086
+ end
1087
+ opts.on('--metadata LIST', String, "Alias for --tags.") do |val|
1088
+ options[:tags] = val
1089
+ end
1090
+ opts.add_hidden_option('--metadata')
1091
+ opts.on('--add-tags TAGS', String, "Add Tags in the format 'name:value, name:value'. This will only add/update tags.") do |val|
1092
+ options[:add_tags] = val
1093
+ end
1094
+ opts.on('--remove-tags TAGS', String, "Remove Tags in the format 'name, name:value'. This removes tags, the :value component is optional and must match if passed.") do |val|
1095
+ options[:remove_tags] = val
1096
+ end
1097
+ # opts.on('--created-by ID', String, "Created By User ID") do |val|
1098
+ # params['createdById'] = val
1099
+ # end
1100
+ build_common_options(opts, options, [:options, :payload, :json, :dry_run, :remote])
1101
+ end
1102
+ optparse.parse!(args)
1103
+ if args.count != 1
1104
+ puts optparse
1105
+ return 1
1106
+ end
1107
+ connect(options)
1108
+
1109
+ begin
1110
+ server = find_host_by_name_or_id(args[0])
1111
+ return 1 if server.nil?
1112
+ new_group = nil
1113
+ passed_options = options[:options] ? options[:options].reject {|k,v| k.is_a?(Symbol) } : {}
1114
+ params.deep_merge!(passed_options) unless passed_options.empty?
1115
+ params.booleanize!
1116
+ # metadata tags
1117
+ if options[:tags]
1118
+ params['tags'] = parse_metadata(options[:tags])
1119
+ else
1120
+ # params['tags'] = prompt_metadata(options)
1121
+ end
1122
+ if options[:add_tags]
1123
+ params['addTags'] = parse_metadata(options[:add_tags])
1124
+ end
1125
+ if options[:remove_tags]
1126
+ params['removeTags'] = parse_metadata(options[:remove_tags])
1127
+ end
1128
+ payload = nil
1129
+ if options[:payload]
1130
+ payload = options[:payload]
1131
+ # support args and option parameters on top of payload
1132
+ if !params.empty?
1133
+ payload['server'] ||= {}
1134
+ payload['server'].deep_merge!(params)
1135
+ end
1136
+ else
1137
+ if params.empty?
1138
+ print_red_alert "Specify at least one option to update"
1139
+ puts optparse
1140
+ return 1
1141
+ end
1142
+ payload = {}
1143
+ payload['server'] = params
1144
+ end
1145
+
1146
+ @servers_interface.setopts(options)
1147
+ if options[:dry_run]
1148
+ print_dry_run @servers_interface.dry.update(server["id"], payload)
1149
+ return
1150
+ end
1151
+ json_response = @servers_interface.update(server["id"], payload)
1152
+
1153
+ if options[:json]
1154
+ puts as_json(json_response, options)
1155
+ else
1156
+ print_green_success "Updated host #{server['name']}"
1157
+ get([server['id']])
1158
+ end
1159
+ return 0
1160
+ rescue RestClient::Exception => e
1161
+ print_rest_exception(e, options)
1162
+ exit 1
1163
+ end
1164
+ end
1165
+
1166
+ def remove(args)
1167
+ options = {}
1168
+ query_params = {}
1169
+ optparse = MtnCloud::Cli::OptionParser.new do |opts|
1170
+ opts.banner = subcommand_usage("[name]")
1171
+ # opts.on( '-S', '--skip-remove-infrastructure', "Skip removal of underlying cloud infrastructure. Same as --remove-resources off" ) do
1172
+ # query_params[:removeResources] = 'off'
1173
+ # end
1174
+ opts.on('--remove-resources [on|off]', ['on','off'], "Remove Infrastructure. Default is on if server is managed.") do |val|
1175
+ query_params[:removeResources] = val.nil? ? 'on' : val
1176
+ end
1177
+ opts.on('--preserve-volumes [on|off]', ['on','off'], "Preserve Volumes. Default is off.") do |val|
1178
+ query_params[:preserveVolumes] = val.nil? ? 'on' : val
1179
+ end
1180
+ opts.on('--remove-instances [on|off]', ['on','off'], "Remove Associated Instances. Default is off.") do |val|
1181
+ query_params[:removeInstances] = val.nil? ? 'on' : val
1182
+ end
1183
+ opts.on('--release-eips [on|off]', ['on','off'], "Release EIPs, default is on. Amazon only.") do |val|
1184
+ params[:releaseEIPs] = val.nil? ? 'on' : val
1185
+ end
1186
+ opts.on( '-f', '--force', "Force Delete" ) do
1187
+ query_params[:force] = 'on'
1188
+ end
1189
+ build_common_options(opts, options, [:auto_confirm, :json, :dry_run, :quiet, :remote])
1190
+ end
1191
+ optparse.parse!(args)
1192
+ if args.count < 1
1193
+ puts optparse
1194
+ exit 1
1195
+ end
1196
+ connect(options)
1197
+
1198
+ begin
1199
+ server = find_host_by_name_or_id(args[0])
1200
+ unless options[:yes] || ::MtnCloud::Cli::OptionTypes::confirm("Are you sure you would like to remove the server '#{server['name']}'?", options)
1201
+ exit 1
1202
+ end
1203
+ @servers_interface.setopts(options)
1204
+ if options[:dry_run]
1205
+ print_dry_run @servers_interface.dry.destroy(server['id'], query_params)
1206
+ return
1207
+ end
1208
+ json_response = @servers_interface.destroy(server['id'], query_params)
1209
+ if options[:json]
1210
+ print JSON.pretty_generate(json_response)
1211
+ print "\n"
1212
+ elsif !options[:quiet]
1213
+ if json_response['deleteApprovalRequired'] == true
1214
+ print_green_success "Delete Request created for Host #{server['name']}"
1215
+ else
1216
+ print_green_success "Host #{server['name']} is being removed..."
1217
+ end
1218
+ #list([])
1219
+ end
1220
+ rescue RestClient::Exception => e
1221
+ print_rest_exception(e, options)
1222
+ exit 1
1223
+ end
1224
+ end
1225
+
1226
+ def start(args)
1227
+ options = {}
1228
+ optparse = MtnCloud::Cli::OptionParser.new do |opts|
1229
+ opts.banner = subcommand_usage("[name]")
1230
+ build_common_options(opts, options, [:auto_confirm, :quiet, :json, :dry_run, :remote])
1231
+ opts.footer = "Start a host.\n" +
1232
+ "[name] is required. This is the name or id of a host. Supports 1-N [name] arguments."
1233
+ end
1234
+ optparse.parse!(args)
1235
+ if args.count < 1
1236
+ puts optparse
1237
+ exit 1
1238
+ end
1239
+ connect(options)
1240
+ begin
1241
+ host_ids = parse_id_list(args)
1242
+ hosts = []
1243
+ host_ids.each do |host_id|
1244
+ host = find_host_by_name_or_id(host_id)
1245
+ return 1 if host.nil?
1246
+ hosts << host
1247
+ end
1248
+ objects_label = "#{hosts.size == 1 ? 'host' : (hosts.size.to_s + ' hosts')} #{anded_list(hosts.collect {|it| it['name'] })}"
1249
+ unless options[:yes] || ::MtnCloud::Cli::OptionTypes::confirm("Are you sure you would like to start #{objects_label}?", options)
1250
+ return 9, "aborted command"
1251
+ end
1252
+ @servers_interface.setopts(options)
1253
+ if options[:dry_run]
1254
+ print_dry_run @servers_interface.dry.start(hosts.collect {|it| it['id'] })
1255
+ return
1256
+ end
1257
+ json_response = @servers_interface.start(hosts.collect {|it| it['id'] })
1258
+ if options[:json]
1259
+ print JSON.pretty_generate(json_response)
1260
+ print "\n"
1261
+ elsif !options[:quiet]
1262
+ print_green_success "Started #{objects_label}"
1263
+ end
1264
+ return 0
1265
+ rescue RestClient::Exception => e
1266
+ print_rest_exception(e, options)
1267
+ exit 1
1268
+ end
1269
+ end
1270
+
1271
+ def stop(args)
1272
+ options = {}
1273
+ optparse = MtnCloud::Cli::OptionParser.new do |opts|
1274
+ opts.banner = subcommand_usage("[name]")
1275
+ build_common_options(opts, options, [:auto_confirm, :quiet, :json, :dry_run, :remote])
1276
+ opts.footer = "Stop a host.\n" +
1277
+ "[name] is required. This is the name or id of a host. Supports 1-N [name] arguments."
1278
+ end
1279
+ optparse.parse!(args)
1280
+ if args.count < 1
1281
+ puts optparse
1282
+ exit 1
1283
+ end
1284
+ connect(options)
1285
+ begin
1286
+ host_ids = parse_id_list(args)
1287
+ hosts = []
1288
+ host_ids.each do |host_id|
1289
+ host = find_host_by_name_or_id(host_id)
1290
+ return 1 if host.nil?
1291
+ hosts << host
1292
+ end
1293
+ objects_label = "#{hosts.size == 1 ? 'host' : (hosts.size.to_s + ' hosts')} #{anded_list(hosts.collect {|it| it['name'] })}"
1294
+ unless options[:yes] || ::MtnCloud::Cli::OptionTypes::confirm("Are you sure you would like to stop #{objects_label}?", options)
1295
+ return 9, "aborted command"
1296
+ end
1297
+ @servers_interface.setopts(options)
1298
+ if options[:dry_run]
1299
+ print_dry_run @servers_interface.dry.stop(hosts.collect {|it| it['id'] })
1300
+ return
1301
+ end
1302
+ json_response = @servers_interface.stop(hosts.collect {|it| it['id'] })
1303
+ if options[:json]
1304
+ print JSON.pretty_generate(json_response)
1305
+ print "\n"
1306
+ elsif !options[:quiet]
1307
+ print_green_success "Stopped #{objects_label}"
1308
+ end
1309
+ return 0
1310
+ rescue RestClient::Exception => e
1311
+ print_rest_exception(e, options)
1312
+ exit 1
1313
+ end
1314
+ end
1315
+
1316
+ def restart(args)
1317
+ options = {}
1318
+ optparse = MtnCloud::Cli::OptionParser.new do |opts|
1319
+ opts.banner = subcommand_usage("[name]")
1320
+ build_common_options(opts, options, [:auto_confirm, :quiet, :json, :dry_run, :remote])
1321
+ opts.footer = "Restart a host.\n" +
1322
+ "[name] is required. This is the name or id of a host."
1323
+ end
1324
+ optparse.parse!(args)
1325
+ if args.count < 1
1326
+ puts optparse
1327
+ exit 1
1328
+ end
1329
+ connect(options)
1330
+ begin
1331
+ server = find_host_by_name_or_id(args[0])
1332
+ unless options[:yes] || ::MtnCloud::Cli::OptionTypes::confirm("Are you sure you would like to restart the server '#{server['name']}'?", options)
1333
+ exit 1
1334
+ end
1335
+ @servers_interface.setopts(options)
1336
+ if options[:dry_run]
1337
+ print_dry_run @servers_interface.dry.restart(server['id'])
1338
+ return
1339
+ end
1340
+ json_response = @servers_interface.restart(server['id'])
1341
+ if options[:json]
1342
+ print JSON.pretty_generate(json_response)
1343
+ print "\n"
1344
+ elsif !options[:quiet]
1345
+ print_green_success "Restarting #{server["name"]}"
1346
+ end
1347
+ rescue RestClient::Exception => e
1348
+ print_rest_exception(e, options)
1349
+ exit 1
1350
+ end
1351
+ end
1352
+
1353
+
1354
+ def resize(args)
1355
+ options = {}
1356
+ optparse = MtnCloud::Cli::OptionParser.new do |opts|
1357
+ opts.banner = subcommand_usage("[name]")
1358
+ opts.on("--storage-controller ARRAY", String, "Storage Controllers, JSON array of controller configs. Each entry accepts id, busNumber, typeId, typeName, removable, editable.") do |val|
1359
+ options[:options] ||= {}
1360
+ options[:options]['storageController'] = JSON.parse(val)
1361
+ end
1362
+ build_common_options(opts, options, [:options, :json, :dry_run, :quiet, :remote])
1363
+ end
1364
+ optparse.parse!(args)
1365
+ if args.count < 1
1366
+ puts optparse
1367
+ exit 1
1368
+ end
1369
+ connect(options)
1370
+ begin
1371
+ server = find_host_by_name_or_id(args[0])
1372
+
1373
+ group_id = server["siteId"] || erver['group']['id']
1374
+ cloud_id = server["zoneId"] || server["zone"]["id"]
1375
+ server_type_id = server['computeServerType']['id']
1376
+ plan_id = server['plan']['id']
1377
+ payload = {
1378
+ :server => {:id => server["id"]}
1379
+ }
1380
+
1381
+ # need to GET provision type for some settings...
1382
+ server_type = @server_types_interface.get(server_type_id)['serverType']
1383
+ provision_type = @provision_types_interface.get(server_type['provisionType']['id'])['provisionType']
1384
+
1385
+ # avoid 500 error
1386
+ # payload[:servicePlanOptions] = {}
1387
+ unless options[:no_prompt]
1388
+ puts "\nDue to limitations by most Guest Operating Systems, Disk sizes can only be expanded and not reduced.\nIf a smaller plan is selected, memory and CPU (if relevant) will be reduced but storage will not.\n\n"
1389
+ # unless hot_resize
1390
+ # puts "\nWARNING: Resize actions for this server will cause instances to be restarted.\n\n"
1391
+ # end
1392
+ end
1393
+
1394
+ # prompt for service plan
1395
+ service_plans_json = @servers_interface.service_plans({zoneId: cloud_id, serverTypeId: server_type_id, serverId: server['id']})
1396
+ service_plans = service_plans_json["plans"]
1397
+ service_plans_dropdown = service_plans.collect {|sp| {'name' => sp["name"], 'value' => sp["id"]} } # already sorted
1398
+ service_plans_dropdown.each do |plan|
1399
+ if plan['value'] && plan['value'].to_i == plan_id.to_i
1400
+ plan['name'] = "#{plan['name']} (current)"
1401
+ end
1402
+ end
1403
+ plan_prompt = MtnCloud::Cli::OptionTypes.prompt([{'fieldName' => 'plan', 'type' => 'select', 'fieldLabel' => 'Plan', 'selectOptions' => service_plans_dropdown, 'required' => true, 'defaultValue' => plan_id, 'description' => 'Choose the appropriately sized plan for this server'}],options[:options])
1404
+ service_plan = service_plans.find {|sp| sp["id"] == plan_prompt['plan'].to_i }
1405
+ payload[:server][:plan] = {id: service_plan["id"]}
1406
+
1407
+ # fetch volumes
1408
+ current_volumes = nil
1409
+ if server['volumes']
1410
+ current_volumes = server['volumes'].sort {|x,y| x['displayOrder'] <=> y['displayOrder'] }
1411
+ else
1412
+ volumes_response = @servers_interface.volumes(server['id'])
1413
+ current_volumes = volumes_response['volumes'].sort {|x,y| x['displayOrder'] <=> y['displayOrder'] }
1414
+ end
1415
+
1416
+ # prompt for volumes
1417
+ vol_options = options
1418
+ vol_options['siteId'] = group_id
1419
+ vol_options['zoneId'] = cloud_id
1420
+ vol_options['resourcePoolId'] = server['resourcePool']['id'] if server['resourcePool']
1421
+ volumes = prompt_resize_volumes(current_volumes, service_plan, provision_type, vol_options, server)
1422
+ if !volumes.empty?
1423
+ payload[:volumes] = volumes
1424
+ end
1425
+
1426
+ # plan customizations
1427
+ plan_opts = prompt_service_plan_options(service_plan, options, @api_client, {}, server)
1428
+ if plan_opts && !plan_opts.empty?
1429
+ payload['servicePlanOptions'] = plan_opts
1430
+ end
1431
+
1432
+ # todo: reconfigure networks
1433
+ # need to get provision_type_id for network info
1434
+ # prompt for network interfaces (if supported)
1435
+ # if server_type["provisionType"] && server_type["provisionType"]["id"] && server_type["provisionType"]["hasNetworks"]
1436
+ # begin
1437
+ # network_interfaces = prompt_network_interfaces(cloud['id'], server_type["provisionType"]["id"], null, options)
1438
+ # if !network_interfaces.empty?
1439
+ # payload[:networkInterfaces] = network_interfaces
1440
+ # end
1441
+ # rescue RestClient::Exception => e
1442
+ # print yellow,"Unable to load network options. Proceeding...",reset,"\n"
1443
+ # print_rest_exception(e, options) if MtnCloud::Logging.debug?
1444
+ # end
1445
+ # end
1446
+
1447
+ # only amazon supports this option
1448
+ # for now, always do this
1449
+ payload[:deleteOriginalVolumes] = true
1450
+ if options[:options] && options[:options]['storageController']
1451
+ payload[:storageController] = options[:options]['storageController']
1452
+ end
1453
+ @servers_interface.setopts(options)
1454
+ if options[:dry_run]
1455
+ print_dry_run @servers_interface.dry.resize(server['id'], payload)
1456
+ return
1457
+ end
1458
+ json_response = @servers_interface.resize(server['id'], payload)
1459
+ if options[:json]
1460
+ print JSON.pretty_generate(json_response)
1461
+ print "\n"
1462
+ else
1463
+ unless options[:quiet]
1464
+ puts "Host #{server['name']} resizing..."
1465
+ list([])
1466
+ end
1467
+ end
1468
+ rescue RestClient::Exception => e
1469
+ print_rest_exception(e, options)
1470
+ exit 1
1471
+ end
1472
+ end
1473
+
1474
+ # Prompt for instance version and layout based on instance type.
1475
+ def prompt_make_managed_instance_options(instance_type, group_id, cloud_id, options={})
1476
+ opt_bucket = options[:options] || {}
1477
+
1478
+ # available versions for this instance type
1479
+ version_source_params = {groupId: group_id, cloudId: cloud_id, instanceTypeId: instance_type['id']}
1480
+ available_versions = options_interface.options_for_source('instanceVersions', version_source_params)['data'] || []
1481
+ # filter out versions that have no layouts
1482
+ available_versions.reject! { |ver| ver['layouts'].nil? || ver['layouts'].empty? }
1483
+ available_versions.sort! { |x,y| x['name']<=> y['name'] }
1484
+
1485
+ # validate version option
1486
+ if opt_bucket['version']
1487
+ selected_version = opt_bucket['version']
1488
+ unless available_versions.find {|av| av['name'].to_s == selected_version.to_s }
1489
+ raise_command_error "Invalid version option '#{selected_version}' passed. Valid versions are: #{available_versions.collect {|av| av['name']}.join(', ')}"
1490
+ end
1491
+ end
1492
+ # prompt for version
1493
+ version_prompt = MtnCloud::Cli::OptionTypes.prompt([{
1494
+ 'fieldName' => 'version',
1495
+ 'type' => 'select',
1496
+ 'fieldLabel' => 'Version',
1497
+ 'selectOptions' => available_versions,
1498
+ 'required' => true,
1499
+ 'defaultValue' => available_versions.first ? available_versions.first['value'] : '',
1500
+ 'description' => 'Instance Type Version'
1501
+ }],
1502
+ opt_bucket
1503
+ )
1504
+ selected_version_value = version_prompt['version']
1505
+
1506
+ # filter layouts that support the selected version and are unmanaged or support convert to managed
1507
+ layouts_for_version = (instance_type['instanceTypeLayouts'] || []).select { |layout|
1508
+ (layout['instanceVersion'] == selected_version_value) &&
1509
+ (layout['supportsConvertToManaged'] == true || layout['serverType'] == 'unmanaged')
1510
+ }
1511
+
1512
+ if layouts_for_version.empty?
1513
+ print_red_alert "No available layouts that support converting to managed for the given instance type"
1514
+ return nil
1515
+ end
1516
+
1517
+ layout_options = layouts_for_version.collect { |layout|
1518
+ {'name' => layout['name'], 'value' => layout['id']}
1519
+ }
1520
+
1521
+ # validate layout input option
1522
+ if opt_bucket['layout']
1523
+ default_layout = opt_bucket['layout']
1524
+ unless layout_options.find {|lo| lo['name'].to_s == default_layout.to_s }
1525
+ raise_command_error "Invalid layout option '#{default_layout}' passed. Valid layouts are: #{layout_options.collect {|lo| lo['name']}.join(', ')}"
1526
+ end
1527
+ end
1528
+
1529
+ layout_prompt = MtnCloud::Cli::OptionTypes.prompt(
1530
+ [{
1531
+ 'fieldName' => 'layout',
1532
+ 'type' => 'select',
1533
+ 'fieldLabel' => 'Layout',
1534
+ 'selectOptions' => layout_options,
1535
+ 'required' => true,
1536
+ 'defaultValue' => layout_options.first ? layout_options.first['value'] : '',
1537
+ 'description' => 'Choose a layout (template) for this instance.'
1538
+ }],
1539
+ opt_bucket
1540
+ )
1541
+ chosen_layout_id = layout_prompt['layout']
1542
+
1543
+ {'instanceVersion' => selected_version_value, 'instanceLayoutId' => chosen_layout_id}
1544
+ end
1545
+ private :prompt_make_managed_instance_options
1546
+
1547
+ def make_managed(args)
1548
+ options = {}
1549
+ optparse = MtnCloud::Cli::OptionParser.new do |opts|
1550
+ opts.banner = subcommand_usage("[name]")
1551
+ build_option_type_options(opts, options, make_managed_option_types(false))
1552
+ opts.on('--install-agent [on|off]', String, "Install Agent? Pass false to manually install agent. Default is true.") do |val|
1553
+ options['installAgent'] = val.to_s == 'on' || val.to_s == 'true' || val.to_s == ''
1554
+ end
1555
+ opts.on('-g', '--group GROUP', String, "Group to assign to new instance.") do |val|
1556
+ options[:group] = val
1557
+ end
1558
+ opts.on('--instance-type ID', String, "Instance Type ID or Name for the new instance. Optional - only specify if you want to set a specific instance type for conversion.") do |val|
1559
+ options['instanceType'] = val
1560
+ end
1561
+ build_common_options(opts, options, [:options, :json, :dry_run, :quiet, :remote])
1562
+ end
1563
+ optparse.parse!(args)
1564
+ if args.count < 1
1565
+ puts optparse
1566
+ exit 1
1567
+ end
1568
+ connect(options)
1569
+ begin
1570
+ host = find_host_by_name_or_id(args[0])
1571
+ if host['agentInstalled']
1572
+ print_red_alert "Agent already installed on host '#{host['name']}'"
1573
+ return false
1574
+ end
1575
+ payload = {
1576
+ 'server' => {}
1577
+ }
1578
+ passed_options = (options[:options] || {}).reject {|k,v| k.is_a?(Symbol) }
1579
+ payload.deep_merge!(passed_options)
1580
+ params = MtnCloud::Cli::OptionTypes.prompt(make_managed_option_types, options[:options], @api_client, options[:params])
1581
+ server_os = params.delete('serverOs')
1582
+ if server_os
1583
+ payload['server']['serverOs'] = {id: server_os}
1584
+ end
1585
+ account_id = params.delete('account') # not yet implemented
1586
+ if account_id
1587
+ payload['server']['account'] = {id: account}
1588
+ end
1589
+ if options[:group]
1590
+ group = options[:group] ? find_group_by_name_or_id_for_provisioning(options[:group]) : nil
1591
+ return 1 if group.nil?
1592
+ params['provisionSiteId'] = group['id']
1593
+ end
1594
+ payload['server'].merge!(params)
1595
+ ['installAgent'].each do |k|
1596
+ if options[k] != nil
1597
+ payload[k] = options[k]
1598
+ end
1599
+ end
1600
+ # If instance type is passed, prompt for version and layout
1601
+ unless options['instanceType'].nil?
1602
+ instance_type = find_instance_type_by_name_or_id(options['instanceType'])
1603
+ if instance_type.nil?
1604
+ print_red_alert "Instance Type not found by name or id #{options['instanceType']}"
1605
+ return 1
1606
+ end
1607
+ if instance_type['active'] != true
1608
+ print_red_alert "Instance Type '#{options['instanceType']}' (#{instance_type['name']}) is not active"
1609
+ return 1
1610
+ end
1611
+ resp=prompt_make_managed_instance_options(instance_type, params['provisionSiteId'] || host['siteId'],
1612
+ (host['zoneId'] || host['zone']['id']), options)
1613
+ if resp.nil?
1614
+ print_red_alert "Failed to select instance version and layout for given instance type '#{instance_type['name']}'"
1615
+ return 1
1616
+ end
1617
+ payload['instanceTypeId'] = instance_type['id']
1618
+ payload['layout'] = resp['instanceLayoutId']
1619
+ payload['version'] = resp['instanceVersion']
1620
+ end
1621
+
1622
+ @servers_interface.setopts(options)
1623
+ if options[:dry_run]
1624
+ print_dry_run(@servers_interface.dry.make_managed(host['id'], payload), options)
1625
+ return 0
1626
+ end
1627
+ json_response = @servers_interface.make_managed(host['id'], payload)
1628
+ if options[:json]
1629
+ print JSON.pretty_generate(json_response)
1630
+ print "\n"
1631
+ elsif !options[:quiet]
1632
+ print_green_success "Host #{host['name']} is being converted to managed."
1633
+ puts "Public Key:\n#{json_response['publicKey']}\n(copy to your authorized_keys file)"
1634
+ end
1635
+ return 0
1636
+ rescue RestClient::Exception => e
1637
+ print_rest_exception(e, options)
1638
+ exit 1
1639
+ end
1640
+ end
1641
+
1642
+ def upgrade_agent(args)
1643
+ options = {}
1644
+ optparse = MtnCloud::Cli::OptionParser.new do |opts|
1645
+ opts.banner = subcommand_usage("[host]")
1646
+ opts.on('--refresh [SECONDS]', String, "Refresh until execution is complete. Default interval is #{default_refresh_interval} seconds.") do |val|
1647
+ options[:refresh_interval] = val.to_s.empty? ? default_refresh_interval : val.to_f
1648
+ end
1649
+ opts.on(nil, '--no-refresh', "Do not refresh" ) do
1650
+ options[:no_refresh] = true
1651
+ end
1652
+ build_standard_update_options(opts, options, [:auto_confirm])
1653
+ opts.footer = <<-EOT
1654
+ Upgrade agent for a host.
1655
+ [host] is required. This is the name or id of a host.
1656
+ EOT
1657
+ end
1658
+ optparse.parse!(args)
1659
+ verify_args!(args:args, optparse:optparse, count:1)
1660
+ connect(options)
1661
+
1662
+ host = find_host_by_name_or_id(args[0])
1663
+ return 1 if host.nil?
1664
+
1665
+ payload = {}
1666
+ if options[:payload]
1667
+ payload = options[:payload]
1668
+ payload.deep_merge!({'server' => parse_passed_options(options)})
1669
+ else
1670
+ payload.deep_merge!({'server' => parse_passed_options(options)})
1671
+ end
1672
+
1673
+ @servers_interface.setopts(options)
1674
+ if options[:dry_run]
1675
+ print_dry_run @servers_interface.dry.upgrade(host['id'], payload)
1676
+ return
1677
+ end
1678
+ json_response = @servers_interface.upgrade(host['id'], payload)
1679
+ render_response(json_response, options) do
1680
+ #get([host['id']])
1681
+ if json_response['success']
1682
+ if json_response['msg'] == nil
1683
+ print_green_success "Upgrading agent on host #{host['name']}..."
1684
+ else
1685
+ print_green_success json_response['msg']
1686
+ end
1687
+ process_id = json_response['processId'] || (json_response['processIds'] ? json_response['processIds'][0] : nil)
1688
+ if process_id
1689
+ unless options[:no_refresh]
1690
+ process = wait_for_process_execution(process_id, options)
1691
+ end
1692
+ else
1693
+ # puts "No process returned"
1694
+ end
1695
+ else
1696
+ # never reached because unsuccessful requests raise an exception
1697
+ print_red_alert "API Request failed: #{json_response['msg']}"
1698
+ end
1699
+ end
1700
+ end
1701
+
1702
+ def run_workflow(args)
1703
+ params = {}
1704
+ options = {}
1705
+ optparse = MtnCloud::Cli::OptionParser.new do |opts|
1706
+ opts.banner = subcommand_usage("[host] [workflow] [options]")
1707
+ opts.on("--phase PHASE", String, "Task Phase to run for Provisioning workflows. The default is provision.") do |val|
1708
+ options[:phase] = val
1709
+ end
1710
+ build_common_options(opts, options, [:options, :payload, :json, :dry_run, :quiet, :remote])
1711
+ opts.footer = <<-EOT
1712
+ Run workflow for a host.
1713
+ [host] is required. This is the name or id of a host
1714
+ [workflow] is required. This is the name or id of a workflow
1715
+ By default the provision phase is executed.
1716
+ Use the --phase option to execute a different phase.
1717
+ The available phases are start, stop, preProvision, provision, postProvision, preDeploy, deploy, reconfigure, teardown, startup and shutdown.
1718
+ EOT
1719
+ end
1720
+ optparse.parse!(args)
1721
+ if args.count != 2
1722
+ puts_error "#{MtnCloud::Terminal.angry_prompt}wrong number of arguments. Expected 2 and received #{args.count} #{args.inspect}\n#{optparse}"
1723
+ return 1
1724
+ end
1725
+ connect(options)
1726
+
1727
+ host = find_host_by_name_or_id(args[0])
1728
+ return 1 if host.nil?
1729
+ workflow = find_workflow_by_name_or_id(args[1])
1730
+ return 1 if workflow.nil?
1731
+
1732
+ # support -O options as arbitrary params
1733
+ old_option_options = (options[:options] || {}).reject {|k,v| k.is_a?(Symbol) }
1734
+ params.deep_merge!(old_option_options) unless old_option_options.empty?
1735
+
1736
+ # the payload format is unusual
1737
+ # payload example: {"taskSet": {taskSetId": {"taskSetTaskId": {"customOptions": {"dbVersion":"5.6"}}}}}
1738
+ payload = nil
1739
+ if options[:payload]
1740
+ payload = options[:payload]
1741
+ else
1742
+ payload = {}
1743
+ # i guess you must pass an option if there are editable options
1744
+ # any option, heh
1745
+ task_types = @tasks_interface.list_types()
1746
+ editable_options = []
1747
+ workflow['taskSetTasks'].sort{|a,b| a['taskOrder'] <=> b['taskOrder']}.each do |task_set_task|
1748
+ task_type_id = task_set_task['task']['taskType']['id']
1749
+ task_type = task_types['taskTypes'].find{ |current_task_type| current_task_type['id'] == task_type_id}
1750
+ task_opts = task_type['optionTypes'].select { |otype| otype['editable']}
1751
+ if !task_opts.nil? && !task_opts.empty?
1752
+ editable_options += task_opts.collect do |task_opt|
1753
+ new_task_opt = task_opt.clone
1754
+ new_task_opt['fieldContext'] = "#{task_set_task['id']}.#{new_task_opt['fieldContext']}"
1755
+ end
1756
+ end
1757
+ end
1758
+ # if params.empty? && !editable_options.empty?
1759
+ # puts optparse
1760
+ # option_lines = editable_options.collect {|it| "\t-O #{it['fieldContext'] ? (it['fieldContext'] + '.') : ''}#{it['fieldName']}=\"value\"" }.join("\n")
1761
+ # puts "\nAvailable Options:\n#{option_lines}\n\n"
1762
+ # return 1
1763
+ # end
1764
+
1765
+ end
1766
+
1767
+ if !params.empty?
1768
+ payload['taskSet'] ||= {}
1769
+ payload['taskSet']["#{workflow['id']}"] ||= {}
1770
+ payload['taskSet']["#{workflow['id']}"].deep_merge!(params)
1771
+ end
1772
+ if options[:phase]
1773
+ payload['taskPhase'] = options[:phase]
1774
+ end
1775
+ begin
1776
+ @servers_interface.setopts(options)
1777
+ if options[:dry_run]
1778
+ print_dry_run @servers_interface.dry.workflow(host['id'],workflow['id'], payload)
1779
+ return
1780
+ end
1781
+ json_response = @servers_interface.workflow(host['id'],workflow['id'], payload)
1782
+ if options[:json]
1783
+ print as_json(json_response, options), "\n"
1784
+ return
1785
+ elsif options[:quiet]
1786
+ return 0
1787
+ else
1788
+ print_green_success "Running workflow #{workflow['name']} on host #{host['name']} ..."
1789
+ end
1790
+ return 0
1791
+ rescue RestClient::Exception => e
1792
+ print_rest_exception(e, options)
1793
+ exit 1
1794
+ end
1795
+ end
1796
+
1797
+ def execution_request(args)
1798
+ options = {}
1799
+ params = {}
1800
+ script_content = nil
1801
+ do_refresh = true
1802
+ optparse = MtnCloud::Cli::OptionParser.new do|opts|
1803
+ opts.banner = subcommand_usage("[id] [options]")
1804
+ opts.on('--script SCRIPT', "Script to be executed" ) do |val|
1805
+ script_content = val
1806
+ end
1807
+ opts.on('--file FILE', "File containing the script. This can be used instead of --script" ) do |filename|
1808
+ full_filename = File.expand_path(filename)
1809
+ if File.exist?(full_filename)
1810
+ script_content = File.read(full_filename)
1811
+ else
1812
+ print_red_alert "File not found: #{full_filename}"
1813
+ exit 1
1814
+ end
1815
+ end
1816
+ opts.on(nil, '--no-refresh', "Do not refresh until finished" ) do
1817
+ do_refresh = false
1818
+ end
1819
+ #build_option_type_options(opts, options, add_user_source_option_types())
1820
+ build_common_options(opts, options, [:options, :payload, :json, :dry_run, :quiet, :remote])
1821
+ opts.footer = "Execute an arbitrary command or script on a host." + "\n" +
1822
+ "[id] is required. This is the id a host." + "\n" +
1823
+ "[script] is required. This is the script that is to be executed."
1824
+ end
1825
+ optparse.parse!(args)
1826
+ connect(options)
1827
+ if args.count != 1
1828
+ print_error MtnCloud::Terminal.angry_prompt
1829
+ puts_error "wrong number of arguments, expected 1 and got (#{args.count}) #{args.inspect}\n#{optparse}"
1830
+ return 1
1831
+ end
1832
+
1833
+
1834
+ begin
1835
+ host = find_host_by_name_or_id(args[0])
1836
+ return 1 if host.nil?
1837
+ params['serverId'] = host['id']
1838
+ # construct payload
1839
+ payload = {}
1840
+ if options[:payload]
1841
+ payload = options[:payload]
1842
+ else
1843
+ payload.deep_merge!(options[:options].reject {|k,v| k.is_a?(Symbol) }) if options[:options]
1844
+ # prompt for Script
1845
+ if script_content.nil?
1846
+ v_prompt = MtnCloud::Cli::OptionTypes.prompt([{'fieldName' => 'script', 'type' => 'code-editor', 'fieldLabel' => 'Script', 'required' => true, 'description' => 'The script content'}], options[:options])
1847
+ script_content = v_prompt['script']
1848
+ end
1849
+ payload['script'] = script_content
1850
+ end
1851
+ # dry run?
1852
+ @servers_interface.setopts(options)
1853
+ if options[:dry_run]
1854
+ print_dry_run @execution_request_interface.dry.create(params, payload)
1855
+ return 0
1856
+ end
1857
+ # do it
1858
+ json_response = @execution_request_interface.create(params, payload)
1859
+ # print and return result
1860
+ if options[:quiet]
1861
+ return 0
1862
+ elsif options[:json]
1863
+ puts as_json(json_response, options)
1864
+ return 0
1865
+ end
1866
+ execution_request = json_response['executionRequest']
1867
+ print_green_success "Executing request #{execution_request['uniqueId']}"
1868
+ if do_refresh
1869
+ MtnCloud::Cli::ExecutionRequestCommand.new.handle(["get", execution_request['uniqueId'], "--refresh"]+ (options[:remote] ? ["-r",options[:remote]] : []))
1870
+ else
1871
+ MtnCloud::Cli::ExecutionRequestCommand.new.handle(["get", execution_request['uniqueId']]+ (options[:remote] ? ["-r",options[:remote]] : []))
1872
+ end
1873
+ return 0
1874
+ rescue RestClient::Exception => e
1875
+ print_rest_exception(e, options)
1876
+ exit 1
1877
+ end
1878
+ end
1879
+
1880
+ def server_types_for_cloud(cloud_id, options)
1881
+ connect(options)
1882
+ zone = find_zone_by_name_or_id(nil, cloud_id)
1883
+ cloud_type = cloud_type_for_id(zone['zoneTypeId'])
1884
+ cloud_server_types = cloud_type['serverTypes'].select{|b| b['creatable'] == true}
1885
+ cloud_server_types = cloud_server_types.sort { |x,y| x['displayOrder'] <=> y['displayOrder'] }
1886
+ if options[:json]
1887
+ print JSON.pretty_generate(cloud_server_types)
1888
+ print "\n"
1889
+ else
1890
+ print_h1 "Server Types - Cloud: #{zone['name']}", [], options
1891
+ if cloud_server_types.nil? || cloud_server_types.empty?
1892
+ print cyan,"No server types found for the selected cloud",reset,"\n"
1893
+ else
1894
+ cloud_server_types.each do |server_type|
1895
+ print cyan, "[#{server_type['code']}]".ljust(20), " - ", "#{server_type['name']}", "\n"
1896
+ end
1897
+ end
1898
+ print reset,"\n"
1899
+ end
1900
+ end
1901
+
1902
+ def list_types(args)
1903
+ options = {}
1904
+ optparse = MtnCloud::Cli::OptionParser.new do |opts|
1905
+ opts.banner = subcommand_usage()
1906
+ opts.on( '-c', '--cloud CLOUD', "Cloud Name or ID" ) do |val|
1907
+ options[:cloud] = val
1908
+ end
1909
+ build_common_options(opts, options, [:list, :query, :json, :yaml, :csv, :fields, :dry_run, :remote])
1910
+ opts.footer = "List host types."
1911
+ end
1912
+ optparse.parse!(args)
1913
+ connect(options)
1914
+ begin
1915
+ params = {}
1916
+ params.merge!(parse_list_options(options))
1917
+ if options[:cloud]
1918
+ #return server_types_for_cloud(options[:cloud], options)
1919
+ zone = find_zone_by_name_or_id(nil, options[:cloud])
1920
+ params["zoneTypeId"] = zone['zoneTypeId']
1921
+ params["creatable"] = true
1922
+ end
1923
+ @server_types_interface.setopts(options)
1924
+ if options[:dry_run]
1925
+ print_dry_run @server_types_interface.dry.list(params)
1926
+ return
1927
+ end
1928
+ json_response = @server_types_interface.list(params)
1929
+
1930
+ render_result = render_with_format(json_response, options, 'serverTypes')
1931
+ return 0 if render_result
1932
+
1933
+ server_types = json_response['serverTypes']
1934
+
1935
+ title = "Server Types"
1936
+ subtitles = []
1937
+ subtitles += parse_list_subtitles(options)
1938
+ if options[:cloud]
1939
+ subtitles << "Cloud: #{options[:cloud]}"
1940
+ end
1941
+ print_h1 title, subtitles
1942
+ if server_types.empty?
1943
+ print cyan,"No server types found.",reset,"\n"
1944
+ else
1945
+ rows = server_types.collect do |server_type|
1946
+ {
1947
+ id: server_type['id'],
1948
+ code: server_type['code'],
1949
+ name: server_type['name']
1950
+ }
1951
+ end
1952
+ columns = [:id, :name, :code]
1953
+ print cyan
1954
+ print as_pretty_table(rows, columns, options)
1955
+ print reset
1956
+ print_results_pagination(json_response)
1957
+ end
1958
+ print reset,"\n"
1959
+ return 0
1960
+
1961
+ rescue RestClient::Exception => e
1962
+ print_rest_exception(e, options)
1963
+ exit 1
1964
+ end
1965
+ end
1966
+
1967
+ def view(args)
1968
+ options = {}
1969
+ optparse = MtnCloud::Cli::OptionParser.new do |opts|
1970
+ opts.banner = subcommand_usage("[host]")
1971
+ opts.on('-w','--wiki', "Open the wiki tab for this host") do
1972
+ options[:link_tab] = "wiki"
1973
+ end
1974
+ opts.on('--tab VALUE', String, "Open a specific tab") do |val|
1975
+ options[:link_tab] = val.to_s
1976
+ end
1977
+ build_common_options(opts, options, [:dry_run, :remote])
1978
+ opts.footer = "View a host in a web browser" + "\n" +
1979
+ "[host] is required. This is the name or id of a host. Supports 1-N [host] arguments."
1980
+ end
1981
+ optparse.parse!(args)
1982
+ if args.count != 1
1983
+ raise_command_error "wrong number of arguments, expected 1 and got (#{args.count}) #{args.join(' ')}\n#{optparse}"
1984
+ end
1985
+ connect(options)
1986
+ id_list = parse_id_list(args)
1987
+ return run_command_for_each_arg(id_list) do |arg|
1988
+ _view(arg, options)
1989
+ end
1990
+ end
1991
+
1992
+ def _view(arg, options={})
1993
+ begin
1994
+ host = find_host_by_name_or_id(arg)
1995
+ return 1 if host.nil?
1996
+
1997
+ link = "#{@appliance_url}/login/oauth-redirect?access_token=#{@access_token}\\&redirectUri=/infrastructure/servers/#{host['id']}"
1998
+ if options[:link_tab]
1999
+ link << "#!#{options[:link_tab]}"
2000
+ end
2001
+
2002
+ if options[:dry_run]
2003
+ puts MtnCloud::Util.open_url_command(link)
2004
+ return 0
2005
+ end
2006
+ return MtnCloud::Util.open_url(link)
2007
+ rescue RestClient::Exception => e
2008
+ print_rest_exception(e, options)
2009
+ exit 1
2010
+ end
2011
+ end
2012
+
2013
+ def wiki(args)
2014
+ options = {}
2015
+ params = {}
2016
+ open_wiki_link = false
2017
+ optparse = MtnCloud::Cli::OptionParser.new do |opts|
2018
+ opts.banner = subcommand_usage("[host]")
2019
+ opts.on('--view', '--view', "View wiki page in web browser.") do
2020
+ open_wiki_link = true
2021
+ end
2022
+ build_common_options(opts, options, [:json, :dry_run, :remote])
2023
+ opts.footer = "View wiki page details for a host." + "\n" +
2024
+ "[host] is required. This is the name or id of a host."
2025
+ end
2026
+ optparse.parse!(args)
2027
+ if args.count != 1
2028
+ puts_error "#{MtnCloud::Terminal.angry_prompt}wrong number of arguments. Expected 1 and received #{args.count} #{args.inspect}\n#{optparse}"
2029
+ return 1
2030
+ end
2031
+ connect(options)
2032
+
2033
+ begin
2034
+ host = find_host_by_name_or_id(args[0])
2035
+ return 1 if host.nil?
2036
+
2037
+
2038
+ @servers_interface.setopts(options)
2039
+ if options[:dry_run]
2040
+ print_dry_run @servers_interface.dry.wiki(host["id"], params)
2041
+ return
2042
+ end
2043
+ json_response = @servers_interface.wiki(host["id"], params)
2044
+ page = json_response['page']
2045
+
2046
+ render_result = render_with_format(json_response, options, 'page')
2047
+ return 0 if render_result
2048
+
2049
+ if page
2050
+
2051
+ # my_terminal.exec("wiki get #{page['id']}")
2052
+
2053
+ print_h1 "Host Wiki Page: #{host['name']}"
2054
+ # print_h1 "Wiki Page Details"
2055
+ print cyan
2056
+
2057
+ print_description_list({
2058
+ "Page ID" => 'id',
2059
+ "Name" => 'name',
2060
+ #"Category" => 'category',
2061
+ #"Ref Type" => 'refType',
2062
+ #"Ref ID" => 'refId',
2063
+ #"Owner" => lambda {|it| it['account'] ? it['account']['name'] : '' },
2064
+ "Created" => lambda {|it| format_local_dt(it['dateCreated']) },
2065
+ "Created By" => lambda {|it| it['createdBy'] ? it['createdBy']['username'] : '' },
2066
+ "Updated" => lambda {|it| format_local_dt(it['lastUpdated']) },
2067
+ "Updated By" => lambda {|it| it['updatedBy'] ? it['updatedBy']['username'] : '' }
2068
+ }, page)
2069
+ print reset,"\n"
2070
+
2071
+ print_h2 "Page Content"
2072
+ print cyan, page['content'], reset, "\n"
2073
+
2074
+ else
2075
+ print "\n"
2076
+ print cyan, "No wiki page found.", reset, "\n"
2077
+ end
2078
+ print reset,"\n"
2079
+
2080
+ if open_wiki_link
2081
+ return view_wiki([args[0]])
2082
+ end
2083
+
2084
+ return 0
2085
+ rescue RestClient::Exception => e
2086
+ print_rest_exception(e, options)
2087
+ exit 1
2088
+ end
2089
+ end
2090
+
2091
+ def view_wiki(args)
2092
+ params = {}
2093
+ options = {}
2094
+ optparse = MtnCloud::Cli::OptionParser.new do |opts|
2095
+ opts.banner = subcommand_usage("[id]")
2096
+ build_common_options(opts, options, [:dry_run, :remote])
2097
+ opts.footer = "View host wiki page in a web browser" + "\n" +
2098
+ "[host] is required. This is the name or id of a host."
2099
+ end
2100
+ optparse.parse!(args)
2101
+ if args.count != 1
2102
+ raise_command_error "wrong number of arguments, expected 1 and got (#{args.count}) #{args.join(' ')}\n#{optparse}"
2103
+ end
2104
+ connect(options)
2105
+ begin
2106
+ host = find_host_by_name_or_id(args[0])
2107
+ return 1 if host.nil?
2108
+
2109
+ link = "#{@appliance_url}/login/oauth-redirect?access_token=#{@access_token}\\&redirectUri=/infrastructure/servers/#{host['id']}#!wiki"
2110
+
2111
+ open_command = nil
2112
+ if RbConfig::CONFIG['host_os'] =~ /mswin|mingw|cygwin/
2113
+ open_command = "start #{link}"
2114
+ elsif RbConfig::CONFIG['host_os'] =~ /darwin/
2115
+ open_command = "open #{link}"
2116
+ elsif RbConfig::CONFIG['host_os'] =~ /linux|bsd/
2117
+ open_command = "xdg-open #{link}"
2118
+ end
2119
+
2120
+ if options[:dry_run]
2121
+ puts "system: #{open_command}"
2122
+ return 0
2123
+ end
2124
+
2125
+ system(open_command)
2126
+
2127
+ return 0
2128
+ rescue RestClient::Exception => e
2129
+ print_rest_exception(e, options)
2130
+ exit 1
2131
+ end
2132
+ end
2133
+
2134
+ def update_wiki(args)
2135
+ options = {}
2136
+ params = {}
2137
+ optparse = MtnCloud::Cli::OptionParser.new do |opts|
2138
+ opts.banner = subcommand_usage("[host] [options]")
2139
+ build_option_type_options(opts, options, update_wiki_page_option_types)
2140
+ opts.on('--file FILE', "File containing the wiki content. This can be used instead of --content") do |filename|
2141
+ full_filename = File.expand_path(filename)
2142
+ if File.exist?(full_filename)
2143
+ params['content'] = File.read(full_filename)
2144
+ else
2145
+ print_red_alert "File not found: #{full_filename}"
2146
+ return 1
2147
+ end
2148
+ # use the filename as the name by default.
2149
+ if !params['name']
2150
+ params['name'] = File.basename(full_filename)
2151
+ end
2152
+ end
2153
+ opts.on(nil, '--clear', "Clear current page content") do |val|
2154
+ params['content'] = ""
2155
+ end
2156
+ build_common_options(opts, options, [:options, :payload, :json, :dry_run, :remote])
2157
+ end
2158
+ optparse.parse!(args)
2159
+ if args.count != 1
2160
+ puts_error "#{MtnCloud::Terminal.angry_prompt}wrong number of arguments. Expected 1 and received #{args.count} #{args.inspect}\n#{optparse}"
2161
+ return 1
2162
+ end
2163
+ connect(options)
2164
+
2165
+ begin
2166
+ host = find_host_by_name_or_id(args[0])
2167
+ return 1 if host.nil?
2168
+ # construct payload
2169
+ passed_options = options[:options] ? options[:options].reject {|k,v| k.is_a?(Symbol) } : {}
2170
+ payload = nil
2171
+ if options[:payload]
2172
+ payload = options[:payload]
2173
+ payload.deep_merge!({'page' => passed_options}) unless passed_options.empty?
2174
+ else
2175
+ payload = {
2176
+ 'page' => {
2177
+ }
2178
+ }
2179
+ # allow arbitrary -O options
2180
+ payload.deep_merge!({'page' => passed_options}) unless passed_options.empty?
2181
+ # prompt for options
2182
+ #params = MtnCloud::Cli::OptionTypes.prompt(update_wiki_page_option_types, options[:options], @api_client, options[:params])
2183
+ #params = passed_options
2184
+ params.deep_merge!(passed_options)
2185
+
2186
+ if params.empty?
2187
+ raise_command_error "Specify at least one option to update.\n#{optparse}"
2188
+ end
2189
+
2190
+ payload.deep_merge!({'page' => params}) unless params.empty?
2191
+ end
2192
+ @servers_interface.setopts(options)
2193
+ if options[:dry_run]
2194
+ print_dry_run @servers_interface.dry.update_wiki(host["id"], payload)
2195
+ return
2196
+ end
2197
+ json_response = @servers_interface.update_wiki(host["id"], payload)
2198
+
2199
+ if options[:json]
2200
+ puts as_json(json_response, options)
2201
+ else
2202
+ print_green_success "Updated wiki page for host #{host['name']}"
2203
+ wiki([host['id']])
2204
+ end
2205
+ return 0
2206
+ rescue RestClient::Exception => e
2207
+ print_rest_exception(e, options)
2208
+ exit 1
2209
+ end
2210
+ end
2211
+
2212
+ def snapshots(args)
2213
+ options = {}
2214
+ optparse = MtnCloud::Cli::OptionParser.new do |opts|
2215
+ opts.banner = subcommand_usage("[host] [snapshot]")
2216
+ # no pagination yet
2217
+ # build_standard_list_options(opts, options)
2218
+ build_standard_list_options(opts, options, [:details])
2219
+ opts.footer = <<-EOT
2220
+ List snapshots for a host.
2221
+ [host] is required. This is the name or id of a host.
2222
+ [snapshot] is optional. This is the name or id of a snapshot.
2223
+ EOT
2224
+ end
2225
+ optparse.parse!(args)
2226
+ verify_args!(args:args, optparse:optparse, min:1)
2227
+ connect(options)
2228
+ begin
2229
+ server = find_host_by_name_or_id(args[0])
2230
+ return 1 if server.nil?
2231
+ params = {}
2232
+ @servers_interface.setopts(options)
2233
+ if options[:dry_run]
2234
+ print_dry_run @servers_interface.dry.snapshots(server['id'], params)
2235
+ return
2236
+ end
2237
+ json_response = @servers_interface.snapshots(server['id'], params)
2238
+ snapshots = json_response['snapshots']
2239
+ # [snapshots] is done with post api filtering by id or name or externalId
2240
+ if args[1]
2241
+ if args[1] =~ /\A\d{1,}\Z/
2242
+ snapshots = snapshots.select {|it| it['id'].to_s == args[1] }
2243
+ else
2244
+ # match beginning of name of externalId
2245
+ snapshots = snapshots.select {|it| it['name'].to_s.index(args[1]) == 0 || it['externalId'].to_s.index(args[1]) == 0 }
2246
+ end
2247
+ json_response['snapshots'] = snapshots # update response for -j filtering too
2248
+ end
2249
+ render_response(json_response, options, 'snapshots') do
2250
+ print_h1 "Snapshots: #{server['name']}", [], options
2251
+ if snapshots.empty?
2252
+ if args[1]
2253
+ print cyan,"No snapshots found for '#{args[1]}'",reset,"\n"
2254
+ elsif
2255
+ print cyan,"No snapshots found",reset,"\n"
2256
+ end
2257
+ print reset, "\n"
2258
+ else
2259
+ if options[:details]
2260
+ # this actually makes a request for each one here so don't go crazy...
2261
+ if snapshots.size > 3
2262
+ print cyan, "Showing first 3 snapshots. Use the ID to get more details.", reset, "\n"
2263
+ snapshots = snapshots.first(3)
2264
+ end
2265
+ snapshots.each do |snapshot|
2266
+ MtnCloud::Cli::Snapshots.new.handle(["get", snapshot['id']] + (options[:remote] ? ["-r",options[:remote]] : []))
2267
+ end
2268
+ else
2269
+ # Snapshots List
2270
+ snapshot_column_definitions = {
2271
+ "ID" => lambda {|it| it['id'] },
2272
+ "Name" => lambda {|it| it['name'] },
2273
+ "Description" => lambda {|it| it['description'] },
2274
+ # "Type" => lambda {|it| it['snapshotType'] },
2275
+ "Date Created" => lambda {|it| format_local_dt(it['snapshotCreated']) },
2276
+ "Status" => lambda {|it| format_snapshot_status(it) }
2277
+ }
2278
+ print cyan
2279
+ print as_pretty_table(snapshots, snapshot_column_definitions.upcase_keys!, options)
2280
+ print_results_pagination({size: snapshots.size, total: snapshots.size})
2281
+ print reset, "\n"
2282
+ end
2283
+ end
2284
+ end
2285
+ return 0
2286
+ rescue RestClient::Exception => e
2287
+ print_rest_exception(e, options)
2288
+ exit 1
2289
+ end
2290
+ end
2291
+
2292
+ def software(args)
2293
+ options = {}
2294
+ optparse = MtnCloud::Cli::OptionParser.new do |opts|
2295
+ opts.banner = subcommand_usage("[host]")
2296
+ build_standard_list_options(opts, options)
2297
+ opts.footer = <<-EOT
2298
+ List installed software for a host.
2299
+ [host] is required. This is the name or id of a host.
2300
+ EOT
2301
+ end
2302
+ optparse.parse!(args)
2303
+ verify_args!(args:args, optparse:optparse, count:1)
2304
+ connect(options)
2305
+ begin
2306
+ server = find_host_by_name_or_id(args[0])
2307
+ return 1 if server.nil?
2308
+ params = {}
2309
+ params.merge!(parse_list_options(options))
2310
+ @servers_interface.setopts(options)
2311
+ if options[:dry_run]
2312
+ print_dry_run @servers_interface.dry.software(server['id'], params)
2313
+ return
2314
+ end
2315
+ json_response = @servers_interface.software(server['id'], params)
2316
+ software = json_response['software']
2317
+ render_response(json_response, options, 'software') do
2318
+ print_h1 "Software: #{server['name']}", [], options
2319
+ if software.empty?
2320
+ print cyan,"No software found",reset,"\n"
2321
+ else
2322
+ software_column_definitions = {
2323
+ # "ID" => lambda {|it| it['id'] },
2324
+ "Name" => lambda {|it| it['name'] },
2325
+ "Version" => lambda {|it| it['packageVersion'] },
2326
+ "Publisher" => lambda {|it| it['packagePublisher'] },
2327
+ # "Release" => lambda {|it| it['packageRelease'] },
2328
+ # "Type" => lambda {|it| it['packageType'] },
2329
+ # "Architecture" => lambda {|it| it['architecture'] },
2330
+ # "Install Date" => lambda {|it| format_local_dt(it['installDate']) },
2331
+ }
2332
+ print cyan
2333
+ print as_pretty_table(software, software_column_definitions.upcase_keys!, options)
2334
+ print_results_pagination({size: software.size, total: software.size})
2335
+ end
2336
+ print reset, "\n"
2337
+ end
2338
+ return 0
2339
+ rescue RestClient::Exception => e
2340
+ print_rest_exception(e, options)
2341
+ exit 1
2342
+ end
2343
+ end
2344
+
2345
+ def software_sync(args)
2346
+ options = {}
2347
+ optparse = MtnCloud::Cli::OptionParser.new do |opts|
2348
+ opts.banner = subcommand_usage("[host]")
2349
+ build_standard_update_options(opts, options)
2350
+ opts.footer = <<-EOT
2351
+ Sync installed software for a host.
2352
+ [host] is required. This is the name or id of a host.
2353
+ EOT
2354
+ end
2355
+ optparse.parse!(args)
2356
+ verify_args!(args:args, optparse:optparse, count:1)
2357
+ connect(options)
2358
+ begin
2359
+ server = find_host_by_name_or_id(args[0])
2360
+ return 1 if server.nil?
2361
+ payload = {}
2362
+ if options[:payload]
2363
+ payload = options[:payload]
2364
+ payload.deep_merge!(parse_passed_options(options))
2365
+ else
2366
+ payload.deep_merge!(parse_passed_options(options))
2367
+ end
2368
+ params = {}
2369
+ params.merge!(parse_query_options(options))
2370
+ @servers_interface.setopts(options)
2371
+ if options[:dry_run]
2372
+ print_dry_run @servers_interface.dry.software_sync(server['id'], payload, params)
2373
+ return
2374
+ end
2375
+ json_response = @servers_interface.software_sync(server['id'], payload, params)
2376
+ render_response(json_response, options) do
2377
+ print_green_success "Syncing software for host #{server['name']}"
2378
+ #get([server['id']])
2379
+ end
2380
+ return 0
2381
+ rescue RestClient::Exception => e
2382
+ print_rest_exception(e, options)
2383
+ exit 1
2384
+ end
2385
+ end
2386
+
2387
+ def update_network_label(args)
2388
+ options = {}
2389
+ params = {}
2390
+ optparse = MtnCloud::Cli::OptionParser.new do |opts|
2391
+ opts.banner = subcommand_usage("[server] [options]")
2392
+ opts.on('--network NETWORK', "Network Interface ID" ) do |val|
2393
+ options[:network] = val
2394
+ end
2395
+ opts.on('--label LABEL', "label") do |val|
2396
+ options[:label] = val
2397
+ end
2398
+ opts.footer = "Change the label of a Network Interface.\n" +
2399
+ "Editing an Interface will not apply changes to the physical hardware. The purpose is for a manual override or data correction (mostly for self managed or baremetal servers where cloud sync is not available)\n" +
2400
+ "[name or id] is required. The name or the id of the server.\n" +
2401
+ "[network] ID of the Network Interface. (optional).\n" +
2402
+ "[label] New Label name for the Network Interface (optional)"
2403
+ build_common_options(opts, options, [:options, :payload, :json, :dry_run, :remote])
2404
+ end
2405
+ optparse.parse!(args)
2406
+ if args.count != 1
2407
+ puts_error "#{MtnCloud::Terminal.angry_prompt}wrong number of arguments. Expected 1 and received #{args.count} #{args.inspect}\n#{optparse}"
2408
+ return 1
2409
+ end
2410
+ connect(options)
2411
+
2412
+ begin
2413
+ host = find_host_by_name_or_id(args[0])
2414
+ return 1 if host.nil?
2415
+
2416
+ network_id = options[:network]
2417
+ if network_id != nil && network_id.to_i == 0
2418
+ print_red_alert "network must be an ID/integer above 0, not a name/string value."
2419
+ network_id = nil
2420
+ end
2421
+
2422
+
2423
+ if !network_id
2424
+ available_networks = get_available_networks(host)
2425
+ network_prompt = MtnCloud::Cli::OptionTypes.prompt([{'fieldName' => 'network', 'fieldLabel' => 'Network', 'type' => 'select', 'selectOptions' => available_networks, 'required' => true, 'defaultValue' => available_networks[0], 'description' => "The networks available for relabeling"}], options[:options])
2426
+ network_id = network_prompt['network']
2427
+ end
2428
+
2429
+ label = options[:label]
2430
+ while label.nil? do
2431
+ label_prompt = MtnCloud::Cli::OptionTypes.prompt([{'fieldName' => 'label', 'fieldLabel' => 'Label', 'type' => 'text', 'required' => true}], options[:options])
2432
+ label = label_prompt['label']
2433
+ end
2434
+ payload = { "name" => label }
2435
+ if options[:dry_run]
2436
+ print_dry_run @servers_interface.dry.update_network_label(network_id, host["id"], payload)
2437
+ return
2438
+ end
2439
+ json_response = @servers_interface.update_network_label(network_id, host["id"], payload)
2440
+ if options[:json]
2441
+ puts as_json(json_response, options)
2442
+ else
2443
+ print_green_success "Updated label for host #{host['name']} network #{network_id} to #{label}"
2444
+ end
2445
+ return 0
2446
+ rescue RestClient::Exception => e
2447
+ print_rest_exception(e, options)
2448
+ exit 1
2449
+ end
2450
+ end
2451
+
2452
+
2453
+ def maintenance(args)
2454
+ options = {}
2455
+ optparse = MtnCloud::Cli::OptionParser.new do |opts|
2456
+ opts.banner = subcommand_usage("[host]")
2457
+ opts.on('--ignoreDaemonsets [on|off]', String, "Ignore Daemonsets") do |val|
2458
+ options[:ignoreDaemonsets] = (val.to_s.empty? || val.to_s == 'on' || val.to_s == 'true')
2459
+ end
2460
+ opts.on('--force [on|off]', String, "Force") do |val|
2461
+ options[:force] = (val.to_s.empty? || val.to_s == 'on' || val.to_s == 'true')
2462
+ end
2463
+ opts.on('--deleteEmptyDir [on|off]', String, "Delete Empty Directories") do |val|
2464
+ options[:deleteEmptyDir] = (val.to_s.empty? || val.to_s == 'on' || val.to_s == 'true')
2465
+ end
2466
+ opts.on('--deleteLocalData [on|off]', String, "Delete Local Data") do |val|
2467
+ options[:deleteLocalData] = (val.to_s == 'on' || val.to_s == 'true')
2468
+ end
2469
+ build_standard_update_options(opts, options, [:auto_confirm])
2470
+ opts.footer = <<-EOT
2471
+ Enable maintenance mode for a host.
2472
+ [host] is required. This is the name or id of a host.
2473
+ EOT
2474
+ end
2475
+ optparse.parse!(args)
2476
+ verify_args!(args:args, optparse:optparse, count:1)
2477
+ connect(options)
2478
+
2479
+ server = find_host_by_name_or_id(args[0])
2480
+ return 1 if server.nil?
2481
+
2482
+ # Just let the API return this error instead
2483
+
2484
+ # # load server type to determine if maintenance mode is supported
2485
+ # server_type_id = server['computeServerType']['id']
2486
+ # server_type = @server_types_interface.get(server_type_id)['serverType']
2487
+ # if !server_type['hasMaintenanceMode']
2488
+ # raise_command_error "Server type does not support maintenance mode"
2489
+ # end
2490
+
2491
+ payload = {}
2492
+
2493
+ if server.dig('config', 'kubernetesRole')
2494
+ payload[:server] = {}
2495
+ payload[:server][:ignoreDaemonsets] = options.fetch(:ignoreDaemonsets) do
2496
+ prompt = MtnCloud::Cli::OptionTypes.prompt([{'fieldName' => 'ignoreDaemonsets', 'fieldLabel' => 'Ignore Daemonsets', 'type' => 'checkbox', 'defaultValue' => true, 'required' => false}], options, @api_client, {})
2497
+ prompt['ignoreDaemonsets'] == 'on'
2498
+ end
2499
+ payload[:server][:force] = options.fetch(:force) do
2500
+ prompt = MtnCloud::Cli::OptionTypes.prompt([{'fieldName' => 'force', 'fieldLabel' => 'Force', 'type' => 'checkbox', 'defaultValue' => true, 'required' => false}], options, @api_client, {})
2501
+ prompt['force'] == 'on'
2502
+ end
2503
+ payload[:server][:deleteEmptyDir] = options.fetch(:deleteEmptyDir) do
2504
+ prompt = MtnCloud::Cli::OptionTypes.prompt([{'fieldName' => 'deleteEmptyDir', 'fieldLabel' => 'Delete Empty Directories', 'type' => 'checkbox', 'defaultValue' => true, 'required' => false}], options, @api_client, {})
2505
+ prompt['deleteEmptyDir'] == 'on'
2506
+ end
2507
+ payload[:server][:deleteLocalData] = options.fetch(:deleteLocalData) do
2508
+ prompt = MtnCloud::Cli::OptionTypes.prompt([{'fieldName' => 'deleteLocalData', 'fieldLabel' => 'Delete Local Data', 'type' => 'checkbox', 'defaultValue' => false, 'required' => false}], options, @api_client, {})
2509
+ prompt['deleteLocalData'] == 'on'
2510
+ end
2511
+ end
2512
+
2513
+ if options[:payload]
2514
+ payload = options[:payload]
2515
+ payload.deep_merge!(parse_passed_options(options))
2516
+ else
2517
+ payload.deep_merge!(parse_passed_options(options))
2518
+ end
2519
+ params = {}
2520
+ params.merge!(parse_query_options(options))
2521
+
2522
+ confirm!("Are you sure you would like to enable maintenance mode on host '#{server['name']}'?", options)
2523
+
2524
+ @servers_interface.setopts(options)
2525
+ if options[:dry_run]
2526
+ print_dry_run @servers_interface.dry.maintenance(server['id'], payload, params)
2527
+ return
2528
+ end
2529
+ json_response = @servers_interface.maintenance(server['id'], payload, params)
2530
+ render_response(json_response, options) do
2531
+ print_green_success "Maintenance mode enabled for host #{server['name']}"
2532
+ #get([server['id']])
2533
+ end
2534
+ return 0, nil
2535
+ end
2536
+
2537
+ def leave_maintenance(args)
2538
+ options = {}
2539
+ optparse = MtnCloud::Cli::OptionParser.new do |opts|
2540
+ opts.banner = subcommand_usage("[host]")
2541
+ build_standard_update_options(opts, options, [:auto_confirm])
2542
+ opts.footer = <<-EOT
2543
+ Disable maintenance mode for a host.
2544
+ [host] is required. This is the name or id of a host.
2545
+ EOT
2546
+ end
2547
+ optparse.parse!(args)
2548
+ verify_args!(args:args, optparse:optparse, count:1)
2549
+ connect(options)
2550
+
2551
+ server = find_host_by_name_or_id(args[0])
2552
+ return 1 if server.nil?
2553
+
2554
+ # Just let the API return this error instead
2555
+
2556
+ # # load server type to determine if maintenance mode is supported
2557
+ # server_type_id = server['computeServerType']['id']
2558
+ # server_type = @server_types_interface.get(server_type_id)['serverType']
2559
+ # if !server_type['hasMaintenanceMode']
2560
+ # raise_command_error "Server type does not support maintenance mode"
2561
+ # end
2562
+
2563
+ payload = {}
2564
+ if options[:payload]
2565
+ payload = options[:payload]
2566
+ payload.deep_merge!(parse_passed_options(options))
2567
+ else
2568
+ payload.deep_merge!(parse_passed_options(options))
2569
+ end
2570
+ params = {}
2571
+ params.merge!(parse_query_options(options))
2572
+
2573
+ confirm!("Are you sure you would like to leave maintenance mode on host '#{server['name']}'?", options)
2574
+
2575
+ @servers_interface.setopts(options)
2576
+ if options[:dry_run]
2577
+ print_dry_run @servers_interface.dry.leave_maintenance(server['id'], payload, params)
2578
+ return
2579
+ end
2580
+ json_response = @servers_interface.leave_maintenance(server['id'], payload, params)
2581
+ render_response(json_response, options) do
2582
+ print_green_success "Left Maintenance Mode for host #{server['name']}"
2583
+ #get([server['id']])
2584
+ end
2585
+ return 0, nil
2586
+ end
2587
+
2588
+ def placement(args)
2589
+ options = {}
2590
+ optparse = MtnCloud::Cli::OptionParser.new do |opts|
2591
+ opts.banner = subcommand_usage("[host]")
2592
+ build_standard_update_options(opts, options, [:auto_confirm])
2593
+ opts.footer = <<-EOT
2594
+ Update placement for a host.
2595
+ [host] is required. This is the name or id of a host.
2596
+ EOT
2597
+ end
2598
+ optparse.parse!(args)
2599
+ verify_args!(args:args, optparse:optparse, count:1)
2600
+ connect(options)
2601
+
2602
+ server = find_host_by_name_or_id(args[0])
2603
+ return 1 if server.nil?
2604
+ payload = {}
2605
+ if options[:payload]
2606
+ payload = options[:payload]
2607
+ payload.deep_merge!({'server' => parse_passed_options(options)})
2608
+ else
2609
+ payload.deep_merge!({'server' => parse_passed_options(options)})
2610
+ # prompt
2611
+ # Host (preferredParentServer.id)
2612
+ if payload['server']['host']
2613
+ options[:options] = payload['server'].delete('host')
2614
+ end
2615
+ default_host = (server['preferredParentServer'] ? server['preferredParentServer']['id'] : (server['parentServer'] ? server['parentServer']['id'] : nil))
2616
+ host = MtnCloud::Cli::OptionTypes.prompt([{'fieldName' => 'host', 'type' => 'select', 'fieldLabel' => 'Host', 'optionSource' => 'parentServers', 'required' => false, 'description' => 'Choose the preferred parent host for this virtual machine to be placed on.', 'defaultValue' => default_host}],options[:options],@api_client,{'serverId' => server['id']})['host']
2617
+ if !host.to_s.empty?
2618
+ payload['server']['preferredParentServer'] = {'id' => host}
2619
+ end
2620
+
2621
+
2622
+ # Placement Strategy (placementStrategy)
2623
+ placement_strategy = MtnCloud::Cli::OptionTypes.prompt([{'fieldName' => 'placementStrategy', 'type' => 'select', 'fieldLabel' => 'Placement Strategy', 'optionSource' => 'placementStrategies', 'required' => false, 'description' => 'Choose the placement strategy for this virtual machine.', 'defaultValue' => server['placementStrategy']}],options[:options],@api_client,{'serverId' => server['id']})['placementStrategy']
2624
+ if !placement_strategy.to_s.empty?
2625
+ payload['server']['placementStrategy'] = placement_strategy
2626
+ end
2627
+ end
2628
+ params = {}
2629
+ params.merge!(parse_query_options(options))
2630
+
2631
+ confirm!("Are you sure you would like to update placement for host '#{server['name']}'?", options)
2632
+
2633
+ @servers_interface.setopts(options)
2634
+ if options[:dry_run]
2635
+ print_dry_run @servers_interface.dry.placement(server['id'], payload, params)
2636
+ return
2637
+ end
2638
+ json_response = @servers_interface.placement(server['id'], payload, params)
2639
+ render_response(json_response, options) do
2640
+ print_green_success "Maintenance mode enabled for host #{server['name']}"
2641
+ #get([server['id']])
2642
+ end
2643
+ return 0, nil
2644
+ end
2645
+
2646
+ def snapshot(args)
2647
+ options = {}
2648
+ optparse = MtnCloud::Cli::OptionParser.new do |opts|
2649
+ opts.banner = subcommand_usage("[host]")
2650
+ opts.on( '--name VALUE', String, "Snapshot Name. Default is \"{name}.{timestamp}\"" ) do |val|
2651
+ options[:options]['name'] = val
2652
+ end
2653
+ opts.on( '--description VALUE', String, "Snapshot Description." ) do |val|
2654
+ options[:options]['description'] = val
2655
+ end
2656
+ opts.on('--memory-snapshot [on|off]', String, "Memory Snapshot? Whether to include the memory state in the snapshot.") do |val|
2657
+ options[:options]['memorySnapshot'] = val.to_s == '' || val.to_s == 'on' || val.to_s == 'true'
2658
+ end
2659
+ opts.on('--for-export [on|off]', String, "For Export? Indicates the snapshot is intended for export to storage.") do |val|
2660
+ options[:options]['forExport'] = val.to_s == '' || val.to_s == 'on' || val.to_s == 'true'
2661
+ end
2662
+ opts.on('--refresh [SECONDS]', String, "Refresh until execution is complete. Default interval is #{default_refresh_interval} seconds.") do |val|
2663
+ options[:refresh_interval] = val.to_s.empty? ? default_refresh_interval : val.to_f
2664
+ end
2665
+ opts.on(nil, '--no-refresh', "Do not refresh" ) do
2666
+ options[:no_refresh] = true
2667
+ end
2668
+ build_standard_add_options(opts, options, [:auto_confirm])
2669
+ opts.footer = <<-EOT
2670
+ Create a snapshot for a host.
2671
+ [host] is required. This is the name or id of a host
2672
+ EOT
2673
+ end
2674
+ optparse.parse!(args)
2675
+ verify_args!(args:args, optparse:optparse, count:1)
2676
+ connect(options)
2677
+ server = find_host_by_name_or_id(args[0])
2678
+ payload = {}
2679
+ if options[:payload]
2680
+ payload = options[:payload]
2681
+ payload.deep_merge!({'snapshot' => parse_passed_options(options)})
2682
+ else
2683
+ payload.deep_merge!({'snapshot' => parse_passed_options(options)})
2684
+ # prompt for name and description
2685
+ name = prompt_value({'fieldName' => 'name', 'type' => 'text', 'fieldLabel' => 'Snapshot Name', 'description' => "Snapshot Name. Default is \"{name}.{timestamp}\""}, options)
2686
+ payload['snapshot']['name'] = name if !name.to_s.empty?
2687
+ description = prompt_value({'fieldName' => 'description', 'type' => 'text', 'fieldLabel' => 'Description', 'description' => "Snapshot Description."}, options)
2688
+ payload['snapshot']['description'] = description if !description.to_s.empty?
2689
+ # need to GET provision type for some settings...
2690
+ provision_type = nil
2691
+ begin
2692
+ provision_type_id = server['computeServerType']['provisionTypeId'] rescue nil
2693
+ if provision_type_id
2694
+ provision_type = @provision_types_interface.get(provision_type_id)['provisionType']
2695
+ end
2696
+ rescue => ex
2697
+ MtnCloud::Logging::DarkPrinter.puts "Failed to load provision type!" if MtnCloud::Logging.debug?
2698
+ end
2699
+ if provision_type && provision_type['hasMemorySnapshots']
2700
+ # prompt for memorySnapshot
2701
+ memory_snapshot = prompt_value({'fieldName' => 'memorySnapshot', 'type' => 'checkbox', 'fieldLabel' => 'Memory Snapshot?', 'description' => "Snapshot Description."}, options)
2702
+ payload['snapshot']['memorySnapshot'] = memory_snapshot if !memory_snapshot.to_s.empty?
2703
+ end
2704
+ # convert "on" and "off" to true/false
2705
+ payload.booleanize!
2706
+ end
2707
+ unless options[:yes] || ::MtnCloud::Cli::OptionTypes::confirm("Are you sure you would like to snapshot the host '#{server['name']}'?", options)
2708
+ exit 1
2709
+ end
2710
+ @servers_interface.setopts(options)
2711
+ if options[:dry_run]
2712
+ print_dry_run @servers_interface.dry.snapshot(server['id'], payload)
2713
+ return
2714
+ end
2715
+ json_response = @servers_interface.snapshot(server['id'], payload)
2716
+ render_response(json_response, options) do
2717
+ print_green_success "Snapshot initiated."
2718
+ process_id = json_response['processIds'][0] rescue nil
2719
+ if process_id
2720
+ unless options[:no_refresh]
2721
+ process = wait_for_process_execution(process_id, options)
2722
+ snapshot_id = process['resultId']
2723
+ if snapshot_id
2724
+ MtnCloud::Cli::Snapshots.new.handle(["get", snapshot_id] + (options[:remote] ? ["-r",options[:remote]] : []))
2725
+ end
2726
+ end
2727
+ else
2728
+ # puts "No process returned"
2729
+ end
2730
+ end
2731
+ return 0, nil
2732
+ end
2733
+
2734
+ def create_linked_clone(args)
2735
+ options = {}
2736
+ server = nil
2737
+ snapshot_id = nil
2738
+
2739
+ optparse = MtnCloud::Cli::OptionParser.new do |opts|
2740
+ opts.banner = subcommand_usage("[host]")
2741
+ opts.on("--snapshot ID", String, "Snapshot ID") do |val|
2742
+ snapshot_id = val
2743
+ end
2744
+ build_common_options(opts, options, [:auto_confirm, :json, :dry_run, :remote])
2745
+ opts.footer = "Create a linked clone using the selected snapshot of a Host." + "\n" +
2746
+ "[snapshotId] is required. This is the id of the snapshot which the clone will refer to."
2747
+ end
2748
+
2749
+ optparse.parse!(args)
2750
+ if args.count != 1
2751
+ raise_command_error "wrong number of arguments, expected 1 and got (#{args.count}) #{args.join(' ')}\n#{optparse}"
2752
+ end
2753
+ connect(options)
2754
+ begin
2755
+ server = find_host_by_name_or_id(args[0])
2756
+ options[:options]['serverId'] = server['id']
2757
+ begin
2758
+ snapshot_options = @servers_interface.snapshots(server['id'], {})['snapshots'].collect {|it| {'name' => "#{it['name']} (#{it['id']})", 'value' => it['id']} }
2759
+ snapshot_prompt = MtnCloud::Cli::OptionTypes.prompt([{'fieldName' => 'snapshotId', 'type' => 'select', 'fieldLabel' => 'Snapshot', 'selectOptions' => snapshot_options, 'required' => true, 'description' => 'Select Snapshot.'}], {}, @api_client, options[:options])
2760
+
2761
+ if !snapshot_prompt['snapshotId'].to_s.empty?
2762
+ snapshot_id = snapshot_prompt['snapshotId']
2763
+ end
2764
+ rescue RestClient::Exception => e
2765
+ puts "Failed to load host snapshots"
2766
+ end
2767
+
2768
+ @servers_interface.setopts(options)
2769
+
2770
+ payload = {}
2771
+ if options[:dry_run]
2772
+ print_dry_run @servers_interface.dry.create_linked_clone(server['id'], snapshot_id, payload)
2773
+ return
2774
+ end
2775
+
2776
+ json_response = @servers_interface.create_linked_clone(server['id'], snapshot_id, payload)
2777
+ if options[:json]
2778
+ puts as_json(json_response, options)
2779
+ else
2780
+ print_green_success "Linked Clone creation initiated."
2781
+ end
2782
+ return 0
2783
+
2784
+ rescue RestClient::Exception => e
2785
+ print_rest_exception(e, options)
2786
+ exit 1
2787
+ end
2788
+ end
2789
+
2790
+ ## Server Devices
2791
+
2792
+ def list_devices(args)
2793
+ MtnCloud::Cli::ServerDevicesCommand.new.list(args)
2794
+ end
2795
+
2796
+ def assign_device(args)
2797
+ MtnCloud::Cli::ServerDevicesCommand.new.assign(args)
2798
+ end
2799
+
2800
+ def attach_device(args)
2801
+ MtnCloud::Cli::ServerDevicesCommand.new.attach(args)
2802
+ end
2803
+
2804
+ def detach_device(args)
2805
+ MtnCloud::Cli::ServerDevicesCommand.new.detach(args)
2806
+ end
2807
+
2808
+ private
2809
+
2810
+ def find_host_by_id(id)
2811
+ begin
2812
+ json_response = @servers_interface.get(id.to_i)
2813
+ return json_response['server']
2814
+ rescue RestClient::Exception => e
2815
+ if e.response && e.response.code == 404
2816
+ print_red_alert "Host not found by id #{id}"
2817
+ exit 1
2818
+ else
2819
+ raise e
2820
+ end
2821
+ end
2822
+ end
2823
+
2824
+ def find_host_by_name(name, include_tenants=false)
2825
+ params = {name: name.to_s}
2826
+ params['includeTenants'] = true if include_tenants
2827
+ results = @servers_interface.list(params)
2828
+ if results['servers'].empty?
2829
+ print_red_alert "Server not found by name #{name}"
2830
+ exit 1
2831
+ elsif results['servers'].size > 1
2832
+ print_red_alert "Multiple Servers exist with the name '#{name}'"
2833
+ puts_error as_pretty_table(results['servers'], [:id, :name], {color:red})
2834
+ print_red_alert "Try using ID instead"
2835
+ exit 1
2836
+ end
2837
+ return results['servers'][0]
2838
+ end
2839
+
2840
+ def find_host_by_name_or_id(val, include_tenants=false)
2841
+ if val.to_s =~ /\A\d{1,}\Z/
2842
+ return find_host_by_id(val)
2843
+ else
2844
+ return find_host_by_name(val, include_tenants)
2845
+ end
2846
+ end
2847
+
2848
+ def find_zone_by_name_or_id(group_id, val)
2849
+ zone = nil
2850
+ if val.to_s =~ /\A\d{1,}\Z/
2851
+ json_results = @clouds_interface.get(val.to_i)
2852
+ zone = json_results['zone']
2853
+ if zone.nil?
2854
+ print_red_alert "Cloud not found by id #{val}"
2855
+ exit 1
2856
+ end
2857
+ else
2858
+ json_results = @clouds_interface.list({groupId: group_id, name: val})
2859
+ zone = json_results['zones'] ? json_results['zones'][0] : nil
2860
+ if zone.nil?
2861
+ print_red_alert "Cloud not found by name #{val}"
2862
+ exit 1
2863
+ end
2864
+ end
2865
+ return zone
2866
+ end
2867
+
2868
+ def find_server_type(zone, name)
2869
+ server_type = zone['serverTypes'].select do |sv_type|
2870
+ (sv_type['name'].downcase == name.downcase || sv_type['code'].downcase == name.downcase) && sv_type['creatable'] == true
2871
+ end
2872
+ if server_type.nil?
2873
+ print_red_alert "Server Type Not Selectable"
2874
+ end
2875
+ return server_type
2876
+ end
2877
+
2878
+ def cloud_type_for_id(id)
2879
+ cloud_types = @clouds_interface.cloud_types({max:1000})['zoneTypes']
2880
+ cloud_type = cloud_types.find { |z| z['id'].to_i == id.to_i}
2881
+ if cloud_type.nil?
2882
+ print_red_alert "Cloud Type not found by id #{id}"
2883
+ exit 1
2884
+ end
2885
+ return cloud_type
2886
+ end
2887
+
2888
+ def find_cluster_by_name_or_id(val)
2889
+ if val.to_s =~ /\A\d{1,}\Z/
2890
+ find_cluster_by_id(val)
2891
+ else
2892
+ find_cluster_by_name(val)
2893
+ end
2894
+ end
2895
+
2896
+ def find_cluster_by_id(id)
2897
+ json_results = @clusters_interface.get(id.to_i)
2898
+ if json_results['cluster'].empty?
2899
+ print_red_alert "Cluster not found by id #{id}"
2900
+ exit 1
2901
+ end
2902
+ json_results['cluster']
2903
+ end
2904
+
2905
+ def find_cluster_by_name(name)
2906
+ json_results = @clusters_interface.list({name: name})
2907
+ if json_results['clusters'].empty? || json_results['clusters'].count > 1
2908
+ print_red_alert "Cluster not found by name #{name}"
2909
+ exit 1
2910
+ end
2911
+ json_results['clusters'][0]
2912
+ end
2913
+
2914
+ def format_server_power_state(server, return_color=cyan)
2915
+ out = ""
2916
+ if server['powerState'] == 'on'
2917
+ out << "#{green}ON#{return_color}"
2918
+ elsif server['powerState'] == 'off'
2919
+ out << "#{red}OFF#{return_color}"
2920
+ else
2921
+ out << "#{white}#{server['powerState'].to_s.upcase}#{return_color}"
2922
+ end
2923
+ out
2924
+ end
2925
+
2926
+ def format_server_status(server, return_color=cyan)
2927
+ out = ""
2928
+ status_string = server['status'].to_s.downcase
2929
+ if status_string == 'provisioned'
2930
+ out = "#{cyan}#{status_string.upcase}#{return_color}"
2931
+ elsif status_string == 'provisioning'
2932
+ out = "#{cyan}#{status_string.upcase}#{cyan}"
2933
+ elsif status_string == 'failed' or status_string == 'error'
2934
+ out = "#{red}#{status_string.upcase}#{return_color}"
2935
+ else
2936
+ out = "#{yellow}#{status_string.upcase}#{return_color}"
2937
+ end
2938
+ out
2939
+ end
2940
+
2941
+ def format_server_status_friendly(server, return_color=cyan)
2942
+ out = ""
2943
+ status_string = server['status'].to_s.downcase
2944
+ if status_string == 'provisioned'
2945
+ # out = format_server_power_state(server, return_color)
2946
+ # make it looks like format_instance_status
2947
+ if server['powerState'] == 'on'
2948
+ out << "#{green}RUNNING#{return_color}"
2949
+ elsif server['powerState'] == 'off'
2950
+ out << "#{red}STOPPED#{return_color}"
2951
+ else
2952
+ out << "#{white}#{server['powerState'].to_s.upcase}#{return_color}"
2953
+ end
2954
+ else
2955
+ out = format_server_status(server, return_color)
2956
+ end
2957
+ out
2958
+ end
2959
+
2960
+ def get_available_networks(host)
2961
+ results = @options_interface.options_for_source('availableNetworksForHost',{serverId: host['id'].to_i})
2962
+ available_networks = results['data'].collect {|it|
2963
+ {"id" => it["value"], "name" => it["name"], "value" => it["value"]}
2964
+ }
2965
+ return available_networks
2966
+ end
2967
+
2968
+
2969
+ def make_managed_option_types(connected=true)
2970
+ [
2971
+ #{'fieldName' => 'account', 'fieldLabel' => 'Account', 'type' => 'select', 'optionSource' => 'accounts', 'required' => true},
2972
+ {'fieldName' => 'sshUsername', 'fieldLabel' => 'SSH Username', 'type' => 'text'},
2973
+ {'fieldName' => 'sshPassword', 'fieldLabel' => 'SSH Password', 'type' => 'password', 'required' => false},
2974
+ {'fieldName' => 'serverOs', 'fieldLabel' => 'OS Type', 'type' => 'select', 'optionSource' => 'osTypes', 'required' => false},
2975
+ ]
2976
+ end
2977
+
2978
+ def update_wiki_page_option_types
2979
+ [
2980
+ {'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.'},
2981
+ #{'fieldName' => 'category', 'fieldLabel' => 'Category', 'type' => 'text', 'required' => false, 'displayOrder' => 2},
2982
+ {'fieldName' => 'content', 'fieldLabel' => 'Content', 'type' => 'textarea', 'required' => false, 'displayOrder' => 3, 'description' => 'The content (markdown) of the wiki page.'}
2983
+ ]
2984
+ end
2985
+
2986
+ end