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,754 @@
1
+ require 'mtncloud/cli/cli_command'
2
+ require 'time'
3
+
4
+ class MtnCloud::Cli::BudgetsCommand
5
+ include MtnCloud::Cli::CliCommand
6
+ set_command_name :budgets
7
+ register_subcommands :list, :get, :add, :update, :remove
8
+
9
+ def connect(opts)
10
+ @api_client = establish_remote_appliance_connection(opts)
11
+ @budgets_interface = @api_client.budgets
12
+ @options_interface = @api_client.options
13
+ end
14
+
15
+ def handle(args)
16
+ handle_subcommand(args)
17
+ end
18
+
19
+ def list(args)
20
+ options = {}
21
+ params = {}
22
+ optparse = MtnCloud::Cli::OptionParser.new do |opts|
23
+ opts.banner = subcommand_usage()
24
+ build_standard_list_options(opts, options)
25
+ opts.footer = "List budgets."
26
+ end
27
+ optparse.parse!(args)
28
+ # verify_args!(args:args, optparse:optparse, count:0)
29
+ if args.count > 0
30
+ options[:phrase] = args.join(" ")
31
+ end
32
+ params.merge!(parse_list_options(options))
33
+ connect(options)
34
+
35
+ params.merge!(parse_list_options(options))
36
+ @budgets_interface.setopts(options)
37
+ if options[:dry_run]
38
+ print_dry_run @budgets_interface.dry.list(params)
39
+ return 0
40
+ end
41
+ json_response = @budgets_interface.list(params)
42
+ budgets = json_response['budgets']
43
+ render_response(json_response, options, 'budgets') do
44
+ title = "Budgets"
45
+ subtitles = []
46
+ subtitles += parse_list_subtitles(options)
47
+ print_h1 title, subtitles
48
+ if budgets.empty?
49
+ print cyan,"No budgets found.",reset,"\n"
50
+ else
51
+ columns = [
52
+ {"ID" => lambda {|budget| budget['id'] } },
53
+ {"NAME" => lambda {|budget| budget['name'] } },
54
+ {"DESCRIPTION" => lambda {|budget| truncate_string(budget['description'], 30) } },
55
+ # {"ENABLED" => lambda {|budget| format_boolean(budget['enabled']) } },
56
+ # {"SCOPE" => lambda {|it| format_budget_scope(it) } },
57
+ {"SCOPE" => lambda {|it| it['refName'] } },
58
+ {"PERIOD" => lambda {|it| it['year'] } },
59
+ {"INTERVAL" => lambda {|it| it['interval'].to_s.capitalize } },
60
+ # the UI doesn't consider timezone, so uhh do it this hacky way for now.
61
+ {"START DATE" => lambda {|it|
62
+ if it['timezone'] == 'UTC'
63
+ ((parse_time(it['startDate'], "%Y-%m-%d").strftime("%x")) rescue it['startDate']) # + ' UTC'
64
+ else
65
+ format_local_date(it['startDate'])
66
+ end
67
+ } },
68
+ {"END DATE" => lambda {|it|
69
+ if it['timezone'] == 'UTC'
70
+ ((parse_time(it['endDate'], "%Y-%m-%d").strftime("%x")) rescue it['endDate']) # + ' UTC'
71
+ else
72
+ format_local_date(it['endDate'])
73
+ end
74
+ } },
75
+ {"TOTAL" => lambda {|it| format_money(it['totalCost'], it['currency']) } },
76
+ {"AVERAGE" => lambda {|it| format_money(it['averageCost'], it['currency']) } },
77
+ # {"CREATED BY" => lambda {|budget| budget['createdByName'] ? budget['createdByName'] : budget['createdById'] } },
78
+ # {"CREATED" => lambda {|budget| format_local_dt(budget['dateCreated']) } },
79
+ # {"UPDATED" => lambda {|budget| format_local_dt(budget['lastUpdated']) } },
80
+ ]
81
+ if options[:include_fields]
82
+ columns = options[:include_fields]
83
+ end
84
+ print as_pretty_table(budgets, columns, options)
85
+ print_results_pagination(json_response)
86
+ end
87
+ print reset,"\n"
88
+ end
89
+ return budgets.empty? ? [3, "no budgets found"] : [0, nil]
90
+ end
91
+
92
+ def get(args)
93
+ options = {}
94
+ params = {}
95
+ optparse = MtnCloud::Cli::OptionParser.new do |opts|
96
+ opts.banner = subcommand_usage("[budget]")
97
+ build_standard_get_options(opts, options)
98
+ opts.footer = "Get details about a budget.\n[budget] is required. Budget ID or name"
99
+ end
100
+ optparse.parse!(args)
101
+ verify_args!(args:args, optparse:optparse, count:1)
102
+ connect(options)
103
+ params.merge!(parse_query_options(options))
104
+ @budgets_interface.setopts(options)
105
+ if options[:dry_run]
106
+ if args[0].to_s =~ /\A\d{1,}\Z/
107
+ print_dry_run @budgets_interface.dry.get(args[0], params)
108
+ else
109
+ print_dry_run @budgets_interface.dry.list({name: args[0].to_s})
110
+ end
111
+ return 0
112
+ end
113
+ budget = find_budget_by_name_or_id(args[0])
114
+ return 1 if budget.nil?
115
+ # skip reload if already fetched via get(id)
116
+ json_response = {'budget' => budget}
117
+ if args[0].to_s != budget['id'].to_s
118
+ json_response = @budgets_interface.get(budget['id'], params)
119
+ budget = json_response['budget']
120
+ end
121
+
122
+ render_response(json_response, options, 'budget') do
123
+
124
+ print_h1 "Budget Details"
125
+ print cyan
126
+ budget_columns = {
127
+ "ID" => 'id',
128
+ "Name" => 'name',
129
+ "Description" => 'description',
130
+ "Enabled" => lambda {|budget| format_boolean(budget['enabled']) },
131
+ "Scope" => lambda {|it| format_budget_scope(it) },
132
+ "Period" => lambda {|it| it['year'] },
133
+ "Interval" => lambda {|it| it['interval'].to_s.capitalize },
134
+ "Forecast Model" => lambda {|it| it['forecastType'] ? it['forecastType']['name'] : '' },
135
+ # the UI doesn't consider timezone, so uhh do it this hacky way for now.
136
+ "Start Date" => lambda {|it|
137
+ if it['timezone'] == 'UTC'
138
+ ((parse_time(it['startDate'], "%Y-%m-%d").strftime("%x")) rescue it['startDate']) # + ' UTC'
139
+ else
140
+ format_local_date(it['startDate'])
141
+ end
142
+ },
143
+ "End Date" => lambda {|it|
144
+ if it['timezone'] == 'UTC'
145
+ ((parse_time(it['endDate'], "%Y-%m-%d").strftime("%x")) rescue it['endDate']) # + ' UTC'
146
+ else
147
+ format_local_date(it['endDate'])
148
+ end
149
+ },
150
+ # "Costs" => lambda {|it|
151
+ # if it['costs'].is_a?(Array)
152
+ # it['costs'] ? it['costs'].join(', ') : ''
153
+ # elsif it['costs'].is_a?(Hash)
154
+ # it['costs'].to_s
155
+ # else
156
+ # it['costs'].to_s
157
+ # end
158
+ # },
159
+ "Created By" => lambda {|it| it['createdByName'] ? it['createdByName'] : it['createdById'] },
160
+ "Created" => lambda {|it| format_local_dt(it['dateCreated']) },
161
+ "Updated" => lambda {|it| format_local_dt(it['lastUpdated']) },
162
+ }
163
+ print_description_list(budget_columns, budget, options)
164
+ # print reset,"\n"
165
+
166
+ # a chart of Budget cost vs Actual cost for each interval in the period.
167
+ print_h2 "Budget Summary", options
168
+ if budget['stats'] && budget['stats']['intervals']
169
+ begin
170
+ budget_summary_columns = {
171
+ # "Cost" => lambda {|it| it[:label] },
172
+ " " => lambda {|it| it[:label] },
173
+ }
174
+ budget_row = {label:"Budget"}
175
+ actual_row = {label:"Actual"}
176
+ forecast_row = {label:"Forecast"}
177
+ multi_year = false
178
+ if budget['startDate'] && budget['endDate'] && parse_time(budget['startDate']).year != parse_time(budget['endDate']).year
179
+ multi_year = true
180
+ end
181
+ budget['stats']['intervals'].each do |it|
182
+ currency = budget['currency'] || budget['stats']['currency']
183
+ interval_key = format_budget_interval_label(budget, it).to_s.upcase
184
+ # interval_date = parse_time(it["startDate"]) rescue nil
185
+ budget_summary_columns[interval_key] = interval_key
186
+ budget_cost = it["budget"].to_f
187
+ actual_cost = it["cost"].to_f
188
+ over_budget = actual_cost > 0 && actual_cost > budget_cost
189
+ if over_budget
190
+ budget_row[interval_key] = "#{cyan}#{format_money(budget_cost, currency)}#{cyan}"
191
+ actual_row[interval_key] = "#{red}#{format_money(actual_cost, currency)}#{cyan}"
192
+ else
193
+ budget_row[interval_key] = "#{cyan}#{format_money(budget_cost, currency)}#{cyan}"
194
+ actual_row[interval_key] = "#{cyan}#{format_money(actual_cost, currency)}#{cyan}"
195
+ end
196
+ forecast_cost = it["forecast"] ? it["forecast"].to_f : 0
197
+ forecast_over_budget = forecast_cost > 0 && forecast_cost > budget_cost
198
+ if forecast_over_budget
199
+ forecast_row[interval_key] = "#{red}#{format_money(forecast_cost, currency)}#{cyan}"
200
+ else
201
+ forecast_row[interval_key] = "#{cyan}#{format_money(forecast_cost, currency)}#{cyan}"
202
+ end
203
+ end
204
+ chart_data = [budget_row, actual_row]
205
+ if budget['stats']['intervals'].find { |it| it['forecast'] && it['forecast'] != 0 }
206
+ chart_data << forecast_row
207
+ end
208
+ print as_pretty_table(chart_data, budget_summary_columns, options)
209
+ print reset,"\n"
210
+ rescue => ex
211
+ print red,"Failed to render budget summary.",reset,"\n"
212
+ raise ex
213
+ end
214
+ else
215
+ print cyan,"No budget stat data found.",reset,"\n"
216
+ end
217
+ end
218
+ return 0, nil
219
+ end
220
+
221
+ def add(args)
222
+ options = {}
223
+ params = {}
224
+ costs = []
225
+ optparse = MtnCloud::Cli::OptionParser.new do |opts|
226
+ opts.banner = subcommand_usage("[name] [options]")
227
+ build_option_type_options(opts, options, add_budget_option_types)
228
+ # opts.on('--cost [amount]', String, "Budget cost amount, for use with default year interval.") do |val|
229
+ # costs['year'] = (val.nil? || val.empty?) ? 0 : val.to_f
230
+ # end
231
+ opts.on('--costs LIST', String, "Budget cost amounts, one for each interval in the budget. eg \"350\" for one year, \"25,25,25,100\" for quarters, and \"10,10,10,10,10,10,10,10,10,10,10,50\" for each month") do |val|
232
+ val = val.to_s.gsub('[', '').gsub(']', '')
233
+ costs = val.to_s.split(',').collect {|it| parse_cost_amount(it) }
234
+ end
235
+ (1..12).each.with_index do |cost_index, i|
236
+ opts.on("--cost#{cost_index} VALUE", String, "Cost #{cost_index.to_s.capitalize} amount") do |val|
237
+ #params["cost#{cost_index.to_s}"] = parse_cost_amount(val)
238
+ costs[i] = parse_cost_amount(val)
239
+ end
240
+ opts.add_hidden_option("--cost#{cost_index}")
241
+ end
242
+ [:q1,:q2,:q3,:q4,].each.with_index do |quarter, i|
243
+ opts.on("--#{quarter.to_s} VALUE", String, "#{quarter.to_s.capitalize} cost amount, use with quarter interval.") do |val|
244
+ costs[i] = parse_cost_amount(val)
245
+ end
246
+ opts.add_hidden_option("--#{quarter.to_s}")
247
+ end
248
+ [:january,:february,:march,:april,:may,:june,:july,:august,:september,:october,:november,:december].each_with_index do |month, i|
249
+ opts.on("--#{month.to_s} VALUE", String, "#{month.to_s.capitalize} cost amount, use with month interval.") do |val|
250
+ costs[i] = parse_cost_amount(val)
251
+ end
252
+ opts.add_hidden_option("--#{month.to_s}")
253
+ end
254
+ opts.on('--enabled [on|off]', String, "Can be used to disable a policy") do |val|
255
+ params['enabled'] = val.to_s == 'on' || val.to_s == 'true' || val.to_s.empty?
256
+ end
257
+ build_standard_add_options(opts, options)
258
+ opts.footer = <<-EOT
259
+ Create a budget.
260
+ The default period is the current year, eg. "#{Time.now.year}"
261
+ and the default interval is "year".
262
+ Costs can be passed as an array of values, one for each interval. eg. --costs "[999]"
263
+
264
+ Examples:
265
+ budgets add example-budget --interval "year" --costs "[2500]"
266
+ budgets add example-qtr-budget --interval "quarter" --costs "[500,500,500,1000]"
267
+ budgets add example-monthly-budget --interval "month" --costs "[400,100,100,100,100,100,100,100,100,100,400,800]"
268
+ budgets add example-future-budget --year "2022" --interval "year" --costs "[5000]"
269
+ budgets add example-custom-budget --year "custom" --interval "year" --start "2021-01-01" --end "2023-12-31" --costs "[2500,5000,10000]"
270
+ EOT
271
+ end
272
+ optparse.parse!(args)
273
+ if args.count > 1
274
+ raise_command_error "wrong number of arguments, expected 0-1 and got (#{args.count}) #{args}\n#{optparse}"
275
+ end
276
+ if args[0]
277
+ options[:options]['name'] ||= args[0]
278
+ end
279
+ connect(options)
280
+ begin
281
+ # construct payload
282
+ passed_options = options[:options] ? options[:options].reject {|k,v| k.is_a?(Symbol) } : {}
283
+ payload = nil
284
+ if options[:payload]
285
+ payload = options[:payload]
286
+ payload.deep_merge!({'budget' => passed_options}) unless passed_options.empty?
287
+ else
288
+ payload = {
289
+ 'budget' => {
290
+ }
291
+ }
292
+ # allow arbitrary -O options
293
+ #passed_options.delete('costs')
294
+ passed_options.delete('tenant')
295
+ passed_options.delete('group')
296
+ passed_options.delete('cloud')
297
+ passed_options.delete('user')
298
+ payload.deep_merge!({'budget' => passed_options}) unless passed_options.empty?
299
+ # prompt for options
300
+ v_prompt = MtnCloud::Cli::OptionTypes.prompt(add_budget_option_types, options[:options], @api_client)
301
+ params.deep_merge!(v_prompt)
302
+ # downcase year 'custom' always
303
+ if params['year']
304
+ params['interval'] = params['interval'].to_s.downcase
305
+ end
306
+ # downcase interval always
307
+ if params['interval']
308
+ params['interval'] = params['interval'].to_s.downcase
309
+ end
310
+ # parse MM/DD/YY but need to convert to to ISO format YYYY-MM-DD for api
311
+ standard_start_date = (params['startDate'] ? Time.strptime(params['startDate'], "%x") : nil) rescue nil
312
+ if standard_start_date
313
+ params['startDate'] = format_date(standard_start_date, {format:"%Y-%m-%d"})
314
+ end
315
+ standard_end_date = (params['endDate'] ? Time.strptime(params['endDate'], "%x") : nil) rescue nil
316
+ if standard_end_date
317
+ params['endDate'] = format_date(standard_end_date, {format:"%Y-%m-%d"})
318
+ end
319
+ if !costs.empty?
320
+ params['costs'] = costs
321
+ else
322
+ params['costs'] = prompt_costs(params, options)
323
+ end
324
+ # budgets api expects scope prefixed parameters like this
325
+ if params['tenant'].is_a?(String) || params['tenant'].is_a?(Numeric)
326
+ params['scopeTenantId'] = params.delete('tenant')
327
+ end
328
+ if params['group'].is_a?(String) || params['group'].is_a?(Numeric)
329
+ params['scopeGroupId'] = params.delete('group')
330
+ end
331
+ if params['cloud'].is_a?(String) || params['cloud'].is_a?(Numeric)
332
+ params['scopeCloudId'] = params.delete('cloud')
333
+ end
334
+ if params['user'].is_a?(String) || params['user'].is_a?(Numeric)
335
+ params['scopeUserId'] = params.delete('user')
336
+ end
337
+ payload.deep_merge!({'budget' => params}) unless params.empty?
338
+ end
339
+
340
+ @budgets_interface.setopts(options)
341
+ if options[:dry_run]
342
+ print_dry_run @budgets_interface.dry.create(payload)
343
+ return
344
+ end
345
+ json_response = @budgets_interface.create(payload)
346
+ if options[:json]
347
+ print JSON.pretty_generate(json_response)
348
+ print "\n"
349
+ else
350
+ display_name = json_response['budget'] ? json_response['budget']['name'] : ''
351
+ print_green_success "Budget #{display_name} added"
352
+ get([json_response['budget']['id']] + (options[:remote] ? ["-r",options[:remote]] : []))
353
+ end
354
+ return 0
355
+ rescue RestClient::Exception => e
356
+ print_rest_exception(e, options)
357
+ exit 1
358
+ end
359
+ end
360
+
361
+ def update(args)
362
+ options = {}
363
+ params = {}
364
+ costs = []
365
+ optparse = MtnCloud::Cli::OptionParser.new do |opts|
366
+ opts.banner = subcommand_usage("[budget] [options]")
367
+ build_option_type_options(opts, options, update_budget_option_types)
368
+ # opts.on('--cost [amount]', String, "Budget cost amount, for use with default year interval.") do |val|
369
+ # costs['year'] = (val.nil? || val.empty?) ? 0 : val.to_f
370
+ # end
371
+ opts.on('--costs COSTS', String, "Budget cost amounts, one for each interval in the budget. eg. [999]") do |val|
372
+ val = val.to_s.gsub('[', '').gsub(']', '')
373
+ costs = val.to_s.split(',').collect {|it| parse_cost_amount(it) }
374
+ end
375
+ (1..12).each.with_index do |cost_index, i|
376
+ opts.on("--cost#{cost_index} VALUE", String, "Cost #{cost_index.to_s.capitalize} amount") do |val|
377
+ #params["cost#{cost_index.to_s}"] = parse_cost_amount(val)
378
+ costs[i] = parse_cost_amount(val)
379
+ end
380
+ opts.add_hidden_option("--cost#{cost_index}")
381
+ end
382
+ [:q1,:q2,:q3,:q4,].each.with_index do |quarter, i|
383
+ opts.on("--#{quarter.to_s} VALUE", String, "#{quarter.to_s.capitalize} cost amount, use with quarter interval.") do |val|
384
+ costs[i] = parse_cost_amount(val)
385
+ end
386
+ opts.add_hidden_option("--#{quarter.to_s}")
387
+ end
388
+ [:january,:february,:march,:april,:may,:june,:july,:august,:september,:october,:november,:december].each_with_index do |month, i|
389
+ opts.on("--#{month.to_s} VALUE", String, "#{month.to_s.capitalize} cost amount, use with month interval.") do |val|
390
+ costs[i] = parse_cost_amount(val)
391
+ end
392
+ opts.add_hidden_option("--#{month.to_s}")
393
+ end
394
+ opts.on('--enabled [on|off]', String, "Can be used to disable a policy") do |val|
395
+ params['enabled'] = val.to_s == 'on' || val.to_s == 'true' || val.to_s.empty?
396
+ end
397
+ build_standard_update_options(opts, options)
398
+ opts.footer = <<-EOT
399
+ Update a budget.
400
+ [budget] is required. Budget ID or name
401
+ EOT
402
+ opts.footer = "Update a budget.\n[budget] is required. Budget ID or name"
403
+ end
404
+ optparse.parse!(args)
405
+
406
+ if args.count != 1
407
+ raise_command_error "wrong number of arguments, expected 1 and got (#{args.count}) #{args}\n#{optparse}"
408
+ end
409
+
410
+ connect(options)
411
+
412
+ budget = find_budget_by_name_or_id(args[0])
413
+ return 1 if budget.nil?
414
+
415
+ original_year = budget['year']
416
+ original_interval = budget['interval']
417
+ original_costs = budget['costs'].is_a?(Array) ? budget['costs'] : nil
418
+
419
+ # construct payload
420
+ passed_options = options[:options] ? options[:options].reject {|k,v| k.is_a?(Symbol) } : {}
421
+ payload = nil
422
+ if options[:payload]
423
+ payload = options[:payload]
424
+ payload.deep_merge!({'budget' => passed_options}) unless passed_options.empty?
425
+ else
426
+ payload = {
427
+ 'budget' => {
428
+ }
429
+ }
430
+ # allow arbitrary -O options
431
+ #passed_options.delete('costs')
432
+ passed_options.delete('tenant')
433
+ passed_options.delete('group')
434
+ passed_options.delete('cloud')
435
+ passed_options.delete('user')
436
+ payload.deep_merge!({'budget' => passed_options}) unless passed_options.empty?
437
+ # prompt for options
438
+ #params = MtnCloud::Cli::OptionTypes.prompt(update_budget_option_types, options[:options], @api_client, options[:params])
439
+ v_prompt = MtnCloud::Cli::OptionTypes.prompt(update_budget_option_types, options[:options].merge(:no_prompt => true), @api_client)
440
+ params.deep_merge!(v_prompt)
441
+ # downcase year 'custom' always
442
+ if params['year']
443
+ params['interval'] = params['interval'].to_s.downcase
444
+ end
445
+ # downcase interval always
446
+ if params['interval']
447
+ params['interval'] = params['interval'].to_s.downcase
448
+ end
449
+ # parse MM/DD/YY but need to convert to to ISO format YYYY-MM-DD for api
450
+ if params['startDate']
451
+ params['startDate'] = format_date(parse_time(params['startDate']), {format:"%Y-%m-%d"})
452
+ end
453
+ if params['endDate']
454
+ params['endDate'] = format_date(parse_time(params['endDate']), {format:"%Y-%m-%d"})
455
+ end
456
+ if !costs.empty?
457
+ params['costs'] = costs
458
+ # merge original costs in on update unless interval is changing too, should check original_year too probably if going to custom...
459
+ if params['interval'] && params['interval'] != original_interval
460
+ original_costs = nil
461
+ end
462
+ if original_costs
463
+ original_costs.each_with_index do |original_cost, i|
464
+ if params['costs'][i].nil?
465
+ params['costs'][i] = original_cost
466
+ end
467
+ end
468
+ end
469
+ else
470
+ if params['interval'] && params['interval'] != original_interval
471
+ raise_command_error "Changing interval requires setting the costs as well.\n#{optparse}"
472
+ end
473
+ end
474
+ # budgets api expects scope prefixed parameters like this
475
+ if params['tenant'].is_a?(String) || params['tenant'].is_a?(Numeric)
476
+ params['scopeTenantId'] = params.delete('tenant')
477
+ end
478
+ if params['group'].is_a?(String) || params['group'].is_a?(Numeric)
479
+ params['scopeGroupId'] = params.delete('group')
480
+ end
481
+ if params['cloud'].is_a?(String) || params['cloud'].is_a?(Numeric)
482
+ params['scopeCloudId'] = params.delete('cloud')
483
+ end
484
+ if params['user'].is_a?(String) || params['user'].is_a?(Numeric)
485
+ params['scopeUserId'] = params.delete('user')
486
+ end
487
+ payload.deep_merge!({'budget' => params}) unless params.empty?
488
+ if payload.empty? || payload['budget'].empty?
489
+ raise_command_error "Specify at least one option to update.\n#{optparse}"
490
+ end
491
+ end
492
+ @budgets_interface.setopts(options)
493
+ if options[:dry_run]
494
+ print_dry_run @budgets_interface.dry.update(budget['id'], payload)
495
+ return
496
+ end
497
+ json_response = @budgets_interface.update(budget['id'], payload)
498
+ render_response(json_response, options, 'budget') do
499
+ display_name = json_response['budget'] ? json_response['budget']['name'] : ''
500
+ print_green_success "Budget #{display_name} updated"
501
+ get([json_response['budget']['id']] + (options[:remote] ? ["-r",options[:remote]] : []))
502
+ end
503
+ return 0, nil
504
+ end
505
+
506
+ def remove(args)
507
+ options = {}
508
+ optparse = MtnCloud::Cli::OptionParser.new do |opts|
509
+ opts.banner = subcommand_usage("[name]")
510
+ build_common_options(opts, options, [:auto_confirm, :json, :dry_run, :remote])
511
+ opts.footer = "Delete budget.\n[budget] is required. Budget ID or name"
512
+ end
513
+ optparse.parse!(args)
514
+
515
+ if args.count != 1
516
+ raise_command_error "wrong number of arguments, expected 1 and got (#{args.count}) #{args}\n#{optparse}"
517
+ end
518
+
519
+ connect(options)
520
+ begin
521
+ budget = find_budget_by_name_or_id(args[0])
522
+ return 1 if budget.nil?
523
+
524
+ unless options[:yes] || MtnCloud::Cli::OptionTypes.confirm("Are you sure you want to delete the budget #{budget['name']}?")
525
+ return 9, "aborted command"
526
+ end
527
+ @budgets_interface.setopts(options)
528
+ if options[:dry_run]
529
+ print_dry_run @budgets_interface.dry.destroy(budget['id'])
530
+ return
531
+ end
532
+ json_response = @budgets_interface.destroy(budget['id'])
533
+ if options[:json]
534
+ print JSON.pretty_generate(json_response)
535
+ print "\n"
536
+ else
537
+ print_green_success "Budget #{budget['name']} removed"
538
+ # list([] + (options[:remote] ? ["-r",options[:remote]] : []))
539
+ end
540
+ return 0
541
+ rescue RestClient::Exception => e
542
+ print_rest_exception(e, options)
543
+ exit 1
544
+ end
545
+ end
546
+
547
+ private
548
+
549
+ def find_budget_by_name_or_id(val)
550
+ if val.to_s =~ /\A\d{1,}\Z/
551
+ return find_budget_by_id(val)
552
+ else
553
+ return find_budget_by_name(val)
554
+ end
555
+ end
556
+
557
+ def find_budget_by_id(id)
558
+ raise "#{self.class} has not defined @budgets_interface" if @budgets_interface.nil?
559
+ begin
560
+ json_response = @budgets_interface.get(id)
561
+ return json_response['budget']
562
+ rescue RestClient::Exception => e
563
+ if e.response && e.response.code == 404
564
+ print_red_alert "Budget not found by id #{id}"
565
+ else
566
+ raise e
567
+ end
568
+ end
569
+ end
570
+
571
+ def find_budget_by_name(name)
572
+ raise "#{self.class} has not defined @budgets_interface" if @budgets_interface.nil?
573
+ budgets = @budgets_interface.list({name: name.to_s})['budgets']
574
+ if budgets.empty?
575
+ print_red_alert "Budget not found by name #{name}"
576
+ return nil
577
+ elsif budgets.size > 1
578
+ print_red_alert "#{budgets.size} Budgets found by name #{name}"
579
+ print as_pretty_table(budgets, [:id,:name], {color:red})
580
+ print reset,"\n"
581
+ return nil
582
+ else
583
+ return budgets[0]
584
+ end
585
+ end
586
+
587
+ def add_budget_option_types
588
+ [
589
+ {'fieldName' => 'name', 'fieldLabel' => 'Name', 'type' => 'text', 'required' => true},
590
+ {'fieldName' => 'description', 'fieldLabel' => 'Description', 'type' => 'text'},
591
+ # {'fieldName' => 'enabled', 'fieldLabel' => 'Enabled', 'type' => 'checkbox', 'defaultValue' => true},
592
+ {'fieldName' => 'scope', 'fieldLabel' => 'Scope', 'code' => 'budget.scope', 'type' => 'select', 'selectOptions' => [{'name'=>'Account','value'=>'account'},{'name'=>'Tenant','value'=>'tenant'},{'name'=>'Cloud','value'=>'cloud'},{'name'=>'Group','value'=>'group'},{'name'=>'User','value'=>'user'}], 'defaultValue' => 'account', 'required' => true},
593
+ {'fieldName' => 'tenant', 'fieldLabel' => 'Tenant', 'type' => 'select', 'optionSource' => lambda {|api_client, api_params|
594
+ @options_interface.options_for_source("tenants", {})['data']
595
+ }, 'required' => true, 'dependsOnCode' => 'budget.scope:tenant'},
596
+ {'fieldName' => 'user', 'fieldLabel' => 'User', 'type' => 'select', 'optionSource' => lambda {|api_client, api_params|
597
+ @options_interface.options_for_source("users", {})['data']
598
+ }, 'required' => true, 'dependsOnCode' => 'budget.scope:user'},
599
+ {'fieldName' => 'group', 'fieldLabel' => 'Group', 'type' => 'select', 'optionSource' => lambda {|api_client, api_params|
600
+ @options_interface.options_for_source("groups", {})['data']
601
+ }, 'required' => true, 'dependsOnCode' => 'budget.scope:group'},
602
+ {'fieldName' => 'cloud', 'fieldLabel' => 'Cloud', 'type' => 'select', 'optionSource' => lambda {|api_client, api_params|
603
+ @options_interface.options_for_source("clouds", {})['data']
604
+ }, 'required' => true, 'dependsOnCode' => 'budget.scope:cloud'},
605
+ {'fieldName' => 'year', 'fieldLabel' => 'Period', 'code' => 'budget.year', 'type' => 'text', 'required' => true, 'defaultValue' => Time.now.year, 'description' => "The period (year) the budget applies, YYYY or 'custom' to enter Start Date and End Date manually"},
606
+ {'fieldName' => 'startDate', 'fieldLabel' => 'Start Date', 'type' => 'text', 'required' => true, 'description' => 'The Start Date for custom period budget eg. 2021-01-01', 'dependsOnCode' => 'budget.year:custom'},
607
+ {'fieldName' => 'endDate', 'fieldLabel' => 'End Date', 'type' => 'text', 'required' => true, 'description' => 'The End Date for custom period budget eg. 2023-12-31 (must be 1, 2 or 3 years from Start Date)', 'dependsOnCode' => 'budget.year:custom'},
608
+ {'fieldName' => 'interval', 'fieldLabel' => 'Interval', 'type' => 'select', 'selectOptions' => [{'name'=>'Year','value'=>'year'},{'name'=>'Quarter','value'=>'quarter'},{'name'=>'Month','value'=>'month'}], 'defaultValue' => 'year', 'required' => true, 'description' => 'The budget interval, determines cost amounts: "year", "quarter" or "month"'},
609
+ {'fieldName' => 'forecastType.id', 'fieldLabel' => 'Forecast Model', 'type' => 'select', 'optionSource' => 'forecastTypes', 'description' => 'The budget forcecast model type, determines projected cost calculations.'},
610
+ ]
611
+ end
612
+
613
+ def update_budget_option_types
614
+ list = add_budget_option_types()
615
+ # list = list.reject {|it| ["interval"].include? it['fieldName'] }
616
+ list.each {|it|
617
+ it.delete('required')
618
+ it.delete('defaultValue')
619
+ it.delete('dependsOnCode')
620
+ }
621
+ list
622
+ end
623
+
624
+ def prompt_costs(params={}, options={})
625
+ # user did -O costs="[3.50,3.50,3.50,5.00]" so just pass through
626
+ default_costs = []
627
+ if options[:options]['costs'] && options[:options]['costs'].is_a?(Array)
628
+ default_costs = options[:options]['costs']
629
+ default_costs.each_with_index do |default_cost, i|
630
+ interval_index = i + 1
631
+ if !default_cost.nil?
632
+ options[:options]["cost#{interval_index}"] = default_cost
633
+ end
634
+ end
635
+ end
636
+ # prompt for each Period Cost based on interval [year|quarter|month]
637
+ budget_period_year = (params['year'] || params['periodValue'])
638
+ is_custom = budget_period_year == 'custom'
639
+ interval = params['interval'] #.to_s.downcase
640
+ total_years = 1
641
+ total_months = 12
642
+ costs = []
643
+ # custom timeframe so prompt from start to end by interval
644
+ start_date = nil
645
+ end_date = nil
646
+
647
+ if is_custom
648
+ start_date = parse_time(params['startDate'])
649
+ if start_date.nil?
650
+ raise_command_error "startDate is required for custom period budgets"
651
+ end
652
+ end_date = parse_time(params['endDate'])
653
+ if end_date.nil?
654
+ raise_command_error "endDate is required for custom period budgets"
655
+ end
656
+ else
657
+ budget_year = budget_period_year ? budget_period_year.to_i : Time.now.year.to_i
658
+ start_date = Time.new(budget_year, 1, 1)
659
+ end_date = Time.new(budget_year, 12, 31)
660
+ end
661
+ epoch_start_month = (start_date.year * 12) + start_date.month
662
+ epoch_end_month = (end_date.year * 12) + end_date.month
663
+ # total_months gets + 1 because endDate is same year, on last day of the month, Dec 31 by default
664
+ total_months = (epoch_end_month - epoch_start_month) + 1
665
+ total_years = (total_months / 12)
666
+ cost_option_types = []
667
+ interval_count = total_months
668
+ if interval == 'year'
669
+ interval_count = total_months / 12
670
+ elsif interval == 'quarter'
671
+ interval_count = total_months / 3
672
+ end
673
+
674
+ is_fiscal = start_date.month != 1 || start_date.day != 1
675
+
676
+ # debug budget shenanigans
677
+ # puts "START: #{start_date}"
678
+ # puts "END: #{end_date}"
679
+ # puts "EPOCH MONTHS: #{epoch_start_month} - #{epoch_end_month}"
680
+ # puts "TOTAL MONTHS: #{total_months}"
681
+ # puts "INTERVAL COUNT IS: #{interval_count}"
682
+
683
+ if total_months < 0
684
+ raise_command_error "budget cannot end (#{end_date}) before it starts (#{start_date})"
685
+ end
686
+ if (total_months % 12) != 0 || (total_months > 36)
687
+ raise_command_error "budget custom period must be 12, 24, or 36 months."
688
+ end
689
+ if interval == 'year'
690
+ (1..interval_count).each_with_index do |interval_index, i|
691
+ interval_start_month = epoch_start_month + (i * 12)
692
+ interval_date = Time.new((interval_start_month / 12), (interval_start_month % 12) == 0 ? 12 : (interval_start_month % 12), 1)
693
+ display_year = is_fiscal ? "FY #{interval_date.year + 1}" : interval_date.year.to_s
694
+ field_name = "cost#{interval_index}"
695
+ field_label = "#{display_year} Cost"
696
+ cost_option_types << {'fieldName' => field_name, 'fieldLabel' => field_label, 'type' => 'text', 'required' => true, 'defaultValue' => (default_costs[i] || 0).to_s}
697
+ end
698
+ elsif interval == 'quarter'
699
+ (1..interval_count).each_with_index do |interval_index, i|
700
+ interval_start_month = epoch_start_month + (i * 3)
701
+ interval_date = Time.new((interval_start_month / 12), (interval_start_month % 12) == 0 ? 12 : (interval_start_month % 12), 1)
702
+ interval_end_date = Time.new((interval_start_month / 12), (interval_start_month % 12) == 0 ? 12 : (interval_start_month % 12), 1)
703
+ display_year = is_fiscal ? "FY #{interval_date.year + 1}" : interval_date.year.to_s
704
+ field_name = "cost#{interval_index}"
705
+ # field_label = "Q#{interval_index} Cost"
706
+ field_label = "Q#{(i % 4) + 1} #{display_year} Cost"
707
+ cost_option_types << {'fieldName' => field_name, 'fieldLabel' => field_label, 'type' => 'text', 'required' => true, 'defaultValue' => (default_costs[i] || 0).to_s}
708
+ end
709
+ elsif interval == 'month'
710
+ (1..interval_count).each_with_index do |interval_index, i|
711
+ interval_start_month = epoch_start_month + i
712
+ interval_date = Time.new((interval_start_month / 12), (interval_start_month % 12) == 0 ? 12 : (interval_start_month % 12), 1)
713
+ display_year = is_fiscal ? "FY #{interval_date.year + 1}" : interval_date.year.to_s
714
+ field_name = "cost#{interval_index}"
715
+ # field_label = "#{interval_date.strftime('%B %Y')} Cost"
716
+ field_label = "#{interval_date.strftime('%B')} #{display_year} Cost"
717
+ cost_option_types << {'fieldName' => field_name, 'fieldLabel' => field_label, 'type' => 'text', 'required' => true, 'defaultValue' => (default_costs[i] || 0).to_s}
718
+ end
719
+ end
720
+ # values is a Hash like {"cost1": 99.0, "cost2": 55.0}
721
+ values = MtnCloud::Cli::OptionTypes.prompt(cost_option_types, options[:options], @api_client)
722
+ values.each do |k,v|
723
+ interval_index = k[4..-1].to_i
724
+ costs[interval_index-1] = parse_cost_amount(v).to_f
725
+ end
726
+ return costs
727
+ end
728
+
729
+ def format_budget_scope(budget)
730
+ if budget['refScope'] && budget['refName']
731
+ "(#{budget['refScope']}) #{budget['refName']}"
732
+ elsif budget['refType']
733
+ budget['refType'] ? "#{budget['refType']} (#{budget['refId']}) #{budget['refName']}".strip : budget['refName'].to_s
734
+ else
735
+ ""
736
+ end
737
+ end
738
+
739
+ # convert String like "$5,499.99" to Float 5499.99
740
+ def parse_cost_amount(val)
741
+ val.to_s.gsub(",","").gsub('$','').strip.to_f
742
+ end
743
+
744
+ def format_budget_interval_label(budget, budget_interval)
745
+ label = ""
746
+ if budget_interval['chartName']
747
+ label = budget_interval['chartName']
748
+ else
749
+ label = (budget_interval['shortName'] || budget_interval['shortYear']).to_s
750
+ end
751
+ return label
752
+ end
753
+
754
+ end