morpheus-cli 5.3.3 → 5.3.4

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 (35) hide show
  1. checksums.yaml +4 -4
  2. data/Dockerfile +1 -1
  3. data/lib/morpheus/api/api_client.rb +12 -0
  4. data/lib/morpheus/api/clouds_interface.rb +4 -11
  5. data/lib/morpheus/api/load_balancer_pools_interface.rb +4 -4
  6. data/lib/morpheus/api/load_balancer_profiles_interface.rb +10 -0
  7. data/lib/morpheus/api/load_balancer_virtual_servers_interface.rb +4 -4
  8. data/lib/morpheus/api/network_routers_interface.rb +21 -0
  9. data/lib/morpheus/api/network_servers_interface.rb +42 -0
  10. data/lib/morpheus/api/rest_interface.rb +2 -1
  11. data/lib/morpheus/api/virtual_servers_interface.rb +9 -0
  12. data/lib/morpheus/cli/cli_command.rb +2 -1
  13. data/lib/morpheus/cli/cloud_resource_pools_command.rb +1 -1
  14. data/lib/morpheus/cli/clouds.rb +22 -40
  15. data/lib/morpheus/cli/hosts.rb +0 -1
  16. data/lib/morpheus/cli/instances.rb +111 -7
  17. data/lib/morpheus/cli/invoices_command.rb +42 -38
  18. data/lib/morpheus/cli/library_option_lists_command.rb +3 -3
  19. data/lib/morpheus/cli/load_balancer_pools.rb +111 -0
  20. data/lib/morpheus/cli/load_balancer_virtual_servers.rb +136 -0
  21. data/lib/morpheus/cli/load_balancers.rb +0 -155
  22. data/lib/morpheus/cli/mixins/load_balancers_helper.rb +2 -2
  23. data/lib/morpheus/cli/mixins/provisioning_helper.rb +32 -11
  24. data/lib/morpheus/cli/mixins/rest_command.rb +53 -37
  25. data/lib/morpheus/cli/mixins/secondary_rest_command.rb +488 -0
  26. data/lib/morpheus/cli/network_routers_command.rb +291 -7
  27. data/lib/morpheus/cli/network_scopes_command.rb +442 -0
  28. data/lib/morpheus/cli/networks_command.rb +2 -2
  29. data/lib/morpheus/cli/option_types.rb +20 -0
  30. data/lib/morpheus/cli/subnets_command.rb +7 -2
  31. data/lib/morpheus/cli/tasks.rb +25 -2
  32. data/lib/morpheus/cli/version.rb +1 -1
  33. data/lib/morpheus/cli/virtual_images.rb +2 -0
  34. data/lib/morpheus/cli.rb +9 -1
  35. metadata +9 -2
@@ -0,0 +1,442 @@
1
+ require 'rest_client'
2
+ require 'optparse'
3
+ require 'filesize'
4
+ require 'morpheus/cli/cli_command'
5
+ require 'morpheus/cli/mixins/infrastructure_helper'
6
+
7
+ class Morpheus::Cli::NetworkScopesCommand
8
+ include Morpheus::Cli::CliCommand
9
+ include Morpheus::Cli::ProvisioningHelper
10
+ include Morpheus::Cli::WhoamiHelper
11
+
12
+ set_command_name :'network-scopes'
13
+ register_subcommands :list, :get, :add, :update, :remove
14
+
15
+ def connect(opts)
16
+ @api_client = establish_remote_appliance_connection(opts)
17
+ @account_interface = @api_client.accounts
18
+ @network_servers_interface = @api_client.network_servers
19
+ @options_interface = @api_client.options
20
+ end
21
+
22
+ def handle(args)
23
+ handle_subcommand(args)
24
+ end
25
+
26
+ def list(args)
27
+ options = {}
28
+ optparse = Morpheus::Cli::OptionParser.new do |opts|
29
+ opts.banner = subcommand_usage("[server]")
30
+ build_common_options(opts, options, [:json, :yaml, :csv, :fields, :dry_run, :remote])
31
+ opts.footer = "List network scopes." + "\n" +
32
+ "[server] is required. This is the name or id of a network server."
33
+ end
34
+
35
+ optparse.parse!(args)
36
+ connect(options)
37
+
38
+ if args.count < 1
39
+ puts optparse
40
+ return 1
41
+ end
42
+
43
+ server = find_network_server(args[0])
44
+ if server.nil?
45
+ return 1
46
+ end
47
+
48
+ _list(server, options)
49
+ end
50
+
51
+ def _list(server, options)
52
+ @network_servers_interface.setopts(options)
53
+
54
+ if options[:dry_run]
55
+ print_dry_run @network_servers_interface.dry.list_scopes(server['id'])
56
+ return
57
+ end
58
+
59
+ if server['type']['hasScopes']
60
+ json_response = @network_servers_interface.list_scopes(server['id'])
61
+ render_response(json_response, options, 'networkScopes') do
62
+ print_h1 "Network Scopes For: #{server['name']}"
63
+ print cyan
64
+ print_scopes(server, json_response['networkScopes'])
65
+ end
66
+ else
67
+ print_red_alert "Scopes not supported for #{server['type']['name']}"
68
+ end
69
+ print reset
70
+ end
71
+
72
+ def get(args)
73
+ options = {}
74
+ optparse = Morpheus::Cli::OptionParser.new do |opts|
75
+ opts.banner = subcommand_usage("[server] [scope]")
76
+ build_common_options(opts, options, [:json, :yaml, :csv, :fields, :dry_run, :remote])
77
+ opts.footer = "Display details on a network scope." + "\n" +
78
+ "[server] is required. This is the name or id of a network server.\n" +
79
+ "[scope] is required. This is the id of a network scope.\n"
80
+ end
81
+
82
+ optparse.parse!(args)
83
+ connect(options)
84
+
85
+ if args.count < 2
86
+ puts optparse
87
+ return 1
88
+ end
89
+
90
+ server = find_network_server(args[0])
91
+ if server.nil?
92
+ return 1
93
+ end
94
+
95
+ _get(server, args[1], options)
96
+ end
97
+
98
+ def _get(server, scope_id, options)
99
+ @network_servers_interface.setopts(options)
100
+
101
+ if options[:dry_run]
102
+ if scope_id.to_s =~ /\A\d{1,}\Z/
103
+ print_dry_run @network_servers_interface.dry.get_scope(server['id'], scope_id.to_i)
104
+ else
105
+ print_dry_run @network_servers_interface.dry.list_scopes(server['id'], {name: scope_id})
106
+ end
107
+ return
108
+ end
109
+
110
+ if server['type']['hasScopes']
111
+ scope = find_scope(server['id'], scope_id)
112
+
113
+ return 1 if scope.nil?
114
+
115
+ render_response({networkScope: scope}, options, 'networkScope') do
116
+ print_h1 "Network Scope Details"
117
+ print cyan
118
+
119
+ description_cols = {
120
+ "ID" => lambda {|it| it['id']},
121
+ "Name" => lambda {|it| it['name']},
122
+ "Description" => lambda {|it| it['description']},
123
+ "Status" => lambda {|it| it['status']}
124
+ }
125
+
126
+ if is_master_account
127
+ description_cols["Visibility"] = lambda {|it| it['visibility']}
128
+ description_cols["Tenants"] = lambda {|it| it['tenants'].collect {|tenant| tenant['name']}.join(', ')}
129
+ end
130
+
131
+ server['type']['scopeOptionTypes'].sort_by {|it| it['displayOrder']}.each do |option_type|
132
+ description_cols[option_type['fieldLabel']] = lambda {|it| Morpheus::Cli::OptionTypes.get_option_value(it, option_type, true)}
133
+ end
134
+ print_description_list(description_cols, scope)
135
+ end
136
+ else
137
+ print_red_alert "Scopes not supported for #{server['type']['name']}"
138
+ end
139
+ println reset
140
+ end
141
+
142
+ def add(args)
143
+ options = {:options=>{}}
144
+ params = {}
145
+ optparse = Morpheus::Cli::OptionParser.new do|opts|
146
+ opts.banner = subcommand_usage("[server]")
147
+ opts.on( '--name NAME', "Name" ) do |val|
148
+ options[:name] = val.to_s
149
+ end
150
+ opts.on("--description [TEXT]", String, "Description") do |val|
151
+ options[:description] = val.to_s
152
+ end
153
+ add_perms_options(opts, options, ['plans', 'groups'])
154
+ build_common_options(opts, options, [:options, :payload, :json, :dry_run, :remote])
155
+ opts.footer = "Create a network scope." + "\n" +
156
+ "[server] is required. This is the name or id of a network server.\n";
157
+ end
158
+ optparse.parse!(args)
159
+ connect(options)
160
+ if args.count < 1
161
+ print_error Morpheus::Terminal.angry_prompt
162
+ puts_error "wrong number of arguments, expected 1 and got (#{args.count}) #{args.inspect}\n#{optparse}"
163
+ return 1
164
+ end
165
+
166
+ server = find_network_server(args[0])
167
+ if server.nil?
168
+ return 1
169
+ end
170
+
171
+ if !server['type']['hasScopes']
172
+ print_red_alert "Scopes not supported for #{server['type']['name']}"
173
+ return 1
174
+ end
175
+
176
+ if options[:payload]
177
+ payload = options[:payload]
178
+ else
179
+ params['name'] = Morpheus::Cli::OptionTypes.prompt([{'fieldName' => 'name', 'type' => 'text', 'fieldLabel' => 'Name', 'required' => true, 'description' => 'Name.'}],options[:options],@api_client,{})['name']
180
+ params['description'] = Morpheus::Cli::OptionTypes.prompt([{'fieldName' => 'description', 'type' => 'text', 'fieldLabel' => 'Description', 'required' => false, 'description' => 'Description.'}],options[:options],@api_client,{})['description']
181
+
182
+ option_types = server['type']['scopeOptionTypes'].sort_by {|it| it['displayOrder']}
183
+
184
+ # prompt options
185
+ option_result = Morpheus::Cli::OptionTypes.prompt(option_types, options[:options].deep_merge({:context_map => {'scope' => ''}}), @api_client, {'networkServerId' => server['id']}, nil, true)
186
+
187
+ # prompt permissions
188
+ perms = prompt_permissions(options, ['plans', 'groups'])
189
+ perms = {'visibility' => perms['resourcePool']['visibility'], 'tenants' => perms['tenantPermissions']['accounts'].collect {|it| {'id' => it}}}
190
+ payload = {'networkScope' => params.deep_merge(option_result).deep_merge(perms)}
191
+ end
192
+
193
+ @network_servers_interface.setopts(options)
194
+
195
+ if options[:dry_run]
196
+ print_dry_run @network_servers_interface.dry.create_scope(server['id'], payload)
197
+ return
198
+ end
199
+
200
+ json_response = @network_servers_interface.create_scope(server['id'], payload)
201
+ render_response(json_response, options, 'networkScope') do
202
+ print_green_success "\nAdded Network Scope #{json_response['id']}\n"
203
+ _get(server, json_response['id'], options)
204
+ end
205
+ end
206
+
207
+ def update(args)
208
+ options = {:options=>{}}
209
+ params = {}
210
+ optparse = Morpheus::Cli::OptionParser.new do|opts|
211
+ opts.banner = subcommand_usage("[server] [scope]")
212
+ opts.on( '--name NAME', "Name" ) do |val|
213
+ params['name'] = val.to_s
214
+ end
215
+ opts.on("--description [TEXT]", String, "Description") do |val|
216
+ params['description'] = val.to_s
217
+ end
218
+ add_perms_options(opts, options, ['plans', 'groups'])
219
+ build_common_options(opts, options, [:options, :payload, :json, :dry_run, :remote])
220
+ opts.footer = "Update a network scope.\n" +
221
+ "[server] is required. This is the name or id of an existing network server.\n" +
222
+ "[scope] is required. This is the name or id of an existing network scope."
223
+ end
224
+ optparse.parse!(args)
225
+ if args.count != 2
226
+ raise_command_error "wrong number of arguments, expected 2 and got (#{args.count}) #{args}\n#{optparse}"
227
+ end
228
+ connect(options)
229
+
230
+ server = find_network_server(args[0])
231
+ if server.nil?
232
+ return 1
233
+ end
234
+
235
+ if !server['type']['hasScopes']
236
+ print_red_alert "Scopes not supported for #{server['type']['name']}"
237
+ return 1
238
+ end
239
+
240
+ scope = find_scope(server['id'], args[1])
241
+ return 1 if scope.nil?
242
+
243
+ payload = parse_payload(options) || {'networkScope' => params}
244
+ payload['networkScope'].deep_merge!(options[:options].reject {|k,v| k.is_a?(Symbol) }) if options[:options] && !payload['networkScope'].nil?
245
+
246
+ if !options[:visibility].nil?
247
+ payload['networkScope']['visibility'] = options[:visibility]
248
+ end
249
+ if !options[:tenants].nil?
250
+ payload['networkScope']['tenants'] = options[:tenants].collect {|id| {id: id.to_i}}
251
+ end
252
+
253
+ if payload['networkScope'].empty?
254
+ option_types = server['type']['scopeOptionTypes'].sort_by {|it| it['displayOrder']}
255
+ print_green_success "Nothing to update"
256
+ println cyan
257
+ print Morpheus::Cli::OptionTypes.display_option_types_help(
258
+ option_types,
259
+ {:include_context => true, :context_map => {'scope' => ''}, :color => cyan, :title => "Available Scope Options"}
260
+ )
261
+ exit 1
262
+ end
263
+
264
+ #payload = {'networkScope' => scope.deep_merge(payload['networkScope'])}
265
+
266
+ @network_servers_interface.setopts(options)
267
+
268
+ if options[:dry_run]
269
+ print_dry_run @network_servers_interface.dry.update_scope(server['id'], scope['id'], payload)
270
+ return
271
+ end
272
+
273
+ json_response = @network_servers_interface.update_scope(server['id'], scope['id'], payload)
274
+ render_response(json_response, options, 'networkScope') do
275
+ print_green_success "\nUpdated Network Scope #{scope['id']}\n"
276
+ _get(server, scope['id'], options)
277
+ end
278
+ end
279
+
280
+ def remove(args)
281
+ options = {}
282
+ optparse = Morpheus::Cli::OptionParser.new do |opts|
283
+ opts.banner = subcommand_usage("[server] [scope]")
284
+ build_common_options(opts, options, [:auto_confirm, :json, :dry_run, :quiet, :remote])
285
+ opts.footer = "Delete a network scope.\n" +
286
+ "[server] is required. This is the name or id of an existing network server.\n" +
287
+ "[scope] is required. This is the name or id of an existing network scope."
288
+ end
289
+ optparse.parse!(args)
290
+ if args.count != 2
291
+ raise_command_error "wrong number of arguments, expected 2 and got (#{args.count}) #{args}\n#{optparse}"
292
+ end
293
+ connect(options)
294
+
295
+ server = find_network_server(args[0])
296
+ if server.nil?
297
+ return 1
298
+ end
299
+
300
+ if !server['type']['hasScopes']
301
+ print_red_alert "Scopes not supported for #{server['type']['name']}"
302
+ return 1
303
+ end
304
+
305
+ scope = find_scope(server['id'], args[1])
306
+ return 1 if scope.nil?
307
+
308
+ unless options[:yes] || ::Morpheus::Cli::OptionTypes::confirm("Are you sure you would like to remove the network scope '#{scope['name']}' from server '#{server['name']}'?", options)
309
+ return 9, "aborted command"
310
+ end
311
+
312
+ @network_servers_interface.setopts(options)
313
+
314
+ if options[:dry_run]
315
+ print_dry_run @network_servers_interface.dry.destroy_scope(server['id'], scope['id'])
316
+ return
317
+ end
318
+ json_response = @network_servers_interface.destroy_scope(server['id'], scope['id'])
319
+ render_response(json_response, options, 'networkScope') do
320
+ print_green_success "\nDeleted Network Scope #{scope['name']}\n"
321
+ _list(server, options)
322
+ end
323
+ end
324
+
325
+ private
326
+
327
+ def print_scopes(server, scopes)
328
+ if scopes.count > 0
329
+ cols = [:id, :name, :description, :status]
330
+ server['type']['scopeOptionTypes'].sort_by {|it| it['displayOrder']}.each do |option_type|
331
+ cols << option_type['fieldLabel']
332
+ end
333
+ cols += [:visibility, :tenants] if is_master_account
334
+ rows = scopes.collect do |it|
335
+ row = {
336
+ id: it['id'],
337
+ name: it['name'],
338
+ description: it['description'],
339
+ status: it['statusMessage'],
340
+ }
341
+ server['type']['scopeOptionTypes'].sort_by {|it| it['displayOrder']}.each do |option_type|
342
+ row[option_type['fieldLabel']] = Morpheus::Cli::OptionTypes.get_option_value(it, option_type, true)
343
+ end
344
+ if is_master_account
345
+ row = row.merge({
346
+ visibility: it['visibility'],
347
+ tenants: it['tenants'].collect {|it| it['name']}.join(', ')
348
+ })
349
+ end
350
+ row
351
+ end
352
+ puts as_pretty_table(rows, cols)
353
+ else
354
+ println "No Scopes\n"
355
+ end
356
+ end
357
+
358
+ def find_network_server(val)
359
+ if val.to_s =~ /\A\d{1,}\Z/
360
+ return find_network_server_by_id(val)
361
+ else
362
+ if server = find_network_server_by_name(val)
363
+ return find_network_server_by_id(server['id'])
364
+ end
365
+ end
366
+ end
367
+
368
+ def find_network_server_by_id(id)
369
+ begin
370
+ json_response = @network_servers_interface.get(id.to_i)
371
+ return json_response['networkServer']
372
+ rescue RestClient::Exception => e
373
+ if e.response && e.response.code == 404
374
+ print_red_alert "Network Server not found by id #{id}"
375
+ return nil
376
+ else
377
+ raise e
378
+ end
379
+ end
380
+ end
381
+
382
+ def find_network_server_by_name(name)
383
+ json_response = @network_servers_interface.list({phrase: name.to_s})
384
+ servers = json_response['networkServers']
385
+ if servers.empty?
386
+ print_red_alert "Network Server not found by name #{name}"
387
+ return nil
388
+ elsif servers.size > 1
389
+ print_red_alert "#{servers.size} network servers found by name #{name}"
390
+ rows = servers.collect do |it|
391
+ {id: it['id'], name: it['name']}
392
+ end
393
+ puts as_pretty_table(rows, [:id, :name], {color:red})
394
+ return nil
395
+ else
396
+ return servers[0]
397
+ end
398
+ end
399
+
400
+ def find_scope(server_id, val)
401
+ if val.to_s =~ /\A\d{1,}\Z/
402
+ return find_scope_by_id(server_id, val)
403
+ else
404
+ if scope = find_scope_by_name(server_id, val)
405
+ return find_scope_by_id(server_id, scope['id'])
406
+ end
407
+ end
408
+ end
409
+
410
+ def find_scope_by_id(server_id, scope_id)
411
+ begin
412
+ json_response = @network_servers_interface.get_scope(server_id, scope_id.to_i)
413
+ return json_response['networkScope']
414
+ rescue RestClient::Exception => e
415
+ if e.response && e.response.code == 404
416
+ print_red_alert "Network Scope not found by id #{id}"
417
+ return nil
418
+ else
419
+ raise e
420
+ end
421
+ end
422
+ end
423
+
424
+ def find_scope_by_name(server_id, name)
425
+ json_response = @network_servers_interface.list_scope(server_id, {phrase: name.to_s})
426
+ scopes = json_response['networkScopes']
427
+ if scopes.empty?
428
+ print_red_alert "Network Scope not found by name #{name}"
429
+ return nil
430
+ elsif scopes.size > 1
431
+ print_red_alert "#{scopes.size} network scopes found by name #{name}"
432
+ rows = scopes.collect do |it|
433
+ {id: it['id'], name: it['name']}
434
+ end
435
+ puts as_pretty_table(rows, [:id, :name], {color:red})
436
+ return nil
437
+ else
438
+ return scopes[0]
439
+ end
440
+ end
441
+
442
+ end
@@ -617,6 +617,7 @@ class Morpheus::Cli::NetworksCommand
617
617
  if network_type_option_types && network_type_option_types.size > 0
618
618
  api_params = {}
619
619
  api_params['network.site.id'] = group ? group['id'] : 'shared'
620
+ api_params['network.zone.id'] = cloud['id'] if !cloud.nil?
620
621
  api_params['network.type.id'] = network_type['id']
621
622
  api_params['network.networkServer.id'] = network_server_id if !network_server_id.nil?
622
623
  network_type_params = Morpheus::Cli::OptionTypes.prompt(network_type_option_types,(options[:options] || {}).merge(payload),@api_client, api_params)
@@ -660,8 +661,7 @@ class Morpheus::Cli::NetworksCommand
660
661
  payload['network']['pool'] = options['pool'].to_i
661
662
  else
662
663
  # todo: select dropdown
663
- # v_prompt = Morpheus::Cli::OptionTypes.prompt([{'fieldName' => 'pool', 'fieldLabel' => 'Network Pool', 'type' => 'select', 'optionSource' => 'networkPools', 'required' => false, 'description' => ''}], options, @api_client, {zoneId: cloud['id']})
664
- v_prompt = Morpheus::Cli::OptionTypes.prompt([{'fieldName' => 'pool', 'fieldLabel' => 'Network Pool', 'type' => 'text', 'required' => false, 'description' => ''}], options)
664
+ v_prompt = Morpheus::Cli::OptionTypes.prompt([{'fieldName' => 'pool', 'fieldLabel' => 'Network Pool', 'type' => 'select', 'optionSource' => 'networkPools', 'required' => false, 'description' => ''}], options, @api_client, api_params)
665
665
  payload['network']['pool'] = v_prompt['pool'].to_i if v_prompt['pool']
666
666
  end
667
667
  end
@@ -992,6 +992,26 @@ module Morpheus
992
992
  return option_type['required'] ? '' : ' (optional)'
993
993
  end
994
994
  end
995
+
996
+ def self.get_option_value(obj, option_type, format=false)
997
+ context = option_type['fieldContext'] == 'config' ? obj['config'] : obj
998
+ name = option_type['fieldName']
999
+ tokens = name.split('.')
1000
+
1001
+ if tokens.length > 1
1002
+ tokens.slice(0, tokens.length - 1).each do |token|
1003
+ context = context[name = token]
1004
+ end
1005
+ end
1006
+
1007
+ rtn = context[name]
1008
+
1009
+ if format
1010
+ rtn = (rtn ? 'On' : 'Off') if option_type['type'] == 'checkbox'
1011
+ rtn = rtn.join(', ') if rtn.is_a?(Array)
1012
+ end
1013
+ rtn
1014
+ end
995
1015
  end
996
1016
  end
997
1017
  end
@@ -350,8 +350,13 @@ class Morpheus::Cli::SubnetsCommand
350
350
  if subnet_type_option_types && subnet_type_option_types.size > 0
351
351
  # prompt for option types
352
352
  subnet_type_params = Morpheus::Cli::OptionTypes.prompt(subnet_type_option_types,options[:options],@api_client, {networkId: network['id'], zoneId: network['zone']['id']})
353
- payload['subnet'].deep_merge!(subnet_type_params['subnet'])
354
-
353
+ if subnet_type_params['subnet']
354
+ payload['subnet'].deep_merge!(subnet_type_params['subnet'])
355
+ end
356
+ if subnet_type_params['config']
357
+ payload['subnet']['config'] ||= {}
358
+ payload['subnet']['config'].deep_merge!(subnet_type_params['config'])
359
+ end
355
360
  else
356
361
  # DEFAULT INPUTS
357
362
 
@@ -198,7 +198,14 @@ class Morpheus::Cli::Tasks
198
198
  end
199
199
  else
200
200
  task_option_types << optionType
201
- task_option_columns << {(optionType['fieldLabel']) => lambda {|it| task['taskOptions'][optionType['fieldName']] || optionType['defaultValue'] } }
201
+ task_option_columns << {(optionType['fieldLabel']) => lambda {|it|
202
+ value = task['taskOptions'][optionType['code']] || task['taskOptions'][optionType['fieldName']] || optionType['defaultValue']
203
+ if optionType['type'] == 'checkbox'
204
+ value.to_s.empty? ? 'off' : value.to_s
205
+ else
206
+ value.to_s
207
+ end
208
+ } }
202
209
  end
203
210
  end
204
211
  else
@@ -430,6 +437,10 @@ class Morpheus::Cli::Tasks
430
437
  if it['fieldContext'].nil? || it['fieldContext'] == ''
431
438
  it['fieldContext'] = 'taskOptions'
432
439
  end
440
+ # taskOptions should prompt for code instead of fieldName, oy vey
441
+ if it['fieldContext'] == 'taskOptions'
442
+ it['fieldName'] = it['code']
443
+ end
433
444
  end
434
445
  end
435
446
  # inject file_params into options for file-content prompt
@@ -444,8 +455,20 @@ class Morpheus::Cli::Tasks
444
455
  end
445
456
  end
446
457
  # prompt
458
+
459
+ # tasks are different in that they use the optionType code instead of fieldName for the key values
447
460
  input_options = Morpheus::Cli::OptionTypes.prompt(task_option_types, options[:options],@api_client, options[:params])
448
- payload.deep_merge!({'task' => input_options}) unless input_options.empty?
461
+ # flatten taskOptions as serverside expects
462
+ if input_options['taskOptions']
463
+ input_options['taskOptions'] = Morpheus::RestClient.grails_params(input_options['taskOptions'])
464
+ # remove "off" checkbox values, like the UI does
465
+ input_options['taskOptions'].keys.each do |k|
466
+ if input_options['taskOptions'][k] == "off"
467
+ input_options['taskOptions'].delete(k)
468
+ end
469
+ end
470
+ end
471
+ payload.deep_merge!({'task' => input_options}) unless input_options.empty?
449
472
 
450
473
 
451
474
  # Target Options
@@ -1,6 +1,6 @@
1
1
 
2
2
  module Morpheus
3
3
  module Cli
4
- VERSION = "5.3.3"
4
+ VERSION = "5.3.4"
5
5
  end
6
6
  end
@@ -83,6 +83,7 @@ class Morpheus::Cli::VirtualImages
83
83
  json_response = @virtual_images_interface.list(params)
84
84
  images = json_response['virtualImages']
85
85
  render_response(json_response, options, 'virtualImages') do
86
+ get_available_virtual_image_types() # preload
86
87
  title = "Morpheus Virtual Images"
87
88
  subtitles = parse_list_subtitles(options)
88
89
  if options[:imageType]
@@ -192,6 +193,7 @@ EOT
192
193
  image_type = virtual_image_type_for_name_or_code(image['imageType'])
193
194
  image_type_display = image_type ? "#{image_type['name']}" : image['imageType']
194
195
  render_response(json_response, options, 'virtualImage') do
196
+ get_available_virtual_image_types() # preload
195
197
  print_h1 "Virtual Image Details", [], options
196
198
  description_cols = {
197
199
  "ID" => 'id',
data/lib/morpheus/cli.rb CHANGED
@@ -50,7 +50,7 @@ module Morpheus
50
50
  Dir[File.dirname(__FILE__) + "/api/**/*.rb"].each {|file| load file }
51
51
 
52
52
  # load mixins
53
- Dir[File.dirname(__FILE__) + "/cli/mixins/*.rb"].each {|file| load file }
53
+ Dir[File.dirname(__FILE__) + "/cli/mixins/**/*.rb"].each {|file| load file }
54
54
 
55
55
  # load commands
56
56
  # Dir[File.dirname(__FILE__) + "/cli/*.rb"].each {|file| load file }
@@ -93,6 +93,13 @@ module Morpheus
93
93
  load 'morpheus/cli/cloud_folders_command.rb'
94
94
  load 'morpheus/cli/hosts.rb'
95
95
  load 'morpheus/cli/load_balancers.rb'
96
+ load 'morpheus/cli/load_balancer_virtual_servers.rb'
97
+ # load 'morpheus/cli/load_balancer_monitors.rb'
98
+ # load 'morpheus/cli/load_balancer_nodes.rb'
99
+ # load 'morpheus/cli/load_balancer_policies.rb'
100
+ load 'morpheus/cli/load_balancer_pools.rb'
101
+ # load 'morpheus/cli/load_balancer_profiles.rb'
102
+ # load 'morpheus/cli/load_balancer_scripts.rb'
96
103
  load 'morpheus/cli/load_balancer_types.rb'
97
104
  load 'morpheus/cli/shell.rb'
98
105
  load 'morpheus/cli/tasks.rb'
@@ -186,6 +193,7 @@ module Morpheus
186
193
  load 'morpheus/cli/vdi_gateways_command.rb'
187
194
  load 'morpheus/cli/vdi_command.rb' # (VDI persona)
188
195
  load 'morpheus/cli/certificates_command.rb' # (VDI persona)
196
+ #load 'morpheus/cli/network_scopes_command.rb'
189
197
  # add new commands here...
190
198
 
191
199
  end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: morpheus-cli
3
3
  version: !ruby/object:Gem::Version
4
- version: 5.3.3
4
+ version: 5.3.4
5
5
  platform: ruby
6
6
  authors:
7
7
  - David Estes
@@ -11,7 +11,7 @@ authors:
11
11
  autorequire:
12
12
  bindir: bin
13
13
  cert_chain: []
14
- date: 2021-09-14 00:00:00.000000000 Z
14
+ date: 2021-11-09 00:00:00.000000000 Z
15
15
  dependencies:
16
16
  - !ruby/object:Gem::Dependency
17
17
  name: bundler
@@ -237,6 +237,7 @@ files:
237
237
  - lib/morpheus/api/library_spec_templates_interface.rb
238
238
  - lib/morpheus/api/license_interface.rb
239
239
  - lib/morpheus/api/load_balancer_pools_interface.rb
240
+ - lib/morpheus/api/load_balancer_profiles_interface.rb
240
241
  - lib/morpheus/api/load_balancer_types_interface.rb
241
242
  - lib/morpheus/api/load_balancer_virtual_servers_interface.rb
242
243
  - lib/morpheus/api/load_balancers_interface.rb
@@ -258,6 +259,7 @@ files:
258
259
  - lib/morpheus/api/network_proxies_interface.rb
259
260
  - lib/morpheus/api/network_routers_interface.rb
260
261
  - lib/morpheus/api/network_security_servers_interface.rb
262
+ - lib/morpheus/api/network_servers_interface.rb
261
263
  - lib/morpheus/api/network_services_interface.rb
262
264
  - lib/morpheus/api/network_subnets_interface.rb
263
265
  - lib/morpheus/api/network_types_interface.rb
@@ -307,6 +309,7 @@ files:
307
309
  - lib/morpheus/api/vdi_interface.rb
308
310
  - lib/morpheus/api/vdi_pools_interface.rb
309
311
  - lib/morpheus/api/virtual_images_interface.rb
312
+ - lib/morpheus/api/virtual_servers_interface.rb
310
313
  - lib/morpheus/api/whitelabel_settings_interface.rb
311
314
  - lib/morpheus/api/whoami_interface.rb
312
315
  - lib/morpheus/api/wiki_interface.rb
@@ -397,7 +400,9 @@ files:
397
400
  - lib/morpheus/cli/library_spec_templates_command.rb
398
401
  - lib/morpheus/cli/library_upgrades_command.rb
399
402
  - lib/morpheus/cli/license.rb
403
+ - lib/morpheus/cli/load_balancer_pools.rb
400
404
  - lib/morpheus/cli/load_balancer_types.rb
405
+ - lib/morpheus/cli/load_balancer_virtual_servers.rb
401
406
  - lib/morpheus/cli/load_balancers.rb
402
407
  - lib/morpheus/cli/log_settings_command.rb
403
408
  - lib/morpheus/cli/login.rb
@@ -418,6 +423,7 @@ files:
418
423
  - lib/morpheus/cli/mixins/provisioning_helper.rb
419
424
  - lib/morpheus/cli/mixins/remote_helper.rb
420
425
  - lib/morpheus/cli/mixins/rest_command.rb
426
+ - lib/morpheus/cli/mixins/secondary_rest_command.rb
421
427
  - lib/morpheus/cli/mixins/vdi_helper.rb
422
428
  - lib/morpheus/cli/mixins/whoami_helper.rb
423
429
  - lib/morpheus/cli/monitoring_alerts_command.rb
@@ -432,6 +438,7 @@ files:
432
438
  - lib/morpheus/cli/network_pools_command.rb
433
439
  - lib/morpheus/cli/network_proxies_command.rb
434
440
  - lib/morpheus/cli/network_routers_command.rb
441
+ - lib/morpheus/cli/network_scopes_command.rb
435
442
  - lib/morpheus/cli/network_services_command.rb
436
443
  - lib/morpheus/cli/networks_command.rb
437
444
  - lib/morpheus/cli/option_parser.rb