morpheus-cli 4.1.8 → 4.1.9

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 (72) hide show
  1. checksums.yaml +4 -4
  2. data/Dockerfile +1 -1
  3. data/lib/morpheus/api/api_client.rb +24 -0
  4. data/lib/morpheus/api/{old_cypher_interface.rb → budgets_interface.rb} +10 -11
  5. data/lib/morpheus/api/cloud_datastores_interface.rb +7 -0
  6. data/lib/morpheus/api/cloud_resource_pools_interface.rb +2 -2
  7. data/lib/morpheus/api/cypher_interface.rb +18 -12
  8. data/lib/morpheus/api/health_interface.rb +72 -0
  9. data/lib/morpheus/api/instances_interface.rb +1 -1
  10. data/lib/morpheus/api/library_instance_types_interface.rb +7 -0
  11. data/lib/morpheus/api/log_settings_interface.rb +6 -0
  12. data/lib/morpheus/api/network_security_servers_interface.rb +30 -0
  13. data/lib/morpheus/api/price_sets_interface.rb +42 -0
  14. data/lib/morpheus/api/prices_interface.rb +68 -0
  15. data/lib/morpheus/api/provisioning_settings_interface.rb +29 -0
  16. data/lib/morpheus/api/servers_interface.rb +1 -1
  17. data/lib/morpheus/api/service_plans_interface.rb +34 -11
  18. data/lib/morpheus/api/task_sets_interface.rb +8 -0
  19. data/lib/morpheus/api/tasks_interface.rb +8 -0
  20. data/lib/morpheus/cli.rb +6 -3
  21. data/lib/morpheus/cli/appliance_settings_command.rb +13 -5
  22. data/lib/morpheus/cli/approvals_command.rb +1 -1
  23. data/lib/morpheus/cli/apps.rb +88 -28
  24. data/lib/morpheus/cli/backup_settings_command.rb +1 -1
  25. data/lib/morpheus/cli/blueprints_command.rb +2 -0
  26. data/lib/morpheus/cli/budgets_command.rb +672 -0
  27. data/lib/morpheus/cli/cli_command.rb +13 -2
  28. data/lib/morpheus/cli/cli_registry.rb +1 -0
  29. data/lib/morpheus/cli/clusters.rb +40 -274
  30. data/lib/morpheus/cli/commands/standard/benchmark_command.rb +114 -66
  31. data/lib/morpheus/cli/commands/standard/coloring_command.rb +12 -0
  32. data/lib/morpheus/cli/commands/standard/curl_command.rb +31 -6
  33. data/lib/morpheus/cli/commands/standard/echo_command.rb +8 -3
  34. data/lib/morpheus/cli/commands/standard/set_prompt_command.rb +1 -1
  35. data/lib/morpheus/cli/containers_command.rb +37 -24
  36. data/lib/morpheus/cli/cypher_command.rb +191 -150
  37. data/lib/morpheus/cli/health_command.rb +903 -0
  38. data/lib/morpheus/cli/hosts.rb +43 -32
  39. data/lib/morpheus/cli/instances.rb +119 -68
  40. data/lib/morpheus/cli/jobs_command.rb +1 -1
  41. data/lib/morpheus/cli/library_instance_types_command.rb +61 -11
  42. data/lib/morpheus/cli/library_option_types_command.rb +2 -2
  43. data/lib/morpheus/cli/log_settings_command.rb +46 -3
  44. data/lib/morpheus/cli/logs_command.rb +24 -17
  45. data/lib/morpheus/cli/mixins/accounts_helper.rb +2 -0
  46. data/lib/morpheus/cli/mixins/logs_helper.rb +73 -19
  47. data/lib/morpheus/cli/mixins/print_helper.rb +29 -1
  48. data/lib/morpheus/cli/mixins/provisioning_helper.rb +554 -96
  49. data/lib/morpheus/cli/mixins/whoami_helper.rb +13 -1
  50. data/lib/morpheus/cli/networks_command.rb +3 -0
  51. data/lib/morpheus/cli/option_types.rb +83 -53
  52. data/lib/morpheus/cli/price_sets_command.rb +543 -0
  53. data/lib/morpheus/cli/prices_command.rb +669 -0
  54. data/lib/morpheus/cli/processes_command.rb +0 -2
  55. data/lib/morpheus/cli/provisioning_settings_command.rb +237 -0
  56. data/lib/morpheus/cli/remote.rb +9 -4
  57. data/lib/morpheus/cli/reports_command.rb +10 -4
  58. data/lib/morpheus/cli/roles.rb +93 -38
  59. data/lib/morpheus/cli/security_groups.rb +10 -0
  60. data/lib/morpheus/cli/service_plans_command.rb +736 -0
  61. data/lib/morpheus/cli/tasks.rb +220 -8
  62. data/lib/morpheus/cli/tenants_command.rb +3 -16
  63. data/lib/morpheus/cli/users.rb +2 -25
  64. data/lib/morpheus/cli/version.rb +1 -1
  65. data/lib/morpheus/cli/whitelabel_settings_command.rb +18 -18
  66. data/lib/morpheus/cli/whoami.rb +28 -10
  67. data/lib/morpheus/cli/workflows.rb +488 -36
  68. data/lib/morpheus/formatters.rb +22 -0
  69. data/morpheus-cli.gemspec +1 -0
  70. metadata +28 -5
  71. data/lib/morpheus/cli/accounts.rb +0 -335
  72. data/lib/morpheus/cli/old_cypher_command.rb +0 -412
@@ -69,7 +69,6 @@ class Morpheus::Cli::Processes
69
69
  connect(options)
70
70
  begin
71
71
  params.merge!(parse_list_options(options))
72
- # params[:query] = params.delete(:phrase) unless params[:phrase].nil?
73
72
  @processes_interface.setopts(options)
74
73
  if options[:dry_run]
75
74
  print_dry_run @processes_interface.dry.list(params)
@@ -201,7 +200,6 @@ class Morpheus::Cli::Processes
201
200
  begin
202
201
  process_id = args[0]
203
202
  params.merge!(parse_list_options(options))
204
- params[:query] = params.delete(:phrase) unless params[:phrase].nil?
205
203
  @processes_interface.setopts(options)
206
204
  if options[:dry_run]
207
205
  print_dry_run @processes_interface.dry.get(process_id, params)
@@ -0,0 +1,237 @@
1
+ require 'morpheus/cli/cli_command'
2
+
3
+ class Morpheus::Cli::ProvisioningSettingsCommand
4
+ include Morpheus::Cli::CliCommand
5
+ include Morpheus::Cli::AccountsHelper
6
+ include Morpheus::Cli::WhoamiHelper
7
+
8
+ set_command_name :'provisioning-settings'
9
+
10
+ register_subcommands :get, :update
11
+
12
+ set_default_subcommand :get
13
+
14
+ def connect(opts)
15
+ @api_client = establish_remote_appliance_connection(opts)
16
+ @provisioning_settings_interface = @api_client.provisioning_settings
17
+ @storage_providers_interface = @api_client.storage_providers
18
+ @key_pairs_interface = @api_client.key_pairs
19
+ @blueprints_interface = @api_client.blueprints
20
+ end
21
+
22
+ def handle(args)
23
+ handle_subcommand(args)
24
+ end
25
+
26
+ def get(args)
27
+ options = {}
28
+ optparse = Morpheus::Cli::OptionParser.new do |opts|
29
+ opts.banner = subcommand_usage()
30
+ build_common_options(opts, options, [:query, :json, :yaml, :csv, :fields, :dry_run, :remote])
31
+ opts.footer = "Get provisioning settings."
32
+ end
33
+ optparse.parse!(args)
34
+ connect(options)
35
+ if args.count != 0
36
+ raise_command_error "wrong number of arguments, expected 0 and got (#{args.count}) #{args}\n#{optparse}"
37
+ return 1
38
+ end
39
+
40
+ begin
41
+ @provisioning_settings_interface.setopts(options)
42
+
43
+ if options[:dry_run]
44
+ print_dry_run @provisioning_settings_interface.dry.get()
45
+ return
46
+ end
47
+ json_response = @provisioning_settings_interface.get()
48
+ if options[:json]
49
+ puts as_json(json_response, options, "provisioningSettings")
50
+ return 0
51
+ elsif options[:yaml]
52
+ puts as_yaml(json_response, options, "provisioningSettings")
53
+ return 0
54
+ elsif options[:csv]
55
+ puts records_as_csv([json_response['provisioningSettings']], options)
56
+ return 0
57
+ end
58
+
59
+ settings = json_response['provisioningSettings']
60
+
61
+ print_h1 "Provisioning Settings"
62
+ print cyan
63
+
64
+ description_cols = {
65
+ "Allow Cloud Selection" => lambda {|it| format_boolean(it['allowZoneSelection'])},
66
+ "Allow Host Selection" => lambda {|it| format_boolean(it['allowServerSelection'])},
67
+ "Require Environment Selection" => lambda {|it| format_boolean(it['requireEnvironments'])},
68
+ "Show Pricing" => lambda {|it| format_boolean(it['showPricing'])},
69
+ "Hide Datastore Stats On Selection" => lambda {|it| format_boolean(it['hideDatastoreStats'])},
70
+ "Cross-Tenant Naming Policies" => lambda {|it| format_boolean(it['crossTenantNamingPolicies'])},
71
+ "Reuse Naming Sequence Numbers" => lambda {|it| format_boolean(it['reuseSequence'])},
72
+ "Deployment Archive Store" => lambda {|it| it['deployStorageProvider'] ? it['deployStorageProvider']['name'] : nil},
73
+ # Cloud-Init Settings
74
+ "Cloud-Init Username" => lambda {|it| it['cloudInitUsername']},
75
+ "Cloud-Init Password" => lambda {|it| it['cloudInitPassword']},
76
+ "Cloud-Init Key Pair" => lambda {|it| it['cloudInitKeyPair'] ? it['cloudInitKeyPair']['name'] : nil},
77
+ # Windows Settings
78
+ "Windows Adminstrator Password" => lambda {|it| it['windowsPassword']},
79
+ # PXE Boot Settings
80
+ "Default Root Password" => lambda {|it| it['pxeRootPassword']},
81
+ # App Blueprint Settings
82
+ "Default Blueprint Type" => lambda {|it| it['defaultTemplateType'] ? it['defaultTemplateType']['name'].capitalize : 'Morpheus'}
83
+ }
84
+ print_description_list(description_cols, settings)
85
+ print reset "\n"
86
+ return 0
87
+ rescue RestClient::Exception => e
88
+ print_rest_exception(e, options)
89
+ return 1
90
+ end
91
+ end
92
+
93
+ def update(args)
94
+ options = {}
95
+ params = {}
96
+
97
+ optparse = Morpheus::Cli::OptionParser.new do |opts|
98
+ opts.banner = opts.banner = subcommand_usage()
99
+ opts.on("--allow-cloud [on|off]", ['on','off'], "Allow cloud selection. Default is on") do |val|
100
+ params['allowZoneSelection'] = val.to_s == 'on' || val.to_s == 'true' || val.to_s == '1' || val.to_s == ''
101
+ end
102
+ opts.on("--allow-host [on|off]", ['on','off'], "Allow host selection. Default is on") do |val|
103
+ params['allowServerSelection'] = val.to_s == 'on' || val.to_s == 'true' || val.to_s == '1' || val.to_s == ''
104
+ end
105
+ opts.on("--require-env [on|off]", ['on','off'], "Require environment selection. Default is on") do |val|
106
+ params['requireEnvironments'] = val.to_s == 'on' || val.to_s == 'true' || val.to_s == '1' || val.to_s == ''
107
+ end
108
+ opts.on("--show-pricing [on|off]", ['on','off'], "Show pricing. Default is on") do |val|
109
+ params['showPricing'] = val.to_s == 'on' || val.to_s == 'true' || val.to_s == '1' || val.to_s == ''
110
+ end
111
+ opts.on("--ds-hide-stats [on|off]", ['on','off'], "Hide datastore stats on selection. Default is on") do |val|
112
+ params['hideDatastoreStats'] = val.to_s == 'on' || val.to_s == 'true' || val.to_s == '1' || val.to_s == ''
113
+ end
114
+ opts.on("--x-tenant-naming [on|off]", ['on','off'], "Cross-tenant naming policies. Default is on") do |val|
115
+ params['crossTenantNamingPolicies'] = val.to_s == 'on' || val.to_s == 'true' || val.to_s == '1' || val.to_s == ''
116
+ end
117
+ opts.on("--reuse-name-seq [on|off]", ['on','off'], "Reuse naming sequence numbers. Default is on") do |val|
118
+ params['reuseSequence'] = val.to_s == 'on' || val.to_s == 'true' || val.to_s == '1' || val.to_s == ''
119
+ end
120
+ opts.on("--deploy-bucket BUCKET", String, "Deployment archive storage provider ID or name") do |val|
121
+ if val == 'null'
122
+ params['deployStorageProvider'] = nil
123
+ else
124
+ options[:deployBucket] = val
125
+ end
126
+ end
127
+ opts.on("--cloud-username STRING", String, "Cloud-init username") do |val|
128
+ params['cloudInitUsername'] = val == 'null' ? nil : val
129
+ end
130
+ opts.on("--cloud-pwd STRING", String, "Cloud-init password") do |val|
131
+ params['cloudInitPassword'] = val == 'null' ? nil : val
132
+ end
133
+ opts.on("--cloud-keypair KEYPAIR", String, "Cloud-init key pair ID or name") do |val|
134
+ if val == 'null'
135
+ params['cloudInitKeyPair'] = nil
136
+ else
137
+ options[:cloudKeyPair] = val
138
+ end
139
+ end
140
+ opts.on("--windows-pwd STRING", String, "Windows administrator password") do |val|
141
+ params['windowsPassword'] = val == 'null' ? nil : val
142
+ end
143
+ opts.on("--pxe-pwd STRING", String, "PXE Boot default root password") do |val|
144
+ params['pxeRootPassword'] = val == 'null' ? nil : val
145
+ end
146
+ opts.on("--blueprint-type TYPE", String, "Default blueprint type ID, name or code") do |val|
147
+ if val == 'null'
148
+ params['defaultTemplateType'] = nil
149
+ else
150
+ options[:blueprintType] = val
151
+ end
152
+ end
153
+ build_common_options(opts, options, [:json, :payload, :dry_run, :quiet, :remote])
154
+ end
155
+
156
+ optparse.parse!(args)
157
+ connect(options)
158
+ if args.count != 0
159
+ raise_command_error "wrong number of arguments, expected 0 and got (#{args.count}) #{args}\n#{optparse}"
160
+ return 1
161
+ end
162
+
163
+ begin
164
+ payload = parse_payload(options)
165
+
166
+ if !payload
167
+ if options[:deployBucket]
168
+ bucket = find_storage_provider(options[:deployBucket])
169
+
170
+ if !bucket
171
+ print_red_alert "Storage provider #{options[:deployBucket]} not found"
172
+ exit 1
173
+ end
174
+ params['deployStorageProvider'] = {'id' => bucket['id']}
175
+ end
176
+
177
+ if options[:cloudKeyPair]
178
+ key_pair = find_key_pair(options[:cloudKeyPair])
179
+
180
+ if !key_pair
181
+ print_red_alert "Key pair #{options[:cloudKeyPair]} not found"
182
+ exit 1
183
+ end
184
+ params['cloudInitKeyPair'] = {'id' => key_pair['id']}
185
+ end
186
+
187
+ if options[:blueprintType]
188
+ template_type = find_template_type(options[:blueprintType])
189
+
190
+ if !template_type
191
+ print_red_alert "Blueprint type #{options[:blueprintType]} not found"
192
+ end
193
+ params['defaultTemplateType'] = {'id' => template_type['id']}
194
+ end
195
+ payload = {'provisioningSettings' => params}
196
+ end
197
+
198
+ @provisioning_settings_interface.setopts(options)
199
+ if options[:dry_run]
200
+ print_dry_run @provisioning_settings_interface.dry.update(payload)
201
+ return
202
+ end
203
+ json_response = @provisioning_settings_interface.update(payload)
204
+
205
+ if options[:json]
206
+ puts as_json(json_response, options)
207
+ elsif !options[:quiet]
208
+ if json_response['success']
209
+ print_green_success "Updated provisioning settings"
210
+ get([] + (options[:remote] ? ["-r",options[:remote]] : []))
211
+ else
212
+ print_red_alert "Error updating provisioning settings: #{json_response['msg'] || json_response['errors']}"
213
+ end
214
+ end
215
+ return 0
216
+
217
+ rescue RestClient::Exception => e
218
+ print_rest_exception(e, options)
219
+ exit 1
220
+ end
221
+ end
222
+
223
+ private
224
+
225
+ def find_storage_provider(val)
226
+ (val.to_s =~ /\A\d{1,}\Z/) ? @storage_providers_interface.get(val.to_i)['storageBucket'] : @storage_providers_interface.list({'name' => val})["storageBuckets"].first
227
+ end
228
+
229
+ def find_key_pair(val)
230
+ (val.to_s =~ /\A\d{1,}\Z/) ? @key_pairs_interface.get(current_account['id'], val.to_i)['keyPair'] : @key_pairs_interface.list(current_account['id'], {'name' => val})["keyPairs"].first
231
+ end
232
+
233
+ def find_template_type(val)
234
+ template_types = @provisioning_settings_interface.template_types['templateTypes']
235
+ (val.to_s =~ /\A\d{1,}\Z/) ? template_types.find {|it| it['id'] == val.to_i} : template_types.find {|it| it['name'].casecmp(val) == 0 || it['code'].casecmp(val) == 0}
236
+ end
237
+ end
@@ -133,7 +133,7 @@ EOT
133
133
  opts.on(nil, "--insecure", "Allow insecure HTTPS communication. i.e. Ignore SSL errors.") do
134
134
  secure = false
135
135
  end
136
- build_common_options(opts, options, [:quiet])
136
+ build_common_options(opts, options, [:options, :quiet])
137
137
  opts.footer = <<-EOT
138
138
  This will add a new remote appliance to your morpheus client configuration.
139
139
  If this is your first remote, --use is automatically applied so
@@ -233,7 +233,7 @@ EOT
233
233
  # hit check api and store version and other info
234
234
  if !options[:quiet]
235
235
  print cyan
236
- puts "Inspecting remote appliance url: #{appliance[:host]} ..."
236
+ puts "Inspecting remote appliance #{appliance[:host]} ..."
237
237
  end
238
238
  appliance, check_json_response = ::Morpheus::Cli::Remote.refresh_remote(new_appliance_name.to_sym)
239
239
  if !options[:quiet]
@@ -260,6 +260,11 @@ EOT
260
260
  return exit_code, err
261
261
  end
262
262
 
263
+ # just skip setup/login stuff is no prompt -N is used.
264
+ if options[:no_prompt]
265
+ return exit_code, err
266
+ end
267
+
263
268
  # check_cmd_result = check_appliance([new_appliance_name, "--quiet"])
264
269
  # check_cmd_result = check_appliance([new_appliance_name])
265
270
 
@@ -1299,9 +1304,9 @@ EOT
1299
1304
  elsif status_str == "ready"
1300
1305
  out << "#{green}#{status_str.upcase}#{return_color}"
1301
1306
  elsif status_str == "http-error"
1302
- out << "#{red}#{status_str.upcase}#{return_color}"
1307
+ out << "#{red}HTTP ERROR#{return_color}"
1303
1308
  elsif ['error', 'net-error', 'ssl-error', 'http-timeout', 'unreachable', 'unrecognized'].include?(status_str)
1304
- out << "#{red}#{status_str.upcase}#{return_color}"
1309
+ out << "#{red}#{status_str.gsub('-', ' ').upcase}#{return_color}"
1305
1310
  else
1306
1311
  # dunno
1307
1312
  out << "#{yellow}#{status_str.upcase}#{return_color}"
@@ -17,6 +17,10 @@ class Morpheus::Cli::ReportsCommand
17
17
 
18
18
  register_subcommands :list, :get, :run, :view, :export, :remove, :types
19
19
 
20
+ def default_refresh_interval
21
+ 5
22
+ end
23
+
20
24
  def handle(args)
21
25
  handle_subcommand(args)
22
26
  end
@@ -29,14 +33,13 @@ class Morpheus::Cli::ReportsCommand
29
33
  opts.on( '--type CODE', String, "Report Type code(s)" ) do |val|
30
34
  params['reportType'] = val.to_s.split(",").compact.collect {|it| it.strip }
31
35
  end
32
- build_common_options(opts, options, [:list, :json, :dry_run, :remote])
36
+ build_common_options(opts, options, [:list, :query, :json, :dry_run, :remote])
33
37
  opts.footer = "List report history."
34
38
  end
35
39
  optparse.parse!(args)
36
40
  connect(options)
37
41
  begin
38
42
  params.merge!(parse_list_options(options))
39
-
40
43
  @reports_interface.setopts(options)
41
44
  if options[:dry_run]
42
45
  print_dry_run @reports_interface.dry.list(params)
@@ -268,6 +271,10 @@ class Morpheus::Cli::ReportsCommand
268
271
 
269
272
  # Report Types tell us what the available filters are...
270
273
  report_option_types = report_type['optionTypes'] || []
274
+ report_option_types = report_option_types.collect {|it|
275
+ it['fieldContext'] = nil
276
+ it
277
+ }
271
278
  # pluck out optionTypes like the UI does..
272
279
  metadata_option_type = nil
273
280
  if report_option_types.find {|it| it['fieldName'] == 'metadata' }
@@ -275,6 +282,7 @@ class Morpheus::Cli::ReportsCommand
275
282
  end
276
283
 
277
284
  v_prompt = Morpheus::Cli::OptionTypes.prompt(report_option_types, options[:options], @api_client)
285
+ payload.deep_merge!({'report' => v_prompt}) unless v_prompt.empty?
278
286
 
279
287
  if metadata_option_type
280
288
  if !options[:options]['metadata']
@@ -285,8 +293,6 @@ class Morpheus::Cli::ReportsCommand
285
293
  end
286
294
  end
287
295
 
288
- # payload.deep_merge!({'report' => v_prompt}) unless v_prompt.empty?
289
- payload.deep_merge!(v_prompt) unless v_prompt.empty?
290
296
  end
291
297
 
292
298
  @reports_interface.setopts(options)
@@ -27,7 +27,7 @@ class Morpheus::Cli::Roles
27
27
  @instances_interface = Morpheus::APIClient.new(@access_token,nil,nil, @appliance_url).instances
28
28
  @instance_types_interface = Morpheus::APIClient.new(@access_token,nil,nil, @appliance_url).instance_types
29
29
  @blueprints_interface = Morpheus::APIClient.new(@access_token,nil,nil, @appliance_url).blueprints
30
- @active_group_id = Morpheus::Cli::Groups.active_group
30
+ @active_group_id = Morpheus::Cli::Groups.active_groups[@appliance_name]
31
31
  end
32
32
 
33
33
  def handle(args)
@@ -88,6 +88,7 @@ class Morpheus::Cli::Roles
88
88
 
89
89
  def get(args)
90
90
  options = {}
91
+ params = {}
91
92
  optparse = Morpheus::Cli::OptionParser.new do |opts|
92
93
  opts.banner = subcommand_usage("[name]")
93
94
  opts.on('-p','--permissions', "Display Permissions") do |val|
@@ -116,7 +117,7 @@ class Morpheus::Cli::Roles
116
117
  options[:include_instance_type_access] = true
117
118
  options[:include_blueprint_access] = true
118
119
  end
119
- build_common_options(opts, options, [:json, :yaml, :csv, :fields, :dry_run, :remote])
120
+ build_common_options(opts, options, [:list, :query, :json, :yaml, :csv, :fields, :dry_run, :remote])
120
121
  opts.footer = "Get details about a role.\n" +
121
122
  "[name] is required. This is the name or id of a role."
122
123
  end
@@ -131,6 +132,9 @@ class Morpheus::Cli::Roles
131
132
  begin
132
133
  account = find_account_from_options(options)
133
134
  account_id = account ? account['id'] : nil
135
+
136
+ params.merge!(parse_query_options(options))
137
+
134
138
  @roles_interface.setopts(options)
135
139
  if options[:dry_run]
136
140
  if args[0].to_s =~ /\A\d{1,}\Z/
@@ -159,16 +163,8 @@ class Morpheus::Cli::Roles
159
163
  role = json_response['role']
160
164
  end
161
165
 
162
- if options[:json]
163
- puts as_json(json_response, options, "role")
164
- return 0
165
- elsif options[:yaml]
166
- puts as_yaml(json_response, options, "role")
167
- return 0
168
- elsif options[:csv]
169
- puts records_as_csv([json_response['role']], options)
170
- return 0
171
- end
166
+ render_result = render_with_format(json_response, options, 'role')
167
+ return 0 if render_result
172
168
 
173
169
  print cyan
174
170
  print_h1 "Role Details", options
@@ -179,7 +175,9 @@ class Morpheus::Cli::Roles
179
175
  "Description" => 'description',
180
176
  "Scope" => lambda {|it| it['scope'] },
181
177
  "Type" => lambda {|it| format_role_type(it) },
182
- "Multitenant" => lambda {|it| format_boolean(it['multitenant']) },
178
+ "Multitenant" => lambda {|it|
179
+ format_boolean(it['multitenant']).to_s + (it['multitenantLocked'] ? " (LOCKED)" : "")
180
+ },
183
181
  "Owner" => lambda {|it| role['owner'] ? role['owner']['name'] : '' },
184
182
  #"Account" => lambda {|it| it['account'] ? it['account']['name'] : '' },
185
183
  "Created" => lambda {|it| format_local_dt(it['dateCreated']) },
@@ -205,15 +203,40 @@ class Morpheus::Cli::Roles
205
203
  access: get_access_string(it['access']),
206
204
  }
207
205
  end
206
+ if options[:sort]
207
+ rows.sort! {|a,b| a[options[:sort]] <=> b[options[:sort]] }
208
+ end
209
+ if options[:direction] == 'desc'
210
+ rows.reverse!
211
+ end
212
+ if options[:phrase]
213
+ phrase_regexp = /#{Regexp.escape(options[:phrase])}/i
214
+ rows = rows.select {|row| row[:code].to_s =~ phrase_regexp || row[:name].to_s =~ phrase_regexp }
215
+ end
208
216
  print as_pretty_table(rows, [:code, :name, :access], options)
209
217
  else
210
- puts "Use --permissions to list permissions"
211
- end
212
-
213
- print_h2 "Group Access", options
218
+ print cyan,"Use --permissions to list permissions","\n"
219
+ end
220
+
221
+ print_h2 "Global Access", options
222
+ # role_access_rows = [
223
+ # {name: "Groups", access: get_access_string(json_response['globalSiteAccess']) },
224
+ # {name: "Clouds", access: get_access_string(json_response['globalZoneAccess']) },
225
+ # {name: "Instance Types", access: get_access_string(json_response['globalInstanceTypeAccess']) },
226
+ # {name: "Blueprints", access: get_access_string(json_response['globalAppTemplateAccess'] || json_response['globalBlueprintAccess']) }
227
+ # ]
228
+ # puts as_pretty_table(role_access_rows, [:name, :access], options)
229
+ puts as_pretty_table([json_response], [
230
+ {"Groups" => lambda {|it| get_access_string(it['globalSiteAccess']) } },
231
+ {"Clouds" => lambda {|it| get_access_string(it['globalZoneAccess']) } },
232
+ {"Instance Types" => lambda {|it| get_access_string(it['globalInstanceTypeAccess']) } },
233
+ {"Blueprints" => lambda {|it| get_access_string(it['globalAppTemplateAccess'] || it['globalBlueprintAccess']) } },
234
+ ], options)
235
+
236
+ #print_h2 "Group Access: #{get_access_string(json_response['globalSiteAccess'])}", options
214
237
  print cyan
215
- puts "Global Group Access: #{get_access_string(json_response['globalSiteAccess'])}\n\n"
216
238
  if json_response['globalSiteAccess'] == 'custom'
239
+ print_h2 "Group Access", options
217
240
  if options[:include_group_access]
218
241
  rows = json_response['sites'].collect do |it|
219
242
  {
@@ -223,14 +246,18 @@ class Morpheus::Cli::Roles
223
246
  end
224
247
  print as_pretty_table(rows, [:name, :access], options)
225
248
  else
226
- puts "Use --group-access to list custom access"
249
+ print cyan,"Use -g, --group-access to list custom access","\n"
227
250
  end
251
+ else
252
+ # print "\n"
253
+ # print cyan,bold,"Group Access: #{get_access_string(json_response['globalSiteAccess'])}",reset,"\n"
228
254
  end
229
-
230
- print_h2 "Cloud Access", options
255
+
231
256
  print cyan
232
- puts "Global Cloud Access: #{get_access_string(json_response['globalZoneAccess'])}\n\n"
257
+ #puts "Cloud Access: #{get_access_string(json_response['globalZoneAccess'])}"
258
+ #print "\n"
233
259
  if json_response['globalZoneAccess'] == 'custom'
260
+ print_h2 "Cloud Access", options
234
261
  if options[:include_cloud_access]
235
262
  rows = json_response['zones'].collect do |it|
236
263
  {
@@ -240,14 +267,18 @@ class Morpheus::Cli::Roles
240
267
  end
241
268
  print as_pretty_table(rows, [:name, :access], options)
242
269
  else
243
- puts "Use --cloud-access to list custom access"
270
+ print cyan,"Use -c, --cloud-access to list custom access","\n"
244
271
  end
272
+ else
273
+ # print "\n"
274
+ # print cyan,bold,"Cloud Access: #{get_access_string(json_response['globalZoneAccess'])}",reset,"\n"
245
275
  end
246
276
 
247
- print_h2 "Instance Type Access", options
248
277
  print cyan
249
- puts "Global Instance Type Access: #{get_access_string(json_response['globalInstanceTypeAccess'])}\n\n"
278
+ # puts "Instance Type Access: #{get_access_string(json_response['globalInstanceTypeAccess'])}"
279
+ # print "\n"
250
280
  if json_response['globalInstanceTypeAccess'] == 'custom'
281
+ print_h2 "Instance Type Access", options
251
282
  if options[:include_instance_type_access]
252
283
  rows = json_response['instanceTypePermissions'].collect do |it|
253
284
  {
@@ -257,16 +288,20 @@ class Morpheus::Cli::Roles
257
288
  end
258
289
  print as_pretty_table(rows, [:name, :access], options)
259
290
  else
260
- puts "Use --instance-type-access to list custom access"
291
+ print cyan,"Use -i, --instance-type-access to list custom access","\n"
261
292
  end
293
+ else
294
+ # print "\n"
295
+ # print cyan,bold,"Instance Type Access: #{get_access_string(json_response['globalInstanceTypeAccess'])}",reset,"\n"
262
296
  end
263
297
 
264
298
  blueprint_global_access = json_response['globalAppTemplateAccess'] || json_response['globalBlueprintAccess']
265
299
  blueprint_permissions = json_response['appTemplatePermissions'] || json_response['blueprintPermissions'] || []
266
- print_h2 "Blueprint Access", options
267
300
  print cyan
268
- puts "Global Blueprint Access: #{get_access_string(json_response['globalAppTemplateAccess'])}\n\n"
301
+ # print_h2 "Blueprint Access: #{get_access_string(json_response['globalAppTemplateAccess'])}", options
302
+ # print "\n"
269
303
  if blueprint_global_access == 'custom'
304
+ print_h2 "Blueprint Access", options
270
305
  if options[:include_blueprint_access]
271
306
  rows = blueprint_permissions.collect do |it|
272
307
  {
@@ -276,8 +311,11 @@ class Morpheus::Cli::Roles
276
311
  end
277
312
  print as_pretty_table(rows, [:name, :access], options)
278
313
  else
279
- puts "Use --blueprint-access to list custom access"
314
+ print cyan,"Use -b, --blueprint-access to list custom access","\n"
280
315
  end
316
+ else
317
+ # print "\n"
318
+ # print cyan,bold,"Blueprint Access: #{get_access_string(json_response['globalAppTemplateAccess'])}",reset,"\n"
281
319
  end
282
320
 
283
321
  print reset,"\n"
@@ -292,7 +330,7 @@ class Morpheus::Cli::Roles
292
330
  options = {}
293
331
  optparse = Morpheus::Cli::OptionParser.new do |opts|
294
332
  opts.banner = subcommand_usage("[role]")
295
- build_common_options(opts, options, [:json, :yaml, :csv, :fields, :dry_run, :remote])
333
+ build_common_options(opts, options, [:list, :json, :yaml, :csv, :fields, :dry_run, :remote])
296
334
  opts.footer = "List the permissions for a role.\n" +
297
335
  "[role] is required. This is the name or id of a role."
298
336
  end
@@ -358,9 +396,19 @@ class Morpheus::Cli::Roles
358
396
  access: get_access_string(it['access']),
359
397
  }
360
398
  end
399
+ if options[:sort]
400
+ rows.sort! {|a,b| a[options[:sort]] <=> b[options[:sort]] }
401
+ end
402
+ if options[:direction] == 'desc'
403
+ rows.reverse!
404
+ end
405
+ if options[:phrase]
406
+ phrase_regexp = /#{Regexp.escape(options[:phrase])}/i
407
+ rows = rows.select {|row| row[:code].to_s =~ phrase_regexp || row[:name].to_s =~ phrase_regexp }
408
+ end
361
409
  print as_pretty_table(rows, [:code, :name, :access], options)
362
410
  else
363
- puts "No permissions found?"
411
+ puts "No permissions found"
364
412
  end
365
413
 
366
414
  print reset,"\n"
@@ -376,12 +424,17 @@ class Morpheus::Cli::Roles
376
424
  options = {}
377
425
  params = {}
378
426
  optparse = Morpheus::Cli::OptionParser.new do |opts|
379
- opts.banner = subcommand_usage("[options]")
427
+ opts.banner = subcommand_usage("[name] [options]")
380
428
  build_option_type_options(opts, options, add_role_option_types)
381
429
  build_common_options(opts, options, [:options, :payload, :json, :dry_run, :remote])
382
430
  end
383
431
  optparse.parse!(args)
384
-
432
+ if args.count > 1
433
+ raise_command_error "wrong number of arguments, expected 0-1 and got (#{args.count}) #{args}\n#{optparse}"
434
+ end
435
+ if args[0]
436
+ options[:options]['authority'] = args[0]
437
+ end
385
438
  connect(options)
386
439
  begin
387
440
 
@@ -425,6 +478,10 @@ class Morpheus::Cli::Roles
425
478
  if role_payload['roleType'] == 'user'
426
479
  v_prompt = Morpheus::Cli::OptionTypes.prompt([{'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', 'displayOrder' => 5}], options[:options])
427
480
  role_payload['multitenant'] = ['on','true'].include?(v_prompt['multitenant'].to_s)
481
+ if role_payload['multitenant']
482
+ v_prompt = Morpheus::Cli::OptionTypes.prompt([{'fieldName' => 'multitenantLocked', 'fieldLabel' => 'Multitenant Locked', 'type' => 'checkbox', 'defaultValue' => 'off', 'description' => 'Prevents subtenants from branching off this role/modifying it. '}], options[:options])
483
+ role_payload['multitenantLocked'] = ['on','true'].include?(v_prompt['multitenantLocked'].to_s)
484
+ end
428
485
  end
429
486
  end
430
487
 
@@ -505,10 +562,10 @@ class Morpheus::Cli::Roles
505
562
  params.deep_merge!(passed_options)
506
563
  prompt_option_types = update_role_option_types()
507
564
  if !@is_master_account
508
- prompt_option_types = prompt_option_types.reject {|it| ['roleType', 'multitenant'].include?(it['fieldName']) }
565
+ prompt_option_types = prompt_option_types.reject {|it| ['roleType', 'multitenant','multitenantLocked'].include?(it['fieldName']) }
509
566
  end
510
567
  if role['roleType'] != 'user'
511
- prompt_option_types = prompt_option_types.reject {|it| ['multitenant'].include?(it['fieldName']) }
568
+ prompt_option_types = prompt_option_types.reject {|it| ['multitenant','multitenantLocked'].include?(it['fieldName']) }
512
569
  end
513
570
  #params = Morpheus::Cli::OptionTypes.prompt(prompt_option_types, options[:options], @api_client, options[:params])
514
571
 
@@ -1265,9 +1322,7 @@ class Morpheus::Cli::Roles
1265
1322
  {'fieldName' => 'roleType', 'fieldLabel' => 'Role Type', 'type' => 'select', 'selectOptions' => [{'name' => 'User Role', 'value' => 'user'}, {'name' => 'Account Role', 'value' => 'account'}], 'defaultValue' => 'user', 'displayOrder' => 3},
1266
1323
  {'fieldName' => 'baseRole', 'fieldLabel' => 'Copy From Role', 'type' => 'text', 'displayOrder' => 4},
1267
1324
  {'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', 'displayOrder' => 5},
1268
- # {'fieldName' => 'instanceLimits.maxStorage', 'fieldLabel' => 'Max Storage (bytes)', 'type' => 'text', 'displayOrder' => 8},
1269
- # {'fieldName' => 'instanceLimits.maxMemory', 'fieldLabel' => 'Max Memory (bytes)', 'type' => 'text', 'displayOrder' => 9},
1270
- # {'fieldName' => 'instanceLimits.maxCpu', 'fieldLabel' => 'CPU Count', 'type' => 'text', 'displayOrder' => 10},
1325
+ {'fieldName' => 'multitenantLocked', 'fieldLabel' => 'Multitenant Locked', 'type' => 'checkbox', 'defaultValue' => 'off', 'description' => 'Prevents subtenants from branching off this role/modifying it. ', 'displayOrder' => 6}
1271
1326
  ]
1272
1327
  end
1273
1328