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,1528 @@
1
+ require 'mtncloud/cli/cli_command'
2
+
3
+ # CLI command for the Service Catalog (Persona): Dashboard / Catalog / Inventory
4
+ # Inventory Items are the main actions, list, get, remove
5
+ # The add command adds to the cart and checkout places an order with the cart.
6
+ # The add-order command allows submitting a new order at once.
7
+ class MtnCloud::Cli::CatalogCommand
8
+ include MtnCloud::Cli::CliCommand
9
+ include MtnCloud::Cli::ProvisioningHelper
10
+ include MtnCloud::Cli::OptionSourceHelper
11
+
12
+ # set_command_name :'service-catalog'
13
+ set_command_name :'catalog'
14
+ set_command_description "Service Catalog Persona: View catalog and manage inventory"
15
+
16
+ # dashboard
17
+ register_subcommands :dashboard
18
+ # catalog (catalogItemTypes)
19
+ register_subcommands :'list-types' => :list_types
20
+ register_subcommands :'get-type' => :get_type
21
+ alias_subcommand :types, :'list-types'
22
+
23
+ # inventory (items) IS the main crud here
24
+ register_subcommands :list, :get, :remove
25
+
26
+ # cart / orders
27
+ register_subcommands :cart => :get_cart
28
+ register_subcommands :'update-cart' => :update_cart
29
+ register_subcommands :add
30
+ #register_subcommands :'update-cart-item' => :update_cart_item
31
+ register_subcommands :'remove-cart-item' => :remove_cart_item
32
+ register_subcommands :'clear-cart' => :clear_cart
33
+ register_subcommands :checkout
34
+
35
+ # create and submit cart in one action
36
+ # maybe call this place-order instead?
37
+ register_subcommands :'add-order' => :add_order
38
+
39
+ def default_sigdig
40
+ 4
41
+ end
42
+
43
+ def connect(opts)
44
+ @api_client = establish_remote_appliance_connection(opts)
45
+ @service_catalog_interface = @api_client.catalog
46
+ @instances_interface = @api_client.instances
47
+ @servers_interface = @api_client.servers # should not be required here!
48
+ @option_types_interface = @api_client.option_types
49
+ end
50
+
51
+ def handle(args)
52
+ handle_subcommand(args)
53
+ end
54
+
55
+ def dashboard(args)
56
+ params = {}
57
+ options = {}
58
+ optparse = MtnCloud::Cli::OptionParser.new do |opts|
59
+ opts.banner = subcommand_usage()
60
+ opts.add_hidden_option('--sigdig')
61
+ build_standard_get_options(opts, options, [:sigdig] || default_sigdig)
62
+ opts.footer = <<-EOT
63
+ View service catalog dashboard.
64
+ Provides an overview of available catalog item types, recent orders and inventory.
65
+ EOT
66
+ end
67
+ optparse.parse!(args)
68
+ verify_args!(args:args, optparse:optparse, max:0)
69
+ connect(options)
70
+
71
+ params.merge!(parse_list_options(options))
72
+ @service_catalog_interface.setopts(options)
73
+ if options[:dry_run]
74
+ print_dry_run @service_catalog_interface.dry.dashboard(params)
75
+ return
76
+ end
77
+ json_response = @service_catalog_interface.dashboard(params)
78
+ catalog_item_types = json_response['catalogItemTypes']
79
+ catalog_meta = json_response['catalogMeta'] || {}
80
+ recent_items = json_response['recentItems'] || {}
81
+ featured_items = json_response['featuredItems'] || []
82
+ inventory_items = json_response['inventoryItems'] || []
83
+ inventory_meta = json_response['inventoryMeta'] || {}
84
+ cart = json_response['cart'] || {}
85
+ cart_items = cart['items'] || []
86
+ cart_stats = cart['stats'] || {}
87
+ current_invoice = json_response['currentInvoice']
88
+
89
+ render_response(json_response, options, catalog_item_type_object_key) do
90
+ print_h1 "Catalog Dashboard", [], options
91
+ print cyan
92
+
93
+ # dashboard_columns = [
94
+ # {"TYPES" => lambda {|it| catalog_meta['total'] } },
95
+ # {"INVENTORY" => lambda {|it| inventory_items.size rescue '' } },
96
+ # {"CART" => lambda {|it| it['cart']['items'].size rescue '' } },
97
+ # ]
98
+ # print as_pretty_table([json_response], dashboard_columns, options)
99
+
100
+ print_h2 "Catalog Items"
101
+ print as_pretty_table(catalog_item_types, {
102
+ "NAME" => lambda {|it| it['name'] },
103
+ "DESCRIPTION" => lambda {|it| it['description'] },
104
+ "FEATURED" => lambda {|it| format_boolean it['featured'] },
105
+ }, options)
106
+ # print reset,"\n"
107
+
108
+ if recent_items && recent_items.size() > 0
109
+ print_h2 "Recently Ordered"
110
+ print as_pretty_table(recent_items, {
111
+ #"ID" => lambda {|it| it['id'] },
112
+ #"NAME" => lambda {|it| it['name'] },
113
+ "TYPE" => lambda {|it| it['type']['name'] rescue '' },
114
+ #"QTY" => lambda {|it| it['quantity'] },
115
+ "ORDER DATE" => lambda {|it| format_local_dt(it['orderDate']) },
116
+ # "STATUS" => lambda {|it| format_catalog_item_status(it) },
117
+ # "CONFIG" => lambda {|it| truncate_string(format_name_values(it['config']), 50) },
118
+ }, options)
119
+ # print reset,"\n"
120
+ end
121
+
122
+ if recent_items && recent_items.size() > 0
123
+ print_h2 "Inventory"
124
+ print as_pretty_table(inventory_items, {
125
+ "ID" => lambda {|it| it['id'] },
126
+ "NAME" => lambda {|it| it['name'] },
127
+ "TYPE" => lambda {|it| it['type']['name'] rescue '' },
128
+ #"QTY" => lambda {|it| it['quantity'] },
129
+ "ORDER DATE" => lambda {|it| format_local_dt(it['orderDate']) },
130
+ "STATUS" => lambda {|it| format_catalog_item_status(it) },
131
+ # "CONFIG" => lambda {|it| format_name_values(it['config']) },
132
+ }, options)
133
+ print_results_pagination(inventory_meta)
134
+ else
135
+ # print_h2 "Inventory"
136
+ # print cyan, "Inventory is empty", reset, "\n"
137
+ end
138
+
139
+ # print reset,"\n"
140
+
141
+ # problematic right now, invoice has all user activity, not just catalog
142
+ show_invoice = false
143
+ if current_invoice && show_invoice
144
+ print_h2 "Current Invoice"
145
+ print cyan
146
+ invoice_columns = {
147
+ # todo: invoice needs to return a currency!!!
148
+ "Compute" => lambda {|it| format_money(it['computePrice'], cart_stats['currency'], {sigdig:options[:sigdig] || default_sigdig}) },
149
+ "Storage" => lambda {|it| format_money(it['storagePrice'], cart_stats['currency'], {sigdig:options[:sigdig] || default_sigdig}) },
150
+ "Memory" => lambda {|it| format_money(it['memoryPrice'], cart_stats['currency'], {sigdig:options[:sigdig] || default_sigdig}) },
151
+ "Network" => lambda {|it| format_money(it['networkPrice'], cart_stats['currency'], {sigdig:options[:sigdig] || default_sigdig}) },
152
+ "Extra" => lambda {|it| format_money(it['extraPrice'], cart_stats['currency'], {sigdig:options[:sigdig] || default_sigdig}) },
153
+ "MTD" => lambda {|it| format_money(it['runningPrice'], cart_stats['currency'], {sigdig:options[:sigdig] || default_sigdig}) },
154
+ "Total (Projected)" => lambda {|it| format_money(it['totalPrice'], cart_stats['currency'], {sigdig:options[:sigdig] || default_sigdig}) },
155
+ #"Items" => lambda {|it| cart['items'].size },
156
+ # "Created" => lambda {|it| format_local_dt(it['dateCreated']) },
157
+ # "Updated" => lambda {|it| format_local_dt(it['lastUpdated']) },
158
+ }
159
+ invoice_columns.delete("Storage") unless current_invoice['storagePrice'] && current_invoice['storagePrice'].to_f > 0
160
+ invoice_columns.delete("Memory") unless current_invoice['memoryPrice'] && current_invoice['memoryPrice'].to_f > 0
161
+ invoice_columns.delete("Network") unless current_invoice['networkPrice'] && current_invoice['networkPrice'].to_f > 0
162
+ invoice_columns.delete("Extra") unless current_invoice['extraPrice'] && current_invoice['extraPrice'].to_f > 0
163
+ print as_pretty_table(current_invoice, invoice_columns.upcase_keys!, options)
164
+ end
165
+
166
+ show_cart = cart && cart['items'] && cart['items'].size() > 0
167
+ if show_cart
168
+ if cart
169
+
170
+ # get_cart([] + (options[:remote] ? ["-r",options[:remote]] : []))
171
+
172
+ print_h2 "Cart"
173
+ print cyan
174
+ if cart['items'].size() > 0
175
+ # cart_columns = {
176
+ # "Qty" => lambda {|it| cart['items'].sum {|cart_item| cart_item['quantity'] } },
177
+ # "Total" => lambda {|it|
178
+ # begin
179
+ # format_money(cart_stats['price'], cart_stats['currency'], {sigdig:options[:sigdig] || default_sigdig}) + (cart_stats['unit'].to_s.empty? ? "" : " / #{cart_stats['unit'] || 'month'}")
180
+ # rescue => ex
181
+ # raise ex
182
+ # # no cart stats eh?
183
+ # end
184
+ # },
185
+ # }
186
+ # print as_pretty_table(cart, cart_columns.upcase_keys!, options)
187
+
188
+
189
+ cart_item_columns = [
190
+ {"ID" => lambda {|it| it['id'] } },
191
+ #{"NAME" => lambda {|it| it['name'] } },
192
+ {"TYPE" => lambda {|it| it['type']['name'] rescue '' } },
193
+ #{"QTY" => lambda {|it| it['quantity'] } },
194
+ {"PRICE" => lambda {|it| it['price'] ? format_money(it['price'] , it['currency'], {sigdig:options[:sigdig] || default_sigdig}) : "No pricing configured" } },
195
+ {"STATUS" => lambda {|it|
196
+ status_string = format_catalog_item_status(it)
197
+ if it['errorMessage'].to_s != ""
198
+ status_string << " - #{it['errorMessage']}"
199
+ end
200
+ status_string
201
+ } },
202
+ # {"CONFIG" => lambda {|it|
203
+ # truncate_string(format_name_values(it['config']), 50)
204
+ # } },
205
+ ]
206
+ print as_pretty_table(cart_items, cart_item_columns)
207
+
208
+ print reset,"\n"
209
+ print cyan
210
+ if cart_stats['price']
211
+ puts "Total: " + format_money(cart_stats['price'], cart_stats['currency'], {sigdig:options[:sigdig] || default_sigdig}) + " / #{cart_stats['unit'].to_s.empty? ? 'month' : cart_stats['unit']}"
212
+ else
213
+ puts "Total: " + "No pricing configured"
214
+ end
215
+ # print reset,"\n"
216
+
217
+ else
218
+ print cyan, "Cart is empty", reset, "\n"
219
+ end
220
+ end
221
+
222
+ end
223
+
224
+ print reset,"\n"
225
+
226
+ end
227
+ return 0, nil
228
+ end
229
+
230
+ def list_types(args)
231
+ options = {}
232
+ params = {}
233
+ ref_ids = []
234
+ optparse = MtnCloud::Cli::OptionParser.new do |opts|
235
+ opts.banner = subcommand_usage("[search]")
236
+ opts.on( '--featured [on|off]', String, "Filter by featured" ) do |val|
237
+ params['featured'] = (val.to_s != 'false' && val.to_s != 'off')
238
+ end
239
+ build_standard_list_options(opts, options, [:sigdig])
240
+ opts.footer = "List available catalog item types."
241
+ end
242
+ optparse.parse!(args)
243
+ connect(options)
244
+ # verify_args!(args:args, optparse:optparse, count:0)
245
+ if args.count > 0
246
+ options[:phrase] = args.join(" ")
247
+ end
248
+ params.merge!(parse_list_options(options))
249
+ @service_catalog_interface.setopts(options)
250
+ if options[:dry_run]
251
+ print_dry_run @service_catalog_interface.dry.list_types(params)
252
+ return
253
+ end
254
+ json_response = @service_catalog_interface.list_types(params)
255
+ catalog_item_types = json_response[catalog_item_type_list_key]
256
+ render_response(json_response, options, catalog_item_type_list_key) do
257
+ print_h1 "Catalog Types", parse_list_subtitles(options), options
258
+ if catalog_item_types.empty?
259
+ print cyan,"No catalog item types found.",reset,"\n"
260
+ else
261
+ list_columns = catalog_item_type_column_definitions.upcase_keys!
262
+ #list_columns["Config"] = lambda {|it| truncate_string(it['config'], 100) }
263
+ print as_pretty_table(catalog_item_types, list_columns.upcase_keys!, options)
264
+ print_results_pagination(json_response)
265
+ end
266
+ print reset,"\n"
267
+ end
268
+ if catalog_item_types.empty?
269
+ return 1, "no catalog item types found"
270
+ else
271
+ return 0, nil
272
+ end
273
+ end
274
+
275
+ def get_type(args)
276
+ params = {}
277
+ options = {}
278
+ optparse = MtnCloud::Cli::OptionParser.new do |opts|
279
+ opts.banner = subcommand_usage("[name]")
280
+ build_standard_get_options(opts, options, [:sigdig])
281
+ opts.footer = <<-EOT
282
+ Get details about a specific catalog item type.
283
+ [name] is required. This is the name or id of a catalog item type.
284
+ EOT
285
+ end
286
+ optparse.parse!(args)
287
+ verify_args!(args:args, optparse:optparse, min:1)
288
+ connect(options)
289
+ id_list = parse_id_list(args)
290
+ return run_command_for_each_arg(id_list) do |arg|
291
+ _get_type(arg, params, options)
292
+ end
293
+ end
294
+
295
+ def _get_type(id, params, options)
296
+ catalog_item_type = nil
297
+ if id.to_s !~ /\A\d{1,}\Z/
298
+ catalog_item_type = find_catalog_item_type_by_name(id)
299
+ return 1, "catalog item type not found for #{id}" if catalog_item_type.nil?
300
+ id = catalog_item_type['id']
301
+ end
302
+ @service_catalog_interface.setopts(options)
303
+ if options[:dry_run]
304
+ print_dry_run @service_catalog_interface.dry.get_type(id, params)
305
+ return
306
+ end
307
+ json_response = @service_catalog_interface.get_type(id, params)
308
+ catalog_item_type = json_response[catalog_item_type_object_key]
309
+ # need to load by id to get optionTypes
310
+ # maybe do ?name=foo&includeOptionTypes=true
311
+ if catalog_item_type['optionTypes'].nil? && catalog_item_type['form'].nil?
312
+ catalog_item_type = find_catalog_item_type_by_id(catalog_item_type['id'])
313
+ return [1, "catalog item type not found"] if catalog_item_type.nil?
314
+ end
315
+ render_response(json_response, options, catalog_item_type_object_key) do
316
+ print_h1 "Catalog Type Details", [], options
317
+ print cyan
318
+ show_columns = catalog_item_type_column_definitions
319
+ print_description_list(show_columns, catalog_item_type)
320
+
321
+ form = catalog_item_type['form']
322
+ if form
323
+ # print_h2 "Configuration Options (Form: #{form['name']})"
324
+ print_h2 "Configuration Options"
325
+ form_inputs = (form['options'] || [])
326
+ if form['fieldGroups']
327
+ form['fieldGroups'].each { |field_group| form_inputs += (field_group['options'] || []) }
328
+ end
329
+ #print format_simple_option_types_table(form_inputs, options)
330
+ print format_option_types_table(form_inputs, options, 'config.customOptions')
331
+ # print reset,"\n"
332
+ else
333
+ # print cyan,"No form inputs found for this catalog item.","\n",reset
334
+ end
335
+
336
+ if catalog_item_type['optionTypes'] && catalog_item_type['optionTypes'].size > 0
337
+ print_h2 "Configuration Options"
338
+ #print format_simple_option_types_table(catalog_item_type['optionTypes'], options)
339
+ print format_option_types_table(catalog_item_type['optionTypes'], options, 'config.customOptions')
340
+ else
341
+ # print cyan,"No option types found for this catalog item.","\n",reset
342
+ end
343
+
344
+ print reset,"\n"
345
+ end
346
+ return 0, nil
347
+ end
348
+
349
+ # inventory actions
350
+
351
+ def list(args)
352
+ options = {}
353
+ params = {}
354
+ ref_ids = []
355
+ optparse = MtnCloud::Cli::OptionParser.new do |opts|
356
+ opts.banner = subcommand_usage("[search]")
357
+ opts.on('-t', '--type TYPE', String, "Catalog Item Type Name or ID") do |val|
358
+ type_id = val.to_s
359
+ end
360
+ build_standard_list_options(opts, options, [:sigdig])
361
+ opts.footer = "List catalog inventory."
362
+ end
363
+ optparse.parse!(args)
364
+ connect(options)
365
+ # verify_args!(args:args, optparse:optparse, count:0)
366
+ if args.count > 0
367
+ options[:phrase] = args.join(" ")
368
+ end
369
+ params.merge!(parse_list_options(options))
370
+ @service_catalog_interface.setopts(options)
371
+ if options[:dry_run]
372
+ print_dry_run @service_catalog_interface.dry.list_inventory(params)
373
+ return
374
+ end
375
+ json_response = @service_catalog_interface.list_inventory(params)
376
+ catalog_items = json_response[catalog_item_list_key]
377
+ render_response(json_response, options, catalog_item_list_key) do
378
+ print_h1 "Catalog Inventory", parse_list_subtitles(options), options
379
+ if catalog_items.empty?
380
+ print cyan,"No catalog items found.",reset,"\n"
381
+ else
382
+ list_columns = catalog_item_column_definitions.upcase_keys!
383
+ #list_columns["Config"] = lambda {|it| truncate_string(it['config'], 100) }
384
+ print as_pretty_table(catalog_items, list_columns.upcase_keys!, options)
385
+ print_results_pagination(json_response)
386
+ end
387
+ print reset,"\n"
388
+ end
389
+ if catalog_items.empty?
390
+ return 1, "no catalog items found"
391
+ else
392
+ return 0, nil
393
+ end
394
+ end
395
+
396
+ def get(args)
397
+ params = {}
398
+ options = {}
399
+ optparse = MtnCloud::Cli::OptionParser.new do |opts|
400
+ opts.banner = subcommand_usage("[item]")
401
+ opts.on( '-c', '--config', "Display raw config only. Default is YAML. Combine with -j for JSON instead." ) do
402
+ options[:show_config] = true
403
+ end
404
+ # opts.on('--no-config', "Do not display config content." ) do
405
+ # options[:no_config] = true
406
+ # end
407
+ build_standard_get_options(opts, options, [:sigdig])
408
+ opts.footer = <<-EOT
409
+ Get details about a specific catalog inventory item.
410
+ [item] is required. This is the name or id of a catalog inventory item.
411
+ EOT
412
+ end
413
+ optparse.parse!(args)
414
+ verify_args!(args:args, optparse:optparse, min:1)
415
+ connect(options)
416
+ id_list = parse_id_list(args)
417
+ return run_command_for_each_arg(id_list) do |arg|
418
+ _get(arg, params, options)
419
+ end
420
+ end
421
+
422
+ def _get(id, params, options)
423
+ catalog_item = find_catalog_item_by_name_or_id(id)
424
+ return 1, "catalog item not found for name or id '#{id}'" if catalog_item.nil?
425
+ @service_catalog_interface.setopts(options)
426
+ if options[:dry_run]
427
+ print_dry_run @service_catalog_interface.dry.get_inventory(catalog_item['id'], params)
428
+ return
429
+ end
430
+ # skip redundant request
431
+ json_response = {catalog_item_object_key => catalog_item}
432
+ # if id !~ /\A\d{1,}\Z/
433
+ # json_response = @service_catalog_interface.get_inventory(catalog_item['id'], params)
434
+ # end
435
+ catalog_item = json_response[catalog_item_object_key]
436
+ item_config = catalog_item['config']
437
+ item_type_code = catalog_item['type']['type'].to_s.downcase rescue nil
438
+ item_instance = catalog_item['instance']
439
+ item_app = catalog_item['app']
440
+ item_execution = catalog_item['execution']
441
+ render_response(json_response, options, catalog_item_object_key) do
442
+ print_h1 "Catalog Item Details", [], options
443
+ print cyan
444
+ show_columns = catalog_item_column_definitions
445
+ # show_columns.delete("Status") if catalog_item['status'].to_s.lowercase == 'ORDERED'
446
+ show_columns.delete("Status") if item_instance || item_app || item_execution
447
+ print_description_list(show_columns, catalog_item)
448
+
449
+ if item_config && !item_config.empty?
450
+ # print_h2 "Configuration", options
451
+ # print cyan
452
+ # print as_description_list(item_config, item_config.keys, options)
453
+ # print "\n", reset
454
+ end
455
+
456
+ if item_type_code == 'instance'
457
+ if item_instance
458
+ print_h2 "Instance", options
459
+ print cyan
460
+ item_instance_columns = [
461
+ {"ID" => lambda {|it| it['id'] } },
462
+ {"NAME" => lambda {|it| it['name'] } },
463
+ {"STATUS" => lambda {|it| format_instance_status(it) } },
464
+ ]
465
+ #print as_description_list(item_instance, item_instance_columns, options)
466
+ print as_pretty_table([item_instance], item_instance_columns, options)
467
+ # print "\n", reset
468
+ else
469
+ print "\n"
470
+ print yellow, "No instance found", reset, "\n"
471
+ end
472
+ end
473
+
474
+ if item_type_code == 'app' || item_type_code == 'blueprint' || item_type_code == 'apptemplate'
475
+ if item_app
476
+ print_h2 "App", options
477
+ print cyan
478
+ item_app_columns = [
479
+ {"ID" => lambda {|it| it['id'] } },
480
+ {"NAME" => lambda {|it| it['name'] } },
481
+ {"STATUS" => lambda {|it| format_app_status(it) } },
482
+ ]
483
+ #print as_description_list(item_app, item_app_columns, options)
484
+ print as_pretty_table([item_app], item_app_columns, options)
485
+ # print "\n", reset
486
+ else
487
+ print "\n"
488
+ print yellow, "No app found", reset, "\n"
489
+ end
490
+ end
491
+
492
+ if item_type_code == 'workflow' || item_type_code == 'operationalworkflow' || item_type_code == 'taskset'
493
+ if item_execution
494
+ print_h2 "Workflow Results", options
495
+ print cyan
496
+ item_workflow_columns = [
497
+ {"EXECUTION ID" => lambda {|it| item_execution ? item_execution['id'] : '' } },
498
+ {"CONTEXT TYPE" => lambda {|it| it['name'] } },
499
+ {"RESOURCE" => lambda {|it| (it['targets'] ? it['targets'].collect { |target| target['name'] }.join(', ') : '') rescue '' } },
500
+ {"STATUS" => lambda {|it| item_execution ? format_job_execution_status(item_execution) : 'N/A' } },
501
+ ]
502
+ #print as_description_list(catalog_item, item_workflow_columns, options)
503
+ print as_pretty_table([catalog_item], item_workflow_columns, options)
504
+ # print "\n", reset
505
+ else
506
+ print "\n"
507
+ print yellow, "No execution found", reset, "\n"
508
+ end
509
+ end
510
+
511
+ print reset,"\n"
512
+ end
513
+ return 0, nil
514
+ end
515
+
516
+ def get_cart(args)
517
+ params = {}
518
+ options = {}
519
+ optparse = MtnCloud::Cli::OptionParser.new do |opts|
520
+ opts.banner = subcommand_usage()
521
+ opts.on('-a', '--details', "Display all details: item configuration." ) do
522
+ options[:details] = true
523
+ end
524
+ build_standard_get_options(opts, options, [:sigdig])
525
+ opts.footer = <<-EOT
526
+ Get details of current cart and the items in it.
527
+ Exits non-zero if cart is empty.
528
+ EOT
529
+ end
530
+ optparse.parse!(args)
531
+ verify_args!(args:args, optparse:optparse, count:0)
532
+ connect(options)
533
+
534
+ @service_catalog_interface.setopts(options)
535
+ if options[:dry_run]
536
+ print_dry_run @service_catalog_interface.dry.get_cart(params)
537
+ return 0, nil
538
+ end
539
+ # skip extra query, list has same data as show right now
540
+ json_response = @service_catalog_interface.get_cart(params)
541
+ cart = json_response['cart']
542
+ cart_items = cart['items'] || []
543
+ cart_stats = cart['stats'] || {}
544
+ render_response(json_response, options, 'cart') do
545
+ print_h1 "Catalog Cart", [], options
546
+ print_order_details(cart, options)
547
+ end
548
+ if cart_items.empty?
549
+ return 1, "cart is empty"
550
+ else
551
+ return 0, nil
552
+ end
553
+ end
554
+
555
+ def update_cart(args)
556
+ options = {}
557
+ params = {}
558
+ optparse = MtnCloud::Cli::OptionParser.new do |opts|
559
+ opts.banner = subcommand_usage("--name [name]")
560
+ opts.on('--name [NAME]', String, "Set an optional name for your catalog order") do |val|
561
+ options[:options]['name'] = val.to_s
562
+ end
563
+ build_standard_update_options(opts, options, [:payloads, :sigdig])
564
+ opts.footer = <<-EOT
565
+ Update your cart settings, such as name.
566
+ EOT
567
+ end
568
+ optparse.parse!(args)
569
+ verify_args!(args:args, optparse:optparse, count:0)
570
+ connect(options)
571
+ # fetch current cart
572
+ # cart = @service_catalog_interface.get_cart()['cart']
573
+ update_cart_object_key = 'order'
574
+ parse_payload(options, update_cart_object_key) do |payload|
575
+ payload.deep_merge!({update_cart_object_key => parse_passed_options(options)})
576
+ if payload[update_cart_object_key].empty? # || options[:no_prompt]
577
+ raise_command_error "Specify at least one option to update.\n#{optparse}"
578
+ end
579
+ end
580
+ execute_api(@service_catalog_interface, :update_cart, [params], options, "cart") do |json_response|
581
+ #cart = json_response["cart"]
582
+ print_green_success "Updated cart"
583
+ get_cart([] + (options[:remote] ? ["-r",options[:remote]] : []))
584
+ end
585
+ end
586
+
587
+ def add(args)
588
+ options = {}
589
+ params = {}
590
+ type_id = nil
591
+ workflow_context = nil
592
+ workflow_target = nil
593
+ quantity = nil
594
+ optparse = MtnCloud::Cli::OptionParser.new do |opts|
595
+ opts.banner = subcommand_usage("[type] [options]")
596
+ opts.on('-t', '--type TYPE', String, "Catalog Item Type Name or ID") do |val|
597
+ type_id = val.to_s
598
+ end
599
+ opts.on('--quantity QUANTITY', String, "Quantity for this catalog item. Will be overridden to 1 if quantity not allowed.") do |val|
600
+ quantity = val.to_s
601
+ end
602
+ opts.on('--validate','--validate', "Validate Only. Validates the configuration and skips adding the item.") do
603
+ options[:validate_only] = true
604
+ params['validate'] = true
605
+ end
606
+ opts.on('--context [instance|server]', String, "Context Type for operational workflow types") do |val|
607
+ workflow_context = val.to_s
608
+ end
609
+ opts.on('--target ID', String, "Target Resource (Instance or Server) for operational workflow types") do |val|
610
+ workflow_target = val.to_s
611
+ end
612
+ opts.add_hidden_option('--sigdig')
613
+ build_standard_add_many_options(opts, options, [:sigdig])
614
+ opts.footer = <<-EOT
615
+ Add an item to your cart
616
+ [type] is required, this is name or id of a catalog item type.
617
+ Catalog item types may require additional configuration.
618
+ EOT
619
+ end
620
+ optparse.parse!(args)
621
+ verify_args!(args:args, optparse:optparse, min:0)
622
+ connect(options)
623
+ if args.count > 0
624
+ type_id = args.join(" ")
625
+ end
626
+ add_item_object_key = 'item'
627
+ parse_payload(options, add_item_object_key) do |payload|
628
+ payload.deep_merge!({add_item_object_key => parse_passed_options(options)})
629
+ # prompt for Type
630
+ if type_id
631
+ catalog_item_type = find_catalog_item_type_by_name_or_id(type_id)
632
+ return [1, "catalog item type not found"] if catalog_item_type.nil?
633
+ elsif
634
+ catalog_type_option_type = {'fieldName' => 'type', 'fieldLabel' => 'Type', 'type' => 'select', 'optionSource' => lambda { |api_client, api_params|
635
+ # @options_interface.options_for_source("licenseTypes", {})['data']
636
+ @service_catalog_interface.list_types({max:10000})['catalogItemTypes'].collect {|it|
637
+ {'name' => it['name'], 'value' => it['id']}
638
+ } }, 'required' => true, 'description' => 'Catalog Item Type name or id'}
639
+ type_id = MtnCloud::Cli::OptionTypes.prompt([catalog_type_option_type], options[:options], @api_client, options[:params])['type']
640
+ catalog_item_type = find_catalog_item_type_by_name_or_id(type_id.to_s)
641
+ return [1, "catalog item type not found"] if catalog_item_type.nil?
642
+ end
643
+ # use name instead of id
644
+ payload[add_item_object_key]['type'] = {'name' => catalog_item_type['name']}
645
+ #payload[add_item_object_key]['type'] = {'id' => catalog_item_type['id']}
646
+
647
+ if quantity
648
+ payload[add_item_object_key].deep_merge!({'quantity' => quantity})
649
+ else
650
+ if catalog_item_type['allowQuantity']
651
+ quantity_option_type = {'fieldName' => 'quantity', 'fieldLabel' => 'Quantity', 'type' => 'number', 'defaultValue' => 1, 'required' => true, 'displayOrder' => 1}
652
+ quantity_prompt = MtnCloud::Cli::OptionTypes.prompt( [quantity_option_type], options[:options], @api_client, options[:params])['quantity']
653
+ payload[add_item_object_key].deep_merge!({'quantity' => quantity_prompt})
654
+ end
655
+ end
656
+
657
+ # this is silly, need to load by id to get optionTypes
658
+ # maybe do ?name=foo&includeOptionTypes=true
659
+ if catalog_item_type['optionTypes'].nil? && catalog_item_type['form'].nil?
660
+ catalog_item_type = find_catalog_item_type_by_id(catalog_item_type['id'])
661
+ return [1, "catalog item type not found"] if catalog_item_type.nil?
662
+ end
663
+
664
+ if catalog_item_type['formType'] == 'form'
665
+ # prompt for form options
666
+ if catalog_item_type['form'].nil?
667
+ raise_command_error "No form found for catalog item type '#{catalog_item_type['name']}'"
668
+ end
669
+ # use the new PromptHelper method prompt_form()
670
+ config_prompt = prompt_form(catalog_item_type['form'], options.merge({:context_map => {'config.customOptions' => 'config'}, :api_params => construct_catalog_api_params(catalog_item_type)}))['config']
671
+ payload[add_item_object_key].deep_merge!({'config' => config_prompt})
672
+ else
673
+ # prompt for optionTypes
674
+ catalog_option_types = catalog_item_type['optionTypes']
675
+ if catalog_option_types.nil?
676
+ #raise_command_error "No options found for catalog item type '#{catalog_item_type['name']}'"
677
+ catalog_option_types = []
678
+ end
679
+ # instead of config.customOptions just use config...
680
+ catalog_option_types = catalog_option_types.collect {|it|
681
+ it['fieldContext'] = 'config'
682
+ it
683
+ }
684
+ if catalog_option_types && !catalog_option_types.empty?
685
+ api_params = construct_catalog_api_params(catalog_item_type)
686
+ config_prompt = MtnCloud::Cli::OptionTypes.prompt(catalog_option_types, options[:options], @api_client, api_params, options[:no_prompt], false, false, true)['config']
687
+ payload[add_item_object_key].deep_merge!({'config' => config_prompt})
688
+ end
689
+ end
690
+
691
+ if workflow_context
692
+ payload[add_item_object_key]['context'] = workflow_context
693
+ else
694
+ # the catalog item type determines if context selection is required
695
+ # only blank string means you can choose? err
696
+ if catalog_item_type['context'] == ''
697
+ context_option_type = {'fieldName' => 'context', 'fieldLabel' => 'Context Type', 'type' => 'select', 'optionSource' => lambda { |api_client, api_params|
698
+ [{'name' => "none", 'value' => "appliance"}, {'name' => "Instance", 'value' => "instance"}, {'name' => "Server", 'value' => "server"}]
699
+ }, 'required' => true, 'description' => 'Context for operational workflow, determines target type', 'defaultValue' => 'instance'}
700
+ workflow_context = MtnCloud::Cli::OptionTypes.prompt([context_option_type], options[:options], @api_client, options[:params])['context']
701
+ elsif !catalog_item_type['context'].nil?
702
+ workflow_context = catalog_item_type['context']
703
+ end
704
+ payload[add_item_object_key]['context'] = workflow_context if workflow_context
705
+ end
706
+
707
+ if workflow_target
708
+ payload[add_item_object_key]['targets'] = [{id: workflow_target}]
709
+ else
710
+ # prompt for Resource (target)
711
+ if workflow_context == 'instance'
712
+ target_option_type = {'fieldName' => 'target', 'fieldLabel' => 'Resource (Instance)', 'type' => 'select', 'optionSource' => lambda { |api_client, api_params|
713
+ # todo: @instances_interface should not be required here
714
+ # @options_interface.options_for_source("instances", {})['data']
715
+ @instances_interface.list({max:10000})['instances'].collect {|it|
716
+ {'name' => it['name'], 'value' => it['id']}
717
+ } }, 'required' => true, 'description' => 'Target Instance'}
718
+ workflow_target = MtnCloud::Cli::OptionTypes.prompt([target_option_type], options[:options], @api_client, options[:params])['target']
719
+ payload[add_item_object_key]['targets'] = [{id: workflow_target}]
720
+ payload[add_item_object_key].delete('target')
721
+ elsif workflow_context == 'server'
722
+ target_option_type = {'fieldName' => 'target', 'fieldLabel' => 'Resource (Server)', 'type' => 'select', 'optionSource' => lambda { |api_client, api_params|
723
+ # todo: @servers_interface should not be required here
724
+ # @options_interface.options_for_source("searchServers", {})['data']
725
+ @servers_interface.list({max:10000})['servers'].collect {|it|
726
+ {'name' => it['name'], 'value' => it['id']}
727
+ } }, 'required' => true, 'description' => 'Target Server'}
728
+ workflow_target = MtnCloud::Cli::OptionTypes.prompt([target_option_type], options[:options], @api_client, options[:params])['target']
729
+ payload[add_item_object_key]['targets'] = [{id: workflow_target}]
730
+ payload[add_item_object_key].delete('target')
731
+ end
732
+ end
733
+ end
734
+ execute_api(@service_catalog_interface, :create_cart_item, [params], options, 'item') do |json_response|
735
+ cart_item = json_response['item']
736
+ if options[:validate_only]
737
+ if json_response['success']
738
+ print_h2 "Validated Cart Item", [], options
739
+ cart_item_columns = {
740
+ "Type" => lambda {|it| it['type']['name'] rescue '' },
741
+ #"Qty" => lambda {|it| it['quantity'] },
742
+ "Price" => lambda {|it| it['price'] ? format_money(it['price'] , it['currency'], {sigdig:options[:sigdig] || default_sigdig}) : "No pricing configured" },
743
+ "Status" => lambda {|it|
744
+ status_string = format_catalog_item_status(it)
745
+ if it['errorMessage'].to_s != ""
746
+ status_string << " - #{it['errorMessage']}"
747
+ end
748
+ status_string
749
+ },
750
+ #"Config" => lambda {|it| truncate_string(format_name_values(it['config']), 50) }
751
+ }
752
+ print as_pretty_table([cart_item], cart_item_columns.upcase_keys!)
753
+ print reset, "\n"
754
+ print_green_success(json_response['msg'] || "Item is valid")
755
+ print reset, "\n"
756
+ else
757
+ # not needed because it will be http 400
758
+ print_rest_errors(json_response, options)
759
+ end
760
+ else
761
+ print_green_success "Added item to cart"
762
+ get_cart([] + (options[:remote] ? ["-r",options[:remote]] : []))
763
+ end
764
+ end
765
+ end
766
+
767
+ def update_cart_item(args)
768
+ #todo
769
+ raise_command_error "Not yet implemented"
770
+ end
771
+
772
+ def remove_cart_item(args)
773
+ options = {}
774
+ params = {}
775
+ optparse = MtnCloud::Cli::OptionParser.new do |opts|
776
+ opts.banner = subcommand_usage("[id]")
777
+ build_standard_remove_options(opts, options, [:sigdig])
778
+ opts.footer = <<-EOT
779
+ Delete an item from the cart.
780
+ [id] is required. This is the id of a cart item (also matches on type)
781
+ EOT
782
+ end
783
+ optparse.parse!(args)
784
+ verify_args!(args:args, optparse:optparse, max:1)
785
+ connect(options)
786
+
787
+ # fetch current cart
788
+ cart = @service_catalog_interface.get_cart()['cart']
789
+ cart_items = cart['items'] || []
790
+ cart_item = nil
791
+ item_id = args[0]
792
+ # match cart item on id OR type.name
793
+ if item_id.nil?
794
+ cart_item_option_type = {'fieldName' => 'id', 'fieldLabel' => 'Cart Item', 'type' => 'select', 'optionSource' => lambda { |api_client, api_params|
795
+ # cart_items.collect {|ci| {'name' => ci['name'], 'value' => ci['id']} }
796
+ cart_items.collect {|ci| {'name' => (ci['type']['name'] rescue ci['name']), 'value' => ci['id']} }
797
+ }, 'required' => true, 'description' => 'Cart Item to be removed'}
798
+ item_id = MtnCloud::Cli::OptionTypes.prompt([cart_item_option_type], options[:options], @api_client)['id']
799
+ end
800
+ if item_id
801
+ cart_item = cart_items.find { |ci| ci['id'] == item_id.to_i }
802
+ if cart_item.nil?
803
+ matching_items = cart_items.select { |ci| (ci['type']['name'] rescue nil) == item_id.to_s }
804
+ if matching_items.size > 1
805
+ print_red_alert "#{matching_items.size} cart items matched '#{item_id}'"
806
+ cart_item_columns = [
807
+ {"ID" => lambda {|it| it['id'] } },
808
+ #{"NAME" => lambda {|it| it['name'] } },
809
+ {"Type" => lambda {|it| it['type']['name'] rescue '' } },
810
+ #{"Qty" => lambda {|it| it['quantity'] } },
811
+ {"Price" => lambda {|it| it['price'] ? format_money(it['price'] , it['currency'], {sigdig:options[:sigdig] || default_sigdig}) : "No pricing configured" } },
812
+ ]
813
+ puts_error as_pretty_table(matching_items, cart_item_columns, {color:red})
814
+ print_red_alert "Try using ID instead"
815
+ print reset,"\n"
816
+ return nil
817
+ end
818
+ cart_item = matching_items[0]
819
+ end
820
+ end
821
+ if cart_item.nil?
822
+ err = "Cart item not found for '#{item_id}'"
823
+ print_red_alert err
824
+ return 1, err
825
+ end
826
+
827
+ @service_catalog_interface.setopts(options)
828
+ if options[:dry_run]
829
+ print_dry_run @service_catalog_interface.dry.destroy_cart_item(cart_item['id'], params)
830
+ return
831
+ end
832
+ unless options[:yes] || MtnCloud::Cli::OptionTypes.confirm("Are you sure you want to remove item '#{cart_item['type']['name'] rescue cart_item['id']}' from your cart?")
833
+ return 9, "aborted command"
834
+ end
835
+ json_response = @service_catalog_interface.destroy_cart_item(cart_item['id'], params)
836
+ render_response(json_response, options) do
837
+ print_green_success "Removed item from cart"
838
+ get_cart([] + (options[:remote] ? ["-r",options[:remote]] : []))
839
+ end
840
+ return 0, nil
841
+ end
842
+
843
+ def clear_cart(args)
844
+ options = {}
845
+ params = {}
846
+ optparse = MtnCloud::Cli::OptionParser.new do |opts|
847
+ opts.banner = subcommand_usage("--name [name]")
848
+ build_standard_remove_options(opts, options, [:sigdig])
849
+ opts.footer = <<-EOT
850
+ Clear your cart.
851
+ This will empty the cart, deleting all items.
852
+ EOT
853
+ end
854
+ optparse.parse!(args)
855
+ verify_args!(args:args, optparse:optparse, count:0)
856
+ connect(options)
857
+ # fetch current cart
858
+ # cart = @service_catalog_interfaceg.get_cart()['cart']
859
+ params.merge!(parse_query_options(options))
860
+ @service_catalog_interface.setopts(options)
861
+ if options[:dry_run]
862
+ print_dry_run @service_catalog_interface.dry.clear_cart(params)
863
+ return
864
+ end
865
+ unless options[:yes] || MtnCloud::Cli::OptionTypes.confirm("Are you sure you want to clear your cart?")
866
+ return 9, "aborted command"
867
+ end
868
+ json_response = @service_catalog_interface.clear_cart(params)
869
+ render_response(json_response, options, 'cart') do
870
+ print_green_success "Cleared cart"
871
+ get_cart([] + (options[:remote] ? ["-r",options[:remote]] : []))
872
+ end
873
+ return 0, nil
874
+ end
875
+
876
+ def checkout(args)
877
+ options = {}
878
+ params = {}
879
+ optparse = MtnCloud::Cli::OptionParser.new do |opts|
880
+ opts.banner = subcommand_usage()
881
+ build_standard_add_options(opts, options, [:auto_confirm, :sigdig])
882
+ opts.footer = <<-EOT
883
+ Checkout to complete your cart and place an order.
884
+ EOT
885
+ end
886
+ optparse.parse!(args)
887
+ verify_args!(args:args, optparse:optparse, count:0)
888
+ connect(options)
889
+ # fetch current cart
890
+ # cart = @service_catalog_interface.get_cart()['cart']
891
+ params.merge!(parse_query_options(options))
892
+ payload = {}
893
+ if options[:payload]
894
+ payload = options[:payload]
895
+ end
896
+ update_cart_object_key = 'order'
897
+ passed_options = parse_passed_options(options)
898
+ payload.deep_merge!({update_cart_object_key => passed_options}) unless passed_options.empty?
899
+
900
+ @service_catalog_interface.setopts(options)
901
+ if options[:dry_run]
902
+ print_dry_run @service_catalog_interface.dry.checkout(params, payload)
903
+ return
904
+ end
905
+
906
+ # checkout
907
+ print_h1 "Checkout"
908
+
909
+ # review cart
910
+ # should load this first, but do this to avoid double load
911
+ cmd_result, cmd_err = get_cart(["--thin"] + (options[:remote] ? ["-r",options[:remote]] : []))
912
+ if cmd_result != 0
913
+ print_red_alert "You must add items before you can checkout. Try `catalog add`"
914
+ return cmd_result, cmd_err
915
+ end
916
+
917
+ unless options[:yes] || MtnCloud::Cli::OptionTypes.confirm("Are you sure you want to checkout and place an order?")
918
+ return 9, "aborted command"
919
+ end
920
+ json_response = @service_catalog_interface.checkout(params, payload)
921
+ render_response(json_response, options) do
922
+ print_green_success "Order placed"
923
+ # ok so this is delayed because list does not return all statuses right now..
924
+ #list([] + (options[:remote] ? ["-r",options[:remote]] : []))
925
+ end
926
+ return 0, nil
927
+ end
928
+
929
+ def add_order(args)
930
+ options = {}
931
+ params = {}
932
+ type_id = nil
933
+ workflow_context = nil
934
+ workflow_target = nil
935
+ quantity = nil
936
+ optparse = MtnCloud::Cli::OptionParser.new do |opts|
937
+ opts.banner = subcommand_usage("[type] [options]")
938
+ opts.on('-t', '--type TYPE', String, "Catalog Item Type Name or ID") do |val|
939
+ type_id = val.to_s
940
+ end
941
+ opts.on('--quantity QUANTITY', String, "Quantity for this catalog item. Will be overridden to 1 if quantity not allowed.") do |val|
942
+ quantity = val.to_s
943
+ end
944
+ opts.on('--validate','--validate', "Validate Only. Validates the configuration and skips creating the order.") do
945
+ options[:validate_only] = true
946
+ params['validate'] = true
947
+ end
948
+ opts.on('-a', '--details', "Display all details: item configuration." ) do
949
+ options[:details] = true
950
+ end
951
+ opts.on('--context [instance|server]', String, "Context Type for operational workflow types") do |val|
952
+ workflow_context = val.to_s
953
+ end
954
+ opts.on('--target ID', String, "Target Resource (Instance or Server) for operational workflow types") do |val|
955
+ workflow_target = val.to_s
956
+ end
957
+ build_standard_add_options(opts, options, [:payloads, :sigdig])
958
+ opts.footer = <<-EOT
959
+ Place an order for new inventory.
960
+ This allows creating a new order without using the cart.
961
+ The order must contain one or more items, each with a valid type and configuration.
962
+ By default the order is placed right away.
963
+ Use the --validate option to validate and review the order without actually placing it.
964
+ EOT
965
+ end
966
+ optparse.parse!(args)
967
+ verify_args!(args:args, optparse:optparse, min:0)
968
+ connect(options)
969
+ if args.count > 0
970
+ type_id = args.join(" ")
971
+ end
972
+ payload = {}
973
+ order_object_key = 'order'
974
+ parse_payload(options, order_object_key) do |payload|
975
+ payload.deep_merge!({order_object_key => {}})
976
+ # Prompt for 1-N Types
977
+ # still_prompting = options[:no_prompt] != true
978
+ still_prompting = true
979
+ available_catalog_item_types = @service_catalog_interface.list_types({max:10000})['catalogItemTypes'].collect {|it|
980
+ {'name' => it['name'], 'value' => it['id']}
981
+ }
982
+ type_cache = {} # prevent repeat lookups
983
+ while still_prompting do
984
+ item_payload = {}
985
+ # prompt for Type
986
+ if type_id
987
+ catalog_item_type = type_cache[type_id.to_s] || find_catalog_item_type_by_name_or_id(type_id)
988
+ return [1, "catalog item type not found"] if catalog_item_type.nil?
989
+ elsif
990
+ type_id = MtnCloud::Cli::OptionTypes.prompt([{'fieldName' => 'type', 'fieldLabel' => 'Type', 'type' => 'select', 'selectOptions' => available_catalog_item_types, 'required' => true, 'description' => 'Catalog Item Type name or id'}], options[:options], @api_client, options[:params])['type']
991
+ catalog_item_type = type_cache[type_id.to_s] || find_catalog_item_type_by_name_or_id(type_id.to_s)
992
+ return [1, "catalog item type not found"] if catalog_item_type.nil?
993
+ end
994
+ type_cache[type_id.to_s] = catalog_item_type
995
+ # use name instead of id
996
+ item_payload['type'] = {'name' => catalog_item_type['name']}
997
+ #payload[add_item_object_key]['type'] = {'id' => catalog_item_type['id']}
998
+
999
+ if quantity
1000
+ item_payload.deep_merge!({'quantity' => quantity})
1001
+ else
1002
+ if catalog_item_type['allowQuantity']
1003
+ quantity_option_type = {'fieldName' => 'quantity', 'fieldLabel' => 'Quantity', 'type' => 'number', 'defaultValue' => 1, 'required' => true, 'displayOrder' => 1}
1004
+ quantity_prompt = MtnCloud::Cli::OptionTypes.prompt( [quantity_option_type], options[:options], @api_client, options[:params])['quantity']
1005
+ item_payload.deep_merge!({'quantity' => quantity_prompt})
1006
+ end
1007
+ end
1008
+
1009
+
1010
+ # this is silly, need to load by id to get optionTypes
1011
+ # maybe do ?name=foo&includeOptionTypes=true
1012
+ if catalog_item_type['optionTypes'].nil? && catalog_item_type['form'].nil?
1013
+ catalog_item_type = find_catalog_item_type_by_id(catalog_item_type['id'])
1014
+ return [1, "catalog item type not found"] if catalog_item_type.nil?
1015
+ end
1016
+
1017
+ if catalog_item_type['formType'] == 'form'
1018
+ # prompt for form options
1019
+ if catalog_item_type['form'].nil?
1020
+ raise_command_error "No form found for catalog item type '#{catalog_item_type['name']}'"
1021
+ end
1022
+ # use the new PromptHelper method prompt_form()
1023
+ config_prompt = prompt_form(catalog_item_type['form'], options.merge({:context_map => {'config.customOptions' => 'config'}, :api_params => construct_catalog_api_params(catalog_item_type)}))['config']
1024
+ item_payload.deep_merge!({'config' => config_prompt})
1025
+ else
1026
+ # prompt for optionTypes
1027
+ catalog_option_types = catalog_item_type['optionTypes']
1028
+ # instead of config.customOptions just use config...
1029
+ catalog_option_types = catalog_option_types.collect {|it|
1030
+ it['fieldContext'] = nil
1031
+ it['fieldContext'] = 'config'
1032
+ it
1033
+ }
1034
+ if catalog_option_types && !catalog_option_types.empty?
1035
+ api_params = construct_catalog_api_params(catalog_item_type)
1036
+ config_prompt = MtnCloud::Cli::OptionTypes.prompt(catalog_option_types, options[:options], @api_client, api_params, options[:no_prompt], false, false, true)['config']
1037
+ item_payload.deep_merge!({'config' => config_prompt})
1038
+ end
1039
+ end
1040
+
1041
+ if workflow_context
1042
+ item_payload['context'] = workflow_context
1043
+ else
1044
+ # the catalog item type determines if context selection is required
1045
+ # only blank string means you can choose? err
1046
+ if catalog_item_type['context'] == ''
1047
+ context_option_type = {'fieldName' => 'context', 'fieldLabel' => 'Context Type', 'type' => 'select', 'optionSource' => lambda { |api_client, api_params|
1048
+ [{'name' => "Instance", 'value' => "instance"}, {'name' => "Server", 'value' => "server"}]
1049
+ }, 'required' => true, 'description' => 'Context for operational workflow, determines target type', 'defaultValue' => 'instance'}
1050
+ workflow_context = MtnCloud::Cli::OptionTypes.prompt([context_option_type], options[:options], @api_client, options[:params])['context']
1051
+ elsif !catalog_item_type['context'].nil?
1052
+ workflow_context = catalog_item_type['context']
1053
+ end
1054
+ item_payload['context'] = workflow_context if workflow_context
1055
+ end
1056
+
1057
+ if workflow_target
1058
+ item_payload['targets'] = [{id: workflow_target}]
1059
+ else
1060
+ # prompt for Resource (target)
1061
+ if workflow_context == 'instance'
1062
+ target_option_type = {'fieldName' => 'target', 'fieldLabel' => 'Resource (Instance)', 'type' => 'select', 'optionSource' => lambda { |api_client, api_params|
1063
+ # todo: @instances_interface should not be required here
1064
+ # @options_interface.options_for_source("instances", {})['data']
1065
+ @instances_interface.list({max:10000})['instances'].collect {|it|
1066
+ {'name' => it['name'], 'value' => it['id']}
1067
+ } }, 'required' => true, 'description' => 'Target Instance'}
1068
+ workflow_target = MtnCloud::Cli::OptionTypes.prompt([target_option_type], options[:options], @api_client, options[:params])['target']
1069
+ item_payload['targets'] = [{id: workflow_target}]
1070
+ item_payload.delete('target')
1071
+ elsif workflow_context == 'server'
1072
+ target_option_type = {'fieldName' => 'target', 'fieldLabel' => 'Resource (Server)', 'type' => 'select', 'optionSource' => lambda { |api_client, api_params|
1073
+ # todo: @servers_interface should not be required here
1074
+ # @options_interface.options_for_source("searchServers", {})['data']
1075
+ @servers_interface.list({max:10000})['servers'].collect {|it|
1076
+ {'name' => it['name'], 'value' => it['id']}
1077
+ } }, 'required' => true, 'description' => 'Target Server'}
1078
+ workflow_target = MtnCloud::Cli::OptionTypes.prompt([target_option_type], options[:options], @api_client, options[:params])['target']
1079
+ item_payload['targets'] = [{id: workflow_target}]
1080
+ item_payload.delete('target')
1081
+ end
1082
+ end
1083
+
1084
+ payload[order_object_key]['items'] ||= []
1085
+ payload[order_object_key]['items'] << item_payload
1086
+
1087
+ if options[:no_prompt]
1088
+ still_prompting = false
1089
+ else
1090
+ if MtnCloud::Cli::OptionTypes.confirm("Add another item?", {default: false})
1091
+ still_prompting = true
1092
+ # clear values for subsequent items, should just use for a different fieldContext instead..
1093
+ type_id = nil
1094
+ options[:options] = {}
1095
+ else
1096
+ still_prompting = false
1097
+ end
1098
+ end
1099
+
1100
+ end
1101
+ end
1102
+ execute_api(@service_catalog_interface, :create_order, [params], options, "order") do |json_response|
1103
+ order = json_response['order'] || json_response['cart']
1104
+ if options[:validate_only]
1105
+ if json_response['success']
1106
+ print_h2 "Review Order", [], options
1107
+ print_order_details(order, options)
1108
+ print_green_success(json_response['msg'] || "Order is valid")
1109
+ print reset, "\n"
1110
+ else
1111
+ # not needed because it will be http 400
1112
+ print_rest_errors(json_response, options)
1113
+ end
1114
+ else
1115
+ print_green_success "Order placed"
1116
+ print_h2 "Order Details", [], options
1117
+ print_order_details(order, options)
1118
+ end
1119
+ end
1120
+ end
1121
+
1122
+ def remove(args)
1123
+ options = {}
1124
+ params = {}
1125
+ optparse = MtnCloud::Cli::OptionParser.new do |opts|
1126
+ opts.banner = subcommand_usage("[item] [options]")
1127
+ opts.on('--remove-instances [true|false]', String, "Remove instances. Default is true. Applies to apps only.") do |val|
1128
+ params[:removeInstances] = ['true','on','1',''].include?(val.to_s.downcase)
1129
+ end
1130
+ opts.on( '-B', '--keep-backups [true|false]', "Preserve copy of backups. Default is false." ) do
1131
+ params[:keepBackups] = ['true','on','1',''].include?(val.to_s.downcase)
1132
+ end
1133
+ opts.on('--preserve-volumes [on|off]', String, "Preserve Volumes. Default is off. Applies to certain types only.") do |val|
1134
+ params[:preserveVolumes] = ['true','on','1',''].include?(val.to_s.downcase)
1135
+ end
1136
+ opts.on('--releaseEIPs [true|false]', String, "Release EIPs. Default is on. Applies to Amazon only.") do |val|
1137
+ params[:releaseEIPs] = ['true','on','1',''].include?(val.to_s.downcase)
1138
+ end
1139
+ opts.on('--release-ips [on|off]', ['on','off'], "Release Floating IPs. Default is on. Applies to certain types only.") do |val|
1140
+ params[:releaseFloatingIps] = ['true','on','1',''].include?(val.to_s.downcase)
1141
+ params[:releaseEIPs] = params[:releaseFloatingIps] # old parameter before 6.0
1142
+ end
1143
+ opts.on('--releaseEIPs [on|off]', ['on','off'], "Alias for Release Floating IPs") do |val|
1144
+ params[:releaseFloatingIps] = ['true','on','1',''].include?(val.to_s.downcase)
1145
+ params[:releaseEIPs] = params[:releaseFloatingIps] # old parameter before 6.0
1146
+ end
1147
+ opts.on( '-f', '--force', "Force Delete" ) do
1148
+ params[:force] = true
1149
+ end
1150
+ build_standard_remove_options(opts, options, [:sigdig])
1151
+ opts.footer = <<-EOT
1152
+ Delete a catalog inventory item.
1153
+ This removes the item from the inventory and deprovisions the associated instance(s).
1154
+ [item] is required. This is the name or id of a catalog inventory item.
1155
+ EOT
1156
+ end
1157
+ optparse.parse!(args)
1158
+ verify_args!(args:args, optparse:optparse, count:1)
1159
+ connect(options)
1160
+
1161
+ catalog_item = find_catalog_item_by_name_or_id(args[0])
1162
+ return 1 if catalog_item.nil?
1163
+
1164
+ is_app = (catalog_item['type']['type'] == 'app' || catalog_item['type']['type'] == 'blueprint' || catalog_item['type']['type'] == 'apptemplate') rescue false
1165
+
1166
+ params.merge!(parse_query_options(options))
1167
+ # delete dialog
1168
+ # we do not have provisioning settings right now to know if we can prompt for volumes / eips
1169
+ # skip force because it is excessive prompting...
1170
+ delete_prompt_options = [
1171
+ {'fieldName' => 'removeInstances', 'fieldLabel' => 'Remove Instances', 'type' => 'checkbox', 'defaultValue' => true},
1172
+ {'fieldName' => 'keepBackups', 'fieldLabel' => 'Preserve Backups', 'type' => 'checkbox', 'defaultValue' => false},
1173
+ #{'fieldName' => 'preserveVolumes', 'fieldLabel' => 'Preserve Volumes', 'type' => 'checkbox', 'defaultValue' => false},
1174
+ # {'fieldName' => 'releaseEIPs', 'fieldLabel' => 'Release EIPs. Default is on. Applies to Amazon only.', 'type' => 'checkbox', 'defaultValue' => true},
1175
+ #{'fieldName' => 'force', 'fieldLabel' => 'Force Delete', 'type' => 'checkbox', 'defaultValue' => false},
1176
+ ]
1177
+ if !is_app
1178
+ delete_prompt_options.reject! {|it| it['fieldName'] == 'removeInstances'}
1179
+ end
1180
+ options[:options][:no_prompt] = true if options[:yes] # -y could always mean do not prompt too..
1181
+ v_prompt = MtnCloud::Cli::OptionTypes.prompt(delete_prompt_options, options[:options], @api_client)
1182
+ v_prompt.booleanize! # 'on' => true
1183
+ params.deep_merge!(v_prompt)
1184
+
1185
+ unless options[:yes] || MtnCloud::Cli::OptionTypes.confirm("Are you sure you want to delete the inventory item #{catalog_item['id']} '#{catalog_item['name']}'?")
1186
+ return 9, "aborted command"
1187
+ end
1188
+ @service_catalog_interface.setopts(options)
1189
+ if options[:dry_run]
1190
+ print_dry_run @service_catalog_interface.dry.destroy_inventory(catalog_item['id'], params)
1191
+ return
1192
+ end
1193
+ json_response = @service_catalog_interface.destroy_inventory(catalog_item['id'], params)
1194
+ render_response(json_response, options) do
1195
+ print_green_success "Removing catalog item"
1196
+ end
1197
+ return 0, nil
1198
+ end
1199
+
1200
+ private
1201
+
1202
+ # Catalog Item Types helpers
1203
+
1204
+ def catalog_item_type_column_definitions()
1205
+ {
1206
+ "ID" => 'id',
1207
+ "Name" => 'name',
1208
+ "Description" => 'description',
1209
+ # "Type" => lambda {|it| format_catalog_type(it) },
1210
+ # "Blueprint" => lambda {|it| it['blueprint'] ? it['blueprint']['name'] : nil },
1211
+ # "Enabled" => lambda {|it| format_boolean(it['enabled']) },
1212
+ "Featured" => lambda {|it| format_boolean(it['featured']) },
1213
+ "Allow Quantity" => lambda {|it| format_boolean(it['allowQuantity']) },
1214
+ #"Config" => lambda {|it| it['config'] },
1215
+ # "Created" => lambda {|it| format_local_dt(it['dateCreated']) },
1216
+ # "Updated" => lambda {|it| format_local_dt(it['lastUpdated']) },
1217
+ }
1218
+ end
1219
+
1220
+ def catalog_item_type_object_key
1221
+ 'catalogItemType'
1222
+ end
1223
+
1224
+ def catalog_item_type_list_key
1225
+ 'catalogItemTypes'
1226
+ end
1227
+
1228
+ def find_catalog_item_type_by_name_or_id(val)
1229
+ if val.to_s =~ /\A\d{1,}\Z/
1230
+ return find_catalog_item_type_by_id(val)
1231
+ else
1232
+ return find_catalog_item_type_by_name(val)
1233
+ end
1234
+ end
1235
+
1236
+ # this returns optionTypes and list does not..
1237
+ def find_catalog_item_type_by_id(id)
1238
+ begin
1239
+ json_response = @service_catalog_interface.get_type(id.to_i)
1240
+ return json_response[catalog_item_type_object_key]
1241
+ rescue RestClient::Exception => e
1242
+ if e.response && e.response.code == 404
1243
+ print_red_alert "Catalog item type not found by id '#{id}'"
1244
+ else
1245
+ raise e
1246
+ end
1247
+ end
1248
+ end
1249
+
1250
+ def find_catalog_item_type_by_name(name)
1251
+ json_response = @service_catalog_interface.list_types({name: name.to_s})
1252
+ catalog_item_types = json_response[catalog_item_type_list_key]
1253
+ if catalog_item_types.empty?
1254
+ print_red_alert "Catalog item type not found by name '#{name}'"
1255
+ return nil
1256
+ elsif catalog_item_types.size > 1
1257
+ print_red_alert "#{catalog_item_types.size} catalog item types found by name '#{name}'"
1258
+ puts_error as_pretty_table(catalog_item_types, [:id, :name], {color:red})
1259
+ print_red_alert "Try using ID instead"
1260
+ print reset,"\n"
1261
+ return nil
1262
+ else
1263
+ return catalog_item_types[0]
1264
+ end
1265
+ end
1266
+
1267
+ def catalog_item_column_definitions()
1268
+ {
1269
+ "ID" => 'id',
1270
+ "Name" => 'name',
1271
+ #"Description" => 'description',
1272
+ "Type" => lambda {|it| it['type']['name'] rescue '' },
1273
+ #"Qty" => lambda {|it| it['quantity'] },
1274
+ # "Enabled" => lambda {|it| format_boolean(it['enabled']) },
1275
+
1276
+ # "Created" => lambda {|it| format_local_dt(it['dateCreated']) },
1277
+ # "Updated" => lambda {|it| format_local_dt(it['lastUpdated']) },
1278
+ "Order Date" => lambda {|it| format_local_dt(it['orderDate']) },
1279
+ "Status" => lambda {|it| format_catalog_item_status(it) },
1280
+ # "Config" => lambda {|it| format_name_values(it['config']) },
1281
+ }
1282
+ end
1283
+
1284
+ # Catalog Items (Inventory) helpers
1285
+
1286
+ def catalog_item_object_key
1287
+ 'item'
1288
+ end
1289
+
1290
+ def catalog_item_list_key
1291
+ 'items'
1292
+ end
1293
+
1294
+ def find_catalog_item_by_name_or_id(val)
1295
+ if val.to_s =~ /\A\d{1,}\Z/
1296
+ return find_catalog_item_by_id(val)
1297
+ else
1298
+ return find_catalog_item_by_name(val)
1299
+ end
1300
+ end
1301
+
1302
+ def find_catalog_item_by_id(id)
1303
+ begin
1304
+ json_response = @service_catalog_interface.get_inventory(id.to_i)
1305
+ return json_response[catalog_item_object_key]
1306
+ rescue RestClient::Exception => e
1307
+ if e.response && e.response.code == 404
1308
+ print_red_alert "Catalog item not found by id '#{id}'"
1309
+ else
1310
+ raise e
1311
+ end
1312
+ end
1313
+ end
1314
+
1315
+ # find by name not yet supported, items do not have a name
1316
+ def find_catalog_item_by_name(name)
1317
+ json_response = @service_catalog_interface.list_inventory({name: name.to_s})
1318
+ catalog_items = json_response[catalog_item_list_key]
1319
+ if catalog_items.empty?
1320
+ print_red_alert "Catalog item not found by name '#{name}'"
1321
+ return nil
1322
+ elsif catalog_items.size > 1
1323
+ print_red_alert "#{catalog_items.size} catalog items found by name '#{name}'"
1324
+ puts_error as_pretty_table(catalog_items, [:id, :name], {color:red})
1325
+ print_red_alert "Try using ID instead"
1326
+ print reset,"\n"
1327
+ return nil
1328
+ else
1329
+ return catalog_items[0]
1330
+ end
1331
+ end
1332
+
1333
+ def format_catalog_item_status(item, return_color=cyan)
1334
+ out = ""
1335
+ status_string = item['status'].to_s.upcase
1336
+ if status_string == 'IN_CART' || status_string == 'IN CART'
1337
+ out << "#{cyan}IN CART#{return_color}"
1338
+ elsif status_string == 'ORDERED'
1339
+ #out << "#{cyan}#{status_string.upcase}#{return_color}"
1340
+ # show the instance/app/execution status instead of the item status ORDERED
1341
+ if item['instance']
1342
+ out << format_instance_status(item['instance'], return_color)
1343
+ elsif item['app']
1344
+ out << format_app_status(item['app'], return_color)
1345
+ elsif item['execution']
1346
+ out << format_job_execution_status(item['execution'], return_color)
1347
+ else
1348
+ out << "#{cyan}#{status_string.upcase}#{return_color}"
1349
+ end
1350
+ elsif status_string == 'VALID'
1351
+ out << "#{green}#{status_string.upcase}#{return_color}"
1352
+ elsif status_string == 'INVALID'
1353
+ out << "#{red}#{status_string.upcase}#{return_color}"
1354
+ elsif status_string == 'FAILED'
1355
+ out << "#{red}#{status_string.upcase}#{return_color}"
1356
+ elsif status_string == 'DELETED'
1357
+ out << "#{red}#{status_string.upcase}#{return_color}" # cyan maybe?
1358
+ else
1359
+ out << "#{yellow}#{status_string.upcase}#{return_color}"
1360
+ end
1361
+ out
1362
+ end
1363
+
1364
+ def format_order_status(cart, return_color=cyan)
1365
+ out = ""
1366
+ cart_items = cart['items']
1367
+ if cart_items.nil? || cart_items.empty?
1368
+ out << "#{yellow}EMPTY#{return_color}"
1369
+ else
1370
+ # status of first item in cart will work i guess...
1371
+ item = cart_items.first
1372
+ status_string = item['status'].to_s.upcase
1373
+ if status_string == "IN_CART"
1374
+ # out << "#{cyan}CART (#{cart_items.size()})#{return_color}"
1375
+ out << "#{cyan}CART#{return_color}"
1376
+ else
1377
+ out << format_catalog_item_status(item, return_color)
1378
+ end
1379
+ end
1380
+ out
1381
+ end
1382
+
1383
+ def print_order_details(cart, options)
1384
+ cart_items = cart['items'] || []
1385
+ cart_stats = cart['stats'] || {}
1386
+ if cart_items && cart_items.size > 0
1387
+ print cyan
1388
+ cart_show_columns = {
1389
+ #"Order ID" => 'id',
1390
+ "Order Name" => 'name',
1391
+ "Order Items" => lambda {|it| cart['items'].size },
1392
+ "Order Qty" => lambda {|it| cart['items'].sum {|cart_item| cart_item['quantity'] } },
1393
+ "Order Status" => lambda {|it| format_order_status(it) },
1394
+ #"Order Total" => lambda {|it| format_money(cart_stats['price'], cart_stats['currency'], {sigdig:options[:sigdig] || default_sigdig}) + " / #{cart_stats['unit'].to_s.empty? ? 'month' : cart_stats['unit']}" },
1395
+ #"Items" => lambda {|it| cart['items'].size },
1396
+ # "Created" => lambda {|it| format_local_dt(it['dateCreated']) },
1397
+ # "Updated" => lambda {|it| format_local_dt(it['lastUpdated']) },
1398
+ }
1399
+ if options[:details] != true
1400
+ cart_show_columns.delete("Order Items")
1401
+ cart_show_columns.delete("Order Qty")
1402
+ cart_show_columns.delete("Order Status")
1403
+ end
1404
+ cart_show_columns.delete("Order Name") if cart['name'].to_s.empty?
1405
+ # if !cart_show_columns.empty?
1406
+ # print_description_list(cart_show_columns, cart)
1407
+ # print reset, "\n"
1408
+ # end
1409
+
1410
+ if options[:details]
1411
+ if !cart_show_columns.empty?
1412
+ print_description_list(cart_show_columns, cart)
1413
+ # print reset, "\n"
1414
+ end
1415
+ #print_h2 "Cart Items"
1416
+ cart_items.each_with_index do |cart_item, index|
1417
+ item_config = cart_item['config']
1418
+ cart_item_columns = [
1419
+ {"ID" => lambda {|it| it['id'] } },
1420
+ #{"NAME" => lambda {|it| it['name'] } },
1421
+ {"Type" => lambda {|it| it['type']['name'] rescue '' } },
1422
+ {"Qty" => lambda {|it| it['quantity'] } },
1423
+ {"Price" => lambda {|it| it['price'] ? format_money(it['price'] , it['currency'], {sigdig:options[:sigdig] || default_sigdig}) : "No pricing configured" } },
1424
+ {"Status" => lambda {|it|
1425
+ status_string = format_catalog_item_status(it)
1426
+ if it['errorMessage'].to_s != ""
1427
+ status_string << " - #{it['errorMessage']}"
1428
+ end
1429
+ status_string
1430
+ } },
1431
+ # {"Config" => lambda {|it| format_name_values(it['config']) } },
1432
+ ]
1433
+ print_h2(index == 0 ? "Item" : "Item #{index+1}", options)
1434
+ print as_description_list(cart_item, cart_item_columns, options)
1435
+ # print "\n", reset
1436
+ if item_config && !item_config.keys.empty?
1437
+ print_h2("Configuration", options)
1438
+ print as_description_list(item_config, item_config.keys, options)
1439
+ print "\n", reset
1440
+ end
1441
+ end
1442
+ else
1443
+ if !cart_show_columns.empty?
1444
+ print_description_list(cart_show_columns, cart)
1445
+ print reset, "\n"
1446
+ end
1447
+ #print_h2 "Cart Items"
1448
+ cart_item_columns = [
1449
+ {"ID" => lambda {|it| it['id'] } },
1450
+ #{"NAME" => lambda {|it| it['name'] } },
1451
+ {"TYPE" => lambda {|it| it['type']['name'] rescue '' } },
1452
+ {"QTY" => lambda {|it| it['quantity'] } },
1453
+ {"PRICE" => lambda {|it| it['price'] ? format_money(it['price'] , it['currency'], {sigdig:options[:sigdig] || default_sigdig}) : "No pricing configured" } },
1454
+ {"STATUS" => lambda {|it|
1455
+ status_string = format_catalog_item_status(it)
1456
+ if it['errorMessage'].to_s != ""
1457
+ status_string << " - #{it['errorMessage']}"
1458
+ end
1459
+ status_string
1460
+ } },
1461
+ # {"CONFIG" => lambda {|it|
1462
+ # truncate_string(format_name_values(it['config']), 50)
1463
+ # } },
1464
+ ]
1465
+ print as_pretty_table(cart_items, cart_item_columns)
1466
+ end
1467
+ print reset,"\n"
1468
+ print cyan
1469
+ if cart_stats['price']
1470
+ puts "Total: " + format_money(cart_stats['price'], cart_stats['currency'], {sigdig:options[:sigdig] || default_sigdig}) + " / #{cart_stats['unit'].to_s.empty? ? 'month' : cart_stats['unit']}"
1471
+ else
1472
+ puts "Total: " + "No pricing configured"
1473
+ end
1474
+ print reset,"\n"
1475
+ else
1476
+ print cyan,"Cart is empty","\n",reset
1477
+ print reset,"\n"
1478
+ end
1479
+ end
1480
+
1481
+ def format_job_execution_status(execution, return_color=cyan)
1482
+ out = ""
1483
+ status_string = execution['status'].to_s.downcase
1484
+ if status_string
1485
+ if ['complete','success', 'successful', 'ok'].include?(status_string)
1486
+ out << "#{green}#{status_string.upcase}"
1487
+ elsif ['error', 'offline', 'failed', 'failure'].include?(status_string)
1488
+ out << "#{red}#{status_string.upcase}"
1489
+ else
1490
+ out << "#{yellow}#{status_string.upcase}"
1491
+ end
1492
+ end
1493
+ out + return_color
1494
+ end
1495
+
1496
+
1497
+ def construct_catalog_api_params(record)
1498
+ catalog_item_type_id = record['id'].to_i
1499
+ api_params = {}
1500
+ api_params['catalogItemType'] ||= {}
1501
+ api_params['catalogItemType']['id'] = catalog_item_type_id
1502
+ # Determine instance.type value
1503
+ # the UI is injecting this parameter into the option source requests
1504
+ # it is needed to populate api option lists eg. optionTypeClouds
1505
+ # this should be fixed on the api side, so it automatically extracts this input from the config
1506
+ begin
1507
+ instance_type_code = nil
1508
+ catalog_item_type = record
1509
+ #catalog_item_type = find_by_id(:catalog_item_type, catalog_item_type_id.to_i)
1510
+ if catalog_item_type
1511
+ if catalog_item_type['type'] == 'instance'
1512
+ if catalog_item_type['config'] && catalog_item_type['config']['type']
1513
+ instance_type_code = catalog_item_type['config']['type']
1514
+ end
1515
+ end
1516
+ end
1517
+ if instance_type_code
1518
+ api_params['instance'] ||= {}
1519
+ api_params['instance']['type'] = instance_type_code
1520
+ end
1521
+ rescue ::RestClient::Exception => e
1522
+ # users may not have permission to this endpoint
1523
+ # puts "Failed to load catalog item type"
1524
+ end
1525
+ return api_params
1526
+ end
1527
+
1528
+ end