morpheus-cli 4.1.4 → 4.1.5

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 (76) hide show
  1. checksums.yaml +4 -4
  2. data/lib/morpheus.rb +5 -0
  3. data/lib/morpheus/api.rb +2 -2
  4. data/lib/morpheus/api/api_client.rb +47 -12
  5. data/lib/morpheus/api/appliance_settings_interface.rb +30 -0
  6. data/lib/morpheus/api/auth_interface.rb +14 -10
  7. data/lib/morpheus/api/clouds_interface.rb +7 -0
  8. data/lib/morpheus/api/clusters_interface.rb +17 -5
  9. data/lib/morpheus/api/custom_instance_types_interface.rb +2 -3
  10. data/lib/morpheus/api/deployments_interface.rb +7 -0
  11. data/lib/morpheus/api/execute_schedules_interface.rb +2 -3
  12. data/lib/morpheus/api/groups_interface.rb +7 -0
  13. data/lib/morpheus/api/license_interface.rb +9 -2
  14. data/lib/morpheus/api/load_balancers_interface.rb +7 -0
  15. data/lib/morpheus/api/logs_interface.rb +11 -2
  16. data/lib/morpheus/api/monitoring_alerts_interface.rb +45 -0
  17. data/lib/morpheus/api/monitoring_checks_interface.rb +2 -2
  18. data/lib/morpheus/api/monitoring_interface.rb +13 -8
  19. data/lib/morpheus/api/power_schedules_interface.rb +2 -3
  20. data/lib/morpheus/api/servers_interface.rb +5 -2
  21. data/lib/morpheus/api/setup_interface.rb +25 -7
  22. data/lib/morpheus/api/task_sets_interface.rb +7 -1
  23. data/lib/morpheus/api/tasks_interface.rb +7 -0
  24. data/lib/morpheus/api/virtual_images_interface.rb +2 -3
  25. data/lib/morpheus/api/whitelabel_settings_interface.rb +60 -0
  26. data/lib/morpheus/cli.rb +18 -14
  27. data/lib/morpheus/cli/access_token_command.rb +18 -2
  28. data/lib/morpheus/cli/appliance_settings_command.rb +303 -0
  29. data/lib/morpheus/cli/apps.rb +4 -3
  30. data/lib/morpheus/cli/archives_command.rb +0 -21
  31. data/lib/morpheus/cli/blueprints_command.rb +2 -2
  32. data/lib/morpheus/cli/cli_command.rb +32 -8
  33. data/lib/morpheus/cli/clouds.rb +6 -11
  34. data/lib/morpheus/cli/clusters.rb +346 -117
  35. data/lib/morpheus/cli/command_error.rb +4 -0
  36. data/lib/morpheus/cli/commands/standard/man_command.rb +1 -1
  37. data/lib/morpheus/cli/containers_command.rb +2 -1
  38. data/lib/morpheus/cli/credentials.rb +49 -4
  39. data/lib/morpheus/cli/deployments.rb +2 -2
  40. data/lib/morpheus/cli/dot_file.rb +2 -2
  41. data/lib/morpheus/cli/error_handler.rb +6 -3
  42. data/lib/morpheus/cli/execute_schedules_command.rb +1 -1
  43. data/lib/morpheus/cli/groups.rb +4 -4
  44. data/lib/morpheus/cli/hosts.rb +3 -2
  45. data/lib/morpheus/cli/image_builder_command.rb +0 -21
  46. data/lib/morpheus/cli/instances.rb +17 -4
  47. data/lib/morpheus/cli/library_container_types_command.rb +1 -1
  48. data/lib/morpheus/cli/library_layouts_command.rb +1 -1
  49. data/lib/morpheus/cli/library_upgrades_command.rb +1 -1
  50. data/lib/morpheus/cli/license.rb +185 -72
  51. data/lib/morpheus/cli/load_balancers.rb +4 -4
  52. data/lib/morpheus/cli/login.rb +4 -0
  53. data/lib/morpheus/cli/logs_command.rb +132 -0
  54. data/lib/morpheus/cli/mixins/infrastructure_helper.rb +2 -2
  55. data/lib/morpheus/cli/mixins/logs_helper.rb +65 -0
  56. data/lib/morpheus/cli/mixins/monitoring_helper.rb +410 -28
  57. data/lib/morpheus/cli/mixins/print_helper.rb +14 -4
  58. data/lib/morpheus/cli/monitoring_alerts_command.rb +800 -0
  59. data/lib/morpheus/cli/monitoring_apps_command.rb +85 -28
  60. data/lib/morpheus/cli/monitoring_checks_command.rb +60 -27
  61. data/lib/morpheus/cli/monitoring_contacts_command.rb +54 -79
  62. data/lib/morpheus/cli/monitoring_groups_command.rb +62 -23
  63. data/lib/morpheus/cli/monitoring_incidents_command.rb +91 -70
  64. data/lib/morpheus/cli/network_pools_command.rb +39 -23
  65. data/lib/morpheus/cli/power_schedules_command.rb +1 -1
  66. data/lib/morpheus/cli/remote.rb +834 -275
  67. data/lib/morpheus/cli/roles.rb +100 -38
  68. data/lib/morpheus/cli/tasks.rb +1 -1
  69. data/lib/morpheus/cli/user_settings_command.rb +20 -12
  70. data/lib/morpheus/cli/version.rb +1 -1
  71. data/lib/morpheus/cli/virtual_images.rb +1 -1
  72. data/lib/morpheus/cli/whitelabel_settings_command.rb +546 -0
  73. data/lib/morpheus/cli/whoami.rb +1 -1
  74. data/lib/morpheus/cli/workflows.rb +2 -2
  75. data/lib/morpheus/terminal.rb +22 -8
  76. metadata +11 -2
@@ -1007,6 +1007,7 @@ class Morpheus::Cli::Apps
1007
1007
  params = {}
1008
1008
  params.merge!(parse_list_options(options))
1009
1009
  params[:query] = params.delete(:phrase) unless params[:phrase].nil?
1010
+ params['order'] = params['direction'] unless params['direction'].nil? # old api version expects order instead of direction
1010
1011
  @logs_interface.setopts(options)
1011
1012
  if options[:dry_run]
1012
1013
  print_dry_run @logs_interface.dry.container_logs(containers, params)
@@ -1027,7 +1028,7 @@ class Morpheus::Cli::Apps
1027
1028
  if logs['data'].empty?
1028
1029
  puts "#{cyan}No logs found.#{reset}"
1029
1030
  else
1030
- logs['data'].reverse.each do |log_entry|
1031
+ logs['data'].each do |log_entry|
1031
1032
  log_level = ''
1032
1033
  case log_entry['level']
1033
1034
  when 'INFO'
@@ -1503,7 +1504,7 @@ class Morpheus::Cli::Apps
1503
1504
  "[app] is required. This is the name or id of an app. Supports 1-N [app] arguments."
1504
1505
  end
1505
1506
  optparse.parse!(args)
1506
- if args.count != 1
1507
+ if args.count < 1
1507
1508
  raise_command_error "wrong number of arguments, expected 1 and got (#{args.count}) #{args.join(' ')}\n#{optparse}"
1508
1509
  end
1509
1510
  connect(options)
@@ -1793,7 +1794,7 @@ class Morpheus::Cli::Apps
1793
1794
  end
1794
1795
 
1795
1796
  def find_app_by_name(name)
1796
- app_results = @apps_interface.get({name: name})
1797
+ app_results = @apps_interface.list({name: name})
1797
1798
  if app_results['apps'].empty?
1798
1799
  print_red_alert "App not found by name #{name}"
1799
1800
  exit 1
@@ -1822,27 +1822,6 @@ class Morpheus::Cli::ArchivesCommand
1822
1822
  return archive_file
1823
1823
  end
1824
1824
 
1825
- # def find_group_by_name(name)
1826
- # group_results = @groups_interface.get(name)
1827
- # if group_results['groups'].empty?
1828
- # print_red_alert "Group not found by name #{name}"
1829
- # return nil
1830
- # end
1831
- # return group_results['groups'][0]
1832
- # end
1833
-
1834
- # def find_cloud_by_name(group_id, name)
1835
- # option_results = @options_interface.options_for_source('clouds',{groupId: group_id})
1836
- # match = option_results['data'].find { |grp| grp['value'].to_s == name.to_s || grp['name'].downcase == name.downcase}
1837
- # if match.nil?
1838
- # print_red_alert "Cloud not found by name #{name}"
1839
- # return nil
1840
- # else
1841
- # return match['value']
1842
- # end
1843
- # end
1844
-
1845
-
1846
1825
  def format_archive_bucket_full_status(archive_bucket, return_color=cyan)
1847
1826
  out = ""
1848
1827
  if archive_bucket['lastResult']
@@ -880,7 +880,7 @@ class Morpheus::Cli::BlueprintsCommand
880
880
  opts.footer = "Update a blueprint, removing a specified instance config." + "\n" +
881
881
  "[id] is required. This is the name or id of a blueprint." + "\n" +
882
882
  "[tier] is required. This is the name of the tier." + "\n" +
883
- "[instance] is required. This is the instance identifier, which may be the type, the name, or the index (starting with 0." + "\n" +
883
+ "[instance] is required. This is the instance identifier, which may be the type, the name, or the index starting with 0." + "\n" +
884
884
  "The config scope is specified with the -g GROUP, -c CLOUD and -e ENV. The -g and -c options are required."
885
885
  end
886
886
  optparse.parse!(args)
@@ -1063,7 +1063,7 @@ class Morpheus::Cli::BlueprintsCommand
1063
1063
  opts.footer = "Update a blueprint, removing a specified instance." + "\n" +
1064
1064
  "[id] is required. This is the name or id of a blueprint." + "\n" +
1065
1065
  "[tier] is required. This is the name of the tier." + "\n" +
1066
- "[instance] is required. This is the instance identifier, which may be the type, the name, or the index (starting with 0."
1066
+ "[instance] is required. This is the instance identifier, which may be the type, the name, or the index starting with 0."
1067
1067
  end
1068
1068
 
1069
1069
  optparse.parse!(args)
@@ -34,14 +34,14 @@ module Morpheus
34
34
  @my_terminal ||= Morpheus::Terminal.instance
35
35
  end
36
36
 
37
- # set the terminal this is running this command.
37
+ # set the terminal running this command.
38
38
  # @param term [MorpheusTerminal] the terminal this command is assigned to
39
39
  # @return the Terminal this command is being executed inside of
40
40
  def my_terminal=(term)
41
- if !t.is_a?(Morpheus::Terminal)
42
- raise "CliCommand #{self.class} terminal= expects object of type Terminal and instead got a #{t.class}"
41
+ if !term.is_a?(Morpheus::Terminal)
42
+ raise "CliCommand (#{self.class}) my_terminal= expects object of type Terminal and instead got a #{term.class}"
43
43
  end
44
- @my_terminal = t
44
+ @my_terminal = term
45
45
  end
46
46
 
47
47
 
@@ -363,8 +363,14 @@ module Morpheus
363
363
  options[:phrase] = phrase
364
364
  end
365
365
 
366
- opts.on( '-S', '--sort ORDER', "Sort Order" ) do |v|
367
- options[:sort] = v
366
+ opts.on( '-S', '--sort ORDER', "Sort Order. DIRECTION may be included as \"ORDER [asc|desc]\"." ) do |v|
367
+ v_parts = v.to_s.split(" ")
368
+ if v_parts.size > 1
369
+ options[:sort] = v_parts[0]
370
+ options[:direction] = (v_parts[1].strip == "desc") ? "desc" : "asc"
371
+ else
372
+ options[:sort] = v
373
+ end
368
374
  end
369
375
 
370
376
  opts.on( '-D', '--desc', "Reverse Sort Order" ) do |v|
@@ -772,8 +778,16 @@ module Morpheus
772
778
  end
773
779
  cmd_results << cur_result
774
780
  end
775
- failed_cmd = cmd_results.find {|cmd_result| cmd_result == false || (cmd_result.is_a?(Integer) && cmd_result != 0) }
776
- return failed_cmd ? failed_cmd : 0
781
+ # find a bad result and return it
782
+ cmd_results = cmd_results.collect do |cmd_result|
783
+ if cmd_result.is_a?(Array)
784
+ cmd_result
785
+ else
786
+ [cmd_result, nil]
787
+ end
788
+ end
789
+ failed_result = cmd_results.find {|cmd_result| cmd_result[0] == false || (cmd_result[0].is_a?(Integer) && cmd_result[0] != 0) }
790
+ return failed_result ? failed_result : cmd_results.last
777
791
  end
778
792
 
779
793
  # This supports the simple remote option eg. `instances add --remote "qa"`
@@ -927,6 +941,16 @@ module Morpheus
927
941
  return subtitles
928
942
  end
929
943
 
944
+ def parse_payload(options={})
945
+ payload = nil
946
+ if options[:payload]
947
+ payload = options[:payload]
948
+ # support -O OPTION switch on top of --payload
949
+ payload.deep_merge!(options[:options].reject {|k,v| k.is_a?(Symbol) }) if options[:options]
950
+ end
951
+ payload
952
+ end
953
+
930
954
  # basic rendering for options :json, :yaml, :csv, :fields, and :outfile
931
955
  # returns the string rendered, or nil if nothing was rendered.
932
956
  def render_with_format(json_response, options, object_key=nil)
@@ -64,11 +64,11 @@ class Morpheus::Cli::Clouds
64
64
  params.merge!(parse_list_options(options))
65
65
  @clouds_interface.setopts(options)
66
66
  if options[:dry_run]
67
- print_dry_run @clouds_interface.dry.get(params)
67
+ print_dry_run @clouds_interface.dry.list(params)
68
68
  return 0
69
69
  end
70
70
 
71
- json_response = @clouds_interface.get(params)
71
+ json_response = @clouds_interface.list(params)
72
72
  if options[:json]
73
73
  puts as_json(json_response, options, "zones")
74
74
  return 0
@@ -117,10 +117,10 @@ class Morpheus::Cli::Clouds
117
117
  params.merge!(parse_list_options(options))
118
118
  @clouds_interface.setopts(options)
119
119
  if options[:dry_run]
120
- print_dry_run @clouds_interface.dry.get(params)
120
+ print_dry_run @clouds_interface.dry.list(params)
121
121
  return
122
122
  end
123
- json_response = @clouds_interface.get(params)
123
+ json_response = @clouds_interface.list(params)
124
124
  # print number only
125
125
  if json_response['meta'] && json_response['meta']['total']
126
126
  print cyan, json_response['meta']['total'], reset, "\n"
@@ -160,16 +160,11 @@ class Morpheus::Cli::Clouds
160
160
  if arg.to_s =~ /\A\d{1,}\Z/
161
161
  print_dry_run @clouds_interface.dry.get(arg.to_i)
162
162
  else
163
- print_dry_run @clouds_interface.dry.get({name:arg})
163
+ print_dry_run @clouds_interface.dry.list({name:arg})
164
164
  end
165
165
  return
166
166
  end
167
167
  cloud = find_cloud_by_name_or_id(arg)
168
- #json_response = {'zone' => cloud}
169
- # if options[:dry_run]
170
- # print_dry_run @clouds_interface.dry.get(cloud['id'])
171
- # return
172
- # end
173
168
  @clouds_interface.setopts(options)
174
169
  json_response = @clouds_interface.get(cloud['id'])
175
170
  cloud = json_response['zone']
@@ -278,7 +273,7 @@ class Morpheus::Cli::Clouds
278
273
  else
279
274
  # print_red_alert "Group not found or specified!"
280
275
  # exit 1
281
- groups_dropdown = @groups_interface.get({})['groups'].collect {|it| {'name' => it["name"], 'value' => it["id"]} }
276
+ groups_dropdown = @groups_interface.list({})['groups'].collect {|it| {'name' => it["name"], 'value' => it["id"]} }
282
277
  group_prompt = Morpheus::Cli::OptionTypes.prompt([{'fieldName' => 'group', 'type' => 'select', 'fieldLabel' => 'Group', 'selectOptions' => groups_dropdown, 'required' => true, 'description' => 'Select Group.'}],options[:options],@api_client,{})
283
278
  group_id = group_prompt['group']
284
279
  end
@@ -24,6 +24,7 @@ class Morpheus::Cli::Clusters
24
24
  register_subcommands :list_pods, :remove_pod, :restart_pod
25
25
  register_subcommands :list_jobs, :remove_job
26
26
  register_subcommands :list_services, :remove_service
27
+ register_subcommands :list_datastores, :get_datastore, :update_datastore
27
28
  register_subcommands :update_permissions
28
29
  register_subcommands :api_config, :view_api_token, :view_kube_config
29
30
  register_subcommands :wiki, :update_wiki
@@ -409,7 +410,7 @@ class Morpheus::Cli::Clusters
409
410
  options[:refresh_interval] = val.to_s.empty? ? default_refresh_interval : val.to_f
410
411
  end
411
412
  opts.on('--workflow ID', String, "Workflow") do |val|
412
- params['taskSetId'] = val.to_i
413
+ options['taskSetId'] = val.to_i
413
414
  end
414
415
  add_server_options(opts, options)
415
416
  build_common_options(opts, options, [:options, :payload, :json, :dry_run, :remote])
@@ -868,7 +869,7 @@ class Morpheus::Cli::Clusters
868
869
  if logs['data'].empty?
869
870
  puts "#{cyan}No logs found.#{reset}"
870
871
  else
871
- logs['data'].reverse.each do |log_entry|
872
+ logs['data'].each do |log_entry|
872
873
  log_level = ''
873
874
  case log_entry['level']
874
875
  when 'INFO'
@@ -2494,6 +2495,203 @@ class Morpheus::Cli::Clusters
2494
2495
  end
2495
2496
  end
2496
2497
 
2498
+ def list_datastores(args)
2499
+ options = {}
2500
+ optparse = Morpheus::Cli::OptionParser.new do |opts|
2501
+ opts.banner = subcommand_usage( "[cluster]")
2502
+ build_common_options(opts, options, [:list, :query, :json, :yaml, :csv, :fields, :dry_run, :remote])
2503
+ opts.footer = "List datastores for a cluster.\n" +
2504
+ "[cluster] is required. This is the name or id of an existing cluster."
2505
+ end
2506
+
2507
+ optparse.parse!(args)
2508
+ if args.count != 1
2509
+ raise_command_error "wrong number of arguments, expected 1 and got (#{args.count}) #{args.join(' ')}\n#{optparse}"
2510
+ end
2511
+ connect(options)
2512
+ begin
2513
+ cluster = find_cluster_by_name_or_id(args[0])
2514
+ return 1 if cluster.nil?
2515
+
2516
+ params = {}
2517
+ params.merge!(parse_list_options(options))
2518
+ @clusters_interface.setopts(options)
2519
+ if options[:dry_run]
2520
+ print_dry_run @clusters_interface.dry.list_datastores(cluster['id'], params)
2521
+ return
2522
+ end
2523
+ json_response = @clusters_interface.list_datastores(cluster['id'], params)
2524
+
2525
+ render_result = render_with_format(json_response, options, 'datastores')
2526
+ return 0 if render_result
2527
+
2528
+ title = "Morpheus Cluster Datastores: #{cluster['name']}"
2529
+ subtitles = []
2530
+ subtitles += parse_list_subtitles(options)
2531
+ print_h1 title, subtitles
2532
+ datastores = json_response['datastores']
2533
+ if datastores.empty?
2534
+ print yellow,"No datastores found.",reset,"\n"
2535
+ else
2536
+ # more stuff to show here
2537
+ rows = datastores.collect do |ds|
2538
+ {
2539
+ id: ds['id'],
2540
+ name: ds['name'],
2541
+ type: ds['type'],
2542
+ capacity: format_bytes_short(ds['freeSpace']).strip,
2543
+ online: format_boolean(ds['online']),
2544
+ visibility: ds['visibility'].nil? ? '' : ds['visibility'].to_s.capitalize,
2545
+ tenants: ds['tenants'].nil? ? '' : ds['tenants'].collect {|it| it['name']}.join(', ')
2546
+ }
2547
+ end
2548
+ columns = [
2549
+ :id, :name, :type, :capacity, :online, :visibility, :tenants
2550
+ ]
2551
+ print as_pretty_table(rows, columns, options)
2552
+ end
2553
+ print reset,"\n"
2554
+ return 0
2555
+ rescue RestClient::Exception => e
2556
+ print_rest_exception(e, options)
2557
+ exit 1
2558
+ end
2559
+ end
2560
+
2561
+ def get_datastore(args)
2562
+ options = {}
2563
+ optparse = Morpheus::Cli::OptionParser.new do |opts|
2564
+ opts.banner = subcommand_usage( "[cluster] [datastore]")
2565
+ build_common_options(opts, options, [:query, :json, :yaml, :csv, :fields, :dry_run, :remote])
2566
+ opts.footer = "Get details about a cluster datastore.\n" +
2567
+ "[cluster] is required. This is the name or id of an existing cluster.\n" +
2568
+ "[datastore] is required. This is the name or id of an existing datastore."
2569
+ end
2570
+ optparse.parse!(args)
2571
+ if args.count != 2
2572
+ raise_command_error "wrong number of arguments, expected 2 and got (#{args.count}) #{args}\n#{optparse}"
2573
+ end
2574
+ connect(options)
2575
+ begin
2576
+ cluster = find_cluster_by_name_or_id(args[0])
2577
+ return 1 if cluster.nil?
2578
+ # this finds the namespace in the cluster api response, then fetches it by ID
2579
+ datastore = find_datastore_by_name_or_id(cluster['id'], args[1])
2580
+ if datastore.nil?
2581
+ print_red_alert "Datastore not found for '#{args[1]}'"
2582
+ exit 1
2583
+ end
2584
+ params = {}
2585
+ params.merge!(parse_list_options(options))
2586
+ @clusters_interface.setopts(options)
2587
+ if options[:dry_run]
2588
+ print_dry_run @clusters_interface.dry.get_datastore(cluster['id'], datastore['id'], params)
2589
+ return
2590
+ end
2591
+ json_response = @clusters_interface.get_datastore(cluster['id'], datastore['id'], params)
2592
+
2593
+ render_result = render_with_format(json_response, options, 'datastore')
2594
+ return 0 if render_result
2595
+
2596
+ print_h1 "Morpheus Cluster Datastore"
2597
+ print cyan
2598
+ description_cols = {
2599
+ "ID" => 'id',
2600
+ "Name" => 'name',
2601
+ "Type" => 'type',
2602
+ "Capacity" => lambda { |it| format_bytes_short(it['freeSpace']).strip },
2603
+ "Online" => lambda { |it| format_boolean(it['online']) },
2604
+ "Visibility" => lambda { |it| it['visibility'].nil? ? '' : it['visibility'].to_s.capitalize },
2605
+ "Tenants" => lambda { |it| it['tenants'].nil? ? '' : it['tenants'].collect {|it| it['name']}.join(', ') },
2606
+ "Cluster" => lambda { |it| cluster['name'] }
2607
+ }
2608
+ print_description_list(description_cols, datastore)
2609
+ print reset,"\n"
2610
+ return 0
2611
+ rescue RestClient::Exception => e
2612
+ print_rest_exception(e, options)
2613
+ exit 1
2614
+ end
2615
+ end
2616
+
2617
+ def update_datastore(args)
2618
+ options = {}
2619
+ optparse = Morpheus::Cli::OptionParser.new do |opts|
2620
+ opts.banner = subcommand_usage( "[cluster] [datastore] [options]")
2621
+ opts.on('--active [on|off]', String, "Enable datastore") do |val|
2622
+ options[:active] = val.to_s == 'on' || val.to_s == 'true' || val.to_s == ''
2623
+ end
2624
+ add_perms_options(opts, options, ['planAccess', 'groupAccessDefaults'])
2625
+ build_common_options(opts, options, [:options, :payload, :json, :dry_run, :remote])
2626
+ opts.footer = "Update a cluster datastore.\n" +
2627
+ "[cluster] is required. This is the name or id of an existing cluster.\n" +
2628
+ "[datastore] is required. This is the name or id of an existing datastore."
2629
+ end
2630
+
2631
+ optparse.parse!(args)
2632
+ if args.count != 2
2633
+ raise_command_error "wrong number of arguments, expected 2 and got (#{args.count}) #{args}\n#{optparse}"
2634
+ end
2635
+ connect(options)
2636
+
2637
+ begin
2638
+ cluster = find_cluster_by_name_or_id(args[0])
2639
+ return 1 if cluster.nil?
2640
+ datastore = find_datastore_by_name_or_id(cluster['id'], args[1])
2641
+ if datastore.nil?
2642
+ print_red_alert "Datastore not found by '#{args[1]}'"
2643
+ exit 1
2644
+ end
2645
+ payload = nil
2646
+ if options[:payload]
2647
+ payload = options[:payload]
2648
+ # support -O OPTION switch on top of everything
2649
+ if options[:options]
2650
+ payload.deep_merge!({'datastore' => options[:options].reject {|k,v| k.is_a?(Symbol) }})
2651
+ end
2652
+ else
2653
+ payload = {'datastore' => {}}
2654
+ payload['datastore']['active'] = options[:active].nil? ? (Morpheus::Cli::OptionTypes.prompt([{'fieldName' => 'active', 'fieldLabel' => 'Active', 'type' => 'checkbox', 'description' => 'Datastore Active', 'defaultValue' => true}], options[:options], @api_client))['active'] == 'on' : options[:active]
2655
+
2656
+ perms = prompt_permissions(options, datastore['owner']['id'] == current_user['accountId'] ? ['planAccess', 'groupAccessDefaults'] : ['planAccess', 'groupAccessDefaults', 'visibility', 'tenants'])
2657
+ perms_payload = {}
2658
+ perms_payload['resourcePermissions'] = perms['resourcePermissions'] if !perms['resourcePermissions'].nil?
2659
+ perms_payload['tenantPermissions'] = perms['tenantPermissions'] if !perms['tenantPermissions'].nil?
2660
+
2661
+ payload['datastore']['permissions'] = perms_payload
2662
+ payload['datastore']['visibility'] = perms['resourcePool']['visibility'] if !perms['resourcePool'].nil? && !perms['resourcePool']['visibility'].nil?
2663
+
2664
+ # support -O OPTION switch on top of everything
2665
+ if options[:options]
2666
+ payload.deep_merge!({'datastore' => options[:options].reject {|k,v| k.is_a?(Symbol) }})
2667
+ end
2668
+
2669
+ if payload['datastore'].nil? || payload['datastore'].empty?
2670
+ raise_command_error "Specify at least one option to update.\n#{optparse}"
2671
+ end
2672
+ end
2673
+
2674
+ @clusters_interface.setopts(options)
2675
+ if options[:dry_run]
2676
+ print_dry_run @clusters_interface.dry.update_datastore(cluster['id'], datastore['id'], payload)
2677
+ return
2678
+ end
2679
+ json_response = @clusters_interface.update_datastore(cluster['id'], datastore['id'], payload)
2680
+ if options[:json]
2681
+ puts as_json(json_response)
2682
+ elsif !options[:quiet]
2683
+ datastore = json_response['datastore']
2684
+ print_green_success "Updated datastore #{datastore['name']}"
2685
+ #get_args = [cluster["id"], datastore["id"]] + (options[:remote] ? ["-r",options[:remote]] : [])
2686
+ #get_namespace(get_args)
2687
+ end
2688
+ return 0
2689
+ rescue RestClient::Exception => e
2690
+ print_rest_exception(e, options)
2691
+ exit 1
2692
+ end
2693
+ end
2694
+
2497
2695
  def api_config(args)
2498
2696
  options = {}
2499
2697
  optparse = Morpheus::Cli::OptionParser.new do |opts|
@@ -3332,6 +3530,16 @@ class Morpheus::Cli::Clusters
3332
3530
  json_results['namespaces'].empty? ? nil : json_results['namespaces'][0]
3333
3531
  end
3334
3532
 
3533
+ def find_datastore_by_name_or_id(cluster_id, val)
3534
+ if val.to_s =~ /\A\d{1,}\Z/
3535
+ params = {datastoreId: val.to_i}
3536
+ else
3537
+ params = {phrase: val}
3538
+ end
3539
+ json_results = @clusters_interface.list_datastores(cluster_id, params)
3540
+ json_results['datastores'].empty? ? nil : json_results['datastores'][0]
3541
+ end
3542
+
3335
3543
  def find_job_by_name_or_id(cluster_id, val)
3336
3544
  if val.to_s =~ /\A\d{1,}\Z/
3337
3545
  params = {jobId: val.to_i}
@@ -3638,49 +3846,62 @@ class Morpheus::Cli::Clusters
3638
3846
  end
3639
3847
  end
3640
3848
 
3641
- def add_perms_options(opts, options)
3642
- opts.on('--group-access-all [on|off]', String, "Toggle Access for all groups.") do |val|
3643
- options[:groupAccessAll] = val.to_s == 'on' || val.to_s == 'true' || val.to_s == ''
3644
- end
3645
- opts.on('--group-access LIST', Array, "Group Access, comma separated list of group IDs.") do |list|
3646
- if list.size == 1 && list[0] == 'null' # hacky way to clear it
3647
- options[:groupAccessList] = []
3648
- else
3649
- options[:groupAccessList] = list.collect {|it| it.to_s.strip.empty? ? nil : it.to_s.strip }.compact.uniq
3849
+ def add_perms_options(opts, options, excludes = [])
3850
+ if !excludes.include?('groupAccess')
3851
+ opts.on('--group-access-all [on|off]', String, "Toggle Access for all groups.") do |val|
3852
+ options[:groupAccessAll] = val.to_s == 'on' || val.to_s == 'true' || val.to_s == ''
3650
3853
  end
3651
- end
3652
- opts.on('--group-defaults LIST', Array, "Group Default Selection, comma separated list of group IDs") do |list|
3653
- if list.size == 1 && list[0] == 'null' # hacky way to clear it
3654
- options[:groupDefaultsList] = []
3655
- else
3656
- options[:groupDefaultsList] = list.collect {|it| it.to_s.strip.empty? ? nil : it.to_s.strip }.compact.uniq
3854
+ opts.on('--group-access LIST', Array, "Group Access, comma separated list of group IDs.") do |list|
3855
+ if list.size == 1 && list[0] == 'null' # hacky way to clear it
3856
+ options[:groupAccessList] = []
3857
+ else
3858
+ options[:groupAccessList] = list.collect {|it| it.to_s.strip.empty? ? nil : it.to_s.strip }.compact.uniq
3859
+ end
3657
3860
  end
3658
- end
3659
- opts.on('--plan-access-all [on|off]', String, "Toggle Access for all service plans.") do |val|
3660
- options[:planAccessAll] = val.to_s == 'on' || val.to_s == 'true' || val.to_s == ''
3661
- end
3662
- opts.on('--plan-access LIST', Array, "Service Plan Access, comma separated list of plan IDs.") do |list|
3663
- if list.size == 1 && list[0] == 'null' # hacky way to clear it
3664
- options[:planAccessList] = []
3665
- else
3666
- options[:planAccessList] = list.collect {|it| it.to_s.strip.empty? ? nil : it.to_s.strip }.compact.uniq
3861
+ if !excludes.include?('groupAccessDefaults')
3862
+ opts.on('--group-defaults LIST', Array, "Group Default Selection, comma separated list of group IDs") do |list|
3863
+ if list.size == 1 && list[0] == 'null' # hacky way to clear it
3864
+ options[:groupDefaultsList] = []
3865
+ else
3866
+ options[:groupDefaultsList] = list.collect {|it| it.to_s.strip.empty? ? nil : it.to_s.strip }.compact.uniq
3867
+ end
3868
+ end
3667
3869
  end
3668
3870
  end
3669
- opts.on('--plan-defaults LIST', Array, "Plan Default Selection, comma separated list of plan IDs") do |list|
3670
- if list.size == 1 && list[0] == 'null' # hacky way to clear it
3671
- options[:planDefaultsList] = []
3672
- else
3673
- options[:planDefaultsList] = list.collect {|it| it.to_s.strip.empty? ? nil : it.to_s.strip }.compact.uniq
3871
+
3872
+ if !excludes.include?('planAccess')
3873
+ opts.on('--plan-access-all [on|off]', String, "Toggle Access for all service plans.") do |val|
3874
+ options[:planAccessAll] = val.to_s == 'on' || val.to_s == 'true' || val.to_s == ''
3875
+ end
3876
+ opts.on('--plan-access LIST', Array, "Service Plan Access, comma separated list of plan IDs.") do |list|
3877
+ if list.size == 1 && list[0] == 'null' # hacky way to clear it
3878
+ options[:planAccessList] = []
3879
+ else
3880
+ options[:planAccessList] = list.collect {|it| it.to_s.strip.empty? ? nil : it.to_s.strip }.compact.uniq
3881
+ end
3882
+ end
3883
+ opts.on('--plan-defaults LIST', Array, "Plan Default Selection, comma separated list of plan IDs") do |list|
3884
+ if list.size == 1 && list[0] == 'null' # hacky way to clear it
3885
+ options[:planDefaultsList] = []
3886
+ else
3887
+ options[:planDefaultsList] = list.collect {|it| it.to_s.strip.empty? ? nil : it.to_s.strip }.compact.uniq
3888
+ end
3674
3889
  end
3675
3890
  end
3676
- opts.on('--visibility [private|public]', String, "Visibility") do |val|
3677
- options[:visibility] = val
3891
+
3892
+ if !excludes.include?('visibility')
3893
+ opts.on('--visibility [private|public]', String, "Visibility") do |val|
3894
+ options[:visibility] = val
3895
+ end
3678
3896
  end
3679
- opts.on('--tenants LIST', Array, "Tenant Access, comma separated list of account IDs") do |list|
3680
- if list.size == 1 && list[0] == 'null' # hacky way to clear it
3681
- options[:tenants] = []
3682
- else
3683
- options[:tenants] = list.collect {|it| it.to_s.strip.empty? ? nil : it.to_s.strip }.compact.uniq
3897
+
3898
+ if !excludes.include?('tenants')
3899
+ opts.on('--tenants LIST', Array, "Tenant Access, comma separated list of account IDs") do |list|
3900
+ if list.size == 1 && list[0] == 'null' # hacky way to clear it
3901
+ options[:tenants] = []
3902
+ else
3903
+ options[:tenants] = list.collect {|it| it.to_s.strip.empty? ? nil : it.to_s.strip }.compact.uniq
3904
+ end
3684
3905
  end
3685
3906
  end
3686
3907
  end
@@ -3748,49 +3969,52 @@ class Morpheus::Cli::Clusters
3748
3969
  rtn
3749
3970
  end
3750
3971
 
3751
- def prompt_permissions(options)
3752
- all_groups = false
3753
- group_access = []
3754
- all_plans = false
3755
- plan_access = []
3972
+ def prompt_permissions(options, excludes = [])
3973
+ all_groups = nil
3974
+ group_access = nil
3975
+ all_plans = nil
3976
+ plan_access = nil
3756
3977
 
3757
3978
  # Group Access
3758
- if options[:groupAccessAll]
3759
- all_groups = true
3760
- end
3979
+ if !excludes.include?('groupAccess')
3980
+ if options[:groupAccessAll]
3981
+ all_groups = true
3982
+ end
3761
3983
 
3762
- if !options[:groupAccessList].empty?
3763
- group_access = options[:groupAccessList].collect {|site_id| {'id' => site_id.to_i}} || []
3764
- elsif !options[:no_prompt]
3765
- available_groups = get_available_groups
3984
+ if !options[:groupAccessList].empty?
3985
+ group_access = options[:groupAccessList].collect {|site_id| {'id' => site_id.to_i}} || []
3986
+ elsif !options[:no_prompt]
3987
+ available_groups = get_available_groups
3766
3988
 
3767
- if available_groups.empty?
3768
- #print_red_alert "No available groups"
3769
- #exit 1
3770
- elsif available_groups.count > 1
3771
- available_groups.unshift({"id" => '0', "name" => "All", "value" => "all"})
3989
+ if available_groups.empty?
3990
+ #print_red_alert "No available groups"
3991
+ #exit 1
3992
+ elsif available_groups.count > 1
3993
+ available_groups.unshift({"id" => '0', "name" => "All", "value" => "all"})
3772
3994
 
3773
- # default to all
3774
- group_id = Morpheus::Cli::OptionTypes.prompt([{'fieldName' => 'group', 'type' => 'select', 'fieldLabel' => 'Group Access', 'selectOptions' => available_groups, 'required' => false, 'description' => 'Add Group Access.'}], options[:options], @api_client, {})['group']
3995
+ # default to all
3996
+ group_id = Morpheus::Cli::OptionTypes.prompt([{'fieldName' => 'group', 'type' => 'select', 'fieldLabel' => 'Group Access', 'selectOptions' => available_groups, 'required' => false, 'description' => 'Add Group Access.'}], options[:options], @api_client, {})['group']
3775
3997
 
3776
- if !group_id.nil?
3777
- if group_id == 'all'
3778
- all_groups = true
3779
- else
3780
- group_access = [{'id' => group_id, 'default' => Morpheus::Cli::OptionTypes.confirm("Set '#{available_groups.find{|it| it['id'] == group_id}['name']}' as default?", {:default => false})}]
3781
- end
3782
- available_groups = available_groups.reject {|it| it['value'] == group_id}
3998
+ if !group_id.nil?
3999
+ if group_id == 'all'
4000
+ all_groups = true
4001
+ else
4002
+ group_access = (excludes.include?('groupAccessDefaults') ? [{'id' => group_id}] : [{'id' => group_id, 'default' => Morpheus::Cli::OptionTypes.confirm("Set '#{available_groups.find{|it| it['id'] == group_id}['name']}' as default?", {:default => false})}])
4003
+ end
4004
+ available_groups = available_groups.reject {|it| it['value'] == group_id}
3783
4005
 
3784
- while !group_id.nil? && !available_groups.empty? && Morpheus::Cli::OptionTypes.confirm("Add another group access?", {:default => false})
3785
- group_id = Morpheus::Cli::OptionTypes.prompt([{'fieldName' => 'group', 'type' => 'select', 'fieldLabel' => 'Group Access', 'selectOptions' => available_groups, 'required' => false, 'description' => 'Add Group Access.'}], options[:options], @api_client, {})['group']
4006
+ while !group_id.nil? && !available_groups.empty? && Morpheus::Cli::OptionTypes.confirm("Add another group access?", {:default => false})
4007
+ group_id = Morpheus::Cli::OptionTypes.prompt([{'fieldName' => 'group', 'type' => 'select', 'fieldLabel' => 'Group Access', 'selectOptions' => available_groups, 'required' => false, 'description' => 'Add Group Access.'}], options[:options], @api_client, {})['group']
3786
4008
 
3787
- if !group_id.nil?
3788
- if group_id == 'all'
3789
- all_groups = true
3790
- else
3791
- group_access << {'id' => group_id, 'default' => Morpheus::Cli::OptionTypes.confirm("Set '#{available_groups.find{|it| it['id'] == group_id}['name']}' as default?", {:default => false})}
4009
+ if !group_id.nil?
4010
+ if group_id == 'all'
4011
+ all_groups = true
4012
+ else
4013
+ group_access ||= []
4014
+ group_access << (excludes.include?('groupAccessDefaults') ? {'id' => group_id} : {'id' => group_id, 'default' => Morpheus::Cli::OptionTypes.confirm("Set '#{available_groups.find{|it| it['id'] == group_id}['name']}' as default?", {:default => false})})
4015
+ end
4016
+ available_groups = available_groups.reject {|it| it['value'] == group_id}
3792
4017
  end
3793
- available_groups = available_groups.reject {|it| it['value'] == group_id}
3794
4018
  end
3795
4019
  end
3796
4020
  end
@@ -3798,43 +4022,46 @@ class Morpheus::Cli::Clusters
3798
4022
  end
3799
4023
 
3800
4024
  # Plan Access
3801
- if options[:planAccessAll]
3802
- all_plans = true
3803
- end
4025
+ if !excludes.include?('planAccess')
4026
+ if options[:planAccessAll]
4027
+ all_plans = true
4028
+ end
3804
4029
 
3805
- if !options[:planAccessList].empty?
3806
- plan_access = options[:planAccessList].collect {|plan_id| {'id' => plan_id.to_i}}
3807
- elsif !options[:no_prompt]
3808
- available_plans = namespace_service_plans.collect {|it| {'id' => it['id'], 'name' => it['name'], 'value' => it['id']} }
4030
+ if !options[:planAccessList].empty?
4031
+ plan_access = options[:planAccessList].collect {|plan_id| {'id' => plan_id.to_i}}
4032
+ elsif !options[:no_prompt]
4033
+ available_plans = namespace_service_plans.collect {|it| {'id' => it['id'], 'name' => it['name'], 'value' => it['id']} }
3809
4034
 
3810
- if available_plans.empty?
3811
- #print_red_alert "No available plans"
3812
- #exit 1
3813
- elsif !available_plans.empty? && !options[:no_prompt]
3814
- available_plans.unshift({"id" => '0', "name" => "All", "value" => "all"})
4035
+ if available_plans.empty?
4036
+ #print_red_alert "No available plans"
4037
+ #exit 1
4038
+ elsif !available_plans.empty? && !options[:no_prompt]
4039
+ available_plans.unshift({"id" => '0', "name" => "All", "value" => "all"})
3815
4040
 
3816
- # default to all
3817
- plan_id = Morpheus::Cli::OptionTypes.prompt([{'fieldName' => 'plan', 'type' => 'select', 'fieldLabel' => 'Service Plan Access', 'selectOptions' => available_plans, 'required' => false, 'description' => 'Add Service Plan Access.'}], options[:options], @api_client, {})['plan']
4041
+ # default to all
4042
+ plan_id = Morpheus::Cli::OptionTypes.prompt([{'fieldName' => 'plan', 'type' => 'select', 'fieldLabel' => 'Service Plan Access', 'selectOptions' => available_plans, 'required' => false, 'description' => 'Add Service Plan Access.'}], options[:options], @api_client, {})['plan']
3818
4043
 
3819
- if !plan_id.nil?
3820
- if plan_id == 'all'
3821
- all_plans = true
3822
- else
3823
- plan_access = [{'id' => plan_id, 'default' => Morpheus::Cli::OptionTypes.confirm("Set '#{available_plans.find{|it| it['id'] == plan_id}['name']}' as default?", {:default => false})}]
3824
- end
4044
+ if !plan_id.nil?
4045
+ if plan_id == 'all'
4046
+ all_plans = true
4047
+ else
4048
+ plan_access = [{'id' => plan_id, 'default' => Morpheus::Cli::OptionTypes.confirm("Set '#{available_plans.find{|it| it['id'] == plan_id}['name']}' as default?", {:default => false})}]
4049
+ end
3825
4050
 
3826
- available_plans = available_plans.reject {|it| it['value'] == plan_id}
4051
+ available_plans = available_plans.reject {|it| it['value'] == plan_id}
3827
4052
 
3828
- while !plan_id.nil? && !available_plans.empty? && Morpheus::Cli::OptionTypes.confirm("Add another service plan access?", {:default => false})
3829
- plan_id = Morpheus::Cli::OptionTypes.prompt([{'fieldName' => 'plan', 'type' => 'select', 'fieldLabel' => 'Service Plan Access', 'selectOptions' => available_plans, 'required' => false, 'description' => 'Add Service Plan Access.'}], options[:options], @api_client, {})['plan']
4053
+ while !plan_id.nil? && !available_plans.empty? && Morpheus::Cli::OptionTypes.confirm("Add another service plan access?", {:default => false})
4054
+ plan_id = Morpheus::Cli::OptionTypes.prompt([{'fieldName' => 'plan', 'type' => 'select', 'fieldLabel' => 'Service Plan Access', 'selectOptions' => available_plans, 'required' => false, 'description' => 'Add Service Plan Access.'}], options[:options], @api_client, {})['plan']
3830
4055
 
3831
- if !plan_id.nil?
3832
- if plan_id == 'all'
3833
- all_plans = true
3834
- else
3835
- plan_access << {'id' => plan_id, 'default' => Morpheus::Cli::OptionTypes.confirm("Set '#{available_plans.find{|it| it['id'] == plan_id}['name']}' as default?", {:default => false})}
4056
+ if !plan_id.nil?
4057
+ if plan_id == 'all'
4058
+ all_plans = true
4059
+ else
4060
+ plan_access ||= []
4061
+ plan_access << {'id' => plan_id, 'default' => Morpheus::Cli::OptionTypes.confirm("Set '#{available_plans.find{|it| it['id'] == plan_id}['name']}' as default?", {:default => false})}
4062
+ end
4063
+ available_plans = available_plans.reject {|it| it['value'] == plan_id}
3836
4064
  end
3837
- available_plans = available_plans.reject {|it| it['value'] == plan_id}
3838
4065
  end
3839
4066
  end
3840
4067
  end
@@ -3842,10 +4069,10 @@ class Morpheus::Cli::Clusters
3842
4069
  end
3843
4070
 
3844
4071
  resource_perms = {}
3845
- resource_perms['all'] = true if all_groups
3846
- resource_perms['sites'] = group_access if !group_access.empty?
3847
- resource_perms['allPlans'] = true if all_plans
3848
- resource_perms['plans'] = plan_access if !plan_access.empty?
4072
+ resource_perms['all'] = all_groups if !all_groups.nil?
4073
+ resource_perms['sites'] = group_access if !group_access.nil?
4074
+ resource_perms['allPlans'] = all_plans if !all_plans.nil?
4075
+ resource_perms['plans'] = plan_access if !plan_access.nil?
3849
4076
 
3850
4077
  permissions = {'resourcePermissions' => resource_perms}
3851
4078
 
@@ -3859,24 +4086,26 @@ class Morpheus::Cli::Clusters
3859
4086
  permissions['resourcePool'] = {'visibility' => visibility}
3860
4087
 
3861
4088
  # Tenants
3862
- if !options[:tenants].nil?
3863
- accounts = options[:tenants].collect {|id| id.to_i}
3864
- elsif !options[:no_prompt]
3865
- account_id = Morpheus::Cli::OptionTypes.prompt([{'fieldName' => 'account_id', 'type' => 'select', 'fieldLabel' => 'Add Tenant', 'selectOptions' => available_accounts, 'required' => false, 'description' => 'Add Tenant Permissions.'}], options[:options], @api_client, {})['account_id']
4089
+ if !excludes.include?('tenants')
4090
+ if !options[:tenants].nil?
4091
+ accounts = options[:tenants].collect {|id| id.to_i}
4092
+ elsif !options[:no_prompt]
4093
+ account_id = Morpheus::Cli::OptionTypes.prompt([{'fieldName' => 'account_id', 'type' => 'select', 'fieldLabel' => 'Add Tenant', 'selectOptions' => available_accounts, 'required' => false, 'description' => 'Add Tenant Permissions.'}], options[:options], @api_client, {})['account_id']
3866
4094
 
3867
- if !account_id.nil?
3868
- accounts << account_id
3869
- available_accounts = available_accounts.reject {|it| it['value'] == account_id}
4095
+ if !account_id.nil?
4096
+ accounts << account_id
4097
+ available_accounts = available_accounts.reject {|it| it['value'] == account_id}
3870
4098
 
3871
- while !available_accounts.empty? && (account_id = Morpheus::Cli::OptionTypes.prompt([{'fieldName' => 'account_id', 'type' => 'select', 'fieldLabel' => 'Add Another Tenant', 'selectOptions' => available_accounts, 'required' => false, 'description' => 'Add Tenant Permissions.'}], options[:options], @api_client, {})['account_id'])
3872
- if !account_id.nil?
3873
- accounts << account_id
3874
- available_accounts = available_accounts.reject {|it| it['value'] == account_id}
4099
+ while !available_accounts.empty? && (account_id = Morpheus::Cli::OptionTypes.prompt([{'fieldName' => 'account_id', 'type' => 'select', 'fieldLabel' => 'Add Another Tenant', 'selectOptions' => available_accounts, 'required' => false, 'description' => 'Add Tenant Permissions.'}], options[:options], @api_client, {})['account_id'])
4100
+ if !account_id.nil?
4101
+ accounts << account_id
4102
+ available_accounts = available_accounts.reject {|it| it['value'] == account_id}
4103
+ end
3875
4104
  end
3876
4105
  end
3877
4106
  end
4107
+ permissions['tenantPermissions'] = {'accounts' => accounts}
3878
4108
  end
3879
- permissions['tenantPermissions'] = {'accounts' => accounts} if !accounts.empty?
3880
4109
  end
3881
4110
  permissions
3882
4111
  end