morpheus-cli 5.3.0.3 → 5.3.2.1

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 (199) hide show
  1. checksums.yaml +4 -4
  2. data/Dockerfile +1 -1
  3. data/README.md +1 -3
  4. data/lib/morpheus/api/account_groups_interface.rb +0 -6
  5. data/lib/morpheus/api/accounts_interface.rb +4 -36
  6. data/lib/morpheus/api/api_client.rb +167 -119
  7. data/lib/morpheus/api/appliance_settings_interface.rb +6 -9
  8. data/lib/morpheus/api/approvals_interface.rb +5 -8
  9. data/lib/morpheus/api/apps_interface.rb +0 -7
  10. data/lib/morpheus/api/archive_buckets_interface.rb +9 -16
  11. data/lib/morpheus/api/archive_files_interface.rb +0 -6
  12. data/lib/morpheus/api/auth_interface.rb +4 -4
  13. data/lib/morpheus/api/backup_settings_interface.rb +5 -8
  14. data/lib/morpheus/api/blueprints_interface.rb +1 -7
  15. data/lib/morpheus/api/budgets_interface.rb +0 -6
  16. data/lib/morpheus/api/certificate_types_interface.rb +14 -0
  17. data/lib/morpheus/api/certificates_interface.rb +9 -0
  18. data/lib/morpheus/api/cloud_datastores_interface.rb +0 -6
  19. data/lib/morpheus/api/cloud_folders_interface.rb +1 -7
  20. data/lib/morpheus/api/cloud_policies_interface.rb +0 -6
  21. data/lib/morpheus/api/cloud_resource_pools_interface.rb +0 -6
  22. data/lib/morpheus/api/clouds_interface.rb +0 -6
  23. data/lib/morpheus/api/clusters_interface.rb +39 -42
  24. data/lib/morpheus/api/containers_interface.rb +0 -6
  25. data/lib/morpheus/api/custom_instance_types_interface.rb +0 -6
  26. data/lib/morpheus/api/cypher_interface.rb +0 -6
  27. data/lib/morpheus/api/datastores_interface.rb +4 -7
  28. data/lib/morpheus/api/deploy_interface.rb +1 -6
  29. data/lib/morpheus/api/environments_interface.rb +0 -6
  30. data/lib/morpheus/api/execute_schedules_interface.rb +0 -6
  31. data/lib/morpheus/api/execution_request_interface.rb +0 -6
  32. data/lib/morpheus/api/file_copy_request_interface.rb +2 -9
  33. data/lib/morpheus/api/group_policies_interface.rb +0 -6
  34. data/lib/morpheus/api/groups_interface.rb +0 -7
  35. data/lib/morpheus/api/guidance_interface.rb +9 -12
  36. data/lib/morpheus/api/health_interface.rb +0 -6
  37. data/lib/morpheus/api/image_builder_boot_scripts_interface.rb +0 -6
  38. data/lib/morpheus/api/image_builder_image_builds_interface.rb +0 -6
  39. data/lib/morpheus/api/image_builder_interface.rb +3 -9
  40. data/lib/morpheus/api/image_builder_preseed_scripts_interface.rb +0 -6
  41. data/lib/morpheus/api/instance_types_interface.rb +0 -7
  42. data/lib/morpheus/api/instances_interface.rb +8 -19
  43. data/lib/morpheus/api/integration_types_interface.rb +14 -0
  44. data/lib/morpheus/api/integrations_interface.rb +36 -21
  45. data/lib/morpheus/api/invoice_line_items_interface.rb +4 -9
  46. data/lib/morpheus/api/jobs_interface.rb +11 -14
  47. data/lib/morpheus/api/key_pairs_interface.rb +0 -6
  48. data/lib/morpheus/api/library_cluster_layouts_interface.rb +0 -6
  49. data/lib/morpheus/api/library_container_scripts_interface.rb +0 -6
  50. data/lib/morpheus/api/library_container_templates_interface.rb +0 -6
  51. data/lib/morpheus/api/library_container_types_interface.rb +0 -6
  52. data/lib/morpheus/api/library_container_upgrades_interface.rb +0 -6
  53. data/lib/morpheus/api/library_instance_types_interface.rb +0 -6
  54. data/lib/morpheus/api/library_layouts_interface.rb +0 -6
  55. data/lib/morpheus/api/library_spec_template_types_interface.rb +0 -6
  56. data/lib/morpheus/api/library_spec_templates_interface.rb +0 -6
  57. data/lib/morpheus/api/license_interface.rb +0 -6
  58. data/lib/morpheus/api/load_balancer_pools_interface.rb +9 -0
  59. data/lib/morpheus/api/load_balancer_types_interface.rb +9 -0
  60. data/lib/morpheus/api/load_balancer_virtual_servers_interface.rb +9 -0
  61. data/lib/morpheus/api/load_balancers_interface.rb +4 -59
  62. data/lib/morpheus/api/log_settings_interface.rb +9 -12
  63. data/lib/morpheus/api/logs_interface.rb +0 -6
  64. data/lib/morpheus/api/monitoring_alerts_interface.rb +0 -6
  65. data/lib/morpheus/api/monitoring_apps_interface.rb +0 -6
  66. data/lib/morpheus/api/monitoring_checks_interface.rb +0 -6
  67. data/lib/morpheus/api/monitoring_contacts_interface.rb +0 -6
  68. data/lib/morpheus/api/monitoring_groups_interface.rb +0 -6
  69. data/lib/morpheus/api/monitoring_incidents_interface.rb +0 -6
  70. data/lib/morpheus/api/monitoring_interface.rb +6 -12
  71. data/lib/morpheus/api/network_domain_records_interface.rb +0 -6
  72. data/lib/morpheus/api/network_domains_interface.rb +0 -6
  73. data/lib/morpheus/api/network_groups_interface.rb +0 -6
  74. data/lib/morpheus/api/network_pool_ips_interface.rb +0 -6
  75. data/lib/morpheus/api/network_pool_servers_interface.rb +0 -6
  76. data/lib/morpheus/api/network_pools_interface.rb +0 -6
  77. data/lib/morpheus/api/network_proxies_interface.rb +0 -6
  78. data/lib/morpheus/api/network_routers_interface.rb +56 -6
  79. data/lib/morpheus/api/network_security_servers_interface.rb +6 -9
  80. data/lib/morpheus/api/network_services_interface.rb +14 -14
  81. data/lib/morpheus/api/network_subnets_interface.rb +0 -6
  82. data/lib/morpheus/api/network_types_interface.rb +1 -7
  83. data/lib/morpheus/api/networks_interface.rb +0 -6
  84. data/lib/morpheus/api/option_type_lists_interface.rb +18 -12
  85. data/lib/morpheus/api/option_types_interface.rb +0 -6
  86. data/lib/morpheus/api/options_interface.rb +0 -6
  87. data/lib/morpheus/api/packages_interface.rb +0 -6
  88. data/lib/morpheus/api/policies_interface.rb +1 -8
  89. data/lib/morpheus/api/power_schedules_interface.rb +0 -6
  90. data/lib/morpheus/api/price_sets_interface.rb +8 -11
  91. data/lib/morpheus/api/prices_interface.rb +12 -15
  92. data/lib/morpheus/api/processes_interface.rb +0 -6
  93. data/lib/morpheus/api/provision_types_interface.rb +0 -6
  94. data/lib/morpheus/api/provisioning_license_types_interface.rb +0 -6
  95. data/lib/morpheus/api/provisioning_licenses_interface.rb +0 -6
  96. data/lib/morpheus/api/provisioning_settings_interface.rb +6 -9
  97. data/lib/morpheus/api/read_interface.rb +23 -0
  98. data/lib/morpheus/api/reports_interface.rb +0 -6
  99. data/lib/morpheus/api/rest_interface.rb +12 -10
  100. data/lib/morpheus/api/roles_interface.rb +7 -6
  101. data/lib/morpheus/api/secondary_read_interface.rb +25 -0
  102. data/lib/morpheus/api/secondary_rest_interface.rb +42 -0
  103. data/lib/morpheus/api/security_group_rules_interface.rb +0 -7
  104. data/lib/morpheus/api/security_groups_interface.rb +0 -6
  105. data/lib/morpheus/api/server_types_interface.rb +0 -6
  106. data/lib/morpheus/api/servers_interface.rb +7 -6
  107. data/lib/morpheus/api/service_plans_interface.rb +11 -14
  108. data/lib/morpheus/api/storage_providers_interface.rb +9 -16
  109. data/lib/morpheus/api/subnet_types_interface.rb +1 -7
  110. data/lib/morpheus/api/subnets_interface.rb +0 -6
  111. data/lib/morpheus/api/task_sets_interface.rb +0 -6
  112. data/lib/morpheus/api/tasks_interface.rb +0 -6
  113. data/lib/morpheus/api/user_groups_interface.rb +0 -6
  114. data/lib/morpheus/api/user_settings_interface.rb +38 -18
  115. data/lib/morpheus/api/user_sources_interface.rb +0 -6
  116. data/lib/morpheus/api/users_interface.rb +0 -6
  117. data/lib/morpheus/api/vdi_allocations_interface.rb +9 -0
  118. data/lib/morpheus/api/vdi_apps_interface.rb +9 -0
  119. data/lib/morpheus/api/vdi_gateways_interface.rb +9 -0
  120. data/lib/morpheus/api/vdi_interface.rb +28 -0
  121. data/lib/morpheus/api/vdi_pools_interface.rb +19 -0
  122. data/lib/morpheus/api/virtual_images_interface.rb +0 -6
  123. data/lib/morpheus/api/whitelabel_settings_interface.rb +8 -11
  124. data/lib/morpheus/api/wiki_interface.rb +0 -6
  125. data/lib/morpheus/cli.rb +10 -2
  126. data/lib/morpheus/cli/access_token_command.rb +1 -1
  127. data/lib/morpheus/cli/account_groups_command.rb +4 -4
  128. data/lib/morpheus/cli/apps.rb +68 -84
  129. data/lib/morpheus/cli/archives_command.rb +5 -5
  130. data/lib/morpheus/cli/blueprints_command.rb +5 -5
  131. data/lib/morpheus/cli/boot_scripts_command.rb +1 -1
  132. data/lib/morpheus/cli/catalog_item_types_command.rb +13 -13
  133. data/lib/morpheus/cli/certificates_command.rb +575 -0
  134. data/lib/morpheus/cli/change_password_command.rb +4 -4
  135. data/lib/morpheus/cli/cli_command.rb +72 -16
  136. data/lib/morpheus/cli/clouds.rb +3 -2
  137. data/lib/morpheus/cli/clusters.rb +3 -3
  138. data/lib/morpheus/cli/commands/standard/man_command.rb +4 -5
  139. data/lib/morpheus/cli/credentials.rb +4 -11
  140. data/lib/morpheus/cli/environments_command.rb +1 -1
  141. data/lib/morpheus/cli/execute_schedules_command.rb +3 -3
  142. data/lib/morpheus/cli/hosts.rb +253 -232
  143. data/lib/morpheus/cli/image_builder_command.rb +6 -6
  144. data/lib/morpheus/cli/instance_types.rb +1 -1
  145. data/lib/morpheus/cli/instances.rb +229 -219
  146. data/lib/morpheus/cli/integrations_command.rb +1155 -42
  147. data/lib/morpheus/cli/invoices_command.rb +75 -67
  148. data/lib/morpheus/cli/key_pairs.rb +2 -2
  149. data/lib/morpheus/cli/library_cluster_layouts_command.rb +2 -3
  150. data/lib/morpheus/cli/library_container_scripts_command.rb +4 -5
  151. data/lib/morpheus/cli/library_container_templates_command.rb +5 -1
  152. data/lib/morpheus/cli/library_container_types_command.rb +8 -9
  153. data/lib/morpheus/cli/library_instance_types_command.rb +6 -7
  154. data/lib/morpheus/cli/library_layouts_command.rb +9 -5
  155. data/lib/morpheus/cli/library_option_lists_command.rb +72 -20
  156. data/lib/morpheus/cli/library_option_types_command.rb +8 -4
  157. data/lib/morpheus/cli/library_spec_templates_command.rb +3 -4
  158. data/lib/morpheus/cli/library_upgrades_command.rb +6 -6
  159. data/lib/morpheus/cli/license.rb +2 -2
  160. data/lib/morpheus/cli/load_balancer_types.rb +37 -0
  161. data/lib/morpheus/cli/load_balancers.rb +149 -314
  162. data/lib/morpheus/cli/log_settings_command.rb +7 -3
  163. data/lib/morpheus/cli/login.rb +10 -1
  164. data/lib/morpheus/cli/mixins/load_balancers_helper.rb +156 -0
  165. data/lib/morpheus/cli/mixins/print_helper.rb +44 -18
  166. data/lib/morpheus/cli/mixins/provisioning_helper.rb +4 -4
  167. data/lib/morpheus/cli/mixins/rest_command.rb +657 -0
  168. data/lib/morpheus/cli/mixins/vdi_helper.rb +246 -0
  169. data/lib/morpheus/cli/network_routers_command.rb +1187 -176
  170. data/lib/morpheus/cli/networks_command.rb +195 -102
  171. data/lib/morpheus/cli/option_types.rb +66 -71
  172. data/lib/morpheus/cli/policies_command.rb +0 -1
  173. data/lib/morpheus/cli/power_schedules_command.rb +3 -3
  174. data/lib/morpheus/cli/preseed_scripts_command.rb +1 -1
  175. data/lib/morpheus/cli/remote.rb +2 -2
  176. data/lib/morpheus/cli/reports_command.rb +4 -1
  177. data/lib/morpheus/cli/roles.rb +224 -64
  178. data/lib/morpheus/cli/security_group_rules.rb +1 -1
  179. data/lib/morpheus/cli/setup.rb +0 -1
  180. data/lib/morpheus/cli/subnets_command.rb +11 -2
  181. data/lib/morpheus/cli/tenants_command.rb +21 -23
  182. data/lib/morpheus/cli/user_groups_command.rb +3 -3
  183. data/lib/morpheus/cli/user_settings_command.rb +268 -57
  184. data/lib/morpheus/cli/user_sources_command.rb +3 -3
  185. data/lib/morpheus/cli/users.rb +3 -3
  186. data/lib/morpheus/cli/vdi_allocations_command.rb +159 -0
  187. data/lib/morpheus/cli/vdi_apps_command.rb +317 -0
  188. data/lib/morpheus/cli/vdi_command.rb +359 -0
  189. data/lib/morpheus/cli/vdi_gateways_command.rb +290 -0
  190. data/lib/morpheus/cli/vdi_pools_command.rb +571 -0
  191. data/lib/morpheus/cli/version.rb +1 -1
  192. data/lib/morpheus/cli/virtual_images.rb +1 -1
  193. data/lib/morpheus/cli/whoami.rb +0 -15
  194. data/lib/morpheus/cli/wiki_command.rb +1 -1
  195. data/lib/morpheus/ext/string.rb +41 -0
  196. data/lib/morpheus/formatters.rb +4 -0
  197. data/lib/morpheus/rest_client.rb +30 -0
  198. data/lib/morpheus/terminal.rb +15 -7
  199. metadata +27 -2
@@ -46,15 +46,29 @@ module Morpheus
46
46
  if options[:help_field_prefix]
47
47
  option_type[:help_field_prefix] = options[:help_field_prefix]
48
48
  end
49
+ # a lot of optionTypes have fieldGroup:'Options' instead of 'default'
50
+ if option_type['fieldGroup'].to_s.downcase == 'options'
51
+ option_type['fieldGroup'] = 'default'
52
+ end
49
53
  end
50
54
  # puts "Options Prompt #{options}"
51
- # only sort if displayOrder is set
52
- sorted_option_types = (option_types[0] && option_types[0]['displayOrder']) ? option_types.sort { |x,y| x['displayOrder'].to_i <=> y['displayOrder'].to_i } : option_types
53
- sorted_option_types.each do |option_type|
55
+ # Sort options by default, group, advanced
56
+ 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|
54
62
  context_map = results
55
63
  value = nil
56
64
  value_found=false
57
65
 
66
+ if cur_field_group != (option_type['fieldGroup'] || 'default')
67
+ cur_field_group = option_type['fieldGroup']
68
+ cur_field_group = cur_field_group.to_s.sub(/options\Z/i, "").strip # avoid "ADVANCED OPTION OPTIONS"
69
+ print "\n#{cur_field_group.upcase} OPTIONS\n#{"=" * ("#{cur_field_group} OPTIONS".length)}\n\n"
70
+ end
71
+
58
72
  # How about this instead?
59
73
  # option_type = option_type.clone
60
74
  # field_key = [option_type['fieldContext'], option_type['fieldName']].select {|it| it && it != '' }.join('.')
@@ -78,46 +92,39 @@ module Morpheus
78
92
  if !option_type['visibleOnCode'].to_s.empty?
79
93
  visible_option_check_value = option_type['visibleOnCode']
80
94
  end
95
+
81
96
  if !visible_option_check_value.to_s.empty?
82
- # support formats code=value or code:value OR code:(value|value2|value3)
83
- # OR fieldContext.fieldName=value
84
- parts = visible_option_check_value.include?("=") ? visible_option_check_value.split("=") : visible_option_check_value.split(":")
85
- depends_on_code = parts[0]
86
- depends_on_value = parts[1].to_s.strip
87
- depends_on_values = []
88
- if depends_on_value.size > 0
89
- # strip parenthesis
90
- if depends_on_value[0] && depends_on_value[0].chr == "("
91
- depends_on_value = depends_on_value[1..-1]
92
- end
93
- depends_on_value.chomp(")")
94
- depends_on_values = depends_on_value.split("|").collect { |it| it.strip }
95
- end
96
- depends_on_option_type = option_types.find {|it| it["code"] == depends_on_code }
97
- if !depends_on_option_type
98
- depends_on_option_type = option_types.find {|it|
99
- (it['fieldContext'] ? "#{it['fieldContext']}.#{it['fieldName']}" : it['fieldName']) == depends_on_code
100
- }
97
+ match_type = 'any'
98
+
99
+ if visible_option_check_value.include?('::')
100
+ match_type = 'all' if visible_option_check_value.start_with?('matchAll')
101
+ visible_option_check_value = visible_option_check_value[visible_option_check_value.index('::') + 2..-1]
101
102
  end
102
- if depends_on_option_type
103
- # dependent option type has a different value
104
- depends_on_field_key = depends_on_option_type['fieldContext'] ? "#{depends_on_option_type['fieldContext']}.#{depends_on_option_type['fieldName']}" : "#{depends_on_option_type['fieldName']}"
105
- found_dep_value = get_object_value(results, depends_on_field_key) || get_object_value(options, depends_on_field_key)
106
- if depends_on_values.size > 0
107
- # must be in the specified values
108
- # todo: uhh this actually needs to change to parse regex
109
- if !depends_on_values.include?(found_dep_value)
110
- next
111
- end
112
- else
113
- # no value found
114
- if found_dep_value.to_s.empty?
115
- next
103
+
104
+ found_dep_value = match_type == 'all' ? true : false
105
+ visible_option_check_value.split(',').each do |value|
106
+ parts = value.split(':')
107
+ depends_on_code = parts[0]
108
+ depends_on_value = parts.count > 1 ? parts[1].to_s.strip : '.'
109
+ depends_on_option_type = option_types.find {|it| it["code"] == depends_on_code }
110
+ if !depends_on_option_type
111
+ depends_on_option_type = option_types.find {|it|
112
+ (it['fieldContext'] ? "#{it['fieldContext']}.#{it['fieldName']}" : it['fieldName']) == depends_on_code
113
+ }
114
+ end
115
+
116
+ if depends_on_option_type
117
+ depends_on_field_key = depends_on_option_type['fieldContext'].nil? || depends_on_option_type['fieldContext'].empty? ? "#{depends_on_option_type['fieldName']}" : "#{depends_on_option_type['fieldContext']}.#{depends_on_option_type['fieldName']}"
118
+ field_value = get_object_value(results, depends_on_field_key) || get_object_value(options, depends_on_field_key)
119
+
120
+ if !field_value.nil? && field_value.match?(depends_on_value)
121
+ found_dep_value = true if match_type != 'all'
122
+ else
123
+ found_dep_value = false if match_type == 'all'
116
124
  end
117
125
  end
118
- else
119
- # could not find the dependent option type, proceed and prompt
120
126
  end
127
+ next if !found_dep_value
121
128
  end
122
129
 
123
130
  cur_namespace = options
@@ -139,7 +146,9 @@ module Morpheus
139
146
  value = cur_namespace[field_name]
140
147
  input_value = ['select', 'multiSelect','typeahead', 'multiTypeahead'].include?(option_type['type']) && option_type['fieldInput'] ? cur_namespace[option_type['fieldInput']] : nil
141
148
  if option_type['type'] == 'number'
142
- value = value.to_s.include?('.') ? value.to_f : value.to_i
149
+ if !value.to_s.empty?
150
+ value = value.to_s.include?('.') ? value.to_f : value.to_i
151
+ end
143
152
  # these select prompts should just fall down through below, with the extra params no_prompt, use_value
144
153
  elsif option_type['type'] == 'select'
145
154
  value = select_prompt(option_type.merge({'defaultValue' => value, 'defaultInputValue' => input_value}), api_client, (option_type['noParams'] ? {} : (api_params || {}).merge(results)), true)
@@ -265,30 +274,13 @@ module Morpheus
265
274
 
266
275
  if option_type['type'] == 'multiSelect'
267
276
  value = [value] if !value.nil? && !value.is_a?(Array)
268
- parent_context_map[parent_ns] = value
269
- else
270
- context_map[field_name] = value
277
+ # parent_context_map[parent_ns] = value
271
278
  end
279
+ context_map[field_name] = value
272
280
  end
273
281
  results
274
282
  end
275
283
 
276
- def self.grails_params(data, context=nil)
277
- params = {}
278
- data.each do |k,v|
279
- if v.is_a?(Hash)
280
- params.merge!(grails_params(v, context ? "#{context}.#{k.to_s}" : k))
281
- else
282
- if context
283
- params["#{context}.#{k.to_s}"] = v
284
- else
285
- params[k.to_s] = v
286
- end
287
- end
288
- end
289
- return params
290
- end
291
-
292
284
  def self.radio_prompt(option_type)
293
285
  value_found = false
294
286
  value = nil
@@ -330,7 +322,9 @@ module Morpheus
330
322
  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+']' : ''}: "
331
323
  input = $stdin.gets.chomp!
332
324
  value = input.empty? ? option_type['defaultValue'] : input
333
- value = value.to_s.include?('.') ? value.to_f : value.to_i
325
+ if !value.to_s.empty?
326
+ value = value.to_s.include?('.') ? value.to_f : value.to_i
327
+ end
334
328
  if input == '?'
335
329
  help_prompt(option_type)
336
330
  elsif !value.nil? || option_type['required'] != true
@@ -363,7 +357,7 @@ module Morpheus
363
357
  if option_type['selectOptions']
364
358
  # calculate from inline lambda
365
359
  if option_type['selectOptions'].is_a?(Proc)
366
- select_options = option_type['selectOptions'].call(api_client, grails_params(api_params || {}))
360
+ select_options = option_type['selectOptions'].call(api_client, api_params || {})
367
361
  else
368
362
  # todo: better type validation
369
363
  select_options = option_type['selectOptions']
@@ -371,13 +365,13 @@ module Morpheus
371
365
  elsif option_type['optionSource']
372
366
  # calculate from inline lambda
373
367
  if option_type['optionSource'].is_a?(Proc)
374
- select_options = option_type['optionSource'].call(api_client, grails_params(api_params || {}))
368
+ select_options = option_type['optionSource'].call(api_client, api_params || {})
375
369
  elsif option_type['optionSource'] == 'list'
376
370
  # /api/options/list is a special action for custom OptionTypeLists, just need to pass the optionTypeId parameter
377
- select_options = load_source_options(option_type['optionSource'], api_client, grails_params(api_params || {}).merge({'optionTypeId' => option_type['id']}))
371
+ select_options = load_source_options(option_type['optionSource'], option_type['optionSourceType'], api_client, api_params || {}.merge({'optionTypeId' => option_type['id']}))
378
372
  else
379
373
  # remote optionSource aka /api/options/$optionSource?
380
- select_options = load_source_options(option_type['optionSource'], api_client, grails_params(api_params || {}))
374
+ select_options = load_source_options(option_type['optionSource'], option_type['optionSourceType'], api_client, api_params || {})
381
375
  end
382
376
  else
383
377
  raise "option '#{field_key}' is type: 'select' and missing selectOptions or optionSource!"
@@ -571,6 +565,7 @@ module Morpheus
571
565
  # looking for help with this input
572
566
  if input == '?'
573
567
  help_prompt(option_type)
568
+ select_options = load_options(option_type, api_client, api_params)
574
569
  display_select_options(option_type, select_options) unless select_options.empty?
575
570
  next
576
571
  end
@@ -597,7 +592,7 @@ module Morpheus
597
592
  # actually that is redundant, it should already be filtered to matches
598
593
  # and can just do this:
599
594
  # select_option = select_options.size == 1 ? select_options[0] : nil
600
- select_option = select_options.find{|b| (b[value_field] && (b[value_field].to_s == input.to_s)) || ((b[value_field].nil? || b[value_field].empty?) && (input == "")) }
595
+ select_option = select_options.find{|b| (b[value_field] && (b[value_field].to_s == input.to_s)) || ((b[value_field].nil? || b[value_field] == "") && (input == "")) }
601
596
  if select_option.nil?
602
597
  select_option = select_options.find{|b| b['name'] && b['name'] == input }
603
598
  end
@@ -888,7 +883,7 @@ module Morpheus
888
883
  if option_type['selectOptions']
889
884
  # calculate from inline lambda
890
885
  if option_type['selectOptions'].is_a?(Proc)
891
- select_options = option_type['selectOptions'].call(api_client, grails_params(api_params || {}))
886
+ select_options = option_type['selectOptions'].call(api_client, api_params || {})
892
887
  else
893
888
  select_options = option_type['selectOptions']
894
889
  end
@@ -903,13 +898,13 @@ module Morpheus
903
898
  elsif option_type['optionSource']
904
899
  # calculate from inline lambda
905
900
  if option_type['optionSource'].is_a?(Proc)
906
- select_options = option_type['optionSource'].call(api_client, grails_params(api_params || {}))
901
+ select_options = option_type['optionSource'].call(api_client, api_params || {})
907
902
  elsif option_type['optionSource'] == 'list'
908
903
  # /api/options/list is a special action for custom OptionTypeLists, just need to pass the optionTypeId parameter
909
- select_options = load_source_options(option_type['optionSource'], api_client, grails_params(api_params || {}).merge({'optionTypeId' => option_type['id']}))
904
+ select_options = load_source_options(option_type['optionSource'], option_type['optionSourceType'], api_client, api_params || {}.merge({'optionTypeId' => option_type['id']}))
910
905
  else
911
906
  # remote optionSource aka /api/options/$optionSource?
912
- select_options = load_source_options(option_type['optionSource'], api_client, grails_params(api_params || {}))
907
+ select_options = load_source_options(option_type['optionSource'], option_type['optionSourceType'], api_client, api_params || {})
913
908
  end
914
909
  else
915
910
  raise "option '#{field_key}' is type: 'typeahead' and missing selectOptions or optionSource!"
@@ -935,8 +930,8 @@ module Morpheus
935
930
  end
936
931
 
937
932
 
938
- def self.load_source_options(source,api_client,params)
939
- api_client.options.options_for_source(source,params)['data']
933
+ def self.load_source_options(source,sourceType,api_client,params)
934
+ api_client.options.options_for_source("#{sourceType ? "#{sourceType}/" : ''}#{source}",params)['data']
940
935
  end
941
936
 
942
937
  def self.format_select_options_help(opt, select_options = [], paging = nil)
@@ -951,7 +946,7 @@ module Morpheus
951
946
  out = ""
952
947
  out << "\n"
953
948
  out << "#{header}\n"
954
- out << "===============\n"
949
+ out << "#{'=' * header.length}\n"
955
950
  select_options.each do |option|
956
951
  out << " * #{option['name']} [#{option['value']}]\n"
957
952
  end
@@ -26,7 +26,6 @@ class Morpheus::Cli::PoliciesCommand
26
26
 
27
27
  def connect(opts)
28
28
  @api_client = establish_remote_appliance_connection(opts)
29
- # @policies_interface = Morpheus::APIClient.new(@access_token,nil,nil, @appliance_url).policies
30
29
  @policies_interface = @api_client.policies
31
30
  @group_policies_interface = @api_client.group_policies
32
31
  @cloud_policies_interface = @api_client.cloud_policies
@@ -13,9 +13,9 @@ class Morpheus::Cli::PowerSchedulesCommand
13
13
 
14
14
  def connect(opts)
15
15
  @api_client = establish_remote_appliance_connection(opts)
16
- @power_schedules_interface = Morpheus::APIClient.new(@access_token,nil,nil, @appliance_url).power_schedules
17
- @instances_interface = Morpheus::APIClient.new(@access_token,nil,nil, @appliance_url).instances
18
- @servers_interface = Morpheus::APIClient.new(@access_token,nil,nil, @appliance_url).servers
16
+ @power_schedules_interface = @api_client.power_schedules
17
+ @instances_interface = @api_client.instances
18
+ @servers_interface = @api_client.servers
19
19
  end
20
20
 
21
21
  def handle(args)
@@ -23,7 +23,7 @@ class Morpheus::Cli::PreseedScriptsCommand
23
23
 
24
24
  def connect(opts)
25
25
  @api_client = establish_remote_appliance_connection(opts)
26
- @image_builder_interface = Morpheus::APIClient.new(@access_token,nil,nil, @appliance_url).image_builder
26
+ @image_builder_interface = @api_client.image_builder
27
27
  @preseed_scripts_interface = @image_builder_interface.preseed_scripts
28
28
  end
29
29
 
@@ -1337,7 +1337,7 @@ EOT
1337
1337
  include Term::ANSIColor
1338
1338
 
1339
1339
  # for caching the the contents of YAML file $home/appliances
1340
- # it is structured like :appliance_name => {:host => "htt[://api.gomorpheus.com", :active => true}
1340
+ # it is structured like :appliance_name => {:host => "https://api.gomorpheus.com", :active => true}
1341
1341
  # not named @@appliances to avoid confusion with the instance variable . This is also a command class...
1342
1342
  @@appliance_config = nil
1343
1343
 
@@ -1700,7 +1700,7 @@ EOT
1700
1700
  # wtf, no url...
1701
1701
  return appliance, json_response
1702
1702
  else
1703
- setup_interface = Morpheus::SetupInterface.new({url:appliance_url, verify_ssl: (appliance[:insecure] != true), timeout: timeout})
1703
+ setup_interface = Morpheus::SetupInterface.new({url:appliance_url, verify_ssl: !appliance[:insecure], timeout: timeout})
1704
1704
  start_time = Time.now
1705
1705
  begin
1706
1706
  json_response = setup_interface.check(params)
@@ -368,7 +368,6 @@ class Morpheus::Cli::ReportsCommand
368
368
  do_mkdir = false
369
369
  optparse = Morpheus::Cli::OptionParser.new do |opts|
370
370
  opts.banner = subcommand_usage("[id] [file]")
371
- build_common_options(opts, options, [:dry_run, :remote])
372
371
  opts.on( '--format VALUE', String, "Report Format for exported file, json or csv. Default is json." ) do |val|
373
372
  report_format = val
374
373
  end
@@ -379,6 +378,7 @@ class Morpheus::Cli::ReportsCommand
379
378
  opts.on( '-p', '--mkdir', "Create missing directories for [local-file] if they do not exist." ) do
380
379
  do_mkdir = true
381
380
  end
381
+ build_common_options(opts, options, [:dry_run, :remote])
382
382
  opts.footer = "Export a report result as json or csv." + "\n" +
383
383
  "[id] is required. This is id of the report result." + "\n" +
384
384
  "[file] is required. This is local destination for the downloaded file."
@@ -394,6 +394,9 @@ class Morpheus::Cli::ReportsCommand
394
394
 
395
395
  outfile = args[1]
396
396
  outfile = File.expand_path(outfile)
397
+ if outfile =~ /\.csv\Z/i
398
+ report_format = "csv"
399
+ end
397
400
 
398
401
  if Dir.exists?(outfile)
399
402
  print_red_alert "[file] is invalid. It is the name of an existing directory: #{outfile}"
@@ -13,21 +13,21 @@ class Morpheus::Cli::Roles
13
13
  include Morpheus::Cli::AccountsHelper
14
14
  include Morpheus::Cli::ProvisioningHelper
15
15
  include Morpheus::Cli::WhoamiHelper
16
- register_subcommands :list, :get, :add, :update, :remove, :'list-permissions', :'update-feature-access', :'update-global-group-access', :'update-group-access', :'update-global-cloud-access', :'update-cloud-access', :'update-global-instance-type-access', :'update-instance-type-access', :'update-global-blueprint-access', :'update-blueprint-access', :'update-global-catalog-item-type-access', :'update-catalog-item-type-access', :'update-persona-access'
16
+ register_subcommands :list, :get, :add, :update, :remove, :'list-permissions', :'update-feature-access', :'update-global-group-access', :'update-group-access', :'update-global-cloud-access', :'update-cloud-access', :'update-global-instance-type-access', :'update-instance-type-access', :'update-global-blueprint-access', :'update-blueprint-access', :'update-global-catalog-item-type-access', :'update-catalog-item-type-access', :'update-persona-access', :'update-global-vdi-pool-access', :'update-vdi-pool-access'
17
17
  alias_subcommand :details, :get
18
18
  set_default_subcommand :list
19
19
 
20
20
  def connect(opts)
21
21
  @api_client = establish_remote_appliance_connection(opts)
22
- @whoami_interface = Morpheus::APIClient.new(@access_token,nil,nil, @appliance_url).whoami
23
- @users_interface = Morpheus::APIClient.new(@access_token,nil,nil, @appliance_url).users
24
- @accounts_interface = Morpheus::APIClient.new(@access_token,nil,nil, @appliance_url).accounts
25
- @roles_interface = Morpheus::APIClient.new(@access_token,nil,nil, @appliance_url).roles
26
- @groups_interface = Morpheus::APIClient.new(@access_token,nil,nil, @appliance_url).groups
27
- @options_interface = Morpheus::APIClient.new(@access_token,nil,nil, @appliance_url).options
28
- @instances_interface = Morpheus::APIClient.new(@access_token,nil,nil, @appliance_url).instances
29
- @instance_types_interface = Morpheus::APIClient.new(@access_token,nil,nil, @appliance_url).instance_types
30
- @blueprints_interface = Morpheus::APIClient.new(@access_token,nil,nil, @appliance_url).blueprints
22
+ @whoami_interface = @api_client.whoami
23
+ @users_interface = @api_client.users
24
+ @accounts_interface = @api_client.accounts
25
+ @roles_interface = @api_client.roles
26
+ @groups_interface = @api_client.groups
27
+ @options_interface = @api_client.options
28
+ @instances_interface = @api_client.instances
29
+ @instance_types_interface = @api_client.instance_types
30
+ @blueprints_interface = @api_client.blueprints
31
31
  @active_group_id = Morpheus::Cli::Groups.active_groups[@appliance_name]
32
32
  end
33
33
 
@@ -102,19 +102,23 @@ class Morpheus::Cli::Roles
102
102
  options[:include_blueprint_access] = true
103
103
  end
104
104
  opts.on(nil,'--catalog-item-type-access', "Display Catalog Item Type Access") do
105
- options[:include_catalog_item_types_access] = true
105
+ options[:include_catalog_item_type_access] = true
106
106
  end
107
107
  opts.on(nil,'--personas', "Display Persona Access") do
108
108
  options[:include_personas_access] = true
109
109
  end
110
+ opts.on(nil,'--vdi-pool-access', "Display VDI Pool Access") do
111
+ options[:include_vdi_pool_access] = true
112
+ end
110
113
  opts.on('-a','--all', "Display All Access Lists") do
111
114
  options[:include_feature_access] = true
112
115
  options[:include_group_access] = true
113
116
  options[:include_cloud_access] = true
114
117
  options[:include_instance_type_access] = true
115
118
  options[:include_blueprint_access] = true
116
- options[:include_catalog_item_types_access] = true
119
+ options[:include_catalog_item_type_access] = true
117
120
  options[:include_personas_access] = true
121
+ options[:include_vdi_pool_access] = true
118
122
  end
119
123
  build_standard_get_options(opts, options)
120
124
  opts.footer = <<-EOT
@@ -206,9 +210,9 @@ EOT
206
210
  rows = rows.select {|row| row[:code].to_s =~ phrase_regexp || row[:name].to_s =~ phrase_regexp }
207
211
  end
208
212
  print as_pretty_table(rows, [:code, :name, :access], options)
209
- print reset,"\n"
213
+ # print reset,"\n"
210
214
  else
211
- print cyan,"Use --permissions to list permissions","\n"
215
+ print cyan,"Use --permissions to list feature permissions","\n"
212
216
  end
213
217
 
214
218
  has_group_access = true
@@ -220,6 +224,7 @@ EOT
220
224
  "Instance Types" => lambda {|it| get_access_string(it['globalInstanceTypeAccess']) },
221
225
  "Blueprints" => lambda {|it| get_access_string(it['globalAppTemplateAccess'] || it['globalBlueprintAccess']) },
222
226
  "Catalog Item Types" => lambda {|it| get_access_string(it['globalCatalogItemTypeAccess']) },
227
+ "VDI Pools" => lambda {|it| get_access_string(it['globalVdiPoolAccess']) },
223
228
  }
224
229
  if role['roleType'].to_s.downcase == 'account'
225
230
  global_access_columns.delete("Groups")
@@ -228,7 +233,7 @@ EOT
228
233
  global_access_columns.delete("Clouds")
229
234
  has_cloud_access = false
230
235
  end
231
- puts as_pretty_table([json_response], global_access_columns, options)
236
+ print as_pretty_table([json_response], global_access_columns, options)
232
237
 
233
238
  if has_group_access
234
239
  #print_h2 "Group Access: #{get_access_string(json_response['globalSiteAccess'])}", options
@@ -246,7 +251,7 @@ EOT
246
251
  else
247
252
  print cyan,"Use -g, --group-access to list custom access","\n"
248
253
  end
249
- print reset,"\n"
254
+ # print reset,"\n"
250
255
  else
251
256
  # print "\n"
252
257
  # print cyan,bold,"Group Access: #{get_access_string(json_response['globalSiteAccess'])}",reset,"\n"
@@ -270,7 +275,7 @@ EOT
270
275
  else
271
276
  print cyan,"Use -c, --cloud-access to list custom access","\n"
272
277
  end
273
- print reset,"\n"
278
+ # print reset,"\n"
274
279
  else
275
280
  # print "\n"
276
281
  # print cyan,bold,"Cloud Access: #{get_access_string(json_response['globalZoneAccess'])}",reset,"\n"
@@ -293,7 +298,7 @@ EOT
293
298
  else
294
299
  print cyan,"Use -i, --instance-type-access to list custom access","\n"
295
300
  end
296
- print reset,"\n"
301
+ # print reset,"\n"
297
302
  else
298
303
  # print "\n"
299
304
  # print cyan,bold,"Instance Type Access: #{get_access_string(json_response['globalInstanceTypeAccess'])}",reset,"\n"
@@ -317,7 +322,7 @@ EOT
317
322
  else
318
323
  print cyan,"Use -b, --blueprint-access to list custom access","\n"
319
324
  end
320
- print reset,"\n"
325
+ # print reset,"\n"
321
326
  else
322
327
  # print "\n"
323
328
  # print cyan,bold,"Blueprint Access: #{get_access_string(json_response['globalAppTemplateAccess'])}",reset,"\n"
@@ -331,7 +336,7 @@ EOT
331
336
  # print "\n"
332
337
  if catalog_item_type_global_access == 'custom'
333
338
  print_h2 "Catalog Item Type Access", options
334
- if options[:include_catalog_item_types_access]
339
+ if options[:include_catalog_item_type_access]
335
340
  rows = catalog_item_type_permissions.collect do |it|
336
341
  {
337
342
  name: it['name'],
@@ -350,6 +355,7 @@ EOT
350
355
 
351
356
  persona_permissions = json_response['personaPermissions'] || json_response['personas'] || []
352
357
  # if options[:include_personas_access]
358
+ print cyan
353
359
  if persona_permissions
354
360
  print_h2 "Persona Access", options
355
361
  rows = persona_permissions.collect do |it|
@@ -358,13 +364,34 @@ EOT
358
364
  access: format_access_string(it['access'], ["none","read","full"]),
359
365
  }
360
366
  end
361
- print as_pretty_table(rows, [:name, :access], options)
362
- print reset,"\n"
367
+ print as_pretty_table(rows, [:name, :access], options)
363
368
  end
364
369
 
365
370
  # print reset,"\n"
366
371
 
372
+ vdi_pool_global_access = json_response['globalVdiPoolAccess']
373
+ vdi_pool_permissions = json_response['vdiPoolPermissions'] || []
374
+ print cyan
375
+ if vdi_pool_global_access == 'custom'
376
+ print_h2 "VDI Pool Access", options
377
+ if options[:include_vdi_pool_access]
378
+ rows = vdi_pool_permissions.collect do |it|
379
+ {
380
+ name: it['name'],
381
+ access: format_access_string(it['access'], ["none","read","full"]),
382
+ }
383
+ end
384
+ print as_pretty_table(rows, [:name, :access], options)
385
+ else
386
+ print cyan,"Use --vdi-pool-access to list custom access","\n"
387
+ end
388
+ else
389
+ # print "\n"
390
+ # print cyan,bold,"VDI Pool Access: #{get_access_string(json_response['globalVdiPoolAccess'])}",reset,"\n"
391
+ end
392
+
367
393
  end
394
+ print reset,"\n"
368
395
 
369
396
  return 0, nil
370
397
  end
@@ -520,7 +547,7 @@ EOT
520
547
  end
521
548
 
522
549
  # v_prompt = Morpheus::Cli::OptionTypes.prompt([{'fieldName' => 'defaultPersona', 'fieldLabel' => 'Default Persona', 'type' => 'select', 'optionSource' => 'personas', 'description' => 'Default Persona'}], options[:options], @api_client)
523
- v_prompt = Morpheus::Cli::OptionTypes.prompt([{'fieldName' => 'defaultPersona', 'fieldLabel' => 'Default Persona', 'type' => 'select', 'selectOptions' => [{'name'=>'Service Catalog','value'=>'serviceCatalog'},{'name'=>'Standard','value'=>'standard'}], 'description' => 'Default Persona'}], options[:options], @api_client)
550
+ v_prompt = Morpheus::Cli::OptionTypes.prompt([{'fieldName' => 'defaultPersona', 'fieldLabel' => 'Default Persona', 'type' => 'select', 'selectOptions' => get_persona_select_options(), 'description' => 'Default Persona'}], options[:options], @api_client)
524
551
  role_payload['defaultPersona'] = {'code' => v_prompt['defaultPersona']} unless v_prompt['defaultPersona'].to_s.strip.empty?
525
552
 
526
553
  payload = {"role" => role_payload}
@@ -782,14 +809,14 @@ EOT
782
809
  def update_group_access(args)
783
810
  options = {}
784
811
  name = nil
785
- group_name = nil
812
+ group_id = nil
786
813
  access_value = nil
787
814
  do_all = false
788
815
  allowed_access_values = ['full', 'read', 'none']
789
816
  optparse = Morpheus::Cli::OptionParser.new do |opts|
790
817
  opts.banner = subcommand_usage("[role] [group] [access]")
791
818
  opts.on( '-g', '--group GROUP', "Group name or id" ) do |val|
792
- group_name = val
819
+ group_id = val
793
820
  end
794
821
  opts.on( nil, '--all', "Update all groups at once." ) do
795
822
  do_all = true
@@ -845,9 +872,8 @@ EOT
845
872
  end
846
873
 
847
874
  group = nil
848
- group_id = nil
849
875
  if !do_all
850
- group = find_group_by_name_or_id_for_provisioning(group_name)
876
+ group = find_group_by_name_or_id_for_provisioning(group_id)
851
877
  return 1 if group.nil?
852
878
  group_id = group['id']
853
879
  end
@@ -932,15 +958,14 @@ EOT
932
958
 
933
959
  def update_cloud_access(args)
934
960
  options = {}
935
- cloud_name = nil
961
+ cloud_id = nil
936
962
  access_value = nil
937
963
  do_all = false
938
964
  allowed_access_values = ['full', 'read', 'none']
939
965
  optparse = Morpheus::Cli::OptionParser.new do |opts|
940
966
  opts.banner = subcommand_usage("[name]")
941
967
  opts.on( '-c', '--cloud CLOUD', "Cloud name or id" ) do |val|
942
- puts "val is : #{val}"
943
- cloud_name = val
968
+ cloud_id = val
944
969
  end
945
970
  opts.on( nil, '--all', "Update all clouds at once." ) do
946
971
  do_all = true
@@ -948,9 +973,6 @@ EOT
948
973
  opts.on( '--access VALUE', String, "Access value [#{allowed_access_values.join('|')}]" ) do |val|
949
974
  access_value = val
950
975
  end
951
- opts.on( '-g', '--group GROUP', "Group to find cloud in" ) do |val|
952
- options[:group] = val
953
- end
954
976
  build_common_options(opts, options, [:json, :dry_run, :remote])
955
977
  opts.footer = "Update role access for a cloud or all clouds.\n" +
956
978
  "[role] is required. This is the name or id of a role.\n" +
@@ -998,23 +1020,11 @@ EOT
998
1020
  exit 1
999
1021
  end
1000
1022
 
1001
- # crap, group_id is needed for this api, maybe just use infrastructure or some other optionSource instead.
1002
- group_id = nil
1003
- cloud_id = nil
1023
+ cloud = nil
1004
1024
  if !do_all
1005
- group_id = nil
1006
- if !options[:group].nil?
1007
- group = find_group_by_name_or_id_for_provisioning(options[:group])
1008
- group_id = group['id']
1009
- else
1010
- group_id = @active_group_id
1011
- end
1012
- if group_id.nil?
1013
- print_red_alert "Group not found or specified!"
1014
- return 1
1015
- end
1016
- cloud_id = find_cloud_id_by_name(group_id, cloud_name)
1017
- return 1 if cloud_id.nil?
1025
+ cloud = find_cloud_by_name_or_id_for_provisioning(nil, cloud_id)
1026
+ return 1 if cloud.nil?
1027
+ cloud_id = cloud['id']
1018
1028
  end
1019
1029
  params = {}
1020
1030
  if do_all
@@ -1037,7 +1047,7 @@ EOT
1037
1047
  if do_all
1038
1048
  print_green_success "Role #{role['authority']} access updated for all clouds"
1039
1049
  else
1040
- print_green_success "Role #{role['authority']} access updated for cloud id #{cloud_id}"
1050
+ print_green_success "Role #{role['authority']} access updated for cloud #{cloud['name']}"
1041
1051
  end
1042
1052
  end
1043
1053
  return 0
@@ -1534,7 +1544,7 @@ EOT
1534
1544
  build_common_options(opts, options, [:json, :dry_run, :remote])
1535
1545
  opts.footer = "Update role access for a persona or all personas.\n" +
1536
1546
  "[role] is required. This is the name or id of a role.\n" +
1537
- "--persona or --all is required. This is the code of a persona. Service Catalog or Standard\n" +
1547
+ "--persona or --all is required. This is the code of a persona. Service Catalog, Standard, or Virtual Desktop\n" +
1538
1548
  "--access is required. This is the new access value. #{anded_list(allowed_access_values)}"
1539
1549
  end
1540
1550
  optparse.parse!(args)
@@ -1606,6 +1616,160 @@ EOT
1606
1616
  end
1607
1617
  end
1608
1618
 
1619
+ def update_global_vdi_pool_access(args)
1620
+ usage = "Usage: morpheus roles update-global-vdi-pool-access [role] [full|custom|none]"
1621
+ options = {}
1622
+ optparse = Morpheus::Cli::OptionParser.new do |opts|
1623
+ opts.banner = subcommand_usage("[role] [full|custom|none]")
1624
+ build_common_options(opts, options, [:json, :dry_run, :remote])
1625
+ end
1626
+ optparse.parse!(args)
1627
+ verify_args!(args:args, optparse:optparse, count: 2)
1628
+ name = args[0]
1629
+ access_value = args[1].to_s.downcase
1630
+ if !['full', 'custom', 'none'].include?(access_value)
1631
+ raise_command_error("invalid access value: #{args[1]}", optparse)
1632
+ end
1633
+
1634
+
1635
+ connect(options)
1636
+ begin
1637
+ account = find_account_from_options(options)
1638
+ account_id = account ? account['id'] : nil
1639
+ role = find_role_by_name_or_id(account_id, name)
1640
+ exit 1 if role.nil?
1641
+ # note: VdiPools being plural is odd, the others are singular
1642
+ params = {permissionCode: 'VdiPools', access: access_value}
1643
+ @roles_interface.setopts(options)
1644
+ if options[:dry_run]
1645
+ print_dry_run @roles_interface.dry.update_permission(account_id, role['id'], params)
1646
+ return
1647
+ end
1648
+ json_response = @roles_interface.update_permission(account_id, role['id'], params)
1649
+
1650
+ if options[:json]
1651
+ print JSON.pretty_generate(json_response)
1652
+ print "\n"
1653
+ else
1654
+ print_green_success "Role #{role['authority']} global vdi pool access updated"
1655
+ end
1656
+ rescue RestClient::Exception => e
1657
+ print_rest_exception(e, options)
1658
+ exit 1
1659
+ end
1660
+ end
1661
+
1662
+ def update_vdi_pool_access(args)
1663
+ options = {}
1664
+ vdi_pool_id = nil
1665
+ access_value = nil
1666
+ do_all = false
1667
+ allowed_access_values = ['full', 'none']
1668
+ optparse = Morpheus::Cli::OptionParser.new do |opts|
1669
+ opts.banner = subcommand_usage("[role] [vdi-pool] [access]")
1670
+ opts.on( '--vdi-pool ID', String, "VDI Pool ID or Name" ) do |val|
1671
+ vdi_pool_id = val
1672
+ end
1673
+ opts.on( nil, '--all', "Update all VDI pools at once." ) do
1674
+ do_all = true
1675
+ end
1676
+ opts.on( '--access VALUE', String, "Access value [#{allowed_access_values.join('|')}]" ) do |val|
1677
+ access_value = val
1678
+ end
1679
+ build_common_options(opts, options, [:json, :dry_run, :remote])
1680
+ opts.footer = "Update role access for a VDI pool or all VDI pools.\n" +
1681
+ "[role] is required. This is the name or id of a role.\n" +
1682
+ "--vdi-pool or --all is required. This is the name or id of a VDI pool.\n" +
1683
+ "--access is required. This is the new access value. #{anded_list(allowed_access_values)}"
1684
+ end
1685
+ optparse.parse!(args)
1686
+
1687
+ # usage: update-vdi-pool-access [role] [access] --all
1688
+ # update-vdi-pool-access [role] [vdi-pool] [access]
1689
+ name = args[0]
1690
+ if do_all
1691
+ verify_args!(args:args, optparse:optparse, min:1, max:2)
1692
+ access_value = args[1] if args[1]
1693
+ else
1694
+ verify_args!(args:args, optparse:optparse, min:1, max:3)
1695
+ vdi_pool_id = args[1] if args[1]
1696
+ access_value = args[2] if args[2]
1697
+ end
1698
+ if !vdi_pool_id && !do_all
1699
+ raise_command_error("missing required argument: [vdi-pool] or --all", optparse)
1700
+ end
1701
+ if !access_value
1702
+ raise_command_error("missing required argument: [access]", optparse)
1703
+ end
1704
+ access_value = access_value.to_s.downcase
1705
+ if !allowed_access_values.include?(access_value)
1706
+ raise_command_error("invalid access value: #{access_value}", optparse)
1707
+ puts optparse
1708
+ return 1
1709
+ end
1710
+
1711
+ connect(options)
1712
+ begin
1713
+ account = find_account_from_options(options)
1714
+ account_id = account ? account['id'] : nil
1715
+ role = find_role_by_name_or_id(account_id, name)
1716
+ return 1 if role.nil?
1717
+
1718
+ role_json = @roles_interface.get(account_id, role['id'])
1719
+ vdi_pool_global_access = role_json['globalVdiPoolAccess']
1720
+ vdi_pool_permissions = role_json['vdiPoolPermissions'] || []
1721
+ if vdi_pool_global_access != 'custom'
1722
+ print "\n", red, "Global VDI Pool Access is currently: #{vdi_pool_global_access.to_s.capitalize}"
1723
+ print "\n", "You must first set it to Custom via `morpheus roles update-global-vdi-pool-access \"#{name}\" custom`"
1724
+ print "\n\n", reset
1725
+ return 1
1726
+ end
1727
+
1728
+ # hacky, but support name or code lookup via the list returned in the show payload
1729
+ vdi_pool = nil
1730
+ if !do_all
1731
+ if vdi_pool_id.to_s =~ /\A\d{1,}\Z/
1732
+ vdi_pool = vdi_pool_permissions.find {|b| b['id'] == vdi_pool_id.to_i }
1733
+ else
1734
+ vdi_pool = vdi_pool_permissions.find {|b| b['name'] == vdi_pool_id }
1735
+ end
1736
+ if vdi_pool.nil?
1737
+ print_red_alert "VDI Pool not found: '#{vdi_pool_id}'"
1738
+ return 1
1739
+ end
1740
+ end
1741
+
1742
+ params = {}
1743
+ if do_all
1744
+ params['allVdiPools'] = true
1745
+ else
1746
+ params['vdiPoolId'] = vdi_pool['id']
1747
+ end
1748
+ params['access'] = access_value
1749
+ @roles_interface.setopts(options)
1750
+ if options[:dry_run]
1751
+ print_dry_run @roles_interface.dry.update_vdi_pool(account_id, role['id'], params)
1752
+ return
1753
+ end
1754
+ json_response = @roles_interface.update_vdi_pool(account_id, role['id'], params)
1755
+
1756
+ if options[:json]
1757
+ print JSON.pretty_generate(json_response)
1758
+ print "\n"
1759
+ else
1760
+ if do_all
1761
+ print_green_success "Role #{role['authority']} access updated for all VDI pools"
1762
+ else
1763
+ print_green_success "Role #{role['authority']} access updated for VDI pool #{vdi_pool['name']}"
1764
+ end
1765
+ end
1766
+ return 0
1767
+ rescue RestClient::Exception => e
1768
+ print_rest_exception(e, options)
1769
+ exit 1
1770
+ end
1771
+ end
1772
+
1609
1773
  private
1610
1774
 
1611
1775
  def add_role_option_types
@@ -1616,7 +1780,7 @@ EOT
1616
1780
  {'fieldName' => 'baseRole', 'fieldLabel' => 'Copy From Role', 'type' => 'text'},
1617
1781
  {'fieldName' => 'multitenant', 'fieldLabel' => 'Multitenant', 'type' => 'checkbox', 'defaultValue' => 'off', 'description' => 'A Multitenant role is automatically copied into all existing subaccounts as well as placed into a subaccount when created. Useful for providing a set of predefined roles a Customer can use'},
1618
1782
  {'fieldName' => 'multitenantLocked', 'fieldLabel' => 'Multitenant Locked', 'type' => 'checkbox', 'defaultValue' => 'off', 'description' => 'Prevents subtenants from branching off this role/modifying it. '},
1619
- {'fieldName' => 'defaultPersona', 'fieldLabel' => 'Default Persona', 'type' => 'select', 'selectOptions' => [{'name'=>'Service Catalog','value'=>'serviceCatalog'},{'name'=>'Standard','value'=>'standard'}], 'description' => 'Default Persona'}
1783
+ {'fieldName' => 'defaultPersona', 'fieldLabel' => 'Default Persona', 'type' => 'select', 'selectOptions' => get_persona_select_options(), 'description' => 'Default Persona'}
1620
1784
  ]
1621
1785
  end
1622
1786
 
@@ -1624,20 +1788,16 @@ EOT
1624
1788
  add_role_option_types.reject {|it| ['roleType', 'baseRole'].include?(it['fieldName']) }
1625
1789
  end
1626
1790
 
1627
-
1628
- def find_cloud_id_by_name(group_id, name)
1629
- option_results = @options_interface.options_for_source('clouds', {groupId: group_id})
1630
- match = option_results['data'].find { |grp| grp['value'].to_s == name.to_s || grp['name'].downcase == name.downcase}
1631
- if match.nil?
1632
- print_red_alert "Cloud not found by name #{name}"
1633
- return nil
1634
- else
1635
- return match['value']
1636
- end
1637
- end
1638
-
1639
1791
  def role_type_options
1640
1792
  [{'name' => 'User Role', 'value' => 'user'}, {'name' => 'Account Role', 'value' => 'account'}]
1641
1793
  end
1642
1794
 
1795
+ def get_persona_select_options
1796
+ [
1797
+ {'name'=>'Service Catalog','value'=>'serviceCatalog'},
1798
+ {'name'=>'Standard','value'=>'standard'},
1799
+ {'name'=>'Virtual Desktop','value'=>'vdi'}
1800
+ ]
1801
+ end
1802
+
1643
1803
  end