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,1203 @@
1
+ require 'mtncloud/cli/cli_command'
2
+
3
+ class MtnCloud::Cli::Systems
4
+ include MtnCloud::Cli::CliCommand
5
+ include MtnCloud::Cli::RestCommand
6
+
7
+ set_command_name :systems
8
+ set_command_description "View and manage systems."
9
+ register_subcommands :list, :get, :add, :update, :remove, :'add-uninitialized', {:'initialize' => 'exec_initialize'}, {:'validate' => 'exec_validate'},
10
+ {:'list-types' => :list_types},
11
+ {:'list-layouts' => :list_layouts},
12
+ {:'list-available-server-updates' => :list_available_server_updates},
13
+ {:'apply-server-update' => :apply_server_update},
14
+ {:'list-available-storage-updates' => :list_available_storage_updates},
15
+ {:'apply-storage-update' => :apply_storage_update},
16
+ {:'list-available-network-updates' => :list_available_network_updates},
17
+ {:'apply-network-update' => :apply_network_update},
18
+ {:'list-available-network-server-updates' => :list_available_network_server_updates},
19
+ {:'apply-network-server-update' => :apply_network_server_update},
20
+ {:'list-available-cluster-updates' => :list_available_cluster_updates},
21
+ {:'apply-cluster-update' => :apply_cluster_update}
22
+
23
+ protected
24
+
25
+ # Systems API uses lowercase keys in payloads.
26
+ def system_object_key
27
+ 'system'
28
+ end
29
+
30
+ def system_list_key
31
+ 'systems'
32
+ end
33
+
34
+ # Required so find_by_name_or_id(:servers, id) resolves the lowercase 'server' key
35
+ def server_object_key
36
+ 'server'
37
+ end
38
+
39
+ def system_list_column_definitions(options)
40
+ {
41
+ "ID" => 'id',
42
+ "Name" => 'name',
43
+ "Type" => lambda {|it| it['type'] ? it['type']['name'] : '' },
44
+ "Layout" => lambda {|it| it['layout'] ? it['layout']['name'] : '' },
45
+ "Status" => 'status',
46
+ "Enabled" => lambda {|it| format_boolean(it['enabled']) },
47
+ "Date Created" => lambda {|it| format_local_dt(it['dateCreated']) }
48
+ }
49
+ end
50
+
51
+ def system_column_definitions(options)
52
+ {
53
+ "ID" => 'id',
54
+ "Name" => 'name',
55
+ "Description" => 'description',
56
+ "Status" => 'status',
57
+ "Status Message" => 'statusMessage',
58
+ "Enabled" => lambda {|it| format_boolean(it['enabled']) },
59
+ "External ID" => 'externalId',
60
+ "Date Created" => lambda {|it| format_local_dt(it['dateCreated']) },
61
+ "Last Updated" => lambda {|it| format_local_dt(it['lastUpdated']) }
62
+ }
63
+ end
64
+
65
+ def render_response_for_get(json_response, options)
66
+ render_response(json_response, options, rest_object_key) do
67
+ record = json_response[rest_object_key] || json_response
68
+ print_h1 rest_label, [], options
69
+ print cyan
70
+ print_description_list(rest_column_definitions(options), record, options)
71
+ print reset,"\n"
72
+ components = record['components'] || []
73
+ if components.any?
74
+ print_h2 "Components (#{components.size})", options
75
+ component_rows = components.collect do |component|
76
+ {
77
+ id: component['id'],
78
+ name: component['name'],
79
+ type_code: component.dig('type', 'code'),
80
+ type_name: component.dig('type', 'name'),
81
+ external_id: component['externalId']
82
+ }
83
+ end
84
+ print as_pretty_table(component_rows, [:id, :name, :type_code, :type_name, :external_id], options)
85
+ end
86
+ end
87
+ end
88
+
89
+ def add(args)
90
+ options = {}
91
+ params = {}
92
+ components = []
93
+ optparse = MtnCloud::Cli::OptionParser.new do |opts|
94
+ opts.banner = subcommand_usage("[name]")
95
+ opts.on('--name NAME', String, "System Name") do |val|
96
+ params['name'] = val.to_s
97
+ end
98
+ opts.on('--description [TEXT]', String, "Description") do |val|
99
+ params['description'] = val.to_s
100
+ end
101
+ opts.on('--type TYPE', String, "System Type ID or name") do |val|
102
+ params['type'] = val
103
+ end
104
+ opts.on('--layout LAYOUT', String, "System Layout ID or name") do |val|
105
+ params['layout'] = val
106
+ end
107
+ opts.on('--component JSON', String, "Component JSON (can be repeated). e.g. '{\"typeCode\":\"compute-node\",\"name\":\"CN-1\"}'") do |val|
108
+ components << JSON.parse(val)
109
+ end
110
+ opts.on('--components JSON', String, "Components JSON array") do |val|
111
+ components.concat(JSON.parse(val))
112
+ end
113
+ build_standard_add_options(opts, options)
114
+ opts.footer = "Create a new system.\n[name] is optional and can be passed as the first argument."
115
+ end
116
+ optparse.parse!(args)
117
+ connect(options)
118
+
119
+ payload = nil
120
+ if options[:payload]
121
+ payload = options[:payload]
122
+ payload[rest_object_key] ||= {}
123
+ payload[rest_object_key].deep_merge!(params) unless params.empty?
124
+ payload[rest_object_key]['name'] ||= args[0] if args[0]
125
+ payload[rest_object_key]['components'] = components unless components.empty?
126
+ else
127
+ system_payload = {}
128
+
129
+ # Name
130
+ system_payload['name'] = params['name'] || args[0]
131
+ if !system_payload['name'] && !options[:no_prompt]
132
+ system_payload['name'] = MtnCloud::Cli::OptionTypes.prompt([{'fieldName' => 'name', 'type' => 'text', 'fieldLabel' => 'Name', 'required' => true}], options[:options], @api_client, {})['name']
133
+ end
134
+ raise_command_error "Name is required.\n#{optparse}" if system_payload['name'].to_s.empty?
135
+
136
+ # Description
137
+ if !params['description'] && !options[:no_prompt]
138
+ system_payload['description'] = MtnCloud::Cli::OptionTypes.prompt([{'fieldName' => 'description', 'type' => 'text', 'fieldLabel' => 'Description', 'required' => false}], options[:options], @api_client, {})['description']
139
+ else
140
+ system_payload['description'] = params['description']
141
+ end
142
+
143
+ # Type
144
+ available_types = system_types_for_dropdown
145
+ type_val = params['type']
146
+ if type_val
147
+ type_id = type_val =~ /\A\d+\Z/ ? type_val.to_i : available_types.find { |t| t['name'] == type_val || t['code'] == type_val }&.dig('id')
148
+ raise_command_error "System type not found: #{type_val}" unless type_id
149
+ system_payload['type'] = {'id' => type_id}
150
+ elsif !options[:no_prompt]
151
+ if available_types.empty?
152
+ raise_command_error "No system types found."
153
+ else
154
+ print cyan, "Available System Types\n", reset
155
+ available_types.each do |t|
156
+ print " #{t['id']}) #{t['name']}#{t['code'] ? " (#{t['code']})" : ''}\n"
157
+ end
158
+ selected = MtnCloud::Cli::OptionTypes.prompt([{'fieldName' => 'type', 'type' => 'text', 'fieldLabel' => 'System Type ID', 'required' => true}], options[:options], @api_client, {})['type']
159
+ type_id = available_types.find { |t| t['id'].to_s == selected.to_s }&.dig('id')
160
+ raise_command_error "Invalid system type id: #{selected}" unless type_id
161
+ system_payload['type'] = {'id' => type_id}
162
+ end
163
+ end
164
+
165
+ # Layout
166
+ available_layouts = system_layouts_for_dropdown(system_payload.dig('type', 'id'))
167
+ layout_val = params['layout']
168
+ if layout_val
169
+ layout_id = layout_val =~ /\A\d+\Z/ ? layout_val.to_i : available_layouts.find { |l| l['name'] == layout_val || l['code'] == layout_val }&.dig('id')
170
+ raise_command_error "System layout not found: #{layout_val}" unless layout_id
171
+ system_payload['layout'] = {'id' => layout_id}
172
+ elsif !options[:no_prompt]
173
+ if available_layouts.empty?
174
+ raise_command_error "No system layouts found for selected type."
175
+ else
176
+ print cyan, "Available System Layouts\n", reset
177
+ available_layouts.each do |l|
178
+ print " #{l['id']}) #{l['name']}#{l['code'] ? " (#{l['code']})" : ''}\n"
179
+ end
180
+ selected = MtnCloud::Cli::OptionTypes.prompt([{'fieldName' => 'layout', 'type' => 'text', 'fieldLabel' => 'System Layout ID', 'required' => true}], options[:options], @api_client, {})['layout']
181
+ layout_id = available_layouts.find { |l| l['id'].to_s == selected.to_s }&.dig('id')
182
+ raise_command_error "Invalid system layout id: #{selected}" unless layout_id
183
+ system_payload['layout'] = {'id' => layout_id}
184
+ end
185
+ end
186
+
187
+ system_payload['components'] = components unless components.empty?
188
+ payload = {rest_object_key => system_payload}
189
+ end
190
+
191
+ if options[:dry_run]
192
+ print_dry_run rest_interface.dry.create(payload)
193
+ return
194
+ end
195
+
196
+ rest_interface.setopts(options)
197
+ json_response = rest_interface.create(payload)
198
+ render_response(json_response, options, rest_object_key) do
199
+ system_id = json_response['id'] || json_response.dig(rest_object_key, 'id')
200
+ print_green_success "System created"
201
+ get([system_id.to_s] + (options[:remote] ? ['-r', options[:remote]] : [])) if system_id
202
+ end
203
+ end
204
+
205
+ def add_uninitialized(args)
206
+ options = {}
207
+ params = {}
208
+ components = []
209
+ optparse = MtnCloud::Cli::OptionParser.new do |opts|
210
+ opts.banner = subcommand_usage("[name]")
211
+ opts.on('--name NAME', String, "System Name") do |val|
212
+ params['name'] = val.to_s
213
+ end
214
+ opts.on('--description [TEXT]', String, "Description") do |val|
215
+ params['description'] = val.to_s
216
+ end
217
+ opts.on('--type TYPE', String, "System Type ID or name") do |val|
218
+ params['type'] = val
219
+ end
220
+ opts.on('--layout LAYOUT', String, "System Layout ID or name") do |val|
221
+ params['layout'] = val
222
+ end
223
+ opts.on('--config JSON', String, "System config JSON") do |val|
224
+ params['config'] = JSON.parse(val)
225
+ end
226
+ opts.on('--externalId ID', String, "External ID") do |val|
227
+ params['externalId'] = val.to_s
228
+ end
229
+ opts.on('--component JSON', String, "Component JSON (can be repeated). e.g. '{\"typeCode\":\"compute-node\",\"name\":\"CN-1\",\"config\":{\"ip\":\"10.0.0.1\"}}'") do |val|
230
+ components << JSON.parse(val)
231
+ end
232
+ opts.on('--components JSON', String, "Components JSON array") do |val|
233
+ components.concat(JSON.parse(val))
234
+ end
235
+ build_standard_add_options(opts, options)
236
+ opts.footer = <<-EOT
237
+ Create a new system in an uninitialized state.
238
+ This creates a skeleton system with components but does not invoke provider initialization.
239
+ [name] is optional and can be passed as the first argument.
240
+ EOT
241
+ end
242
+ optparse.parse!(args)
243
+ connect(options)
244
+
245
+ payload = nil
246
+ if options[:payload]
247
+ payload = options[:payload]
248
+ payload[rest_object_key] ||= {}
249
+ payload[rest_object_key].deep_merge!(params) unless params.empty?
250
+ payload[rest_object_key]['name'] ||= args[0] if args[0]
251
+ payload[rest_object_key]['components'] = components unless components.empty?
252
+ else
253
+ system_payload = {}
254
+
255
+ # Name
256
+ system_payload['name'] = params['name'] || args[0]
257
+ if !system_payload['name'] && !options[:no_prompt]
258
+ system_payload['name'] = MtnCloud::Cli::OptionTypes.prompt([{'fieldName' => 'name', 'type' => 'text', 'fieldLabel' => 'Name', 'required' => true}], options[:options], @api_client, {})['name']
259
+ end
260
+ raise_command_error "Name is required.\n#{optparse}" if system_payload['name'].to_s.empty?
261
+
262
+ # Description
263
+ if !params['description'] && !options[:no_prompt]
264
+ system_payload['description'] = MtnCloud::Cli::OptionTypes.prompt([{'fieldName' => 'description', 'type' => 'text', 'fieldLabel' => 'Description', 'required' => false}], options[:options], @api_client, {})['description']
265
+ else
266
+ system_payload['description'] = params['description']
267
+ end
268
+
269
+ # Type
270
+ available_types = system_types_for_dropdown
271
+ type_val = params['type']
272
+ if type_val
273
+ type_id = type_val =~ /\A\d+\Z/ ? type_val.to_i : available_types.find { |t| t['name'] == type_val || t['code'] == type_val }&.dig('id')
274
+ raise_command_error "System type not found: #{type_val}" unless type_id
275
+ system_payload['type'] = {'id' => type_id}
276
+ elsif !options[:no_prompt]
277
+ if available_types.empty?
278
+ raise_command_error "No system types found."
279
+ else
280
+ print cyan, "Available System Types\n", reset
281
+ available_types.each do |t|
282
+ print " #{t['id']}) #{t['name']}#{t['code'] ? " (#{t['code']})" : ''}\n"
283
+ end
284
+ selected = MtnCloud::Cli::OptionTypes.prompt([{'fieldName' => 'type', 'type' => 'text', 'fieldLabel' => 'System Type ID', 'required' => true}], options[:options], @api_client, {})['type']
285
+ type_id = available_types.find { |t| t['id'].to_s == selected.to_s }&.dig('id')
286
+ raise_command_error "Invalid system type id: #{selected}" unless type_id
287
+ system_payload['type'] = {'id' => type_id}
288
+ end
289
+ end
290
+
291
+ # Layout
292
+ available_layouts = system_layouts_for_dropdown(system_payload.dig('type', 'id'))
293
+ selected_layout = nil
294
+ layout_val = params['layout']
295
+ if layout_val
296
+ layout_id = layout_val =~ /\A\d+\Z/ ? layout_val.to_i : available_layouts.find { |l| l['name'] == layout_val || l['code'] == layout_val }&.dig('id')
297
+ raise_command_error "System layout not found: #{layout_val}" unless layout_id
298
+ system_payload['layout'] = {'id' => layout_id}
299
+ selected_layout = available_layouts.find { |l| l['id'].to_i == layout_id.to_i }
300
+ elsif !options[:no_prompt]
301
+ if available_layouts.empty?
302
+ raise_command_error "No system layouts found for selected type."
303
+ else
304
+ print cyan, "Available System Layouts\n", reset
305
+ available_layouts.each do |l|
306
+ print " #{l['id']}) #{l['name']}#{l['code'] ? " (#{l['code']})" : ''}\n"
307
+ end
308
+ selected = MtnCloud::Cli::OptionTypes.prompt([{'fieldName' => 'layout', 'type' => 'text', 'fieldLabel' => 'System Layout ID', 'required' => true}], options[:options], @api_client, {})['layout']
309
+ selected_layout = available_layouts.find { |l| l['id'].to_s == selected.to_s }
310
+ raise_command_error "Invalid system layout id: #{selected}" unless selected_layout
311
+ system_payload['layout'] = {'id' => selected_layout['id']}
312
+ end
313
+ end
314
+
315
+ # Config
316
+ system_payload['config'] = params['config'] if params['config']
317
+
318
+ # External ID
319
+ system_payload['externalId'] = params['externalId'] if params['externalId']
320
+
321
+ # Components — prompt interactively if none provided via flags
322
+ if components.empty? && !options[:no_prompt] && selected_layout
323
+ available_component_types = selected_layout['componentTypes'] || []
324
+ if available_component_types.any?
325
+ print cyan, "\nAvailable Component Types for layout '#{selected_layout['name']}':\n", reset
326
+ available_component_types.each do |ct|
327
+ print " #{ct['code']}#{ct['category'] ? " [#{ct['category']}]" : ''} - #{ct['name']}\n"
328
+ end
329
+ print "\n"
330
+ add_more = true
331
+ while add_more
332
+ add_component = MtnCloud::Cli::OptionTypes.prompt([{'fieldName' => 'addComponent', 'type' => 'text', 'fieldLabel' => 'Add a component? (yes/no)', 'required' => true, 'defaultValue' => 'yes'}], options[:options], @api_client, {})['addComponent']
333
+ if add_component.to_s.downcase =~ /^(y|yes)$/
334
+ # Component type selection
335
+ print cyan, "Component Types:\n", reset
336
+ available_component_types.each_with_index do |ct, idx|
337
+ print " #{idx + 1}) #{ct['name']} (#{ct['code']})\n"
338
+ end
339
+ selected_ct = MtnCloud::Cli::OptionTypes.prompt([{'fieldName' => 'componentType', 'type' => 'text', 'fieldLabel' => 'Component Type (number or code)', 'required' => true}], options[:options], @api_client, {})['componentType']
340
+ component_type = nil
341
+ if selected_ct =~ /\A\d+\Z/
342
+ idx = selected_ct.to_i - 1
343
+ component_type = available_component_types[idx] if idx >= 0 && idx < available_component_types.size
344
+ else
345
+ component_type = available_component_types.find { |ct| ct['code'] == selected_ct }
346
+ end
347
+ if component_type.nil?
348
+ print_red_alert "Invalid component type: #{selected_ct}"
349
+ next
350
+ end
351
+ # Component name
352
+ default_name = component_type['name']
353
+ comp_name = MtnCloud::Cli::OptionTypes.prompt([{'fieldName' => 'componentName', 'type' => 'text', 'fieldLabel' => 'Component Name', 'required' => false, 'defaultValue' => default_name}], options[:options], @api_client, {})['componentName']
354
+ comp = {'typeCode' => component_type['code'], 'name' => comp_name || default_name}
355
+ # Component config
356
+ comp_config = MtnCloud::Cli::OptionTypes.prompt([{'fieldName' => 'componentConfig', 'type' => 'text', 'fieldLabel' => 'Component Config JSON (optional)', 'required' => false}], options[:options], @api_client, {})['componentConfig']
357
+ if comp_config && !comp_config.to_s.empty?
358
+ begin
359
+ comp['config'] = JSON.parse(comp_config)
360
+ rescue JSON::ParserError => e
361
+ print_red_alert "Invalid JSON: #{e.message}"
362
+ next
363
+ end
364
+ end
365
+ components << comp
366
+ print_green_success "Added component: #{comp['name']} (#{comp['typeCode']})"
367
+ else
368
+ add_more = false
369
+ end
370
+ end
371
+ end
372
+ end
373
+ system_payload['components'] = components unless components.empty?
374
+
375
+ payload = {rest_object_key => system_payload}
376
+ end
377
+
378
+ if options[:dry_run]
379
+ print_dry_run rest_interface.dry.save_uninitialized(payload)
380
+ return
381
+ end
382
+
383
+ rest_interface.setopts(options)
384
+ json_response = rest_interface.save_uninitialized(payload)
385
+ render_response(json_response, options, rest_object_key) do
386
+ system_id = json_response['id'] || json_response.dig(rest_object_key, 'id')
387
+ print_green_success "Uninitialized system created"
388
+ get([system_id.to_s] + (options[:remote] ? ['-r', options[:remote]] : [])) if system_id
389
+ end
390
+ end
391
+
392
+ def exec_initialize(args)
393
+ options = {}
394
+ params = {}
395
+ components = []
396
+ optparse = MtnCloud::Cli::OptionParser.new do |opts|
397
+ opts.banner = subcommand_usage("[system]")
398
+ opts.on('--name NAME', String, "Update the system name before initializing") do |val|
399
+ params['name'] = val.to_s
400
+ end
401
+ opts.on('--description [TEXT]', String, "Update the description before initializing") do |val|
402
+ params['description'] = val.to_s
403
+ end
404
+ opts.on('--externalId ID', String, "Set the external ID before initializing") do |val|
405
+ params['externalId'] = val.to_s
406
+ end
407
+ opts.on('--config JSON', String, "Set config JSON before initializing") do |val|
408
+ params['config'] = JSON.parse(val)
409
+ end
410
+ opts.on('--component JSON', String, "Component update JSON (can be repeated). e.g. '{\"typeCode\":\"compute-node\",\"externalId\":\"ext-001\",\"config\":{\"ip\":\"10.0.0.1\"}}'") do |val|
411
+ components << JSON.parse(val)
412
+ end
413
+ opts.on('--components JSON', String, "Component updates JSON array") do |val|
414
+ components.concat(JSON.parse(val))
415
+ end
416
+ build_standard_update_options(opts, options)
417
+ opts.footer = <<-EOT
418
+ Initialize an existing system that is in an uninitialized state.
419
+ This invokes the provider's prepare and initialize lifecycle methods.
420
+ [system] is required. This is the name or id of a system.
421
+ EOT
422
+ end
423
+ optparse.parse!(args)
424
+ verify_args!(args: args, optparse: optparse, count: 1)
425
+ connect(options)
426
+
427
+ system_record = nil
428
+ if args[0].to_s =~ /\A\d{1,}\Z/
429
+ json_response = rest_interface.get(args[0].to_i)
430
+ system_record = json_response[rest_object_key] || json_response
431
+ else
432
+ system_record = find_by_name(rest_key, args[0])
433
+ end
434
+ return 1, "System not found for '#{args[0]}'" if system_record.nil?
435
+
436
+ # Prompt for component updates if none provided via flags and not in no-prompt mode
437
+ if components.empty? && !options[:no_prompt] && !options[:payload]
438
+ existing_components = system_record['components'] || []
439
+ if existing_components.any?
440
+ print cyan, "\nExisting Components:\n", reset
441
+ existing_components.each_with_index do |c, idx|
442
+ type_code = c.dig('type', 'code') || 'unknown'
443
+ print " #{idx + 1}) #{c['name']} (#{type_code})#{c['externalId'] ? " externalId=#{c['externalId']}" : ''}\n"
444
+ end
445
+ print "\n"
446
+ update_components = MtnCloud::Cli::OptionTypes.prompt([{'fieldName' => 'updateComponents', 'type' => 'text', 'fieldLabel' => 'Update any components? (yes/no)', 'required' => true, 'defaultValue' => 'no'}], options[:options], @api_client, {})['updateComponents']
447
+ if update_components.to_s.downcase =~ /^(y|yes)$/
448
+ existing_components.each do |c|
449
+ type_code = c.dig('type', 'code') || 'unknown'
450
+ print cyan, "\nComponent: #{c['name']} (#{type_code})\n", reset
451
+ comp_update = {'typeCode' => type_code}
452
+
453
+ ext_id = MtnCloud::Cli::OptionTypes.prompt([{'fieldName' => 'externalId', 'type' => 'text', 'fieldLabel' => " External ID (current: #{c['externalId'] || 'none'})", 'required' => false}], options[:options], @api_client, {})['externalId']
454
+ comp_update['externalId'] = ext_id unless ext_id.to_s.empty?
455
+
456
+ comp_config = MtnCloud::Cli::OptionTypes.prompt([{'fieldName' => 'config', 'type' => 'text', 'fieldLabel' => ' Config JSON (optional)', 'required' => false}], options[:options], @api_client, {})['config']
457
+ if comp_config && !comp_config.to_s.empty?
458
+ begin
459
+ comp_update['config'] = JSON.parse(comp_config)
460
+ rescue JSON::ParserError => e
461
+ print_red_alert "Invalid JSON for component config: #{e.message}"
462
+ end
463
+ end
464
+
465
+ components << comp_update if comp_update.keys.length > 1
466
+ end
467
+ end
468
+ end
469
+ end
470
+
471
+ payload = {}
472
+ if options[:payload]
473
+ payload = options[:payload]
474
+ payload[rest_object_key] ||= {}
475
+ payload[rest_object_key].deep_merge!(params) unless params.empty?
476
+ payload[rest_object_key]['components'] = components unless components.empty?
477
+ else
478
+ params['components'] = components unless components.empty?
479
+ payload = {rest_object_key => params}
480
+ end
481
+
482
+ if options[:dry_run]
483
+ print_dry_run rest_interface.dry.initialize_system(system_record['id'], payload)
484
+ return
485
+ end
486
+
487
+ rest_interface.setopts(options)
488
+ json_response = rest_interface.initialize_system(system_record['id'], payload)
489
+ render_response(json_response, options, rest_object_key) do
490
+ print_green_success "System #{system_record['name']} initialized"
491
+ get([system_record['id'].to_s] + (options[:remote] ? ['-r', options[:remote]] : []))
492
+ end
493
+ end
494
+
495
+ def exec_validate(args)
496
+ options = {}
497
+ params = {}
498
+ optparse = MtnCloud::Cli::OptionParser.new do |opts|
499
+ opts.banner = subcommand_usage("[system]")
500
+ build_standard_get_options(opts, options)
501
+ opts.footer = <<-EOT
502
+ Validate an existing system by running the provider's pre-check phase.
503
+ No state changes are made. Returns success if the provider's prepare check passes.
504
+ [system] is required. This is the name or id of a system.
505
+ EOT
506
+ end
507
+ optparse.parse!(args)
508
+ verify_args!(args: args, optparse: optparse, count: 1)
509
+ connect(options)
510
+
511
+ system = nil
512
+ if args[0].to_s =~ /\A\d{1,}\Z/
513
+ json_response = rest_interface.get(args[0].to_i)
514
+ system = json_response[rest_object_key] || json_response
515
+ else
516
+ system = find_by_name(rest_key, args[0])
517
+ end
518
+ return 1, "System not found for '#{args[0]}'" if system.nil?
519
+
520
+ if options[:dry_run]
521
+ print_dry_run rest_interface.dry.validate_system(system['id'])
522
+ return
523
+ end
524
+
525
+ rest_interface.setopts(options)
526
+ json_response = rest_interface.validate_system(system['id'])
527
+ render_response(json_response, options) do
528
+ if json_response['success']
529
+ print_green_success "System #{system['name']} validated successfully"
530
+ else
531
+ print_red_alert "System #{system['name']} validation failed: #{json_response['msg']}"
532
+ end
533
+ end
534
+ end
535
+
536
+ def remove(args)
537
+ options = {}
538
+ optparse = MtnCloud::Cli::OptionParser.new do |opts|
539
+ opts.banner = subcommand_usage("[system]")
540
+ build_standard_remove_options(opts, options)
541
+ opts.footer = <<-EOT
542
+ Delete an existing system.
543
+ [system] is required. This is the name or id of a system.
544
+ EOT
545
+ end
546
+ optparse.parse!(args)
547
+ verify_args!(args: args, optparse: optparse, count: 1)
548
+ connect(options)
549
+
550
+ system = nil
551
+ if args[0].to_s =~ /\A\d{1,}\Z/
552
+ json_response = rest_interface.get(args[0].to_i)
553
+ system = json_response[rest_object_key] || json_response
554
+ else
555
+ system = find_by_name(rest_key, args[0])
556
+ end
557
+ return 1, "System not found for '#{args[0]}'" if system.nil?
558
+
559
+ unless options[:yes] || MtnCloud::Cli::OptionTypes.confirm("Are you sure you want to delete the system #{system['name']}?")
560
+ return 9, "aborted"
561
+ end
562
+
563
+ if options[:dry_run]
564
+ print_dry_run rest_interface.dry.destroy(system['id'])
565
+ return
566
+ end
567
+
568
+ rest_interface.setopts(options)
569
+ json_response = rest_interface.destroy(system['id'])
570
+ render_response(json_response, options) do
571
+ print_green_success "System #{system['name']} removed"
572
+ end
573
+ end
574
+
575
+ def update(args)
576
+ options = {}
577
+ params = {}
578
+ components = []
579
+ components_specified = false
580
+ optparse = MtnCloud::Cli::OptionParser.new do |opts|
581
+ opts.banner = subcommand_usage("[system]")
582
+ opts.on("--name NAME", String, "Updates System Name") do |val|
583
+ params['name'] = val.to_s
584
+ end
585
+ opts.on("--description [TEXT]", String, "Updates System Description") do |val|
586
+ params['description'] = val.to_s
587
+ end
588
+ opts.on('--enabled [on|off]', String, "Set whether the system is enabled") do |val|
589
+ params['enabled'] = val.to_s
590
+ end
591
+ opts.on('--externalId ID', String, "Set the external ID") do |val|
592
+ params['externalId'] = val.to_s
593
+ end
594
+ opts.on('--config JSON', String, "Set config JSON") do |val|
595
+ params['config'] = JSON.parse(val)
596
+ end
597
+ opts.on('--component JSON', String, "Component JSON (can be repeated). Pass the full desired component set when using component updates.") do |val|
598
+ components_specified = true
599
+ components << JSON.parse(val)
600
+ end
601
+ opts.on('--components JSON', String, "Components JSON array. This should be the full desired final component list.") do |val|
602
+ components_specified = true
603
+ components.concat(JSON.parse(val))
604
+ end
605
+ build_standard_update_options(opts, options, [:find_by_name])
606
+ opts.footer = <<-EOT
607
+ Update an existing system.
608
+ If system.components is supplied, it is authoritative: omitted components will be removed.
609
+ Omit the components key entirely to leave components unchanged.
610
+ [system] is required. This is the name or id of a system.
611
+ EOT
612
+ end
613
+ optparse.parse!(args)
614
+ verify_args!(args: args, optparse: optparse, count: 1)
615
+ connect(options)
616
+
617
+ system = nil
618
+ if args[0].to_s =~ /\A\d{1,}\Z/
619
+ json_response = rest_interface.get(args[0].to_i)
620
+ system = json_response[rest_object_key] || json_response
621
+ else
622
+ system = find_by_name(rest_key, args[0])
623
+ end
624
+ return 1, "System not found for '#{args[0]}'" if system.nil?
625
+
626
+ passed_options = parse_passed_options(options)
627
+ params.deep_merge!(passed_options) unless passed_options.empty?
628
+ params.booleanize!
629
+
630
+ payload = parse_payload(options) || {rest_object_key => params}
631
+ payload[rest_object_key] ||= {}
632
+ payload[rest_object_key].deep_merge!(params) unless params.empty?
633
+ payload[rest_object_key]['components'] = components if components_specified
634
+ if payload[rest_object_key].nil? || payload[rest_object_key].empty?
635
+ raise_command_error "Specify at least one option to update.\n#{optparse}"
636
+ end
637
+
638
+ if options[:dry_run]
639
+ print_dry_run rest_interface.dry.update(system['id'], payload)
640
+ return
641
+ end
642
+
643
+ rest_interface.setopts(options)
644
+ json_response = rest_interface.update(system['id'], payload)
645
+ render_response(json_response, options, rest_object_key) do
646
+ print_green_success "Updated system #{system['id']}"
647
+ get([system['id']] + (options[:remote] ? ['-r', options[:remote]] : []))
648
+ end
649
+ end
650
+
651
+ def system_types_for_dropdown
652
+ result = @api_client.system_types.list({'max' => 100})
653
+ items = result ? (result['systemTypes'] || result[:systemTypes] || result['types'] || result[:types] || []) : []
654
+ items.map { |t| {'id' => t['id'] || t[:id], 'name' => t['name'] || t[:name], 'value' => (t['id'] || t[:id]).to_s, 'code' => t['code'] || t[:code]} }
655
+ end
656
+
657
+ def system_layouts_for_dropdown(type_id = nil)
658
+ return [] if type_id.nil?
659
+ result = @api_client.system_types.list_layouts(type_id, {'max' => 100})
660
+ items = result ? (result['systemTypeLayouts'] || result[:systemTypeLayouts] || result['layouts'] || result[:layouts] || []) : []
661
+ items.map { |l| {'id' => l['id'] || l[:id], 'name' => l['name'] || l[:name], 'value' => (l['id'] || l[:id]).to_s, 'code' => l['code'] || l[:code], 'componentTypes' => l['componentTypes'] || l[:componentTypes] || []} }
662
+ end
663
+
664
+ def list_types(args)
665
+ options = {}
666
+ optparse = MtnCloud::Cli::OptionParser.new do |opts|
667
+ opts.banner = subcommand_usage()
668
+ build_standard_list_options(opts, options)
669
+ opts.footer = "List available system types."
670
+ end
671
+ optparse.parse!(args)
672
+ connect(options)
673
+ begin
674
+ params = {}
675
+ params.merge!(parse_list_options(options))
676
+ @system_types_interface = @api_client.system_types
677
+ @system_types_interface.setopts(options)
678
+ if options[:dry_run]
679
+ print_dry_run @system_types_interface.dry.list(params)
680
+ return 0
681
+ end
682
+ json_response = @system_types_interface.list(params)
683
+ system_types = json_response['systemTypes'] || []
684
+ render_response(json_response, options, 'systemTypes') do
685
+ print_h1 "System Types", [], options
686
+ if system_types.empty?
687
+ print cyan, "No system types found.", reset, "\n"
688
+ else
689
+ columns = {
690
+ "ID" => 'id',
691
+ "Name" => 'name',
692
+ "Code" => 'code',
693
+ }
694
+ print cyan
695
+ print as_pretty_table(system_types, columns.upcase_keys!, options)
696
+ print_results_pagination({size: system_types.size, total: (json_response['meta'] ? json_response['meta']['total'] : system_types.size)})
697
+ end
698
+ print reset, "\n"
699
+ end
700
+ return 0
701
+ rescue RestClient::Exception => e
702
+ print_rest_exception(e, options)
703
+ exit 1
704
+ end
705
+ end
706
+
707
+ def list_layouts(args)
708
+ options = {}
709
+ optparse = MtnCloud::Cli::OptionParser.new do |opts|
710
+ opts.banner = subcommand_usage("[type]")
711
+ build_standard_list_options(opts, options)
712
+ opts.footer = <<-EOT
713
+ List available layouts for a system type.
714
+ [type] is required. This is the id of a system type.
715
+ Use 'systems list-types' to find the type id.
716
+ EOT
717
+ end
718
+ optparse.parse!(args)
719
+ verify_args!(args:args, optparse:optparse, count:1)
720
+ connect(options)
721
+ begin
722
+ type_id = args[0].to_i
723
+ params = {}
724
+ params.merge!(parse_list_options(options))
725
+ @system_types_interface = @api_client.system_types
726
+ @system_types_interface.setopts(options)
727
+ if options[:dry_run]
728
+ print_dry_run @system_types_interface.dry.list_layouts(type_id, params)
729
+ return 0
730
+ end
731
+ json_response = @system_types_interface.list_layouts(type_id, params)
732
+ layouts = json_response['systemTypeLayouts'] || []
733
+ render_response(json_response, options, 'systemTypeLayouts') do
734
+ print_h1 "System Type Layouts", [], options
735
+ if layouts.empty?
736
+ print cyan, "No layouts found.", reset, "\n"
737
+ else
738
+ columns = {
739
+ "ID" => 'id',
740
+ "Name" => 'name',
741
+ "Code" => 'code',
742
+ }
743
+ print cyan
744
+ print as_pretty_table(layouts, columns.upcase_keys!, options)
745
+ print_results_pagination({size: layouts.size, total: (json_response['meta'] ? json_response['meta']['total'] : layouts.size)})
746
+ layouts.each do |layout|
747
+ component_types = layout['componentTypes'] || []
748
+ next if component_types.empty?
749
+ print_h2 "Components for #{layout['name']}", options
750
+ component_type_rows = component_types.collect do |ct|
751
+ {
752
+ id: ct['id'],
753
+ code: ct['code'],
754
+ name: ct['name'],
755
+ category: ct['category']
756
+ }
757
+ end
758
+ print as_pretty_table(component_type_rows, [:id, :code, :name, :category], options)
759
+ end
760
+ end
761
+ print reset, "\n"
762
+ end
763
+ return 0
764
+ rescue RestClient::Exception => e
765
+ print_rest_exception(e, options)
766
+ exit 1
767
+ end
768
+ end
769
+
770
+ def list_available_server_updates(args)
771
+ options = {}
772
+ optparse = MtnCloud::Cli::OptionParser.new do |opts|
773
+ opts.banner = subcommand_usage("[system] [server]")
774
+ build_standard_list_options(opts, options)
775
+ opts.footer = <<-EOT
776
+ List available update definitions for a compute server component of a system.
777
+ [system] is required. This is the name or id of a system.
778
+ [server] is required. This is the name or id of the compute server.
779
+ EOT
780
+ end
781
+ optparse.parse!(args)
782
+ verify_args!(args:args, optparse:optparse, count:2)
783
+ connect(options)
784
+ begin
785
+ system = find_by_name_or_id(:systems, args[0])
786
+ return 1 if system.nil?
787
+ server = find_by_name_or_id(:servers, args[1])
788
+ return 1 if server.nil?
789
+ params = {}
790
+ params.merge!(parse_list_options(options))
791
+ @systems_interface.setopts(options)
792
+ if options[:dry_run]
793
+ print_dry_run @systems_interface.dry.list_compute_server_update_definitions(system['id'], server['id'], params)
794
+ return
795
+ end
796
+ json_response = @systems_interface.list_compute_server_update_definitions(system['id'], server['id'], params)
797
+ update_definitions = json_response['updateDefinitions']
798
+ render_response(json_response, options, 'updateDefinitions') do
799
+ print_h1 "Available Server Updates: #{system['name']} / #{server['name']}", [], options
800
+ if update_definitions.nil? || update_definitions.empty?
801
+ print cyan, "No update definitions found.", reset, "\n"
802
+ else
803
+ columns = {
804
+ "ID" => 'id',
805
+ "Name" => 'name',
806
+ "Version" => 'updateVersion',
807
+ "Severity" => 'severity',
808
+ "Type" => 'type',
809
+ "Reboot" => lambda {|it| format_boolean(it['requiresReboot']) },
810
+ "Rollback" => lambda {|it| format_boolean(it['supportsRollback']) },
811
+ "Released" => lambda {|it| it['updateReleaseDate'] ? format_local_dt(it['updateReleaseDate']) : '' },
812
+ }
813
+ print cyan
814
+ print as_pretty_table(update_definitions, columns.upcase_keys!, options)
815
+ print_results_pagination({size: update_definitions.size, total: (json_response['meta'] ? json_response['meta']['total'] : update_definitions.size)})
816
+ end
817
+ print reset, "\n"
818
+ end
819
+ return 0
820
+ rescue RestClient::Exception => e
821
+ print_rest_exception(e, options)
822
+ exit 1
823
+ end
824
+ end
825
+
826
+ def apply_server_update(args)
827
+ options = {}
828
+ optparse = MtnCloud::Cli::OptionParser.new do |opts|
829
+ opts.banner = subcommand_usage("[system] [server] [updateDefinitionId]")
830
+ opts.on('--dry-run-update', "Execute as a dry run — passes dryRun:true to the server, no changes applied.") do
831
+ options[:dry_run_update] = true
832
+ end
833
+ build_standard_update_options(opts, options)
834
+ opts.footer = <<-EOT
835
+ Apply an update definition to a compute server component of a system.
836
+ [system] is required. This is the name or id of a system.
837
+ [server] is required. This is the name or id of the compute server.
838
+ [updateDefinitionId] is required. This is the id of the update definition.
839
+ EOT
840
+ end
841
+ optparse.parse!(args)
842
+ verify_args!(args:args, optparse:optparse, count:3)
843
+ connect(options)
844
+ begin
845
+ system = find_by_name_or_id(:systems, args[0])
846
+ return 1 if system.nil?
847
+ server = find_by_name_or_id(:servers, args[1])
848
+ return 1 if server.nil?
849
+ update_definition_id = args[2]
850
+ payload = {}
851
+ payload['dryRun'] = true if options[:dry_run_update]
852
+ payload.deep_merge!(parse_passed_options(options))
853
+ params = {}
854
+ @systems_interface.setopts(options)
855
+ if options[:dry_run]
856
+ print_dry_run @systems_interface.dry.apply_compute_server_update_definition(system['id'], server['id'], update_definition_id, payload, params)
857
+ return
858
+ end
859
+ json_response = @systems_interface.apply_compute_server_update_definition(system['id'], server['id'], update_definition_id, payload, params)
860
+ render_response(json_response, options) do
861
+ print_green_success "Update operation #{json_response['updateOperation']['id']} queued for server #{server['name']} on system #{system['name']}."
862
+ end
863
+ return 0
864
+ rescue RestClient::Exception => e
865
+ print_rest_exception(e, options)
866
+ exit 1
867
+ end
868
+ end
869
+
870
+ def list_available_storage_updates(args)
871
+ options = {}
872
+ optparse = MtnCloud::Cli::OptionParser.new do |opts|
873
+ opts.banner = subcommand_usage("[system] [storage-server]")
874
+ build_standard_list_options(opts, options)
875
+ opts.footer = <<-EOT
876
+ List available update definitions for a storage server component of a system.
877
+ [system] is required. This is the name or id of a system.
878
+ [storage-server] is required. This is the name or id of the storage server.
879
+ EOT
880
+ end
881
+ optparse.parse!(args)
882
+ verify_args!(args:args, optparse:optparse, count:2)
883
+ connect(options)
884
+ begin
885
+ system = find_by_name_or_id(:systems, args[0])
886
+ return 1 if system.nil?
887
+ storage_server = find_by_name_or_id(:storage_servers, args[1])
888
+ return 1 if storage_server.nil?
889
+ params = {}
890
+ params.merge!(parse_list_options(options))
891
+ @systems_interface.setopts(options)
892
+ if options[:dry_run]
893
+ print_dry_run @systems_interface.dry.list_storage_server_update_definitions(system['id'], storage_server['id'], params)
894
+ return
895
+ end
896
+ json_response = @systems_interface.list_storage_server_update_definitions(system['id'], storage_server['id'], params)
897
+ update_definitions = json_response['updateDefinitions']
898
+ render_response(json_response, options, 'updateDefinitions') do
899
+ print_h1 "Available Storage Updates: #{system['name']} / #{storage_server['name']}", [], options
900
+ if update_definitions.nil? || update_definitions.empty?
901
+ print cyan, "No update definitions found.", reset, "\n"
902
+ else
903
+ columns = {
904
+ "ID" => 'id',
905
+ "Name" => 'name',
906
+ "Version" => 'updateVersion',
907
+ "Severity" => 'severity',
908
+ "Type" => 'type',
909
+ "Reboot" => lambda {|it| format_boolean(it['requiresReboot']) },
910
+ "Rollback" => lambda {|it| format_boolean(it['supportsRollback']) },
911
+ "Released" => lambda {|it| it['updateReleaseDate'] ? format_local_dt(it['updateReleaseDate']) : '' },
912
+ }
913
+ print cyan
914
+ print as_pretty_table(update_definitions, columns.upcase_keys!, options)
915
+ print_results_pagination({size: update_definitions.size, total: (json_response['meta'] ? json_response['meta']['total'] : update_definitions.size)})
916
+ end
917
+ print reset, "\n"
918
+ end
919
+ return 0
920
+ rescue RestClient::Exception => e
921
+ print_rest_exception(e, options)
922
+ exit 1
923
+ end
924
+ end
925
+
926
+ def apply_storage_update(args)
927
+ options = {}
928
+ optparse = MtnCloud::Cli::OptionParser.new do |opts|
929
+ opts.banner = subcommand_usage("[system] [storage-server] [updateDefinitionId]")
930
+ opts.on('--dry-run-update', "Execute as a dry run — passes dryRun:true to the server, no changes applied.") do
931
+ options[:dry_run_update] = true
932
+ end
933
+ build_standard_update_options(opts, options)
934
+ opts.footer = <<-EOT
935
+ Apply an update definition to a storage server component of a system.
936
+ [system] is required. This is the name or id of a system.
937
+ [storage-server] is required. This is the name or id of the storage server.
938
+ [updateDefinitionId] is required. This is the id of the update definition.
939
+ EOT
940
+ end
941
+ optparse.parse!(args)
942
+ verify_args!(args:args, optparse:optparse, count:3)
943
+ connect(options)
944
+ begin
945
+ system = find_by_name_or_id(:systems, args[0])
946
+ return 1 if system.nil?
947
+ storage_server = find_by_name_or_id(:storage_servers, args[1])
948
+ return 1 if storage_server.nil?
949
+ update_definition_id = args[2]
950
+ payload = {}
951
+ payload['dryRun'] = true if options[:dry_run_update]
952
+ payload.deep_merge!(parse_passed_options(options))
953
+ params = {}
954
+ @systems_interface.setopts(options)
955
+ if options[:dry_run]
956
+ print_dry_run @systems_interface.dry.apply_storage_server_update_definition(system['id'], storage_server['id'], update_definition_id, payload, params)
957
+ return
958
+ end
959
+ json_response = @systems_interface.apply_storage_server_update_definition(system['id'], storage_server['id'], update_definition_id, payload, params)
960
+ render_response(json_response, options) do
961
+ print_green_success "Update operation #{json_response['updateOperation']['id']} queued for storage server #{storage_server['name']} on system #{system['name']}."
962
+ end
963
+ return 0
964
+ rescue RestClient::Exception => e
965
+ print_rest_exception(e, options)
966
+ exit 1
967
+ end
968
+ end
969
+
970
+ def list_available_network_server_updates(args)
971
+ options = {}
972
+ optparse = MtnCloud::Cli::OptionParser.new do |opts|
973
+ opts.banner = subcommand_usage("[system] [network-server]")
974
+ build_standard_list_options(opts, options)
975
+ opts.footer = <<-EOT
976
+ List available update definitions for a network server component of a system.
977
+ [system] is required. This is the name or id of a system.
978
+ [network-server] is required. This is the name or id of the network server.
979
+ EOT
980
+ end
981
+ optparse.parse!(args)
982
+ verify_args!(args:args, optparse:optparse, count:2)
983
+ connect(options)
984
+ begin
985
+ system = find_by_name_or_id(:systems, args[0])
986
+ return 1 if system.nil?
987
+ network_server = find_by_name_or_id(:network_servers, args[1])
988
+ return 1 if network_server.nil?
989
+ params = {}
990
+ params.merge!(parse_list_options(options))
991
+ @systems_interface.setopts(options)
992
+ if options[:dry_run]
993
+ print_dry_run @systems_interface.dry.list_network_server_update_definitions(system['id'], network_server['id'], params)
994
+ return
995
+ end
996
+ json_response = @systems_interface.list_network_server_update_definitions(system['id'], network_server['id'], params)
997
+ update_definitions = json_response['updateDefinitions']
998
+ render_response(json_response, options, 'updateDefinitions') do
999
+ print_h1 "Available Network Server Updates: #{system['name']} / #{network_server['name']}", [], options
1000
+ if update_definitions.nil? || update_definitions.empty?
1001
+ print cyan, "No update definitions found.", reset, "\n"
1002
+ else
1003
+ columns = {
1004
+ "ID" => 'id',
1005
+ "Name" => 'name',
1006
+ "Version" => 'updateVersion',
1007
+ "Severity" => 'severity',
1008
+ "Type" => 'type',
1009
+ "Reboot" => lambda {|it| format_boolean(it['requiresReboot']) },
1010
+ "Rollback" => lambda {|it| format_boolean(it['supportsRollback']) },
1011
+ "Released" => lambda {|it| it['updateReleaseDate'] ? format_local_dt(it['updateReleaseDate']) : '' },
1012
+ }
1013
+ print cyan
1014
+ print as_pretty_table(update_definitions, columns.upcase_keys!, options)
1015
+ print_results_pagination({size: update_definitions.size, total: (json_response['meta'] ? json_response['meta']['total'] : update_definitions.size)})
1016
+ end
1017
+ print reset, "\n"
1018
+ end
1019
+ return 0
1020
+ rescue RestClient::Exception => e
1021
+ print_rest_exception(e, options)
1022
+ exit 1
1023
+ end
1024
+ end
1025
+
1026
+ def list_available_network_updates(args)
1027
+ list_available_network_server_updates(args)
1028
+ end
1029
+
1030
+ def apply_network_server_update(args)
1031
+ options = {}
1032
+ optparse = MtnCloud::Cli::OptionParser.new do |opts|
1033
+ opts.banner = subcommand_usage("[system] [network-server] [updateDefinitionId]")
1034
+ opts.on('--dry-run-update', "Execute as a dry run — passes dryRun:true to the server, no changes applied.") do
1035
+ options[:dry_run_update] = true
1036
+ end
1037
+ build_standard_update_options(opts, options)
1038
+ opts.footer = <<-EOT
1039
+ Apply an update definition to a network server component of a system.
1040
+ [system] is required. This is the name or id of a system.
1041
+ [network-server] is required. This is the name or id of the network server.
1042
+ [updateDefinitionId] is required. This is the id of the update definition.
1043
+ EOT
1044
+ end
1045
+ optparse.parse!(args)
1046
+ verify_args!(args:args, optparse:optparse, count:3)
1047
+ connect(options)
1048
+ begin
1049
+ system = find_by_name_or_id(:systems, args[0])
1050
+ return 1 if system.nil?
1051
+ network_server = find_by_name_or_id(:network_servers, args[1])
1052
+ return 1 if network_server.nil?
1053
+ update_definition_id = args[2]
1054
+ payload = {}
1055
+ payload['dryRun'] = true if options[:dry_run_update]
1056
+ payload.deep_merge!(parse_passed_options(options))
1057
+ params = {}
1058
+ @systems_interface.setopts(options)
1059
+ if options[:dry_run]
1060
+ print_dry_run @systems_interface.dry.apply_network_server_update_definition(system['id'], network_server['id'], update_definition_id, payload, params)
1061
+ return
1062
+ end
1063
+ json_response = @systems_interface.apply_network_server_update_definition(system['id'], network_server['id'], update_definition_id, payload, params)
1064
+ render_response(json_response, options) do
1065
+ print_green_success "Update operation #{json_response['updateOperation']['id']} queued for network server #{network_server['name']} on system #{system['name']}."
1066
+ end
1067
+ return 0
1068
+ rescue RestClient::Exception => e
1069
+ print_rest_exception(e, options)
1070
+ exit 1
1071
+ end
1072
+ end
1073
+
1074
+ def apply_network_update(args)
1075
+ apply_network_server_update(args)
1076
+ end
1077
+
1078
+ def list_available_cluster_updates(args)
1079
+ options = {}
1080
+ optparse = MtnCloud::Cli::OptionParser.new do |opts|
1081
+ opts.banner = subcommand_usage("[system] [cluster]")
1082
+ build_standard_list_options(opts, options)
1083
+ opts.footer = <<-EOT
1084
+ List available update definitions for a cluster component of a system.
1085
+ [system] is required. This is the name or id of a system.
1086
+ [cluster] is required. This is the name or id of the cluster.
1087
+ EOT
1088
+ end
1089
+ optparse.parse!(args)
1090
+ verify_args!(args:args, optparse:optparse, count:2)
1091
+ connect(options)
1092
+ begin
1093
+ system = find_by_name_or_id(:systems, args[0])
1094
+ return 1 if system.nil?
1095
+ cluster = find_cluster_by_name_or_id(args[1])
1096
+ return 1 if cluster.nil?
1097
+ params = {}
1098
+ params.merge!(parse_list_options(options))
1099
+ @systems_interface.setopts(options)
1100
+ if options[:dry_run]
1101
+ print_dry_run @systems_interface.dry.list_cluster_update_definitions(system['id'], cluster['id'], params)
1102
+ return
1103
+ end
1104
+ json_response = @systems_interface.list_cluster_update_definitions(system['id'], cluster['id'], params)
1105
+ update_definitions = json_response['updateDefinitions']
1106
+ render_response(json_response, options, 'updateDefinitions') do
1107
+ print_h1 "Available Cluster Updates: #{system['name']} / #{cluster['name']}", [], options
1108
+ if update_definitions.nil? || update_definitions.empty?
1109
+ print cyan, "No update definitions found.", reset, "\n"
1110
+ else
1111
+ columns = {
1112
+ "ID" => 'id',
1113
+ "Name" => 'name',
1114
+ "Version" => 'updateVersion',
1115
+ "Severity" => 'severity',
1116
+ "Type" => 'type',
1117
+ "Reboot" => lambda {|it| format_boolean(it['requiresReboot']) },
1118
+ "Rollback" => lambda {|it| format_boolean(it['supportsRollback']) },
1119
+ "Released" => lambda {|it| it['updateReleaseDate'] ? format_local_dt(it['updateReleaseDate']) : '' },
1120
+ }
1121
+ print cyan
1122
+ print as_pretty_table(update_definitions, columns.upcase_keys!, options)
1123
+ print_results_pagination({size: update_definitions.size, total: (json_response['meta'] ? json_response['meta']['total'] : update_definitions.size)})
1124
+ end
1125
+ print reset, "\n"
1126
+ end
1127
+ return 0
1128
+ rescue RestClient::Exception => e
1129
+ print_rest_exception(e, options)
1130
+ exit 1
1131
+ end
1132
+ end
1133
+
1134
+ def apply_cluster_update(args)
1135
+ options = {}
1136
+ optparse = MtnCloud::Cli::OptionParser.new do |opts|
1137
+ opts.banner = subcommand_usage("[system] [cluster] [updateDefinitionId]")
1138
+ opts.on('--dry-run-update', "Execute as a dry run — passes dryRun:true to the server, no changes applied.") do
1139
+ options[:dry_run_update] = true
1140
+ end
1141
+ build_standard_update_options(opts, options)
1142
+ opts.footer = <<-EOT
1143
+ Apply an update definition to a cluster component of a system.
1144
+ [system] is required. This is the name or id of a system.
1145
+ [cluster] is required. This is the name or id of the cluster.
1146
+ [updateDefinitionId] is required. This is the id of the update definition.
1147
+ EOT
1148
+ end
1149
+ optparse.parse!(args)
1150
+ verify_args!(args:args, optparse:optparse, count:3)
1151
+ connect(options)
1152
+ begin
1153
+ system = find_by_name_or_id(:systems, args[0])
1154
+ return 1 if system.nil?
1155
+ cluster = find_cluster_by_name_or_id(args[1])
1156
+ return 1 if cluster.nil?
1157
+ update_definition_id = args[2]
1158
+ payload = {}
1159
+ payload['dryRun'] = true if options[:dry_run_update]
1160
+ payload.deep_merge!(parse_passed_options(options))
1161
+ params = {}
1162
+ @systems_interface.setopts(options)
1163
+ if options[:dry_run]
1164
+ print_dry_run @systems_interface.dry.apply_cluster_update_definition(system['id'], cluster['id'], update_definition_id, payload, params)
1165
+ return
1166
+ end
1167
+ json_response = @systems_interface.apply_cluster_update_definition(system['id'], cluster['id'], update_definition_id, payload, params)
1168
+ render_response(json_response, options) do
1169
+ print_green_success "Update operation #{json_response['updateOperation']['id']} queued for cluster #{cluster['name']} on system #{system['name']}."
1170
+ end
1171
+ return 0
1172
+ rescue RestClient::Exception => e
1173
+ print_rest_exception(e, options)
1174
+ exit 1
1175
+ end
1176
+ end
1177
+
1178
+ private
1179
+
1180
+ def find_cluster_by_name_or_id(val)
1181
+ if val.to_s =~ /\A\d{1,}\Z/
1182
+ json_result = @api_client.clusters.get(val.to_i)
1183
+ cluster = json_result['cluster']
1184
+ if cluster.nil?
1185
+ print_red_alert "Cluster not found by id #{val}"
1186
+ return nil
1187
+ end
1188
+ cluster
1189
+ else
1190
+ json_result = @api_client.clusters.list({name: val})
1191
+ clusters = json_result['clusters']
1192
+ if clusters.nil? || clusters.empty?
1193
+ print_red_alert "Cluster not found by name '#{val}'"
1194
+ return nil
1195
+ elsif clusters.size > 1
1196
+ print_red_alert "#{clusters.size} clusters found by name '#{val}'. Use the id instead."
1197
+ return nil
1198
+ end
1199
+ clusters.first
1200
+ end
1201
+ end
1202
+
1203
+ end