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
@@ -294,7 +294,7 @@ You can use this to create isolated environments (sandboxes), within which to ex
|
|
294
294
|
|
295
295
|
```shell
|
296
296
|
export MORPHEUS_CLI_HOME=~/morpheus_test
|
297
|
-
morpheus remote add
|
297
|
+
morpheus remote add demo https://demo.mymorpheus.com --insecure
|
298
298
|
morpheus instances list
|
299
299
|
```
|
300
300
|
|
@@ -526,6 +526,7 @@ class Morpheus::Cli::ContainersCommand
|
|
526
526
|
params = {}
|
527
527
|
params.merge!(parse_list_options(options))
|
528
528
|
params[:query] = params.delete(:phrase) unless params[:phrase].nil?
|
529
|
+
params['order'] = params['direction'] unless params['direction'].nil? # old api version expects order instead of direction
|
529
530
|
@logs_interface.setopts(options)
|
530
531
|
if options[:dry_run]
|
531
532
|
print_dry_run @logs_interface.dry.container_logs(containers, params)
|
@@ -546,7 +547,7 @@ class Morpheus::Cli::ContainersCommand
|
|
546
547
|
if logs['data'].empty?
|
547
548
|
puts "#{cyan}No logs found.#{reset}"
|
548
549
|
else
|
549
|
-
logs['data'].
|
550
|
+
logs['data'].each do |log_entry|
|
550
551
|
log_level = ''
|
551
552
|
case log_entry['level']
|
552
553
|
when 'INFO'
|
@@ -106,11 +106,18 @@ module Morpheus
|
|
106
106
|
unless options[:quiet] || options[:no_prompt]
|
107
107
|
# if username.empty? || password.empty?
|
108
108
|
if options[:test_only]
|
109
|
-
print "Test Morpheus Credentials for #{display_appliance(@appliance_name, @appliance_url)}\n",reset
|
109
|
+
print "Test Morpheus Credentials for #{display_appliance(@appliance_name, @appliance_url)}", "\n", reset
|
110
110
|
else
|
111
|
-
print "Enter Morpheus Credentials for #{display_appliance(@appliance_name, @appliance_url)}\n",reset
|
111
|
+
print "Enter Morpheus Credentials for #{display_appliance(@appliance_name, @appliance_url)}", "\n", reset
|
112
112
|
end
|
113
113
|
# end
|
114
|
+
if options[:client_id].empty?
|
115
|
+
# print "Client ID: #{required_blue_prompt} #{options[:client_id]}", "\n", reset
|
116
|
+
else
|
117
|
+
if options[:client_id] != Morpheus::APIClient::CLIENT_ID
|
118
|
+
print "Client ID: #{required_blue_prompt} #{options[:client_id]}", "\n", reset
|
119
|
+
end
|
120
|
+
end
|
114
121
|
if username.empty?
|
115
122
|
print "Username: #{required_blue_prompt} "
|
116
123
|
username = $stdin.gets.chomp!
|
@@ -131,7 +138,7 @@ module Morpheus
|
|
131
138
|
return nil
|
132
139
|
end
|
133
140
|
begin
|
134
|
-
auth_interface = Morpheus::AuthInterface.new(
|
141
|
+
auth_interface = Morpheus::AuthInterface.new({url:@appliance_url, client_id: options[:client_id]})
|
135
142
|
auth_interface.setopts(options)
|
136
143
|
if options[:dry_run]
|
137
144
|
print_dry_run auth_interface.dry.login(username, password)
|
@@ -270,7 +277,7 @@ module Morpheus
|
|
270
277
|
username = wallet['username']
|
271
278
|
|
272
279
|
begin
|
273
|
-
auth_interface = Morpheus::AuthInterface.new(
|
280
|
+
auth_interface = Morpheus::AuthInterface.new({url:@appliance_url})
|
274
281
|
auth_interface.setopts(options)
|
275
282
|
if options[:dry_run]
|
276
283
|
print_dry_run auth_interface.dry.use_refresh_token(wallet['refresh_token'])
|
@@ -414,6 +421,44 @@ module Morpheus
|
|
414
421
|
end
|
415
422
|
end
|
416
423
|
end
|
424
|
+
|
425
|
+
def rename_credentials(appliance_name, new_appliance_name)
|
426
|
+
# reloading file is better for now, otherwise you can lose credentials with multiple shells.
|
427
|
+
credential_map = load_credentials_file || {}
|
428
|
+
|
429
|
+
if new_appliance_name.to_s.empty?
|
430
|
+
puts "Cannot rename credentials without specifying a new name"
|
431
|
+
return nil
|
432
|
+
elsif credential_map[new_appliance_name.to_s] || credential_map[new_appliance_name.to_sym]
|
433
|
+
# yes you can, maybe require --force?
|
434
|
+
puts "Cannot rename credentials to a name that already exists: #{new_appliance_name}"
|
435
|
+
return nil
|
436
|
+
end
|
437
|
+
|
438
|
+
# always remove symbol, which was used pre 3.6.9
|
439
|
+
credential_map.delete(appliance_name.to_sym)
|
440
|
+
begin
|
441
|
+
fn = credentials_file_path
|
442
|
+
if !Dir.exists?(File.dirname(fn))
|
443
|
+
FileUtils.mkdir_p(File.dirname(fn))
|
444
|
+
end
|
445
|
+
#Morpheus::Logging::DarkPrinter.puts "renaming credentials for #{appliance_name} to #{fn}" if Morpheus::Logging.debug?
|
446
|
+
Morpheus::Logging::DarkPrinter.puts "renaming credentials from #{appliance_name} to #{appliance_name}" if Morpheus::Logging.debug?
|
447
|
+
File.open(fn, 'w') {|f| f.write credential_map.to_yaml } #Store
|
448
|
+
FileUtils.chmod(0600, fn)
|
449
|
+
@@appliance_credentials_map = credential_map
|
450
|
+
rescue => e
|
451
|
+
puts "failed to save #{fn}. #{e}" if Morpheus::Logging.debug?
|
452
|
+
ensure
|
453
|
+
# recalcuate echo vars
|
454
|
+
#puts "Recalculating variable maps for username change"
|
455
|
+
Morpheus::Cli::Echo.recalculate_variable_map()
|
456
|
+
# recalculate shell prompt after this change
|
457
|
+
if Morpheus::Cli::Shell.has_instance?
|
458
|
+
Morpheus::Cli::Shell.instance.reinitialize()
|
459
|
+
end
|
460
|
+
end
|
461
|
+
end
|
417
462
|
end
|
418
463
|
end
|
419
464
|
end
|
@@ -36,10 +36,10 @@ class Morpheus::Cli::Deployments
|
|
36
36
|
end
|
37
37
|
@deployments_interface.setopts(options)
|
38
38
|
if options[:dry_run]
|
39
|
-
print_dry_run @deployments_interface.dry.
|
39
|
+
print_dry_run @deployments_interface.dry.list(params)
|
40
40
|
return
|
41
41
|
end
|
42
|
-
json_response = @deployments_interface.
|
42
|
+
json_response = @deployments_interface.list(params)
|
43
43
|
if options[:json]
|
44
44
|
puts JSON.pretty_generate(json_response)
|
45
45
|
else
|
@@ -62,12 +62,12 @@ class Morpheus::Cli::DotFile
|
|
62
62
|
if err.success?
|
63
63
|
cmd_result = true
|
64
64
|
else
|
65
|
-
puts "#{red} source file: #{@filename} line: #{line_num} command: #{line}
|
65
|
+
puts "#{red} source file: #{@filename}, line: #{line_num}, command: #{line}, error: #{err}#{reset}"
|
66
66
|
cmd_result = false
|
67
67
|
end
|
68
68
|
rescue => err
|
69
69
|
# raise err
|
70
|
-
puts "#{red} source file: #{@filename} line: #{line_num} command: #{line}
|
70
|
+
puts "#{red} source file: #{@filename}, line: #{line_num}, command: #{line}, error: #{err}#{reset}"
|
71
71
|
cmd_result = false
|
72
72
|
end
|
73
73
|
if cmd_result == false
|
@@ -16,6 +16,7 @@ class Morpheus::Cli::ErrorHandler
|
|
16
16
|
|
17
17
|
def handle_error(err, options={})
|
18
18
|
exit_code = 1
|
19
|
+
options = (options || {}).clone
|
19
20
|
# heh
|
20
21
|
if Morpheus::Logging.debug? && options[:debug].nil?
|
21
22
|
options[:debug] = true
|
@@ -147,6 +148,8 @@ class Morpheus::Cli::ErrorHandler
|
|
147
148
|
else
|
148
149
|
@stderr.print red, "Error Communicating with the Appliance. #{e}", reset, "\n"
|
149
150
|
end
|
151
|
+
# uh, having this print method return exit_code, err to standardize return values of methods that are still calling it, at the end just by chance..
|
152
|
+
return exit_code, err #.to_s
|
150
153
|
end
|
151
154
|
|
152
155
|
def print_rest_errors(response, options={})
|
@@ -178,7 +181,7 @@ class Morpheus::Cli::ErrorHandler
|
|
178
181
|
end
|
179
182
|
|
180
183
|
def print_rest_request(req)
|
181
|
-
@stderr.print "
|
184
|
+
@stderr.print "REQUEST"
|
182
185
|
@stderr.print "\n"
|
183
186
|
@stderr.print "#{req.method.to_s.upcase} #{req.url.inspect}"
|
184
187
|
@stderr.print "\n"
|
@@ -187,10 +190,10 @@ class Morpheus::Cli::ErrorHandler
|
|
187
190
|
def print_rest_response(res)
|
188
191
|
# size = @raw_response ? File.size(@tf.path) : (res.body.nil? ? 0 : res.body.size)
|
189
192
|
size = (res.body.nil? ? 0 : res.body.size)
|
190
|
-
@stderr.print "
|
193
|
+
@stderr.print "RESPONSE"
|
191
194
|
@stderr.print "\n"
|
192
195
|
display_size = Filesize.from("#{size} B").pretty rescue size
|
193
|
-
@stderr.print "HTTP #{res.net_http_res.code}
|
196
|
+
@stderr.print "HTTP #{res.net_http_res.code} #{res.net_http_res.message} | #{(res['Content-type'] || '').gsub(/;.*$/, '')} #{display_size}"
|
194
197
|
@stderr.print "\n"
|
195
198
|
begin
|
196
199
|
@stderr.print JSON.pretty_generate(JSON.parse(res.body))
|
@@ -680,7 +680,7 @@ class Morpheus::Cli::ExecuteSchedulesCommand
|
|
680
680
|
end
|
681
681
|
|
682
682
|
def find_instance_by_name(name)
|
683
|
-
instances = @instances_interface.
|
683
|
+
instances = @instances_interface.list({name: name.to_s})['instances']
|
684
684
|
if instances.empty?
|
685
685
|
print_red_alert "Instance not found by name #{name}"
|
686
686
|
return nil
|
data/lib/morpheus/cli/groups.rb
CHANGED
@@ -45,10 +45,10 @@ class Morpheus::Cli::Groups
|
|
45
45
|
params.merge!(parse_list_options(options))
|
46
46
|
@groups_interface.setopts(options)
|
47
47
|
if options[:dry_run]
|
48
|
-
print_dry_run @groups_interface.
|
48
|
+
print_dry_run @groups_interface.list(params)
|
49
49
|
return 0
|
50
50
|
end
|
51
|
-
json_response = @groups_interface.
|
51
|
+
json_response = @groups_interface.list(params)
|
52
52
|
render_result = render_with_format(json_response, options, 'groups')
|
53
53
|
return 0 if render_result
|
54
54
|
|
@@ -69,7 +69,7 @@ class Morpheus::Cli::Groups
|
|
69
69
|
#end
|
70
70
|
else
|
71
71
|
unless options[:remote]
|
72
|
-
print "\n# => No active group, see `groups use`\n", reset
|
72
|
+
print cyan, "\n# => No active group, see `groups use`\n", reset
|
73
73
|
end
|
74
74
|
end
|
75
75
|
end
|
@@ -107,7 +107,7 @@ class Morpheus::Cli::Groups
|
|
107
107
|
if arg.to_s =~ /\A\d{1,}\Z/
|
108
108
|
print_dry_run @groups_interface.dry.get(arg.to_i)
|
109
109
|
else
|
110
|
-
print_dry_run @groups_interface.dry.
|
110
|
+
print_dry_run @groups_interface.dry.list({name:arg})
|
111
111
|
end
|
112
112
|
return 0
|
113
113
|
end
|
data/lib/morpheus/cli/hosts.rb
CHANGED
@@ -577,6 +577,7 @@ class Morpheus::Cli::Hosts
|
|
577
577
|
params = {}
|
578
578
|
params.merge!(parse_list_options(options))
|
579
579
|
params[:query] = params.delete(:phrase) unless params[:phrase].nil?
|
580
|
+
params[:order] = params[:direction] unless params[:direction].nil? # old api version expects order instead of direction
|
580
581
|
@logs_interface.setopts(options)
|
581
582
|
if options[:dry_run]
|
582
583
|
print_dry_run @logs_interface.dry.server_logs([server['id']], params)
|
@@ -600,7 +601,7 @@ class Morpheus::Cli::Hosts
|
|
600
601
|
if logs['data'].empty?
|
601
602
|
puts "#{cyan}No logs found.#{reset}"
|
602
603
|
else
|
603
|
-
logs['data'].
|
604
|
+
logs['data'].each do |log_entry|
|
604
605
|
log_level = ''
|
605
606
|
case log_entry['level']
|
606
607
|
when 'INFO'
|
@@ -1805,7 +1806,7 @@ class Morpheus::Cli::Hosts
|
|
1805
1806
|
exit 1
|
1806
1807
|
end
|
1807
1808
|
else
|
1808
|
-
json_results = @clouds_interface.
|
1809
|
+
json_results = @clouds_interface.list({groupId: group_id, name: val})
|
1809
1810
|
zone = json_results['zones'] ? json_results['zones'][0] : nil
|
1810
1811
|
if zone.nil?
|
1811
1812
|
print_red_alert "Cloud not found by name #{val}"
|
@@ -739,27 +739,6 @@ class Morpheus::Cli::ImageBuilderCommand
|
|
739
739
|
end
|
740
740
|
end
|
741
741
|
|
742
|
-
# def find_group_by_name(name)
|
743
|
-
# group_results = @groups_interface.get(name)
|
744
|
-
# if group_results['groups'].empty?
|
745
|
-
# print_red_alert "Group not found by name #{name}"
|
746
|
-
# return nil
|
747
|
-
# end
|
748
|
-
# return group_results['groups'][0]
|
749
|
-
# end
|
750
|
-
|
751
|
-
# def find_cloud_by_name(group_id, name)
|
752
|
-
# option_results = @options_interface.options_for_source('clouds',{groupId: group_id})
|
753
|
-
# match = option_results['data'].find { |grp| grp['value'].to_s == name.to_s || grp['name'].downcase == name.downcase}
|
754
|
-
# if match.nil?
|
755
|
-
# print_red_alert "Cloud not found by name #{name}"
|
756
|
-
# return nil
|
757
|
-
# else
|
758
|
-
# return match['value']
|
759
|
-
# end
|
760
|
-
# end
|
761
|
-
|
762
|
-
|
763
742
|
def format_image_build_status(image_build, return_color=cyan)
|
764
743
|
out = ""
|
765
744
|
return out if !image_build
|
@@ -966,7 +966,7 @@ class Morpheus::Cli::Instances
|
|
966
966
|
"[instance] is required. This is the name or id of an instance. Supports 1-N [instance] arguments."
|
967
967
|
end
|
968
968
|
optparse.parse!(args)
|
969
|
-
if args.count
|
969
|
+
if args.count < 1
|
970
970
|
raise_command_error "wrong number of arguments, expected 1 and got (#{args.count}) #{args.join(' ')}\n#{optparse}"
|
971
971
|
end
|
972
972
|
connect(options)
|
@@ -1011,6 +1011,7 @@ class Morpheus::Cli::Instances
|
|
1011
1011
|
end
|
1012
1012
|
|
1013
1013
|
def logs(args)
|
1014
|
+
params = {}
|
1014
1015
|
options = {}
|
1015
1016
|
optparse = Morpheus::Cli::OptionParser.new do |opts|
|
1016
1017
|
opts.banner = subcommand_usage("[instance]")
|
@@ -1031,9 +1032,9 @@ class Morpheus::Cli::Instances
|
|
1031
1032
|
if options[:node_id] && container_ids.include?(options[:node_id])
|
1032
1033
|
container_ids = [options[:node_id]]
|
1033
1034
|
end
|
1034
|
-
params = {}
|
1035
1035
|
params.merge!(parse_list_options(options))
|
1036
1036
|
params[:query] = params.delete(:phrase) unless params[:phrase].nil?
|
1037
|
+
params['order'] = params['direction'] unless params['direction'].nil? # old api version expects order instead of direction
|
1037
1038
|
@logs_interface.setopts(options)
|
1038
1039
|
if options[:dry_run]
|
1039
1040
|
print_dry_run @logs_interface.dry.container_logs(container_ids, params)
|
@@ -1054,7 +1055,7 @@ class Morpheus::Cli::Instances
|
|
1054
1055
|
if logs['data'].empty?
|
1055
1056
|
puts "#{cyan}No logs found.#{reset}"
|
1056
1057
|
else
|
1057
|
-
logs['data'].
|
1058
|
+
logs['data'].each do |log_entry|
|
1058
1059
|
log_level = ''
|
1059
1060
|
case log_entry['level']
|
1060
1061
|
when 'INFO'
|
@@ -1539,6 +1540,9 @@ class Morpheus::Cli::Instances
|
|
1539
1540
|
opts.on( '-c', '--cloud CLOUD', "Cloud Name or ID for the new instance" ) do |val|
|
1540
1541
|
options[:cloud] = val
|
1541
1542
|
end
|
1543
|
+
opts.on("--create-user on|off", String, "User Config: Create Your User. Default is on") do |val|
|
1544
|
+
options[:create_user] = !['false','off','0'].include?(val.to_s)
|
1545
|
+
end
|
1542
1546
|
build_common_options(opts, options, [:options, :payload, :auto_confirm, :json, :dry_run, :remote])
|
1543
1547
|
end
|
1544
1548
|
optparse.parse!(args)
|
@@ -1607,6 +1611,15 @@ class Morpheus::Cli::Instances
|
|
1607
1611
|
passed_options.delete('group')
|
1608
1612
|
payload.deep_merge!(passed_options)
|
1609
1613
|
end
|
1614
|
+
|
1615
|
+
# JD: this actually fixed a customer problem
|
1616
|
+
# It appears to be important to pass this... not sure if config.createUser is necessary...
|
1617
|
+
if options[:create_user].nil?
|
1618
|
+
options[:create_user] = true
|
1619
|
+
end
|
1620
|
+
if options[:create_user] != nil
|
1621
|
+
payload.deep_merge!({'createUser' => options[:create_user], 'config' =>{'createUser' => options[:create_user]}})
|
1622
|
+
end
|
1610
1623
|
unless options[:yes] || ::Morpheus::Cli::OptionTypes::confirm("Are you sure you would like to clone the instance #{instance['name']} as '#{payload['name']}'?", options)
|
1611
1624
|
return 9, "aborted command"
|
1612
1625
|
end
|
@@ -3626,7 +3639,7 @@ private
|
|
3626
3639
|
end
|
3627
3640
|
|
3628
3641
|
def find_workflow_by_name(name)
|
3629
|
-
workflows = @task_sets_interface.
|
3642
|
+
workflows = @task_sets_interface.list({name: name.to_s})['taskSets']
|
3630
3643
|
if workflows.empty?
|
3631
3644
|
print_red_alert "Workflow not found by name #{name}"
|
3632
3645
|
return nil
|
@@ -315,7 +315,7 @@ class Morpheus::Cli::LibraryContainerTypesCommand
|
|
315
315
|
# err, these optionTypes have the fieldContext
|
316
316
|
# so merge them at the root level of the request.
|
317
317
|
|
318
|
-
provision_types = @provision_types_interface.
|
318
|
+
provision_types = @provision_types_interface.list({customSupported: true})['provisionTypes']
|
319
319
|
if provision_types.empty?
|
320
320
|
print_red_alert "No available provision types found!"
|
321
321
|
return 1
|
@@ -331,7 +331,7 @@ class Morpheus::Cli::LibraryLayoutsCommand
|
|
331
331
|
params['description'] = v_prompt['description'] if v_prompt['description']
|
332
332
|
end
|
333
333
|
|
334
|
-
provision_types = @provision_types_interface.
|
334
|
+
provision_types = @provision_types_interface.list({customSupported: true})['provisionTypes']
|
335
335
|
if provision_types.empty?
|
336
336
|
print_red_alert "No available provision types found!"
|
337
337
|
exit 1
|
@@ -288,7 +288,7 @@ class Morpheus::Cli::LibraryUpgradesCommand
|
|
288
288
|
end
|
289
289
|
|
290
290
|
|
291
|
-
# provision_types = @provision_types_interface.
|
291
|
+
# provision_types = @provision_types_interface.list({customSupported: true})['provisionTypes']
|
292
292
|
# if provision_types.empty?
|
293
293
|
# print_red_alert "No available provision types found!"
|
294
294
|
# exit 1
|
data/lib/morpheus/cli/license.rb
CHANGED
@@ -6,8 +6,10 @@ require 'morpheus/cli/cli_command'
|
|
6
6
|
class Morpheus::Cli::License
|
7
7
|
include Morpheus::Cli::CliCommand
|
8
8
|
|
9
|
-
register_subcommands :get, :
|
10
|
-
|
9
|
+
register_subcommands :get, :install, :uninstall, :test
|
10
|
+
# deprecated
|
11
|
+
register_subcommands :decode, :apply
|
12
|
+
#alias_subcommand :details, :get
|
11
13
|
|
12
14
|
def initialize()
|
13
15
|
# @appliance_name, @appliance_url = Morpheus::Cli::Remote.active_appliance
|
@@ -25,50 +27,82 @@ class Morpheus::Cli::License
|
|
25
27
|
|
26
28
|
def get(args)
|
27
29
|
options = {}
|
30
|
+
params = {}
|
28
31
|
optparse = Morpheus::Cli::OptionParser.new do |opts|
|
29
32
|
opts.banner = subcommand_usage()
|
30
|
-
build_common_options(opts, options, [:json, :dry_run, :remote])
|
33
|
+
build_common_options(opts, options, [:json, :yaml, :fields, :dry_run, :remote])
|
34
|
+
opts.footer = "Get details about the currently installed license.\n" +
|
35
|
+
"This information includes license features and limits.\n" +
|
36
|
+
"The actual secret license key value will never be returned."
|
31
37
|
end
|
32
38
|
optparse.parse!(args)
|
39
|
+
if args.count > 0
|
40
|
+
raise_command_error "wrong number of arguments, expected 0 and got (#{args.count}) #{args.join(' ')}\n#{optparse}"
|
41
|
+
end
|
33
42
|
connect(options)
|
34
43
|
begin
|
44
|
+
# make api request
|
35
45
|
@license_interface.setopts(options)
|
36
46
|
if options[:dry_run]
|
37
47
|
print_dry_run @license_interface.dry.get()
|
38
|
-
return
|
48
|
+
return 0, nil
|
39
49
|
end
|
40
|
-
|
41
|
-
|
42
|
-
|
43
|
-
|
44
|
-
|
45
|
-
|
46
|
-
|
47
|
-
|
48
|
-
|
49
|
-
|
50
|
-
|
51
|
-
max_memory = "Unlimited"
|
52
|
-
max_storage = "Unlimited"
|
53
|
-
max_memory = Filesize.from("#{license['maxMemory']} B").pretty if license['maxMemory'].to_i != 0
|
54
|
-
max_storage = Filesize.from("#{license['maxStorage']} B").pretty if license['maxStorage'].to_i != 0
|
55
|
-
used_memory = Filesize.from("#{used_memory} B").pretty if used_memory.to_i != 0
|
56
|
-
print cyan
|
57
|
-
description_cols = {
|
58
|
-
"Account" => 'accountName',
|
59
|
-
"Product Tier" => lambda {|it| format_product_tier(it) },
|
60
|
-
"Start Date" => lambda {|it| format_local_dt(it['startDate']) },
|
61
|
-
"End Date" => lambda {|it| format_local_dt(it['endDate']) },
|
62
|
-
"Memory" => lambda {|it| "#{used_memory} / #{max_memory}" },
|
63
|
-
"Max Storage" => lambda {|it| "#{max_storage}" },
|
64
|
-
"Max Instances" => lambda {|it| it["maxInstances"].to_i == 0 ? 'Unlimited' : it["maxInstances"] },
|
65
|
-
"Hard Limit" => lambda {|it| it[""] == false ? 'Yes' : 'No' },
|
66
|
-
}
|
67
|
-
print_description_list(description_cols, license)
|
68
|
-
print reset,"\n"
|
69
|
-
end
|
50
|
+
json_response = @license_interface.get()
|
51
|
+
# 200 OK, parse results
|
52
|
+
license = json_response['license']
|
53
|
+
used_memory = json_response['licenseUsedMemory']
|
54
|
+
|
55
|
+
# Determine exit status and any error conditions for the command
|
56
|
+
exit_code = 0
|
57
|
+
err = nil
|
58
|
+
if license.nil?
|
59
|
+
exit_code = 1
|
60
|
+
err = "No license currently installed."
|
70
61
|
end
|
71
|
-
|
62
|
+
|
63
|
+
# render common formats like dry run, curl, json , yaml , etc.
|
64
|
+
render_result = render_with_format(json_response, options)
|
65
|
+
return exit_code, err if render_result
|
66
|
+
|
67
|
+
if options[:quiet]
|
68
|
+
return exit_code, err
|
69
|
+
end
|
70
|
+
|
71
|
+
# if exit_code != 0
|
72
|
+
# print_error red, err.to_s, reset, "\n"
|
73
|
+
# return exit_code, err
|
74
|
+
# end
|
75
|
+
|
76
|
+
# render output
|
77
|
+
|
78
|
+
print_h1 "License"
|
79
|
+
max_memory = "Unlimited"
|
80
|
+
max_storage = "Unlimited"
|
81
|
+
max_memory = Filesize.from("#{license['maxMemory']} B").pretty if license['maxMemory'].to_i != 0
|
82
|
+
max_storage = Filesize.from("#{license['maxStorage']} B").pretty if license['maxStorage'].to_i != 0
|
83
|
+
used_memory = Filesize.from("#{used_memory} B").pretty if used_memory.to_i != 0
|
84
|
+
print cyan
|
85
|
+
description_cols = {
|
86
|
+
"Account" => 'accountName',
|
87
|
+
"Product Tier" => lambda {|it| format_product_tier(it) },
|
88
|
+
"Start Date" => lambda {|it| format_local_dt(it['startDate']) },
|
89
|
+
"End Date" => lambda {|it|
|
90
|
+
if it['endDate']
|
91
|
+
format_local_dt(it['endDate']).to_s + ' (' + format_duration(Time.now, it['endDate']).to_s + ')'
|
92
|
+
else
|
93
|
+
'Never'
|
94
|
+
end
|
95
|
+
},
|
96
|
+
"Memory" => lambda {|it| "#{used_memory} / #{max_memory}" },
|
97
|
+
"Max Storage" => lambda {|it| "#{max_storage}" },
|
98
|
+
"Max Instances" => lambda {|it| it["maxInstances"].to_i == 0 ? 'Unlimited' : it["maxInstances"] },
|
99
|
+
"Hard Limit" => lambda {|it| it[""] == false ? 'Yes' : 'No' },
|
100
|
+
}
|
101
|
+
print_description_list(description_cols, license)
|
102
|
+
print reset,"\n"
|
103
|
+
|
104
|
+
return exit_code, err
|
105
|
+
|
72
106
|
rescue RestClient::Exception => e
|
73
107
|
print_rest_exception(e, options)
|
74
108
|
return false
|
@@ -76,6 +110,11 @@ class Morpheus::Cli::License
|
|
76
110
|
end
|
77
111
|
|
78
112
|
def apply(args)
|
113
|
+
print_error "#{yellow}DEPRECATION WARNING: `license apply` has been deprecated and replaced with `license install`. Please use `license install` instead.#{reset}\n"
|
114
|
+
install(args)
|
115
|
+
end
|
116
|
+
|
117
|
+
def install(args)
|
79
118
|
options = {}
|
80
119
|
account_name = nil
|
81
120
|
optparse = Morpheus::Cli::OptionParser.new do |opts|
|
@@ -83,6 +122,9 @@ class Morpheus::Cli::License
|
|
83
122
|
build_common_options(opts, options, [:json, :dry_run, :remote])
|
84
123
|
end
|
85
124
|
optparse.parse!(args)
|
125
|
+
if args.count > 1
|
126
|
+
raise_command_error "wrong number of arguments, expected 0-1 and got (#{args.count}) #{args.join(' ')}\n#{optparse}"
|
127
|
+
end
|
86
128
|
connect(options)
|
87
129
|
begin
|
88
130
|
if args[0]
|
@@ -93,13 +135,13 @@ class Morpheus::Cli::License
|
|
93
135
|
end
|
94
136
|
@license_interface.setopts(options)
|
95
137
|
if options[:dry_run]
|
96
|
-
print_dry_run @license_interface.dry.
|
138
|
+
print_dry_run @license_interface.dry.install(key)
|
97
139
|
return 0
|
98
140
|
end
|
99
|
-
|
100
|
-
license =
|
141
|
+
json_response = @license_interface.install(key)
|
142
|
+
license = json_response['license']
|
101
143
|
if options[:json]
|
102
|
-
puts JSON.pretty_generate(
|
144
|
+
puts JSON.pretty_generate(json_response)
|
103
145
|
else
|
104
146
|
print_green_success "License applied successfully!"
|
105
147
|
# get([]) # show it
|
@@ -112,13 +154,22 @@ class Morpheus::Cli::License
|
|
112
154
|
end
|
113
155
|
|
114
156
|
def decode(args)
|
157
|
+
print_error "#{yellow}DEPRECATION WARNING: `license decode` has been deprecated and replaced with `license test`. Please use `license test` instead.#{reset}\n"
|
158
|
+
test(args)
|
159
|
+
end
|
160
|
+
|
161
|
+
def test(args)
|
115
162
|
options = {}
|
116
163
|
optparse = Morpheus::Cli::OptionParser.new do |opts|
|
117
164
|
opts.banner = subcommand_usage("[key]")
|
118
|
-
build_common_options(opts, options, [:json, :dry_run, :remote])
|
119
|
-
opts.footer = "
|
165
|
+
build_common_options(opts, options, [:json, :yaml, :csv, :fields, :dry_run, :remote])
|
166
|
+
opts.footer = "Test a license key.\n" +
|
167
|
+
"This is a way to decode and view a license key before installing it."
|
120
168
|
end
|
121
169
|
optparse.parse!(args)
|
170
|
+
if args.count > 1
|
171
|
+
raise_command_error "wrong number of arguments, expected 0-1 and got (#{args.count}) #{args.join(' ')}\n#{optparse}"
|
172
|
+
end
|
122
173
|
connect(options)
|
123
174
|
key = nil
|
124
175
|
if args[0]
|
@@ -130,46 +181,108 @@ class Morpheus::Cli::License
|
|
130
181
|
begin
|
131
182
|
@license_interface.setopts(options)
|
132
183
|
if options[:dry_run]
|
133
|
-
print_dry_run @license_interface.dry.
|
184
|
+
print_dry_run @license_interface.dry.test(key)
|
134
185
|
return
|
135
186
|
end
|
136
|
-
|
137
|
-
license =
|
138
|
-
|
139
|
-
|
140
|
-
|
141
|
-
|
142
|
-
|
143
|
-
|
144
|
-
|
145
|
-
|
146
|
-
|
147
|
-
|
148
|
-
|
149
|
-
|
150
|
-
|
151
|
-
|
152
|
-
|
153
|
-
|
154
|
-
|
155
|
-
|
156
|
-
|
157
|
-
|
158
|
-
|
159
|
-
|
160
|
-
|
161
|
-
|
162
|
-
|
163
|
-
|
164
|
-
|
187
|
+
json_response = @license_interface.test(key)
|
188
|
+
license = json_response['license']
|
189
|
+
|
190
|
+
exit_code, err = 0, nil
|
191
|
+
if license.nil?
|
192
|
+
err = "Unable to decode license."
|
193
|
+
exit_code = 1
|
194
|
+
#return err, exit_code
|
195
|
+
end
|
196
|
+
render_result = render_with_format(json_response, options)
|
197
|
+
if render_result
|
198
|
+
return exit_code, err
|
199
|
+
end
|
200
|
+
if options[:quiet]
|
201
|
+
return exit_code, err
|
202
|
+
end
|
203
|
+
if exit_code != 0
|
204
|
+
print_error red, err.to_s, reset, "\n"
|
205
|
+
return exit_code, err
|
206
|
+
end
|
207
|
+
|
208
|
+
# all good
|
209
|
+
print_h1 "License"
|
210
|
+
max_memory = "Unlimited"
|
211
|
+
max_storage = "Unlimited"
|
212
|
+
max_memory = Filesize.from("#{license['maxMemory']} B").pretty if license['maxMemory'].to_i != 0
|
213
|
+
max_storage = Filesize.from("#{license['maxStorage']} B").pretty if license['maxStorage'].to_i != 0
|
214
|
+
print cyan
|
215
|
+
description_cols = {
|
216
|
+
"Account" => 'accountName',
|
217
|
+
"Product Tier" => lambda {|it| format_product_tier(it) },
|
218
|
+
"Start Date" => lambda {|it| format_local_dt(it['startDate']) },
|
219
|
+
"End Date" => lambda {|it| format_local_dt(it['endDate']) },
|
220
|
+
"Max Memory" => lambda {|it| max_memory },
|
221
|
+
"Max Storage" => lambda {|it| max_storage },
|
222
|
+
"Max Instances" => lambda {|it| it["maxInstances"].to_i == 0 ? 'Unlimited' : it["maxInstances"] },
|
223
|
+
"Hard Limit" => lambda {|it| it[""] == false ? 'Yes' : 'No' },
|
224
|
+
}
|
225
|
+
print_description_list(description_cols, license)
|
226
|
+
print reset,"\n"
|
227
|
+
return exit_code, err
|
228
|
+
rescue RestClient::Exception => e
|
229
|
+
print_rest_exception(e, options)
|
230
|
+
return 1
|
231
|
+
end
|
232
|
+
end
|
233
|
+
|
234
|
+
def uninstall(args)
|
235
|
+
options = {}
|
236
|
+
params = {}
|
237
|
+
optparse = Morpheus::Cli::OptionParser.new do |opts|
|
238
|
+
opts.banner = subcommand_usage("[key]")
|
239
|
+
build_common_options(opts, options, [:auto_confirm, :json, :yaml, :dry_run, :remote])
|
240
|
+
opts.footer = "Uninstall the current license key.\n" +
|
241
|
+
"This clears out the current license key from the appliance.\n" +
|
242
|
+
"The function of the remote appliance will be restricted without a license installed.\n" +
|
243
|
+
"Be careful using this."
|
244
|
+
end
|
245
|
+
optparse.parse!(args)
|
246
|
+
if args.count > 0
|
247
|
+
raise_command_error "wrong number of arguments, expected 0 and got (#{args.count}) #{args.join(' ')}\n#{optparse}"
|
248
|
+
end
|
249
|
+
connect(options)
|
250
|
+
begin
|
251
|
+
@license_interface.setopts(options)
|
252
|
+
if options[:dry_run]
|
253
|
+
print_dry_run @license_interface.dry.uninstall(params)
|
254
|
+
return
|
255
|
+
end
|
256
|
+
|
257
|
+
unless options[:quiet]
|
258
|
+
print cyan,"#{bold}WARNING!#{reset}#{cyan} You are about to uninstall your license key.",reset,"\n"
|
259
|
+
print yellow, "Be careful using this. Make sure you have a copy of your key somewhere if you intend to use it again.",reset, "\n"
|
260
|
+
print "\n"
|
261
|
+
end
|
262
|
+
|
263
|
+
unless options[:yes] || ::Morpheus::Cli::OptionTypes::confirm("Are you sure you want to uninstall the license key for remote #{@appliance_name} - #{@appliance_url}?")
|
264
|
+
return 9, "command aborted"
|
165
265
|
end
|
266
|
+
|
267
|
+
json_response = @license_interface.uninstall(params)
|
268
|
+
|
269
|
+
@apps_interface.setopts(options)
|
270
|
+
if options[:dry_run]
|
271
|
+
print_dry_run @apps_interface.dry.wiki(app["id"], params)
|
272
|
+
return
|
273
|
+
end
|
274
|
+
render_result = render_with_format(json_response, options)
|
275
|
+
return 0 if render_result
|
276
|
+
return 0 if options[:quiet]
|
277
|
+
print_green_success "License uninstalled!"
|
166
278
|
return 0
|
167
279
|
rescue RestClient::Exception => e
|
168
280
|
print_rest_exception(e, options)
|
169
|
-
return
|
281
|
+
return 1
|
170
282
|
end
|
171
283
|
end
|
172
284
|
|
285
|
+
|
173
286
|
def format_product_tier(license)
|
174
287
|
product_tier = license['productTier'] || 'capacity'
|
175
288
|
if product_tier == 'capacity'
|