morpheus-cli 5.5.3.2 → 6.0.1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (38) hide show
  1. checksums.yaml +4 -4
  2. data/Dockerfile +1 -1
  3. data/lib/morpheus/api/api_client.rb +8 -0
  4. data/lib/morpheus/api/cloud_resource_pools_interface.rb +28 -3
  5. data/lib/morpheus/api/containers_interface.rb +10 -0
  6. data/lib/morpheus/api/doc_interface.rb +1 -10
  7. data/lib/morpheus/api/jobs_interface.rb +2 -2
  8. data/lib/morpheus/api/key_pairs_interface.rb +9 -0
  9. data/lib/morpheus/api/network_floating_ips_interface.rb +37 -0
  10. data/lib/morpheus/api/resource_pool_groups_interface.rb +51 -0
  11. data/lib/morpheus/cli/cli_command.rb +17 -11
  12. data/lib/morpheus/cli/commands/appliance_settings_command.rb +5 -0
  13. data/lib/morpheus/cli/commands/apps.rb +12 -6
  14. data/lib/morpheus/cli/commands/catalog_item_types_command.rb +44 -12
  15. data/lib/morpheus/cli/commands/clusters.rb +23 -2
  16. data/lib/morpheus/cli/commands/containers_command.rb +129 -4
  17. data/lib/morpheus/cli/commands/doc.rb +14 -13
  18. data/lib/morpheus/cli/commands/hosts.rb +2 -0
  19. data/lib/morpheus/cli/commands/instances.rb +9 -3
  20. data/lib/morpheus/cli/commands/jobs_command.rb +50 -3
  21. data/lib/morpheus/cli/commands/key_pairs.rb +94 -33
  22. data/lib/morpheus/cli/commands/network_floating_ips.rb +109 -0
  23. data/lib/morpheus/cli/commands/reports_command.rb +8 -1
  24. data/lib/morpheus/cli/commands/resource_pool_groups_command.rb +586 -0
  25. data/lib/morpheus/cli/commands/roles.rb +10 -10
  26. data/lib/morpheus/cli/commands/service_catalog_command.rb +40 -2
  27. data/lib/morpheus/cli/commands/service_plans_command.rb +51 -22
  28. data/lib/morpheus/cli/commands/shell.rb +1 -1
  29. data/lib/morpheus/cli/commands/tasks.rb +130 -35
  30. data/lib/morpheus/cli/commands/workflows.rb +109 -23
  31. data/lib/morpheus/cli/mixins/infrastructure_helper.rb +148 -0
  32. data/lib/morpheus/cli/mixins/jobs_helper.rb +30 -3
  33. data/lib/morpheus/cli/mixins/processes_helper.rb +2 -26
  34. data/lib/morpheus/cli/mixins/provisioning_helper.rb +2 -1
  35. data/lib/morpheus/cli/option_types.rb +2 -2
  36. data/lib/morpheus/cli/version.rb +1 -1
  37. data/test/cli/doc_test.rb +1 -1
  38. metadata +6 -2
@@ -550,40 +550,101 @@ class Morpheus::Cli::Workflows
550
550
  target_type = nil
551
551
  instance_ids = []
552
552
  instances = []
553
+ instance_label = nil
553
554
  server_ids = []
554
555
  servers = []
555
- default_refresh_interval = 10
556
+ server_label = nil
557
+ default_refresh_interval = 5
558
+ all_target_types = ['appliance', 'instance', 'instance-label', 'server', 'server-label']
556
559
  optparse = Morpheus::Cli::OptionParser.new do |opts|
557
- opts.banner = subcommand_usage("[workflow] --instance [instance] [options]")
558
- opts.on('--instance INSTANCE', String, "Instance name or id to execute the workflow on. This option can be passed more than once.") do |val|
560
+ opts.banner = subcommand_usage("[workflow] [options]")
561
+ opts.on('--context-type VALUE', String, "Context Type, #{ored_list(all_target_types)}") do |val|
562
+ val = val.downcase
563
+ val = 'appliance' if val == 'none'
564
+ if target_type && target_type != val
565
+ raise ::OptionParser::InvalidOption.new("cannot be combined with another context (#{target_type})")
566
+ end
567
+ if !all_target_types.include?(val)
568
+ raise ::OptionParser::InvalidOption.new("'#{val}' is invalid. It must be one of the following: instance, instance-label, server, server-label or appliance")
569
+ end
570
+ target_type = val
571
+ end
572
+ opts.on('--target-type VALUE', String, "alias for context-type") do |val|
573
+ val = val.downcase
574
+ val = 'appliance' if val == 'none'
575
+ if target_type && target_type != val
576
+ raise ::OptionParser::InvalidOption.new("cannot be combined with another context (#{target_type})")
577
+ end
578
+ if !all_target_types.include?(val)
579
+ raise ::OptionParser::InvalidOption.new("'#{val}' is invalid. It must be one of the following: instance, instance-label, server, server-label or appliance")
580
+ end
581
+ target_type = val
582
+ end
583
+ opts.add_hidden_option('--target-type')
584
+ opts.on('--instance INSTANCE', String, "Instance name or id to target for execution. This option can be passed more than once.") do |val|
585
+ if target_type && target_type != 'instance'
586
+ raise ::OptionParser::InvalidOption.new("cannot be combined with another context (#{target_type})")
587
+ end
559
588
  target_type = 'instance'
560
589
  instance_ids << val
561
590
  end
562
- opts.on('--instances [LIST]', Array, "Instances, comma separated list of instance names or IDs.") do |list|
591
+ opts.on('--instances LIST', Array, "Instances, comma separated list of instance names or IDs.") do |list|
592
+ if target_type && target_type != 'instance'
593
+ raise ::OptionParser::InvalidOption.new("cannot be combined with another context (#{target_type})")
594
+ end
563
595
  target_type = 'instance'
564
596
  instance_ids = list.collect {|it| it.to_s.strip.empty? ? nil : it.to_s.strip }.compact.uniq
565
597
  end
566
- opts.on('--host HOST', String, "Host name or id to execute the workflow on. This option can be passed more than once.") do |val|
598
+ opts.on('--instance-label LABEL', String, "Instance Label") do |val|
599
+ if target_type && target_type != 'instance-label'
600
+ raise ::OptionParser::InvalidOption.new("cannot be combined with another context (#{target_type})")
601
+ end
602
+ target_type = 'instance-label'
603
+ instance_label = val
604
+ end
605
+ opts.on('--server SERVER', String, "Server name or id to target for execution. This option can be passed more than once.") do |val|
606
+ if target_type && target_type != 'server'
607
+ raise ::OptionParser::InvalidOption.new("cannot be combined with another context (#{target_type})")
608
+ end
567
609
  target_type = 'server'
568
610
  server_ids << val
569
611
  end
570
- opts.on('--hosts [LIST]', Array, "Hosts, comma separated list of host names or IDs.") do |list|
612
+ opts.on('--servers LIST', Array, "Servers, comma separated list of host names or IDs.") do |list|
613
+ if target_type && target_type != 'server'
614
+ raise ::OptionParser::InvalidOption.new("cannot be combined with another context (#{target_type})")
615
+ end
571
616
  target_type = 'server'
572
617
  server_ids = list.collect {|it| it.to_s.strip.empty? ? nil : it.to_s.strip }.compact.uniq
573
618
  end
574
- opts.on('--server HOST', String, "alias for --host") do |val|
619
+ opts.on('--server-label LABEL', String, "Server Label") do |val|
620
+ if target_type && target_type != 'server-label'
621
+ raise ::OptionParser::InvalidOption.new("cannot be combined with another context (#{target_type})")
622
+ end
623
+ target_type = 'server-label'
624
+ server_label = val
625
+ end
626
+ opts.on('--host HOST', String, "alias for --server") do |val|
627
+ if target_type && target_type != 'server'
628
+ raise ::OptionParser::InvalidOption.new("cannot be combined with another context (#{target_type})")
629
+ end
575
630
  target_type = 'server'
576
631
  server_ids << val
577
632
  end
578
- opts.on('--servers [LIST]', Array, "alias for --hosts") do |list|
633
+ opts.add_hidden_option('--host')
634
+ opts.on('--hosts HOSTS', Array, "alias for --servers") do |list|
635
+ if target_type && target_type != 'server'
636
+ raise ::OptionParser::InvalidOption.new("The --hosts option cannot be combined with another context (#{target_type})")
637
+ end
579
638
  target_type = 'server'
580
639
  server_ids = list.collect {|it| it.to_s.strip.empty? ? nil : it.to_s.strip }.compact.uniq
581
640
  end
641
+ opts.add_hidden_option('--hosts')
582
642
  opts.on('-a', '--appliance', "Execute on the appliance, the target is the appliance itself.") do
643
+ if target_type && target_type != 'appliance'
644
+ raise ::OptionParser::InvalidOption.new("The --appliance option cannot be combined with another context (#{target_type})")
645
+ end
583
646
  target_type = 'appliance'
584
647
  end
585
- opts.add_hidden_option('--server')
586
- opts.add_hidden_option('--servers')
587
648
  opts.on('--config [TEXT]', String, "Custom config") do |val|
588
649
  params['customConfig'] = val.to_s
589
650
  end
@@ -593,7 +654,7 @@ class Morpheus::Cli::Workflows
593
654
  opts.on(nil, '--no-refresh', "Do not refresh" ) do
594
655
  options[:no_refresh] = true
595
656
  end
596
- build_common_options(opts, options, [:payload, :options, :json, :dry_run, :remote])
657
+ build_standard_post_options(opts, options)
597
658
  end
598
659
  optparse.parse!(args)
599
660
  if args.count != 1
@@ -611,27 +672,55 @@ class Morpheus::Cli::Workflows
611
672
  payload = options[:payload]
612
673
  payload.deep_merge!({'job' => passed_options}) unless passed_options.empty?
613
674
  else
614
- if instance_ids.size > 0 && server_ids.size > 0
615
- raise_command_error "Pass --instance or --host, not both.\n#{optparse}"
616
- elsif instance_ids.size > 0
675
+ # prompt for target type and target
676
+ if target_type.nil?
677
+ # todo: Need api to fetch available Context Types for taskId/workflowId
678
+ available_target_types = get_available_contexts_for_workflow(workflow)
679
+ default_target_type = available_target_types.first ? available_target_types.first['name'] : nil
680
+ if !available_target_types.empty?
681
+ default_target_type = available_target_types.first ? available_target_types.first['name'] : nil
682
+ target_type = Morpheus::Cli::OptionTypes.prompt([{'switch' => 'context-type', 'fieldName' => 'targetType', 'fieldLabel' => 'Context Type', 'type' => 'select', 'selectOptions' => available_target_types, 'defaultValue' => default_target_type, 'required' => true, 'description' => 'Context Type determines the type of target(s) for the execution'}], options[:options], @api_client)['targetType']
683
+ end
684
+ end
685
+ if target_type
686
+ params['targetType'] = target_type
687
+ end
688
+ if target_type == 'instance'
689
+ if instance_ids.empty?
690
+ instance_ids_value = Morpheus::Cli::OptionTypes.prompt([{'switch' => 'instances', 'fieldName' => 'instances', 'fieldLabel' => 'Instance(s)', 'type' => 'text', 'required' => true, 'description' => 'Instances, comma separated list of instance names or IDs.'}], options[:options], @api_client)['instances']
691
+ instance_ids = parse_array(instance_ids_value)
692
+ end
617
693
  instance_ids.each do |instance_id|
618
694
  instance = find_instance_by_name_or_id(instance_id)
619
695
  return 1 if instance.nil?
620
696
  instances << instance
621
697
  end
622
698
  params['instances'] = instances.collect {|it| it['id'] }
623
- elsif server_ids.size > 0
699
+ elsif target_type == 'instance-label'
700
+ if instance_label.nil?
701
+ instance_label = Morpheus::Cli::OptionTypes.prompt([{'switch' => 'instance-label', 'fieldName' => 'instanceLabel', 'fieldLabel' => 'Instance Label', 'type' => 'text', 'required' => true, 'description' => 'Instance Label'}], options[:options], @api_client)['instanceLabel']
702
+ end
703
+ # params['config'] ||= {}
704
+ # params['config']['instanceLabel'] = instance_label
705
+ params['instanceLabel'] = instance_label
706
+ elsif target_type == 'server'
707
+ if server_ids.empty?
708
+ server_ids_value = Morpheus::Cli::OptionTypes.prompt([{'switch' => 'servers', 'fieldName' => 'servers', 'fieldLabel' => 'Server(s)', 'type' => 'text', 'required' => true, 'description' => 'Servers, comma separated list of server names or IDs.'}], options[:options], @api_client)['servers']
709
+ server_ids = parse_array(server_ids_value)
710
+ end
624
711
  server_ids.each do |server_id|
625
712
  server = find_server_by_name_or_id(server_id)
626
713
  return 1 if server.nil?
627
714
  servers << server
628
715
  end
629
716
  params['servers'] = servers.collect {|it| it['id'] }
630
- elsif target_type == 'appliance'
631
- # cool, run it locally.
632
- else
633
- # cool, run it locally.
634
- #raise_command_error "missing required option: --instance, --host or --appliance\n#{optparse}"
717
+ elsif target_type == 'server-label'
718
+ if server_label.nil?
719
+ server_label = Morpheus::Cli::OptionTypes.prompt([{'switch' => 'server-label', 'fieldName' => 'serverLabel', 'fieldLabel' => 'Server Label', 'type' => 'text', 'required' => true, 'description' => 'Server Label'}], options[:options], @api_client)['serverLabel']
720
+ end
721
+ # params['config'] ||= {}
722
+ # params['config']['serverLabel'] = server_label
723
+ params['serverLabel'] = server_label
635
724
  end
636
725
 
637
726
  # prompt to workflow optionTypes for customOptions
@@ -643,9 +732,6 @@ class Morpheus::Cli::Workflows
643
732
  }
644
733
  custom_options = Morpheus::Cli::OptionTypes.prompt(custom_option_types, options[:options], @api_client, {})
645
734
  end
646
- if target_type
647
- params['targetType'] = target_type
648
- end
649
735
  job_payload = {}
650
736
  job_payload.deep_merge!(params)
651
737
  passed_options.delete('customOptions')
@@ -39,6 +39,18 @@ module Morpheus::Cli::InfrastructureHelper
39
39
  @network_groups_interface
40
40
  end
41
41
 
42
+ def resource_pool_groups_interface
43
+ # @api_client.resource_pool_groups
44
+ raise "#{self.class} has not defined @resource_pool_groups_interface" if @resource_pool_groups_interface.nil?
45
+ @resource_pool_groups_interface
46
+ end
47
+
48
+ def resource_pools_interface
49
+ # @api_client.resource_pool_groups
50
+ raise "#{self.class} has not defined @cloud_resource_pools_interface" if @cloud_resource_pools_interface.nil?
51
+ @cloud_resource_pools_interface
52
+ end
53
+
42
54
  def network_types_interface
43
55
  # @api_client.network_types
44
56
  raise "#{self.class} has not defined @network_types_interface" if @network_types_interface.nil?
@@ -343,6 +355,86 @@ module Morpheus::Cli::InfrastructureHelper
343
355
  end
344
356
  end
345
357
 
358
+ def find_resource_pool_by_name_or_id(val)
359
+ if val.to_s =~ /\A\d{1,}\Z/
360
+ return find_resource_pool_by_id(val)
361
+ else
362
+ return find_resource_pool_by_name(val)
363
+ end
364
+ end
365
+
366
+ def find_resource_pool_by_id(id)
367
+ begin
368
+ json_response = resource_pools_interface.get_without_cloud(id.to_i)
369
+ return json_response['resourcePool']
370
+ rescue RestClient::Exception => e
371
+ if e.response && e.response.code == 404
372
+ print_red_alert "Resource Pool not found by id #{id}"
373
+ return nil
374
+ else
375
+ raise e
376
+ end
377
+ end
378
+ end
379
+
380
+ def find_resource_pool_by_name(name)
381
+ json_response = resource_pools_interface.list_without_cloud({name: name.to_s})
382
+ resource_pools = json_response['resourcePools']
383
+ if resource_pools.empty?
384
+ print_red_alert "Resource Pool not found by name #{name}"
385
+ return nil
386
+ elsif resource_pools.size > 1
387
+ print_red_alert "#{resource_pools.size} resource pools found by name #{name}"
388
+ rows = resource_pools.collect do |it|
389
+ {id: it['id'], name: it['name']}
390
+ end
391
+ puts as_pretty_table(rows, [:id, :name], {color:red})
392
+ return nil
393
+ else
394
+ return resource_pools[0]
395
+ end
396
+ end
397
+
398
+ def find_resource_pool_group_by_name_or_id(val)
399
+ if val.to_s =~ /\A\d{1,}\Z/
400
+ return find_resource_pool_group_by_id(val)
401
+ else
402
+ return find_resource_pool_group_by_name(val)
403
+ end
404
+ end
405
+
406
+ def find_resource_pool_group_by_id(id)
407
+ begin
408
+ json_response = resource_pool_groups_interface.get(id.to_i)
409
+ return json_response['resourcePoolGroup']
410
+ rescue RestClient::Exception => e
411
+ if e.response && e.response.code == 404
412
+ print_red_alert "Resource Pool Group not found by id #{id}"
413
+ return nil
414
+ else
415
+ raise e
416
+ end
417
+ end
418
+ end
419
+
420
+ def find_resource_pool_group_by_name(name)
421
+ json_response = resource_pool_groups_interface.list({name: name.to_s})
422
+ resource_pool_groups = json_response['resourcePoolGroups']
423
+ if resource_pool_groups.empty?
424
+ print_red_alert "Resource Pool Group not found by name #{name}"
425
+ return nil
426
+ elsif resource_pool_groups.size > 1
427
+ print_red_alert "#{resource_pool_groups.size} resource pool groups found by name #{name}"
428
+ rows = resource_pool_groups.collect do |it|
429
+ {id: it['id'], name: it['name']}
430
+ end
431
+ puts as_pretty_table(rows, [:id, :name], {color:red})
432
+ return nil
433
+ else
434
+ return resource_pool_groups[0]
435
+ end
436
+ end
437
+
346
438
  def prompt_for_network(network_id, options={}, required=true, field_name='network', field_label='Network')
347
439
  # Prompt for a Network, text input that searches by name or id
348
440
  network = nil
@@ -479,6 +571,62 @@ module Morpheus::Cli::InfrastructureHelper
479
571
  return {success:true, data: record_ids}
480
572
  end
481
573
 
574
+ def prompt_for_pools(params, options={}, api_client=nil, api_params={})
575
+ # Pools
576
+ pool_list = nil
577
+ pool_ids = nil
578
+ still_prompting = true
579
+ if params['pools'].nil?
580
+ still_prompting = true
581
+ while still_prompting do
582
+ v_prompt = Morpheus::Cli::OptionTypes.prompt([{'fieldName' => 'pools', 'type' => 'text', 'fieldLabel' => 'Pools', 'required' => false, 'description' => 'Pools to include, comma separated list of names or IDs.'}], options[:options])
583
+ unless v_prompt['pools'].to_s.empty?
584
+ pool_list = v_prompt['pools'].split(",").collect {|it| it.to_s.strip.empty? ? nil : it.to_s.strip }.compact.uniq
585
+ end
586
+ pool_ids = []
587
+ bad_ids = []
588
+ if pool_list && pool_list.size > 0
589
+ pool_list.each do |it|
590
+ found_pool = nil
591
+ begin
592
+ found_pool = find_resource_pool_by_name_or_id(it)
593
+ rescue SystemExit => cmdexit
594
+ end
595
+ if found_pool
596
+ pool_ids << found_pool['id']
597
+ else
598
+ bad_ids << it
599
+ end
600
+ end
601
+ end
602
+ still_prompting = bad_ids.empty? ? false : true
603
+ end
604
+ else
605
+ pool_list = params['pools']
606
+ still_prompting = false
607
+ pool_ids = []
608
+ bad_ids = []
609
+ if pool_list && pool_list.size > 0
610
+ pool_list.each do |it|
611
+ found_pool = nil
612
+ begin
613
+ found_pool = find_resource_pool_by_name_or_id(it)
614
+ rescue SystemExit => cmdexit
615
+ end
616
+ if found_pool
617
+ pool_ids << found_pool['id']
618
+ else
619
+ bad_ids << it
620
+ end
621
+ end
622
+ end
623
+ if !bad_ids.empty?
624
+ return {success:false, msg:"Pools not found: #{bad_ids}"}
625
+ end
626
+ end
627
+ return {success:true, data: pool_ids}
628
+ end
629
+
482
630
  def network_pool_server_list_column_definitions(options)
483
631
  {
484
632
  "ID" => 'id',
@@ -41,8 +41,8 @@ module Morpheus::Cli::JobsHelper
41
41
  "Created By" => lambda {|it| it[:created_by]},
42
42
  "Duration" => lambda {|it| it[:duration]},
43
43
  "Status" => lambda {|it| it[:status]},
44
- "Error" => lambda {|it| options[:details] ? it[:error] : truncate_string(it[:error], 32) },
45
- "Output" => lambda {|it| options[:details] ? it[:output] : truncate_string(it[:output], 32) }
44
+ "Error" => lambda {|it| options[:details] ? it[:error].to_s.strip : truncate_string(it[:error], 32).to_s.strip.gsub("\n", ' ') },
45
+ "Output" => lambda {|it| options[:details] ? it[:output].to_s.strip : truncate_string(it[:output], 32).to_s.strip.gsub("\n", ' ') }
46
46
  }
47
47
  print as_pretty_table(events.collect {|it| get_process_event_data(it)}, event_columns.upcase_keys!, options)
48
48
  end
@@ -147,7 +147,7 @@ module Morpheus::Cli::JobsHelper
147
147
  # refresh execution request until it is finished
148
148
  # returns json response data of the last execution request when status reached 'completed' or 'failed'
149
149
  def wait_for_job_execution(job_execution_id, options={}, print_output = true)
150
- refresh_interval = 10
150
+ refresh_interval = 5
151
151
  if options[:refresh_interval].to_i > 0
152
152
  refresh_interval = options[:refresh_interval]
153
153
  end
@@ -168,5 +168,32 @@ module Morpheus::Cli::JobsHelper
168
168
  end
169
169
 
170
170
 
171
+ def get_available_contexts_for_task(task)
172
+ #If task has target of resource, then CAN NOT run it local
173
+ targets = []
174
+ has_resource = task['executeTarget'] == 'resource'
175
+ if !has_resource
176
+ targets << {'name' => 'None', 'value' => 'appliance'}
177
+ end
178
+ targets << {'name' => 'Instance', 'value' => 'instance'}
179
+ targets << {'name' => 'Instance Label', 'value' => 'instance-label'}
180
+ targets << {'name' => 'Server', 'value' => 'server'}
181
+ targets << {'name' => 'Server Label', 'value' => 'server-label'}
182
+ return targets
183
+ end
184
+
185
+ def get_available_contexts_for_workflow(workflow)
186
+ #If any task has target of resource, then CAN NOT run it local
187
+ targets = []
188
+ has_resource = workflow['taskSetTasks'].find {|task| task['executeTarget'] == 'resource' }
189
+ if !has_resource
190
+ targets << {'name' => 'None', 'value' => 'appliance'}
191
+ end
192
+ targets << {'name' => 'Instance', 'value' => 'instance'}
193
+ targets << {'name' => 'Instance Label', 'value' => 'instance-label'}
194
+ targets << {'name' => 'Server', 'value' => 'server'}
195
+ targets << {'name' => 'Server Label', 'value' => 'server-label'}
196
+ return targets
197
+ end
171
198
 
172
199
  end
@@ -88,36 +88,12 @@ module Morpheus::Cli::ProcessesHelper
88
88
 
89
89
  # decolorize, remove newlines and truncate for table cell
90
90
  def format_process_error(process, max_length=20, return_color=cyan)
91
- #return max_length ? truncate_string(process['error'], max_length) : process['error']
92
- out = ""
93
- if process['error']
94
- # lines = process['error'].split("\n").collect {|line| reset + "#{line.to_s.strip}" }
95
- # lines = process['error'].split("\n").collect {|line| "#{line.to_s.strip}" }
96
- lines = [process['error']]
97
- out = lines.join(" ")
98
- if max_length
99
- out = truncate_string(out, max_length)
100
- end
101
- out << return_color if return_color
102
- end
103
- out
91
+ truncate_string(process['error'].to_s.strip.gsub("\n", " "), max_length)
104
92
  end
105
93
 
106
94
  # decolorize, remove newlines and truncate for table cell
107
95
  def format_process_output(process, max_length=20, return_color=cyan)
108
- return max_length ? truncate_string(process['output'], max_length) : process['output']
109
- out = ""
110
- if process['output']
111
- # lines = process['output'].split("\n").collect {|line| reset + "#{line.to_s.strip}" }
112
- # lines = process['error'].split("\n").collect {|line| "#{line.to_s.strip}" }
113
- lines = [process['output']]
114
- out = lines.join(" ")
115
- if max_length
116
- out = truncate_string(out, max_length)
117
- end
118
- out << return_color if return_color
119
- end
120
- out
96
+ truncate_string(process['output'].to_s.strip.gsub("\n", " "), max_length)
121
97
  end
122
98
 
123
99
  # format for either ETA/Duration
@@ -778,6 +778,7 @@ module Morpheus::Cli::ProvisioningHelper
778
778
 
779
779
  resource_pool_options = options_interface.options_for_source('zonePools', {groupId: group_id, siteId: group_id, zoneId: cloud_id, cloudId: cloud_id, instanceTypeId: instance_type['id'], layoutId: layout["id"]}.merge(service_plan.nil? ? {} : {planId: service_plan["id"]}))['data']
780
780
  resource_pool = resource_pool_options.find {|opt| opt['id'] == options[:resource_pool].to_i} if options[:resource_pool]
781
+ pool_required = provision_type["zonePoolRequired"]
781
782
 
782
783
  if resource_pool
783
784
  pool_id = resource_pool['id']
@@ -785,7 +786,7 @@ module Morpheus::Cli::ProvisioningHelper
785
786
  if options[:default_resource_pool]
786
787
  default_resource_pool = resource_pool_options.find {|rp| rp['id'] == options[:default_resource_pool]}
787
788
  end
788
- resource_pool_option_type ||= {'fieldContext' => 'config', 'fieldName' => 'resourcePoolId', 'type' => 'select', 'fieldLabel' => 'Resource Pool', 'selectOptions' => resource_pool_options, 'required' => true, 'skipSingleOption' => true, 'description' => 'Select resource pool.', 'defaultValue' => default_resource_pool ? default_resource_pool['name'] : nil}
789
+ resource_pool_option_type ||= {'fieldContext' => 'config', 'fieldName' => 'resourcePoolId', 'type' => 'select', 'fieldLabel' => 'Resource Pool', 'selectOptions' => resource_pool_options, 'required' => pool_required, 'skipSingleOption' => true, 'description' => 'Select resource pool.', 'defaultValue' => default_resource_pool ? default_resource_pool['name'] : nil}
789
790
  resource_pool_prompt = Morpheus::Cli::OptionTypes.prompt([resource_pool_option_type],options[:options],api_client,{}, no_prompt, true)
790
791
  resource_pool_prompt.deep_compact!
791
792
  payload.deep_merge!(resource_pool_prompt)
@@ -678,7 +678,7 @@ module Morpheus
678
678
  # print "Perhaps you meant one of these? #{ored_list(matched_options.collect {|i|i[value_field]}, 3)}\n"
679
679
  print "Try using value instead of name.\n"
680
680
  print "\n"
681
- exit 1
681
+ #exit 1
682
682
  elsif matched_options.size == 1
683
683
  matched_option = matched_options[0]
684
684
  end
@@ -814,7 +814,7 @@ module Morpheus
814
814
  api_params ||= {}
815
815
  api_params['query'] = query_value
816
816
  # skip refresh if you just hit enter
817
- if !query_value.empty?
817
+ if !query_value.empty? || (select_options.nil? || select_options.empty?)
818
818
  select_options = load_options(option_type, api_client, api_params, query_value)
819
819
  end
820
820
 
@@ -1,6 +1,6 @@
1
1
 
2
2
  module Morpheus
3
3
  module Cli
4
- VERSION = "5.5.3.2"
4
+ VERSION = "6.0.1"
5
5
  end
6
6
  end
data/test/cli/doc_test.rb CHANGED
@@ -28,7 +28,7 @@ class MorpheusTest::DocTest < MorpheusTest::TestCase
28
28
  def test_doc_get_unauthorized
29
29
  # authentication is NOT required for this api
30
30
  without_authentication do
31
- assert_success("doc get -q")
31
+ assert_error("doc get -q")
32
32
  end
33
33
  end
34
34
 
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.5.3.2
4
+ version: 6.0.1
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: 2023-02-21 00:00:00.000000000 Z
14
+ date: 2023-03-14 00:00:00.000000000 Z
15
15
  dependencies:
16
16
  - !ruby/object:Gem::Dependency
17
17
  name: bundler
@@ -280,6 +280,7 @@ files:
280
280
  - lib/morpheus/api/network_domain_records_interface.rb
281
281
  - lib/morpheus/api/network_domains_interface.rb
282
282
  - lib/morpheus/api/network_edge_clusters_interface.rb
283
+ - lib/morpheus/api/network_floating_ips_interface.rb
283
284
  - lib/morpheus/api/network_groups_interface.rb
284
285
  - lib/morpheus/api/network_pool_ips_interface.rb
285
286
  - lib/morpheus/api/network_pool_server_types_interface.rb
@@ -313,6 +314,7 @@ files:
313
314
  - lib/morpheus/api/provisioning_settings_interface.rb
314
315
  - lib/morpheus/api/read_interface.rb
315
316
  - lib/morpheus/api/reports_interface.rb
317
+ - lib/morpheus/api/resource_pool_groups_interface.rb
316
318
  - lib/morpheus/api/rest_interface.rb
317
319
  - lib/morpheus/api/roles_interface.rb
318
320
  - lib/morpheus/api/scale_thresholds_interface.rb
@@ -455,6 +457,7 @@ files:
455
457
  - lib/morpheus/cli/commands/network_domains_command.rb
456
458
  - lib/morpheus/cli/commands/network_edge_clusters_command.rb
457
459
  - lib/morpheus/cli/commands/network_firewalls_command.rb
460
+ - lib/morpheus/cli/commands/network_floating_ips.rb
458
461
  - lib/morpheus/cli/commands/network_groups_command.rb
459
462
  - lib/morpheus/cli/commands/network_pool_server_types.rb
460
463
  - lib/morpheus/cli/commands/network_pool_servers_command.rb
@@ -483,6 +486,7 @@ files:
483
486
  - lib/morpheus/cli/commands/recent_activity_command.rb
484
487
  - lib/morpheus/cli/commands/remote.rb
485
488
  - lib/morpheus/cli/commands/reports_command.rb
489
+ - lib/morpheus/cli/commands/resource_pool_groups_command.rb
486
490
  - lib/morpheus/cli/commands/rm_command.rb
487
491
  - lib/morpheus/cli/commands/roles.rb
488
492
  - lib/morpheus/cli/commands/scale_thresholds.rb