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,2297 @@
1
+ require 'mtncloud/cli/cli_command'
2
+
3
+ class MtnCloud::Cli::BlueprintsCommand
4
+ include MtnCloud::Cli::CliCommand
5
+ include MtnCloud::Cli::ProvisioningHelper
6
+ include MtnCloud::Cli::AccountsHelper # needed? replace with OptionSourceHelper
7
+ include MtnCloud::Cli::OptionSourceHelper
8
+
9
+ set_command_name :'blueprints'
10
+ register_subcommands :list, :get, :add, :update, :remove
11
+ register_subcommands :'types' => :list_types
12
+ register_subcommands :duplicate
13
+ register_subcommands :'upload-image' => :upload_image
14
+ register_subcommands :'update-permissions' => :update_permissions
15
+ register_subcommands :'available-tiers'
16
+ register_subcommands :'add-tier', :'update-tier', :'remove-tier', :'connect-tiers', :'disconnect-tiers'
17
+ register_subcommands :'add-instance'
18
+ #register_subcommands :'update-instance'
19
+ register_subcommands :'remove-instance'
20
+ register_subcommands :'add-instance-config'
21
+ #register_subcommands :'update-instance-config'
22
+ register_subcommands :'remove-instance-config'
23
+ # alias_subcommand :details, :get
24
+ # set_default_subcommand :list
25
+
26
+ def initialize()
27
+ # @appliance_name, @appliance_url = MtnCloud::Cli::Remote.active_appliance
28
+ end
29
+
30
+ def connect(opts)
31
+ @api_client = establish_remote_appliance_connection(opts)
32
+ @blueprints_interface = @api_client.blueprints
33
+ @groups_interface = @api_client.groups
34
+ @instances_interface = @api_client.instances
35
+ @instance_types_interface = @api_client.instance_types
36
+ @options_interface = @api_client.options
37
+ @active_group_id = MtnCloud::Cli::Groups.active_groups[@appliance_name]
38
+ @clouds_interface = @api_client.clouds
39
+ @account_users_interface = @api_client.account_users
40
+ @library_layouts_interface = @api_client.library_layouts
41
+ end
42
+
43
+ def handle(args)
44
+ handle_subcommand(args)
45
+ end
46
+
47
+ def list(args)
48
+ params = {}
49
+ options = {}
50
+ optparse = MtnCloud::Cli::OptionParser.new do |opts|
51
+ opts.banner = subcommand_usage()
52
+ opts.on('-t', '--type CODE', "Blueprint Type") do |val|
53
+ params['type'] ||= []
54
+ params['type'] << val
55
+ end
56
+ opts.on( '--owner USER', "Owner Username or ID" ) do |val|
57
+ params['ownerId'] ||= []
58
+ params['ownerId'] << val
59
+ end
60
+ opts.on( '--created-by USER', "Alias for --owner" ) do |val|
61
+ params['ownerId'] ||= []
62
+ params['ownerId'] << val
63
+ end
64
+ opts.add_hidden_option('--created-by')
65
+ opts.on('-l', '--labels LABEL', String, "Filter by labels, can match any of the values") do |val|
66
+ add_query_parameter(params, 'labels', parse_labels(val))
67
+ end
68
+ opts.on('--all-labels LABEL', String, "Filter by labels, must match all of the values") do |val|
69
+ add_query_parameter(params, 'allLabels', parse_labels(val))
70
+ end
71
+ build_standard_list_options(opts, options)
72
+ opts.footer = "List blueprints."
73
+ end
74
+ optparse.parse!(args)
75
+ connect(options)
76
+ # verify_args!(args:args, optparse:optparse, count:0)
77
+ if args.count > 0
78
+ options[:phrase] = args.join(" ")
79
+ end
80
+ begin
81
+ if params['ownerId']
82
+ params['ownerId'] = params['ownerId'].collect do |owner_id|
83
+ # user = find_user_by_username_or_id(nil, owner_id)
84
+ user = find_available_user_option(owner_id)
85
+ return 1 if user.nil?
86
+ user['id']
87
+ end
88
+ end
89
+ params.merge!(parse_list_options(options))
90
+ @blueprints_interface.setopts(options)
91
+ if options[:dry_run]
92
+ print_dry_run @blueprints_interface.dry.list(params)
93
+ return
94
+ end
95
+
96
+ json_response = @blueprints_interface.list(params)
97
+ blueprints = json_response['blueprints']
98
+
99
+ if options[:json]
100
+ puts as_json(json_response, options, "blueprints")
101
+ return 0
102
+ elsif options[:csv]
103
+ puts records_as_csv(json_response['blueprints'], options)
104
+ return 0
105
+ elsif options[:yaml]
106
+ puts as_yaml(json_response, options, "blueprints")
107
+ return 0
108
+ end
109
+
110
+
111
+ title = "Blueprints"
112
+ subtitles = []
113
+ subtitles += parse_list_subtitles(options)
114
+ print_h1 title, subtitles
115
+
116
+ if blueprints.empty?
117
+ print cyan,"No blueprints found.",reset,"\n"
118
+ else
119
+ print_blueprints_table(blueprints, options)
120
+ print_results_pagination(json_response)
121
+ end
122
+ print reset,"\n"
123
+ return 0
124
+
125
+ rescue RestClient::Exception => e
126
+ print_rest_exception(e, options)
127
+ exit 1
128
+ end
129
+ end
130
+
131
+ def get(args)
132
+ options = {}
133
+ optparse = MtnCloud::Cli::OptionParser.new do |opts|
134
+ opts.banner = subcommand_usage("[blueprint]")
135
+ opts.on( '-c', '--config', "Display raw config only. Default is YAML. Combine with -j for JSON instead." ) do
136
+ options[:show_config] = true
137
+ end
138
+ build_standard_get_options(opts, options)
139
+ opts.footer = "Get details about a blueprint.\n" +
140
+ "[blueprint] is required. This is the name or id of a blueprint. Supports 1-N [instance] arguments."
141
+ end
142
+ optparse.parse!(args)
143
+ if args.count < 1
144
+ raise_command_error "wrong number of arguments, expected 1-N and got (#{args.count}) #{args.join(', ')}\n#{optparse}"
145
+ end
146
+ connect(options)
147
+ id_list = parse_id_list(args)
148
+ return run_command_for_each_arg(id_list) do |arg|
149
+ _get(arg, options)
150
+ end
151
+ end
152
+
153
+ def _get(arg, options)
154
+ connect(options)
155
+ begin
156
+ if options[:dry_run]
157
+ @blueprints_interface.setopts(options)
158
+ if args[0].to_s =~ /\A\d{1,}\Z/
159
+ print_dry_run @blueprints_interface.dry.get(arg.to_i)
160
+ else
161
+ print_dry_run @blueprints_interface.dry.list({name:arg})
162
+ end
163
+ return
164
+ end
165
+ @blueprints_interface.setopts(options)
166
+ blueprint = find_blueprint_by_name_or_id(arg)
167
+ if blueprint.nil?
168
+ return 1, "blueprint not found"
169
+ end
170
+ json_response = {'blueprint' => blueprint} # skip redundant request
171
+ #json_response = @blueprints_interface.get(blueprint['id'])
172
+ blueprint = json_response['blueprint']
173
+
174
+ # export just the config as json or yaml (default)
175
+ if options[:show_config]
176
+ unless options[:json] || options[:yaml] || options[:csv]
177
+ options[:yaml] = true
178
+ end
179
+ return render_with_format(blueprint['config'], options)
180
+ end
181
+ render_response(json_response, options, 'blueprint') do
182
+ print_h1 "Blueprint Details"
183
+ print_blueprint_details(blueprint)
184
+ end
185
+ return 0, nil
186
+ rescue RestClient::Exception => e
187
+ print_rest_exception(e, options)
188
+ exit 1
189
+ end
190
+ end
191
+
192
+ def add(args)
193
+ options = {}
194
+ optparse = MtnCloud::Cli::OptionParser.new do |opts|
195
+ opts.banner = subcommand_usage("[name] [options]")
196
+ build_option_type_options(opts, options, add_blueprint_option_types(false))
197
+ opts.on('-t', '--type TYPE', String, "Blueprint Type. Default is morpheus.") do |val|
198
+ options[:blueprint_type] = parse_blueprint_type(val.to_s)
199
+ end
200
+ opts.on('-l', '--labels [LIST]', String, "Labels") do |val|
201
+ options[:options]['labels'] = parse_labels(val)
202
+ end
203
+ build_standard_add_options(opts, options)
204
+ opts.footer = "Create a new blueprint.\n" +
205
+ "[name] is required. This is the name of the new blueprint."
206
+ end
207
+ optparse.parse!(args)
208
+ verify_args!(args:args, optparse:optparse, min:0, max:1)
209
+ if args[0]
210
+ options[:options]['name'] = args[0]
211
+ end
212
+ connect(options)
213
+ begin
214
+ payload = {}
215
+ passed_options = options[:options] ? options[:options].reject {|k,v| k.is_a?(Symbol) } : {}
216
+ if options[:payload]
217
+ payload = options[:payload]
218
+ payload.deep_merge!(passed_options) unless passed_options.empty?
219
+ else
220
+ # prompt for payload
221
+ payload = {}
222
+ payload.deep_merge!(passed_options) unless passed_options.empty?
223
+ if options[:blueprint_type]
224
+ options[:options]['type'] = options[:blueprint_type]
225
+ else
226
+ # options[:options]['type'] = 'mtncloud'
227
+ end
228
+ params = MtnCloud::Cli::OptionTypes.prompt(add_blueprint_option_types, options[:options], @api_client, options[:params])
229
+ params.deep_compact!
230
+ # expects no namespace, just the config
231
+ payload.deep_merge!(params)
232
+ end
233
+ @blueprints_interface.setopts(options)
234
+ if options[:dry_run]
235
+ print_dry_run @blueprints_interface.dry.create(payload)
236
+ return
237
+ end
238
+
239
+ json_response = @blueprints_interface.create(payload)
240
+ blueprint = json_response['blueprint']
241
+ render_response(json_response, options, 'blueprint') do
242
+ print_green_success "Added blueprint #{blueprint['name']}"
243
+ if !options[:no_prompt]
244
+ if options[:payload].nil? && ::MtnCloud::Cli::OptionTypes::confirm("Would you like to add a tier now?", options.merge({default: false}))
245
+ add_tier([blueprint['id']])
246
+ while ::MtnCloud::Cli::OptionTypes::confirm("Add another tier?", options.merge({default: false})) do
247
+ add_tier([blueprint['id']])
248
+ end
249
+ else
250
+ # print details
251
+ return _get(blueprint["id"], options)
252
+ end
253
+ end
254
+ end
255
+ return 0, nil
256
+ rescue RestClient::Exception => e
257
+ print_rest_exception(e, options)
258
+ exit 1
259
+ end
260
+ end
261
+
262
+ def update(args)
263
+ payload, options = {}, {}
264
+ optparse = MtnCloud::Cli::OptionParser.new do |opts|
265
+ opts.banner = subcommand_usage("[blueprint] [options]")
266
+ build_option_type_options(opts, options, update_blueprint_option_types(false))
267
+ opts.on( '--owner USER', "Owner Username or ID" ) do |val|
268
+ options[:owner] = val == 'null' ? nil : val
269
+ end
270
+ opts.on('-l', '--labels [LIST]', String, "Labels") do |val|
271
+ options[:options]['labels'] = parse_labels(val)
272
+ end
273
+ build_standard_update_options(opts, options)
274
+ opts.footer = "Update a blueprint.\n" +
275
+ "[blueprint] is required. This is the name or id of a blueprint."
276
+ end
277
+ optparse.parse!(args)
278
+ if args.count != 1
279
+ raise_command_error "wrong number of arguments, expected 1 and got (#{args.count}) #{args.join(', ')}\n#{optparse}"
280
+ end
281
+ connect(options)
282
+ begin
283
+ blueprint = find_blueprint_by_name_or_id(args[0])
284
+ return 1 if blueprint.nil?
285
+ payload = {}
286
+ if options[:payload]
287
+ payload = options[:payload]
288
+ payload.deep_merge!(parse_passed_options(options))
289
+ else
290
+ # no prompting, just merge passed options
291
+ payload = blueprint["config"]
292
+ end
293
+ payload.deep_merge!(parse_passed_options(options))
294
+ # Owner
295
+ if options.key?(:owner)
296
+ owner_id = options[:owner]
297
+ if owner_id.to_s.empty?
298
+ # allow clearing
299
+ owner_id = nil
300
+ elsif options[:owner]
301
+ if owner_id.to_s =~ /\A\d{1,}\Z/
302
+ # allow id without lookup
303
+ else
304
+ user = find_available_user_option(owner_id)
305
+ return 1 if user.nil?
306
+ owner_id = user['id']
307
+ end
308
+ end
309
+ # payload['blueprint'] ||= {}
310
+ # payload['blueprint']['ownerId'] = owner_id
311
+ payload['ownerId'] = owner_id
312
+ end
313
+ if payload.empty?
314
+ # this wont happen because its sending back the current config
315
+ raise_command_error "Specify at least one option to update.\n#{optparse}"
316
+ end
317
+ @blueprints_interface.setopts(options)
318
+ if options[:dry_run]
319
+ print_dry_run @blueprints_interface.dry.update(blueprint['id'], payload)
320
+ return
321
+ end
322
+
323
+ json_response = @blueprints_interface.update(blueprint['id'], payload)
324
+
325
+ if options[:json]
326
+ print JSON.pretty_generate(json_response)
327
+ print "\n"
328
+ else
329
+ unless options[:quiet]
330
+ blueprint = json_response['blueprint']
331
+ print_green_success "Updated blueprint #{blueprint['name']}"
332
+ get([blueprint['id']] + (options[:remote] ? ["-r",options[:remote]] : []))
333
+ end
334
+ end
335
+
336
+ rescue RestClient::Exception => e
337
+ print_rest_exception(e, options)
338
+ exit 1
339
+ end
340
+ end
341
+
342
+ def update_permissions(args)
343
+ payload, options = {}, {}
344
+ group_access_all = nil
345
+ group_access_list = nil
346
+ group_defaults_list = nil
347
+ optparse = MtnCloud::Cli::OptionParser.new do |opts|
348
+ opts.banner = subcommand_usage("[blueprint] [options]")
349
+ opts.on('--group-access-all [on|off]', String, "Toggle Access for all groups.") do |val|
350
+ group_access_all = val.to_s == 'on' || val.to_s == 'true' || val.to_s == ''
351
+ end
352
+ opts.on('--group-access LIST', Array, "Group Access, comma separated list of group IDs.") do |list|
353
+ if list.size == 1 && list[0] == 'null' # hacky way to clear it
354
+ group_access_list = []
355
+ else
356
+ group_access_list = list.collect {|it| it.to_s.strip.empty? ? nil : it.to_s.strip }.compact.uniq
357
+ end
358
+ end
359
+ opts.on('--visibility [private|public]', String, "Visibility") do |val|
360
+ options['visibility'] = val
361
+ end
362
+ opts.on( '--owner USER', "Owner Username or ID" ) do |val|
363
+ options[:owner] = val == 'null' ? nil : val
364
+ end
365
+ build_option_type_options(opts, options, update_blueprint_option_types(false))
366
+ build_standard_update_options(opts, options)
367
+ opts.footer = "Update a blueprint permissions.\n" +
368
+ "[blueprint] is required. This is the name or id of a blueprint."
369
+ end
370
+ optparse.parse!(args)
371
+
372
+ if args.count != 1
373
+ puts optparse
374
+ return 1
375
+ end
376
+
377
+ connect(options)
378
+
379
+ begin
380
+ blueprint = find_blueprint_by_name_or_id(args[0])
381
+ return 1 if blueprint.nil?
382
+ if options[:payload]
383
+ payload = options[:payload]
384
+ end
385
+ payload['blueprint'] ||= {}
386
+ payload.deep_merge!(parse_passed_options(options))
387
+ # Group Access
388
+ if group_access_all != nil
389
+ payload['resourcePermissions'] ||= {}
390
+ payload['resourcePermissions']['all'] = group_access_all
391
+ end
392
+ if group_access_list != nil
393
+ payload['resourcePermissions'] ||= {}
394
+ payload['resourcePermissions']['sites'] = group_access_list.collect do |site_id|
395
+ site = {"id" => site_id.to_i}
396
+ if group_defaults_list && group_defaults_list.include?(site_id)
397
+ site["default"] = true
398
+ end
399
+ site
400
+ end
401
+ end
402
+ # Visibility
403
+ if options['visibility'] != nil
404
+ payload['blueprint']['visibility'] = options['visibility'].to_s.downcase
405
+ end
406
+ # Owner
407
+ if options.key?(:owner)
408
+ owner_id = options[:owner]
409
+ if owner_id.to_s.empty?
410
+ # allow clearing
411
+ owner_id = nil
412
+ elsif options[:owner]
413
+ if owner_id.to_s =~ /\A\d{1,}\Z/
414
+ # allow id without lookup
415
+ else
416
+ user = find_available_user_option(owner_id)
417
+ return 1 if user.nil?
418
+ owner_id = user['id']
419
+ end
420
+ end
421
+ payload['blueprint']['ownerId'] = owner_id
422
+ end
423
+ if payload['blueprint'] && payload['blueprint'].empty?
424
+ payload.delete('blueprint')
425
+ end
426
+ if payload.empty?
427
+ raise_command_error "Specify at least one option to update.\n#{optparse}" if payload.empty?
428
+ end
429
+ @blueprints_interface.setopts(options)
430
+ if options[:dry_run]
431
+ print_dry_run @blueprints_interface.dry.update_permissions(blueprint['id'], payload)
432
+ return
433
+ end
434
+
435
+ json_response = @blueprints_interface.update_permissions(blueprint['id'], payload)
436
+
437
+ if options[:json]
438
+ puts JSON.pretty_generate(json_response)
439
+ else
440
+ unless options[:quiet]
441
+ blueprint = json_response['blueprint']
442
+ print_green_success "Updated permissions for blueprint #{blueprint['name']}"
443
+ get([blueprint['id']] + (options[:remote] ? ["-r",options[:remote]] : []))
444
+ end
445
+ end
446
+ return 0
447
+ rescue RestClient::Exception => e
448
+ print_rest_exception(e, options)
449
+ exit 1
450
+ end
451
+ end
452
+
453
+
454
+ def upload_image(args)
455
+ options = {}
456
+ optparse = MtnCloud::Cli::OptionParser.new do |opts|
457
+ opts.banner = subcommand_usage("[blueprint] [file]")
458
+ build_common_options(opts, options, [:json, :dry_run, :quiet, :remote])
459
+ opts.footer = "Upload an image file to be used as the icon for a blueprint.\n" +
460
+ "[blueprint] is required. This is the name or id of a blueprint.\n" +
461
+ "[file] is required. This is the local path of a file to upload [png|jpg|svg]."
462
+ end
463
+ optparse.parse!(args)
464
+ if args.count != 2
465
+ print_error MtnCloud::Terminal.angry_prompt
466
+ puts_error "#{command_name} upload-image expects 2 arguments and received #{args.count}: #{args}\n#{optparse}"
467
+ return 1
468
+ end
469
+ blueprint_name = args[0]
470
+ filename = File.expand_path(args[1].to_s)
471
+ image_file = nil
472
+ if filename && File.file?(filename)
473
+ # maybe validate it's an image file? [.png|jpg|svg]
474
+ image_file = File.new(filename, 'rb')
475
+ else
476
+ print_red_alert "File not found: #{filename}"
477
+ # print_error MtnCloud::Terminal.angry_prompt
478
+ # puts_error "bad argument [file] - File not found: #{filename}\n#{optparse}"
479
+ return 1
480
+ end
481
+ connect(options)
482
+ begin
483
+ blueprint = find_blueprint_by_name_or_id(blueprint_name)
484
+ exit 1 if blueprint.nil?
485
+ @blueprints_interface.setopts(options)
486
+ if options[:dry_run]
487
+ print_dry_run @blueprints_interface.dry.save_image(blueprint['id'], image_file)
488
+ return 0
489
+ end
490
+ unless options[:quiet] || options[:json]
491
+ print cyan, "Uploading file #{filename} ...", reset, "\n"
492
+ end
493
+ json_response = @blueprints_interface.save_image(blueprint['id'], image_file)
494
+ if options[:json]
495
+ print JSON.pretty_generate(json_response)
496
+ elsif !options[:quiet]
497
+ blueprint = json_response['blueprint']
498
+ new_image_url = blueprint['image']
499
+ print cyan, "Updated blueprint #{blueprint['name']} image.\nNew image url is: #{new_image_url}", reset, "\n\n"
500
+ get([blueprint['id']] + (options[:remote] ? ["-r",options[:remote]] : []))
501
+ end
502
+ return 0
503
+ rescue RestClient::Exception => e
504
+ print_rest_exception(e, options)
505
+ return 1
506
+ end
507
+ end
508
+
509
+ def duplicate(args)
510
+ options = {}
511
+ optparse = MtnCloud::Cli::OptionParser.new do |opts|
512
+ opts.banner = subcommand_usage("[blueprint] [new name]")
513
+ build_common_options(opts, options, [:auto_confirm, :json, :dry_run, :remote])
514
+ opts.footer = "Duplicate a blueprint." + "\n" +
515
+ "[blueprint] is required. This is the name or id of a blueprint." + "\n" +
516
+ "[new name] is required. This is the name for the clone."
517
+ end
518
+ optparse.parse!(args)
519
+
520
+ if args.count < 1
521
+ puts optparse
522
+ exit 1
523
+ end
524
+
525
+ payload = {"blueprint" => {}}
526
+ if args[1]
527
+ payload["blueprint"]["name"] = args[1]
528
+ end
529
+
530
+ connect(options)
531
+ begin
532
+ blueprint = find_blueprint_by_name_or_id(args[0])
533
+ exit 1 if blueprint.nil?
534
+ # unless options[:yes] || MtnCloud::Cli::OptionTypes.confirm("Are you sure you want to duplicate the blueprint #{blueprint['name']}?")
535
+ # exit
536
+ # end
537
+ @blueprints_interface.setopts(options)
538
+ if options[:dry_run]
539
+ print_dry_run @blueprints_interface.dry.duplicate(blueprint['id'], payload)
540
+ return
541
+ end
542
+ json_response = @blueprints_interface.duplicate(blueprint['id'], payload)
543
+
544
+ if options[:json]
545
+ print JSON.pretty_generate(json_response)
546
+ print "\n"
547
+ else
548
+ new_blueprint = json_response["blueprint"] || {}
549
+ print_green_success "Created duplicate blueprint '#{new_blueprint['name']}'"
550
+ #get([new_blueprint['id']] + (options[:remote] ? ["-r",options[:remote]] : []))
551
+ end
552
+
553
+ rescue RestClient::Exception => e
554
+ print_rest_exception(e, options)
555
+ exit 1
556
+ end
557
+ end
558
+
559
+ def remove(args)
560
+ options = {}
561
+ optparse = MtnCloud::Cli::OptionParser.new do |opts|
562
+ opts.banner = subcommand_usage("[blueprint]")
563
+ build_standard_remove_options(opts, options)
564
+ opts.footer = "Delete a blueprint." + "\n" +
565
+ "[blueprint] is required. This is the name or id of a blueprint."
566
+ end
567
+ optparse.parse!(args)
568
+
569
+ if args.count < 1
570
+ puts optparse
571
+ exit 1
572
+ end
573
+
574
+ connect(options)
575
+ begin
576
+ blueprint = find_blueprint_by_name_or_id(args[0])
577
+ exit 1 if blueprint.nil?
578
+ unless options[:yes] || MtnCloud::Cli::OptionTypes.confirm("Are you sure you want to delete the blueprint #{blueprint['name']}?")
579
+ exit
580
+ end
581
+ @blueprints_interface.setopts(options)
582
+ if options[:dry_run]
583
+ print_dry_run @blueprints_interface.dry.destroy(blueprint['id'])
584
+ return
585
+ end
586
+ json_response = @blueprints_interface.destroy(blueprint['id'])
587
+
588
+ if options[:json]
589
+ print JSON.pretty_generate(json_response)
590
+ print "\n"
591
+ else
592
+ print_green_success "Removed blueprint #{blueprint['name']}"
593
+ end
594
+
595
+ rescue RestClient::Exception => e
596
+ print_rest_exception(e, options)
597
+ exit 1
598
+ end
599
+ end
600
+
601
+ def add_instance(args)
602
+ options = {}
603
+ optparse = MtnCloud::Cli::OptionParser.new do |opts|
604
+ opts.banner = subcommand_usage("[blueprint] [tier] [instance-type]")
605
+ # opts.on( '-g', '--group GROUP', "Group" ) do |val|
606
+ # options[:group] = val
607
+ # end
608
+ # opts.on( '-c', '--cloud CLOUD', "Cloud" ) do |val|
609
+ # options[:cloud] = val
610
+ # end
611
+ opts.on('--name VALUE', String, "Instance Name") do |val|
612
+ options[:instance_name] = val
613
+ end
614
+ build_common_options(opts, options, [:options, :json, :dry_run, :remote])
615
+ opts.footer = "Update a blueprint, adding an instance." + "\n" +
616
+ "[blueprint] is required. This is the name or id of a blueprint." + "\n" +
617
+ "[tier] is required and will be prompted for. This is the name of the tier." + "\n" +
618
+ "[instance-type] is required and will be prompted for. This is the type of instance."
619
+ end
620
+ optparse.parse!(args)
621
+
622
+ if args.count < 1 || args.count > 3
623
+ print_error MtnCloud::Terminal.angry_prompt
624
+ puts_error "#{command_name} add-instance expects 2-3 arguments and received #{args.count}: #{args}\n#{optparse}"
625
+ return 1
626
+ end
627
+
628
+ connect(options)
629
+
630
+ begin
631
+ blueprint_name = args[0]
632
+ tier_name = args[1]
633
+ instance_type_code = args[2]
634
+ # we also need consider when there is multiple instances of the same type in
635
+ # a template/tier.. so maybe split instance_type_code as [type-code]:[index].. or...errr
636
+
637
+ blueprint = find_blueprint_by_name_or_id(blueprint_name)
638
+ return 1 if blueprint.nil?
639
+
640
+ if !tier_name
641
+ v_prompt = MtnCloud::Cli::OptionTypes.prompt([{'fieldName' => 'tierName', 'fieldLabel' => 'Tier Name', 'type' => 'text', 'required' => true, 'description' => 'Enter the name of the tier'}], options[:options])
642
+ tier_name = v_prompt['tierName']
643
+ end
644
+
645
+ if !instance_type_code
646
+ instance_type_prompt = MtnCloud::Cli::OptionTypes.prompt([{'fieldName' => 'type', 'type' => 'select', 'fieldLabel' => 'Type', 'optionSource' => 'instanceTypes', 'required' => true, 'description' => 'Select Instance Type.'}],options[:options],api_client,{})
647
+ instance_type_code = instance_type_prompt['type']
648
+ end
649
+ instance_type = find_instance_type_by_code(instance_type_code)
650
+ return 1 if instance_type.nil?
651
+
652
+ tier_config = nil
653
+ instance_config = nil
654
+
655
+ blueprint["config"] ||= {}
656
+ tiers = blueprint["config"]["tiers"]
657
+ tiers ||= {}
658
+ # tier identified by name, case sensitive...
659
+ if !tiers[tier_name]
660
+ tiers[tier_name] = {}
661
+ end
662
+ tier_config = tiers[tier_name]
663
+
664
+ instance_config = {'instance' => {'type' => instance_type['code']} }
665
+ tier_config['instances'] ||= []
666
+ tier_config['instances'].push(instance_config)
667
+
668
+ # just prompts for Instance Name (optional)
669
+ instance_name = nil
670
+ if options[:instance_name]
671
+ instance_name = options[:instance_name]
672
+ else
673
+ v_prompt = MtnCloud::Cli::OptionTypes.prompt([{'fieldName' => 'name', 'fieldLabel' => 'Instance Name', 'type' => 'text', 'defaultValue' => instance_config['instance']['name']}])
674
+ instance_name = v_prompt['name'] || ''
675
+ end
676
+
677
+ if instance_name
678
+ if instance_name.to_s == 'null'
679
+ instance_config['instance'].delete('name')
680
+ # instance_config['instance']['name'] = ''
681
+ else
682
+ instance_config['instance']['name'] = instance_name
683
+ end
684
+ end
685
+
686
+ # ok, make api request
687
+ blueprint["config"]["tiers"] = tiers
688
+ payload = {blueprint: blueprint}
689
+ @blueprints_interface.setopts(options)
690
+ if options[:dry_run]
691
+ print_dry_run @blueprints_interface.dry.update(blueprint['id'], payload)
692
+ return 0
693
+ end
694
+
695
+ json_response = @blueprints_interface.update(blueprint['id'], payload)
696
+
697
+ if options[:json]
698
+ puts JSON.pretty_generate(json_response)
699
+ elsif !options[:quiet]
700
+ print_green_success "Instance added to blueprint #{blueprint['name']}"
701
+ # prompt for new instance
702
+ if !options[:no_prompt]
703
+ if ::MtnCloud::Cli::OptionTypes::confirm("Would you like to add a config now?", options.merge({default: true}))
704
+ # todo: this needs to work by index, because you can have multiple instances of the same type
705
+ # instance_identifier = instance_config['instance']['name'] # instance_type['code']
706
+ instance_identifier = tier_config['instances'].size - 1
707
+ add_instance_config([blueprint['id'], tier_name, instance_identifier])
708
+ while ::MtnCloud::Cli::OptionTypes::confirm("Add another config?", options.merge({default: false})) do
709
+ add_instance_config([blueprint['id'], tier_name, instance_identifier])
710
+ end
711
+ else
712
+ # print details
713
+ get([blueprint['id']] + (options[:remote] ? ["-r",options[:remote]] : []))
714
+ end
715
+ end
716
+ end
717
+ return 0
718
+
719
+ rescue RestClient::Exception => e
720
+ print_rest_exception(e, options)
721
+ return 1
722
+ end
723
+
724
+ end
725
+
726
+ def add_instance_config(args)
727
+ options = {}
728
+ optparse = MtnCloud::Cli::OptionParser.new do |opts|
729
+ opts.banner = subcommand_usage("[blueprint] [tier] [instance]")
730
+ opts.on( '-g', '--group GROUP', "Group" ) do |val|
731
+ options[:group] = val
732
+ end
733
+ opts.on( '-c', '--cloud CLOUD', "Cloud" ) do |val|
734
+ options[:cloud] = val
735
+ end
736
+ opts.on( '-e', '--env ENVIRONMENT', "Environment" ) do |val|
737
+ options[:environment] = val
738
+ end
739
+ opts.on('--name VALUE', String, "Instance Name") do |val|
740
+ options[:instance_name] = val
741
+ end
742
+ build_common_options(opts, options, [:options, :json, :dry_run, :remote])
743
+ opts.footer = "Update a blueprint, adding an instance config." + "\n" +
744
+ "[blueprint] is required. This is the name or id of a blueprint." + "\n" +
745
+ "[tier] is required. This is the name of the tier." + "\n" +
746
+ "[instance] is required. This is the type of instance."
747
+ end
748
+ optparse.parse!(args)
749
+
750
+ if args.count < 3
751
+ print_error MtnCloud::Terminal.angry_prompt
752
+ puts_error "Wrong number of arguments"
753
+ puts_error optparse
754
+ return 1
755
+ end
756
+
757
+ connect(options)
758
+
759
+ begin
760
+
761
+ blueprint_name = args[0]
762
+ tier_name = args[1]
763
+ instance_identifier = args[2]
764
+
765
+ blueprint = find_blueprint_by_name_or_id(blueprint_name)
766
+ return 1 if blueprint.nil?
767
+
768
+ # instance_type = find_instance_type_by_code(instance_type_code)
769
+ # return 1 if instance_type.nil?
770
+
771
+ tier_config = nil
772
+ instance_config = nil
773
+
774
+ blueprint["config"] ||= {}
775
+ tiers = blueprint["config"]["tiers"]
776
+ tiers ||= {}
777
+ # tier identified by name, case sensitive...
778
+ if !tiers[tier_name]
779
+ tiers[tier_name] = {}
780
+ end
781
+ tier_config = tiers[tier_name]
782
+ tier_config['instances'] ||= []
783
+ matching_instance_configs = []
784
+ if tier_config['instances']
785
+ if instance_identifier.to_s =~ /\A\d{1,}\Z/
786
+ matching_instance_configs = [tier_config['instances'][instance_identifier.to_i]].compact
787
+ else
788
+ tier_config['instances'] ||= []
789
+ matching_instance_configs = []
790
+ matching_instance_configs = (tier_config['instances'] || []).select {|instance_config| instance_config['instance'] && instance_config['instance']['name'] == instance_identifier }
791
+ if matching_instance_configs.empty?
792
+ matching_instance_configs = (tier_config['instances'] || []).select {|instance_config| instance_config['instance'] && instance_config['instance']['type'].to_s.downcase == instance_identifier.to_s.downcase }
793
+ end
794
+ end
795
+ end
796
+
797
+ if matching_instance_configs.size == 0
798
+ print_red_alert "Instance not found by tier: #{tier_name}, type: #{instance_identifier}"
799
+ return 1
800
+ elsif matching_instance_configs.size > 1
801
+ #print_error MtnCloud::Terminal.angry_prompt
802
+ print_red_alert "More than one instance found by tier: #{tier_name}, type: #{instance_identifier}"
803
+ puts_error "Try passing the name or index to identify the instance you wish to add a config to."
804
+ puts_error optparse
805
+ return 1
806
+ end
807
+
808
+ instance_config = matching_instance_configs[0]
809
+
810
+ # group prompt
811
+
812
+ # use active group by default
813
+ #options[:group] ||= @active_group_id
814
+
815
+ # available_groups = get_available_groups()
816
+ # group_prompt = MtnCloud::Cli::OptionTypes.prompt([{'fieldName' => 'group', 'fieldLabel' => 'Group', 'type' => 'select', 'selectOptions' => get_available_groups(), 'required' => true, 'defaultValue' => @active_group_id}],options[:options],@api_client,{})
817
+
818
+ # group_id = group_prompt['group']
819
+ # the_group = find_group_by_name_or_id_for_provisioning(group_id)
820
+
821
+ # # cloud prompt
822
+ # cloud_prompt = MtnCloud::Cli::OptionTypes.prompt([{'fieldName' => 'cloud', 'type' => 'select', 'fieldLabel' => 'Cloud', 'optionSource' => 'clouds', 'required' => true, 'description' => 'Select Cloud.'}],options[:options],@api_client,{groupId: group_id})
823
+ # cloud_id = cloud_prompt['cloud']
824
+
825
+ # look for existing config for group + cloud
826
+
827
+ options[:name_required] = false
828
+ options[:instance_type_code] = instance_config['instance']['type'] #instance_type["code"]
829
+ options[:for_app] = true
830
+ options[:skip_labels_prompt] = true
831
+ #options[:options].deep_merge!(specific_config)
832
+ # this provisioning helper method handles all (most) of the parsing and prompting
833
+ instance_config_payload = prompt_new_instance(options)
834
+
835
+ # strip all empty string and nil, would be problematic for update()
836
+ instance_config_payload.deep_compact!
837
+
838
+ # puts "INSTANCE CONFIG YAML:"
839
+ # puts as_yaml(instance_config_payload)
840
+
841
+ selected_environment = instance_config_payload.delete('instanceContext') || instance_config_payload.delete('environment')
842
+ # groom provision instance payload for template purposes
843
+ selected_cloud_id = instance_config_payload.delete('zoneId')
844
+ selected_site = instance_config_payload['instance'].delete('site')
845
+ selected_site_id = selected_site['id']
846
+
847
+ selected_group = find_group_by_name_or_id_for_provisioning(selected_site_id)
848
+ selected_cloud = find_cloud_by_name_or_id_for_provisioning(selected_group['id'], selected_cloud_id)
849
+
850
+ # store config in environments => env => groups => groupname => clouds => cloudname =>
851
+ current_config = instance_config
852
+ if selected_environment.to_s != ''
853
+ instance_config['environments'] ||= {}
854
+ instance_config['environments'][selected_environment] ||= {}
855
+ current_config = instance_config['environments'][selected_environment]
856
+ end
857
+
858
+ current_config['groups'] ||= {}
859
+ current_config['groups'][selected_group['name']] ||= {}
860
+ current_config['groups'][selected_group['name']]['clouds'] ||= {}
861
+ current_config['groups'][selected_group['name']]['clouds'][selected_cloud['name']] = instance_config_payload
862
+
863
+ # ok, make api request
864
+ blueprint["config"]["tiers"] = tiers
865
+ payload = {blueprint: blueprint}
866
+ @blueprints_interface.setopts(options)
867
+ if options[:dry_run]
868
+ print_dry_run @blueprints_interface.dry.update(blueprint['id'], payload)
869
+ return 0
870
+ end
871
+
872
+ json_response = @blueprints_interface.update(blueprint['id'], payload)
873
+
874
+ if options[:json]
875
+ puts JSON.pretty_generate(json_response)
876
+ else
877
+ print_green_success "Instance added to blueprint #{blueprint['name']}"
878
+ get([blueprint['id']] + (options[:remote] ? ["-r",options[:remote]] : []))
879
+ end
880
+ return 0
881
+
882
+ rescue RestClient::Exception => e
883
+ print_rest_exception(e, options)
884
+ return 1
885
+ end
886
+
887
+ end
888
+
889
+ def remove_instance_config(args)
890
+ #instance_index = nil
891
+ options = {}
892
+ optparse = MtnCloud::Cli::OptionParser.new do |opts|
893
+ opts.banner = subcommand_usage("[blueprint] [tier] [instance] -g GROUP -c CLOUD")
894
+ opts.on( '-g', '--group GROUP', "Group" ) do |val|
895
+ options[:group] = val
896
+ end
897
+ opts.on( '-c', '--cloud CLOUD', "Cloud" ) do |val|
898
+ options[:cloud] = val
899
+ end
900
+ opts.on( '-e', '--env ENV', "Environment" ) do |val|
901
+ options[:environment] = val
902
+ end
903
+ # opts.on( nil, '--index NUMBER', "The index of the instance to remove, starting with 0." ) do |val|
904
+ # instance_index = val.to_i
905
+ # end
906
+ build_common_options(opts, options, [:auto_confirm, :json, :dry_run, :remote])
907
+ opts.footer = "Update a blueprint, removing a specified instance config." + "\n" +
908
+ "[blueprint] is required. This is the name or id of a blueprint." + "\n" +
909
+ "[tier] is required. This is the name of the tier." + "\n" +
910
+ "[instance] is required. This is the instance identifier, which may be the type, the name, or the index starting with 0." + "\n" +
911
+ "The config scope is specified with the -g GROUP, -c CLOUD and -e ENV. The -g and -c options are required."
912
+ end
913
+ optparse.parse!(args)
914
+
915
+ if args.count != 3
916
+ print_error MtnCloud::Terminal.angry_prompt
917
+ puts_error "Wrong number of arguments"
918
+ puts_error optparse
919
+ return 1
920
+ end
921
+ if !options[:group]
922
+ print_error MtnCloud::Terminal.angry_prompt
923
+ puts_error "Missing required argument -g GROUP"
924
+ puts_error optparse
925
+ return 1
926
+ end
927
+ if !options[:cloud]
928
+ print_error MtnCloud::Terminal.angry_prompt
929
+ puts_error "Missing required argument -c CLOUD"
930
+ puts_error optparse
931
+ return 1
932
+ end
933
+ connect(options)
934
+
935
+ begin
936
+
937
+ blueprint_name = args[0]
938
+ tier_name = args[1]
939
+ instance_identifier = args[2]
940
+
941
+ blueprint = find_blueprint_by_name_or_id(blueprint_name)
942
+ return 1 if blueprint.nil?
943
+
944
+ # instance_type = find_instance_type_by_code(instance_type_code)
945
+ # return 1 if instance_type.nil?
946
+
947
+ tier_config = nil
948
+ # instance_config = nil
949
+
950
+ blueprint["config"] ||= {}
951
+ tiers = blueprint["config"]["tiers"]
952
+ tiers ||= {}
953
+ # tier identified by name, case sensitive...
954
+ if !tiers[tier_name]
955
+ print_red_alert "Tier not found by name #{tier_name}"
956
+ return 1
957
+ end
958
+ tier_config = tiers[tier_name]
959
+
960
+ if !tier_config
961
+ print_red_alert "Tier not found by name #{tier1_name}!"
962
+ return 1
963
+ elsif tier_config['instances'].nil? || tier_config['instances'].empty?
964
+ print_red_alert "Tier #{tier_name} is empty!"
965
+ return 1
966
+ end
967
+
968
+ matching_indices = []
969
+ if tier_config['instances']
970
+ if instance_identifier.to_s =~ /\A\d{1,}\Z/
971
+ matching_indices = [instance_identifier.to_i].compact
972
+ else
973
+ tier_config['instances'].each_with_index do |instance_config, index|
974
+ if instance_config['instance'] && instance_config['instance']['type'].to_s.downcase == instance_identifier.to_s.downcase
975
+ matching_indices << index
976
+ elsif instance_config['instance'] && instance_config['instance']['name'] == instance_identifier
977
+ matching_indices << index
978
+ end
979
+ end
980
+ end
981
+ end
982
+
983
+
984
+ if matching_indices.size == 0
985
+ print_red_alert "Instance not found by tier: #{tier_name}, type: #{instance_identifier}"
986
+ return 1
987
+ elsif matching_indices.size > 1
988
+ #print_error MtnCloud::Terminal.angry_prompt
989
+ print_red_alert "More than one instance found by tier: #{tier_name}, type: #{instance_identifier}"
990
+ puts_error "Try passing the name or index to identify the instance you wish to remove."
991
+ puts_error optparse
992
+ return 1
993
+ end
994
+
995
+ # ok, find the specified config
996
+ instance_config = tier_config['instances'][matching_indices[0]]
997
+ parent_config = nil
998
+ current_config = instance_config
999
+ delete_key = nil
1000
+
1001
+ config_description = "type: #{instance_identifier}"
1002
+ config_description << " environment: #{options[:environment]}" if options[:environment]
1003
+ config_description << " group: #{options[:group]}" if options[:group]
1004
+ config_description << " cloud: #{options[:cloud]}" if options[:cloud]
1005
+ config_description = config_description.strip
1006
+
1007
+
1008
+ # find config in environments => env => groups => groupname => clouds => cloudname =>
1009
+ if options[:environment]
1010
+ if current_config && current_config['environments'] && current_config['environments'][options[:environment]]
1011
+ parent_config = current_config['environments']
1012
+ delete_key = options[:environment]
1013
+ current_config = parent_config[delete_key]
1014
+ else
1015
+ print_red_alert "Instance config not found for scope #{config_description}"
1016
+ return 1
1017
+ end
1018
+ end
1019
+ if options[:group]
1020
+ if current_config && current_config['groups'] && current_config['groups'][options[:group]]
1021
+ parent_config = current_config['groups']
1022
+ delete_key = options[:group]
1023
+ current_config = parent_config[delete_key]
1024
+ else
1025
+ print_red_alert "Instance config not found for scope #{config_description}"
1026
+ return 1
1027
+ end
1028
+ end
1029
+ if options[:cloud]
1030
+ if current_config && current_config['clouds'] && current_config['clouds'][options[:cloud]]
1031
+ parent_config = current_config['clouds']
1032
+ delete_key = options[:cloud]
1033
+ current_config = parent_config[delete_key]
1034
+ else
1035
+ print_red_alert "Instance config not found for scope #{config_description}"
1036
+ return 1
1037
+ end
1038
+ end
1039
+
1040
+ # remove it
1041
+ parent_config.delete(delete_key)
1042
+
1043
+ unless options[:yes] || MtnCloud::Cli::OptionTypes.confirm("Are you sure you want to delete this instance config #{config_description} ?")
1044
+ return 9
1045
+ end
1046
+
1047
+ # ok, make api request
1048
+ blueprint["config"]["tiers"] = tiers
1049
+ payload = {blueprint: blueprint}
1050
+ @blueprints_interface.setopts(options)
1051
+ if options[:dry_run]
1052
+ print_dry_run @blueprints_interface.dry.update(blueprint['id'], payload)
1053
+ return
1054
+ end
1055
+ json_response = @blueprints_interface.update(blueprint['id'], payload)
1056
+
1057
+ if options[:json]
1058
+ puts JSON.pretty_generate(json_response)
1059
+ else
1060
+ print_green_success "Removed instance from blueprint."
1061
+ get([blueprint['id']] + (options[:remote] ? ["-r",options[:remote]] : []))
1062
+ end
1063
+ return 0
1064
+
1065
+ rescue RestClient::Exception => e
1066
+ print_rest_exception(e, options)
1067
+ exit 1
1068
+ end
1069
+ end
1070
+
1071
+ def update_instance(args)
1072
+ print_red_alert "NOT YET SUPPORTED"
1073
+ return 5
1074
+ end
1075
+
1076
+ def update_instance_config(args)
1077
+ print_red_alert "NOT YET SUPPORTED"
1078
+ return 5
1079
+ end
1080
+
1081
+ def remove_instance(args)
1082
+ #instance_index = nil
1083
+ options = {}
1084
+ optparse = MtnCloud::Cli::OptionParser.new do |opts|
1085
+ opts.banner = subcommand_usage("[blueprint] [tier] [instance]")
1086
+ # opts.on('--index NUMBER', Number, "Identify Instance by index within tier, starting with 0." ) do |val|
1087
+ # instance_index = val.to_i
1088
+ # end
1089
+ build_common_options(opts, options, [:auto_confirm, :json, :dry_run, :remote])
1090
+ opts.footer = "Update a blueprint, removing a specified instance." + "\n" +
1091
+ "[blueprint] is required. This is the name or id of a blueprint." + "\n" +
1092
+ "[tier] is required. This is the name of the tier." + "\n" +
1093
+ "[instance] is required. This is the instance identifier, which may be the type, the name, or the index starting with 0."
1094
+ end
1095
+
1096
+ optparse.parse!(args)
1097
+
1098
+ if args.count != 3
1099
+ print_error MtnCloud::Terminal.angry_prompt
1100
+ puts_error "Wrong number of arguments"
1101
+ puts_error optparse
1102
+ return 1
1103
+ end
1104
+
1105
+ connect(options)
1106
+
1107
+ begin
1108
+
1109
+ blueprint_name = args[0]
1110
+ tier_name = args[1]
1111
+ instance_identifier = args[2]
1112
+
1113
+ # instance_type_code = args[2]
1114
+ # we also need consider when there is multiple instances of the same type in
1115
+ # a template/tier.. so maybe split instance_type_code as [type-code]:[index].. or...errr
1116
+
1117
+ blueprint = find_blueprint_by_name_or_id(blueprint_name)
1118
+ return 1 if blueprint.nil?
1119
+
1120
+ # instance_type = find_instance_type_by_code(instance_type_code)
1121
+ # return 1 if instance_type.nil?
1122
+
1123
+ tier_config = nil
1124
+ # instance_config = nil
1125
+
1126
+ blueprint["config"] ||= {}
1127
+ tiers = blueprint["config"]["tiers"]
1128
+ tiers ||= {}
1129
+ # tier identified by name, case sensitive...
1130
+ if !tiers[tier_name]
1131
+ print_red_alert "Tier not found by name #{tier_name}"
1132
+ return 1
1133
+ end
1134
+ tier_config = tiers[tier_name]
1135
+
1136
+ if tier_config['instances'].nil? || tier_config['instances'].empty?
1137
+ print_red_alert "Tier #{tier_name} is empty!"
1138
+ return 1
1139
+ end
1140
+
1141
+ # find instance
1142
+ matching_indices = []
1143
+ if tier_config['instances']
1144
+ if instance_identifier.to_s =~ /\A\d{1,}\Z/
1145
+ matching_indices = [instance_identifier.to_i].compact
1146
+ else
1147
+ tier_config['instances'].each_with_index do |instance_config, index|
1148
+ if instance_config['instance'] && instance_config['instance']['type'].to_s.downcase == instance_identifier.to_s.downcase
1149
+ matching_indices << index
1150
+ elsif instance_config['instance'] && instance_config['instance']['name'] == instance_identifier
1151
+ matching_indices << index
1152
+ end
1153
+ end
1154
+ end
1155
+ end
1156
+ if matching_indices.size == 0
1157
+ print_red_alert "Instance not found by tier: #{tier_name}, instance: #{instance_identifier}"
1158
+ return 1
1159
+ elsif matching_indices.size > 1
1160
+ #print_error MtnCloud::Terminal.angry_prompt
1161
+ print_red_alert "More than one instance matched tier: #{tier_name}, instance: #{instance_identifier}"
1162
+ puts_error "Try passing the name or index to identify the instance you wish to remove."
1163
+ puts_error optparse
1164
+ return 1
1165
+ end
1166
+
1167
+ # remove it
1168
+ tier_config['instances'].delete_at(matching_indices[0])
1169
+
1170
+ unless options[:yes] || MtnCloud::Cli::OptionTypes.confirm("Are you sure you want to delete this instance #{instance_identifier} instance from tier: #{tier_name}?")
1171
+ return 9
1172
+ end
1173
+
1174
+ # ok, make api request
1175
+ blueprint["config"]["tiers"] = tiers
1176
+ payload = {blueprint: blueprint}
1177
+ @blueprints_interface.setopts(options)
1178
+ if options[:dry_run]
1179
+ print_dry_run @blueprints_interface.dry.update(blueprint['id'], payload)
1180
+ return
1181
+ end
1182
+ json_response = @blueprints_interface.update(blueprint['id'], payload)
1183
+
1184
+ if options[:json]
1185
+ puts JSON.pretty_generate(json_response)
1186
+ else
1187
+ print_green_success "Removed instance from blueprint."
1188
+ get([blueprint['id']] + (options[:remote] ? ["-r",options[:remote]] : []))
1189
+ end
1190
+ return 0
1191
+
1192
+ rescue RestClient::Exception => e
1193
+ print_rest_exception(e, options)
1194
+ exit 1
1195
+ end
1196
+ end
1197
+
1198
+ def add_tier(args)
1199
+ options = {}
1200
+ boot_order = nil
1201
+ linked_tiers = nil
1202
+ tier_index = nil
1203
+ optparse = MtnCloud::Cli::OptionParser.new do |opts|
1204
+ opts.banner = subcommand_usage("[blueprint] [tier]")
1205
+ opts.on('--name VALUE', String, "Tier Name") do |val|
1206
+ options[:name] = val
1207
+ end
1208
+ opts.on('--bootOrder NUMBER', String, "Boot Order" ) do |val|
1209
+ boot_order = val
1210
+ end
1211
+ opts.on('--linkedTiers x,y,z', Array, "Connected Tiers.") do |val|
1212
+ linked_tiers = val
1213
+ end
1214
+ opts.on('--tierIndex NUMBER', Array, "Tier Index. Used for Display Order") do |val|
1215
+ tier_index = val
1216
+ end
1217
+ build_common_options(opts, options, [:options, :json, :dry_run, :remote])
1218
+ end
1219
+ optparse.parse!(args)
1220
+
1221
+ if args.count < 1
1222
+ print_error MtnCloud::Terminal.angry_prompt
1223
+ puts_error "#{command_name} add-tier requires argument: [blueprint]\n#{optparse}"
1224
+ # puts optparse
1225
+ return 1
1226
+ end
1227
+ blueprint_name = args[0]
1228
+ tier_name = args[1]
1229
+
1230
+ connect(options)
1231
+
1232
+ begin
1233
+ blueprint = find_blueprint_by_name_or_id(blueprint_name)
1234
+ return 1 if blueprint.nil?
1235
+
1236
+ blueprint["config"] ||= {}
1237
+ blueprint["config"]["tiers"] ||= {}
1238
+ tiers = blueprint["config"]["tiers"]
1239
+
1240
+ # prompt new tier
1241
+ # Name
1242
+ # {'fieldName' => 'name', 'fieldLabel' => 'Name', 'type' => 'text', 'required' => true, 'displayOrder' => 1, 'description' => 'A unique name for the blueprint.'},
1243
+ # {'fieldName' => 'bootOrder', 'fieldLabel' => 'Boot Order', 'type' => 'text', 'required' => false, 'displayOrder' => 2, 'description' => 'Boot Order'}
1244
+ if !tier_name
1245
+ v_prompt = MtnCloud::Cli::OptionTypes.prompt([{'fieldName' => 'name', 'fieldLabel' => 'Tier Name', 'type' => 'text', 'required' => true, 'description' => 'Enter the name of the tier'}], options[:options])
1246
+ tier_name = v_prompt['name']
1247
+ end
1248
+ # case insensitive match
1249
+ existing_tier_names = tiers.keys
1250
+ matching_tier_name = existing_tier_names.find {|k| k.downcase == tier_name.downcase }
1251
+ if matching_tier_name
1252
+ # print_red_alert "Tier #{tier_name} already exists"
1253
+ # return 1
1254
+ print cyan,"Tier #{tier_name} already exists.",reset,"\n"
1255
+ return 0
1256
+ end
1257
+ # idempotent
1258
+ if !tiers[tier_name]
1259
+ tiers[tier_name] = {'instances' => []}
1260
+ end
1261
+ tier = tiers[tier_name]
1262
+
1263
+ # Boot Order
1264
+ if !boot_order
1265
+ v_prompt = MtnCloud::Cli::OptionTypes.prompt([{'fieldName' => 'bootOrder', 'fieldLabel' => 'Boot Order', 'type' => 'text', 'required' => false, 'description' => 'Sequence order for starting app instances by tier. 0-N', 'defaultValue' => tier['bootOrder']}], options[:options])
1266
+ boot_order = v_prompt['bootOrder']
1267
+ end
1268
+ if boot_order.to_s == 'null'
1269
+ tier.delete('bootOrder')
1270
+ elsif boot_order.to_s != ''
1271
+ tier['bootOrder'] = boot_order.to_i
1272
+ end
1273
+
1274
+ # Connected Tiers
1275
+ if !linked_tiers
1276
+ v_prompt = MtnCloud::Cli::OptionTypes.prompt([{'fieldName' => 'linkedTiers', 'fieldLabel' => 'Connected Tiers', 'type' => 'text', 'required' => false, 'description' => 'Names of connected tiers, comma separated', 'defaultValue' => (linked_tiers ? linked_tiers.join(',') : nil)}], options[:options])
1277
+ linked_tiers = v_prompt['linkedTiers'].to_s.split(',').collect {|it| it.strip }.select {|it| it != ''}
1278
+ end
1279
+ if linked_tiers && !linked_tiers.empty?
1280
+ linked_tiers.each do |other_tier_name|
1281
+ link_result = link_tiers(tiers, [tier_name, other_tier_name])
1282
+ # could just re-prompt unless options[:no_prompt]
1283
+ return 1 if !link_result
1284
+ end
1285
+ end
1286
+
1287
+ # Tier Index
1288
+ if !tier_index
1289
+ #v_prompt = MtnCloud::Cli::OptionTypes.prompt([{'fieldName' => 'tierIndex', 'fieldLabel' => 'Tier Index', 'type' => 'number', 'required' => false, 'description' => 'Sequence order for displaying app instances by tier. 0-N', 'defaultValue' => tier['tierIndex']}], options[:options])
1290
+ #tier_index = v_prompt['tierIndex']
1291
+ tier_index = (tiers.size - 1)
1292
+ end
1293
+
1294
+ if tier_index.to_s == 'null'
1295
+ tier.delete('tierIndex')
1296
+ elsif tier_index
1297
+ tier['tierIndex'] = tier_index.to_i
1298
+ end
1299
+
1300
+ # ok, make api request
1301
+ blueprint["config"]["tiers"] = tiers
1302
+ payload = blueprint["config"]
1303
+ # payload = {blueprint: blueprint}
1304
+ @blueprints_interface.setopts(options)
1305
+ if options[:dry_run]
1306
+ print_dry_run @blueprints_interface.dry.update(blueprint['id'], payload)
1307
+ return
1308
+ end
1309
+ json_response = @blueprints_interface.update(blueprint['id'], payload)
1310
+
1311
+ if options[:json]
1312
+ puts JSON.pretty_generate(json_response)
1313
+ elsif !options[:quiet]
1314
+ print_green_success "Added tier #{tier_name}"
1315
+ # prompt for new instance
1316
+ if !options[:no_prompt]
1317
+ if ::MtnCloud::Cli::OptionTypes::confirm("Would you like to add an instance now?", options.merge({default: true}))
1318
+ add_instance([blueprint['id'], tier_name])
1319
+ while ::MtnCloud::Cli::OptionTypes::confirm("Add another instance now?", options.merge({default: false})) do
1320
+ add_instance([blueprint['id'], tier_name])
1321
+ end
1322
+ # if !add_instance_result
1323
+ # end
1324
+ end
1325
+ end
1326
+ # print details
1327
+ get([blueprint['id']] + (options[:remote] ? ["-r",options[:remote]] : []))
1328
+ end
1329
+ return 0
1330
+ rescue RestClient::Exception => e
1331
+ print_rest_exception(e, options)
1332
+ exit 1
1333
+ end
1334
+ end
1335
+
1336
+ def update_tier(args)
1337
+ options = {}
1338
+ new_tier_name = nil
1339
+ boot_order = nil
1340
+ linked_tiers = nil
1341
+ tier_index = nil
1342
+ optparse = MtnCloud::Cli::OptionParser.new do |opts|
1343
+ opts.banner = subcommand_usage("[blueprint] [tier]")
1344
+ opts.on('--name VALUE', String, "Tier Name") do |val|
1345
+ new_tier_name = val
1346
+ end
1347
+ opts.on('--bootOrder NUMBER', String, "Boot Order" ) do |val|
1348
+ boot_order = val
1349
+ end
1350
+ opts.on('--linkedTiers x,y,z', Array, "Connected Tiers") do |val|
1351
+ linked_tiers = val
1352
+ end
1353
+ opts.on('--tierIndex NUMBER', String, "Tier Index. Used for Display Order") do |val|
1354
+ tier_index = val.to_i
1355
+ end
1356
+ build_common_options(opts, options, [:options, :json, :dry_run, :remote])
1357
+ end
1358
+ optparse.parse!(args)
1359
+
1360
+ if args.count != 2
1361
+ print_error MtnCloud::Terminal.angry_prompt
1362
+ puts_error "#{command_name} update-tier expects 2 arguments and received #{args.count}: #{args}\n#{optparse}"
1363
+ return 1
1364
+ end
1365
+ blueprint_name = args[0]
1366
+ tier_name = args[1]
1367
+
1368
+ connect(options)
1369
+
1370
+ begin
1371
+ blueprint = find_blueprint_by_name_or_id(blueprint_name)
1372
+ return 1 if blueprint.nil?
1373
+
1374
+ blueprint["config"] ||= {}
1375
+ blueprint["config"]["tiers"] ||= {}
1376
+ tiers = blueprint["config"]["tiers"]
1377
+
1378
+ if !tiers[tier_name]
1379
+ print_red_alert "Tier not found by name #{tier_name}"
1380
+ return 1
1381
+ end
1382
+ tier = tiers[tier_name]
1383
+
1384
+ passed_options = options[:options] ? options[:options].reject {|k,v| k.is_a?(Symbol) } : {}
1385
+
1386
+ if options[:no_prompt]
1387
+ if !(new_tier_name || boot_order || linked_tiers || tier_index || !passed_options.empty?)
1388
+ print_error MtnCloud::Terminal.angry_prompt
1389
+ puts_error "#{command_name} update-tier requires an option to update.\n#{optparse}"
1390
+ return 1
1391
+ end
1392
+ end
1393
+
1394
+ tier.deep_merge!(passed_options) unless passed_options.empty?
1395
+
1396
+ # prompt update tier
1397
+ # Name
1398
+ if !new_tier_name
1399
+ v_prompt = MtnCloud::Cli::OptionTypes.prompt([{'fieldName' => 'name', 'fieldLabel' => 'Tier Name', 'type' => 'text', 'required' => true, 'description' => 'Rename the tier', 'defaultValue' => tier_name}], options[:options])
1400
+ new_tier_name = v_prompt['name']
1401
+ end
1402
+ if new_tier_name && new_tier_name != tier_name
1403
+ if tiers[new_tier_name]
1404
+ print_red_alert "A tier named #{tier_name} already exists."
1405
+ return 1
1406
+ end
1407
+ tier = tiers.delete(tier_name)
1408
+ tiers[new_tier_name] = tier
1409
+ # Need to fix all the linkedTiers
1410
+ tiers.each do |k, v|
1411
+ if v['linkedTiers'] && v['linkedTiers'].include?(tier_name)
1412
+ v['linkedTiers'] = v['linkedTiers'].map {|it| it == tier_name ? new_tier_name : it }
1413
+ end
1414
+ end
1415
+ tier_name = new_tier_name
1416
+ end
1417
+
1418
+ # Boot Order
1419
+ if !boot_order
1420
+ v_prompt = MtnCloud::Cli::OptionTypes.prompt([{'fieldName' => 'bootOrder', 'fieldLabel' => 'Boot Order', 'type' => 'text', 'required' => false, 'description' => 'Sequence order for starting app instances by tier. 0-N', 'defaultValue' => tier['bootOrder']}], options[:options])
1421
+ boot_order = v_prompt['bootOrder']
1422
+ end
1423
+ if boot_order.to_s == 'null'
1424
+ tier.delete('bootOrder')
1425
+ elsif boot_order.to_s != ''
1426
+ tier['bootOrder'] = boot_order.to_i
1427
+ end
1428
+
1429
+ # Connected Tiers
1430
+ if !linked_tiers
1431
+ v_prompt = MtnCloud::Cli::OptionTypes.prompt([{'fieldName' => 'linkedTiers', 'fieldLabel' => 'Connected Tiers', 'type' => 'text', 'required' => false, 'description' => 'Names of connected tiers, comma separated', 'defaultValue' => (tier['linkedTiers'] ? tier['linkedTiers'].join(',') : nil)}], options[:options])
1432
+ linked_tiers = v_prompt['linkedTiers'].to_s.split(',').collect {|it| it.strip }.select {|it| it != ''}
1433
+ end
1434
+ current_linked_tiers = tier['linkedTiers'] || []
1435
+ if linked_tiers && linked_tiers != current_linked_tiers
1436
+ remove_tiers = current_linked_tiers - linked_tiers
1437
+ remove_tiers.each do |other_tier_name|
1438
+ unlink_result = unlink_tiers(tiers, [tier_name, other_tier_name])
1439
+ # could just re-prompt unless options[:no_prompt]
1440
+ return 1 if !unlink_result
1441
+ end
1442
+ add_tiers = linked_tiers - current_linked_tiers
1443
+ add_tiers.each do |other_tier_name|
1444
+ link_result = link_tiers(tiers, [tier_name, other_tier_name])
1445
+ # could just re-prompt unless options[:no_prompt]
1446
+ return 1 if !link_result
1447
+ end
1448
+ end
1449
+
1450
+ # Tier Index
1451
+ if tier_index.to_s == 'null'
1452
+ tier.delete('tierIndex')
1453
+ elsif tier_index
1454
+ tier['tierIndex'] = tier_index.to_i
1455
+ end
1456
+
1457
+ # ok, make api request
1458
+ blueprint["config"]["tiers"] = tiers
1459
+ payload = blueprint["config"]
1460
+ # payload = {blueprint: blueprint}
1461
+ @blueprints_interface.setopts(options)
1462
+ if options[:dry_run]
1463
+ print_dry_run @blueprints_interface.dry.update(blueprint['id'], payload)
1464
+ return
1465
+ end
1466
+ json_response = @blueprints_interface.update(blueprint['id'], payload)
1467
+
1468
+ if options[:json]
1469
+ puts JSON.pretty_generate(json_response)
1470
+ elsif !options[:quiet]
1471
+ print_green_success "Updated tier #{tier_name}"
1472
+ get([blueprint['id']] + (options[:remote] ? ["-r",options[:remote]] : []))
1473
+ end
1474
+ return 0
1475
+ rescue RestClient::Exception => e
1476
+ print_rest_exception(e, options)
1477
+ exit 1
1478
+ end
1479
+ end
1480
+
1481
+ def remove_tier(args)
1482
+ options = {}
1483
+ optparse = MtnCloud::Cli::OptionParser.new do |opts|
1484
+ opts.banner = subcommand_usage("[blueprint] [tier]")
1485
+ build_common_options(opts, options, [:auto_confirm, :json, :dry_run, :remote])
1486
+ end
1487
+ optparse.parse!(args)
1488
+
1489
+ if args.count < 2
1490
+ print_error MtnCloud::Terminal.angry_prompt
1491
+ puts_error "#{command_name} remove-tier expects 2 arguments and received #{args.count}: #{args}\n#{optparse}"
1492
+ return 1
1493
+ end
1494
+ blueprint_name = args[0]
1495
+ tier_name = args[1]
1496
+
1497
+ connect(options)
1498
+
1499
+ begin
1500
+ blueprint = find_blueprint_by_name_or_id(blueprint_name)
1501
+ return 1 if blueprint.nil?
1502
+
1503
+ blueprint["config"] ||= {}
1504
+ blueprint["config"]["tiers"] ||= {}
1505
+ tiers = blueprint["config"]["tiers"]
1506
+
1507
+ if !tiers[tier_name]
1508
+ # print_red_alert "Tier not found by name #{tier_name}"
1509
+ # return 1
1510
+ print cyan,"Tier #{tier_name} does not exist.",reset,"\n"
1511
+ return 0
1512
+ end
1513
+
1514
+ unless options[:yes] || MtnCloud::Cli::OptionTypes.confirm("Are you sure you want to delete the tier #{tier_name}?")
1515
+ exit
1516
+ end
1517
+
1518
+ # remove it
1519
+ tiers.delete(tier_name)
1520
+
1521
+ # ok, make api request
1522
+ blueprint["config"]["tiers"] = tiers
1523
+ payload = blueprint["config"]
1524
+ # payload = {blueprint: blueprint}
1525
+ @blueprints_interface.setopts(options)
1526
+ if options[:dry_run]
1527
+ print_dry_run @blueprints_interface.dry.update(blueprint['id'], payload)
1528
+ return
1529
+ end
1530
+
1531
+ json_response = @blueprints_interface.update(blueprint['id'], payload)
1532
+
1533
+
1534
+ if options[:json]
1535
+ print JSON.pretty_generate(json_response)
1536
+ print "\n"
1537
+ else
1538
+ print_green_success "Removed tier #{tier_name}"
1539
+ get([blueprint['id']] + (options[:remote] ? ["-r",options[:remote]] : []))
1540
+ end
1541
+
1542
+ rescue RestClient::Exception => e
1543
+ print_rest_exception(e, options)
1544
+ exit 1
1545
+ end
1546
+ end
1547
+
1548
+ def connect_tiers(args)
1549
+ options = {}
1550
+ optparse = MtnCloud::Cli::OptionParser.new do |opts|
1551
+ opts.banner = subcommand_usage("[blueprint] [Tier1] [Tier2]")
1552
+ build_common_options(opts, options, [:json, :dry_run, :remote])
1553
+ end
1554
+ optparse.parse!(args)
1555
+
1556
+ if args.count < 3
1557
+ print_error MtnCloud::Terminal.angry_prompt
1558
+ puts_error "#{command_name} connect-tiers expects 3 arguments and received #{args.count}: #{args}\n#{optparse}"
1559
+ # puts optparse
1560
+ return 1
1561
+ end
1562
+ blueprint_name = args[0]
1563
+ tier1_name = args[1]
1564
+ tier2_name = args[2]
1565
+
1566
+ connect(options)
1567
+
1568
+ begin
1569
+ blueprint = find_blueprint_by_name_or_id(blueprint_name)
1570
+ return 1 if blueprint.nil?
1571
+
1572
+ blueprint["config"] ||= {}
1573
+ tiers = blueprint["config"]["tiers"]
1574
+
1575
+ if !tiers || tiers.keys.size == 0
1576
+ raise_command_error "Blueprint #{blueprint['name']} has no tiers."
1577
+ end
1578
+
1579
+ tier1 = tiers[tier1_name]
1580
+ tier2 = tiers[tier2_name]
1581
+ # uhh support N args
1582
+
1583
+ if tier1.nil?
1584
+ print_red_alert "Tier not found by name #{tier1_name}!"
1585
+ return 1
1586
+ end
1587
+
1588
+ if tier2.nil?
1589
+ print_red_alert "Tier not found by name #{tier2_name}!"
1590
+ return 1
1591
+ end
1592
+
1593
+ tier1["linkedTiers"] = tier1["linkedTiers"] || []
1594
+ tier2["linkedTiers"] = tier2["linkedTiers"] || []
1595
+
1596
+ found_edge = tier1["linkedTiers"].include?(tier2_name) || tier2["linkedTiers"].include?(tier1_name)
1597
+
1598
+ if found_edge
1599
+ puts cyan,"Tiers #{tier1_name} and #{tier2_name} are already connected.",reset
1600
+ return 0
1601
+ end
1602
+
1603
+ # ok to be connect the tiers
1604
+ # note: the ui doesn't hook up both sides eh?
1605
+
1606
+ if !tier1["linkedTiers"].include?(tier2_name)
1607
+ tier1["linkedTiers"].push(tier2_name)
1608
+ end
1609
+
1610
+ if !tier2["linkedTiers"].include?(tier1_name)
1611
+ tier2["linkedTiers"].push(tier1_name)
1612
+ end
1613
+
1614
+ # ok, make api request
1615
+ blueprint["config"]["tiers"] = tiers
1616
+ payload = blueprint["config"]
1617
+ # payload = {blueprint: blueprint}
1618
+ @blueprints_interface.setopts(options)
1619
+ if options[:dry_run]
1620
+ print_dry_run @blueprints_interface.dry.update(blueprint['id'], payload)
1621
+ return
1622
+ end
1623
+ json_response = @blueprints_interface.update(blueprint['id'], payload)
1624
+
1625
+
1626
+ if options[:json]
1627
+ print JSON.pretty_generate(json_response)
1628
+ print "\n"
1629
+ else
1630
+ print_green_success "Connected 2 tiers for blueprint #{blueprint['name']}"
1631
+ get([blueprint['id']] + (options[:remote] ? ["-r",options[:remote]] : []))
1632
+ end
1633
+
1634
+ rescue RestClient::Exception => e
1635
+ print_rest_exception(e, options)
1636
+ exit 1
1637
+ end
1638
+ end
1639
+
1640
+ def disconnect_tiers(args)
1641
+ options = {}
1642
+ optparse = MtnCloud::Cli::OptionParser.new do |opts|
1643
+ opts.banner = subcommand_usage("[blueprint] [Tier1] [Tier2]")
1644
+ build_common_options(opts, options, [:json, :dry_run, :remote])
1645
+ end
1646
+ optparse.parse!(args)
1647
+
1648
+ if args.count < 3
1649
+ print_error MtnCloud::Terminal.angry_prompt
1650
+ puts_error "#{command_name} disconnect-tiers expects 3 arguments and received #{args.count}: #{args}\n#{optparse}"
1651
+ # puts optparse
1652
+ return 1
1653
+ end
1654
+ blueprint_name = args[0]
1655
+ tier1_name = args[1]
1656
+ tier2_name = args[2]
1657
+
1658
+ connect(options)
1659
+
1660
+ begin
1661
+ blueprint = find_blueprint_by_name_or_id(blueprint_name)
1662
+ return 1 if blueprint.nil?
1663
+
1664
+ blueprint["config"] ||= {}
1665
+ tiers = blueprint["config"]["tiers"]
1666
+
1667
+ if !tiers || tiers.keys.size == 0
1668
+ # print_red_alert "Blueprint #{blueprint['name']} has no tiers."
1669
+ # raise_command_error "Blueprint #{blueprint['name']} has no tiers."
1670
+ print_error MtnCloud::Terminal.angry_prompt
1671
+ puts_error "Blueprint #{blueprint['name']} has no tiers."
1672
+ return 1
1673
+ end
1674
+
1675
+ tier1 = tiers[tier1_name]
1676
+ tier2 = tiers[tier2_name]
1677
+ # uhh support N args
1678
+
1679
+ if tier1.nil?
1680
+ print_red_alert "Tier not found by name #{tier1_name}!"
1681
+ return 1
1682
+ end
1683
+
1684
+ if tier2.nil?
1685
+ print_red_alert "Tier not found by name #{tier2_name}!"
1686
+ return 1
1687
+ end
1688
+
1689
+ tier1["linkedTiers"] = tier1["linkedTiers"] || []
1690
+ tier2["linkedTiers"] = tier2["linkedTiers"] || []
1691
+
1692
+ found_edge = tier1["linkedTiers"].include?(tier2_name) || tier2["linkedTiers"].include?(tier1_name)
1693
+
1694
+ if found_edge
1695
+ puts cyan,"Tiers #{tier1_name} and #{tier2_name} are not connected.",reset
1696
+ return 0
1697
+ end
1698
+
1699
+ # remove links
1700
+ tier1["linkedTiers"] = tier1["linkedTiers"].reject {|it| it == tier2_name }
1701
+ tier2["linkedTiers"] = tier2["linkedTiers"].reject {|it| it == tier1_name }
1702
+
1703
+ # ok, make api request
1704
+ blueprint["config"]["tiers"] = tiers
1705
+ payload = blueprint["config"]
1706
+ # payload = {blueprint: blueprint}
1707
+ @blueprints_interface.setopts(options)
1708
+ if options[:dry_run]
1709
+ print_dry_run @blueprints_interface.dry.update(blueprint['id'], payload)
1710
+ return
1711
+ end
1712
+ json_response = @blueprints_interface.update(blueprint['id'], payload)
1713
+
1714
+
1715
+ if options[:json]
1716
+ print JSON.pretty_generate(json_response)
1717
+ print "\n"
1718
+ else
1719
+ print_green_success "Connected 2 tiers for blueprint #{blueprint['name']}"
1720
+ get([blueprint['id']] + (options[:remote] ? ["-r",options[:remote]] : []))
1721
+ end
1722
+
1723
+ rescue RestClient::Exception => e
1724
+ print_rest_exception(e, options)
1725
+ exit 1
1726
+ end
1727
+ end
1728
+
1729
+ def available_tiers(args)
1730
+ options = {}
1731
+ optparse = MtnCloud::Cli::OptionParser.new do |opts|
1732
+ opts.banner = subcommand_usage()
1733
+ build_common_options(opts, options, [:json, :dry_run, :remote])
1734
+ end
1735
+ optparse.parse!(args)
1736
+ connect(options)
1737
+ params = {}
1738
+
1739
+ begin
1740
+ @blueprints_interface.setopts(options)
1741
+ if options[:dry_run]
1742
+ print_dry_run @blueprints_interface.dry.list_tiers(params)
1743
+ return
1744
+ end
1745
+ json_response = @blueprints_interface.list_tiers(params)
1746
+ tiers = json_response["tiers"] # just a list of names
1747
+ if options[:json]
1748
+ puts JSON.pretty_generate(json_response)
1749
+ else
1750
+ print_h1 "Available Tiers"
1751
+ if tiers.empty?
1752
+ print cyan,"No tiers found.",reset,"\n"
1753
+ else
1754
+ print cyan
1755
+ tiers.each do |tier_name|
1756
+ puts tier_name
1757
+ end
1758
+ end
1759
+ print reset,"\n"
1760
+ end
1761
+ return 0
1762
+ rescue RestClient::Exception => e
1763
+ print_rest_exception(e, options)
1764
+ exit 1
1765
+ end
1766
+
1767
+ end
1768
+
1769
+ def list_types(args)
1770
+ options = {}
1771
+ optparse = MtnCloud::Cli::OptionParser.new do |opts|
1772
+ opts.banner = subcommand_usage()
1773
+ build_common_options(opts, options, [:json, :yaml, :csv, :fields, :dry_run, :remote])
1774
+ opts.footer = "List blueprint types."
1775
+ end
1776
+ optparse.parse!(args)
1777
+ connect(options)
1778
+ begin
1779
+ params = {}
1780
+ params.merge!(parse_list_options(options))
1781
+ @blueprints_interface.setopts(options)
1782
+ if options[:dry_run]
1783
+ print_dry_run @blueprints_interface.dry.list_types(params)
1784
+ return
1785
+ end
1786
+
1787
+ json_response = @blueprints_interface.list_types(params)
1788
+ blueprint_types = json_response['types']
1789
+
1790
+ if options[:json]
1791
+ puts as_json(json_response, options, "types")
1792
+ return 0
1793
+ elsif options[:csv]
1794
+ puts records_as_csv(json_response['types'], options)
1795
+ return 0
1796
+ elsif options[:yaml]
1797
+ puts as_yaml(json_response, options, "types")
1798
+ return 0
1799
+ end
1800
+
1801
+
1802
+ title = "Blueprint Types"
1803
+ subtitles = []
1804
+ subtitles += parse_list_subtitles(options)
1805
+ print_h1 title, subtitles
1806
+ if blueprint_types.empty?
1807
+ print cyan,"No blueprint types found.",reset,"\n"
1808
+ else
1809
+ rows = blueprint_types.collect do |blueprint_type|
1810
+ {
1811
+ code: blueprint_type['code'],
1812
+ name: blueprint_type['name']
1813
+ }
1814
+ end
1815
+ columns = [:code, :name]
1816
+ print cyan
1817
+ print as_pretty_table(rows, columns, options)
1818
+ print reset
1819
+ # print_results_pagination(json_response)
1820
+ end
1821
+ print reset,"\n"
1822
+ return 0
1823
+
1824
+ rescue RestClient::Exception => e
1825
+ print_rest_exception(e, options)
1826
+ exit 1
1827
+ end
1828
+ end
1829
+
1830
+ private
1831
+
1832
+
1833
+ def add_blueprint_option_types(connected=true)
1834
+ [
1835
+ {'fieldName' => 'name', 'fieldLabel' => 'Name', 'type' => 'text', 'required' => true, 'description' => 'Enter a name for this app'},
1836
+ {'fieldName' => 'type', 'fieldLabel' => 'Type', 'type' => 'select', 'selectOptions' => (connected ? get_available_blueprint_types() : []), 'required' => true, 'defaultValue' => 'morpheus'},
1837
+ {'fieldName' => 'description', 'fieldLabel' => 'Description', 'type' => 'text', 'required' => false},
1838
+ {'fieldName' => 'category', 'fieldLabel' => 'Category', 'type' => 'text', 'required' => false},
1839
+ #{'fieldName' => 'group', 'fieldLabel' => 'Group', 'type' => 'select', 'selectOptions' => (connected ? get_available_groups() : []), 'required' => true}
1840
+ ]
1841
+ end
1842
+
1843
+ def get_available_blueprint_types(refresh=false)
1844
+ if !@available_blueprint_types || refresh
1845
+ begin
1846
+ # results = @options_interface.options_for_source('blueprintTypes',{})
1847
+ results = @blueprints_interface.list_types({})
1848
+ @available_blueprint_types = results['types'].collect {|it|
1849
+ {"name" => (it["name"] || it["code"]), "value" => (it["code"] || it["value"])}
1850
+ }
1851
+ rescue RestClient::Exception
1852
+ # older version
1853
+ @available_blueprint_types = [{"name" => "Morpheus", "value" => "morpheus"}, {"name" => "Terraform", "value" => "terraform"}, {"name" => "CloudFormation", "value" => "cloudFormation"}, {"name" => "ARM template", "value" => "arm"}]
1854
+ end
1855
+ end
1856
+ #puts "get_available_blueprints() rtn: #{@available_blueprints.inspect}"
1857
+ return @available_blueprint_types
1858
+ end
1859
+
1860
+ def update_blueprint_option_types(connected=true)
1861
+ list = add_blueprint_option_types(connected)
1862
+ list = list.select {|it| ["name","decription","category"].include? it['fieldName'] }
1863
+ list.each {|it| it['required'] = false }
1864
+ list
1865
+ end
1866
+
1867
+ def find_blueprint_by_name_or_id(val)
1868
+ if val.to_s =~ /\A\d{1,}\Z/
1869
+ return find_blueprint_by_id(val)
1870
+ else
1871
+ return find_blueprint_by_name(val)
1872
+ end
1873
+ end
1874
+
1875
+ def find_blueprint_by_id(id)
1876
+ begin
1877
+ json_response = @blueprints_interface.get(id.to_i)
1878
+ return json_response['blueprint']
1879
+ rescue RestClient::Exception => e
1880
+ if e.response && e.response.code == 404
1881
+ print_red_alert "Blueprint not found by id #{id}"
1882
+ else
1883
+ raise e
1884
+ end
1885
+ end
1886
+ end
1887
+
1888
+ def find_blueprint_by_name(name)
1889
+ blueprints = @blueprints_interface.list({name: name.to_s})['blueprints']
1890
+ if blueprints.empty?
1891
+ print_red_alert "Blueprint not found by name #{name}"
1892
+ return nil
1893
+ elsif blueprints.size > 1
1894
+ print_red_alert "#{blueprints.size} blueprints by name #{name}"
1895
+ print_blueprints_table(blueprints, {color: red})
1896
+ print reset,"\n"
1897
+ return nil
1898
+ else
1899
+ return blueprints[0]
1900
+ end
1901
+ end
1902
+
1903
+ def find_group_by_name(name)
1904
+ group_results = @groups_interface.get(name)
1905
+ if group_results['groups'].empty?
1906
+ print_red_alert "Group not found by name #{name}"
1907
+ return nil
1908
+ end
1909
+ return group_results['groups'][0]
1910
+ end
1911
+
1912
+ def find_cloud_by_name(group_id, name)
1913
+ option_results = @options_interface.options_for_source('clouds',{groupId: group_id})
1914
+ match = option_results['data'].find { |grp| grp['value'].to_s == name.to_s || grp['name'].downcase == name.downcase}
1915
+ if match.nil?
1916
+ print_red_alert "Cloud not found by name #{name}"
1917
+ return nil
1918
+ else
1919
+ return match['value']
1920
+ end
1921
+ end
1922
+
1923
+ def print_blueprints_table(blueprints, opts={})
1924
+ table_color = opts[:color] || cyan
1925
+ rows = blueprints.collect do |blueprint|
1926
+ #instance_type_names = (blueprint['instanceTypes'] || []).collect {|it| it['name'] }.join(', ')
1927
+ #instance_type_names = []
1928
+ # if blueprint['config'] && blueprint['config']["tiers"]
1929
+ # blueprint['config']["tiers"]
1930
+ # end
1931
+ {
1932
+ id: blueprint['id'],
1933
+ name: blueprint['name'],
1934
+ labels: format_list(blueprint['labels'], '', 3),
1935
+ type: blueprint['type'].kind_of?(Hash) ? blueprint['type']['name'] : format_blueprint_type(blueprint['type']),
1936
+ description: blueprint['description'],
1937
+ category: blueprint['category'],
1938
+ visibility: blueprint['visibility'].to_s.capitalize,
1939
+ owner: blueprint['owner'] ? blueprint['owner']['username'] : '',
1940
+ tenant: blueprint['tenant'] ? blueprint['tenant']['name'] : '',
1941
+ tiers_summary: format_blueprint_tiers_summary(blueprint),
1942
+ }
1943
+ end
1944
+
1945
+ term_width = current_terminal_width()
1946
+ tiers_col_width = 60
1947
+ if term_width > 190
1948
+ tiers_col_width += 130
1949
+ end
1950
+ columns = [
1951
+ :id,
1952
+ :name,
1953
+ :labels,
1954
+ :type,
1955
+ :description,
1956
+ :category,
1957
+ :owner,
1958
+ :tenant,
1959
+ :visibility,
1960
+ {:tiers_summary => {:display_name => "TIERS", :max_width => tiers_col_width} },
1961
+ ]
1962
+ if opts[:include_fields]
1963
+ columns = opts[:include_fields]
1964
+ end
1965
+ print table_color
1966
+ print as_pretty_table(rows, columns, opts)
1967
+ print reset
1968
+ end
1969
+
1970
+ def generate_id(len=16)
1971
+ id = ""
1972
+ len.times { id << (1 + rand(9)).to_s }
1973
+ id
1974
+ end
1975
+
1976
+ def format_blueprint_tiers_summary(blueprint)
1977
+ # don't use colors here, or cell truncation will not work
1978
+ str = ""
1979
+ if blueprint["config"] && blueprint["config"]["tiers"]
1980
+ tier_descriptions = blueprint["config"]["tiers"].collect do |tier_name, tier_config|
1981
+ # maybe do Tier Name (instance, instance2)
1982
+ instance_blurbs = []
1983
+ if tier_config["instances"]
1984
+ tier_config["instances"].each do |instance_config|
1985
+ if instance_config["instance"] && instance_config["instance"]["type"]
1986
+ # only have type: code in the config, rather not name fetch remotely right now..
1987
+ # instance_blurbs << instance_config["instance"]["type"]
1988
+ instance_name = instance_config["instance"]["name"] || ""
1989
+ instance_type_code = instance_config["instance"]["type"]
1990
+ instances_str = "#{instance_type_code}"
1991
+ if instance_name.to_s != ""
1992
+ instances_str << " - #{instance_name}"
1993
+ end
1994
+ begin
1995
+ config_list = parse_scoped_instance_configs(instance_config)
1996
+ if config_list.size == 0
1997
+ instances_str << " (No configs)"
1998
+ elsif config_list.size == 1
1999
+ # configs_str = config_list.collect {|it|
2000
+ # str = ""
2001
+ # it[:scope].to_s.inspect
2002
+ # }.join(", ")
2003
+ the_config = config_list[0]
2004
+ scope_str = the_config[:scope].collect {|k,v| v.to_s }.join("/")
2005
+ instances_str << " (#{scope_str})"
2006
+ else
2007
+ instances_str << " (#{config_list.size} configs)"
2008
+ end
2009
+ rescue => err
2010
+ puts_error "Failed to parse instance scoped instance configs: #{err.class} #{err.message}"
2011
+ raise err
2012
+ end
2013
+ instance_blurbs << instances_str
2014
+ end
2015
+ end
2016
+ end
2017
+ if instance_blurbs.size > 0
2018
+ tier_name + ": #{instance_blurbs.join(', ')}"
2019
+ else
2020
+ tier_name + ": (empty)"
2021
+ end
2022
+ end
2023
+ str += tier_descriptions.compact.join(", ")
2024
+ end
2025
+ str
2026
+ end
2027
+
2028
+ def print_blueprint_details(blueprint)
2029
+ print cyan
2030
+ description_cols = {
2031
+ "ID" => 'id',
2032
+ "Name" => 'name',
2033
+ "Labels" => lambda {|it| format_list(it['labels'], '') rescue '' },
2034
+ "Type" => lambda {|it| it['type'].kind_of?(Hash) ? it['type']['name'] : it['type'] },
2035
+ "Description" => 'description',
2036
+ "Category" => 'category',
2037
+ "Image" => lambda {|it| it['config'] ? (it['config']['image'] == '/assets/apps/template.png' ? '(default)' : it['config']['image']) : '' },
2038
+ "Owner" => lambda {|it| it['owner'] ? it['owner']['username'] : '' },
2039
+ "Tenant" => lambda {|it| it['tenant'] ? it['tenant']['name'] : '' },
2040
+ "Visibility" => 'visibility',
2041
+ "Group Access" => lambda {|it|
2042
+ group_access_str = ""
2043
+ begin
2044
+ rows = []
2045
+ if blueprint['resourcePermission']
2046
+ if blueprint['resourcePermission']['allSites'] || blueprint['resourcePermission']['all']
2047
+ rows.push({"name" => 'All'})
2048
+ end
2049
+ if blueprint['resourcePermission']['sites']
2050
+ blueprint['resourcePermission']['sites'].each do |site|
2051
+ rows.push(site)
2052
+ end
2053
+ end
2054
+ else
2055
+ # rows.push({"name" => 'All'})
2056
+ end
2057
+ group_access_str = rows.collect {|it| it['default'] ? "#{it['name']} (default)" : "#{it['name']}"}.join(',')
2058
+ rescue => ex
2059
+ MtnCloud::Logging::DarkPrinter.puts "Error parsing group access: #{ex}" if MtnCloud::Logging.debug?
2060
+ end
2061
+ group_access_str
2062
+ },
2063
+ "Tiers" => lambda {|it|
2064
+ tiers = []
2065
+ if blueprint["config"]["tiers"].is_a?(Hash)
2066
+ tiers = blueprint["config"]["tiers"].keys
2067
+ end
2068
+ "(#{(tiers || []).size()}) #{tiers.collect {|it| it.is_a?(Hash) ? it['name'] : it }.join(', ')}"
2069
+ },
2070
+ "Instances" => lambda {|it|
2071
+ instances = []
2072
+ tiers = {}
2073
+ if blueprint["config"]["tiers"].is_a?(Hash)
2074
+ tiers = blueprint["config"]["tiers"]
2075
+ end
2076
+ sorted_tiers = tiers.collect {|k,v| [k,v] }.sort {|a,b| a[1]['tierIndex'] <=> b[1]['tierIndex'] }
2077
+ sorted_tiers.each do |tier_obj|
2078
+ #tier_name = tier_obj[0]
2079
+ tier_config = tier_obj[1]
2080
+ if tier_config && tier_config['instances']
2081
+ tier_config['instances'].each_with_index do |instance_config, instance_index|
2082
+ instances << instance_config
2083
+ end
2084
+ end
2085
+ end
2086
+ #"(#{instances.count})"
2087
+ "(#{instances.count}) #{instances.collect {|it| it['instance'] ? it['instance']['type'] : (it['type'] || it['name']) }.join(', ')}"
2088
+ },
2089
+ # "Containers" => lambda {|it|
2090
+ # i wish
2091
+ # },
2092
+ }
2093
+
2094
+ print_description_list(description_cols, blueprint)
2095
+ print reset,"\n"
2096
+ # print_h2 "Tiers"
2097
+ if blueprint["config"] && blueprint["config"]["tiers"] && blueprint["config"]["tiers"].keys.size != 0
2098
+ print cyan
2099
+ #puts as_yaml(blueprint["config"]["tiers"])
2100
+ tiers = blueprint["config"]["tiers"]
2101
+ sorted_tiers = tiers.collect {|k,v| [k,v] }.sort {|a,b| a[1]['tierIndex'] <=> b[1]['tierIndex'] }
2102
+ sorted_tiers.each do |tier_obj|
2103
+ tier_name = tier_obj[0]
2104
+ tier_config = tier_obj[1]
2105
+ # print_h2 "Tier: #{tier_name}"
2106
+ print_h2 tier_name
2107
+ # puts " Instances:"
2108
+ if tier_config['instances'] && tier_config['instances'].size != 0
2109
+ # puts as_yaml(tier)
2110
+ tier_config['instances'].each_with_index do |instance_config, instance_index|
2111
+ instance_name = instance_config["instance"]["name"] || ""
2112
+ instance_type_code = ""
2113
+ if instance_config["instance"]["type"]
2114
+ instance_type_code = instance_config["instance"]["type"]
2115
+ end
2116
+ instance_bullet = ""
2117
+ # instance_bullet += "#{green} - #{bold}#{instance_type_code}#{reset}"
2118
+ instance_bullet += "#{green}#{bold}#{instance_type_code}#{reset}"
2119
+ if instance_name.to_s != ""
2120
+ instance_bullet += "#{green} - #{instance_name}#{reset}"
2121
+ end
2122
+ puts instance_bullet
2123
+ # print "\n"
2124
+ begin
2125
+ config_list = parse_scoped_instance_configs(instance_config)
2126
+ print cyan
2127
+ if config_list.size > 0
2128
+ print "\n"
2129
+ if config_list.size == 1
2130
+ puts " Config:"
2131
+ else
2132
+ puts " Configs (#{config_list.size}):"
2133
+ end
2134
+ config_list.each do |config_obj|
2135
+ # puts " = #{config_obj[:scope].inspect}"
2136
+ config_scope = config_obj[:scope]
2137
+ #scoped_instance_config = config_obj[:config]
2138
+ config_description = ""
2139
+ config_items = []
2140
+ if config_scope[:environment]
2141
+ config_items << {label: "Environment", value: config_scope[:environment]}
2142
+ end
2143
+ if config_scope[:group]
2144
+ config_items << {label: "Group", value: config_scope[:group]}
2145
+ end
2146
+ if config_scope[:cloud]
2147
+ config_items << {label: "Cloud", value: config_scope[:cloud]}
2148
+ end
2149
+ # if scoped_instance_config['plan'] && scoped_instance_config['plan']['code']
2150
+ # config_items << {label: "Plan", value: scoped_instance_config['plan']['code']}
2151
+ # end
2152
+ config_description = config_items.collect {|item| "#{item[:label]}: #{item[:value]}"}.join(", ")
2153
+ puts " * #{config_description}"
2154
+ end
2155
+ else
2156
+ print white," Instance has no configs, use `blueprints add-instance-config \"#{blueprint['name']}\" \"#{tier_name}\" \"#{instance_name.to_s.empty? ? instance_type_code : instance_name}\"`",reset,"\n"
2157
+ end
2158
+ rescue => err
2159
+ MtnCloud::Logging::DarkPrinter.puts "Failed to parse instance config at index #{instance_index}. Exception: #{err.class} #{err.message}" if MtnCloud::Logging.debug?
2160
+ end
2161
+ print "\n"
2162
+ #puts as_yaml(instance_config)
2163
+ # todo: iterate over
2164
+ # instance_config["groups"][group_name]["clouds"][cloud_name]
2165
+ end
2166
+
2167
+ print cyan
2168
+ if tier_config['bootOrder']
2169
+ puts "Boot Order: #{tier_config['bootOrder']}"
2170
+ end
2171
+ if tier_config['linkedTiers'] && !tier_config['linkedTiers'].empty?
2172
+ puts "Connected Tiers: #{tier_config['linkedTiers'].join(', ')}"
2173
+ end
2174
+
2175
+ else
2176
+ #print cyan," Tier is empty, use `blueprints add-instance \"#{blueprint['name']}\" \"#{tier_name}\"`",reset,"\n"
2177
+ end
2178
+ # print "\n"
2179
+
2180
+ end
2181
+ # print "\n"
2182
+
2183
+ else
2184
+ #print white,"\nTemplate is empty, use `blueprints add-tier \"#{blueprint['name']}\"`",reset,"\n"
2185
+ end
2186
+ # print reset,"\n"
2187
+ print reset
2188
+ end
2189
+
2190
+ # this parses the environments => groups => clouds tree structure
2191
+ # and returns a list of objects like {scope: {group:'thegroup'}, config: Map}
2192
+ # this would be be better as a recursive function, brute forced for now.
2193
+ def parse_scoped_instance_configs(instance_config)
2194
+ config_list = []
2195
+ if instance_config['environments'] && instance_config['environments'].keys.size > 0
2196
+ instance_config['environments'].each do |env_name, env_config|
2197
+ if env_config['groups']
2198
+ env_config['groups'].each do |group_name, group_config|
2199
+ if group_config['clouds'] && !group_config['clouds'].empty?
2200
+ group_config['clouds'].each do |cloud_name, cloud_config|
2201
+ config_list << {config: cloud_config, scope: {environment: env_name, group: group_name, cloud: cloud_name}}
2202
+ end
2203
+ end
2204
+ if (!group_config['clouds'] || group_config['clouds'].empty?)
2205
+ config_list << {config: group_config, scope: {environment: env_name, group: group_name}}
2206
+ end
2207
+ end
2208
+ end
2209
+ if env_config['clouds'] && !env_config['clouds'].empty?
2210
+ env_config['clouds'].each do |cloud_name, cloud_config|
2211
+ config_list << {config: cloud_config, scope: {environment: env_name, cloud: cloud_name}}
2212
+ end
2213
+ end
2214
+ if (!env_config['groups'] || env_config['groups'].empty?) && (!env_config['clouds'] || env_config['clouds'].empty?)
2215
+ config_list << {config: env_config, scope: {environment: env_name}}
2216
+ end
2217
+ end
2218
+ end
2219
+ if instance_config['groups']
2220
+ instance_config['groups'].each do |group_name, group_config|
2221
+ if group_config['clouds'] && !group_config['clouds'].empty?
2222
+ group_config['clouds'].each do |cloud_name, cloud_config|
2223
+ config_list << {config: cloud_config, scope: {group: group_name, cloud: cloud_name}}
2224
+ end
2225
+ end
2226
+ if (!group_config['clouds'] || group_config['clouds'].empty?)
2227
+ config_list << {config: group_config, scope: {group: group_name}}
2228
+ end
2229
+ end
2230
+ end
2231
+ if instance_config['clouds']
2232
+ instance_config['clouds'].each do |cloud_name, cloud_config|
2233
+ config_list << {config: cloud_config, scope: {cloud: cloud_name}}
2234
+ end
2235
+ end
2236
+ return config_list
2237
+ end
2238
+
2239
+ def link_tiers(tiers, tier_names)
2240
+ # tiers = blueprint["config"]["tiers"]
2241
+ tier_names = [tier_names].flatten.collect {|it| it }.compact.uniq
2242
+ if !tiers
2243
+ print_red_alert "No tiers found for template"
2244
+ return false
2245
+ end
2246
+
2247
+ existing_tier_names = tiers.keys
2248
+ matching_tier_names = tier_names.map {|tier_name|
2249
+ existing_tier_names.find {|k| k.downcase == tier_name.downcase }
2250
+ }.compact
2251
+ if matching_tier_names.size != tier_names.size
2252
+ print_red_alert "Template does not contain tiers: '#{tier_names}'"
2253
+ return false
2254
+ end
2255
+ matching_tier_names.each do |tier_name|
2256
+ tier = tiers[tier_name]
2257
+ tier['linkedTiers'] ||= []
2258
+ other_tier_names = matching_tier_names.select {|it| tier_name != it}
2259
+ other_tier_names.each do |other_tier_name|
2260
+ if !tier['linkedTiers'].include?(other_tier_name)
2261
+ tier['linkedTiers'].push(other_tier_name)
2262
+ end
2263
+ end
2264
+ end
2265
+ return true
2266
+ end
2267
+
2268
+ def unlink_tiers(tiers, tier_names)
2269
+ # tiers = blueprint["config"]["tiers"]
2270
+ tier_names = [tier_names].flatten.collect {|it| it }.compact.uniq
2271
+ if !tiers
2272
+ print_red_alert "No tiers found for template"
2273
+ return false
2274
+ end
2275
+
2276
+ existing_tier_names = tiers.keys
2277
+ matching_tier_names = tier_names.map {|tier_name|
2278
+ existing_tier_names.find {|k| k.downcase == tier_name.downcase }
2279
+ }.compact
2280
+ if matching_tier_names.size != tier_names.size
2281
+ print_red_alert "Template does not contain tiers: '#{tier_names}'"
2282
+ return false
2283
+ end
2284
+ matching_tier_names.each do |tier_name|
2285
+ tier = tiers[tier_name]
2286
+ tier['linkedTiers'] ||= []
2287
+ other_tier_names = matching_tier_names.select {|it| tier_name != it}
2288
+ other_tier_names.each do |other_tier_name|
2289
+ if tier['linkedTiers'].include?(other_tier_name)
2290
+ tier['linkedTiers'] = tier['linkedTiers'].reject {|it| it == other_tier_name }
2291
+ end
2292
+ end
2293
+ end
2294
+ return true
2295
+ end
2296
+
2297
+ end