morpheus-cli 5.3.4 → 5.4.3

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 (214) hide show
  1. checksums.yaml +4 -4
  2. data/Dockerfile +1 -1
  3. data/lib/morpheus/api/account_users_interface.rb +68 -0
  4. data/lib/morpheus/api/api_client.rb +69 -11
  5. data/lib/morpheus/api/audit_interface.rb +9 -0
  6. data/lib/morpheus/api/catalog_item_types_interface.rb +20 -0
  7. data/lib/morpheus/api/health_interface.rb +37 -3
  8. data/lib/morpheus/api/instances_interface.rb +49 -0
  9. data/lib/morpheus/api/load_balancer_monitors_interface.rb +9 -0
  10. data/lib/morpheus/api/load_balancer_pools_interface.rb +4 -4
  11. data/lib/morpheus/api/load_balancer_profiles_interface.rb +4 -5
  12. data/lib/morpheus/api/load_balancer_virtual_servers_interface.rb +13 -4
  13. data/lib/morpheus/api/load_balancers_interface.rb +5 -0
  14. data/lib/morpheus/api/network_dhcp_relays_interface.rb +36 -0
  15. data/lib/morpheus/api/network_dhcp_servers_interface.rb +36 -0
  16. data/lib/morpheus/api/network_edge_clusters_interface.rb +26 -0
  17. data/lib/morpheus/api/network_routers_interface.rb +9 -0
  18. data/lib/morpheus/api/network_servers_interface.rb +68 -12
  19. data/lib/morpheus/api/network_static_routes_interface.rb +36 -0
  20. data/lib/morpheus/api/ping_interface.rb +2 -0
  21. data/lib/morpheus/api/read_interface.rb +4 -3
  22. data/lib/morpheus/api/rest_interface.rb +3 -3
  23. data/lib/morpheus/api/roles_interface.rb +7 -0
  24. data/lib/morpheus/api/secondary_read_interface.rb +1 -1
  25. data/lib/morpheus/api/secondary_rest_interface.rb +19 -19
  26. data/lib/morpheus/api/setup_interface.rb +4 -0
  27. data/lib/morpheus/api/snapshots_interface.rb +19 -0
  28. data/lib/morpheus/api/storage_server_types_interface.rb +14 -0
  29. data/lib/morpheus/api/storage_servers_interface.rb +9 -0
  30. data/lib/morpheus/api/storage_volume_types_interface.rb +9 -0
  31. data/lib/morpheus/api/storage_volumes_interface.rb +9 -0
  32. data/lib/morpheus/api/users_interface.rb +16 -63
  33. data/lib/morpheus/cli/cli_command.rb +260 -13
  34. data/lib/morpheus/cli/cli_registry.rb +2 -1
  35. data/lib/morpheus/cli/{access_token_command.rb → commands/access_token_command.rb} +1 -1
  36. data/lib/morpheus/cli/{account_groups_command.rb → commands/account_groups_command.rb} +0 -8
  37. data/lib/morpheus/cli/{activity_command.rb → commands/activity_command.rb} +0 -0
  38. data/lib/morpheus/cli/commands/{standard/alias_command.rb → alias_command.rb} +1 -4
  39. data/lib/morpheus/cli/{appliance_settings_command.rb → commands/appliance_settings_command.rb} +0 -0
  40. data/lib/morpheus/cli/{approvals_command.rb → commands/approvals_command.rb} +0 -0
  41. data/lib/morpheus/cli/{apps.rb → commands/apps.rb} +14 -87
  42. data/lib/morpheus/cli/{archives_command.rb → commands/archives_command.rb} +0 -6
  43. data/lib/morpheus/cli/commands/audit.rb +188 -0
  44. data/lib/morpheus/cli/{backup_jobs_command.rb → commands/backup_jobs_command.rb} +0 -0
  45. data/lib/morpheus/cli/{backup_settings_command.rb → commands/backup_settings_command.rb} +0 -0
  46. data/lib/morpheus/cli/{backups_command.rb → commands/backups_command.rb} +0 -0
  47. data/lib/morpheus/cli/commands/{standard/benchmark_command.rb → benchmark_command.rb} +0 -3
  48. data/lib/morpheus/cli/{blueprints_command.rb → commands/blueprints_command.rb} +1 -1
  49. data/lib/morpheus/cli/{boot_scripts_command.rb → commands/boot_scripts_command.rb} +0 -3
  50. data/lib/morpheus/cli/{budgets_command.rb → commands/budgets_command.rb} +0 -0
  51. data/lib/morpheus/cli/commands/{standard/cat_command.rb → cat_command.rb} +0 -0
  52. data/lib/morpheus/cli/{catalog_item_types_command.rb → commands/catalog_item_types_command.rb} +88 -0
  53. data/lib/morpheus/cli/{certificates_command.rb → commands/certificates_command.rb} +0 -0
  54. data/lib/morpheus/cli/commands/change_password_command.rb +132 -0
  55. data/lib/morpheus/cli/{cloud_datastores_command.rb → commands/cloud_datastores_command.rb} +0 -4
  56. data/lib/morpheus/cli/{cloud_folders_command.rb → commands/cloud_folders_command.rb} +0 -4
  57. data/lib/morpheus/cli/{cloud_resource_pools_command.rb → commands/cloud_resource_pools_command.rb} +0 -4
  58. data/lib/morpheus/cli/{clouds.rb → commands/clouds.rb} +0 -7
  59. data/lib/morpheus/cli/{clusters.rb → commands/clusters.rb} +96 -64
  60. data/lib/morpheus/cli/commands/{standard/coloring_command.rb → coloring_command.rb} +0 -2
  61. data/lib/morpheus/cli/{containers_command.rb → commands/containers_command.rb} +0 -7
  62. data/lib/morpheus/cli/commands/{standard/curl_command.rb → curl_command.rb} +0 -3
  63. data/lib/morpheus/cli/{cypher_command.rb → commands/cypher_command.rb} +0 -1
  64. data/lib/morpheus/cli/{dashboard_command.rb → commands/dashboard_command.rb} +0 -2
  65. data/lib/morpheus/cli/commands/{standard/debug_command.rb → debug_command.rb} +0 -1
  66. data/lib/morpheus/cli/{deploy.rb → commands/deploy.rb} +0 -1
  67. data/lib/morpheus/cli/{deployments.rb → commands/deployments.rb} +0 -0
  68. data/lib/morpheus/cli/{deploys.rb → commands/deploys.rb} +0 -1
  69. data/lib/morpheus/cli/{doc.rb → commands/doc.rb} +1 -1
  70. data/lib/morpheus/cli/commands/{standard/echo_command.rb → echo_command.rb} +0 -2
  71. data/lib/morpheus/cli/commands/{standard/edit_profile_command.rb → edit_profile_command.rb} +15 -4
  72. data/lib/morpheus/cli/commands/{standard/edit_rc_command.rb → edit_rc_command.rb} +19 -3
  73. data/lib/morpheus/cli/{environments_command.rb → commands/environments_command.rb} +0 -5
  74. data/lib/morpheus/cli/{execute_schedules_command.rb → commands/execute_schedules_command.rb} +0 -0
  75. data/lib/morpheus/cli/{execution_request_command.rb → commands/execution_request_command.rb} +0 -2
  76. data/lib/morpheus/cli/commands/{standard/exit_command.rb → exit_command.rb} +0 -2
  77. data/lib/morpheus/cli/{file_copy_request_command.rb → commands/file_copy_request_command.rb} +0 -4
  78. data/lib/morpheus/cli/{forgot_password.rb → commands/forgot_password.rb} +0 -0
  79. data/lib/morpheus/cli/commands/{standard/get_prompt_command.rb → get_prompt_command.rb} +0 -3
  80. data/lib/morpheus/cli/{groups.rb → commands/groups.rb} +0 -7
  81. data/lib/morpheus/cli/{guidance_command.rb → commands/guidance_command.rb} +1 -1
  82. data/lib/morpheus/cli/{health_command.rb → commands/health_command.rb} +104 -19
  83. data/lib/morpheus/cli/commands/{standard/history_command.rb → history_command.rb} +0 -3
  84. data/lib/morpheus/cli/{hosts.rb → commands/hosts.rb} +27 -24
  85. data/lib/morpheus/cli/{image_builder_command.rb → commands/image_builder_command.rb} +6 -16
  86. data/lib/morpheus/cli/{instance_types.rb → commands/instance_types.rb} +0 -3
  87. data/lib/morpheus/cli/{instances.rb → commands/instances.rb} +359 -7
  88. data/lib/morpheus/cli/{integrations_command.rb → commands/integrations_command.rb} +1 -12
  89. data/lib/morpheus/cli/{invoices_command.rb → commands/invoices_command.rb} +1 -1
  90. data/lib/morpheus/cli/{jobs_command.rb → commands/jobs_command.rb} +0 -0
  91. data/lib/morpheus/cli/{key_pairs.rb → commands/key_pairs.rb} +0 -6
  92. data/lib/morpheus/cli/{library_cluster_layouts_command.rb → commands/library_cluster_layouts_command.rb} +0 -4
  93. data/lib/morpheus/cli/{library_container_scripts_command.rb → commands/library_container_scripts_command.rb} +0 -0
  94. data/lib/morpheus/cli/{library_container_templates_command.rb → commands/library_container_templates_command.rb} +0 -1
  95. data/lib/morpheus/cli/{library_container_types_command.rb → commands/library_container_types_command.rb} +0 -4
  96. data/lib/morpheus/cli/{library_instance_types_command.rb → commands/library_instance_types_command.rb} +3 -4
  97. data/lib/morpheus/cli/{library_layouts_command.rb → commands/library_layouts_command.rb} +0 -4
  98. data/lib/morpheus/cli/{library_option_lists_command.rb → commands/library_option_lists_command.rb} +0 -4
  99. data/lib/morpheus/cli/{library_option_types_command.rb → commands/library_option_types_command.rb} +0 -4
  100. data/lib/morpheus/cli/{library_spec_templates_command.rb → commands/library_spec_templates_command.rb} +0 -1
  101. data/lib/morpheus/cli/{library_upgrades_command.rb → commands/library_upgrades_command.rb} +0 -4
  102. data/lib/morpheus/cli/{license.rb → commands/license.rb} +0 -3
  103. data/lib/morpheus/cli/commands/load_balancer_monitors.rb +70 -0
  104. data/lib/morpheus/cli/commands/load_balancer_pools.rb +90 -0
  105. data/lib/morpheus/cli/commands/load_balancer_profiles.rb +64 -0
  106. data/lib/morpheus/cli/{load_balancer_types.rb → commands/load_balancer_types.rb} +9 -8
  107. data/lib/morpheus/cli/{load_balancer_virtual_servers.rb → commands/load_balancer_virtual_servers.rb} +69 -58
  108. data/lib/morpheus/cli/commands/load_balancers.rb +192 -0
  109. data/lib/morpheus/cli/commands/{standard/log_level_command.rb → log_level_command.rb} +0 -3
  110. data/lib/morpheus/cli/{log_settings_command.rb → commands/log_settings_command.rb} +0 -0
  111. data/lib/morpheus/cli/{login.rb → commands/login.rb} +0 -5
  112. data/lib/morpheus/cli/commands/logout.rb +63 -0
  113. data/lib/morpheus/cli/{logs_command.rb → commands/logs_command.rb} +0 -3
  114. data/lib/morpheus/cli/commands/{standard/man_command.rb → man_command.rb} +0 -2
  115. data/lib/morpheus/cli/{monitoring_alerts_command.rb → commands/monitoring_alerts_command.rb} +0 -7
  116. data/lib/morpheus/cli/{monitoring_apps_command.rb → commands/monitoring_apps_command.rb} +0 -1
  117. data/lib/morpheus/cli/{monitoring_checks_command.rb → commands/monitoring_checks_command.rb} +0 -1
  118. data/lib/morpheus/cli/{monitoring_contacts_command.rb → commands/monitoring_contacts_command.rb} +0 -7
  119. data/lib/morpheus/cli/{monitoring_groups_command.rb → commands/monitoring_groups_command.rb} +0 -1
  120. data/lib/morpheus/cli/{monitoring_incidents_command.rb → commands/monitoring_incidents_command.rb} +0 -1
  121. data/lib/morpheus/cli/commands/network_dhcp_relays_command.rb +416 -0
  122. data/lib/morpheus/cli/commands/network_dhcp_servers_command.rb +407 -0
  123. data/lib/morpheus/cli/{network_domains_command.rb → commands/network_domains_command.rb} +0 -4
  124. data/lib/morpheus/cli/commands/network_edge_clusters_command.rb +329 -0
  125. data/lib/morpheus/cli/commands/network_firewalls_command.rb +823 -0
  126. data/lib/morpheus/cli/{network_groups_command.rb → commands/network_groups_command.rb} +0 -4
  127. data/lib/morpheus/cli/{network_pool_servers_command.rb → commands/network_pool_servers_command.rb} +0 -4
  128. data/lib/morpheus/cli/{network_pools_command.rb → commands/network_pools_command.rb} +0 -4
  129. data/lib/morpheus/cli/{network_proxies_command.rb → commands/network_proxies_command.rb} +0 -4
  130. data/lib/morpheus/cli/{network_routers_command.rb → commands/network_routers_command.rb} +96 -50
  131. data/lib/morpheus/cli/{network_services_command.rb → commands/network_services_command.rb} +0 -4
  132. data/lib/morpheus/cli/commands/network_static_routes_command.rb +451 -0
  133. data/lib/morpheus/cli/{network_scopes_command.rb → commands/network_transport_zones_command.rb} +102 -92
  134. data/lib/morpheus/cli/{networks_command.rb → commands/networks_command.rb} +20 -20
  135. data/lib/morpheus/cli/commands/open_command.rb +30 -0
  136. data/lib/morpheus/cli/commands/options.rb +98 -0
  137. data/lib/morpheus/cli/{packages_command.rb → commands/packages_command.rb} +0 -2
  138. data/lib/morpheus/cli/{ping.rb → commands/ping.rb} +3 -12
  139. data/lib/morpheus/cli/{policies_command.rb → commands/policies_command.rb} +2 -9
  140. data/lib/morpheus/cli/{power_schedules_command.rb → commands/power_schedules_command.rb} +0 -0
  141. data/lib/morpheus/cli/{preseed_scripts_command.rb → commands/preseed_scripts_command.rb} +0 -3
  142. data/lib/morpheus/cli/{price_sets_command.rb → commands/price_sets_command.rb} +0 -0
  143. data/lib/morpheus/cli/{prices_command.rb → commands/prices_command.rb} +7 -7
  144. data/lib/morpheus/cli/{processes_command.rb → commands/processes_command.rb} +0 -1
  145. data/lib/morpheus/cli/{projects_command.rb → commands/projects_command.rb} +0 -0
  146. data/lib/morpheus/cli/{provisioning_licenses_command.rb → commands/provisioning_licenses_command.rb} +0 -0
  147. data/lib/morpheus/cli/{provisioning_settings_command.rb → commands/provisioning_settings_command.rb} +1 -0
  148. data/lib/morpheus/cli/{recent_activity_command.rb → commands/recent_activity_command.rb} +0 -0
  149. data/lib/morpheus/cli/{remote.rb → commands/remote.rb} +21 -19
  150. data/lib/morpheus/cli/{reports_command.rb → commands/reports_command.rb} +0 -2
  151. data/lib/morpheus/cli/commands/{standard/rm_command.rb → rm_command.rb} +0 -0
  152. data/lib/morpheus/cli/{roles.rb → commands/roles.rb} +245 -40
  153. data/lib/morpheus/cli/{search_command.rb → commands/search_command.rb} +0 -0
  154. data/lib/morpheus/cli/{security_group_rules.rb → commands/security_group_rules.rb} +0 -5
  155. data/lib/morpheus/cli/{security_groups.rb → commands/security_groups.rb} +2 -8
  156. data/lib/morpheus/cli/{service_catalog_command.rb → commands/service_catalog_command.rb} +0 -0
  157. data/lib/morpheus/cli/{service_plans_command.rb → commands/service_plans_command.rb} +1 -1
  158. data/lib/morpheus/cli/commands/{standard/set_prompt_command.rb → set_prompt_command.rb} +0 -3
  159. data/lib/morpheus/cli/{setup.rb → commands/setup.rb} +1 -1
  160. data/lib/morpheus/cli/{shell.rb → commands/shell.rb} +4 -105
  161. data/lib/morpheus/cli/commands/{standard/sleep_command.rb → sleep_command.rb} +0 -2
  162. data/lib/morpheus/cli/commands/snapshots.rb +139 -0
  163. data/lib/morpheus/cli/commands/{standard/source_command.rb → source_command.rb} +0 -2
  164. data/lib/morpheus/cli/commands/{standard/ssl_verification_command.rb → ssl_verification_command.rb} +0 -3
  165. data/lib/morpheus/cli/{storage_providers_command.rb → commands/storage_providers_command.rb} +0 -4
  166. data/lib/morpheus/cli/commands/storage_server_types.rb +50 -0
  167. data/lib/morpheus/cli/commands/storage_servers.rb +122 -0
  168. data/lib/morpheus/cli/commands/storage_volume_types.rb +50 -0
  169. data/lib/morpheus/cli/commands/storage_volumes.rb +103 -0
  170. data/lib/morpheus/cli/{subnets_command.rb → commands/subnets_command.rb} +0 -4
  171. data/lib/morpheus/cli/{tasks.rb → commands/tasks.rb} +5 -9
  172. data/lib/morpheus/cli/commands/{standard/tee_command.rb → tee_command.rb} +0 -0
  173. data/lib/morpheus/cli/{tenants_command.rb → commands/tenants_command.rb} +1 -8
  174. data/lib/morpheus/cli/commands/{standard/update_command.rb → update_command.rb} +0 -1
  175. data/lib/morpheus/cli/{usage_command.rb → commands/usage_command.rb} +0 -0
  176. data/lib/morpheus/cli/{user_groups_command.rb → commands/user_groups_command.rb} +1 -2
  177. data/lib/morpheus/cli/{user_settings_command.rb → commands/user_settings_command.rb} +3 -2
  178. data/lib/morpheus/cli/{user_sources_command.rb → commands/user_sources_command.rb} +1 -2
  179. data/lib/morpheus/cli/{users.rb → commands/users.rb} +28 -35
  180. data/lib/morpheus/cli/{vdi_allocations_command.rb → commands/vdi_allocations_command.rb} +0 -0
  181. data/lib/morpheus/cli/{vdi_apps_command.rb → commands/vdi_apps_command.rb} +0 -0
  182. data/lib/morpheus/cli/{vdi_command.rb → commands/vdi_command.rb} +0 -0
  183. data/lib/morpheus/cli/{vdi_gateways_command.rb → commands/vdi_gateways_command.rb} +0 -0
  184. data/lib/morpheus/cli/{vdi_pools_command.rb → commands/vdi_pools_command.rb} +0 -0
  185. data/lib/morpheus/cli/commands/{standard/version_command.rb → version_command.rb} +0 -0
  186. data/lib/morpheus/cli/commands/view.rb +102 -0
  187. data/lib/morpheus/cli/{virtual_images.rb → commands/virtual_images.rb} +4 -5
  188. data/lib/morpheus/cli/{whitelabel_settings_command.rb → commands/whitelabel_settings_command.rb} +0 -1
  189. data/lib/morpheus/cli/{whoami.rb → commands/whoami.rb} +0 -4
  190. data/lib/morpheus/cli/{wiki_command.rb → commands/wiki_command.rb} +0 -5
  191. data/lib/morpheus/cli/{workflows.rb → commands/workflows.rb} +0 -3
  192. data/lib/morpheus/cli/mixins/accounts_helper.rb +5 -5
  193. data/lib/morpheus/cli/mixins/load_balancers_helper.rb +24 -4
  194. data/lib/morpheus/cli/mixins/logs_helper.rb +1 -1
  195. data/lib/morpheus/cli/mixins/print_helper.rb +51 -18
  196. data/lib/morpheus/cli/mixins/processes_helper.rb +1 -2
  197. data/lib/morpheus/cli/mixins/provisioning_helper.rb +96 -6
  198. data/lib/morpheus/cli/mixins/rest_command.rb +222 -62
  199. data/lib/morpheus/cli/mixins/secondary_rest_command.rb +249 -70
  200. data/lib/morpheus/cli/mixins/storage_servers_helper.rb +156 -0
  201. data/lib/morpheus/cli/mixins/storage_volumes_helper.rb +119 -0
  202. data/lib/morpheus/cli/option_types.rb +150 -46
  203. data/lib/morpheus/cli/version.rb +1 -1
  204. data/lib/morpheus/cli.rb +5 -135
  205. data/lib/morpheus/ext/string.rb +29 -6
  206. data/lib/morpheus/routes.rb +238 -0
  207. data/lib/morpheus/terminal.rb +5 -6
  208. data/lib/morpheus/util.rb +6 -1
  209. metadata +174 -144
  210. data/lib/morpheus/cli/change_password_command.rb +0 -147
  211. data/lib/morpheus/cli/library.rb +0 -1
  212. data/lib/morpheus/cli/load_balancer_pools.rb +0 -111
  213. data/lib/morpheus/cli/load_balancers.rb +0 -90
  214. data/lib/morpheus/cli/logout.rb +0 -81
@@ -0,0 +1,119 @@
1
+ require 'morpheus/cli/mixins/print_helper'
2
+ require 'morpheus/cli/option_types'
3
+ require 'morpheus/rest_client'
4
+ # Mixin for Morpheus::Cli command classes
5
+ # Provides common methods for storage volume management
6
+ # including storage volumes and storage volume types
7
+ module Morpheus::Cli::StorageVolumesHelper
8
+
9
+ def self.included(klass)
10
+ klass.send :include, Morpheus::Cli::PrintHelper
11
+ end
12
+
13
+ def storage_volumes_interface
14
+ # @api_client.storage_volumes
15
+ raise "#{self.class} has not defined @storage_volumes_interface" if @storage_volumes_interface.nil?
16
+ @storage_volumes_interface
17
+ end
18
+
19
+ def storage_volume_types_interface
20
+ # @api_client.storage_volume_types
21
+ raise "#{self.class} has not defined @storage_volume_types_interface" if @storage_volume_types_interface.nil?
22
+ @storage_volume_types_interface
23
+ end
24
+
25
+ def storage_volume_object_key
26
+ 'storageVolume'
27
+ end
28
+
29
+ def storage_volume_list_key
30
+ 'storageVolumes'
31
+ end
32
+
33
+ def storage_volume_label
34
+ 'Storage Volume'
35
+ end
36
+
37
+ def storage_volume_label_plural
38
+ 'Storage Volume'
39
+ end
40
+
41
+ def storage_volume_type_object_key
42
+ 'storageVolumeType'
43
+ end
44
+
45
+ def storage_volume_type_list_key
46
+ 'storageVolumeTypes'
47
+ end
48
+
49
+ def storage_volume_type_label
50
+ 'Storage Volume Type'
51
+ end
52
+
53
+ def storage_volume_type_label_plural
54
+ 'Storage Volume Types'
55
+ end
56
+
57
+ def get_available_storage_volume_types(refresh=false)
58
+ if !@available_storage_volume_types || refresh
59
+ @available_storage_volume_types = storage_volume_types_interface.list({max:1000})[storage_volume_type_list_key]
60
+ end
61
+ return @available_storage_volume_types
62
+ end
63
+
64
+ def storage_volume_type_for_name_or_id(val)
65
+ if val.to_s =~ /\A\d{1,}\Z/
66
+ return storage_volume_type_for_id(val)
67
+ else
68
+ return storage_volume_type_for_name(val)
69
+ end
70
+ end
71
+
72
+ def storage_volume_type_for_id(val)
73
+ record = get_available_storage_volume_types().find { |z| z['id'].to_i == val.to_i}
74
+ label = "Storage Volume Type"
75
+ if record.nil?
76
+ print_red_alert "#{label} not found by id #{val}"
77
+ return nil
78
+ end
79
+ return record
80
+ end
81
+
82
+ def storage_volume_type_for_name(val)
83
+ records = get_available_storage_volume_types().select { |z| z['name'].downcase == val.downcase || z['code'].downcase == val.downcase}
84
+ label = "Storage Volume Type"
85
+ if records.empty?
86
+ print_red_alert "#{label} not found by name '#{val}'"
87
+ return nil
88
+ elsif records.size > 1
89
+ print_red_alert "More than one #{label.downcase} found by name '#{val}'"
90
+ print_error "\n"
91
+ puts_error as_pretty_table(records, [:id, :name], {color:red})
92
+ print_red_alert "Try using ID instead"
93
+ print_error reset,"\n"
94
+ return nil
95
+ else
96
+ return records[0]
97
+ end
98
+ end
99
+
100
+ def format_storage_volume_status(record, return_color=cyan)
101
+ out = ""
102
+ status_string = record['status']
103
+ if status_string.nil? || status_string.empty? || status_string == "unknown"
104
+ out << "#{white}UNKNOWN#{return_color}"
105
+ elsif status_string == 'provisioned' || status_string == 'unattached'
106
+ out << "#{cyan}#{status_string.capitalize}#{return_color}"
107
+ elsif status_string == 'syncing'
108
+ out << "#{yellow}#{status_string.capitalize}#{return_color}"
109
+ else
110
+ out << "#{red}#{status_string ? status_string.capitalize : 'N/A'}#{record['statusMessage'] ? "#{return_color} - #{record['statusMessage']}" : ''}#{return_color}"
111
+ end
112
+ out
113
+ end
114
+
115
+ def format_storage_volume_source(storage_volume)
116
+ storage_volume['source']
117
+ end
118
+
119
+ end
@@ -33,14 +33,21 @@ module Morpheus
33
33
  end
34
34
  end
35
35
 
36
+ # supresses prompting unless --prompt has been passed
36
37
  def self.no_prompt(option_types, options={}, api_client=nil,api_params={})
37
- prompt(option_types, options, api_client, api_params, true)
38
+ if options[:always_prompt]
39
+ prompt(option_types, options, api_client, api_params)
40
+ else
41
+ prompt(option_types, options, api_client, api_params, true)
42
+ end
38
43
  end
39
44
 
40
- def self.prompt(option_types, options={}, api_client=nil, api_params={}, no_prompt=false, paging_enabled=false)
45
+ def self.prompt(option_types, options={}, api_client=nil, api_params={}, no_prompt=false, paging_enabled=false, ignore_empty=false)
41
46
  paging_enabled = false if Morpheus::Cli.windows?
47
+ no_prompt = no_prompt || options[:no_prompt]
42
48
  results = {}
43
49
  options = options || {}
50
+
44
51
  # inject cli only stuff into option_types (should clone() here)
45
52
  option_types.each do |option_type|
46
53
  if options[:help_field_prefix]
@@ -50,15 +57,15 @@ module Morpheus
50
57
  if option_type['fieldGroup'].to_s.downcase == 'options'
51
58
  option_type['fieldGroup'] = 'default'
52
59
  end
60
+ # apply custom templates
61
+ if option_type['fieldName'] == 'sshHosts'
62
+ option_type['type'] = 'multiText'
63
+ end
53
64
  end
54
65
  # puts "Options Prompt #{options}"
55
66
  # Sort options by default, group, advanced
56
67
  cur_field_group = 'default'
57
- (
58
- option_types.reject {|it| (it['fieldGroup'] || 'default') != 'default'}.sort {|a,b| a['displayOrder'].to_i <=> b['displayOrder'].to_i} +
59
- option_types.reject {|it| ['default', 'advanced'].include?(it['fieldGroup'] || 'default')}.sort{|a,b| a['displayOrder'] <=> b['displayOrder']}.group_by{|it| it['fieldGroup']}.values.collect { |it| it.sort{|a,b| a['displayOrder'].to_i <=> b['displayOrder'].to_i}}.flatten +
60
- option_types.reject {|it| it['fieldGroup'] != 'advanced'}.sort {|a,b| a['displayOrder'].to_i <=> b['displayOrder'].to_i}
61
- ).each do |option_type|
68
+ self.sorted_option_types(option_types).each do |option_type|
62
69
  context_map = results
63
70
  value = nil
64
71
  value_found = false
@@ -66,7 +73,9 @@ module Morpheus
66
73
 
67
74
  if cur_field_group != field_group
68
75
  cur_field_group = field_group
69
- print "\n#{cur_field_group.upcase} OPTIONS\n#{"=" * ("#{cur_field_group} OPTIONS".length)}\n\n"
76
+ if !no_prompt
77
+ print "\n#{cur_field_group.upcase} OPTIONS\n#{"=" * ("#{cur_field_group} OPTIONS".length)}\n\n"
78
+ end
70
79
  end
71
80
 
72
81
  # How about this instead?
@@ -123,7 +132,11 @@ module Morpheus
123
132
  get_object_value(options, depends_on_field_key) ||
124
133
  get_object_value(api_params, depends_on_field_key)
125
134
 
126
- if !field_value.nil? && (depends_on_value.nil? || depends_on_value.empty? || field_value.match?(depends_on_value))
135
+ if field_value.nil? && !options['_object_key'].nil?
136
+ field_value = get_object_value({options['_object_key'] => results}, depends_on_field_key)
137
+ end
138
+
139
+ if !field_value.nil? && (depends_on_value.nil? || depends_on_value.empty? || field_value.to_s.match?(depends_on_value))
127
140
  found_dep_value = true if match_type != 'all'
128
141
  else
129
142
  found_dep_value = false if match_type == 'all'
@@ -146,6 +159,10 @@ module Morpheus
146
159
  context_map = context_map[ns.to_s]
147
160
  end
148
161
 
162
+ # build parameters for option source api request
163
+ option_params = (option_type['noParams'] ? {} : (api_params || {}).deep_merge(results))
164
+ option_params.merge!(option_type['optionParams']) if option_type['optionParams']
165
+
149
166
  # use the value passed in the options map
150
167
  if cur_namespace.respond_to?('key?') && cur_namespace.key?(field_name)
151
168
  value = cur_namespace[field_name]
@@ -156,25 +173,25 @@ module Morpheus
156
173
  end
157
174
  # these select prompts should just fall down through below, with the extra params no_prompt, use_value
158
175
  elsif option_type['type'] == 'select'
159
- value = select_prompt(option_type.merge({'defaultValue' => value, 'defaultInputValue' => input_value}), api_client, (option_type['noParams'] ? {} : (api_params || {}).merge(results)), true)
176
+ value = select_prompt(option_type.merge({'defaultValue' => value, 'defaultInputValue' => input_value}), api_client, option_params, true, nil, false, ignore_empty)
160
177
  elsif option_type['type'] == 'multiSelect'
161
178
  # support value as csv like "thing1, thing2"
162
179
  value_list = value.is_a?(String) ? value.parse_csv.collect {|v| v ? v.to_s.strip : v } : [value].flatten
163
180
  input_value_list = input_value.is_a?(String) ? input_value.parse_csv.collect {|v| v ? v.to_s.strip : v } : [input_value].flatten
164
181
  select_value_list = []
165
182
  value_list.each_with_index do |v, i|
166
- select_value_list << select_prompt(option_type.merge({'defaultValue' => v, 'defaultInputValue' => input_value_list[i]}), api_client, (option_type['noParams'] ? {} : (api_params || {}).merge(results)), true)
183
+ select_value_list << select_prompt(option_type.merge({'defaultValue' => v, 'defaultInputValue' => input_value_list[i]}), api_client, option_params, true, nil, false, ignore_empty)
167
184
  end
168
185
  value = select_value_list
169
186
  elsif option_type['type'] == 'typeahead'
170
- value = typeahead_prompt(option_type.merge({'defaultValue' => value, 'defaultInputValue' => input_value}), api_client, (option_type['noParams'] ? {} : (api_params || {}).merge(results)), true)
187
+ value = typeahead_prompt(option_type.merge({'defaultValue' => value, 'defaultInputValue' => input_value}), api_client, option_params, true)
171
188
  elsif option_type['type'] == 'multiTypeahead'
172
189
  # support value as csv like "thing1, thing2"
173
190
  value_list = value.is_a?(String) ? value.parse_csv.collect {|v| v ? v.to_s.strip : v } : [value].flatten
174
191
  input_value_list = input_value.is_a?(String) ? input_value.parse_csv.collect {|v| v ? v.to_s.strip : v } : [input_value].flatten
175
192
  select_value_list = []
176
193
  value_list.each_with_index do |v, i|
177
- select_value_list << typeahead_prompt(option_type.merge({'defaultValue' => v, 'defaultInputValue' => input_value_list[i]}), api_client, (option_type['noParams'] ? {} : (api_params || {}).merge(results)), true)
194
+ select_value_list << typeahead_prompt(option_type.merge({'defaultValue' => v, 'defaultInputValue' => input_value_list[i]}), api_client, option_params, true)
178
195
  end
179
196
  value = select_value_list
180
197
  end
@@ -190,7 +207,6 @@ module Morpheus
190
207
  end
191
208
  # no_prompt means skip prompting and instead
192
209
  # use default value or error if a required option is not present
193
- no_prompt = no_prompt || options[:no_prompt]
194
210
  if no_prompt
195
211
  if !value_found
196
212
  if option_type['defaultValue'] != nil && !['select', 'multiSelect','typeahead','multiTypeahead'].include?(option_type['type'])
@@ -201,14 +217,14 @@ module Morpheus
201
217
  # select type is special because it supports skipSingleOption
202
218
  # and prints the available options on error
203
219
  if ['select', 'multiSelect'].include?(option_type['type'])
204
- value = select_prompt(option_type, api_client, (option_type['noParams'] ? {} : (api_params || {}).merge(results)), true)
220
+ value = select_prompt(option_type, api_client, option_params, true, nil, false, ignore_empty)
205
221
  value_found = !!value
206
222
  end
207
223
  if ['typeahead', 'multiTypeahead'].include?(option_type['type'])
208
- value = typeahead_prompt(option_type, api_client, (option_type['noParams'] ? {} : (api_params || {}).merge(results)), true)
224
+ value = typeahead_prompt(option_type, api_client, option_params, true)
209
225
  value_found = !!value
210
226
  end
211
- if !value_found
227
+ if !value_found && !ignore_empty
212
228
  if option_type['required']
213
229
  print Term::ANSIColor.red, "\nMissing Required Option\n\n", Term::ANSIColor.reset
214
230
  print Term::ANSIColor.red, " * #{option_type['fieldLabel']} [-O #{help_field_key}=] - #{option_type['description']}\n", Term::ANSIColor.reset
@@ -242,11 +258,11 @@ module Morpheus
242
258
  # I suppose the entered value should take precedence
243
259
  # api_params = api_params.merge(options) # this might be good enough
244
260
  # dup it
245
- value = select_prompt(option_type, api_client, (option_type['noParams'] ? {} : (api_params || {}).deep_merge(results)), options[:no_prompt], nil, paging_enabled)
261
+ value = select_prompt(option_type, api_client, option_params, options[:no_prompt], nil, paging_enabled, ignore_empty)
246
262
  if value && option_type['type'] == 'multiSelect'
247
263
  value = [value]
248
264
  while self.confirm("Add another #{option_type['fieldLabel']}?", {:default => false}) do
249
- if addn_value = select_prompt(option_type, api_client, (option_type['noParams'] ? {} : (api_params || {}).merge(results)), options[:no_prompt], nil, paging_enabled)
265
+ if addn_value = select_prompt(option_type, api_client, option_params, options[:no_prompt], nil, paging_enabled, ignore_empty)
250
266
  value << addn_value
251
267
  else
252
268
  break
@@ -254,11 +270,11 @@ module Morpheus
254
270
  end
255
271
  end
256
272
  elsif ['typeahead', 'multiTypeahead'].include?(option_type['type'])
257
- value = typeahead_prompt(option_type, api_client, (option_type['noParams'] ? {} : (api_params || {}).merge(results)), options[:no_prompt], nil, paging_enabled)
273
+ value = typeahead_prompt(option_type, api_client, option_params, options[:no_prompt], nil, paging_enabled)
258
274
  if value && option_type['type'] == 'multiTypeahead'
259
275
  value = [value]
260
276
  while self.confirm("Add another #{option_type['fieldLabel']}?", {:default => false}) do
261
- if addn_value = typeahead_prompt(option_type, api_client, (option_type['noParams'] ? {} : (api_params || {}).merge(results)), options[:no_prompt], nil, paging_enabled)
277
+ if addn_value = typeahead_prompt(option_type, api_client, option_params, options[:no_prompt], nil, paging_enabled)
262
278
  value << addn_value
263
279
  else
264
280
  break
@@ -266,12 +282,17 @@ module Morpheus
266
282
  end
267
283
  end
268
284
  elsif option_type['type'] == 'hidden'
269
- value = option_type['defaultValue']
270
- input = value
285
+ if option_type['optionSource'].nil?
286
+ value = option_type['defaultValue']
287
+ else
288
+ value = load_source_options(option_type['optionSource'], option_type['optionSourceType'], api_client, api_params || {})
289
+ end
271
290
  elsif option_type['type'] == 'file'
272
291
  value = file_prompt(option_type)
273
292
  elsif option_type['type'] == 'file-content'
274
293
  value = file_content_prompt(option_type, options, api_client, {})
294
+ elsif option_type['type'] == 'multiText'
295
+ value = multitext_prompt(option_type)
275
296
  else
276
297
  value = generic_prompt(option_type)
277
298
  end
@@ -279,7 +300,11 @@ module Morpheus
279
300
 
280
301
  if option_type['type'] == 'multiSelect'
281
302
  value = [value] if !value.nil? && !value.is_a?(Array)
282
- # parent_context_map[parent_ns] = value
303
+ elsif option_type['type'] == 'multiText'
304
+ # multiText expects csv value
305
+ if value && value.is_a?(String)
306
+ value = value.split(",").collect {|it| it.strip }
307
+ end
283
308
  end
284
309
  context_map[field_name] = value if !(value.nil? || (value.is_a?(Hash) && value.empty?))
285
310
  parent_context_map.reject! {|k,v| k == parent_ns && (v.nil? || (v.is_a?(Hash) && v.empty?))}
@@ -298,7 +323,7 @@ module Morpheus
298
323
  end
299
324
  optionString = options.collect{ |b| b[:checked] ? "(#{b[:key]})" : b[:key]}.join(', ')
300
325
  while !value_found do
301
- print "#{option_type['fieldLabel']}#{option_type['fieldAddOn'] ? ('(' + option_type['fieldAddOn'] + ') ') : '' }[#{optionString}]: "
326
+ print "#{option_type['fieldLabel']}#{option_type['fieldAddOn'] ? (' (' + option_type['fieldAddOn'] + ') ') : '' }[#{optionString}]: "
302
327
  input = $stdin.gets.chomp!
303
328
  if input == '?'
304
329
  help_prompt(option_type)
@@ -325,7 +350,7 @@ module Morpheus
325
350
  value_found = false
326
351
  value = nil
327
352
  while !value_found do
328
- print "#{option_type['fieldLabel']}#{option_type['fieldAddOn'] ? ('(' + option_type['fieldAddOn'] + ') ') : '' }#{!option_type['required'] ? ' (optional)' : ''}#{!option_type['defaultValue'].to_s.empty? ? ' ['+option_type['defaultValue'].to_s+']' : ''}: "
353
+ print "#{option_type['fieldLabel']}#{option_type['fieldAddOn'] ? (' (' + option_type['fieldAddOn'] + ') ') : '' }#{!option_type['required'] ? ' (optional)' : ''}#{!option_type['defaultValue'].to_s.empty? ? ' ['+option_type['defaultValue'].to_s+']' : ''}: "
329
354
  input = $stdin.gets.chomp!
330
355
  value = input.empty? ? option_type['defaultValue'] : input
331
356
  if !value.to_s.empty?
@@ -349,7 +374,7 @@ module Morpheus
349
374
  Thread.current[:_last_select]
350
375
  end
351
376
 
352
- def self.select_prompt(option_type,api_client, api_params={}, no_prompt=false, use_value=nil, paging_enabled=false)
377
+ def self.select_prompt(option_type, api_client, api_params={}, no_prompt=false, use_value=nil, paging_enabled=false, ignore_empty=false)
353
378
  paging_enabled = false if Morpheus::Cli.windows?
354
379
  field_key = [option_type['fieldContext'], option_type['fieldName']].select {|it| it && it != '' }.join('.')
355
380
  help_field_key = option_type[:help_field_prefix] ? "#{option_type[:help_field_prefix]}.#{field_key}" : field_key
@@ -358,7 +383,12 @@ module Morpheus
358
383
  value_field = (option_type['config'] ? option_type['config']['valueField'] : nil) || 'value'
359
384
  default_value = option_type['defaultValue']
360
385
  default_value = default_value['id'] if default_value && default_value.is_a?(Hash) && !default_value['id'].nil?
361
- api_params ||= {}
386
+
387
+ if !option_type['params'].nil?
388
+ api_params = (api_params || {}).select {|k,v| option_type['params'].key?(k) || option_type['params'].key?(k.to_s)}
389
+ option_type['params'].select {|k,v| !v.empty?}.each {|k,v| api_params[k] = v}
390
+ end
391
+
362
392
  # local array of options
363
393
  if option_type['selectOptions']
364
394
  # calculate from inline lambda
@@ -380,9 +410,11 @@ module Morpheus
380
410
  select_options = load_source_options(option_type['optionSource'], option_type['optionSourceType'], api_client, api_params || {})
381
411
  end
382
412
  else
383
- raise "option '#{field_key}' is type: 'select' and missing selectOptions or optionSource!"
413
+ raise "option '#{help_field_key}' is type: 'select' and missing selectOptions or optionSource!"
384
414
  end
385
415
 
416
+ return nil if (select_options.nil? || select_options.count == 0) && ignore_empty
417
+
386
418
  # ensure the preselected value (passed as an option) is in the dropdown
387
419
  if !use_value.nil?
388
420
  matched_option = select_options.find {|opt| opt[value_field].to_s == use_value.to_s || opt['name'].to_s == use_value.to_s }
@@ -417,7 +449,8 @@ module Morpheus
417
449
  default_value = found_default_option['name'] # name is prettier than value
418
450
  end
419
451
  else
420
- found_default_option = select_options.find {|opt| opt[value_field].to_s == default_value.to_s}
452
+ found_default_option = select_options.find {|opt| opt[value_field].to_s == default_value.to_s || opt['name'] == default_value.to_s}
453
+ found_default_option = select_options.find {|opt| opt[value_field].to_s.start_with?(default_value.to_s) || opt['name'].to_s.start_with?(default_value.to_s)} if !found_default_option
421
454
  if found_default_option
422
455
  default_value = found_default_option['name'] # name is prettier than value
423
456
  end
@@ -476,7 +509,7 @@ module Morpheus
476
509
  }
477
510
 
478
511
  has_more_pages = paging && (paging[:cur_page] * paging[:page_size]) < paging[:total]
479
- input = Readline.readline("#{option_type['fieldLabel']}#{option_type['fieldAddOn'] ? ('(' + option_type['fieldAddOn'] + ') ') : '' }#{!option_type['required'] ? ' (optional)' : ''}#{!default_value.to_s.empty? ? ' ['+default_value.to_s+']' : ''} ['?' for#{has_more_pages && paging[:cur_page] > 0 ? ' more ' : ' '}options]: ", false).to_s
512
+ input = Readline.readline("#{option_type['fieldLabel']}#{option_type['fieldAddOn'] ? (' (' + option_type['fieldAddOn'] + ') ') : '' }#{!option_type['required'] ? ' (optional)' : ''}#{!default_value.to_s.empty? ? ' ['+default_value.to_s+']' : ''} ['?' for#{has_more_pages && paging[:cur_page] > 0 ? ' more ' : ' '}options]: ", false).to_s
480
513
  input = input.chomp.strip
481
514
  if input.empty? && default_value
482
515
  input = default_value.to_s
@@ -504,13 +537,19 @@ module Morpheus
504
537
  if value && !option_type['fieldInput'].nil?
505
538
  value = {option_type['fieldName'].split('.').last => value, option_type['fieldInput'] => (no_prompt ? option_type['defaultInputValue'] : field_input_prompt(option_type))}
506
539
  end
540
+
541
+ if value && !option_type['resultValueField'].nil?
542
+ value = {option_type['resultValueField'] => value}
543
+ end
507
544
  value
508
545
  end
509
546
 
510
547
  # this works like select_prompt, but refreshes options with ?query=value between inputs
511
548
  # paging_enabled is ignored right now
512
549
  def self.typeahead_prompt(option_type,api_client, api_params={}, no_prompt=false, use_value=nil, paging_enabled=false)
513
- select_options = []
550
+ paging_enabled = false if Morpheus::Cli.windows?
551
+ paging = nil
552
+ select_options = nil
514
553
  field_key = [option_type['fieldContext'], option_type['fieldName']].select {|it| it && it != '' }.join('.')
515
554
  help_field_key = option_type[:help_field_prefix] ? "#{option_type[:help_field_prefix]}.#{field_key}" : field_key
516
555
  input = ""
@@ -544,7 +583,8 @@ module Morpheus
544
583
  matches
545
584
  }
546
585
  # prompt for typeahead input value
547
- input = Readline.readline("#{option_type['fieldLabel']}#{option_type['fieldAddOn'] ? ('(' + option_type['fieldAddOn'] + ') ') : '' }#{!option_type['required'] ? ' (optional)' : ''}#{!default_value.to_s.empty? ? ' ['+default_value.to_s+']' : ''} ['?' for options]: ", false).to_s
586
+ has_more_pages = paging && ((paging[:cur_page] + 1) * paging[:page_size]) < paging[:total]
587
+ input = Readline.readline("#{option_type['fieldLabel']}#{option_type['fieldAddOn'] ? (' (' + option_type['fieldAddOn'] + ') ') : '' }#{!option_type['required'] ? ' (optional)' : ''}#{!default_value.to_s.empty? ? ' ['+default_value.to_s+']' : ''} ['?' for#{has_more_pages ? ' more ' : ' '}options]: ", false).to_s
548
588
  input = input.chomp.strip
549
589
  end
550
590
 
@@ -571,8 +611,22 @@ module Morpheus
571
611
  # looking for help with this input
572
612
  if input == '?'
573
613
  help_prompt(option_type)
574
- select_options = load_options(option_type, api_client, api_params)
575
- display_select_options(option_type, select_options) unless select_options.empty?
614
+ select_options = select_options || load_options(option_type, api_client, api_params)
615
+
616
+ if !select_options.empty?
617
+ if paging_enabled
618
+ if paging.nil?
619
+ option_count = select_options ? select_options.count : 0
620
+ page_size = Readline.get_screen_size[0] - 6
621
+ if page_size < option_count
622
+ paging = {:cur_page => 0, :page_size => page_size, :total => option_count}
623
+ end
624
+ else
625
+ paging[:cur_page] = (paging[:cur_page] + 1) * paging[:page_size] < paging[:total] ? paging[:cur_page] + 1 : 0
626
+ end
627
+ end
628
+ display_select_options(option_type, select_options, paging)
629
+ end
576
630
  next
577
631
  end
578
632
 
@@ -624,6 +678,10 @@ module Morpheus
624
678
  if select_options.empty?
625
679
  print "The value '#{input}' matched 0 options.\n"
626
680
  # print "Please try again.\n"
681
+ elsif select_options.size() == 1
682
+ print "The value '#{input}' matched 1 option.\n"
683
+ print "Perhaps you meant '#{select_options[0]['name']}' instead?"
684
+ # print "Please try again.\n"
627
685
  else
628
686
  print "The value '#{input}' matched #{select_options.size()} options.\n"
629
687
  print "Perhaps you meant one of these? #{ored_list(select_options.collect {|i|i['name']}, 3)}\n"
@@ -638,6 +696,9 @@ module Morpheus
638
696
  if select_options.empty?
639
697
  print "The value '#{input}' matched 0 options.\n"
640
698
  print "Please try again.\n"
699
+ elsif select_options.size() == 1
700
+ print "The value '#{input}' matched 1 option.\n"
701
+ print "Perhaps you meant '#{select_options[0]['name']}' instead?"
641
702
  else
642
703
  print "The value '#{input}' matched #{select_options.size()} options.\n"
643
704
  print "Perhaps you meant one of these? #{ored_list(select_options.collect {|i|i['name']}, 3)}\n"
@@ -719,7 +780,7 @@ module Morpheus
719
780
  value_found = false
720
781
  value = nil
721
782
  while !value_found do
722
- print "#{option_type['fieldLabel']}#{option_type['fieldAddOn'] ? ('(' + option_type['fieldAddOn'] + ') ') : '' }#{!option_type['required'] ? ' (optional)' : ''}#{!option_type['defaultValue'].to_s.empty? ? ' ['+option_type['defaultValue'].to_s+']' : ''}: "
783
+ print "#{option_type['fieldLabel']}#{option_type['fieldAddOn'] ? (' (' + option_type['fieldAddOn'] + ') ') : '' }#{!option_type['required'] ? ' (optional)' : ''}#{!option_type['defaultValue'].to_s.empty? ? ' ['+option_type['defaultValue'].to_s+']' : ''}: "
723
784
  input = $stdin.gets.chomp!
724
785
  value = input.empty? ? option_type['defaultValue'] : input
725
786
  if input == '?'
@@ -736,7 +797,7 @@ module Morpheus
736
797
  value = nil
737
798
  while !value_found do
738
799
  if value.nil?
739
- print "#{option_type['fieldLabel']}#{option_type['fieldAddOn'] ? ('(' + option_type['fieldAddOn'] + ') ') : '' }#{optional_label(option_type)} [Type 'EOF' to stop input]: \n"
800
+ print "#{option_type['fieldLabel']}#{option_type['fieldAddOn'] ? (' (' + option_type['fieldAddOn'] + ') ') : '' }#{optional_label(option_type)} [Type 'EOF' to stop input]: \n"
740
801
  end
741
802
  input = $stdin.gets.chomp!
742
803
  # value = input.empty? ? option_type['defaultValue'] : input
@@ -760,7 +821,7 @@ module Morpheus
760
821
  def self.password_prompt(option_type)
761
822
  value_found = false
762
823
  while !value_found do
763
- print "#{option_type['fieldLabel']}#{option_type['fieldAddOn'] ? ('(' + option_type['fieldAddOn'] + ') ') : '' }#{optional_label(option_type)}#{option_type['defaultValue'] ? ' ['+option_type['defaultValue'].to_s+']' : ''}: "
824
+ print "#{option_type['fieldLabel']}#{option_type['fieldAddOn'] ? (' (' + option_type['fieldAddOn'] + ') ') : '' }#{optional_label(option_type)}#{option_type['defaultValue'] ? ' ['+option_type['defaultValue'].to_s+']' : ''}: "
764
825
  input = $stdin.noecho(&:gets).chomp!
765
826
  value = input
766
827
  print "\n"
@@ -780,11 +841,11 @@ module Morpheus
780
841
  value_found = false
781
842
  value = nil
782
843
  while !value_found do
783
- #print "#{option_type['fieldLabel']}#{option_type['fieldAddOn'] ? ('(' + option_type['fieldAddOn'] + ') ') : '' }#{optional_label(option_type)}#{option_type['defaultValue'] ? ' ['+option_type['defaultValue'].to_s+']' : ''}: "
844
+ #print "#{option_type['fieldLabel']}#{option_type['fieldAddOn'] ? (' (' + option_type['fieldAddOn'] + ') ') : '' }#{optional_label(option_type)}#{option_type['defaultValue'] ? ' ['+option_type['defaultValue'].to_s+']' : ''}: "
784
845
  Readline.completion_append_character = ""
785
846
  Readline.basic_word_break_characters = ''
786
847
  Readline.completion_proc = proc {|s| Readline::FILENAME_COMPLETION_PROC.call(s) }
787
- input = Readline.readline("#{option_type['fieldLabel']}#{option_type['fieldAddOn'] ? ('(' + option_type['fieldAddOn'] + ') ') : '' }#{optional_label(option_type)}#{option_type['defaultValue'] ? ' ['+option_type['defaultValue'].to_s+']' : ''}: ", false).to_s
848
+ input = Readline.readline("#{option_type['fieldLabel']}#{option_type['fieldAddOn'] ? (' (' + option_type['fieldAddOn'] + ') ') : '' }#{optional_label(option_type)}#{option_type['defaultValue'] ? ' ['+option_type['defaultValue'].to_s+']' : ''}: ", false).to_s
788
849
  input = input.chomp.strip
789
850
  #input = $stdin.gets.chomp!
790
851
  value = input.empty? ? option_type['defaultValue'] : input.to_s
@@ -883,7 +944,35 @@ module Morpheus
883
944
  return file_params
884
945
  end
885
946
 
947
+ def self.multitext_prompt(option_type)
948
+ rtn = nil
949
+
950
+ # supports multi-part fields via config.fields
951
+ # {"fields": [{"name":"tag", "required":true, "label": "Tag"}, {"name":"value", "required":false, "label": "Scope"}]}
952
+ if option_type['config']['fields']
953
+ while (option_type['required'] && rtn.empty?) || self.confirm("Add#{rtn.empty? ? '': ' more'} #{option_type['fieldLabel']}?", {:default => false})
954
+ rtn ||= []
955
+ value = {}
956
+ option_type['config']['fields'].each do |field|
957
+ field_label = field['label'] || field['name'].capitalize
958
+ value[field['name']] = generic_prompt(option_type.merge({'fieldLabel' => field_label, 'required' => field['required'], 'description' => "#{option_type['fieldLabel']} #{field_label}"}))
959
+ end
960
+ rtn << value
961
+ end
962
+ else
963
+ if rtn = generic_prompt(option_type)
964
+ rtn = [rtn]
965
+ while self.confirm("Add more #{option_type['fieldLabel']}?", {:default => false}) do
966
+ rtn << generic_prompt(option_type)
967
+ end
968
+ end
969
+ end
970
+ rtn
971
+ end
972
+
886
973
  def self.load_options(option_type, api_client, api_params, query_value=nil)
974
+ field_key = [option_type['fieldContext'], option_type['fieldName']].select {|it| it && it != '' }.join('.')
975
+ help_field_key = option_type[:help_field_prefix] ? "#{option_type[:help_field_prefix]}.#{field_key}" : field_key
887
976
  select_options = []
888
977
  # local array of options
889
978
  if option_type['selectOptions']
@@ -902,6 +991,8 @@ module Morpheus
902
991
  select_options = filtered_options
903
992
  end
904
993
  elsif option_type['optionSource']
994
+ api_params = api_params.select {|k,v| option_type['params'].include(k)} if !option_type['params'].nil? && api_params
995
+
905
996
  # calculate from inline lambda
906
997
  if option_type['optionSource'].is_a?(Proc)
907
998
  select_options = option_type['optionSource'].call(api_client, api_params || {})
@@ -913,7 +1004,7 @@ module Morpheus
913
1004
  select_options = load_source_options(option_type['optionSource'], option_type['optionSourceType'], api_client, api_params || {})
914
1005
  end
915
1006
  else
916
- raise "option '#{field_key}' is type: 'typeahead' and missing selectOptions or optionSource!"
1007
+ raise "option '#{help_field_key}' is type: 'typeahead' and missing selectOptions or optionSource!"
917
1008
  end
918
1009
 
919
1010
  return select_options
@@ -960,21 +1051,29 @@ module Morpheus
960
1051
  return out
961
1052
  end
962
1053
 
1054
+ def self.sorted_option_types(option_types)
1055
+ option_types.reject {|it| (it['fieldGroup'] || 'default') != 'default'}.sort {|a,b| a['displayOrder'].to_i <=> b['displayOrder'].to_i} +
1056
+ option_types.reject {|it| ['default', 'advanced'].include?(it['fieldGroup'] || 'default')}.sort{|a,b| a['displayOrder'] <=> b['displayOrder']}.group_by{|it| it['fieldGroup']}.values.collect { |it| it.sort{|a,b| a['displayOrder'].to_i <=> b['displayOrder'].to_i}}.flatten +
1057
+ option_types.reject {|it| it['fieldGroup'] != 'advanced'}.sort {|a,b| a['displayOrder'].to_i <=> b['displayOrder'].to_i}
1058
+ end
1059
+
963
1060
  def self.display_select_options(opt, select_options = [], paging = nil)
964
- puts format_select_options_help(opt, select_options, paging)
1061
+ puts self.format_select_options_help(opt, select_options, paging)
965
1062
  end
966
1063
 
967
1064
  def self.format_option_types_help(option_types, opts={})
1065
+ option_types = self.sorted_option_types(option_types).reject {|it| it['hidden']}
1066
+
968
1067
  if option_types.empty?
969
1068
  "#{opts[:color]}#{opts[:title] || "Available Options:"}\nNone\n\n"
970
1069
  else
971
1070
  if opts[:include_context]
972
- option_lines = option_types.sort {|it| it['displayOrder']}.collect {|it|
1071
+ option_lines = option_types.collect {|it|
973
1072
  field_context = (opts[:context_map] || {})[it['fieldContext']] || it['fieldContext']
974
1073
  " -O #{field_context && field_context != '' ? "#{field_context}." : ''}#{it['fieldName']}=\"value\""
975
1074
  }
976
1075
  else
977
- option_lines = option_types.sort {|it| it['displayOrder']}.collect {|it| " -O #{it['fieldName']}=\"value\"" }
1076
+ option_lines = option_types.collect {|it| " -O #{it['fieldName']}=\"value\"" }
978
1077
  end
979
1078
  "#{opts[:color]}#{opts[:title] || "Available Options:"}\n#{option_lines.join("\n")}\n\n"
980
1079
  end
@@ -1000,11 +1099,16 @@ module Morpheus
1000
1099
 
1001
1100
  if tokens.length > 1
1002
1101
  tokens.slice(0, tokens.length - 1).each do |token|
1003
- context = context[name = token]
1102
+ context = context[token]
1004
1103
  end
1104
+ name = tokens.last
1005
1105
  end
1006
1106
 
1007
- rtn = context[name]
1107
+ if context.kind_of?(Array)
1108
+ rtn = context.collect {|it| it['name'] || it[name]}.join ', '
1109
+ else
1110
+ rtn = context[name]
1111
+ end
1008
1112
 
1009
1113
  if format
1010
1114
  rtn = (rtn ? 'On' : 'Off') if option_type['type'] == 'checkbox'
@@ -1,6 +1,6 @@
1
1
 
2
2
  module Morpheus
3
3
  module Cli
4
- VERSION = "5.3.4"
4
+ VERSION = "5.4.3"
5
5
  end
6
6
  end