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.
- checksums.yaml +4 -4
- data/lib/morpheus.rb +5 -0
- data/lib/morpheus/api.rb +2 -2
- data/lib/morpheus/api/api_client.rb +47 -12
- data/lib/morpheus/api/appliance_settings_interface.rb +30 -0
- data/lib/morpheus/api/auth_interface.rb +14 -10
- data/lib/morpheus/api/clouds_interface.rb +7 -0
- data/lib/morpheus/api/clusters_interface.rb +17 -5
- data/lib/morpheus/api/custom_instance_types_interface.rb +2 -3
- data/lib/morpheus/api/deployments_interface.rb +7 -0
- data/lib/morpheus/api/execute_schedules_interface.rb +2 -3
- data/lib/morpheus/api/groups_interface.rb +7 -0
- data/lib/morpheus/api/license_interface.rb +9 -2
- data/lib/morpheus/api/load_balancers_interface.rb +7 -0
- data/lib/morpheus/api/logs_interface.rb +11 -2
- data/lib/morpheus/api/monitoring_alerts_interface.rb +45 -0
- data/lib/morpheus/api/monitoring_checks_interface.rb +2 -2
- data/lib/morpheus/api/monitoring_interface.rb +13 -8
- data/lib/morpheus/api/power_schedules_interface.rb +2 -3
- data/lib/morpheus/api/servers_interface.rb +5 -2
- data/lib/morpheus/api/setup_interface.rb +25 -7
- data/lib/morpheus/api/task_sets_interface.rb +7 -1
- data/lib/morpheus/api/tasks_interface.rb +7 -0
- data/lib/morpheus/api/virtual_images_interface.rb +2 -3
- data/lib/morpheus/api/whitelabel_settings_interface.rb +60 -0
- data/lib/morpheus/cli.rb +18 -14
- data/lib/morpheus/cli/access_token_command.rb +18 -2
- data/lib/morpheus/cli/appliance_settings_command.rb +303 -0
- data/lib/morpheus/cli/apps.rb +4 -3
- data/lib/morpheus/cli/archives_command.rb +0 -21
- data/lib/morpheus/cli/blueprints_command.rb +2 -2
- data/lib/morpheus/cli/cli_command.rb +32 -8
- data/lib/morpheus/cli/clouds.rb +6 -11
- data/lib/morpheus/cli/clusters.rb +346 -117
- data/lib/morpheus/cli/command_error.rb +4 -0
- data/lib/morpheus/cli/commands/standard/man_command.rb +1 -1
- data/lib/morpheus/cli/containers_command.rb +2 -1
- data/lib/morpheus/cli/credentials.rb +49 -4
- data/lib/morpheus/cli/deployments.rb +2 -2
- data/lib/morpheus/cli/dot_file.rb +2 -2
- data/lib/morpheus/cli/error_handler.rb +6 -3
- data/lib/morpheus/cli/execute_schedules_command.rb +1 -1
- data/lib/morpheus/cli/groups.rb +4 -4
- data/lib/morpheus/cli/hosts.rb +3 -2
- data/lib/morpheus/cli/image_builder_command.rb +0 -21
- data/lib/morpheus/cli/instances.rb +17 -4
- data/lib/morpheus/cli/library_container_types_command.rb +1 -1
- data/lib/morpheus/cli/library_layouts_command.rb +1 -1
- data/lib/morpheus/cli/library_upgrades_command.rb +1 -1
- data/lib/morpheus/cli/license.rb +185 -72
- data/lib/morpheus/cli/load_balancers.rb +4 -4
- data/lib/morpheus/cli/login.rb +4 -0
- data/lib/morpheus/cli/logs_command.rb +132 -0
- data/lib/morpheus/cli/mixins/infrastructure_helper.rb +2 -2
- data/lib/morpheus/cli/mixins/logs_helper.rb +65 -0
- data/lib/morpheus/cli/mixins/monitoring_helper.rb +410 -28
- data/lib/morpheus/cli/mixins/print_helper.rb +14 -4
- data/lib/morpheus/cli/monitoring_alerts_command.rb +800 -0
- data/lib/morpheus/cli/monitoring_apps_command.rb +85 -28
- data/lib/morpheus/cli/monitoring_checks_command.rb +60 -27
- data/lib/morpheus/cli/monitoring_contacts_command.rb +54 -79
- data/lib/morpheus/cli/monitoring_groups_command.rb +62 -23
- data/lib/morpheus/cli/monitoring_incidents_command.rb +91 -70
- data/lib/morpheus/cli/network_pools_command.rb +39 -23
- data/lib/morpheus/cli/power_schedules_command.rb +1 -1
- data/lib/morpheus/cli/remote.rb +834 -275
- data/lib/morpheus/cli/roles.rb +100 -38
- data/lib/morpheus/cli/tasks.rb +1 -1
- data/lib/morpheus/cli/user_settings_command.rb +20 -12
- data/lib/morpheus/cli/version.rb +1 -1
- data/lib/morpheus/cli/virtual_images.rb +1 -1
- data/lib/morpheus/cli/whitelabel_settings_command.rb +546 -0
- data/lib/morpheus/cli/whoami.rb +1 -1
- data/lib/morpheus/cli/workflows.rb +2 -2
- data/lib/morpheus/terminal.rb +22 -8
- metadata +11 -2
data/lib/morpheus/cli/apps.rb
CHANGED
@@ -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'].
|
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
|
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.
|
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
|
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
|
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
|
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 !
|
42
|
-
raise "CliCommand #{self.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 =
|
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
|
-
|
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
|
-
|
776
|
-
|
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)
|
data/lib/morpheus/cli/clouds.rb
CHANGED
@@ -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.
|
67
|
+
print_dry_run @clouds_interface.dry.list(params)
|
68
68
|
return 0
|
69
69
|
end
|
70
70
|
|
71
|
-
json_response = @clouds_interface.
|
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.
|
120
|
+
print_dry_run @clouds_interface.dry.list(params)
|
121
121
|
return
|
122
122
|
end
|
123
|
-
json_response = @clouds_interface.
|
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.
|
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.
|
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
|
-
|
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'].
|
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
|
-
|
3643
|
-
|
3644
|
-
|
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
|
-
|
3652
|
-
|
3653
|
-
|
3654
|
-
|
3655
|
-
|
3656
|
-
|
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
|
-
|
3659
|
-
|
3660
|
-
|
3661
|
-
|
3662
|
-
|
3663
|
-
|
3664
|
-
|
3665
|
-
|
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
|
-
|
3670
|
-
|
3671
|
-
|
3672
|
-
|
3673
|
-
|
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
|
-
|
3677
|
-
|
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
|
-
|
3680
|
-
|
3681
|
-
|
3682
|
-
|
3683
|
-
|
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 =
|
3753
|
-
group_access =
|
3754
|
-
all_plans =
|
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
|
3759
|
-
|
3760
|
-
|
3979
|
+
if !excludes.include?('groupAccess')
|
3980
|
+
if options[:groupAccessAll]
|
3981
|
+
all_groups = true
|
3982
|
+
end
|
3761
3983
|
|
3762
|
-
|
3763
|
-
|
3764
|
-
|
3765
|
-
|
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
|
-
|
3768
|
-
|
3769
|
-
|
3770
|
-
|
3771
|
-
|
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
|
-
|
3774
|
-
|
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
|
-
|
3777
|
-
|
3778
|
-
|
3779
|
-
|
3780
|
-
|
3781
|
-
|
3782
|
-
|
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
|
-
|
3785
|
-
|
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
|
-
|
3788
|
-
|
3789
|
-
|
3790
|
-
|
3791
|
-
|
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
|
3802
|
-
|
3803
|
-
|
4025
|
+
if !excludes.include?('planAccess')
|
4026
|
+
if options[:planAccessAll]
|
4027
|
+
all_plans = true
|
4028
|
+
end
|
3804
4029
|
|
3805
|
-
|
3806
|
-
|
3807
|
-
|
3808
|
-
|
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
|
-
|
3811
|
-
|
3812
|
-
|
3813
|
-
|
3814
|
-
|
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
|
-
|
3817
|
-
|
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
|
-
|
3820
|
-
|
3821
|
-
|
3822
|
-
|
3823
|
-
|
3824
|
-
|
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
|
-
|
4051
|
+
available_plans = available_plans.reject {|it| it['value'] == plan_id}
|
3827
4052
|
|
3828
|
-
|
3829
|
-
|
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
|
-
|
3832
|
-
|
3833
|
-
|
3834
|
-
|
3835
|
-
|
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'] =
|
3846
|
-
resource_perms['sites'] = group_access if !group_access.
|
3847
|
-
resource_perms['allPlans'] =
|
3848
|
-
resource_perms['plans'] = plan_access if !plan_access.
|
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 !
|
3863
|
-
|
3864
|
-
|
3865
|
-
|
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
|
-
|
3868
|
-
|
3869
|
-
|
4095
|
+
if !account_id.nil?
|
4096
|
+
accounts << account_id
|
4097
|
+
available_accounts = available_accounts.reject {|it| it['value'] == account_id}
|
3870
4098
|
|
3871
|
-
|
3872
|
-
|
3873
|
-
|
3874
|
-
|
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
|