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,1151 @@
1
+ require 'mtncloud/cli/cli_command'
2
+ require 'date' #needed?
3
+
4
+ class MtnCloud::Cli::InvoicesCommand
5
+ include MtnCloud::Cli::CliCommand
6
+ include MtnCloud::Cli::ProvisioningHelper
7
+ include MtnCloud::Cli::OptionSourceHelper
8
+
9
+ set_command_name :'invoices'
10
+
11
+ register_subcommands :list, :get, :update, :refresh,
12
+ :list_line_items, :get_line_item
13
+
14
+ def connect(opts)
15
+ @api_client = establish_remote_appliance_connection(opts)
16
+ @invoices_interface = @api_client.invoices
17
+ @invoice_line_items_interface = @api_client.invoice_line_items
18
+ end
19
+
20
+ def handle(args)
21
+ handle_subcommand(args)
22
+ end
23
+
24
+ def list(args)
25
+ options = {}
26
+ params = {}
27
+ ref_ids = []
28
+ optparse = MtnCloud::Cli::OptionParser.new do |opts|
29
+ opts.banner = subcommand_usage()
30
+ opts.on('-a', '--all', "Display all details, costs and prices." ) do
31
+ options[:show_all] = true
32
+ options[:show_dates] = true
33
+ options[:show_estimates] = true
34
+ options[:show_costs] = true
35
+ end
36
+ opts.on('--dates', "Display Ref Start, Ref End, etc.") do |val|
37
+ options[:show_dates] = true
38
+ end
39
+ opts.on('--costs', '--costs', "Display Costs in addition to prices" ) do
40
+ options[:show_costs] = true
41
+ end
42
+ opts.on('--estimates', '--estimates', "Display all estimated prices, from usage metering info: Compute, Memory, Storage, Network, Extra" ) do
43
+ options[:show_estimates] = true
44
+ end
45
+ opts.on('-t', '--type TYPE', "Filter by Ref Type eg. ComputeSite (Group), ComputeZone (Cloud), ComputeServer (Host), Instance, Container, User") do |val|
46
+ params['refType'] ||= []
47
+ values = val.split(",").collect {|it| it.strip }.select {|it| it != "" }
48
+ values.each { |it| params['refType'] << parse_invoice_ref_type(it) }
49
+ end
50
+ opts.on('--id ID', String, "Filter by Ref ID") do |val|
51
+ ref_ids << val
52
+ end
53
+ opts.on('--ref-id ID', String, "Filter by Ref ID") do |val|
54
+ ref_ids << val
55
+ end
56
+ opts.add_hidden_option('--ref-id')
57
+ opts.on('--group ID', String, "Filter by Group") do |val|
58
+ options[:groups] ||= []
59
+ options[:groups] << val
60
+ end
61
+ opts.on( '-c', '--cloud CLOUD', "Filter by Cloud" ) do |val|
62
+ options[:clouds] ||= []
63
+ options[:clouds] << val
64
+ end
65
+ opts.on('--instance ID', String, "Filter by Instance") do |val|
66
+ options[:instances] ||= []
67
+ options[:instances] << val
68
+ end
69
+ opts.on('--container ID', String, "Filter by Container") do |val|
70
+ params['containerId'] ||= []
71
+ params['containerId'] << val
72
+ end
73
+ opts.on('--server ID', String, "Filter by Server (Host)") do |val|
74
+ options[:servers] ||= []
75
+ options[:servers] << val
76
+ end
77
+ opts.on('--user ID', String, "Filter by User") do |val|
78
+ options[:users] ||= []
79
+ options[:users] << val
80
+ end
81
+ opts.on('--project PROJECT', String, "View invoices for a project.") do |val|
82
+ options[:projects] ||= []
83
+ options[:projects] << val
84
+ end
85
+ # opts.on('--cluster ID', String, "Filter by Cluster") do |val|
86
+ # params['clusterId'] ||= []
87
+ # params['clusterId'] << val
88
+ # end
89
+ opts.on('--start DATE', String, "Start date in the format YYYY-MM-DD.") do |val|
90
+ params['startDate'] = val #parse_time(val).utc.iso8601
91
+ end
92
+ opts.on('--end DATE', String, "End date in the format YYYY-MM-DD. Default is now.") do |val|
93
+ params['endDate'] = val #parse_time(val).utc.iso8601
94
+ end
95
+ opts.on('--period PERIOD', String, "Period in the format YYYYMM. This can be used instead of start/end.") do |val|
96
+ params['period'] = parse_period(val)
97
+ end
98
+ opts.on('--active [true|false]',String, "Filter by active.") do |val|
99
+ params['active'] = (val.to_s != 'false' && val.to_s != 'off')
100
+ end
101
+ opts.on('--estimate [true|false]',String, "Filter by estimate.") do |val|
102
+ params['estimate'] = (val.to_s != 'false' && val.to_s != 'off')
103
+ end
104
+ opts.on('--tenant ID', String, "View invoices for a tenant. Default is your own account.") do |val|
105
+ params['accountId'] = val
106
+ end
107
+ opts.on('--tags Name=Value',String, "Filter by tags.") do |val|
108
+ val.split(",").each do |value_pair|
109
+ k,v = value_pair.strip.split("=")
110
+ options[:tags] ||= {}
111
+ options[:tags][k] ||= []
112
+ options[:tags][k] << (v || '')
113
+ end
114
+ end
115
+ opts.on('--totals', "View total costs and prices for all the invoices found.") do |val|
116
+ params['includeTotals'] = true
117
+ options[:show_invoice_totals] = true
118
+ end
119
+ opts.on('--totals-only', "View totals only") do |val|
120
+ params['includeTotals'] = true
121
+ options[:show_invoice_totals] = true
122
+ options[:totals_only] = true
123
+ end
124
+ opts.on('--sigdig DIGITS', "Significant digits when rounding cost values for display as currency. Default is 2. eg. $3.50") do |val|
125
+ options[:sigdig] = val.to_i
126
+ end
127
+ opts.on('--test-count VALUE', "Test if value matches the total number of results found and exit with error code 3 if not.") do |val|
128
+ options[:test_count] = val.to_i
129
+ end
130
+ build_standard_list_options(opts, options)
131
+ opts.footer = "List invoices."
132
+ end
133
+ optparse.parse!(args)
134
+ connect(options)
135
+ # verify_args!(args:args, optparse:optparse, count:0)
136
+ if args.count > 0
137
+ options[:phrase] = args.join(" ")
138
+ end
139
+ # construct params
140
+ params.merge!(parse_list_options(options))
141
+ if options[:clouds]
142
+ cloud_ids = parse_cloud_id_list(options[:clouds], {}, false, true)
143
+ return 1, "clouds not found for #{options[:clouds]}" if cloud_ids.nil?
144
+ params['zoneId'] = cloud_ids
145
+ end
146
+ if options[:groups]
147
+ group_ids = parse_group_id_list(options[:groups], {}, false, true)
148
+ return 1, "groups not found for #{options[:groups]}" if group_ids.nil?
149
+ params['siteId'] = group_ids
150
+ end
151
+ if options[:instances]
152
+ instance_ids = parse_instance_id_list(options[:instances], {}, false, true)
153
+ return 1, "instances not found for #{options[:instances]}" if instance_ids.nil?
154
+ params['instanceId'] = instance_ids
155
+ end
156
+ if options[:servers]
157
+ server_ids = parse_server_id_list(options[:servers], {}, false, true)
158
+ return 1, "servers not found for #{options[:servers]}" if server_ids.nil?
159
+ params['serverId'] = server_ids
160
+ end
161
+ if options[:users]
162
+ user_ids = parse_user_id_list(options[:users], {}, false, true)
163
+ return 1, "users not found for #{options[:users]}" if user_ids.nil?
164
+ params['userId'] = user_ids
165
+ end
166
+ if options[:projects]
167
+ project_ids = parse_project_id_list(options[:projects], {}, false, true)
168
+ return 1, "projects not found for #{options[:projects]}" if project_ids.nil?
169
+ params['projectId'] = project_ids
170
+ end
171
+ params['refId'] = ref_ids unless ref_ids.empty?
172
+ if options[:tags] && !options[:tags].empty?
173
+ options[:tags].each do |k,v|
174
+ params['tags.' + k] = v
175
+ end
176
+ end
177
+ @invoices_interface.setopts(options)
178
+ if options[:dry_run]
179
+ print_dry_run @invoices_interface.dry.list(params)
180
+ return
181
+ end
182
+ json_response = @invoices_interface.list(params)
183
+ invoices = json_response['invoices']
184
+ render_response(json_response, options, 'invoices') do
185
+ title = "Invoices"
186
+ subtitles = []
187
+ if params['startDate']
188
+ subtitles << "Start Date: #{params['startDate']}"
189
+ end
190
+ if params['endDate']
191
+ subtitles << "End Date: #{params['endDate']}"
192
+ end
193
+ subtitles += parse_list_subtitles(options)
194
+ print_h1 title, subtitles
195
+ if invoices.empty?
196
+ print cyan,"No invoices found.",reset,"\n"
197
+ print reset,"\n"
198
+ else
199
+ # current_date = Time.now
200
+ # current_period = "#{current_date.year}#{current_date.month.to_s.rjust(2, '0')}"
201
+ show_projects = invoices.find {|it| it['project'] } || (params['projectId'] || params['projectName'] || params['projectTag'])
202
+ columns = [
203
+ {"INVOICE ID" => lambda {|it| it['id'] } },
204
+ {"TYPE" => lambda {|it| format_invoice_ref_type(it) } },
205
+ {"REF ID" => lambda {|it| it['refId'] } },
206
+ {"REF UUID" => lambda {|it| it['refUuid'] } },
207
+ {"REF NAME" => lambda {|it|
208
+ if options[:show_all]
209
+ it['refName']
210
+ else
211
+ truncate_string_right(it['refName'], 100)
212
+ end
213
+ } },
214
+ #{"INTERVAL" => lambda {|it| it['interval'] } },
215
+ {"CLOUD" => lambda {|it| it['cloud'] ? it['cloud']['name'] : '' } },
216
+ #{"TENANT" => lambda {|it| it['account'] ? it['account']['name'] : '' } },
217
+
218
+ #{"COST TYPE" => lambda {|it| it['costType'].to_s.capitalize } },
219
+ {"PERIOD" => lambda {|it| format_invoice_period(it) } },
220
+ {"START" => lambda {|it| format_date(it['startDate']) } },
221
+ {"END" => lambda {|it| format_date(it['endDate']) } },
222
+ ] + ((options[:show_dates] || options[:show_all]) ? [
223
+ {"REF START" => lambda {|it| format_dt(it['refStart']) } },
224
+ {"REF END" => lambda {|it| format_dt(it['refEnd']) } },
225
+ # {"LAST COST DATE" => lambda {|it| format_local_dt(it['lastCostDate']) } },
226
+ # {"LAST ACTUAL DATE" => lambda {|it| format_local_dt(it['lastActualDate']) } },
227
+ ] : []) + [
228
+ {"COMPUTE PRICE" => lambda {|it| format_money(it['computePrice'], it['currency'] || 'USD', {sigdig:options[:sigdig]}) } },
229
+ {"MEMORY PRICE" => lambda {|it| format_money(it['memoryPrice'], it['currency'] || 'USD', {sigdig:options[:sigdig]}) } },
230
+ {"STORAGE PRICE" => lambda {|it| format_money(it['storagePrice'], it['currency'] || 'USD', {sigdig:options[:sigdig]}) } },
231
+ {"NETWORK PRICE" => lambda {|it| format_money(it['networkPrice'], it['currency'] || 'USD', {sigdig:options[:sigdig]}) } },
232
+ {"EXTRA PRICE" => lambda {|it| format_money(it['extraPrice'], it['currency'] || 'USD', {sigdig:options[:sigdig]}) } },
233
+ {"MTD PRICE" => lambda {|it| format_money(it['runningPrice'], it['currency'] || 'USD', {sigdig:options[:sigdig]}) } },
234
+ {"TOTAL PRICE" => lambda {|it|
235
+ format_money(it['totalPrice'], it['currency'] || 'USD', {sigdig:options[:sigdig]}) + ((it['totalCost'].to_f > 0 && it['totalCost'] != it['runningCost']) ? " (Projected)" : "")
236
+ } }
237
+ ]
238
+
239
+ if options[:show_costs] && json_response['masterAccount'] != false
240
+ columns += [
241
+ {"COMPUTE COST" => lambda {|it| format_money(it['computeCost'], it['currency'] || 'USD', {sigdig:options[:sigdig]}) } },
242
+ {"MEMORY COST" => lambda {|it| format_money(it['memoryCost']) } },
243
+ {"STORAGE COST" => lambda {|it| format_money(it['storageCost'], it['currency'] || 'USD', {sigdig:options[:sigdig]}) } },
244
+ {"NETWORK COST" => lambda {|it| format_money(it['networkCost'], it['currency'] || 'USD', {sigdig:options[:sigdig]}) } },
245
+ {"EXTRA COST" => lambda {|it| format_money(it['extraCost'], it['currency'] || 'USD', {sigdig:options[:sigdig]}) } },
246
+ {"MTD COST" => lambda {|it| format_money(it['runningCost'], it['currency'] || 'USD', {sigdig:options[:sigdig]}) } },
247
+ {"TOTAL COST" => lambda {|it|
248
+ format_money(it['totalCost'], it['currency'] || 'USD', {sigdig:options[:sigdig]}) + ((it['totalCost'].to_f > 0 && it['totalCost'] != it['runningCost']) ? " (Projected)" : "")
249
+ } }
250
+ ]
251
+ end
252
+ if options[:show_estimates]
253
+ columns += [
254
+ {"METERED COMPUTE PRICE" => lambda {|it| format_money(it['estimatedComputePrice'], it['estimatedCurrency'] || 'USD', {sigdig:options[:sigdig]}) } },
255
+ {"METERED MEMORY PRICE" => lambda {|it| format_money(it['estimatedMemoryPrice'], it['estimatedCurrency'] || 'USD', {sigdig:options[:sigdig]}) } },
256
+ {"METERED STORAGE PRICE" => lambda {|it| format_money(it['estimatedStoragePrice'], it['estimatedCurrency'] || 'USD', {sigdig:options[:sigdig]}) } },
257
+ {"METERED NETWORK PRICE" => lambda {|it| format_money(it['estimatedNetworkPrice'], it['estimatedCurrency'] || 'USD', {sigdig:options[:sigdig]}) } },
258
+ {"METERED EXTRA PRICE" => lambda {|it| format_money(it['estimatedExtraPrice'], it['estimatedCurrency'] || 'USD', {sigdig:options[:sigdig]}) } },
259
+ {"METERED MTD PRICE" => lambda {|it| format_money(it['estimatedRunningPrice'], it['estimatedCurrency'] || 'USD', {sigdig:options[:sigdig]}) } },
260
+ {"METERED TOTAL PRICE" => lambda {|it|
261
+ format_money(it['estimatedTotalPrice'], it['estimatedCurrency'] || 'USD', {sigdig:options[:sigdig]}) + ((it['estimatedTotalPrice'].to_f > 0 && it['estimatedTotalPrice'] != it['estimatedRunningPrice']) ? " (Projected)" : "")
262
+ } },
263
+ ]
264
+ if options[:show_costs] && json_response['masterAccount'] != false
265
+ columns += [
266
+ {"METERED COMPUTE COST" => lambda {|it| format_money(it['estimatedComputeCost'], it['estimatedCurrency'] || 'USD', {sigdig:options[:sigdig]}) } },
267
+ {"METERED MEMORY COST" => lambda {|it| format_money(it['estimatedMemoryCost'], it['estimatedCurrency'] || 'USD', {sigdig:options[:sigdig]}) } },
268
+ {"METERED STORAGE COST" => lambda {|it| format_money(it['estimatedStorageCost'], it['estimatedCurrency'] || 'USD', {sigdig:options[:sigdig]}) } },
269
+ {"METERED NETWORK COST" => lambda {|it| format_money(it['estimatedNetworkCost'], it['estimatedCurrency'] || 'USD', {sigdig:options[:sigdig]}) } },
270
+ {"METERED EXTRA COST" => lambda {|it| format_money(it['estimatedExtraCost'], it['estimatedCurrency'] || 'USD', {sigdig:options[:sigdig]}) } },
271
+ {"METERED MTD COST" => lambda {|it| format_money(it['estimatedRunningCost'], it['estimatedCurrency'] || 'USD', {sigdig:options[:sigdig]}) } },
272
+ {"METERED TOTAL COST" => lambda {|it|
273
+ format_money(it['estimatedTotalCost'], it['estimatedCurrency'] || 'USD', {sigdig:options[:sigdig]}) + ((it['estimatedTotalCost'].to_f > 0 && it['estimatedTotalCost'] != it['estimatedRunningCost']) ? " (Projected)" : "")
274
+ } },
275
+ ]
276
+ end
277
+ end
278
+ columns += [
279
+ {"ESTIMATE" => lambda {|it| format_boolean(it['estimate']) } },
280
+ {"ACTIVE" => lambda {|it| format_boolean(it['active']) } },
281
+ {"ITEMS" => lambda {|it| (it['lineItemCount'] ? it['lineItemCount'] : it['lineItems'].size) rescue '' } },
282
+ {"TAGS" => lambda {|it| (it['metadata'] || it['tags']) ? (it['metadata'] || it['tags']).collect {|m| "#{m['name']}: #{m['value']}" }.join(', ') : '' } },
283
+ ]
284
+ if show_projects
285
+ columns += [
286
+ {"PROJECT ID" => lambda {|it| it['project'] ? it['project']['id'] : '' } },
287
+ {"PROJECT NAME" => lambda {|it| it['project'] ? it['project']['name'] : '' } },
288
+ {"PROJECT TAGS" => lambda {|it| it['project'] ? truncate_string(format_metadata(it['project']['tags']), 50) : '' } },
289
+ ]
290
+ end
291
+ if options[:show_dates]
292
+ columns += [
293
+ {"LAST COST DATE" => lambda {|it| format_local_dt(it['lastCostDate']) } },
294
+ {"LAST ACTUAL DATE" => lambda {|it| format_local_dt(it['lastActualDate']) } },
295
+ ]
296
+ end
297
+ columns += [
298
+ {"CREATED" => lambda {|it| format_local_dt(it['dateCreated']) } },
299
+ {"UPDATED" => lambda {|it| format_local_dt(it['lastUpdated']) } },
300
+ ]
301
+ unless options[:totals_only]
302
+ print as_pretty_table(invoices, columns, options)
303
+ print_results_pagination(json_response, {:label => "invoice", :n_label => "invoices"})
304
+ end
305
+
306
+ if options[:show_invoice_totals]
307
+ invoice_totals = json_response['invoiceTotals']
308
+ print_h2 "Invoice Totals (#{format_number(json_response['meta']['total']) rescue ''})"
309
+
310
+ if invoice_totals
311
+ cost_rows = [
312
+ {label: 'Price'.upcase, compute: invoice_totals['actualComputePrice'], memory: invoice_totals['actualMemoryPrice'], storage: invoice_totals['actualStoragePrice'], network: invoice_totals['actualNetworkPrice'], license: invoice_totals['actualLicensePrice'], extra: invoice_totals['actualExtraPrice'], running: invoice_totals['actualRunningPrice'], total: invoice_totals['actualTotalPrice'], currency: invoice_totals['actualCurrency']},
313
+ ]
314
+ if options[:show_costs]
315
+ cost_rows += [
316
+ {label: 'Cost'.upcase, compute: invoice_totals['actualComputeCost'], memory: invoice_totals['actualMemoryCost'], storage: invoice_totals['actualStorageCost'], network: invoice_totals['actualNetworkCost'], license: invoice_totals['actualLicenseCost'], extra: invoice_totals['actualExtraCost'], running: invoice_totals['actualRunningCost'], total: invoice_totals['actualTotalCost'], currency: invoice_totals['actualCurrency']}
317
+ ]
318
+ end
319
+ if options[:show_estimates]
320
+ cost_rows += [
321
+ {label: 'Metered Price'.upcase, compute: invoice_totals['estimatedComputePrice'], memory: invoice_totals['estimatedMemoryPrice'], storage: invoice_totals['estimatedStoragePrice'], network: invoice_totals['estimatedNetworkPrice'], license: invoice_totals['estimatedLicensePrice'], extra: invoice_totals['estimatedExtraPrice'], running: invoice_totals['estimatedRunningPrice'], total: invoice_totals['estimatedTotalPrice'], currency: invoice_totals['estimatedCurrency']}
322
+ ]
323
+ if options[:show_costs]
324
+ cost_rows += [
325
+ {label: 'Metered Cost'.upcase, compute: invoice_totals['estimatedComputeCost'], memory: invoice_totals['estimatedMemoryCost'], storage: invoice_totals['estimatedStorageCost'], network: invoice_totals['estimatedNetworkCost'], license: invoice_totals['estimatedLicenseCost'], extra: invoice_totals['estimatedExtraCost'], running: invoice_totals['estimatedRunningCost'], total: invoice_totals['estimatedTotalCost'], currency: invoice_totals['estimatedCurrency']}
326
+ ]
327
+ end
328
+ end
329
+ cost_columns = {
330
+ "" => lambda {|it| it[:label] },
331
+ "Compute" => lambda {|it| format_money(it[:compute], it[:currency] || it[:currency] || 'USD', {sigdig:options[:sigdig]}) },
332
+ "Memory" => lambda {|it| format_money(it[:memory], it[:currency] || 'USD', {sigdig:options[:sigdig]}) },
333
+ "Storage" => lambda {|it| format_money(it[:storage], it[:currency] || 'USD', {sigdig:options[:sigdig]}) },
334
+ "Network" => lambda {|it| format_money(it[:network], it[:currency] || 'USD', {sigdig:options[:sigdig]}) },
335
+ "License" => lambda {|it| format_money(it[:license], it[:currency] || 'USD', {sigdig:options[:sigdig]}) },
336
+ "Extra" => lambda {|it| format_money(it[:extra], it[:currency] || 'USD', {sigdig:options[:sigdig]}) },
337
+ "MTD" => lambda {|it| format_money(it[:running], it[:currency] || 'USD', {sigdig:options[:sigdig]}) },
338
+ "Total" => lambda {|it|
339
+ format_money(it[:total], it[:currency] || 'USD', {sigdig:options[:sigdig]}) + ((it[:total].to_f > 0 && it[:total] != it[:running]) ? " (Projected)" : "")
340
+ },
341
+ "Currency" => lambda {|it| it[:currency] },
342
+ }.upcase_keys!
343
+ # remove columns that rarely have data...
344
+ if cost_rows.sum { |it| it[:memory].to_f } == 0
345
+ cost_columns.delete("Memory".upcase)
346
+ end
347
+ if cost_rows.sum { |it| it[:license].to_f } == 0
348
+ cost_columns.delete("License".upcase)
349
+ end
350
+ if cost_rows.sum { |it| it[:extra].to_f } == 0
351
+ cost_columns.delete("Extra".upcase)
352
+ end
353
+ print as_pretty_table(cost_rows, cost_columns, options.merge(include_fields: nil))
354
+ else
355
+ print "\n"
356
+ print yellow, "No invoice totals data", reset, "\n"
357
+ end
358
+ end
359
+ print reset,"\n"
360
+ end
361
+ total_count = (json_response["meta"]["total"] rescue nil)
362
+ if options[:test_count] && options[:test_count] != total_count
363
+ return 3, "Test count failure. Expected #{options[:test_count]} and got #{total_count}"
364
+ end
365
+ return 0, nil
366
+ end
367
+ end
368
+
369
+ def get(args)
370
+ options, params = {}, {}
371
+ optparse = MtnCloud::Cli::OptionParser.new do |opts|
372
+ opts.banner = subcommand_usage("[id]")
373
+ opts.on('-a', '--all', "Display all details, costs and prices." ) do
374
+ options[:show_estimates] = true
375
+ options[:show_costs] = true
376
+ options[:max_line_items] = 10000
377
+ end
378
+ opts.on('--estimates', '--estimates', "Display all estimated prices, from usage metering info: Compute, Memory, Storage, Network, Extra" ) do
379
+ options[:show_estimates] = true
380
+ end
381
+ opts.on('--costs', '--costs', "Display Costs in addition to prices" ) do
382
+ options[:show_costs] = true
383
+ end
384
+ opts.on('--no-line-items', '--no-line-items', "Do not display line items.") do
385
+ options[:hide_line_items] = true
386
+ end
387
+ opts.on('--max-line-items VALUE', 'String', "Max line items to load. Default is 1000.") do |val|
388
+ params['maxLineItems'] = val.to_i
389
+ end
390
+ opts.on('--sigdig DIGITS', "Significant digits when rounding cost values for display as currency. Default is 2. eg. $3.50") do |val|
391
+ options[:sigdig] = val.to_i
392
+ end
393
+ build_standard_get_options(opts, options)
394
+ opts.footer = <<-EOT
395
+ Get details about a specific invoice.
396
+ [id] is required. This is the id of an invoice.
397
+ EOT
398
+ end
399
+ optparse.parse!(args)
400
+ verify_args!(args:args, optparse:optparse, min:1)
401
+ connect(options)
402
+ params.merge!(parse_query_options(options))
403
+ id_list = parse_id_list(args)
404
+ return run_command_for_each_arg(id_list) do |arg|
405
+ _get(arg, params, options)
406
+ end
407
+ end
408
+
409
+ def _get(id, params, options)
410
+ @invoices_interface.setopts(options)
411
+ if options[:dry_run]
412
+ print_dry_run @invoices_interface.dry.get(id, params)
413
+ return
414
+ end
415
+ json_response = @invoices_interface.get(id, params)
416
+ if options[:hide_line_items]
417
+ json_response['invoice'].delete('lineItems') rescue nil
418
+ end
419
+ render_response(json_response, options, invoice_object_key) do
420
+ invoice = json_response[invoice_object_key]
421
+ print_h1 "Invoice Details"
422
+ print cyan
423
+ description_cols = {
424
+ "Invoice ID" => lambda {|it| it['id'] },
425
+ "Type" => lambda {|it| format_invoice_ref_type(it) },
426
+ "Ref ID" => lambda {|it| it['refId'] },
427
+ "Ref Name" => lambda {|it| it['refName'] },
428
+ "Cloud" => lambda {|it| it['cloud'] ? it['cloud']['name'] : '' },
429
+ "Plan" => lambda {|it| it['plan'] ? it['plan']['name'] : '' },
430
+ "Power State" => lambda {|it| format_server_power_state(it) },
431
+ "Tenant" => lambda {|it| it['account'] ? it['account']['name'] : '' },
432
+ "Active" => lambda {|it| format_boolean(it['active']) },
433
+ "Estimate" => lambda {|it| format_boolean(it['estimate']) },
434
+ #"Cost Type" => lambda {|it| it['costType'].to_s.capitalize },
435
+ "Period" => lambda {|it| format_invoice_period(it) },
436
+ #"Interval" => lambda {|it| it['interval'] },
437
+ "Start" => lambda {|it| format_date(it['startDate']) },
438
+ "End" => lambda {|it| format_date(it['endDate']) },
439
+ "Ref Start" => lambda {|it| format_dt(it['refStart']) },
440
+ "Ref End" => lambda {|it| format_dt(it['refEnd']) },
441
+ "Currency" => lambda {|it| (it['estimate'] ? it['estimatedCurrency'] : it['currency']) || 'USD' },
442
+ "Conversion Rate" => lambda {|it| (it['estimate'] ? it['estimatedConversionRate'] : it['conversionRate']) },
443
+ # "Estimated Currency" => lambda {|it| it['estimatedCurrency'] },
444
+ # "Estimated Conversion Rate" => lambda {|it| it['estimatedConversionRate'] },
445
+ "Items" => lambda {|it| (it['lineItemCount'] ? it['lineItemCount'] : it['lineItems'].size) rescue '' },
446
+ "Tags" => lambda {|it| (it['metadata'] || it['tags']) ? (it['metadata'] || it['tags']).collect {|m| "#{m['name']}: #{m['value']}" }.join(', ') : '' },
447
+ "Project ID" => lambda {|it| it['project'] ? it['project']['id'] : '' },
448
+ "Project Name" => lambda {|it| it['project'] ? it['project']['name'] : '' },
449
+ "Project Tags" => lambda {|it| it['project'] ? format_metadata(it['project']['tags']) : '' },
450
+ "Created" => lambda {|it| format_local_dt(it['dateCreated']) },
451
+ "Updated" => lambda {|it| format_local_dt(it['lastUpdated']) }
452
+ }
453
+ # remove columns that do not apply
454
+ if invoice['plan'].nil?
455
+ description_cols.delete("Plan")
456
+ end
457
+ if invoice['project'].nil?
458
+ description_cols.delete("Project ID")
459
+ description_cols.delete("Project Name")
460
+ description_cols.delete("Project Tags")
461
+ end
462
+ tags = (invoice['metadata'] || invoice['tags'])
463
+ if tags.nil? || tags.empty?
464
+ description_cols.delete("Tags")
465
+ end
466
+ if !['ComputeServer','Instance','Container'].include?(invoice['refType'])
467
+ description_cols.delete("Power State")
468
+ end
469
+ # if invoice['currency'].nil? || invoice['currency'] == 'USD'
470
+ # description_cols.delete("Currency")
471
+ # end
472
+ # if invoice['actualConversionRate'].nil? || invoice['actualConversionRate'] == 1
473
+ # description_cols.delete("Conversion Rate")
474
+ # end
475
+ print_description_list(description_cols, invoice)
476
+
477
+ # Line Items
478
+ line_items = invoice['lineItems']
479
+ if line_items && line_items.size > 0 && options[:hide_line_items] != true
480
+ line_items_columns = [
481
+ {"ID" => lambda {|it| it['id'] } },
482
+ #{"REF TYPE" => lambda {|it| format_invoice_ref_type(it) } },
483
+ #{"REF ID" => lambda {|it| it['refId'] } },
484
+ #{"REF NAME" => lambda {|it| it['refName'] } },
485
+ #{"REF CATEGORY" => lambda {|it| it['refCategory'] } },
486
+ {"START" => lambda {|it| format_dt(it['startDate']) } },
487
+ {"END" => lambda {|it| format_dt(it['endDate']) } },
488
+ {"USAGE TYPE" => lambda {|it| it['usageType'] } },
489
+ {"USAGE CATEGORY" => lambda {|it| it['usageCategory'] } },
490
+ {"USAGE" => lambda {|it| it['itemUsage'] } },
491
+ {"RATE" => lambda {|it| it['itemRate'] } },
492
+ {"UNIT" => lambda {|it| it['rateUnit'] } },
493
+ {"COST" => lambda {|it| format_money(it['itemCost'], it['currency'] || 'USD', {sigdig:options[:sigdig]}) } },
494
+ {"PRICE" => lambda {|it| format_money(it['itemPrice'], it['currency'] || 'USD', {sigdig:options[:sigdig]}) } },
495
+ #{"TAX" => lambda {|it| format_money(it['itemTax'], it['currency'] || 'USD', {sigdig:options[:sigdig]}) } },
496
+ # {"TERM" => lambda {|it| it['itemTerm'] } },
497
+ {"ITEM ID" => lambda {|it| truncate_string_right(it['itemId'], 65) } },
498
+ {"ITEM NAME" => lambda {|it| it['itemName'] } },
499
+ {"ITEM TYPE" => lambda {|it| it['itemType'] } },
500
+ {"ITEM DESCRIPTION" => lambda {|it| it['itemDescription'] } },
501
+ {"PRODUCT CODE" => lambda {|it| it['productCode'] } },
502
+ {"CREATED" => lambda {|it| format_local_dt(it['dateCreated']) } },
503
+ {"UPDATED" => lambda {|it| format_local_dt(it['lastUpdated']) } }
504
+ ]
505
+ print_h2 "Line Items"
506
+ #max_line_items = options[:max_line_items] ? options[:max_line_items].to_i : 5
507
+ paged_line_items = line_items #.first(max_line_items)
508
+ print as_pretty_table(paged_line_items, line_items_columns, options)
509
+ print_results_pagination({total: line_items.size, size: paged_line_items.size}, {:label => "line item", :n_label => "line items"})
510
+ end
511
+
512
+ print_h2 "Invoice Totals"
513
+
514
+ cost_rows = [
515
+ {label: 'Price'.upcase, compute: invoice['computePrice'], memory: invoice['memoryPrice'], storage: invoice['storagePrice'], network: invoice['networkPrice'], license: invoice['licensePrice'], extra: invoice['extraPrice'], running: invoice['runningPrice'], total: invoice['totalPrice'], currency: invoice['currency']},
516
+ ]
517
+ if options[:show_costs] # && json_response['masterAccount'] != false
518
+ cost_rows += [
519
+ {label: 'Cost'.upcase, compute: invoice['computeCost'], memory: invoice['memoryCost'], storage: invoice['storageCost'], network: invoice['networkCost'], license: invoice['licenseCost'], extra: invoice['extraCost'], running: invoice['runningCost'], total: invoice['totalCost'], currency: invoice['currency']},
520
+ ]
521
+ end
522
+ if options[:show_estimates]
523
+ cost_rows += [
524
+ {label: 'Metered Price'.upcase, compute: invoice['estimatedComputePrice'], memory: invoice['estimatedMemoryPrice'], storage: invoice['estimatedStoragePrice'], network: invoice['estimatedNetworkPrice'], license: invoice['estimatedLicensePrice'], extra: invoice['estimatedExtraPrice'], running: invoice['estimatedRunningPrice'], total: invoice['estimatedTotalPrice'], currency: invoice['estimatedCurrency']}
525
+ ]
526
+ if options[:show_costs] # && json_response['masterAccount'] != false
527
+ cost_rows += [
528
+ {label: 'Metered Cost'.upcase, compute: invoice['estimatedComputeCost'], memory: invoice['estimatedMemoryCost'], storage: invoice['estimatedStorageCost'], network: invoice['estimatedNetworkCost'], license: invoice['estimatedLicenseCost'], extra: invoice['estimatedExtraCost'], running: invoice['estimatedRunningCost'], total: invoice['estimatedTotalCost'], currency: invoice['estimatedCurrency']},
529
+ ]
530
+ end
531
+ end
532
+ cost_columns = {
533
+ "" => lambda {|it| it[:label] },
534
+ "Compute" => lambda {|it| format_money(it[:compute], it[:currency] || 'USD', {sigdig:options[:sigdig]}) },
535
+ "Memory" => lambda {|it| format_money(it[:memory], it[:currency] || 'USD', {sigdig:options[:sigdig]}) },
536
+ "Storage" => lambda {|it| format_money(it[:storage], it[:currency] || 'USD', {sigdig:options[:sigdig]}) },
537
+ "Network" => lambda {|it| format_money(it[:network], it[:currency] || 'USD', {sigdig:options[:sigdig]}) },
538
+ "License" => lambda {|it| format_money(it[:license], it[:currency] || 'USD', {sigdig:options[:sigdig]}) },
539
+ "Extra" => lambda {|it| format_money(it[:extra], it[:currency] || 'USD', {sigdig:options[:sigdig]}) },
540
+ "MTD" => lambda {|it| format_money(it[:running], it[:currency] || 'USD', {sigdig:options[:sigdig]}) },
541
+ "Total" => lambda {|it|
542
+ format_money(it[:total], it[:currency] || 'USD', {sigdig:options[:sigdig]}) + ((it[:total].to_f > 0 && it[:total] != it[:running]) ? " (Projected)" : "")
543
+ },
544
+ "Currency" => lambda {|it| it[:currency] },
545
+ }.upcase_keys!
546
+ # remove columns that rarely have data...
547
+ if cost_rows.sum { |it| it[:memory].to_f } == 0
548
+ cost_columns.delete("Memory".upcase)
549
+ end
550
+ if cost_rows.sum { |it| it[:license].to_f } == 0
551
+ cost_columns.delete("License".upcase)
552
+ end
553
+ if cost_rows.sum { |it| it[:extra].to_f } == 0
554
+ cost_columns.delete("Extra".upcase)
555
+ end
556
+ print as_pretty_table(cost_rows, cost_columns, options)
557
+ print reset,"\n"
558
+ end
559
+ return 0, nil
560
+ end
561
+
562
+ def update(args)
563
+ options = {}
564
+ params = {}
565
+ payload = {}
566
+ optparse = MtnCloud::Cli::OptionParser.new do |opts|
567
+ opts.banner = subcommand_usage("[invoice] [options]")
568
+ opts.on('--tags LIST', String, "Tags in the format 'name:value, name:value'. This will add and remove tags.") do |val|
569
+ options[:tags] = val
570
+ end
571
+ opts.on('--add-tags TAGS', String, "Add Tags in the format 'name:value, name:value'. This will only add/update tags.") do |val|
572
+ options[:add_tags] = val
573
+ end
574
+ opts.on('--remove-tags TAGS', String, "Remove Tags in the format 'name, name:value'. This removes tags, the :value component is optional and must match if passed.") do |val|
575
+ options[:remove_tags] = val
576
+ end
577
+ build_standard_update_options(opts, options)
578
+ opts.footer = <<-EOT
579
+ Update an invoice.
580
+ [invoice] is required. This is the id of an invoice.
581
+ EOT
582
+ end
583
+ optparse.parse!(args)
584
+ verify_args!(args:args, optparse:optparse, count:1)
585
+ connect(options)
586
+ json_response = @invoices_interface.get(args[0])
587
+ invoice = json_response['invoice']
588
+
589
+ invoice_payload = parse_passed_options(options)
590
+ if options[:tags]
591
+ invoice_payload['tags'] = parse_metadata(options[:tags])
592
+ end
593
+ if options[:add_tags]
594
+ invoice_payload['addTags'] = parse_metadata(options[:add_tags])
595
+ end
596
+ if options[:remove_tags]
597
+ invoice_payload['removeTags'] = parse_metadata(options[:remove_tags])
598
+ end
599
+
600
+ payload = {}
601
+ if options[:payload]
602
+ payload = options[:payload]
603
+ payload.deep_merge!({'invoice' => invoice_payload})
604
+ else
605
+ payload.deep_merge!({'invoice' => invoice_payload})
606
+ if invoice_payload.empty?
607
+ raise_command_error "Specify at least one option to update.\n#{optparse}"
608
+ end
609
+ end
610
+ @invoices_interface.setopts(options)
611
+ if options[:dry_run]
612
+ print_dry_run @invoices_interface.dry.update(invoice['id'], payload)
613
+ return
614
+ end
615
+ json_response = @invoices_interface.update(invoice['id'], payload)
616
+ invoice = json_response['invoice']
617
+ render_response(json_response, options, 'invoice') do
618
+ print_green_success "Updated invoice #{invoice['id']}"
619
+ return _get(invoice["id"], {}, options)
620
+ end
621
+ return 0, nil
622
+ end
623
+
624
+ def refresh(args)
625
+ options = {}
626
+ params = {}
627
+ payload = {}
628
+ optparse = MtnCloud::Cli::OptionParser.new do |opts|
629
+ opts.banner = subcommand_usage("[-c CLOUD]")
630
+ opts.on( '-c', '--clouds CLOUD', "Specify clouds to refresh costing for." ) do |val|
631
+ payload[:clouds] ||= []
632
+ payload[:clouds] << val
633
+ end
634
+ opts.on( '--all', "Refresh costing for all clouds. This can be used instead of --clouds" ) do
635
+ payload[:all] = true
636
+ end
637
+ opts.on( '--date DATE', String, "Date to collect costing for. By default the cost data is collected for the end of the previous job interval (hour or day)." ) do |val|
638
+ payload[:date] = val.to_s
639
+ end
640
+ opts.on( '--period PERIOD', "Period in the format YYYYMM to process invoices for. Default is the current period. This is an alias for the --date option." ) do |val|
641
+ payload[:date] = val.to_s
642
+ end
643
+ opts.on( '--rebuild', "Rebuild invoices for period. Only applies to mode=costing." ) do |val|
644
+ payload[:rebuild] = val.to_s == 'on' || val.to_s == 'true' || val.to_s == '1' || val.to_s == ''
645
+ end
646
+ build_standard_update_options(opts, options, [:query, :auto_confirm])
647
+ opts.footer = <<-EOT
648
+ Refresh invoice costing data for the specified clouds.
649
+ EOT
650
+ end
651
+ optparse.parse!(args)
652
+ verify_args!(args:args, optparse:optparse, count:0)
653
+ connect(options)
654
+ params.merge!(parse_query_options(options))
655
+ if options[:payload]
656
+ payload = options[:payload]
657
+ end
658
+ payload.deep_merge!(parse_passed_options(options))
659
+ # --clouds lookup ID for name
660
+ if payload[:clouds]
661
+ cloud_ids = parse_cloud_id_list(payload[:clouds], {}, false, true)
662
+ return 1, "clouds not found for #{payload[:clouds]}" if cloud_ids.nil?
663
+ payload[:clouds] = cloud_ids
664
+ end
665
+ # are you sure?
666
+ unless options[:yes] || MtnCloud::Cli::OptionTypes.confirm("Are you sure you want to refresh invoices?")
667
+ return 9, "aborted command"
668
+ end
669
+ # ok, make the request
670
+ @invoices_interface.setopts(options)
671
+ if options[:dry_run]
672
+ print_dry_run @invoices_interface.dry.refresh(params, payload)
673
+ return
674
+ end
675
+ json_response = @invoices_interface.refresh(params, payload)
676
+ # render the result
677
+ render_result = render_with_format(json_response, options)
678
+ return 0 if render_result
679
+ # print output
680
+ print_green_success(json_response['msg'] || "Refreshing invoices")
681
+ return 0
682
+ end
683
+
684
+ def list_line_items(args)
685
+ options = {}
686
+ params = {}
687
+ ref_ids = []
688
+ optparse = MtnCloud::Cli::OptionParser.new do |opts|
689
+ opts.banner = subcommand_usage()
690
+ opts.on('-a', '--all', "Display all details, costs and prices." ) do
691
+ options[:show_actual_costs] = true
692
+ options[:show_costs] = true
693
+ options[:details] = true
694
+ end
695
+ # opts.on('--actuals', '--actuals', "Display all actual costs: Compute, Memory, Storage, Network, Extra" ) do
696
+ # options[:show_actual_costs] = true
697
+ # end
698
+ opts.on('--costs', '--costs', "Display costs in addition to prices" ) do
699
+ options[:show_costs] = true
700
+ end
701
+ opts.on('--invoice-id ID', String, "Filter by Invoice ID") do |val|
702
+ params['invoiceId'] ||= []
703
+ params['invoiceId'] << val
704
+ end
705
+ opts.on('--external-id ID', String, "Filter by External ID") do |val|
706
+ params['externalId'] ||= []
707
+ params['externalId'] << val
708
+ end
709
+ opts.on('-t', '--type TYPE', "Filter by Ref Type eg. ComputeSite (Group), ComputeZone (Cloud), ComputeServer (Host), Instance, Container, User") do |val|
710
+ params['refType'] ||= []
711
+ values = val.split(",").collect {|it| it.strip }.select {|it| it != "" }
712
+ values.each { |it| params['refType'] << parse_invoice_ref_type(it) }
713
+ end
714
+ opts.on('--id ID', String, "Filter by Ref ID") do |val|
715
+ ref_ids << val
716
+ end
717
+ opts.on('--ref-id ID', String, "Filter by Ref ID") do |val|
718
+ ref_ids << val
719
+ end
720
+ opts.add_hidden_option('--ref-id')
721
+ opts.on('--group ID', String, "Filter by Group") do |val|
722
+ options[:groups] ||= []
723
+ options[:groups] << val
724
+ end
725
+ opts.on( '-c', '--cloud CLOUD', "Filter by Cloud" ) do |val|
726
+ options[:clouds] ||= []
727
+ options[:clouds] << val
728
+ end
729
+ opts.on('--instance ID', String, "Filter by Instance") do |val|
730
+ options[:instances] ||= []
731
+ options[:instances] << val
732
+ end
733
+ opts.on('--container ID', String, "Filter by Container") do |val|
734
+ params['containerId'] ||= []
735
+ params['containerId'] << val
736
+ end
737
+ opts.on('--server ID', String, "Filter by Server (Host)") do |val|
738
+ options[:servers] ||= []
739
+ options[:servers] << val
740
+ end
741
+ opts.on('--user ID', String, "Filter by User") do |val|
742
+ options[:users] ||= []
743
+ options[:users] << val
744
+ end
745
+ opts.on('--project PROJECT', String, "View invoices for a project.") do |val|
746
+ options[:projects] ||= []
747
+ options[:projects] << val
748
+ end
749
+ # opts.on('--cluster ID', String, "Filter by Cluster") do |val|
750
+ # params['clusterId'] ||= []
751
+ # params['clusterId'] << val
752
+ # end
753
+ opts.on('--start DATE', String, "Start date in the format YYYY-MM-DD.") do |val|
754
+ params['startDate'] = val #parse_time(val).utc.iso8601
755
+ end
756
+ opts.on('--end DATE', String, "End date in the format YYYY-MM-DD. Default is now.") do |val|
757
+ params['endDate'] = val #parse_time(val).utc.iso8601
758
+ end
759
+ opts.on('--period PERIOD', String, "Period in the format YYYYMM. This can be used instead of start/end.") do |val|
760
+ params['period'] = parse_period(val)
761
+ end
762
+ opts.on('--active [true|false]',String, "Filter by active.") do |val|
763
+ params['active'] = (val.to_s != 'false' && val.to_s != 'off')
764
+ end
765
+ opts.on('--estimate [true|false]',String, "Filter by estimate.") do |val|
766
+ params['estimate'] = (val.to_s != 'false' && val.to_s != 'off')
767
+ end
768
+ opts.on('--tenant ID', String, "View invoice line items for a tenant. Default is your own account.") do |val|
769
+ params['accountId'] = val
770
+ end
771
+ opts.on('--tags Name=Value',String, "Filter by tags.") do |val|
772
+ val.split(",").each do |value_pair|
773
+ k,v = value_pair.strip.split("=")
774
+ options[:tags] ||= {}
775
+ options[:tags][k] ||= []
776
+ options[:tags][k] << (v || '')
777
+ end
778
+ end
779
+ opts.on('--totals', "View total costs and prices for all the invoices found.") do |val|
780
+ params['includeTotals'] = true
781
+ options[:show_invoice_totals] = true
782
+ end
783
+ opts.on('--sigdig DIGITS', "Significant digits when rounding cost values for display as currency. Default is 2. eg. $3.50") do |val|
784
+ options[:sigdig] = val.to_i
785
+ end
786
+ opts.on('--test-count VALUE', "Test if value matches the total number of results found and exit with error code 3 if not.") do |val|
787
+ options[:test_count] = val.to_i
788
+ end
789
+ opts.add_hidden_option('--test-count')
790
+ build_standard_list_options(opts, options)
791
+ opts.footer = "List invoice line items."
792
+ end
793
+ optparse.parse!(args)
794
+ connect(options)
795
+ # verify_args!(args:args, optparse:optparse, count:0)
796
+ if args.count > 0
797
+ options[:phrase] = args.join(" ")
798
+ end
799
+
800
+ # construct params
801
+ params.merge!(parse_list_options(options))
802
+ if options[:clouds]
803
+ cloud_ids = parse_cloud_id_list(options[:clouds], {}, false, true)
804
+ return 1, "clouds not found for #{options[:clouds]}" if cloud_ids.nil?
805
+ params['zoneId'] = cloud_ids
806
+ end
807
+ if options[:groups]
808
+ group_ids = parse_group_id_list(options[:groups], {}, false, true)
809
+ return 1, "groups not found for #{options[:groups]}" if group_ids.nil?
810
+ params['siteId'] = group_ids
811
+ end
812
+ if options[:instances]
813
+ instance_ids = parse_instance_id_list(options[:instances], {}, false, true)
814
+ return 1, "instances not found for #{options[:instances]}" if instance_ids.nil?
815
+ params['instanceId'] = instance_ids
816
+ end
817
+ if options[:servers]
818
+ server_ids = parse_server_id_list(options[:servers], {}, false, true)
819
+ return 1, "servers not found for #{options[:servers]}" if server_ids.nil?
820
+ params['serverId'] = server_ids
821
+ end
822
+ if options[:users]
823
+ user_ids = parse_user_id_list(options[:users], {}, false, true)
824
+ return 1, "users not found for #{options[:users]}" if user_ids.nil?
825
+ params['userId'] = user_ids
826
+ end
827
+ if options[:projects]
828
+ project_ids = parse_project_id_list(options[:projects], {}, false, true)
829
+ return 1, "projects not found for #{options[:projects]}" if project_ids.nil?
830
+ params['projectId'] = project_ids
831
+ end
832
+ params['refId'] = ref_ids unless ref_ids.empty?
833
+ if options[:tags] && !options[:tags].empty?
834
+ options[:tags].each do |k,v|
835
+ params['tags.' + k] = v
836
+ end
837
+ end
838
+ @invoice_line_items_interface.setopts(options)
839
+ if options[:dry_run]
840
+ print_dry_run @invoice_line_items_interface.dry.list(params)
841
+ return
842
+ end
843
+ json_response = @invoice_line_items_interface.list(params)
844
+ line_items = json_response['lineItems']
845
+ render_response(json_response, options, 'lineItems') do
846
+ title = "Line Items"
847
+ subtitles = []
848
+ if params['startDate']
849
+ subtitles << "Start Date: #{params['startDate']}"
850
+ end
851
+ if params['endDate']
852
+ subtitles << "End Date: #{params['endDate']}"
853
+ end
854
+ subtitles += parse_list_subtitles(options)
855
+ print_h1 title, subtitles
856
+ if line_items.empty?
857
+ print cyan,"No line items found.",reset,"\n"
858
+ else
859
+ # current_date = Time.now
860
+ # current_period = "#{current_date.year}#{current_date.month.to_s.rjust(2, '0')}"
861
+ columns = [
862
+ {"ID" => lambda {|it| it['id'] } },
863
+ {"INVOICE ID" => lambda {|it| it['invoiceId'] } },
864
+ {"TYPE" => lambda {|it| format_invoice_ref_type(it) } },
865
+ {"REF ID" => lambda {|it| it['refId'] } },
866
+ {"REF NAME" => lambda {|it| it['refName'] } },
867
+ #{"REF CATEGORY" => lambda {|it| it['refCategory'] } },
868
+ {"START" => lambda {|it| format_date(it['startDate']) } },
869
+ {"END" => lambda {|it| format_date(it['endDate']) } },
870
+ {"USAGE TYPE" => lambda {|it| it['usageType'] } },
871
+ {"USAGE CATEGORY" => lambda {|it| it['usageCategory'] } },
872
+ {"USAGE" => lambda {|it| it['itemUsage'] } },
873
+ {"RATE" => lambda {|it| it['itemRate'] } },
874
+ {"UNIT" => lambda {|it| it['rateUnit'] } },
875
+ {"PRICE" => lambda {|it| format_money(it['itemPrice'], it['currency'] || 'USD', {sigdig:options[:sigdig]}) } },
876
+ ] + (options[:show_costs] ? [
877
+ {"COST" => lambda {|it| format_money(it['itemCost'], it['currency'] || 'USD', {sigdig:options[:sigdig]}) } },
878
+ {"TAX" => lambda {|it| format_money(it['itemTax'], it['currency'] || 'USD', {sigdig:options[:sigdig]}) } },
879
+ ] : []) + [
880
+ {"ITEM ID" => lambda {|it| options[:details] ? it['itemId'] : truncate_string_right(it['itemId'], 65) } },
881
+ {"ITEM NAME" => lambda {|it| it['itemName'] } },
882
+ {"ITEM TYPE" => lambda {|it| it['itemType'] } },
883
+ {"ITEM DESCRIPTION" => lambda {|it| it['itemDescription'] } },
884
+ {"PRODUCT CODE" => lambda {|it| it['productCode'] } },
885
+ "CREATED" => lambda {|it| format_local_dt(it['dateCreated']) },
886
+ "UPDATED" => lambda {|it| format_local_dt(it['lastUpdated']) }
887
+ ]
888
+
889
+ # if options[:show_invoice_totals]
890
+ # line_item_totals = json_response['lineItemTotals']
891
+ # if line_item_totals
892
+ # totals_row = line_item_totals.clone
893
+ # totals_row['id'] = 'TOTAL:'
894
+ # #totals_row['usageCategory'] = 'TOTAL:'
895
+ # line_items = line_items + [totals_row]
896
+ # end
897
+ # end
898
+ unless options[:totals_only]
899
+ print as_pretty_table(line_items, columns, options)
900
+ print_results_pagination(json_response, {:label => "line item", :n_label => "line items"})
901
+ end
902
+
903
+ if options[:show_invoice_totals]
904
+ line_item_totals = json_response['lineItemTotals']
905
+ if line_item_totals
906
+ print_h2 "Line Item Totals" unless options[:totals_only]
907
+ invoice_totals_columns = [
908
+ {"Items" => lambda {|it| format_number(json_response['meta']['total']) rescue '' } },
909
+ #{"Usage" => lambda {|it| it['itemUsage'] } },
910
+ {"Price" => lambda {|it| format_money(it['itemPrice'], it['currency'] || 'USD', {sigdig:options[:sigdig]}) } },
911
+ ] + (options[:show_costs] ? [
912
+ {"Cost" => lambda {|it| format_money(it['itemCost'], it['currency'] || 'USD', {sigdig:options[:sigdig]}) } },
913
+ #{"Tax" => lambda {|it| format_money(it['itemTax'], it['currency'] || 'USD', {sigdig:options[:sigdig]}) } },
914
+
915
+ ] : [])
916
+ print_description_list(invoice_totals_columns, line_item_totals)
917
+ else
918
+ print "\n"
919
+ print yellow, "No line item totals data", reset, "\n"
920
+ end
921
+ end
922
+
923
+ end
924
+ print reset,"\n"
925
+ end
926
+ total_count = (json_response["meta"]["total"] rescue nil)
927
+ if options[:test_count] && options[:test_count] != total_count
928
+ return 3, "Test count failure. Expected #{options[:test_count]} and got #{total_count}"
929
+ end
930
+ return 0, nil
931
+ end
932
+
933
+ def get_line_item(args)
934
+ options, params = {}, {}
935
+ optparse = MtnCloud::Cli::OptionParser.new do |opts|
936
+ opts.banner = subcommand_usage("[id]")
937
+ opts.on('--sigdig DIGITS', "Significant digits when rounding cost values for display as currency. Default is 2. eg. $3.50") do |val|
938
+ options[:sigdig] = val.to_i
939
+ end
940
+ build_standard_get_options(opts, options)
941
+ opts.footer = <<-EOT
942
+ Get details about a specific invoice line item.
943
+ [id] is required. This is the id of an invoice line item.
944
+ EOT
945
+ end
946
+ optparse.parse!(args)
947
+ verify_args!(args:args, optparse:optparse, min:1)
948
+ connect(options)
949
+ params.merge!(parse_query_options(options))
950
+ id_list = parse_id_list(args)
951
+ return run_command_for_each_arg(id_list) do |arg|
952
+ _get_line_item(arg, params, options)
953
+ end
954
+ end
955
+
956
+
957
+ def _get_line_item(id, params, options)
958
+ @invoice_line_items_interface.setopts(options)
959
+ if options[:dry_run]
960
+ print_dry_run @invoice_line_items_interface.dry.get(id, params)
961
+ return
962
+ end
963
+ json_response = @invoice_line_items_interface.get(id, params)
964
+ line_item = json_response['lineItem']
965
+ render_response(json_response, options, 'lineItem') do
966
+ print_h1 "Line Item Details"
967
+ print cyan
968
+ description_cols = {
969
+ "ID" => lambda {|it| it['id'] },
970
+ "Invoice ID" => lambda {|it| it['invoiceId'] },
971
+ "Type" => lambda {|it| format_invoice_ref_type(it) },
972
+ "Ref ID" => lambda {|it| it['refId'] },
973
+ "Ref Name" => lambda {|it| it['refName'] },
974
+ "Start" => lambda {|it| format_date(it['startDate']) },
975
+ "End" => lambda {|it| it['endDate'] ? format_date(it['endDate']) : '' },
976
+ "Usage Type" => lambda {|it| it['usageType'] },
977
+ "Usage Category" => lambda {|it| it['usageCategory'] },
978
+ "Item Usage" => lambda {|it| it['itemUsage'] },
979
+ "Item Rate" => lambda {|it| it['itemRate'] },
980
+ "Item Cost" => lambda {|it| format_money(it['itemCost'], it['currency'] || 'USD', {sigdig:options[:sigdig]}) },
981
+ "Item Price" => lambda {|it| format_money(it['itemPrice'], it['currency'] || 'USD', {sigdig:options[:sigdig]}) },
982
+ #"Item Tax" => lambda {|it| format_money(it['itemTax'], it['currency'] || 'USD', {sigdig:options[:sigdig]}) },
983
+ #"Tax Type" => lambda {|it| it['taxType'] },
984
+ "Item Term" => lambda {|it| it['itemTerm'] },
985
+ "Item ID" => lambda {|it| it['itemId'] },
986
+ "Item Name" => lambda {|it| it['itemName'] },
987
+ "Item Type" => lambda {|it| it['itemType'] },
988
+ "Item Description" => lambda {|it| it['itemDescription'] },
989
+ "Product Code" => lambda {|it| it['productCode'] },
990
+ "Created" => lambda {|it| format_local_dt(it['dateCreated']) },
991
+ "Updated" => lambda {|it| format_local_dt(it['lastUpdated']) }
992
+ }
993
+ print_description_list(description_cols, line_item, options)
994
+
995
+ print reset,"\n"
996
+ end
997
+ return 0, nil
998
+ end
999
+
1000
+ private
1001
+
1002
+ def invoice_object_key
1003
+ 'invoice'
1004
+ end
1005
+
1006
+ def invoice_list_key
1007
+ 'invoices'
1008
+ end
1009
+
1010
+ def invoice_line_item_object_key
1011
+ 'lineItem'
1012
+ end
1013
+
1014
+ def invoice_line_item_list_key
1015
+ 'lineItems'
1016
+ end
1017
+
1018
+ # def find_invoice_by_name_or_id(val)
1019
+ # if val.to_s =~ /\A\d{1,}\Z/
1020
+ # return find_invoice_by_id(val)
1021
+ # else
1022
+ # return find_invoice_by_name(val)
1023
+ # end
1024
+ # end
1025
+
1026
+ def find_invoice_by_id(id)
1027
+ begin
1028
+ json_response = @invoices_interface.get(id.to_i)
1029
+ return json_response['invoice']
1030
+ rescue RestClient::Exception => e
1031
+ if e.response && e.response.code == 404
1032
+ print_red_alert "Invoice not found by id #{id}"
1033
+ else
1034
+ raise e
1035
+ end
1036
+ end
1037
+ end
1038
+
1039
+ # def find_invoice_by_name(name)
1040
+ # invoices = @invoices_interface.list({name: name.to_s})['invoices']
1041
+ # if invoices.empty?
1042
+ # print_red_alert "Invoice not found by name #{name}"
1043
+ # return nil
1044
+ # elsif invoices.size > 1
1045
+ # print_red_alert "#{invoices.size} invoices found by name #{name}"
1046
+ # print_invoices_table(invoices, {color: red})
1047
+ # print_red_alert "Try using ID instead"
1048
+ # print reset,"\n"
1049
+ # return nil
1050
+ # else
1051
+ # return invoices[0]
1052
+ # end
1053
+ # end
1054
+
1055
+ def format_invoice_ref_type(it)
1056
+ if it['refType'] == 'ComputeZone'
1057
+ "Cloud"
1058
+ # elsif it['refType'] == 'ComputeServer'
1059
+ # "Host"
1060
+ elsif it['refType'] == 'ComputeServerGroup'
1061
+ "Cluster"
1062
+ elsif it['refType'] == 'ComputeSite'
1063
+ "Group"
1064
+ else
1065
+ it['refType']
1066
+ end
1067
+ end
1068
+
1069
+ def parse_invoice_ref_type(ref_type)
1070
+ val = ref_type.to_s.downcase
1071
+ if val == 'cloud' || val == 'zone'
1072
+ 'ComputeZone'
1073
+ elsif val == 'instance'
1074
+ 'Instance'
1075
+ elsif val == 'server' || val == 'host'
1076
+ 'ComputeServer'
1077
+ elsif val == 'cluster'
1078
+ 'ComputeServerGroup'
1079
+ elsif val == 'group' || val == 'site'
1080
+ 'ComputeSite'
1081
+ elsif val == 'user'
1082
+ 'User'
1083
+ else
1084
+ ref_type
1085
+ end
1086
+ end
1087
+
1088
+ # convert "202003" to "March 2020"
1089
+ def format_invoice_period(it)
1090
+ interval = it['interval']
1091
+ period = it['period']
1092
+ if period
1093
+ if interval == 'month'
1094
+ year = period[0..3]
1095
+ month = period[4..5]
1096
+ if year && month
1097
+ month_name = Date::MONTHNAMES[month.to_i] || "#{month}?"
1098
+ return "#{month_name} #{year}"
1099
+ else
1100
+ return "#{year}"
1101
+ end
1102
+ else
1103
+ return it['period']
1104
+ end
1105
+ else
1106
+ return "n/a"
1107
+ end
1108
+ end
1109
+
1110
+ # convert "March 2020" to "202003"
1111
+ def parse_period(period, interval='month')
1112
+ if period
1113
+ if interval == 'month'
1114
+ if period.include?(" ")
1115
+ period_parts = period.split(" ")
1116
+ month = Date::MONTHNAMES.index(period_parts[0])
1117
+ year = period_parts[1].to_i
1118
+ if month
1119
+ return "#{year}#{month.to_s.rjust(2, '0')}"
1120
+ else
1121
+ return "#{year}00" # meh, bad month name, raise error probably
1122
+ end
1123
+ else
1124
+ return "#{period}"
1125
+ end
1126
+ else
1127
+ return "#{period}"
1128
+ end
1129
+ else
1130
+ return nil
1131
+ end
1132
+ end
1133
+
1134
+ def get_current_period()
1135
+ now = Time.now.utc
1136
+ now.year.to_s + now.month.to_s.rjust(2,'0')
1137
+ end
1138
+
1139
+ def format_server_power_state(server, return_color=cyan)
1140
+ out = ""
1141
+ if server['powerState'] == 'on'
1142
+ out << "#{green}ON#{return_color}"
1143
+ elsif server['powerState'] == 'off'
1144
+ out << "#{red}OFF#{return_color}"
1145
+ else
1146
+ out << "#{white}#{server['powerState'].to_s.upcase}#{return_color}"
1147
+ end
1148
+ out
1149
+ end
1150
+
1151
+ end