morpheus-cli 6.1.2 → 6.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 (30) 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/backup_jobs_interface.rb +4 -0
  5. data/lib/morpheus/api/backup_restores_interface.rb +23 -0
  6. data/lib/morpheus/api/backup_results_interface.rb +28 -0
  7. data/lib/morpheus/api/backups_interface.rb +5 -4
  8. data/lib/morpheus/api/monitoring_settings_interface.rb +0 -4
  9. data/lib/morpheus/cli/cli_command.rb +176 -46
  10. data/lib/morpheus/cli/commands/appliance_settings_command.rb +7 -19
  11. data/lib/morpheus/cli/commands/apps.rb +1 -1
  12. data/lib/morpheus/cli/commands/backup_jobs_command.rb +78 -20
  13. data/lib/morpheus/cli/commands/backup_restores_command.rb +144 -0
  14. data/lib/morpheus/cli/commands/backup_results_command.rb +149 -0
  15. data/lib/morpheus/cli/commands/backups_command.rb +215 -93
  16. data/lib/morpheus/cli/commands/hosts.rb +15 -2
  17. data/lib/morpheus/cli/commands/instances.rb +18 -3
  18. data/lib/morpheus/cli/commands/monitoring_settings.rb +0 -16
  19. data/lib/morpheus/cli/commands/plugins.rb +2 -1
  20. data/lib/morpheus/cli/commands/roles.rb +9 -9
  21. data/lib/morpheus/cli/commands/service_catalog_command.rb +50 -83
  22. data/lib/morpheus/cli/commands/user_sources_command.rb +36 -8
  23. data/lib/morpheus/cli/commands/view.rb +20 -20
  24. data/lib/morpheus/cli/mixins/backups_helper.rb +58 -0
  25. data/lib/morpheus/cli/mixins/print_helper.rb +27 -4
  26. data/lib/morpheus/cli/option_types.rb +10 -7
  27. data/lib/morpheus/cli/version.rb +1 -1
  28. data/lib/morpheus/formatters.rb +1 -1
  29. data/lib/morpheus/routes.rb +18 -3
  30. metadata +6 -2
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 683efa948a958a0fb4a6def11cb94ae525bdde8cbde0ba1d1aa313adeef3387d
4
- data.tar.gz: c19c0522892a7f96a8398811b89ea4324815f4494011bf6696be1fb362787304
3
+ metadata.gz: 3ede124df9259964d52e159be3a4097dd21987e35a20423ef81c63efb65be54d
4
+ data.tar.gz: 270fb5f083ecb5b7643aef13bb2b37e5e3ee02fd706ded8c394635376bbda14b
5
5
  SHA512:
6
- metadata.gz: a1b269a981ec0fcbeecbad62a91ba90f6e7429c26593579185a0a513d0ab5ea5e2394ab11d7bf138570314a418059b6a072e47fb04b0393010dc0f66a463db54
7
- data.tar.gz: 3c211238b4a2dae07c4da54659be1c43e9f0cf7aaf25f7bbfcf53f0c6a0482b43b87b44db541287dfd7201228902902e80c0a1b4a5b538207f3303174940cff9
6
+ metadata.gz: 86475908b6b602bcb9185e1e4a3c554f7fdb581e010e6e7e49e075124eb24d087bde16d90cb07b8dd8cb944da9d1f7de34f9d3d4252c9859811c4e9acd51eb7c
7
+ data.tar.gz: e1c6ed1cb7a06ec481687e516582131348a3f4292c618ebbe1a81c3b422e17d49f8ca85e65283d027e1516dd28c2ac35820691b90435a3933474c0ac44308c74
data/Dockerfile CHANGED
@@ -1,5 +1,5 @@
1
1
  FROM ruby:2.7.5
2
2
 
3
- RUN gem install morpheus-cli -v 6.1.2
3
+ RUN gem install morpheus-cli -v 6.2.1
4
4
 
5
5
  ENTRYPOINT ["morpheus"]
@@ -862,6 +862,14 @@ class Morpheus::APIClient
862
862
  Morpheus::BackupJobsInterface.new(common_interface_options).setopts(@options)
863
863
  end
864
864
 
865
+ def backup_results
866
+ Morpheus::BackupResultsInterface.new(common_interface_options).setopts(@options)
867
+ end
868
+
869
+ def backup_restores
870
+ Morpheus::BackupRestoresInterface.new(common_interface_options).setopts(@options)
871
+ end
872
+
865
873
  def backup_services
866
874
  Morpheus::BackupServicesInterface.new(common_interface_options).setopts(@options)
867
875
  end
@@ -6,4 +6,8 @@ class Morpheus::BackupJobsInterface < Morpheus::RestInterface
6
6
  "/api/backups/jobs"
7
7
  end
8
8
 
9
+ def execute_job(id, payload={}, params={}, headers={})
10
+ execute(method: :post, url: "#{base_path}/#{CGI::escape(id.to_s)}/execute", params: params, payload: payload, headers: headers)
11
+ end
12
+
9
13
  end
@@ -0,0 +1,23 @@
1
+ require 'morpheus/api/api_client'
2
+
3
+ class Morpheus::BackupRestoresInterface < Morpheus::APIClient
4
+
5
+ def base_path
6
+ "/api/backups/restores"
7
+ end
8
+
9
+ def list(params={}, headers={})
10
+ execute(method: :get, url: "#{base_path}", params: params, headers: headers)
11
+ end
12
+
13
+ def get(id, params={}, headers={})
14
+ validate_id!(id)
15
+ execute(method: :get, url: "#{base_path}/#{CGI::escape(id.to_s)}", params: params, headers: headers)
16
+ end
17
+
18
+ def destroy(id, params = {}, headers={})
19
+ validate_id!(id)
20
+ execute(method: :delete, url: "#{base_path}/#{CGI::escape(id.to_s)}", params: params, headers: headers)
21
+ end
22
+
23
+ end
@@ -0,0 +1,28 @@
1
+ require 'morpheus/api/api_client'
2
+
3
+ class Morpheus::BackupResultsInterface < Morpheus::APIClient
4
+
5
+ def base_path
6
+ "/api/backups/results"
7
+ end
8
+
9
+ def list(params={}, headers={})
10
+ execute(method: :get, url: "#{base_path}", params: params, headers: headers)
11
+ end
12
+
13
+ def get(id, params={}, headers={})
14
+ validate_id!(id)
15
+ execute(method: :get, url: "#{base_path}/#{CGI::escape(id.to_s)}", params: params, headers: headers)
16
+ end
17
+
18
+ def cancel(id, payload={}, params={}, headers={})
19
+ validate_id!(id)
20
+ execute(method: :put, url: "#{base_path}/#{CGI::escape(id.to_s)}", params: params, payload: payload, headers: headers)
21
+ end
22
+
23
+ def destroy(id, params = {}, headers={})
24
+ validate_id!(id)
25
+ execute(method: :delete, url: "#{base_path}/#{CGI::escape(id.to_s)}", params: params, headers: headers)
26
+ end
27
+
28
+ end
@@ -10,11 +10,12 @@ class Morpheus::BackupsInterface < Morpheus::RestInterface
10
10
  execute(method: :post, url: "#{base_path}/create", params: params, payload: payload, headers: headers)
11
11
  end
12
12
 
13
- def summary(params={})
14
- execute(method: :get, url: "#{base_path}/summary", params: params)
13
+ def summary(params={}, headers={})
14
+ execute(method: :get, url: "#{base_path}/summary", params: params, headers: headers)
15
15
  end
16
16
 
17
- def history(params={})
18
- execute(method: :get, url: "#{base_path}/history", params: params)
17
+ def execute_backup(id, payload={}, params={}, headers={})
18
+ execute(method: :post, url: "#{base_path}/#{CGI::escape(id.to_s)}/execute", params: params, payload: payload, headers: headers)
19
19
  end
20
+
20
21
  end
@@ -18,8 +18,4 @@ class Morpheus::MonitoringSettingsInterface < Morpheus::APIClient
18
18
  execute(method: :put, url: "#{base_path}/service-now", payload: payload, params: params, headers: headers)
19
19
  end
20
20
 
21
- def update_new_relic(payload, params={}, headers={})
22
- execute(method: :put, url: "#{base_path}/new-relic", payload: payload, params: params, headers: headers)
23
- end
24
-
25
21
  end
@@ -267,6 +267,11 @@ module Morpheus
267
267
  build_standard_post_options(opts, options, includes, excludes)
268
268
  end
269
269
 
270
+ # todo: this can go away once every command is using execute_api()
271
+ def build_standard_add_many_options(opts, options, includes=[], excludes=[])
272
+ build_standard_post_options(opts, options, includes + [:payloads], excludes)
273
+ end
274
+
270
275
  def build_standard_update_options(opts, options, includes=[], excludes=[])
271
276
  build_standard_put_options(opts, options, includes, excludes)
272
277
  end
@@ -551,13 +556,14 @@ module Morpheus
551
556
  end
552
557
  end
553
558
  end if all_option_keys.include?(:payloads)
554
- opts.on('--payloads-ignore-error', "Continue processing payloads if an error occurs. The default behavior is to stop processing when an error occurs.") do
555
- options[:payloads_ignore_error] = true
559
+ opts.on('--ignore-payload-errors', "Continue processing any remaining payloads if an error occurs. The default behavior is to stop processing when an error occurs.") do
560
+ options[:ignore_payload_errors] = true
556
561
  end if all_option_keys.include?(:payloads)
557
562
  when :payloads
558
- # added under when :payloads... just need it here to avoid unknown key error
563
+ # added with :payload too... just need it here to avoid unknown key error
564
+ # todo: remove this when every command supporting :payload is updated to use parse_payload(options) and execute_api(options)
559
565
  when :list
560
- opts.on( '-m', '--max MAX', "Max Results" ) do |val|
566
+ opts.on( '-m', '--max MAX', "Max Results (use -1 for all results)" ) do |val|
561
567
  # api supports max=-1 for all at the moment..
562
568
  if val.to_s == "all" || val.to_s == "-1"
563
569
  options[:max] = "-1"
@@ -1365,6 +1371,11 @@ module Morpheus
1365
1371
  # params['phrase'] = = args.join(" ")
1366
1372
  end
1367
1373
  params.merge!(parse_list_options(options))
1374
+ # query parameters are stored in :params
1375
+ # preserve anything already set in :params by the OptionParser or command specific logic..
1376
+ options[:params] ||= {}
1377
+ options[:params].deep_merge!(params)
1378
+ return options
1368
1379
  end
1369
1380
 
1370
1381
  # The default way to build options for the list command
@@ -1490,50 +1501,121 @@ module Morpheus
1490
1501
  return subtitles
1491
1502
  end
1492
1503
 
1493
- def parse_payload(options={}, object_key=nil)
1494
- payload = nil
1495
- if options[:payload]
1496
- payload = options[:payload]
1497
- # support -O OPTION switch on top of --payload
1498
- apply_options(payload, options, object_key)
1499
- end
1500
- payload
1501
- end
1502
-
1503
- def parse_payloads(options={}, object_key=nil, &block)
1504
+ # Construct the request query parameters from the standard command options
1505
+ # This populates :params with a map of parameters.
1506
+ # This should replace the use of parse_query_options, parse_list_options and parse_list_options! and parse_get_options
1507
+ # which are used everywhere eg. params.merge!(parse_query_options(options))
1508
+ def parse_options(options, params={})
1509
+ params = params ? params.dup : {}
1510
+ # parse_list_options!(args, options, params)
1511
+ # merge in options set with -Q max=3, --query max=3&sort=id
1512
+ params.deep_merge!(options[:query_filters]) if options[:query_filters]
1513
+ # query parameters are stored in :params
1514
+ # preserve anything already set in :params by the OptionParser or command specific logic..
1515
+ options[:params] ||= {}
1516
+ options[:params].deep_merge!(params)
1517
+ # (JSON) body parameters (JSON) are stored in :payload
1518
+ # if options[:payload]
1519
+ # end
1520
+ # ok now call execute_request(@api_client.whoami, :get, nil, options)
1521
+ return options
1522
+ end
1523
+
1524
+ # Parse payload(s) from the standard command options or else invoke the given block.
1525
+ # First looks for --payload or --payload options and if they are nil then the block is executed to establish the payload
1526
+ # By default this also merges all the values passed with -O, --options foo="bar" into payload under the object_key context.
1527
+ # and they are merged under the object_key context (if passed). This can be disabled with apply_options: false
1528
+ #
1529
+ # @param options [Hash] standard command options
1530
+ # @option options [Hash] :payload is a Hash of objects to serialize as the payload
1531
+ # @option options [Hash] :payloads is an array of payload objects@yield [street_name] Invokes the block with a street name for eac
1532
+ # This is silly and should go away, instead you should iterate in the terminal environment
1533
+ # @option options [Boolean] :apply_options can be set to false to skip -O options merge
1534
+ # @param object_key [String] The name of the object being constructed, -O --options will be merged under this context.
1535
+ # @return array of payloads
1536
+ # @yield [payload] Invokes the block to establish :payload (only when --payload(s) is not used)
1537
+ def parse_payload(options, object_key=nil, &block)
1538
+ # populate options[:params] here too
1539
+ parse_options(options)
1504
1540
  payloads = []
1541
+ # todo: only need to support a a single payload here, :payloads is silly and is going away
1505
1542
  if options[:payload]
1506
1543
  # --payload option was used
1507
1544
  payload = options[:payload]
1508
1545
  # support -O OPTION switch on top of --payload
1509
- apply_options(payload, options, object_key)
1546
+ apply_options(payload, options, object_key) unless options[:apply_options] == false
1510
1547
  payloads << payload
1511
1548
  elsif options[:payloads]
1512
1549
  # --payloads option was used
1513
1550
  payloads = options[:payloads]
1514
- # payloads.each { |it| apply_options(it, options, object_key) }
1515
- else
1516
- # default is to construct one using the block
1551
+ # support -O OPTION switch on top of --payloads
1552
+ payloads.each do |payload|
1553
+ apply_options(payload, options, object_key) unless options[:apply_options] == false
1554
+ end
1555
+ #else
1556
+ # should always do this, but a lot of methods rely on this returning nil right now, not {}
1557
+ # so for now only do it if block is given
1558
+ elsif block_given?
1559
+ # yield to block to construct the payload,
1560
+ # this is typically where prompting for inputs with optionTypes happens
1517
1561
  payload = {}
1518
- apply_options(payload, options, object_key)
1562
+ apply_options(payload, options, object_key) unless options[:apply_options] == false
1519
1563
  if block_given?
1520
- result = yield payload
1521
- #payload = result if result
1564
+ yield payload
1522
1565
  end
1523
1566
  payloads << payload
1567
+ options[:payload] = payload
1524
1568
  end
1525
- return payloads
1569
+ return payloads.first
1526
1570
  end
1527
1571
 
1528
- def process_payloads(payloads, options, &block)
1572
+ # support -O OPTION switch
1573
+ def apply_options(payload, options, object_key=nil)
1574
+ payload ||= {}
1575
+ if options[:options]
1576
+ # allow options[:object_key] to be used
1577
+ object_key = object_key ? object_key : options[:object_key]
1578
+ # could use parse_passed_options() here to support exclusion of certain options
1579
+ #passed_options = parse_passed_options(options, options[:apply_options] || {})
1580
+ passed_options = options[:options].reject {|k,v| k.is_a?(Symbol)}
1581
+ if object_key
1582
+ payload.deep_merge!({object_key => passed_options})
1583
+ else
1584
+ payload.deep_merge!(passed_options)
1585
+ end
1586
+ end
1587
+ payload
1588
+ end
1589
+
1590
+ # Executes the block with each payload (:payload or :payloads as parsed from --payload FILE and --payloads --PATH)
1591
+ # This is a wrapper to support execution on 1-N payloads
1592
+ # It also looks for --ignore-payload-errors behavior to continue processing
1593
+ # It is up to the block to actually make the api request
1594
+ # @param options [Hash] standard command options
1595
+ # @raise [Error] if there is no :payload or :payloads defined.
1596
+ # @yield [payload] Yields each payload to the block
1597
+ # @return parsed command result of the last return value of the block ie. [0, nil]
1598
+ def handle_each_payload(options, &block)
1599
+ payloads = []
1600
+ if options[:payloads]
1601
+ payloads = options[:payloads]
1602
+ elsif options[:payload]
1603
+ payloads << options[:payload]
1604
+ else
1605
+ raise "handle_each_payload() requires :payload or :payloads"
1606
+ end
1529
1607
  if !payloads.is_a?(Array) || payloads.compact.empty?
1530
- raise "process_payloads() requires an Array of at least one payload and instead got: (#{payloads.class}) #{payloads.inspect}"
1608
+ raise "handle_each_payload() requires a payload"
1609
+ end
1610
+ if !block_given?
1611
+ raise "handle_each_payload() requires a block to process the payload(s) with"
1531
1612
  end
1532
1613
  results = []
1533
1614
  payloads.each do |payload|
1534
1615
  begin
1535
1616
  result = yield payload
1536
- results << [0, nil]
1617
+ results << Morpheus::Cli::CliRegistry.parse_command_result(result)
1618
+ #results << [0, nil]
1537
1619
  rescue => e
1538
1620
  if options[:payloads_ignore_error]
1539
1621
  # results << [1, e.message]
@@ -1548,16 +1630,67 @@ module Morpheus
1548
1630
  return results.last
1549
1631
  end
1550
1632
 
1551
- def build_payload(options, object_key=nil)
1552
- payload = {}
1553
- if options[:payload]
1554
- parse_payload(options, object_key)
1633
+ # Standard handler for all commands that execute an api request.
1634
+ # This looks for a payload that can be set with --payload or --payloads or the default prompting
1635
+ # It is up to the block to handle the rendering behavior
1636
+ # @param api_interface [APIClient] An APIClient instance
1637
+ # @param api_method [String or Symbol] api method to invoke eg. :get, :create, :update, :destroy
1638
+ # @param args [Array] Array of arguments to be passed to the api method, usually just the [payload] or [payload, query_params]
1639
+ # @param options [Hash] options
1640
+ # @param object_key [String or Symbol] name of object being constructed, used by default rendering eg. --fields id,name
1641
+ # @yield [json_response] Invokes the block with the json response to handle rendering.
1642
+ # @return parsed command result of the last block.call(json_response)
1643
+ #
1644
+ # @example Fetch first 100 backups
1645
+ # execute_api(@api_client.backups, :list, [{"max" => 100}], options) do |json_response|
1646
+ # print_green_success "Fetched first #{json_response['backups'].size} of #{json_response['meta']['total']} backups"
1647
+ # end
1648
+ #
1649
+ # @example Create a backup, uses POST with options[:payload] as the body
1650
+ # @options[:payload] = {"backup" => { }}
1651
+ # execute_api(@api_client.backups, :create, nil, options, 'backup') do |json_response|
1652
+ # print_green_success "Added backup #{json_response['backup']['name']}"
1653
+ # end
1654
+ #
1655
+ def execute_api(api_interface, api_method, args, options, object_key=nil, &block)
1656
+ args = args.is_a?(Array) ? args : [args].compact
1657
+ if options[:payload] || options[:payloads]
1658
+ execute_api_payload(api_interface, api_method, args, options, object_key, &block)
1659
+ else
1660
+ execute_api_request(api_interface, api_method, args, options, object_key, &block)
1661
+ end
1662
+ end
1663
+
1664
+ # Standard handler for all POST commands that send a request for a payload
1665
+ # This supports the --payloads option for 1-N payloads, that is silly and will probably go away
1666
+ def execute_api_payload(api_interface, api_method, args, options, object_key=nil, &block)
1667
+ handle_each_payload(options) do |payload|
1668
+ execute_api_request(api_interface, api_method, (args || []) + [payload], options, object_key, &block)
1669
+ end
1670
+ end
1671
+
1672
+ # Standard handler for executing any API request
1673
+ # Supports the --dry-run option and standard rendering options --json, --yaml, --fields, --select, etc.
1674
+ def execute_api_request(api_interface, api_method, args, options, object_key=nil, &block)
1675
+ args = args.is_a?(Array) ? args : [args].compact # allow caller to pass [payload] or payload
1676
+ api_interface.setopts(options) # this is needed to support --timeout and --headers
1677
+ # this assumes the interface parameter order is: [payload, params] and not vice versa
1678
+ if options[:params] && !options[:params].empty?
1679
+ args << options[:params]
1680
+ end
1681
+ if options[:dry_run]
1682
+ # this is a dry run
1683
+ dry_response = api_interface.dry.send(api_method, *args)
1684
+ print_dry_run(dry_response, options)
1685
+ return 0, nil
1555
1686
  else
1556
- apply_options(payload, options, object_key)
1687
+ # execute the request and render the result
1688
+ json_response = api_interface.send(api_method, *args)
1689
+ return render_response(json_response, options, object_key, &block)
1557
1690
  end
1558
- return payload
1559
1691
  end
1560
1692
 
1693
+ # Parse an array from a string (csv)
1561
1694
  def parse_array(val, opts={})
1562
1695
  opts = {strip:true, allow_blank:false}.merge(opts)
1563
1696
  values = []
@@ -1580,19 +1713,6 @@ module Morpheus
1580
1713
  parse_array(val, {strip:true, allow_blank:false})
1581
1714
  end
1582
1715
 
1583
- # support -O OPTION switch
1584
- def apply_options(payload, options, object_key=nil)
1585
- payload ||= {}
1586
- if options[:options]
1587
- if object_key
1588
- payload.deep_merge!({object_key => options[:options].reject {|k,v| k.is_a?(Symbol)}})
1589
- else
1590
- payload.deep_merge!(options[:options].reject {|k,v| k.is_a?(Symbol)})
1591
- end
1592
- end
1593
- payload
1594
- end
1595
-
1596
1716
  def validate_outfile(outfile, options)
1597
1717
  full_filename = File.expand_path(outfile)
1598
1718
  outdir = File.dirname(full_filename)
@@ -1619,6 +1739,8 @@ module Morpheus
1619
1739
  # basic rendering for options :json, :yml, :csv, :quiet, and :outfile
1620
1740
  # returns the string rendered, or nil if nothing was rendered.
1621
1741
  def render_response(json_response, options, object_key=nil, &block)
1742
+ # allow options[:object_key] to be used
1743
+ object_key = object_key ? object_key : options[:object_key]
1622
1744
  output = nil
1623
1745
  if options[:select_fields]
1624
1746
  # support foos get --raw-select foo.x,foo.y,foo.z
@@ -1676,7 +1798,7 @@ module Morpheus
1676
1798
  else
1677
1799
  # no render happened, so calling the block if given
1678
1800
  if block_given?
1679
- result = yield
1801
+ result = yield json_response
1680
1802
  if result
1681
1803
  return result
1682
1804
  else
@@ -1903,6 +2025,14 @@ module Morpheus
1903
2025
  # add aliases here as needed
1904
2026
  if key == "cloud"
1905
2027
  key = "zone"
2028
+ elsif key == "site"
2029
+ key = "group"
2030
+ elsif key == "backupJob"
2031
+ key = "job"
2032
+ elsif key == "backupResult"
2033
+ key = "result"
2034
+ elsif key == "backupRestore"
2035
+ key = "restore"
1906
2036
  end
1907
2037
  return key
1908
2038
  end
@@ -231,9 +231,7 @@ class Morpheus::Cli::ApplianceSettingsCommand
231
231
  end
232
232
 
233
233
  begin
234
- payload = parse_payload(options)
235
-
236
- if !payload
234
+ parse_payload(options) do |payload|
237
235
  available_zone_types = @appliance_settings_interface.cloud_types['zoneTypes']
238
236
 
239
237
  if options[:enableZoneTypes]
@@ -283,29 +281,19 @@ class Morpheus::Cli::ApplianceSettingsCommand
283
281
  exit 1
284
282
  end
285
283
  end
286
-
287
- payload = {'applianceSettings' => params}
284
+ payload['applianceSettings'] = params
288
285
  end
289
-
290
- @appliance_settings_interface.setopts(options)
291
- if options[:dry_run]
292
- print_dry_run @appliance_settings_interface.dry.update(payload)
293
- return
294
- end
295
- json_response = @appliance_settings_interface.update(payload)
296
-
297
- if options[:json]
298
- puts as_json(json_response, options)
299
- elsif !options[:quiet]
286
+ execute_api(@appliance_settings_interface, :update, nil, options, "applianceSettings") do |json_response|
300
287
  if json_response['success']
301
288
  print_green_success "Updated appliance settings"
302
289
  get([] + (options[:remote] ? ["-r",options[:remote]] : []))
303
290
  else
304
- print_red_alert "Error updating appliance settings: #{json_response['msg'] || json_response['errors']}"
291
+ #todo: API should return 400 on error and then this is not needed
292
+ #print_red_alert "Error updating appliance settings"
293
+ print_rest_errors(json_response)
294
+ [1, "Error updating appliance settings"]
305
295
  end
306
296
  end
307
- return 0
308
-
309
297
  rescue RestClient::Exception => e
310
298
  print_rest_exception(e, options)
311
299
  exit 1
@@ -790,7 +790,7 @@ class Morpheus::Cli::Apps
790
790
  if !instance['connectionInfo'].nil? && instance['connectionInfo'].empty? == false
791
791
  connection_string = "#{instance['connectionInfo'][0]['ip']}:#{instance['connectionInfo'][0]['port']}"
792
792
  end
793
- {id: instance['id'], name: instance['name'], connection: connection_string, environment: instance['instanceContext'], nodes: (instance['containers'] || []).count, status: format_instance_status(instance), type: instance['instanceType']['name'], group: !instance['group'].nil? ? instance['group']['name'] : nil, cloud: !instance['cloud'].nil? ? instance['cloud']['name'] : nil}
793
+ {id: instance['id'], name: instance['displayName'] ? instance['displayName'] : instance['name'], connection: connection_string, environment: instance['instanceContext'], nodes: (instance['containers'] || []).count, status: format_instance_status(instance), type: instance['instanceType']['name'], group: !instance['group'].nil? ? instance['group']['name'] : nil, cloud: !instance['cloud'].nil? ? instance['cloud']['name'] : nil}
794
794
  end
795
795
  instances_rows = instances_rows.sort {|x,y| x[:id] <=> y[:id] } #oldest to newest..
796
796
  print cyan