morpheus-cli 4.2.8 → 4.2.10
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/Dockerfile +1 -1
- data/lib/morpheus/api.rb +1 -1
- data/lib/morpheus/api/activity_interface.rb +9 -0
- data/lib/morpheus/api/api_client.rb +83 -27
- data/lib/morpheus/api/apps_interface.rb +21 -0
- data/lib/morpheus/api/dashboard_interface.rb +5 -21
- data/lib/morpheus/api/instances_interface.rb +3 -10
- data/lib/morpheus/api/invoice_line_items_interface.rb +14 -0
- data/lib/morpheus/api/invoices_interface.rb +7 -12
- data/lib/morpheus/api/library_layouts_interface.rb +8 -0
- data/lib/morpheus/api/ping_interface.rb +20 -0
- data/lib/morpheus/api/projects_interface.rb +33 -0
- data/lib/morpheus/api/setup_interface.rb +19 -36
- data/lib/morpheus/api/user_settings_interface.rb +0 -6
- data/lib/morpheus/api/whoami_interface.rb +4 -8
- data/lib/morpheus/benchmarking.rb +16 -26
- data/lib/morpheus/cli.rb +10 -5
- data/lib/morpheus/cli/access_token_command.rb +5 -8
- data/lib/morpheus/cli/activity_command.rb +146 -0
- data/lib/morpheus/cli/apps.rb +312 -121
- data/lib/morpheus/cli/archives_command.rb +1 -1
- data/lib/morpheus/cli/auth_command.rb +4 -11
- data/lib/morpheus/cli/blueprints_command.rb +196 -137
- data/lib/morpheus/cli/change_password_command.rb +1 -1
- data/lib/morpheus/cli/cli_command.rb +225 -72
- data/lib/morpheus/cli/cli_registry.rb +2 -2
- data/lib/morpheus/cli/cloud_datastores_command.rb +1 -1
- data/lib/morpheus/cli/clouds.rb +5 -20
- data/lib/morpheus/cli/clusters.rb +4 -28
- data/lib/morpheus/cli/commands/standard/alias_command.rb +2 -9
- data/lib/morpheus/cli/commands/standard/benchmark_command.rb +2 -0
- data/lib/morpheus/cli/commands/standard/curl_command.rb +2 -3
- data/lib/morpheus/cli/commands/standard/history_command.rb +3 -6
- data/lib/morpheus/cli/commands/standard/man_command.rb +10 -7
- data/lib/morpheus/cli/commands/standard/ssl_verification_command.rb +10 -9
- data/lib/morpheus/cli/containers_command.rb +3 -3
- data/lib/morpheus/cli/credentials.rb +13 -16
- data/lib/morpheus/cli/error_handler.rb +18 -12
- data/lib/morpheus/cli/errors.rb +45 -0
- data/lib/morpheus/cli/execute_schedules_command.rb +1 -1
- data/lib/morpheus/cli/execution_request_command.rb +4 -4
- data/lib/morpheus/cli/groups.rb +84 -132
- data/lib/morpheus/cli/hosts.rb +6 -16
- data/lib/morpheus/cli/instances.rb +100 -183
- data/lib/morpheus/cli/invoices_command.rb +505 -71
- data/lib/morpheus/cli/library_layouts_command.rb +254 -166
- data/lib/morpheus/cli/library_option_lists_command.rb +0 -87
- data/lib/morpheus/cli/library_option_types_command.rb +0 -96
- data/lib/morpheus/cli/license.rb +3 -0
- data/lib/morpheus/cli/login.rb +17 -37
- data/lib/morpheus/cli/logout.rb +9 -5
- data/lib/morpheus/cli/mixins/accounts_helper.rb +83 -7
- data/lib/morpheus/cli/mixins/operations_helper.rb +41 -0
- data/lib/morpheus/cli/mixins/option_source_helper.rb +255 -0
- data/lib/morpheus/cli/mixins/print_helper.rb +18 -4
- data/lib/morpheus/cli/mixins/provisioning_helper.rb +222 -13
- data/lib/morpheus/cli/mixins/remote_helper.rb +139 -0
- data/lib/morpheus/cli/monitoring_checks_command.rb +11 -3
- data/lib/morpheus/cli/network_groups_command.rb +8 -2
- data/lib/morpheus/cli/option_types.rb +1 -1
- data/lib/morpheus/cli/ping.rb +252 -0
- data/lib/morpheus/cli/price_sets_command.rb +16 -27
- data/lib/morpheus/cli/prices_command.rb +34 -27
- data/lib/morpheus/cli/processes_command.rb +81 -7
- data/lib/morpheus/cli/projects_command.rb +607 -0
- data/lib/morpheus/cli/recent_activity_command.rb +87 -65
- data/lib/morpheus/cli/remote.rb +965 -974
- data/lib/morpheus/cli/reports_command.rb +3 -15
- data/lib/morpheus/cli/roles.rb +8 -31
- data/lib/morpheus/cli/service_plans_command.rb +25 -31
- data/lib/morpheus/cli/setup.rb +392 -0
- data/lib/morpheus/cli/shell.rb +144 -56
- data/lib/morpheus/cli/subnets_command.rb +71 -11
- data/lib/morpheus/cli/tasks.rb +3 -3
- data/lib/morpheus/cli/user_sources_command.rb +4 -4
- data/lib/morpheus/cli/users.rb +135 -109
- data/lib/morpheus/cli/version.rb +1 -1
- data/lib/morpheus/cli/whitelabel_settings_command.rb +7 -7
- data/lib/morpheus/cli/whoami.rb +90 -129
- data/lib/morpheus/cli/wiki_command.rb +2 -14
- data/lib/morpheus/ext/rest_client.rb +36 -0
- data/lib/morpheus/formatters.rb +42 -5
- data/lib/morpheus/rest_client.rb +0 -10
- data/lib/morpheus/terminal.rb +41 -1
- data/lib/morpheus/util.rb +24 -0
- metadata +16 -3
- data/lib/morpheus/cli/command_error.rb +0 -22
@@ -1,7 +1,4 @@
|
|
1
|
-
require 'optparse'
|
2
1
|
require 'morpheus/cli/cli_command'
|
3
|
-
require 'morpheus/cli/mixins/accounts_helper'
|
4
|
-
require 'json'
|
5
2
|
|
6
3
|
class Morpheus::Cli::RecentActivityCommand
|
7
4
|
include Morpheus::Cli::CliCommand
|
@@ -9,6 +6,9 @@ class Morpheus::Cli::RecentActivityCommand
|
|
9
6
|
|
10
7
|
set_command_name :'recent-activity'
|
11
8
|
|
9
|
+
# deprecated 4.2.10
|
10
|
+
set_command_hidden
|
11
|
+
|
12
12
|
def initialize()
|
13
13
|
# @appliance_name, @appliance_url = Morpheus::Cli::Remote.active_appliance
|
14
14
|
end
|
@@ -19,58 +19,89 @@ class Morpheus::Cli::RecentActivityCommand
|
|
19
19
|
@accounts_interface = @api_client.accounts
|
20
20
|
end
|
21
21
|
|
22
|
-
def usage
|
23
|
-
|
24
|
-
end
|
22
|
+
# def usage
|
23
|
+
# "Usage: morpheus #{command_name}"
|
24
|
+
# end
|
25
25
|
|
26
26
|
def handle(args)
|
27
|
+
print_error yellow,"[DEPRECATED] The command `recent-activity` is deprecated. It has been replaced by `activity list`.",reset,"\n"
|
27
28
|
list(args)
|
28
29
|
end
|
30
|
+
|
29
31
|
def list(args)
|
30
|
-
options = {}
|
32
|
+
params, options = {}, {}
|
31
33
|
optparse = Morpheus::Cli::OptionParser.new do |opts|
|
32
34
|
opts.banner = usage
|
35
|
+
opts.on( '-u', '--user USER', "Username or ID" ) do |val|
|
36
|
+
options[:user] = val
|
37
|
+
end
|
33
38
|
opts.on('--start TIMESTAMP','--start TIMESTAMP', "Start timestamp. Default is 30 days ago.") do |val|
|
34
39
|
options[:start] = parse_time(val).utc.iso8601
|
35
40
|
end
|
36
41
|
opts.on('--end TIMESTAMP','--end TIMESTAMP', "End timestamp. Default is now.") do |val|
|
37
42
|
options[:end] = parse_time(val).utc.iso8601
|
38
43
|
end
|
39
|
-
|
44
|
+
build_standard_get_options(opts, options)
|
45
|
+
opts.footer = <<-EOT
|
46
|
+
List recent activity.
|
47
|
+
This command is deprecated. Use `activity` instead.
|
48
|
+
EOT
|
40
49
|
end
|
50
|
+
# parse options
|
41
51
|
optparse.parse!(args)
|
52
|
+
# parse arguments
|
53
|
+
verify_args!(args:args, count:0, optparse:optparse)
|
54
|
+
# establish connection to @remote_appliance
|
42
55
|
connect(options)
|
43
|
-
|
44
|
-
|
45
|
-
|
46
|
-
|
47
|
-
|
48
|
-
|
49
|
-
|
50
|
-
|
51
|
-
|
52
|
-
|
53
|
-
|
54
|
-
|
55
|
-
|
56
|
-
|
57
|
-
|
58
|
-
end
|
59
|
-
|
56
|
+
# construct request
|
57
|
+
#params.merge!(parse_query_options(options)) # inject -Q PARAMS
|
58
|
+
params.merge!(parse_list_options(options)) # inject phrase,sort,max,offset and -Q PARAMS
|
59
|
+
# parse my options
|
60
|
+
# this api allows filter by params.accountId
|
61
|
+
# todo: use OptionSourceHelper parse_tenant_id() instead of AccountsHelper
|
62
|
+
account = find_account_from_options(options)
|
63
|
+
account_id = account ? account['id'] : nil
|
64
|
+
if account_id
|
65
|
+
params['accountId'] = account_id
|
66
|
+
end
|
67
|
+
if options[:start]
|
68
|
+
params['start'] = options[:start]
|
69
|
+
end
|
70
|
+
if options[:end]
|
71
|
+
params['end'] = options[:end]
|
72
|
+
end
|
60
73
|
|
61
|
-
|
62
|
-
|
63
|
-
|
64
|
-
|
65
|
-
|
66
|
-
|
67
|
-
|
68
|
-
|
69
|
-
|
70
|
-
|
71
|
-
|
72
|
-
|
73
|
-
|
74
|
+
# parse --user
|
75
|
+
if options[:user]
|
76
|
+
user_ids = parse_user_id_list(options[:user])
|
77
|
+
return 1 if user_ids.nil?
|
78
|
+
# userId limited to one right now
|
79
|
+
# params['userId'] = user_ids
|
80
|
+
params['userId'] = user_ids[0]
|
81
|
+
end
|
82
|
+
|
83
|
+
# setup interface and check for dry run?
|
84
|
+
@dashboard_interface.setopts(options)
|
85
|
+
if options[:dry_run]
|
86
|
+
print_dry_run @dashboard_interface.dry.recent_activity(params)
|
87
|
+
return 0, nil
|
88
|
+
end
|
89
|
+
|
90
|
+
# make the request
|
91
|
+
json_response = @dashboard_interface.recent_activity(params)
|
92
|
+
|
93
|
+
# determine exit status
|
94
|
+
exit_code, err = 0, nil
|
95
|
+
|
96
|
+
# could error if there are no results.
|
97
|
+
# if json_response['activity'].empty?
|
98
|
+
# exit_code = 3
|
99
|
+
# err = "0 results found"
|
100
|
+
# end
|
101
|
+
|
102
|
+
# render output
|
103
|
+
render_response(json_response, options, "activity") do
|
104
|
+
title = "Activity"
|
74
105
|
subtitles = []
|
75
106
|
subtitles += parse_list_subtitles(options)
|
76
107
|
if options[:start]
|
@@ -85,37 +116,28 @@ class Morpheus::Cli::RecentActivityCommand
|
|
85
116
|
if items.empty?
|
86
117
|
puts "No activity found."
|
87
118
|
print reset,"\n"
|
88
|
-
|
119
|
+
else
|
120
|
+
# JD: this api response is funky, no meta and it includes date objects
|
121
|
+
# ok then its gone, get good api response data gosh darnit!
|
122
|
+
# use /api/activity instead
|
123
|
+
items = items.select { |item| item['_id'] || item['name'] }
|
124
|
+
columns = [
|
125
|
+
# {"ID" => lambda {|item| item['id'] } },
|
126
|
+
# {"SEVERITY" => lambda {|item| format_activity_severity(item['severity']) } },
|
127
|
+
{"TYPE" => lambda {|item| item['activityType'] } },
|
128
|
+
{"AUTHOR" => lambda {|item| item['userName'] || '' } },
|
129
|
+
{"MESSAGE" => lambda {|item| item['message'] || '' } },
|
130
|
+
{"OBJECT" => lambda {|item| format_activity_display_object(item) } },
|
131
|
+
{"WHEN" => lambda {|item| format_local_dt(item['ts']) } }
|
132
|
+
]
|
133
|
+
print as_pretty_table(items, columns, options)
|
134
|
+
print reset,"\n"
|
89
135
|
end
|
90
|
-
|
91
|
-
items = items.select { |item| item['_id'] || item['name'] }
|
92
|
-
print_recent_activity_table(items, options)
|
93
|
-
print reset,"\n"
|
94
|
-
return 0
|
95
|
-
|
96
|
-
rescue RestClient::Exception => e
|
97
|
-
print_rest_exception(e, options)
|
98
|
-
return 1
|
136
|
+
return exit_code, err
|
99
137
|
end
|
100
138
|
end
|
101
139
|
|
102
|
-
|
103
|
-
columns = [
|
104
|
-
# {"ID" => lambda {|item| item['id'] } },
|
105
|
-
# {"SEVERITY" => lambda {|item| format_activity_severity(item['severity']) } },
|
106
|
-
{"TYPE" => lambda {|item| item['activityType'] } },
|
107
|
-
{"AUTHOR" => lambda {|item| item['userName'] || '' } },
|
108
|
-
{"MESSAGE" => lambda {|item| item['message'] || '' } },
|
109
|
-
# {"NAME" => lambda {|item| item['name'] } },
|
110
|
-
{"OBJECT" => lambda {|item| format_activity_display_object(item) } },
|
111
|
-
{"WHEN" => lambda {|item| format_local_dt(item['ts']) } }
|
112
|
-
# {"WHEN" => lambda {|item| "#{format_duration(item['ts'])} ago" } }
|
113
|
-
]
|
114
|
-
if opts[:include_fields]
|
115
|
-
columns = opts[:include_fields]
|
116
|
-
end
|
117
|
-
print as_pretty_table(items, columns, opts)
|
118
|
-
end
|
140
|
+
protected
|
119
141
|
|
120
142
|
def format_activity_severity(severity, return_color=cyan)
|
121
143
|
out = ""
|
data/lib/morpheus/cli/remote.rb
CHANGED
@@ -10,9 +10,16 @@ require 'morpheus/cli/cli_command'
|
|
10
10
|
|
11
11
|
class Morpheus::Cli::Remote
|
12
12
|
include Morpheus::Cli::CliCommand
|
13
|
+
include Morpheus::Cli::RemoteHelper
|
13
14
|
|
14
|
-
register_subcommands :list, :add, :get, :update, :rename, :remove, :use, :unuse, :current
|
15
|
-
|
15
|
+
register_subcommands :list, :add, :get, :update, :rename, :remove, :use, :unuse, :clone, :current, :view
|
16
|
+
# remote setup and remote check
|
17
|
+
# are now avaiable under ping and setup
|
18
|
+
# they do the same thing
|
19
|
+
register_subcommands :setup
|
20
|
+
register_subcommands :check
|
21
|
+
register_subcommands :'check-all' => :check_all
|
22
|
+
register_subcommands :version => :version
|
16
23
|
|
17
24
|
set_default_subcommand :list
|
18
25
|
|
@@ -21,8 +28,8 @@ class Morpheus::Cli::Remote
|
|
21
28
|
end
|
22
29
|
|
23
30
|
def connect(opts={})
|
24
|
-
|
25
|
-
@api_client = establish_remote_appliance_connection(
|
31
|
+
# no authorization needed, do not verify a token or prompt for login
|
32
|
+
@api_client = establish_remote_appliance_connection({:skip_verify_access_token => true, :skip_login => true}.merge(opts))
|
26
33
|
@setup_interface = @api_client.setup
|
27
34
|
end
|
28
35
|
|
@@ -34,16 +41,23 @@ class Morpheus::Cli::Remote
|
|
34
41
|
options = {}
|
35
42
|
params = {}
|
36
43
|
show_all_activity = false
|
44
|
+
current_only = false
|
45
|
+
do_check = false
|
37
46
|
optparse = Morpheus::Cli::OptionParser.new do|opts|
|
38
47
|
opts.banner = subcommand_usage()
|
39
48
|
opts.on("-a",'--all', "Show all the appliance activity details") do
|
40
49
|
show_all_activity = true
|
50
|
+
options[:wrap] = true
|
51
|
+
end
|
52
|
+
opts.on("--current", "--current", "List only the active (current) appliance.") do
|
53
|
+
current_only = true
|
54
|
+
end
|
55
|
+
opts.on("--check", "--check", "Check each appliance in the list to refresh their status, this may take a while.") do
|
56
|
+
do_check = true
|
41
57
|
end
|
42
58
|
build_common_options(opts, options, [:list, :json, :yaml, :csv, :fields])
|
43
59
|
opts.footer = <<-EOT
|
44
|
-
|
45
|
-
the current appliance. The current appliance is where morpheus will send
|
46
|
-
its commands by default. That is, in absence of the '--remote' option.
|
60
|
+
List the configured remote appliances.
|
47
61
|
EOT
|
48
62
|
end
|
49
63
|
optparse.parse!(args)
|
@@ -54,138 +68,195 @@ EOT
|
|
54
68
|
params.merge!(parse_list_options(options))
|
55
69
|
appliances = ::Morpheus::Cli::Remote.load_all_remotes(params)
|
56
70
|
# if appliances.empty?
|
57
|
-
# raise_command_error "You have no appliances configured. See the `remote add
|
71
|
+
# raise_command_error "You have no appliances configured. See the command `remote add`."
|
58
72
|
# end
|
59
|
-
|
60
|
-
|
61
|
-
if options[:json]
|
62
|
-
puts as_json(json_response, options, "appliances")
|
63
|
-
return 0
|
64
|
-
elsif options[:yaml]
|
65
|
-
puts as_yaml(json_response, options, "appliances")
|
66
|
-
return 0
|
67
|
-
elsif options[:csv]
|
68
|
-
puts records_as_csv(appliances, options)
|
69
|
-
return 0
|
73
|
+
if current_only
|
74
|
+
appliances = appliances.select {|a| a[:active] }
|
70
75
|
end
|
71
|
-
if
|
72
|
-
|
73
|
-
|
74
|
-
|
75
|
-
|
76
|
-
|
77
|
-
|
78
|
-
|
79
|
-
|
80
|
-
|
81
|
-
|
82
|
-
|
83
|
-
|
84
|
-
|
85
|
-
|
86
|
-
|
87
|
-
|
88
|
-
|
89
|
-
|
90
|
-
|
91
|
-
{:activity => {display_method: lambda {|it| show_all_activity ? get_appliance_session_blurbs(it).join("\t") : get_appliance_session_blurbs(it).first } } }
|
92
|
-
]
|
93
|
-
print as_pretty_table(appliances, columns, options)
|
94
|
-
print reset
|
95
|
-
if @appliance_name
|
96
|
-
#unless appliances.keys.size == 1
|
97
|
-
print cyan, "\n# => #{@appliance_name} is the current remote appliance\n", reset
|
98
|
-
#end
|
76
|
+
if do_check
|
77
|
+
# return here because it prints a list() too..
|
78
|
+
return _check_all_appliances(options)
|
79
|
+
end
|
80
|
+
# mock json
|
81
|
+
json_response = {"appliances" => appliances}
|
82
|
+
# render
|
83
|
+
exit_code, err = 0, nil
|
84
|
+
render_response(json_response, options, "appliances") do
|
85
|
+
|
86
|
+
if appliances.empty?
|
87
|
+
if params[:phrase]
|
88
|
+
print reset,"0 remotes matched '#{params[:phrase]}'", reset, "\n"
|
89
|
+
print reset,"Try `remote add #{params[:phrase]}`", reset, "\n"
|
90
|
+
return 0, nil # maybe exit non-zero when no records are found, could be nicer
|
91
|
+
else
|
92
|
+
warning_msg = "No remote appliances configured. See the command `remote add`."
|
93
|
+
print yellow, warning_msg, reset, "\n"
|
94
|
+
return 2, warning_msg
|
95
|
+
end
|
99
96
|
else
|
100
|
-
|
97
|
+
title = "Morpheus Appliances"
|
98
|
+
subtitles = parse_list_subtitles(options)
|
99
|
+
subtitles << "Current" if current_only
|
100
|
+
print_h1 title, subtitles, options
|
101
|
+
|
102
|
+
columns = {
|
103
|
+
"Name" => :name,
|
104
|
+
"URL" => lambda {|it| it[:url] || it[:host] },
|
105
|
+
"Status" => lambda {|it| format_appliance_status(it, cyan) },
|
106
|
+
"Version" => lambda {|it| it[:build_version] ? "#{it[:build_version]}" : '' },
|
107
|
+
"Appliance URL" => lambda {|it| it[:appliance_url] ? "#{it[:appliance_url]}" : '' },
|
108
|
+
"Secure" => lambda {|it| format_boolean(it[:insecure] != true && (it[:url] || it[:host]).to_s.include?("https")) },
|
109
|
+
"Active" => lambda {|it| it[:active] ? "Yes " + format_is_current() : "No" },
|
110
|
+
#"Authenticated" => lambda {|it| format_boolean it[:authenticated] },
|
111
|
+
"Username" => :username,
|
112
|
+
# "Activity" => lambda {|it| get_appliance_session_blurbs(it).join("\n" + (' '*15)) },
|
113
|
+
"Last Login" => lambda {|it| format_duration_ago(it[:last_login_at]) },
|
114
|
+
#"Last Logout" => lambda {|it| format_duration_ago(it[:last_logout_at]) },
|
115
|
+
"Last Success" => lambda {|it| format_duration_ago(it[:last_success_at]) },
|
116
|
+
"Last Check" => lambda {|it|
|
117
|
+
check_str = ""
|
118
|
+
if it[:last_check]
|
119
|
+
check_timestamp = it[:last_check][:timestamp]
|
120
|
+
check_status = it[:last_check][:http_status]
|
121
|
+
if check_status
|
122
|
+
if check_status == 200
|
123
|
+
# no need to show this
|
124
|
+
else
|
125
|
+
check_status = check_status
|
126
|
+
end
|
127
|
+
end
|
128
|
+
if check_timestamp
|
129
|
+
check_duration_str = format_duration_ago(check_timestamp)
|
130
|
+
# check_str = check_status ? "#{check_duration_str} (HTTP #{check_status})" : check_duration_str
|
131
|
+
check_str = check_duration_str
|
132
|
+
end
|
133
|
+
else
|
134
|
+
# check_str = "n/a"
|
135
|
+
end
|
136
|
+
check_str
|
137
|
+
},
|
138
|
+
"Response Time" => lambda {|it| format_duration_milliseconds(it[:last_check][:took]) rescue "" },
|
139
|
+
#"Response Time" => lambda {|it| format_sig_dig((it[:last_check][:took]/ 1000.to_f), 3) + "s" rescue "" },
|
140
|
+
"Error" => {display_method: lambda {|it|
|
141
|
+
error_str = it[:last_check] ? it[:last_check][:error].to_s : ""
|
142
|
+
error_str
|
143
|
+
}, max_width: 30},
|
144
|
+
}
|
145
|
+
# when an active remote is in the list, add => prefix and padding to keep things aligned.
|
146
|
+
# this is sucky, use arrays
|
147
|
+
has_active_remote = appliances.find {|appliance| appliance[:active] }
|
148
|
+
if has_active_remote
|
149
|
+
columns.delete("Name")
|
150
|
+
columns = {" Name" => lambda {|it| it[:active] ? (bold + "=> #{it[:name]}" + reset + cyan) : " #{it[:name]}" } }.merge(columns)
|
151
|
+
end
|
152
|
+
has_an_error = appliances.find {|appliance| appliance[:last_check][:error] rescue nil }
|
153
|
+
if !has_an_error
|
154
|
+
columns.delete("Error")
|
155
|
+
end
|
156
|
+
if show_all_activity != true
|
157
|
+
columns.delete("Secure")
|
158
|
+
columns.delete("Appliance URL")
|
159
|
+
columns.delete("Active")
|
160
|
+
columns.delete("Authenticated")
|
161
|
+
columns.delete("Last Login")
|
162
|
+
columns.delete("Last Logout")
|
163
|
+
columns.delete("Last Success")
|
164
|
+
#columns.delete("Error") # unless appliances.find {|appliance| appliance[:last_check][:error] rescue nil }
|
165
|
+
else
|
166
|
+
# always remove these columns because they are worthless
|
167
|
+
columns.delete("Authenticated")
|
168
|
+
columns.delete("Active")
|
169
|
+
columns.delete("Last Success")
|
170
|
+
end
|
171
|
+
# oops, table labels are upcase, but description list is not??, make them upcase here
|
172
|
+
new_columns = {}
|
173
|
+
columns.each {|k,v| new_columns[k.to_s.upcase] = v }
|
174
|
+
columns = new_columns
|
175
|
+
print as_pretty_table(appliances, columns, options)
|
176
|
+
print reset
|
177
|
+
print_results_pagination({size:appliances.size,total:appliances.size})
|
101
178
|
end
|
102
179
|
print reset, "\n"
|
103
180
|
end
|
104
|
-
return
|
181
|
+
return exit_code, err
|
105
182
|
end
|
106
183
|
|
107
184
|
def add(args)
|
108
|
-
|
109
|
-
options = {}
|
110
|
-
params = {}
|
185
|
+
options, params, payload = {}, {}, {}
|
111
186
|
new_appliance_map = {}
|
112
|
-
use_it =
|
187
|
+
use_it = nil
|
113
188
|
secure = nil
|
114
189
|
optparse = Morpheus::Cli::OptionParser.new do|opts|
|
115
|
-
banner = subcommand_usage(
|
116
|
-
|
117
|
-
|
118
|
-
[url] The url of your appliance eg. https://demo.mymorpheus.com
|
119
|
-
EOT
|
120
|
-
opts.banner = banner + "\n" + banner_args
|
121
|
-
opts.on(nil, '--use', "Make this the current appliance" ) do
|
122
|
-
use_it = true
|
123
|
-
new_appliance_map[:active] = true
|
124
|
-
end
|
125
|
-
# let's free up the -d switch for global options, maybe?
|
126
|
-
opts.on( '-d', '--default', "Does the same thing as --use" ) do
|
127
|
-
use_it = true
|
190
|
+
opts.banner = subcommand_usage('[name] [url]')
|
191
|
+
opts.on(nil, '--use [true|false]', "Start using remote right now. By default this is true if it's the first remote, otherwise false." ) do |val|
|
192
|
+
use_it = (val == 'no' || val == 'off' || val.to_s == 'false')
|
128
193
|
new_appliance_map[:active] = true
|
129
194
|
end
|
130
|
-
opts.on(nil, "--secure", "Prevent insecure HTTPS communication.
|
195
|
+
opts.on(nil, "--secure", "Prevent insecure HTTPS communication. Default is true.") do
|
131
196
|
secure = true
|
132
197
|
end
|
133
|
-
opts.on(nil, "--insecure", "Allow insecure HTTPS communication. i.e. Ignore SSL errors.") do
|
198
|
+
opts.on(nil, "--insecure", "Allow insecure HTTPS communication. i.e. Ignore SSL errors. Default is false.") do
|
134
199
|
secure = false
|
135
200
|
end
|
201
|
+
# ok, need to be able to pass every option supported by login() and setup()
|
136
202
|
build_common_options(opts, options, [:options, :quiet])
|
137
203
|
opts.footer = <<-EOT
|
138
|
-
|
139
|
-
|
140
|
-
|
141
|
-
|
142
|
-
|
204
|
+
Add a new remote to your morpheus client configuration.
|
205
|
+
[name] is required. A unique name for your appliance. eg. demo
|
206
|
+
[url] is required. The URL of your appliance eg. https://demo.morpheusdata.com
|
207
|
+
First, this inspects the remote url to check the appliance status and version.
|
208
|
+
If remote is ready, it will prompt to login, see the command `login`.
|
209
|
+
If remote is freshly installed, it will prompt to initialize the appliance, see the command `setup`.
|
210
|
+
The option --use can be included to start using the new remote right away.
|
211
|
+
The remote will be used by default if it is the first remote in the configuration.
|
212
|
+
The --quiet option can be used to to skip prompting.
|
213
|
+
|
143
214
|
EOT
|
144
215
|
end
|
145
216
|
optparse.parse!(args)
|
146
|
-
|
147
|
-
raise_command_error "wrong number of arguments, expected 0-2 and got (#{args.count}) #{args.join(' ')}\n#{optparse}"
|
148
|
-
end
|
217
|
+
verify_args!(args:args, max:2, optparse:optparse)
|
149
218
|
|
219
|
+
# payload = options[:payload] ? options[:payload] : {}
|
220
|
+
# payload.deep_merge!(parse_passed_options(options))
|
221
|
+
# # skip prompting when --payload is used
|
222
|
+
# if options[:payload].nil?
|
223
|
+
# end
|
224
|
+
|
150
225
|
# load current appliances
|
151
226
|
appliances = ::Morpheus::Cli::Remote.appliances
|
152
227
|
|
153
|
-
|
154
|
-
|
155
|
-
new_appliance_map[:active] = true
|
156
|
-
end
|
157
|
-
|
158
|
-
new_appliance_name = args[0] if args[0]
|
159
|
-
url = args[1] if args[1]
|
228
|
+
new_appliance_name = args[0] ? args[0] : nil
|
229
|
+
url = args[1] ? args[1] : nil
|
160
230
|
|
161
231
|
# Name
|
162
232
|
still_prompting = true
|
163
233
|
while still_prompting do
|
164
|
-
if
|
165
|
-
|
166
|
-
|
234
|
+
if args[0]
|
235
|
+
new_appliance_name = args[0]
|
236
|
+
still_prompting = false
|
237
|
+
else
|
238
|
+
if new_appliance_name.to_s.empty?
|
239
|
+
v_prompt = Morpheus::Cli::OptionTypes.prompt([{'fieldName' => 'name', 'fieldLabel' => 'Name', 'type' => 'text', 'required' => true, 'description' => 'A unique name for the remote Morpheus appliance. Example: local'}], options[:options])
|
240
|
+
new_appliance_name = v_prompt['name']
|
241
|
+
end
|
167
242
|
end
|
168
|
-
|
169
243
|
# for the sake of sanity
|
170
|
-
if [:current, :all].include?(new_appliance_name.to_sym)
|
171
|
-
raise_command_error "The specified appliance name '#{new_appliance_name}' is invalid."
|
244
|
+
if [:current, :all, :'remote-url'].include?(new_appliance_name.to_sym)
|
245
|
+
raise_command_error "The specified remote appliance name '#{new_appliance_name}' is invalid."
|
172
246
|
new_appliance_name = nil
|
173
247
|
end
|
174
248
|
# unique name
|
175
249
|
existing_appliance = appliances[new_appliance_name.to_sym]
|
176
250
|
if existing_appliance
|
177
|
-
print_error red,"The specified appliance name '#{new_appliance_name}' already exists
|
251
|
+
print_error red,"The specified remote appliance name '#{new_appliance_name}' already exists: #{display_appliance(existing_appliance[:name], (existing_appliance[:url]))}",reset,"\n"
|
178
252
|
new_appliance_name = nil
|
179
253
|
end
|
180
|
-
|
181
|
-
if new_appliance_name.to_s.empty?
|
182
|
-
if options[:no_prompt]
|
183
|
-
return 1
|
184
|
-
end
|
185
|
-
still_prompting = true
|
186
|
-
else
|
254
|
+
if new_appliance_name
|
187
255
|
still_prompting = false
|
188
256
|
end
|
257
|
+
if new_appliance_name.nil? && still_prompting == false
|
258
|
+
return 1
|
259
|
+
end
|
189
260
|
end
|
190
261
|
|
191
262
|
new_appliance_map[:name] = new_appliance_name.to_sym
|
@@ -193,83 +264,109 @@ EOT
|
|
193
264
|
# URL
|
194
265
|
still_prompting = true
|
195
266
|
while still_prompting do
|
196
|
-
if
|
197
|
-
|
198
|
-
|
267
|
+
if args[1]
|
268
|
+
url = args[1]
|
269
|
+
still_prompting = false
|
270
|
+
else
|
271
|
+
if !url
|
272
|
+
default_url = nil
|
273
|
+
# use Name: dev to get a happy default.
|
274
|
+
# if new_appliance_name == "dev"
|
275
|
+
if new_appliance_name == "local" || new_appliance_name == "localhost" || new_appliance_name == "dev"
|
276
|
+
default_url = "http://localhost:8080"
|
277
|
+
end
|
278
|
+
v_prompt = Morpheus::Cli::OptionTypes.prompt([{'fieldName' => 'url', 'fieldLabel' => 'URL', 'type' => 'text', 'required' => true, 'description' => 'The URL of the remote Morpheus appliance. Example: https://10.0.2.2', 'defaultValue' => default_url}], options[:options])
|
279
|
+
url = v_prompt['url']
|
280
|
+
end
|
199
281
|
end
|
200
282
|
|
201
|
-
|
202
|
-
|
203
|
-
|
283
|
+
# strip whitespace from URL
|
284
|
+
url = url.to_s.strip
|
285
|
+
|
286
|
+
if url.to_s !~ /^https?\:\/\/.+/
|
287
|
+
print_error red,"The specified remote appliance url '#{url}' is invalid.",reset,"\n"
|
288
|
+
#still_prompting = true
|
204
289
|
url = nil
|
205
290
|
else
|
206
291
|
still_prompting = false
|
207
292
|
end
|
293
|
+
if url.nil? && still_prompting == false
|
294
|
+
return 1
|
295
|
+
end
|
208
296
|
end
|
209
297
|
|
210
|
-
# let's replace :host with :url
|
211
|
-
new_appliance_map[:host] = url
|
212
298
|
new_appliance_map[:url] = url
|
213
299
|
|
214
|
-
#
|
215
|
-
|
216
|
-
|
217
|
-
|
218
|
-
|
300
|
+
# --insecure or --secure
|
301
|
+
# Secure? (Ignore SSL errors)
|
302
|
+
# secure is the default,
|
303
|
+
# try to only store insecure:false in the appliances config
|
304
|
+
if url.to_s =~ /^https\:/ && secure.nil?
|
305
|
+
if secure != nil
|
306
|
+
new_appliance_map[:insecure] = !secure
|
307
|
+
else
|
308
|
+
#v_prompt = Morpheus::Cli::OptionTypes.prompt([{'fieldName' => 'secure', 'fieldLabel' => 'Secure', 'type' => 'checkbox', 'required' => false, 'defaultValue' => true, 'description' => 'Prevent insecure HTTPS communication, respect SSL errors.'}], options[:options])
|
309
|
+
v_prompt = Morpheus::Cli::OptionTypes.prompt([{'fieldName' => 'insecure', 'fieldLabel' => 'Insecure (Ignore SSL Errors)', 'type' => 'checkbox', 'required' => false, 'defaultValue' => false, 'description' => 'Allow insecure HTTPS communication, ignore SSL errors.'}], options[:options])
|
310
|
+
if v_prompt['insecure'].to_s == 'true' || v_prompt['insecure'].to_s == 'on'
|
311
|
+
new_appliance_map[:insecure] = true
|
312
|
+
end
|
313
|
+
end
|
219
314
|
end
|
220
|
-
|
221
|
-
|
222
|
-
|
315
|
+
|
316
|
+
# --use
|
317
|
+
if use_it != nil
|
318
|
+
if use_it
|
319
|
+
new_appliance_map[:active] = true
|
320
|
+
end
|
321
|
+
else
|
322
|
+
# if ::Morpheus::Cli::OptionTypes::confirm("Would you like to switch to using this remote now?", options.merge({default: appliances.empty?}))
|
323
|
+
# new_appliance_map[:active] = true
|
324
|
+
# end
|
325
|
+
v_prompt = Morpheus::Cli::OptionTypes.prompt([{'fieldName' => 'use', 'fieldLabel' => 'Use?', 'type' => 'checkbox', 'defaultValue' => appliances.empty?, 'description' => 'Start using this remote right away'}], options[:options])
|
326
|
+
if v_prompt['use'].to_s == 'true' || v_prompt['use'].to_s == 'on'
|
327
|
+
new_appliance_map[:active] = true
|
328
|
+
end
|
223
329
|
end
|
224
330
|
|
225
331
|
# save it
|
226
332
|
appliance = ::Morpheus::Cli::Remote.save_remote(new_appliance_name.to_sym, new_appliance_map)
|
227
333
|
|
228
|
-
|
229
|
-
|
230
|
-
|
231
|
-
|
334
|
+
# refresh it (does /api/setup/check to refresh status and build
|
335
|
+
# todo: this should happen in save eh?
|
336
|
+
#Morpheus::Logging::DarkPrinter.puts "inspecting remote #{appliance[:name]} #{appliance[:url]}" if Morpheus::Logging.debug? && !options[:quiet]
|
337
|
+
appliance, json_response = ::Morpheus::Cli::Remote.refresh_remote(new_appliance_name.to_sym)
|
232
338
|
|
233
|
-
# hit check api and
|
339
|
+
# hit /setup/check api and update version and status
|
234
340
|
if !options[:quiet]
|
235
|
-
|
236
|
-
|
237
|
-
end
|
238
|
-
appliance, check_json_response = ::Morpheus::Cli::Remote.refresh_remote(new_appliance_name.to_sym)
|
239
|
-
if !options[:quiet]
|
240
|
-
print cyan
|
241
|
-
puts "Status is: #{format_appliance_status(appliance)}"
|
341
|
+
# print_green_success "Added remote #{new_appliance_name}, status is #{format_appliance_status(appliance)}"
|
342
|
+
print cyan,"Added remote #{new_appliance_name}, status is #{format_appliance_status(appliance)}",reset,"\n"
|
242
343
|
end
|
344
|
+
|
345
|
+
appliance, json_response = ::Morpheus::Cli::Remote.refresh_remote(new_appliance_name.to_sym)
|
346
|
+
# if !options[:quiet]
|
347
|
+
# print cyan
|
348
|
+
# puts "Status: #{format_appliance_status(appliance)}"
|
349
|
+
# print reset
|
350
|
+
# end
|
243
351
|
# puts "refreshed appliance #{appliance.inspect}"
|
244
352
|
# determine command exit_code and err
|
245
|
-
exit_code =
|
246
|
-
|
247
|
-
|
248
|
-
|
249
|
-
exit_code = 1
|
250
|
-
err = "Check Failed: #{appliance[:error]}"
|
251
|
-
end
|
353
|
+
exit_code, err = 0, nil
|
354
|
+
if (appliance[:status] != 'ready' && appliance[:status] != 'fresh')
|
355
|
+
exit_code = 1
|
356
|
+
err = "remote status is #{appliance[:status]}"
|
252
357
|
end
|
253
358
|
|
359
|
+
# just skip prompting no prompt -q is used.
|
254
360
|
if options[:quiet]
|
255
361
|
return exit_code, err
|
256
362
|
end
|
257
|
-
|
258
|
-
if options[:json]
|
259
|
-
puts as_json(check_json_response, options)
|
260
|
-
return exit_code, err
|
261
|
-
end
|
262
|
-
|
263
|
-
# just skip setup/login stuff is no prompt -N is used.
|
363
|
+
# just skip prompting no prompt -N is used.
|
264
364
|
if options[:no_prompt]
|
265
365
|
return exit_code, err
|
266
366
|
end
|
267
367
|
|
268
|
-
#
|
269
|
-
# check_cmd_result = check_appliance([new_appliance_name])
|
270
|
-
|
368
|
+
# setup fresh appliance?
|
271
369
|
if appliance[:status] == 'fresh' # || appliance[:setup_needed] == true
|
272
|
-
|
273
370
|
if !appliance[:active]
|
274
371
|
if ::Morpheus::Cli::OptionTypes::confirm("Would you like to switch to using this remote now?", options.merge({default: true}))
|
275
372
|
use([appliance[:name]])
|
@@ -283,21 +380,20 @@ EOT
|
|
283
380
|
# no need to login, setup() handles that
|
284
381
|
end
|
285
382
|
|
286
|
-
|
287
383
|
# only login if you are using this remote
|
288
384
|
# maybe remote use should do the login prompting eh?
|
289
385
|
# if appliance[:active] && appliance[:status] == 'ready'
|
290
386
|
if appliance[:status] == 'ready'
|
291
387
|
print reset
|
292
388
|
if ::Morpheus::Cli::OptionTypes::confirm("Would you like to login now?", options.merge({default: true}))
|
293
|
-
login_result = ::Morpheus::Cli::Login.new.handle(["
|
389
|
+
login_result = ::Morpheus::Cli::Login.new.handle(["-r", appliance[:name].to_s])
|
294
390
|
keep_trying = true
|
295
391
|
if login_result == 0
|
296
392
|
keep_trying = false
|
297
393
|
end
|
298
394
|
while keep_trying do
|
299
|
-
if ::Morpheus::Cli::OptionTypes::confirm("Login
|
300
|
-
login_result = ::Morpheus::Cli::Login.new.handle(["
|
395
|
+
if ::Morpheus::Cli::OptionTypes::confirm("Login attempt failed. Would you like to try again?", options.merge({default: true}))
|
396
|
+
login_result = ::Morpheus::Cli::Login.new.handle(["-r", appliance[:name].to_s])
|
301
397
|
if login_result == 0
|
302
398
|
keep_trying = false
|
303
399
|
end
|
@@ -308,18 +404,16 @@ EOT
|
|
308
404
|
|
309
405
|
end
|
310
406
|
|
311
|
-
if !appliance[:active]
|
312
|
-
if ::Morpheus::Cli::OptionTypes::confirm("Would you like to switch to using this remote now?", options.merge({default: true}))
|
313
|
-
use([appliance[:name]])
|
314
|
-
end
|
315
|
-
end
|
316
|
-
|
317
407
|
else
|
318
408
|
#puts "Status is #{format_appliance_status(appliance)}"
|
319
409
|
end
|
320
410
|
|
321
411
|
# print new appliance details
|
322
|
-
|
412
|
+
print_h1 "Morpheus Appliance", [], options
|
413
|
+
print cyan
|
414
|
+
print format_remote_details(appliance, options)
|
415
|
+
print reset, "\n"
|
416
|
+
#_get(appliance[:name], {})
|
323
417
|
|
324
418
|
return exit_code, err
|
325
419
|
end
|
@@ -333,14 +427,14 @@ EOT
|
|
333
427
|
checkall = false
|
334
428
|
optparse = Morpheus::Cli::OptionParser.new do|opts|
|
335
429
|
opts.banner = subcommand_usage("[name]")
|
336
|
-
build_common_options(opts, options, [:json, :yaml, :csv, :fields, :quiet
|
430
|
+
build_common_options(opts, options, [:json, :yaml, :csv, :fields, :quiet])
|
337
431
|
opts.on('-a', '--all', "Check all remotes.") do
|
338
432
|
checkall = true
|
339
433
|
end
|
340
434
|
opts.footer = <<-EOT
|
341
435
|
Check the status of a remote appliance.
|
342
436
|
[name] is optional. This is the name of a remote. Default is the current remote. Can be passed as 'all'. to perform remote check-all.
|
343
|
-
This makes a request to the
|
437
|
+
This makes a request to the remote url and updates the status and version.
|
344
438
|
EOT
|
345
439
|
end
|
346
440
|
optparse.parse!(args)
|
@@ -362,50 +456,133 @@ EOT
|
|
362
456
|
end
|
363
457
|
end
|
364
458
|
|
365
|
-
def
|
366
|
-
|
367
|
-
|
368
|
-
|
369
|
-
|
370
|
-
|
371
|
-
if !appliance
|
372
|
-
raise_command_error "No current appliance, see `remote use`."
|
373
|
-
end
|
374
|
-
appliance_name = appliance[:name]
|
375
|
-
else
|
376
|
-
appliance = ::Morpheus::Cli::Remote.load_remote(appliance_name)
|
377
|
-
if !appliance
|
378
|
-
raise_command_error "Remote not found by the name '#{appliance_name}'"
|
379
|
-
end
|
459
|
+
def version(args)
|
460
|
+
options = {}
|
461
|
+
optparse = Morpheus::Cli::OptionParser.new do|opts|
|
462
|
+
opts.banner = subcommand_usage("[remote]")
|
463
|
+
opts.on('--offline', '--offline', "Do this offline without an api request to refresh the remote appliance status.") do
|
464
|
+
options[:do_offline] = true
|
380
465
|
end
|
466
|
+
build_common_options(opts, options, [:json, :yaml, :csv, :fields, :quiet])
|
467
|
+
opts.footer = <<-EOT
|
468
|
+
Print version of remote appliance.
|
469
|
+
[name] is optional. This is the name of a remote. Default is the current remote.
|
470
|
+
This makes a request to the configured appliance url and updates the status and version.
|
471
|
+
EOT
|
472
|
+
end
|
473
|
+
optparse.parse!(args)
|
474
|
+
verify_args!(args:args, max:1, optparse:optparse)
|
475
|
+
#connect(options)
|
476
|
+
# print version, default is current remote
|
477
|
+
appliance_name = nil
|
478
|
+
if args.count == 0
|
479
|
+
appliance_name = 'current'
|
480
|
+
elsif args.count == 1
|
481
|
+
appliance_name = args[0]
|
482
|
+
else
|
483
|
+
raise_command_error "No current appliance, see the command `remote use`"
|
484
|
+
end
|
485
|
+
exit_code, err = 0, nil
|
486
|
+
|
487
|
+
appliance = load_remote_by_name(appliance_name)
|
488
|
+
appliance_name = appliance[:name]
|
489
|
+
appliance_url = appliance[:url]
|
381
490
|
|
382
|
-
|
383
|
-
|
384
|
-
|
385
|
-
|
386
|
-
|
387
|
-
|
388
|
-
|
389
|
-
|
491
|
+
# found appliance, now refresh it
|
492
|
+
# print "Checking remote url: #{appliance[:url]} ..."
|
493
|
+
json_response = nil
|
494
|
+
if options[:do_offline] == true
|
495
|
+
json_response = {'appliance' => appliance}
|
496
|
+
else
|
497
|
+
appliance, json_response = ::Morpheus::Cli::Remote.refresh_remote(appliance_name)
|
498
|
+
end
|
390
499
|
|
391
|
-
|
500
|
+
# render
|
501
|
+
render_response(json_response, options) do
|
502
|
+
end
|
503
|
+
# if options[:json] || options[:yml] || options[:csv] || options[:quiet]
|
504
|
+
render_result = render_with_format(json_response, options)
|
505
|
+
return exit_code if render_result
|
392
506
|
|
393
|
-
|
507
|
+
build_version = appliance[:build_version]
|
508
|
+
if build_version
|
509
|
+
print cyan,build_version.to_s,reset,"\n"
|
510
|
+
return 0
|
511
|
+
else
|
512
|
+
print yellow,"version unknown".to_s,reset,"\n"
|
513
|
+
return 1
|
514
|
+
end
|
515
|
+
|
516
|
+
end
|
394
517
|
|
395
|
-
|
396
|
-
|
397
|
-
|
398
|
-
|
399
|
-
|
518
|
+
def check(args)
|
519
|
+
options = {}
|
520
|
+
checkall = false
|
521
|
+
optparse = Morpheus::Cli::OptionParser.new do|opts|
|
522
|
+
opts.banner = subcommand_usage("[name]")
|
523
|
+
build_common_options(opts, options, [:json, :yaml, :csv, :fields, :quiet])
|
524
|
+
opts.on('-a', '--all', "Check all remotes.") do
|
525
|
+
checkall = true
|
526
|
+
end
|
527
|
+
opts.on('--offline', '--offline', "Do this offline without an api request to refresh the remote appliance status.") do
|
528
|
+
options[:do_offline] = true
|
400
529
|
end
|
530
|
+
opts.footer = <<-EOT
|
531
|
+
Check the status of a remote appliance.
|
532
|
+
[name] is optional. This is the name of a remote. Default is the current remote. Can be passed as 'all'. to perform remote check-all.
|
533
|
+
This makes a request to the configured appliance url and updates the status and version.
|
534
|
+
EOT
|
535
|
+
end
|
536
|
+
optparse.parse!(args)
|
537
|
+
if checkall == true
|
538
|
+
return _check_all_appliances(options)
|
539
|
+
end
|
540
|
+
if args.count == 0
|
541
|
+
id_list = ['current']
|
542
|
+
else
|
543
|
+
id_list = parse_id_list(args)
|
544
|
+
end
|
545
|
+
# trick for remote check all
|
546
|
+
if id_list.length == 1 && id_list[0].to_s.downcase == 'all'
|
547
|
+
return _check_all_appliances(options)
|
548
|
+
end
|
549
|
+
#connect(options)
|
550
|
+
return run_command_for_each_arg(id_list) do |arg|
|
551
|
+
_check_appliance(arg, options)
|
552
|
+
end
|
553
|
+
end
|
401
554
|
|
402
|
-
|
403
|
-
|
555
|
+
def _check_appliance(appliance_name, options)
|
556
|
+
exit_code, err = 0, nil
|
557
|
+
begin
|
558
|
+
appliance = load_remote_by_name(appliance_name)
|
559
|
+
appliance_name = appliance[:name]
|
560
|
+
appliance_url = appliance[:url]
|
404
561
|
|
405
|
-
|
562
|
+
# found appliance, now refresh it
|
563
|
+
|
564
|
+
if options[:do_offline]
|
565
|
+
json_response = {'appliance' => appliance} # mock payload
|
566
|
+
else
|
567
|
+
appliance, json_response = ::Morpheus::Cli::Remote.refresh_remote(appliance_name.to_sym)
|
568
|
+
json_response = {'appliance' => appliance} # mock payload
|
569
|
+
appliance, json_response = ::Morpheus::Cli::Remote.refresh_remote(appliance_name)
|
570
|
+
# json_response = {'appliance' => appliance} # mock payload
|
571
|
+
end
|
572
|
+
# appliance, json_response = ::Morpheus::Cli::Remote.refresh_remote(appliance_name)
|
406
573
|
|
407
|
-
|
574
|
+
if (appliance[:status] != 'ready' && appliance[:status] != 'fresh')
|
575
|
+
exit_code = 1
|
576
|
+
# err = appliance[:last_check] && appliance[:last_check][:error] ? appliance[:last_check][:error] : nil
|
577
|
+
end
|
408
578
|
|
579
|
+
render_response(json_response, options) do
|
580
|
+
print_h1 "Morpheus Appliance", [], options
|
581
|
+
print cyan
|
582
|
+
print format_remote_details(appliance, options)
|
583
|
+
print reset, "\n"
|
584
|
+
end
|
585
|
+
return exit_code, err
|
409
586
|
rescue RestClient::Exception => e
|
410
587
|
print_rest_exception(e, options)
|
411
588
|
exit 1
|
@@ -428,7 +605,7 @@ EOT
|
|
428
605
|
if args.count != 0
|
429
606
|
raise_command_error "wrong number of arguments, expected 0-1 and got (#{args.count}) #{args.join(' ')}\n#{optparse}"
|
430
607
|
end
|
431
|
-
connect() # needed?
|
608
|
+
connect(options) # needed?
|
432
609
|
_check_all_appliances(options)
|
433
610
|
end
|
434
611
|
|
@@ -438,16 +615,16 @@ EOT
|
|
438
615
|
id_list = ::Morpheus::Cli::Remote.appliances.keys # sort ?
|
439
616
|
if id_list.size > 1
|
440
617
|
print cyan
|
441
|
-
puts "Checking #{id_list.size}
|
618
|
+
puts "Checking #{id_list.size} remotes"
|
442
619
|
elsif id_list.size == 1
|
443
620
|
puts "Checking #{Morpheus::Cli::Remote.appliances.keys.first}"
|
444
621
|
end
|
445
622
|
id_list.each do |appliance_name|
|
446
623
|
#print "."
|
447
|
-
appliance,
|
624
|
+
appliance, json_response = ::Morpheus::Cli::Remote.refresh_remote(appliance_name)
|
448
625
|
end
|
449
626
|
took_sec = (Time.now - start_time)
|
450
|
-
print_green_success "Completed
|
627
|
+
print_green_success "Completed check of #{id_list.size} #{id_list.size == 1 ? 'remote' : 'remotes'} in #{format_duration_seconds(took_sec)}"
|
451
628
|
|
452
629
|
if options[:quiet]
|
453
630
|
return 0
|
@@ -457,8 +634,7 @@ EOT
|
|
457
634
|
end
|
458
635
|
|
459
636
|
def rename(args)
|
460
|
-
options = {}
|
461
|
-
params = {}
|
637
|
+
exit_code, err, options, params, payload = 0, nil, {}, {}, {}
|
462
638
|
use_it = false
|
463
639
|
is_insecure = nil
|
464
640
|
new_name = nil
|
@@ -466,11 +642,9 @@ EOT
|
|
466
642
|
opts.banner = subcommand_usage("[name] [new name]")
|
467
643
|
opts.on(nil, "--name NAME", "Update the name of your remote appliance") do |val|
|
468
644
|
new_name = val
|
469
|
-
end
|
470
|
-
|
645
|
+
end
|
471
646
|
# opts.on(nil, '--use', "Make this the current appliance" ) do
|
472
647
|
# use_it = true
|
473
|
-
# params[:active] = true
|
474
648
|
# end
|
475
649
|
build_common_options(opts, options, [:auto_confirm, :quiet])
|
476
650
|
opts.footer = <<-EOT
|
@@ -481,25 +655,20 @@ This changes your client configuration remote name, not the appliance itself.
|
|
481
655
|
EOT
|
482
656
|
end
|
483
657
|
optparse.parse!(args)
|
484
|
-
|
485
|
-
print_error Morpheus::Terminal.angry_prompt
|
486
|
-
puts_error "#{command_name} rename expects argument [name]."
|
487
|
-
puts_error optparse
|
488
|
-
return 1
|
489
|
-
end
|
658
|
+
verify_args!(args:args, count:2, optparse:optparse)
|
490
659
|
appliance_name = args[0].to_sym
|
491
660
|
new_appliance_name = args[1].to_sym
|
492
661
|
appliance = ::Morpheus::Cli::Remote.load_remote(appliance_name)
|
493
662
|
if !appliance
|
494
|
-
raise_command_error "Remote appliance not found by the name '#{appliance_name}'"
|
663
|
+
raise_command_error "Remote appliance not found by the name '#{appliance_name}', see the command `remote list`"
|
495
664
|
end
|
496
665
|
# don't allow overwrite yet
|
497
666
|
matching_appliance = ::Morpheus::Cli::Remote.load_remote(new_appliance_name)
|
498
667
|
if matching_appliance
|
499
|
-
raise_command_error "Remote appliance already exists with the name '#{new_appliance_name}'"
|
668
|
+
raise_command_error "Remote appliance already exists with the name '#{new_appliance_name}', see the command `, see the command `remote get #{new_appliance_name}`"
|
500
669
|
end
|
501
670
|
|
502
|
-
unless options[:yes] || ::Morpheus::Cli::OptionTypes::confirm("Are you sure you
|
671
|
+
unless options[:yes] || ::Morpheus::Cli::OptionTypes::confirm("Are you sure you want to rename remote '#{appliance_name}' to '#{new_appliance_name}'?", options)
|
503
672
|
return 9, "aborted command"
|
504
673
|
end
|
505
674
|
# this does all the work
|
@@ -508,22 +677,20 @@ EOT
|
|
508
677
|
print_green_success "Renamed remote #{appliance_name} to #{new_appliance_name}"
|
509
678
|
# todo: just go ahead and refresh it now...
|
510
679
|
# _check(appliance_name, {:quiet => true})
|
511
|
-
# appliance,
|
680
|
+
# appliance, json_response = ::Morpheus::Cli::Remote.refresh_remote(new_appliance_name)
|
512
681
|
# print new appliance details
|
513
682
|
_get(new_appliance_name, {})
|
514
683
|
return 0, nil
|
515
684
|
end
|
516
685
|
|
517
686
|
def update(args)
|
518
|
-
options = {}
|
519
|
-
params = {}
|
687
|
+
exit_code, err, options, params, payload = 0, nil, {}, {}, {}
|
520
688
|
use_it = false
|
521
689
|
is_insecure = nil
|
522
|
-
new_name = nil
|
523
690
|
optparse = Morpheus::Cli::OptionParser.new do|opts|
|
524
691
|
opts.banner = subcommand_usage("[name]")
|
525
|
-
opts.on(
|
526
|
-
|
692
|
+
opts.on("--name NAME", String, "Update the name of your remote appliance") do |val|
|
693
|
+
params[:name] = val
|
527
694
|
end
|
528
695
|
opts.on("--url URL", String, "Update the url of your remote appliance") do |val|
|
529
696
|
params[:host] = val
|
@@ -542,18 +709,12 @@ EOT
|
|
542
709
|
opts.footer = "This can be used to update remote appliance settings.\n"
|
543
710
|
end
|
544
711
|
optparse.parse!(args)
|
545
|
-
|
546
|
-
print_error Morpheus::Terminal.angry_prompt
|
547
|
-
puts_error "#{command_name} update expects argument [name]."
|
548
|
-
puts_error optparse
|
549
|
-
return 1
|
550
|
-
end
|
712
|
+
verify_args!(args:args, count:1, optparse:optparse)
|
551
713
|
|
552
714
|
appliance_name = args[0].to_sym
|
553
|
-
appliance =
|
554
|
-
|
555
|
-
|
556
|
-
end
|
715
|
+
appliance = load_remote_by_name(appliance_name)
|
716
|
+
appliance_name = appliance[:name]
|
717
|
+
appliance_url = appliance[:url]
|
557
718
|
|
558
719
|
# params[:url] = args[1] if args[1]
|
559
720
|
|
@@ -574,34 +735,117 @@ EOT
|
|
574
735
|
end
|
575
736
|
|
576
737
|
::Morpheus::Cli::Remote.save_remote(appliance_name, appliance)
|
577
|
-
|
578
|
-
|
738
|
+
# rename_remote() should be inside save_remote()
|
739
|
+
if params[:name] && params[:name].to_s != appliance_name.to_s
|
740
|
+
::Morpheus::Cli::Remote.save_remote(appliance_name, appliance)
|
741
|
+
::Morpheus::Cli::Remote.rename_remote(appliance_name, params[:name])
|
742
|
+
print_green_success "Updated remote #{appliance_name} (renamed #{params[:name]})"
|
743
|
+
appliance_name = params[:name]
|
744
|
+
else
|
745
|
+
::Morpheus::Cli::Remote.save_remote(appliance_name, appliance)
|
746
|
+
print_green_success "Updated remote #{appliance_name}"
|
747
|
+
end
|
748
|
+
|
579
749
|
# todo: just go ahead and refresh it now...
|
580
750
|
# _check(appliance_name, {:quiet => true})
|
581
|
-
appliance,
|
751
|
+
appliance, json_response = ::Morpheus::Cli::Remote.refresh_remote(appliance_name)
|
582
752
|
# print new appliance details
|
583
753
|
_get(appliance[:name], {})
|
584
|
-
return
|
754
|
+
return exit_code, err
|
755
|
+
end
|
756
|
+
|
757
|
+
def clone(args)
|
758
|
+
exit_code, err, options, params, payload = 0, nil, {}, {}, {}
|
759
|
+
use_it = false
|
760
|
+
optparse = Morpheus::Cli::OptionParser.new do|opts|
|
761
|
+
opts.banner = subcommand_usage("[remote] [name]")
|
762
|
+
# opts.on(nil, "--secure", "Prevent insecure HTTPS communication. This is enabled by default") do
|
763
|
+
# params[:secure] = true
|
764
|
+
# end
|
765
|
+
# opts.on(nil, "--insecure", "Allow insecure HTTPS communication. i.e. Ignore SSL errors.") do
|
766
|
+
# params[:insecure] = true
|
767
|
+
# end
|
768
|
+
opts.on(nil, '--use', "Make it the current appliance" ) do
|
769
|
+
use_it = true
|
770
|
+
params[:active] = true
|
771
|
+
end
|
772
|
+
build_common_options(opts, options, [:quiet])
|
773
|
+
opts.footer = <<-EOT
|
774
|
+
Clone remote appliance configuratio, including any existing credentials.
|
775
|
+
[remote] is required. This is the name of an existing remote.
|
776
|
+
[name] is optional. This is the name of the new remote that will be created.
|
777
|
+
EOT
|
778
|
+
end
|
779
|
+
optparse.parse!(args)
|
780
|
+
verify_args!(args:args, optparse:optparse, count:2)
|
781
|
+
|
782
|
+
|
783
|
+
appliance_name = args[0].to_sym
|
784
|
+
appliance = load_remote_by_name(appliance_name)
|
785
|
+
if !appliance
|
786
|
+
raise_command_error "Remote appliance not found by the name '#{appliance_name}', see the command `remote list`"
|
787
|
+
end
|
788
|
+
|
789
|
+
new_appliance_name = args[1].to_sym
|
790
|
+
matching_appliance = ::Morpheus::Cli::Remote.appliances[new_appliance_name.to_sym]
|
791
|
+
if matching_appliance
|
792
|
+
raise_command_error "Remote already exists with the name '#{matching_appliance[:name]}', see the command `remote get #{matching_appliance[:name]}`"
|
793
|
+
end
|
794
|
+
|
795
|
+
# ok clone it
|
796
|
+
original_appliance = appliance
|
797
|
+
appliance = original_appliance.clone
|
798
|
+
appliance[:name] = new_appliance_name
|
799
|
+
|
800
|
+
if params[:insecure]
|
801
|
+
appliance[:insecure] = true
|
802
|
+
elsif params[:secure]
|
803
|
+
appliance.delete(:insecure)
|
804
|
+
end
|
805
|
+
if params[:url] || params[:host]
|
806
|
+
appliance[:url] = params[:url] || params[:host]
|
807
|
+
# appliance.delete(:host)
|
808
|
+
end
|
809
|
+
if use_it
|
810
|
+
appliance[:active] = true
|
811
|
+
end
|
812
|
+
|
813
|
+
# save the new remote
|
814
|
+
::Morpheus::Cli::Remote.save_remote(appliance_name, appliance)
|
815
|
+
# refresh it now?
|
816
|
+
appliance, json_response = ::Morpheus::Cli::Remote.refresh_remote(new_appliance_name)
|
817
|
+
|
818
|
+
# render
|
819
|
+
if options[:quiet]
|
820
|
+
return exit_code, err
|
821
|
+
end
|
822
|
+
print_green_success "Cloned remote #{original_appliance[:name]} to #{appliance[:name]}"
|
823
|
+
# print new appliance details
|
824
|
+
_get(appliance[:name], {})
|
825
|
+
return exit_code, err
|
585
826
|
end
|
586
827
|
|
587
828
|
def get(args)
|
588
|
-
options = {}
|
829
|
+
exit_code, err, options, params, payload = 0, nil, {}, {}, {}
|
589
830
|
optparse = Morpheus::Cli::OptionParser.new do |opts|
|
590
831
|
opts.banner = subcommand_usage("[name]")
|
591
832
|
opts.on( '-u', '--url', "Print only the url." ) do
|
592
833
|
options[:url_only] = true
|
593
834
|
end
|
594
|
-
|
835
|
+
opts.on('--offline', '--offline', "Do this offline without an api request to refresh the remote appliance status.") do
|
836
|
+
options[:do_offline] = true
|
837
|
+
end
|
838
|
+
build_common_options(opts, options, [:json,:yaml,:csv,:fields, :quiet])
|
595
839
|
end
|
596
840
|
optparse.parse!(args)
|
597
|
-
|
598
|
-
|
599
|
-
|
600
|
-
|
601
|
-
|
841
|
+
id_list = nil
|
842
|
+
# verify_args!(args:args, min:1, optparse:optparse)
|
843
|
+
if args.count == 0
|
844
|
+
id_list = ['current']
|
845
|
+
else
|
846
|
+
id_list = parse_id_list(args)
|
602
847
|
end
|
603
848
|
#connect(options)
|
604
|
-
id_list = parse_id_list(args)
|
605
849
|
return run_command_for_each_arg(id_list) do |arg|
|
606
850
|
_get(arg, options)
|
607
851
|
end
|
@@ -609,41 +853,23 @@ EOT
|
|
609
853
|
|
610
854
|
def _get(appliance_name, options)
|
611
855
|
exit_code, err = 0, nil
|
612
|
-
|
613
|
-
|
614
|
-
|
615
|
-
|
616
|
-
if !appliance
|
617
|
-
err = "No current appliance, see `remote use`."
|
618
|
-
exit_code = 1
|
619
|
-
end
|
620
|
-
appliance_name = appliance[:name]
|
621
|
-
else
|
622
|
-
appliance = ::Morpheus::Cli::Remote.load_remote(appliance_name)
|
623
|
-
if !appliance
|
624
|
-
err = "Remote appliance not found by the name '#{appliance_name}'"
|
625
|
-
exit_code = 1
|
626
|
-
end
|
627
|
-
end
|
628
|
-
|
629
|
-
if options[:quiet]
|
630
|
-
return exit_code, err
|
631
|
-
end
|
632
|
-
|
633
|
-
if options[:json]
|
634
|
-
json_response = {'appliance' => appliance} # mock payload
|
635
|
-
puts as_json(json_response, options, "appliance")
|
636
|
-
return exit_code, err
|
637
|
-
end
|
638
|
-
|
639
|
-
if options[:yaml]
|
640
|
-
json_response = {'appliance' => appliance} # mock payload
|
641
|
-
puts as_yaml(json_response, options, "appliance")
|
642
|
-
return exit_code, err
|
643
|
-
end
|
856
|
+
|
857
|
+
appliance = load_remote_by_name(appliance_name)
|
858
|
+
appliance_name = appliance[:name]
|
859
|
+
appliance_url = appliance[:url]
|
644
860
|
|
645
|
-
|
861
|
+
# refresh remote status and version by default
|
862
|
+
# should json just be appliance instead maybe?
|
863
|
+
json_response = nil
|
864
|
+
if options[:do_offline]
|
865
|
+
json_response = {'appliance' => appliance} # mock payload
|
866
|
+
else
|
867
|
+
appliance, json_response = ::Morpheus::Cli::Remote.refresh_remote(appliance_name.to_sym)
|
868
|
+
json_response = {'appliance' => appliance} # mock payload
|
869
|
+
end
|
646
870
|
|
871
|
+
# render
|
872
|
+
render_response(json_response, options) do
|
647
873
|
if options[:url_only]
|
648
874
|
if appliance
|
649
875
|
print cyan, (appliance[:url] || appliance[:host]),"\n",reset
|
@@ -653,100 +879,113 @@ EOT
|
|
653
879
|
return exit_code, err
|
654
880
|
end
|
655
881
|
end
|
656
|
-
|
657
882
|
if exit_code != 0
|
658
883
|
print_error red, err,"\n",reset
|
659
884
|
return exit_code, err
|
660
885
|
end
|
661
886
|
|
662
|
-
|
663
|
-
# print_h1 "Current Remote Appliance: #{appliance[:name]}"
|
664
|
-
print_h1 "Morpheus Appliance", [], options
|
665
|
-
else
|
666
|
-
print_h1 "Morpheus Appliance", [], options
|
667
|
-
end
|
668
|
-
print cyan
|
669
|
-
description_cols = {
|
670
|
-
"Name" => :name,
|
671
|
-
"URL" => :host,
|
672
|
-
"Secure" => lambda {|it| format_appliance_secure(it) },
|
673
|
-
"Version" => lambda {|it| it[:build_version] ? "#{it[:build_version]}" : 'unknown' },
|
674
|
-
"Status" => lambda {|it| format_appliance_status(it, cyan) },
|
675
|
-
"Username" => :username,
|
676
|
-
# "Authenticated" => lambda {|it| format_boolean it[:authenticated] },
|
677
|
-
# todo: fix this layout, obv
|
678
|
-
"Activity" => lambda {|it| get_appliance_session_blurbs(it).join("\n" + (' '*10)) }
|
679
|
-
}
|
887
|
+
print_h1 "Morpheus Appliance", [], options
|
680
888
|
print cyan
|
681
|
-
|
682
|
-
|
683
|
-
# if appliance[:insecure]
|
684
|
-
# puts " Ignore SSL Errors: Yes"
|
685
|
-
# else
|
686
|
-
# puts " Ignore SSL Errors: No"
|
687
|
-
# end
|
688
|
-
|
689
|
-
if appliance[:active]
|
690
|
-
# print cyan
|
691
|
-
print cyan, "# => #{appliance[:name]} is the current remote appliance.", reset, "\n\n"
|
692
|
-
end
|
693
|
-
|
694
|
-
return 0
|
695
|
-
rescue RestClient::Exception => e
|
696
|
-
print_rest_exception(e, options)
|
697
|
-
exit 1
|
889
|
+
print format_remote_details(appliance, options)
|
890
|
+
print reset, "\n"
|
698
891
|
end
|
892
|
+
return exit_code, err
|
893
|
+
|
699
894
|
end
|
700
895
|
|
701
|
-
def
|
896
|
+
def view(args)
|
702
897
|
options = {}
|
898
|
+
path = "/"
|
899
|
+
no_auth = false
|
703
900
|
optparse = Morpheus::Cli::OptionParser.new do|opts|
|
704
901
|
opts.banner = subcommand_usage("[name]")
|
705
|
-
|
902
|
+
opts.on('--path PATH', String, "Specify a path to load. eg '/logs'" ) do |val|
|
903
|
+
path = val
|
904
|
+
end
|
905
|
+
opts.on('--no-auth PATH', String, "Do not attempt to login with access token." ) do |val|
|
906
|
+
no_auth = true
|
907
|
+
end
|
908
|
+
build_common_options(opts, options, [:dry_run])
|
706
909
|
opts.footer = <<-EOT
|
707
|
-
|
708
|
-
[name] is
|
910
|
+
View remote appliance in a web browser.
|
911
|
+
[name] is optional. This is the name of a remote. Default is the current remote.
|
912
|
+
This will automatically login with the current access token.
|
709
913
|
EOT
|
710
914
|
end
|
711
915
|
optparse.parse!(args)
|
916
|
+
# verify_args!(args:args, optparse:optparse)
|
712
917
|
if args.count == 0
|
713
|
-
|
714
|
-
raise_command_error "wrong number of arguments, expected 1-N and got 0\n#{optparse}"
|
918
|
+
id_list = ['current']
|
919
|
+
#raise_command_error "wrong number of arguments, expected 1-N and got 0\n#{optparse}"
|
715
920
|
else
|
716
921
|
id_list = parse_id_list(args)
|
717
922
|
end
|
718
923
|
#connect(options)
|
719
|
-
unless options[:yes] || ::Morpheus::Cli::OptionTypes::confirm("Are you sure you would like to delete #{id_list.size == 1 ? 'remote' : 'remotes'}: #{anded_list(id_list)}?", options)
|
720
|
-
return 9, "aborted command"
|
721
|
-
end
|
722
924
|
return run_command_for_each_arg(id_list) do |arg|
|
723
|
-
|
925
|
+
_view_appliance(arg, path, no_auth, options)
|
724
926
|
end
|
725
927
|
end
|
726
928
|
|
727
|
-
def
|
728
|
-
|
729
|
-
appliance_name =
|
730
|
-
|
731
|
-
if
|
732
|
-
raise_command_error "Remote appliance not
|
929
|
+
def _view_appliance(appliance_name, path, no_auth, options)
|
930
|
+
appliance = load_remote_by_name(appliance_name)
|
931
|
+
appliance_name = appliance[:name]
|
932
|
+
appliance_url = appliance[:url]
|
933
|
+
if appliance_url.to_s.empty?
|
934
|
+
raise_command_error "Remote appliance does not have a url?"
|
935
|
+
end
|
936
|
+
path = path.to_s.empty? ? "/" : path
|
937
|
+
if path[0].chr != "/"
|
938
|
+
path = "/#{path}"
|
939
|
+
end
|
940
|
+
wallet = ::Morpheus::Cli::Credentials.new(appliance_name, nil).load_saved_credentials()
|
941
|
+
# try to auto login if we have a token
|
942
|
+
link = "#{appliance_url}#{path}"
|
943
|
+
if no_auth == false
|
944
|
+
if wallet && wallet['access_token']
|
945
|
+
link = "#{appliance_url}/login/oauth-redirect?access_token=#{wallet['access_token']}\\&redirectUri=#{path}"
|
946
|
+
end
|
733
947
|
end
|
734
|
-
|
735
948
|
|
736
|
-
|
949
|
+
if options[:dry_run]
|
950
|
+
puts Morpheus::Util.open_url_command(link)
|
951
|
+
return 0
|
952
|
+
end
|
953
|
+
return Morpheus::Util.open_url(link)
|
954
|
+
end
|
737
955
|
|
738
|
-
|
739
|
-
|
740
|
-
|
741
|
-
|
742
|
-
|
743
|
-
|
956
|
+
def remove(args)
|
957
|
+
options = {}
|
958
|
+
optparse = Morpheus::Cli::OptionParser.new do|opts|
|
959
|
+
opts.banner = subcommand_usage("[name]")
|
960
|
+
build_common_options(opts, options, [:auto_confirm, :quiet])
|
961
|
+
opts.footer = <<-EOT
|
962
|
+
This will delete the specified remote appliance(s) from your local configuration.
|
963
|
+
[name] is required. This is the name of a remote. More than one can be passed.
|
964
|
+
EOT
|
965
|
+
end
|
966
|
+
optparse.parse!(args)
|
967
|
+
verify_args!(args:args, min:1, optparse:optparse)
|
968
|
+
id_list = parse_id_list(args)
|
969
|
+
#connect(options)
|
970
|
+
# verify they all exist first, this a cheap lookup and raises and error if not found
|
971
|
+
id_list.each do |remote_id|
|
972
|
+
found_remote = load_remote_by_name(remote_id)
|
973
|
+
return 1, "Remote appliance not found by the name '#{remote_id}', see the command `remote list`" if found_remote.nil?
|
974
|
+
end
|
975
|
+
unless options[:yes] || ::Morpheus::Cli::OptionTypes::confirm("Are you sure you would like to delete #{id_list.size == 1 ? 'remote' : id_list.size.to_s + ' remotes'}: #{anded_list(id_list)}?", options)
|
976
|
+
return 9, "aborted command"
|
977
|
+
end
|
978
|
+
return run_command_for_each_arg(id_list) do |arg|
|
979
|
+
_remove_appliance(arg, options)
|
744
980
|
end
|
981
|
+
end
|
745
982
|
|
983
|
+
def _remove_appliance(appliance_name, options)
|
984
|
+
if ::Morpheus::Cli::Remote.appliances[appliance_name.to_sym].nil?
|
985
|
+
raise_command_error "Remote does not exist with name '#{appliance_name.to_s}'"
|
986
|
+
end
|
746
987
|
# ok, delete it
|
747
|
-
|
748
988
|
::Morpheus::Cli::Remote.delete_remote(appliance_name)
|
749
|
-
|
750
989
|
# return result
|
751
990
|
if options[:quiet]
|
752
991
|
return 0
|
@@ -756,29 +995,94 @@ EOT
|
|
756
995
|
return 0
|
757
996
|
end
|
758
997
|
|
998
|
+
def remove_all(args)
|
999
|
+
options = {}
|
1000
|
+
checkall = false
|
1001
|
+
optparse = Morpheus::Cli::OptionParser.new do|opts|
|
1002
|
+
opts.banner = subcommand_usage()
|
1003
|
+
build_common_options(opts, options, [:auto_confirm, :quiet])
|
1004
|
+
opts.footer = <<-EOT
|
1005
|
+
Remove all remote appliances, clearing the client configuration.
|
1006
|
+
This clears all the configured remotes and credentials.
|
1007
|
+
EOT
|
1008
|
+
end
|
1009
|
+
optparse.parse!(args)
|
1010
|
+
verify_args!(args:args, count:0, optparse:optparse)
|
1011
|
+
connect(options) # needed?
|
1012
|
+
_remove_all_appliances(options)
|
1013
|
+
end
|
1014
|
+
|
1015
|
+
def _remove_all_appliances(options)
|
1016
|
+
exit_code, err = 0, nil
|
1017
|
+
all_appliance_names = ::Morpheus::Cli::Remote.appliances.keys.size
|
1018
|
+
if all_appliance_names.empty?
|
1019
|
+
if options[:quiet] != true
|
1020
|
+
print_green_success "No remotes found, nothing to remove"
|
1021
|
+
return 0, nil
|
1022
|
+
end
|
1023
|
+
end
|
1024
|
+
unless options[:yes] || ::Morpheus::Cli::OptionTypes::confirm("Are you sure you want to remove all of your remotes (#{all_appliance_names.size})?", options)
|
1025
|
+
return 9, "aborted command"
|
1026
|
+
end
|
1027
|
+
# ok, do it
|
1028
|
+
deleted_list = ::Morpheus::Cli::Remote.delete_all_remotes()
|
1029
|
+
|
1030
|
+
# render
|
1031
|
+
if options[:quiet]
|
1032
|
+
return exit_code, err
|
1033
|
+
end
|
1034
|
+
if all_appliance_names.size == 1
|
1035
|
+
print_green_success "Removed 1 remote (#{all_appliance_names.join(', ')})"
|
1036
|
+
else
|
1037
|
+
print_green_success "Removed 1 remote () "
|
1038
|
+
end
|
1039
|
+
#list([])
|
1040
|
+
return exit_code, err
|
1041
|
+
end
|
1042
|
+
|
759
1043
|
def use(args)
|
760
1044
|
options = {}
|
761
1045
|
optparse = Morpheus::Cli::OptionParser.new do|opts|
|
762
1046
|
opts.banner = subcommand_usage("[name]")
|
1047
|
+
opts.on('--offline', '--offline', "Do this offline without an api request to refresh the remote appliance status.") do
|
1048
|
+
options[:do_offline] = true
|
1049
|
+
end
|
763
1050
|
build_common_options(opts, options, [:quiet])
|
764
|
-
opts.footer =
|
765
|
-
|
766
|
-
|
1051
|
+
opts.footer = <<-EOT
|
1052
|
+
[name] is required. This is the name of a remote, see the command `remote list`.
|
1053
|
+
Start using a remote, making it the active (current) remote appliance.
|
1054
|
+
This switches the remote context of your client configuration for all subsequent commands.
|
1055
|
+
So rely on 'remote use' with caution.
|
1056
|
+
It is important to always be aware of the context your commands are running in.
|
1057
|
+
The command `remote current` will return the current remote information.
|
1058
|
+
Also, instead of using an active remote, the -r option can be specified in your commands.
|
1059
|
+
|
1060
|
+
It is recommeneded to set a custom prompt to show the remote name.
|
1061
|
+
For example, add the following to your .morpheusrc file:
|
1062
|
+
|
1063
|
+
# set your shell prompt to display the current username and remote
|
1064
|
+
set-prompt "%green%username%reset@%magenta%remote %cyanmorpheus> %reset"
|
1065
|
+
|
1066
|
+
EOT
|
767
1067
|
end
|
768
1068
|
optparse.parse!(args)
|
769
|
-
|
770
|
-
|
771
|
-
|
772
|
-
|
773
|
-
|
774
|
-
|
775
|
-
|
776
|
-
appliance_name = args[0].to_sym
|
777
|
-
appliance = ::Morpheus::Cli::Remote.load_remote(appliance_name)
|
778
|
-
if !appliance
|
779
|
-
raise_command_error "Remote appliance not found by the name '#{appliance_name}'"
|
1069
|
+
verify_args!(args:args, count:1, optparse:optparse)
|
1070
|
+
exit_code, err = 0, nil
|
1071
|
+
# connect()
|
1072
|
+
current_appliance_name, current_appliance_url = @appliance_name, @appliance_url
|
1073
|
+
current_appliance = ::Morpheus::Cli::Remote.load_active_remote()
|
1074
|
+
if current_appliance
|
1075
|
+
current_appliance_name, current_appliance_url = current_appliance[:name], current_appliance[:url]
|
780
1076
|
end
|
781
1077
|
|
1078
|
+
# current_appliance_name, current_appliance_url = @appliance_name, @appliance_url
|
1079
|
+
appliance_name = args[0].to_sym
|
1080
|
+
appliance = load_remote_by_name(appliance_name)
|
1081
|
+
# appliance = ::Morpheus::Cli::Remote.load_remote(appliance_name)
|
1082
|
+
# if !appliance
|
1083
|
+
# raise_command_error "Remote not found by the name '#{appliance_name}', see the command `remote list`"
|
1084
|
+
# end
|
1085
|
+
|
782
1086
|
# appliance = ::Morpheus::Cli::Remote.set_active_appliance(appliance_name)
|
783
1087
|
appliance[:active] = true
|
784
1088
|
appliance = ::Morpheus::Cli::Remote.save_remote(appliance_name, appliance)
|
@@ -788,15 +1092,25 @@ EOT
|
|
788
1092
|
end
|
789
1093
|
|
790
1094
|
if current_appliance_name.to_s == appliance_name.to_s
|
791
|
-
|
1095
|
+
print_green_success "Using remote #{display_appliance(appliance[:name], appliance[:url])}"
|
792
1096
|
else
|
793
|
-
|
1097
|
+
print_green_success "Using remote #{display_appliance(appliance[:name], appliance[:url])}"
|
794
1098
|
end
|
795
1099
|
|
796
1100
|
# recalculate session variables
|
797
1101
|
::Morpheus::Cli::Remote.recalculate_variable_map()
|
798
1102
|
|
799
|
-
|
1103
|
+
# could just do this
|
1104
|
+
# return _get(appliance_name, options)
|
1105
|
+
|
1106
|
+
# ok need to refresh here unless --offline
|
1107
|
+
# refresh status and version
|
1108
|
+
# maybe just make json_response = appliance here
|
1109
|
+
unless options[:do_offline]
|
1110
|
+
appliance, json_response = ::Morpheus::Cli::Remote.refresh_remote(appliance[:name])
|
1111
|
+
end
|
1112
|
+
# return list([])
|
1113
|
+
return exit_code, err
|
800
1114
|
end
|
801
1115
|
|
802
1116
|
def unuse(args)
|
@@ -804,30 +1118,31 @@ EOT
|
|
804
1118
|
optparse = Morpheus::Cli::OptionParser.new do|opts|
|
805
1119
|
opts.banner = subcommand_usage()
|
806
1120
|
opts.footer = "" +
|
807
|
-
"
|
1121
|
+
"Stop using the current remote appliance.\n"
|
808
1122
|
build_common_options(opts, options, [])
|
809
1123
|
end
|
810
1124
|
optparse.parse!(args)
|
811
|
-
|
812
|
-
raise_command_error "wrong number of arguments, expected 0-1 and got (#{args.count}) #{args.join(' ')}\n#{optparse}"
|
813
|
-
end
|
1125
|
+
verify_args!(args:args, count:0, optparse:optparse)
|
814
1126
|
#connect(options)
|
1127
|
+
exit_code, err = 0, nil
|
815
1128
|
@appliance_name, @appliance_url = Morpheus::Cli::Remote.active_appliance
|
816
1129
|
if !@appliance_name
|
817
|
-
print
|
1130
|
+
print reset,"You are not using any remote appliance",reset,"\n"
|
818
1131
|
return 0
|
819
1132
|
end
|
820
1133
|
Morpheus::Cli::Remote.clear_active_appliance()
|
821
|
-
|
1134
|
+
print_green_success "Stopped using remote #{display_appliance(@appliance_name, @appliance_url)}"
|
822
1135
|
# recalculate session variables
|
823
1136
|
::Morpheus::Cli::Remote.recalculate_variable_map()
|
824
|
-
return
|
1137
|
+
# return list([])
|
1138
|
+
return exit_code, err
|
825
1139
|
end
|
826
1140
|
|
827
1141
|
def current(args)
|
828
1142
|
options = {}
|
829
1143
|
name_only = false
|
830
1144
|
url_only = false
|
1145
|
+
version_only = false
|
831
1146
|
optparse = Morpheus::Cli::OptionParser.new do|opts|
|
832
1147
|
opts.banner = subcommand_usage()
|
833
1148
|
opts.on( '-n', '--name', "Print only the name." ) do
|
@@ -836,561 +1151,171 @@ EOT
|
|
836
1151
|
opts.on( '-u', '--url', "Print only the url." ) do
|
837
1152
|
url_only = true
|
838
1153
|
end
|
839
|
-
|
840
|
-
|
841
|
-
"The default behavior is the same as 'remote get current'."
|
842
|
-
end
|
843
|
-
optparse.parse!(args)
|
844
|
-
if args.count != 0
|
845
|
-
raise_command_error "wrong number of arguments, expected 0 and got (#{args.count}) #{args.join(' ')}\n#{optparse}"
|
846
|
-
end
|
847
|
-
connect(options)
|
848
|
-
# if !@appliance_name
|
849
|
-
# print yellow, "No current appliance, see `remote use`\n", reset
|
850
|
-
# return 1
|
851
|
-
# end
|
852
|
-
#connect(options)
|
853
|
-
if name_only
|
854
|
-
print cyan, @appliance_name,"\n",reset
|
855
|
-
return 0
|
856
|
-
elsif url_only
|
857
|
-
print cyan, @appliance_url,"\n",reset
|
858
|
-
return 0
|
859
|
-
else
|
860
|
-
return _get("current", options)
|
861
|
-
end
|
862
|
-
|
863
|
-
|
864
|
-
end
|
865
|
-
|
866
|
-
# this is a wizard that walks through the /api/setup controller
|
867
|
-
# it only needs to be used once to initialize a new appliance
|
868
|
-
def setup(args)
|
869
|
-
options = {}
|
870
|
-
optparse = Morpheus::Cli::OptionParser.new do|opts|
|
871
|
-
opts.banner = subcommand_usage()
|
872
|
-
build_common_options(opts, options, [:payload, :options, :json, :dry_run, :quiet, :remote])
|
873
|
-
opts.on('--hubmode MODE','--hubmode MODE', "Choose an option for hub registration possible values are login, register, skip.") do |val|
|
874
|
-
options[:hubmode] = val.to_s.downcase
|
1154
|
+
opts.on( '-v', '--version', "Print only the build version." ) do
|
1155
|
+
version_only = true
|
875
1156
|
end
|
876
|
-
opts.
|
877
|
-
|
878
|
-
|
879
|
-
|
880
|
-
|
1157
|
+
opts.on('--offline', '--offline', "Do this offline without an api request to refresh the remote appliance status.") do
|
1158
|
+
options[:do_offline] = true
|
1159
|
+
end
|
1160
|
+
build_common_options(opts, options, [:json,:yaml,:csv,:fields, :quiet])
|
1161
|
+
opts.footer = <<-EOT
|
1162
|
+
Print details about the current remote appliance.
|
1163
|
+
This behaves the same as `remote get current`.
|
1164
|
+
EOT
|
881
1165
|
end
|
882
1166
|
optparse.parse!(args)
|
883
|
-
|
884
|
-
# first arg as remote name otherwise the active appliance is connected to
|
885
|
-
if args.count > 1
|
886
|
-
raise_command_error "wrong number of arguments, expected 0-1 and got (#{args.count}) #{args.join(' ')}\n#{optparse}"
|
887
|
-
end
|
888
|
-
if args[0]
|
889
|
-
options[:remote] = args[0]
|
890
|
-
end
|
1167
|
+
verify_args!(args:args, count:0, optparse:optparse)
|
891
1168
|
connect(options)
|
892
1169
|
|
893
|
-
|
894
|
-
|
895
|
-
|
1170
|
+
# this does the same thing
|
1171
|
+
#return _get("current", options)
|
1172
|
+
|
1173
|
+
# appliance = load_remote_by_name("current")
|
1174
|
+
appliance = @remote_appliance
|
1175
|
+
exit_code, err = 0, nil
|
1176
|
+
if appliance.nil?
|
1177
|
+
raise_command_error "no current remote appliance, see command `remote add`."
|
896
1178
|
end
|
897
1179
|
|
898
|
-
#
|
899
|
-
|
900
|
-
|
901
|
-
|
1180
|
+
# ok need to refresh here unless do_offline
|
1181
|
+
# refresh status and version
|
1182
|
+
# maybe just make json_response = appliance here
|
1183
|
+
json_response = nil
|
1184
|
+
if options[:do_offline]
|
1185
|
+
json_response = {'appliance' => appliance} # mock payload
|
902
1186
|
else
|
903
|
-
|
904
|
-
|
905
|
-
|
906
|
-
|
907
|
-
|
908
|
-
|
909
|
-
|
910
|
-
|
911
|
-
|
912
|
-
|
913
|
-
|
914
|
-
|
915
|
-
|
916
|
-
|
917
|
-
|
918
|
-
|
919
|
-
rescue RestClient::Exception => e
|
920
|
-
print_rest_exception(e, options)
|
921
|
-
return false
|
922
|
-
end
|
923
|
-
|
924
|
-
# retrieved hub.enabled and hub.url
|
925
|
-
hub_settings = appliance_status_json['hubSettings'] || appliance_status_json['hub'] || {}
|
926
|
-
|
927
|
-
# store login/registration info in here, for prompt default values
|
928
|
-
hub_info = nil
|
929
|
-
print cyan
|
930
|
-
print_h2 "Remote Setup: #{@appliance_name} - #{@appliance_url}"
|
931
|
-
|
932
|
-
print cyan
|
933
|
-
puts "Welcome to the setup of your new Morpheus Appliance #{@appliance_name} @ #{@appliance_url}"
|
934
|
-
puts "It looks like you're the first here, so let's begin."
|
935
|
-
|
936
|
-
hubmode = nil
|
937
|
-
hub_init_payload = nil # gets included as payload for hub scoped like hub.email
|
938
|
-
if hub_settings['enabled']
|
939
|
-
|
940
|
-
# Hub Registration
|
941
|
-
hub_action_dropdown = [
|
942
|
-
{'name' => 'Login to existing hub account', 'value' => 'login', 'isDefault' => true},
|
943
|
-
{'name' => 'Register a new hub account', 'value' => 'register'},
|
944
|
-
{'name' => 'Skip this step and manually install a license later.', 'value' => 'skip'},
|
945
|
-
{'name' => 'Abort', 'value' => 'abort'}
|
946
|
-
]
|
947
|
-
|
948
|
-
|
1187
|
+
appliance, json_response = ::Morpheus::Cli::Remote.refresh_remote(appliance[:name])
|
1188
|
+
json_response = {'appliance' => appliance} # mock payload
|
1189
|
+
end
|
1190
|
+
# could set exit_code if appliance[:build_version].nil?
|
1191
|
+
render_response(json_response, options) do
|
1192
|
+
if name_only && url_only
|
1193
|
+
#print cyan, display_appliance(appliance[:name], appliance[:url]),"\n",reset
|
1194
|
+
print cyan, appliance[:name], " ", appliance[:url],"\n",reset
|
1195
|
+
elsif name_only
|
1196
|
+
print cyan, appliance[:name],"\n",reset
|
1197
|
+
elsif url_only
|
1198
|
+
print cyan, appliance[:url],"\n",reset
|
1199
|
+
elsif version_only
|
1200
|
+
print cyan, appliance[:build_version],"\n",reset
|
1201
|
+
else
|
1202
|
+
print_h1 "Morpheus Appliance", [], options
|
949
1203
|
print cyan
|
950
|
-
|
951
|
-
|
952
|
-
puts "This is done to retrieve and install the license key for your appliance."
|
953
|
-
puts "You have several options for how to proceed:"
|
954
|
-
hub_action_dropdown.each_with_index do |hub_action, idx|
|
955
|
-
puts "#{idx+1}. #{hub_action['name']} [#{hub_action['value']}]"
|
956
|
-
end
|
957
|
-
print "\n", reset
|
958
|
-
|
959
|
-
while hubmode == nil do
|
960
|
-
|
961
|
-
options[:options]['hubmode'] = options[:hubmode] if options.key?(:hubmode)
|
962
|
-
v_prompt = Morpheus::Cli::OptionTypes.prompt([{'fieldName' => 'hubmode', 'fieldLabel' => 'Choose Hub Mode', 'type' => 'select', 'selectOptions' => hub_action_dropdown, 'required' => true, 'defaultValue' => 'login'}], options[:options])
|
963
|
-
hubmode = v_prompt['hubmode']
|
964
|
-
|
965
|
-
if hubmode == 'login'
|
966
|
-
|
967
|
-
# print cyan
|
968
|
-
# puts "MORPHEUS HUB #{hub_settings['url']}"
|
969
|
-
# puts "The Command Center for DevOps"
|
970
|
-
# print reset
|
971
|
-
|
972
|
-
# Hub Login
|
973
|
-
print_h2 "Morpheus Hub Login @ #{hub_settings['url']}", options
|
974
|
-
hub_login_option_types = [
|
975
|
-
{'fieldContext' => 'hub', 'fieldName' => 'email', 'fieldLabel' => 'Email', 'type' => 'text', 'required' => true, 'description' => 'Email Address of existing Morpheus Hub user to link with.'},
|
976
|
-
{'fieldContext' => 'hub', 'fieldName' => 'password', 'fieldLabel' => 'Password', 'type' => 'password', 'required' => true, 'description' => 'Password of existing Morpheus Hub user.'},
|
977
|
-
]
|
978
|
-
v_prompt = Morpheus::Cli::OptionTypes.prompt(hub_login_option_types, options[:options])
|
979
|
-
hub_login_payload = v_prompt['hub']
|
980
|
-
hub_login_response = nil
|
981
|
-
begin
|
982
|
-
hub_login_response = @setup_interface.hub_login(hub_login_payload)
|
983
|
-
hub_init_payload = hub_login_payload
|
984
|
-
hub_info = {'email' => hub_login_payload['email'], 'password' => hub_login_payload['password'] }
|
985
|
-
hub_info.deep_merge!(hub_login_response['data']['info']) if (hub_login_response['data'] && hub_login_response['data']['info'])
|
986
|
-
hub_info.deep_merge!(hub_login_response['hub']) if hub_login_response['hub'].is_a?(Hash)
|
987
|
-
print_green_success "Logged into Morpheus Hub as #{hub_info['email']}"
|
988
|
-
rescue RestClient::Exception => e
|
989
|
-
hub_login_response = parse_rest_exception(e)
|
990
|
-
error_msg = hub_login_response["msg"] || "Hub login failed."
|
991
|
-
print_error red,error_msg,reset,"\n"
|
992
|
-
hubmode = nil
|
993
|
-
#print_rest_exception(e, options)
|
994
|
-
#exit 1
|
995
|
-
end
|
996
|
-
|
997
|
-
# DEBUG
|
998
|
-
if options[:debug] && hub_login_response
|
999
|
-
print_h2 "JSON response for hub login"
|
1000
|
-
Morpheus::Logging::DarkPrinter.puts as_json(hub_login_response)
|
1001
|
-
end
|
1002
|
-
|
1003
|
-
elsif hubmode == 'register'
|
1004
|
-
# Hub Registration
|
1005
|
-
print_h2 "Morpheus Hub Registration", options
|
1006
|
-
hub_register_option_types = [
|
1007
|
-
{'fieldContext' => 'hub', 'fieldName' => 'companyName', 'fieldLabel' => 'Company Name', 'type' => 'text', 'required' => true, 'description' => 'Company Name of new Morpheus Hub account to be created.'},
|
1008
|
-
{'fieldContext' => 'hub', 'fieldName' => 'firstName', 'fieldLabel' => 'First Name', 'type' => 'text', 'required' => true, 'description' => 'First Name of new Morpheus Hub user.'},
|
1009
|
-
{'fieldContext' => 'hub', 'fieldName' => 'lastName', 'fieldLabel' => 'Last Name', 'type' => 'text', 'required' => true, 'description' => 'Last Name of new Morpheus Hub user.'},
|
1010
|
-
{'fieldContext' => 'hub', 'fieldName' => 'email', 'fieldLabel' => 'Email', 'type' => 'text', 'required' => true, 'description' => 'Email Address of new Morpheus Hub user.'}
|
1011
|
-
]
|
1012
|
-
v_prompt = Morpheus::Cli::OptionTypes.prompt(hub_register_option_types, options[:options])
|
1013
|
-
hub_register_payload = v_prompt['hub']
|
1014
|
-
|
1015
|
-
# Password prompt with re-prompting if no match
|
1016
|
-
need_password = true
|
1017
|
-
if options[:no_prompt]
|
1018
|
-
if options[:options]['hub'] && options[:options]['hub']['password']
|
1019
|
-
options[:options]['hub']['confirmPassword'] = options[:options]['hub']['password']
|
1020
|
-
end
|
1021
|
-
end
|
1022
|
-
while need_password do
|
1023
|
-
password_option_types = [
|
1024
|
-
{'fieldContext' => 'hub', 'fieldName' => 'password', 'fieldLabel' => 'Create Password', 'type' => 'password', 'required' => true, 'description' => 'Confirm password of new Morpheus Hub user.'},
|
1025
|
-
{'fieldContext' => 'hub', 'fieldName' => 'confirmPassword', 'fieldLabel' => 'Confirm Password', 'type' => 'password', 'required' => true, 'description' => 'Confirm password of new Morpheus Hub user.'}
|
1026
|
-
]
|
1027
|
-
v_prompt = Morpheus::Cli::OptionTypes.prompt(password_option_types, options[:options])
|
1028
|
-
if v_prompt['hub']['password'] == v_prompt['hub']['confirmPassword']
|
1029
|
-
hub_register_payload.deep_merge!(v_prompt['hub'])
|
1030
|
-
need_password = false
|
1031
|
-
else
|
1032
|
-
print_error red, "Password confirmation does not match. Re-enter your new password.", reset, "\n"
|
1033
|
-
end
|
1034
|
-
end
|
1035
|
-
|
1036
|
-
begin
|
1037
|
-
hub_register_response = @setup_interface.hub_register(hub_register_payload)
|
1038
|
-
hub_init_payload = hub_register_payload
|
1039
|
-
hub_info = {'email' => hub_register_payload['email'], 'password' => hub_register_payload['password'] }
|
1040
|
-
hub_info.deep_merge!(hub_register_payload)
|
1041
|
-
hub_info.deep_merge!(hub_register_response['data']['info']) if (hub_register_response['data'] && hub_register_response['data']['info'])
|
1042
|
-
hub_info.deep_merge!(hub_register_response['hub']) if hub_register_response['hub'].is_a?(Hash)
|
1043
|
-
print_green_success "Registered with Morpheus Hub as #{hub_info['email']}"
|
1044
|
-
# uh ok so that means the init() request can use login
|
1045
|
-
# this avoid duplicate email error
|
1046
|
-
# but it can also just omit hubMode from the init() payload to achieve the same thing.
|
1047
|
-
# hubmode = nil
|
1048
|
-
rescue RestClient::Exception => e
|
1049
|
-
hub_register_response = parse_rest_exception(e)
|
1050
|
-
error_msg = hub_register_response["msg"] || "Hub Registration failed."
|
1051
|
-
print_error red,error_msg,reset,"\n"
|
1052
|
-
hubmode = nil
|
1053
|
-
#print_rest_exception(e, options)
|
1054
|
-
#exit 1
|
1055
|
-
end
|
1056
|
-
|
1057
|
-
# DEBUG
|
1058
|
-
if options[:debug] && hub_register_response
|
1059
|
-
print_h2 "JSON response for hub registration"
|
1060
|
-
Morpheus::Logging::DarkPrinter.puts as_json(hub_register_response)
|
1061
|
-
end
|
1062
|
-
|
1063
|
-
elsif hubmode == 'skip'
|
1064
|
-
print cyan,"Skipping hub registraton for now...",reset,"\n"
|
1065
|
-
# puts "You may enter a license key later."
|
1066
|
-
elsif hubmode == 'abort'
|
1067
|
-
return 9, "aborted command"
|
1068
|
-
else
|
1069
|
-
hubmode = nil
|
1070
|
-
end
|
1071
|
-
end
|
1072
|
-
end
|
1073
|
-
|
1074
|
-
# ok, we're done with the hub.
|
1075
|
-
# now build the payload for POST /api/setup/init
|
1076
|
-
|
1077
|
-
payload = {}
|
1078
|
-
payload.deep_merge!(params)
|
1079
|
-
|
1080
|
-
# print cyan
|
1081
|
-
#print_h1 "Morpheus Appliance Setup", [], options
|
1082
|
-
#print cyan
|
1083
|
-
#puts "Initializing remote appliance at URL: #{@appliance_url}"
|
1084
|
-
|
1085
|
-
# Master Account
|
1086
|
-
print_h2 "Create Master Tenant", options
|
1087
|
-
account_option_types = [
|
1088
|
-
{'fieldName' => 'accountName', 'fieldLabel' => 'Master Tenant Name', 'type' => 'text', 'required' => true, 'defaultValue' => (hub_info ? hub_info['companyName'] : nil), 'description' => 'A unique name for the Master Tenant (account).'},
|
1089
|
-
]
|
1090
|
-
v_prompt = Morpheus::Cli::OptionTypes.prompt(account_option_types, options[:options])
|
1091
|
-
payload.merge!(v_prompt)
|
1092
|
-
|
1093
|
-
# Master User
|
1094
|
-
print_h2 "Create Master User", options
|
1095
|
-
user_option_types = [
|
1096
|
-
{'fieldName' => 'firstName', 'fieldLabel' => 'First Name', 'type' => 'text', 'required' => false, 'defaultValue' => (hub_info ? hub_info['firstName'] : nil), 'description' => 'First name of the user.'},
|
1097
|
-
{'fieldName' => 'lastName', 'fieldLabel' => 'Last Name', 'type' => 'text', 'required' => false, 'defaultValue' => (hub_info ? hub_info['lastName'] : nil), 'description' => 'Last name of the user.'},
|
1098
|
-
{'fieldName' => 'email', 'fieldLabel' => 'Email', 'type' => 'text', 'required' => true, 'defaultValue' => (hub_info ? hub_info['email'] : nil), 'description' => 'A unique email address for the user.'},
|
1099
|
-
{'fieldName' => 'username', 'fieldLabel' => 'Username', 'type' => 'text', 'required' => true, 'description' => 'A unique username for the master user.'}
|
1100
|
-
]
|
1101
|
-
v_prompt = Morpheus::Cli::OptionTypes.prompt(user_option_types, options[:options])
|
1102
|
-
payload.merge!(v_prompt)
|
1103
|
-
|
1104
|
-
# Password prompt with re-prompting if no match
|
1105
|
-
need_password = true
|
1106
|
-
if options[:no_prompt]
|
1107
|
-
options[:options]['confirmPassword'] = payload['password']
|
1108
|
-
payload['confirmPassword'] = payload['password'] if payload['password']
|
1109
|
-
end
|
1110
|
-
while need_password do
|
1111
|
-
password_option_types = [
|
1112
|
-
{'fieldName' => 'password', 'fieldLabel' => 'Create Password', 'type' => 'password', 'required' => true, 'description' => 'Create a new password for the user.'},
|
1113
|
-
{'fieldName' => 'confirmPassword', 'fieldLabel' => 'Confirm Password', 'type' => 'password', 'required' => true, 'description' => 'Confirm the new password for the user.'},
|
1114
|
-
]
|
1115
|
-
password_prompt = Morpheus::Cli::OptionTypes.prompt(password_option_types, options[:options])
|
1116
|
-
if password_prompt['password'] == password_prompt['confirmPassword']
|
1117
|
-
payload['password'] = password_prompt['password']
|
1118
|
-
need_password = false
|
1119
|
-
else
|
1120
|
-
print_error red, "Password confirmation does not match. Re-enter your new password.", reset, "\n"
|
1121
|
-
end
|
1122
|
-
end
|
1123
|
-
|
1124
|
-
# Appliance Settings
|
1125
|
-
default_appliance_url = appliance_status_json['applianceUrl']
|
1126
|
-
if default_appliance_url && default_appliance_url.include?('10.0.2.2:8080') # ignore this default value.
|
1127
|
-
default_appliance_url = @appliance_url
|
1128
|
-
end
|
1129
|
-
default_appliance_name = appliance_status_json['applianceName']
|
1130
|
-
if default_appliance_name.nil?
|
1131
|
-
default_appliance_name = @appliance_name
|
1132
|
-
end
|
1133
|
-
print_h2 "Initial Setup", options
|
1134
|
-
extra_option_types = [
|
1135
|
-
{'fieldName' => 'applianceName', 'fieldLabel' => 'Appliance Name', 'type' => 'text', 'required' => true, 'defaultValue' => default_appliance_name, 'description' => 'A name for identifying your morpheus appliance.'},
|
1136
|
-
{'fieldName' => 'applianceUrl', 'fieldLabel' => 'Appliance URL', 'type' => 'text', 'required' => true, 'defaultValue' => default_appliance_url, 'description' => 'Appliance URL. Can be used for integrations and callbacks.'},
|
1137
|
-
{'fieldName' => 'backups', 'fieldLabel' => 'Enable Backups', 'type' => 'checkbox', 'required' => false, 'defaultValue' => 'off', 'description' => 'Backups. Default is off. This means backups are created automatically during provisioning.'},
|
1138
|
-
{'fieldName' => 'monitoring', 'fieldLabel' => 'Enable Monitoring', 'type' => 'checkbox', 'required' => false, 'defaultValue' => 'on', 'description' => 'Enable Monitoring. This means checks are created automatically during provisioning.'},
|
1139
|
-
{'fieldName' => 'logs', 'fieldLabel' => 'Enable Logs', 'type' => 'checkbox', 'required' => false, 'defaultValue' => 'on', 'description' => 'Enable Logs. This means container logs are collected.'}
|
1140
|
-
]
|
1141
|
-
v_prompt = Morpheus::Cli::OptionTypes.prompt(extra_option_types, options[:options])
|
1142
|
-
payload.merge!(v_prompt)
|
1143
|
-
|
1144
|
-
# include hubmode and hub params for login or registration
|
1145
|
-
# actually we remove hubMode because it has already been setup, probably just now,
|
1146
|
-
# and the init() request will just used the same creds instead of
|
1147
|
-
# reauthenticated/registering with the hub
|
1148
|
-
if hubmode
|
1149
|
-
payload['hubMode'] = hubmode
|
1150
|
-
end
|
1151
|
-
if hub_init_payload
|
1152
|
-
payload['hub'] = hub_init_payload
|
1153
|
-
end
|
1154
|
-
if hubmode == 'register' || hubmode == 'login'
|
1155
|
-
payload.delete('hubMode')
|
1156
|
-
payload.delete('hub')
|
1157
|
-
end
|
1158
|
-
|
1159
|
-
end
|
1160
|
-
|
1161
|
-
# ok, make the api request
|
1162
|
-
@setup_interface.setopts(options)
|
1163
|
-
if options[:dry_run]
|
1164
|
-
print_dry_run @setup_interface.dry.init(payload)
|
1165
|
-
return
|
1166
|
-
end
|
1167
|
-
|
1168
|
-
json_response = @setup_interface.init(payload)
|
1169
|
-
|
1170
|
-
render_result = render_with_format(json_response, options)
|
1171
|
-
return 0 if render_result
|
1172
|
-
|
1173
|
-
if options[:json]
|
1174
|
-
print JSON.pretty_generate(json_response)
|
1175
|
-
print "\n"
|
1176
|
-
return
|
1177
|
-
end
|
1178
|
-
print "\n"
|
1179
|
-
print green,"Setup complete for remote #{@appliance_name} - #{@appliance_url}",reset,"\n"
|
1180
|
-
#print cyan, "You may now login with the command `login`.\n"
|
1181
|
-
# uh, just use Credentials.login(username, password, {save: true})
|
1182
|
-
cmd_res = Morpheus::Cli::Login.new.login(['--username', payload['username'], '--password', payload['password'], '-q'] + (options[:remote] ? ["-r",options[:remote]] : []))
|
1183
|
-
# print "\n"
|
1184
|
-
print cyan, "You are now logged in as the System Admin #{payload['username']}.\n"
|
1185
|
-
print reset
|
1186
|
-
#print "\n"
|
1187
|
-
|
1188
|
-
if hubmode == 'skip'
|
1189
|
-
if ::Morpheus::Cli::OptionTypes::confirm("Would you like to apply your License Key now?", options.merge({:default => true}))
|
1190
|
-
cmd_res = Morpheus::Cli::License.new.apply([] + (options[:remote] ? ["-r",options[:remote]] : []))
|
1191
|
-
# license_is_valid = cmd_res != false
|
1204
|
+
print format_remote_details(appliance, options)
|
1205
|
+
print reset, "\n"
|
1192
1206
|
end
|
1193
1207
|
end
|
1194
|
-
|
1195
|
-
if ::Morpheus::Cli::OptionTypes::confirm("Do you want to create the first group now?", options.merge({:default => true}))
|
1196
|
-
cmd_res = Morpheus::Cli::Groups.new.add(['--use'] + (options[:remote] ? ["-r",options[:remote]] : []))
|
1197
|
-
|
1198
|
-
#print "\n"
|
1199
|
-
|
1200
|
-
# if cmd_res !=
|
1201
|
-
if ::Morpheus::Cli::OptionTypes::confirm("Do you want to create the first cloud now?", options.merge({:default => true}))
|
1202
|
-
cmd_res = Morpheus::Cli::Clouds.new.add([] + (options[:remote] ? ["-r",options[:remote]] : []))
|
1203
|
-
#print "\n"
|
1204
|
-
end
|
1205
|
-
# end
|
1206
|
-
end
|
1207
|
-
print "\n",reset
|
1208
|
-
|
1208
|
+
return exit_code, err
|
1209
1209
|
end
|
1210
1210
|
|
1211
|
-
|
1212
|
-
#
|
1213
|
-
|
1214
|
-
|
1211
|
+
|
1212
|
+
# This moved to the SetupCommand
|
1213
|
+
def setup(args)
|
1214
|
+
print_error yellow,"[DEPRECATED] The command `remote setup [name]` is deprecated. It has been replaced by `setup init`.",reset,"\n"
|
1215
1215
|
options = {}
|
1216
1216
|
optparse = Morpheus::Cli::OptionParser.new do|opts|
|
1217
1217
|
opts.banner = subcommand_usage()
|
1218
|
-
build_common_options(opts, options, [:json, :dry_run, :quiet
|
1219
|
-
opts.
|
1218
|
+
build_common_options(opts, options, [:payload, :options, :json, :dry_run, :quiet])
|
1219
|
+
opts.on('--hubmode MODE','--hubmode MODE', "Choose an option for hub registration possible values are login, register, skip.") do |val|
|
1220
|
+
options[:hubmode] = val.to_s.downcase
|
1221
|
+
end
|
1222
|
+
opts.footer = <<-EOT
|
1223
|
+
Setup a fresh remote appliance, initializing it.
|
1224
|
+
First, this checks if setup is available, and returns an error if not.
|
1225
|
+
Then it prompts to create the master tenant and admin user.
|
1226
|
+
If Morpheus Hub registration is enabled, you may login or register to retrieve a license key,
|
1227
|
+
or you can pass `--hubmode skip`.
|
1228
|
+
This is only available on a new, freshly installed remote appliance,
|
1229
|
+
and it may only be executed successfully one time.
|
1230
|
+
EOT
|
1220
1231
|
end
|
1221
1232
|
optparse.parse!(args)
|
1222
|
-
|
1223
|
-
#
|
1224
|
-
|
1225
|
-
|
1226
|
-
|
1233
|
+
verify_args!(args:args, max:1, optparse:optparse)
|
1234
|
+
# just invoke the setup command.
|
1235
|
+
# for this to work, the argument [remote] must be the first argument.
|
1236
|
+
cmd_args = []
|
1237
|
+
remote_name = nil
|
1227
1238
|
if args[0]
|
1228
|
-
|
1229
|
-
|
1230
|
-
|
1231
|
-
|
1232
|
-
if !@appliance_name
|
1233
|
-
print yellow, "No active appliance, see `remote use`\n", reset
|
1234
|
-
return false
|
1235
|
-
end
|
1236
|
-
|
1237
|
-
unless options[:quiet]
|
1238
|
-
print yellow
|
1239
|
-
print "\n"
|
1240
|
-
puts "WARNING: You are about to reset your appliance installation."
|
1241
|
-
puts "It's only possible to perform teardown when the appliance has just been installed."
|
1242
|
-
puts "This provides a way to reset your appliance and run setup again."
|
1243
|
-
print reset
|
1244
|
-
print "\n"
|
1245
|
-
end
|
1246
|
-
|
1247
|
-
unless options[:yes] || ::Morpheus::Cli::OptionTypes::confirm("Are you sure you would like teardown appliance '#{@appliance_name}'.", options)
|
1248
|
-
return 9, "aborted command" # new exit code for aborting confirmation
|
1249
|
-
end
|
1250
|
-
|
1251
|
-
#@setup_interface = @api_client.setup
|
1252
|
-
|
1253
|
-
# construct payload
|
1254
|
-
|
1255
|
-
params = {}
|
1256
|
-
params.deep_merge!(options[:options].reject {|k,v| k.is_a?(Symbol) }) if options[:options]
|
1257
|
-
|
1258
|
-
# this works without any authentication!
|
1259
|
-
# it will allow anyone to use it, if there are no users/accounts in the system.
|
1260
|
-
#@api_client = establish_remote_appliance_connection(options)
|
1261
|
-
#@setup_interface = @api_client.setup
|
1262
|
-
@setup_interface = Morpheus::SetupInterface.new({url:@appliance_url,access_token:@access_token, very_ssl:false})
|
1263
|
-
json_response = nil
|
1264
|
-
begin
|
1265
|
-
json_response = @setup_interface.teardown(params)
|
1266
|
-
if json_response['success'] != true
|
1267
|
-
print_error red, (json_response['msg'] || "Teardown failed").to_s, reset, "\n"
|
1268
|
-
return false
|
1269
|
-
end
|
1270
|
-
rescue RestClient::Exception => e
|
1271
|
-
print_rest_exception(e, options)
|
1272
|
-
return false
|
1273
|
-
end
|
1274
|
-
|
1275
|
-
|
1276
|
-
# ok, make the api request and render the response or print a message
|
1277
|
-
@setup_interface.setopts(options)
|
1278
|
-
if options[:dry_run]
|
1279
|
-
print_dry_run @setup_interface.dry.teardown(params)
|
1280
|
-
return
|
1281
|
-
end
|
1282
|
-
|
1283
|
-
json_response = @setup_interface.teardown(params)
|
1284
|
-
|
1285
|
-
render_result = render_with_format(json_response, options)
|
1286
|
-
return 0 if render_result
|
1287
|
-
if options[:quiet]
|
1288
|
-
return 0
|
1289
|
-
end
|
1290
|
-
if json_response['msg']
|
1291
|
-
print_green_success json_response['msg']
|
1292
|
-
else
|
1293
|
-
print_green_success "Teardown complete for remote #{@appliance_name} - #{@appliance_url}. Now see `remote setup`"
|
1294
|
-
end
|
1295
|
-
return 0
|
1296
|
-
|
1297
|
-
end
|
1298
|
-
|
1299
|
-
def format_appliance_status(app_map, return_color=cyan)
|
1300
|
-
return "" if !app_map
|
1301
|
-
status_str = app_map[:status] || app_map['status'] || "unknown" # get_object_value(app_map, :status)
|
1302
|
-
status_str = status_str.empty? ? "unknown" : status_str.to_s.downcase
|
1303
|
-
out = ""
|
1304
|
-
if status_str == "new"
|
1305
|
-
out << "#{cyan}#{status_str.upcase}#{return_color}"
|
1306
|
-
elsif status_str == "fresh"
|
1307
|
-
# maybe just green instead?
|
1308
|
-
out << "#{magenta}#{status_str.upcase}#{return_color}"
|
1309
|
-
elsif status_str == "ready"
|
1310
|
-
out << "#{green}#{status_str.upcase}#{return_color}"
|
1311
|
-
elsif status_str == "http-error"
|
1312
|
-
out << "#{red}HTTP ERROR#{return_color}"
|
1313
|
-
elsif ['error', 'net-error', 'ssl-error', 'http-timeout', 'unreachable', 'unrecognized'].include?(status_str)
|
1314
|
-
out << "#{red}#{status_str.gsub('-', ' ').upcase}#{return_color}"
|
1315
|
-
else
|
1316
|
-
# dunno
|
1317
|
-
out << "#{yellow}#{status_str.upcase}#{return_color}"
|
1239
|
+
remote_name = args.shift
|
1240
|
+
# cmd_args = cmd_args + ["-r",remote_name, args]
|
1241
|
+
cmd_args = args + ["-r",remote_name, args]
|
1318
1242
|
end
|
1319
|
-
|
1243
|
+
return Morpheus::Cli::Setup.new.init(cmd_args)
|
1320
1244
|
end
|
1321
1245
|
|
1322
|
-
def
|
1323
|
-
|
1324
|
-
|
1325
|
-
|
1326
|
-
|
1327
|
-
|
1328
|
-
|
1246
|
+
def load_remote_by_name(appliance_name, allow_current=true)
|
1247
|
+
appliance = nil
|
1248
|
+
if appliance_name.to_s == "current" && allow_current
|
1249
|
+
appliance = ::Morpheus::Cli::Remote.load_active_remote()
|
1250
|
+
if !appliance
|
1251
|
+
raise_command_error "No current appliance, see the command `remote use`"
|
1252
|
+
end
|
1329
1253
|
else
|
1330
|
-
|
1331
|
-
|
1332
|
-
|
1333
|
-
# should have a flag that gets set when everything actually looks good..
|
1334
|
-
out << "Yes"
|
1254
|
+
appliance = ::Morpheus::Cli::Remote.load_remote(appliance_name)
|
1255
|
+
if !appliance
|
1256
|
+
raise_command_error "Remote not found by name '#{appliance_name}', see the command `remote list`"
|
1335
1257
|
end
|
1336
1258
|
end
|
1337
|
-
|
1259
|
+
return appliance
|
1338
1260
|
end
|
1339
1261
|
|
1340
|
-
|
1341
|
-
|
1342
|
-
|
1343
|
-
|
1344
|
-
|
1345
|
-
|
1346
|
-
|
1347
|
-
|
1348
|
-
|
1349
|
-
|
1350
|
-
|
1351
|
-
|
1352
|
-
|
1353
|
-
|
1354
|
-
|
1355
|
-
|
1262
|
+
def format_remote_details(appliance, options={})
|
1263
|
+
columns = {
|
1264
|
+
"Name" => :name,
|
1265
|
+
#"Name" => lambda {|it| it[:active] ? "#{it[:name]} #{bold}(current)#{reset}#{cyan}" : it[:name] },
|
1266
|
+
"URL" => lambda {|it| it[:url] || it[:host] },
|
1267
|
+
#"Status" => lambda {|it| format_appliance_status(it, cyan) },
|
1268
|
+
"Version" => lambda {|it| it[:build_version] ? "#{it[:build_version]}" : '' },
|
1269
|
+
"Appliance URL" => lambda {|it| it[:appliance_url] ? "#{it[:appliance_url]}" : '' },
|
1270
|
+
"Secure" => lambda {|it| format_appliance_secure(it) },
|
1271
|
+
"Active" => lambda {|it| it[:active] ? "Yes " + format_is_current() : "No" },
|
1272
|
+
# "Active" => lambda {|it| format_boolean(it[:active]) },
|
1273
|
+
#"Authenticated" => lambda {|it| format_boolean it[:authenticated] },
|
1274
|
+
"Username" => :username,
|
1275
|
+
# "Activity" => lambda {|it| get_appliance_session_blurbs(it).join("\n" + (' '*15)) },
|
1276
|
+
"Last Login" => lambda {|it| format_duration_ago(it[:last_login_at]) },
|
1277
|
+
#"Last Logout" => lambda {|it| format_duration_ago(it[:last_logout_at]) },
|
1278
|
+
"Last Success" => lambda {|it| format_duration_ago(it[:last_success_at]) },
|
1279
|
+
"Last Check" => lambda {|it|
|
1280
|
+
check_timestamp = nil
|
1281
|
+
if it[:last_check] && it[:last_check][:timestamp]
|
1282
|
+
check_timestamp = it[:last_check][:timestamp]
|
1356
1283
|
end
|
1357
|
-
|
1358
|
-
if
|
1359
|
-
|
1360
|
-
else
|
1361
|
-
blurbs << "Logged out."
|
1284
|
+
check_status = nil
|
1285
|
+
if it[:last_check] && it[:last_check][:http_status]
|
1286
|
+
check_status = it[:last_check][:http_status]
|
1362
1287
|
end
|
1363
|
-
if
|
1364
|
-
|
1288
|
+
if check_timestamp
|
1289
|
+
format_duration_ago(check_timestamp) # + (check_status ? " (HTTP #{check_status})" : "")
|
1290
|
+
else
|
1291
|
+
""
|
1365
1292
|
end
|
1366
|
-
|
1367
|
-
|
1368
|
-
|
1369
|
-
|
1370
|
-
|
1371
|
-
|
1293
|
+
},
|
1294
|
+
"Response Time" => lambda {|it| format_duration_milliseconds(it[:last_check][:took]) rescue "" },
|
1295
|
+
#"Response Time" => lambda {|it| format_sig_dig((it[:last_check][:took]/ 1000.to_f), 3) + "s" rescue "" },
|
1296
|
+
"Status" => lambda {|it| format_appliance_status(it, cyan) },
|
1297
|
+
"Error" => lambda {|it|
|
1298
|
+
error_str = it[:last_check] ? it[:last_check][:error] : ""
|
1299
|
+
# meh no need to show http status, :error explains it well enough
|
1300
|
+
# check_status = it[:last_check] ? it[:last_check][:http_status] : nil
|
1301
|
+
# if check_status && check_status != 200
|
1302
|
+
# #"(HTTP #{check_status}) #{error_str}"
|
1303
|
+
# else
|
1304
|
+
# error_str
|
1305
|
+
# end
|
1306
|
+
error_str
|
1307
|
+
},
|
1308
|
+
|
1309
|
+
}
|
1310
|
+
if appliance[:last_success_at].nil?
|
1311
|
+
columns.delete("Last Success")
|
1372
1312
|
else
|
1373
|
-
|
1374
|
-
if app_map[:last_check]
|
1375
|
-
if app_map[:last_check][:timestamp]
|
1376
|
-
blurbs << "Last checked #{format_duration(app_map[:last_check][:timestamp])} ago."
|
1377
|
-
end
|
1378
|
-
if app_map[:last_check][:error]
|
1379
|
-
last_error_msg = truncate_string(app_map[:last_check][:error], 250)
|
1380
|
-
blurbs << "Error: #{last_error_msg}"
|
1381
|
-
end
|
1382
|
-
if app_map[:last_check][:http_status]
|
1383
|
-
blurbs << "HTTP #{app_map[:last_check][:http_status]}"
|
1384
|
-
end
|
1385
|
-
end
|
1386
|
-
|
1387
|
-
if app_map[:last_success_at]
|
1388
|
-
blurbs << "Last Success: #{format_local_dt(app_map[:last_success_at])}"
|
1389
|
-
end
|
1390
|
-
|
1313
|
+
columns.delete("Last Success")
|
1391
1314
|
end
|
1392
|
-
|
1393
|
-
|
1315
|
+
if appliance[:last_check].nil? || appliance[:last_check][:error].nil?
|
1316
|
+
columns.delete("Error")
|
1317
|
+
end
|
1318
|
+
return as_description_list(appliance, columns, options)
|
1394
1319
|
end
|
1395
1320
|
|
1396
1321
|
class << self
|
@@ -1406,7 +1331,18 @@ EOT
|
|
1406
1331
|
end
|
1407
1332
|
|
1408
1333
|
def appliance_config
|
1409
|
-
@@appliance_config
|
1334
|
+
if @@appliance_config.nil?
|
1335
|
+
@@appliance_config
|
1336
|
+
@@appliance_config = load_appliance_file
|
1337
|
+
# fix things right away, replace deprecated :host with :url
|
1338
|
+
@@appliance_config.each do |app_name, appliance|
|
1339
|
+
host = appliance.delete(:host)
|
1340
|
+
if host && appliance[:url].to_s.empty?
|
1341
|
+
appliance[:url] = host
|
1342
|
+
end
|
1343
|
+
end
|
1344
|
+
end
|
1345
|
+
return @@appliance_config
|
1410
1346
|
end
|
1411
1347
|
|
1412
1348
|
# Returns two things, the remote appliance name and url
|
@@ -1472,10 +1408,14 @@ EOT
|
|
1472
1408
|
end
|
1473
1409
|
# apply sort
|
1474
1410
|
sort_key = params[:sort] ? params[:sort].to_sym : :name
|
1411
|
+
# :url used to be stored as :host
|
1412
|
+
if sort_key == :url || sort_key == :host
|
1413
|
+
all_appliances = all_appliances.sort {|a,b| (a[:url] || a[:host]).to_s <=> (b[:url] || b[:host]).to_s }
|
1414
|
+
elsif sort_key
|
1415
|
+
all_appliances = all_appliances.sort {|a,b| a[sort_key].to_s <=> b[sort_key].to_s }
|
1416
|
+
end
|
1475
1417
|
if params['direction'] == 'desc'
|
1476
|
-
all_appliances
|
1477
|
-
else
|
1478
|
-
all_appliances = all_appliances.sort {|a,b| a[sort_key] <=> b[sort_key] }
|
1418
|
+
all_appliances.reverse!
|
1479
1419
|
end
|
1480
1420
|
# limit
|
1481
1421
|
if params[:max]
|
@@ -1577,12 +1517,26 @@ EOT
|
|
1577
1517
|
# @param app_map [Hash] appliance configuration data :url, :insecure, :active, :etc
|
1578
1518
|
# @return [Hash] updated appliance config data
|
1579
1519
|
def save_remote(app_name, app_map)
|
1520
|
+
# need an app_name to save it
|
1521
|
+
if app_name.to_s.empty?
|
1522
|
+
puts "skipped save of remote with a blank name"
|
1523
|
+
return nil
|
1524
|
+
end
|
1525
|
+
# in case a temporary config gets passed in here, do not save it.. this should be avoided though
|
1526
|
+
if app_map[:temporary]
|
1527
|
+
puts "skipped save of temporary remote '#{app_name}'"
|
1528
|
+
return nil
|
1529
|
+
end
|
1580
1530
|
app_name = app_name.to_sym
|
1581
1531
|
# it's probably better to use load_appliance_file() here instead
|
1582
1532
|
cur_appliances = self.appliances #.clone
|
1583
1533
|
cur_appliances[app_name] = app_map
|
1584
|
-
cur_appliances[app_name] ||= {:status => "unknown", :error => "Bad configuration. Missing url. See 'remote update --url'" }
|
1585
|
-
|
1534
|
+
#cur_appliances[app_name] ||= {:status => "unknown", :error => "Bad configuration. Missing url. See 'remote update --url'" }
|
1535
|
+
cur_appliances[app_name] ||= {:status => "unknown"}
|
1536
|
+
# :host is gone, use :url please
|
1537
|
+
if cur_appliances[app_name][:host]
|
1538
|
+
cur_appliances[app_name][:url] = cur_appliances[app_name].delete(:host)
|
1539
|
+
end
|
1586
1540
|
# this is the new set_active_appliance(), instead just pass :active => true
|
1587
1541
|
# remove active flag from others
|
1588
1542
|
if app_map[:active]
|
@@ -1619,12 +1573,12 @@ EOT
|
|
1619
1573
|
cur_appliances = self.appliances #.clone
|
1620
1574
|
app_map = cur_appliances[app_name]
|
1621
1575
|
if app_map.nil?
|
1622
|
-
print_red_alert "
|
1576
|
+
print_red_alert "Remote not found by the name '#{app_name}', see the command `remote list`"
|
1623
1577
|
#print "Did you mean one of these commands: #{suggestions.join(', ')?", reset, "\n"
|
1624
1578
|
return nil
|
1625
1579
|
end
|
1626
1580
|
if cur_appliances[new_app_name]
|
1627
|
-
print_red_alert "A remote already exists with name '#{new_app_name}'
|
1581
|
+
print_red_alert "A remote already exists with name '#{new_app_name}', see the command `remote get #{new_app_name}`"
|
1628
1582
|
puts "First, you must rename or remove the existing remote."
|
1629
1583
|
return nil
|
1630
1584
|
end
|
@@ -1695,109 +1649,146 @@ EOT
|
|
1695
1649
|
return app_map
|
1696
1650
|
end
|
1697
1651
|
|
1652
|
+
def delete_all_remotes()
|
1653
|
+
deleted_list = []
|
1654
|
+
self.appliances.each do |app_name, appliance|
|
1655
|
+
deleted_list << delete_remote(app_name)
|
1656
|
+
end
|
1657
|
+
# self.appliances = {}
|
1658
|
+
# Morpheus::Cli::Remote.save_appliances({})
|
1659
|
+
# recalculate_variable_map()
|
1660
|
+
# return deleted_list
|
1661
|
+
return self.appliances
|
1662
|
+
end
|
1663
|
+
|
1698
1664
|
# refresh_remote makes an api request to the configured appliance url
|
1699
1665
|
# and updates the appliance's build version, status and last_check attributes
|
1700
|
-
def refresh_remote(app_name)
|
1701
|
-
# this might be better off staying in the CliCommands themselves
|
1702
|
-
# todo: public api /api/setup/check should move to /api/version or /api/server-info
|
1666
|
+
def refresh_remote(app_name, params={}, timeout=5)
|
1703
1667
|
app_name = app_name.to_sym
|
1704
1668
|
cur_appliances = self.appliances
|
1705
|
-
|
1706
|
-
|
1707
|
-
|
1708
|
-
if !app_url
|
1669
|
+
appliance = cur_appliances[app_name] || {}
|
1670
|
+
appliance_url = (appliance[:url] || appliance[:host]).to_s
|
1671
|
+
if !appliance_url
|
1709
1672
|
raise "appliance config is missing url!" # should not need this
|
1710
1673
|
end
|
1711
|
-
|
1712
1674
|
# todo: this insecure flag needs to applied everywhere now tho..
|
1713
|
-
if
|
1675
|
+
if appliance[:insecure]
|
1714
1676
|
Morpheus::RestClient.enable_ssl_verification = false
|
1677
|
+
# Morpheus::RestClient.enable_http = true
|
1678
|
+
end
|
1679
|
+
err = nil
|
1680
|
+
json_response = nil
|
1681
|
+
# make request to /api/setup/check
|
1682
|
+
# and update appliance :status, :build_version, :last_check{}
|
1683
|
+
if appliance_url.to_s.empty?
|
1684
|
+
err = "no url specified"
|
1685
|
+
# wtf, no url...
|
1686
|
+
return appliance, json_response
|
1687
|
+
else
|
1688
|
+
setup_interface = Morpheus::SetupInterface.new({url:appliance_url, verify_ssl: (appliance[:insecure] != true), timeout: timeout})
|
1689
|
+
start_time = Time.now
|
1690
|
+
begin
|
1691
|
+
json_response = setup_interface.check(params)
|
1692
|
+
rescue => ex
|
1693
|
+
err = ex
|
1694
|
+
ensure
|
1695
|
+
took_sec = Time.now - start_time
|
1696
|
+
end
|
1697
|
+
|
1698
|
+
# save and update appliance info
|
1699
|
+
return save_remote_last_check(appliance, json_response, err, took_sec)
|
1700
|
+
end
|
1701
|
+
end
|
1702
|
+
|
1703
|
+
# save the app status and last request information
|
1704
|
+
# looks for json_response like /setup/check and /ping
|
1705
|
+
def save_remote_last_check(appliance, json_response, err=nil, took_sec=nil)
|
1706
|
+
#puts "save_remote_last_check: #{appliance}, #{json_response}"
|
1707
|
+
app_name = appliance[:name] ? appliance[:name].to_sym : nil
|
1708
|
+
cur_appliances = self.appliances
|
1709
|
+
app_map = appliance
|
1710
|
+
app_url = (app_map[:url] || app_map[:host]).to_s
|
1711
|
+
if !app_url
|
1712
|
+
raise "appliance config is missing url!"
|
1715
1713
|
end
|
1716
|
-
|
1717
|
-
|
1718
|
-
|
1719
|
-
|
1720
|
-
|
1721
|
-
|
1722
|
-
|
1723
|
-
|
1724
|
-
#
|
1725
|
-
|
1726
|
-
|
1727
|
-
|
1728
|
-
|
1729
|
-
|
1730
|
-
|
1731
|
-
if
|
1732
|
-
|
1733
|
-
|
1714
|
+
|
1715
|
+
# only change stuff that was contained in the response
|
1716
|
+
# this stores things under the context last_check
|
1717
|
+
appliance[:last_check] = {}
|
1718
|
+
appliance[:last_check][:success] = json_response.nil?
|
1719
|
+
appliance[:last_check][:timestamp] = Time.now.to_i
|
1720
|
+
appliance[:last_check][:http_status] = json_response ? 200 : nil
|
1721
|
+
if took_sec
|
1722
|
+
# store in ms
|
1723
|
+
appliance[:last_check][:took] = (took_sec.to_f*1000).round
|
1724
|
+
end
|
1725
|
+
if json_response
|
1726
|
+
if json_response.key?('applianceUrl')
|
1727
|
+
appliance[:appliance_url] = json_response['applianceUrl']
|
1728
|
+
end
|
1729
|
+
if json_response.key?('buildVersion')
|
1730
|
+
appliance[:build_version] = json_response['buildVersion']
|
1731
|
+
appliance[:status] = 'ready'
|
1732
|
+
appliance[:last_check][:success] = true
|
1734
1733
|
# consider bumping this after every successful api command
|
1735
|
-
|
1736
|
-
|
1734
|
+
appliance[:last_success_at] = Time.now.to_i
|
1735
|
+
appliance.delete(:error)
|
1737
1736
|
end
|
1738
|
-
if
|
1739
|
-
|
1740
|
-
|
1741
|
-
|
1742
|
-
|
1737
|
+
if json_response.key?('setupNeeded')
|
1738
|
+
if json_response['setupNeeded'] == true
|
1739
|
+
appliance[:setup_needed] = true
|
1740
|
+
appliance[:status] = 'fresh'
|
1741
|
+
else
|
1742
|
+
appliance.delete(:setup_needed)
|
1743
|
+
end
|
1743
1744
|
end
|
1744
|
-
|
1745
|
-
|
1746
|
-
|
1747
|
-
|
1748
|
-
|
1749
|
-
|
1750
|
-
|
1751
|
-
|
1752
|
-
|
1753
|
-
|
1754
|
-
|
1755
|
-
|
1756
|
-
|
1757
|
-
|
1758
|
-
|
1759
|
-
|
1760
|
-
|
1761
|
-
|
1762
|
-
|
1763
|
-
|
1764
|
-
|
1765
|
-
|
1766
|
-
|
1767
|
-
|
1768
|
-
|
1769
|
-
|
1770
|
-
|
1771
|
-
|
1772
|
-
|
1773
|
-
|
1774
|
-
|
1775
|
-
|
1776
|
-
|
1777
|
-
#
|
1778
|
-
|
1779
|
-
|
1780
|
-
|
1781
|
-
|
1745
|
+
else
|
1746
|
+
# no response body eh?
|
1747
|
+
appliance[:last_check][:success] = false
|
1748
|
+
appliance[:last_check][:error] = "Invalid api response"
|
1749
|
+
appliance[:status] = 'error'
|
1750
|
+
end
|
1751
|
+
# handle error
|
1752
|
+
if err
|
1753
|
+
case(err)
|
1754
|
+
when SocketError
|
1755
|
+
appliance[:status] = 'unreachable'
|
1756
|
+
appliance[:last_check][:http_status] = nil
|
1757
|
+
appliance[:last_check][:error] = err.message
|
1758
|
+
when RestClient::Exceptions::Timeout
|
1759
|
+
# print_rest_exception(e, options)
|
1760
|
+
# exit 1
|
1761
|
+
appliance[:status] = 'http-timeout'
|
1762
|
+
appliance[:last_check][:http_status] = nil
|
1763
|
+
when Errno::ECONNREFUSED
|
1764
|
+
appliance[:status] = 'net-error'
|
1765
|
+
appliance[:last_check][:error] = err.message
|
1766
|
+
when OpenSSL::SSL::SSLError
|
1767
|
+
appliance[:status] = 'ssl-error'
|
1768
|
+
appliance[:last_check][:error] = err.message
|
1769
|
+
when JSON::ParserError
|
1770
|
+
appliance[:status] = 'unrecognized'
|
1771
|
+
appliance[:last_check][:error] = err.message
|
1772
|
+
when RestClient::Exception
|
1773
|
+
appliance[:status] = 'http-error'
|
1774
|
+
# appliance[:http_status] = err.response ? err.response.code : nil
|
1775
|
+
appliance[:last_check][:http_status] = err.response ? err.response.code : nil
|
1776
|
+
appliance[:last_check][:error] = err.message
|
1777
|
+
# if err.response.code == 404
|
1778
|
+
# appliance[:status] = 'ready' # 'ok'
|
1779
|
+
# Morpheus::Logging::DarkPrinter.puts "ping failed but it is ready" if Morpheus::Logging.debug?
|
1780
|
+
# end
|
1781
|
+
else
|
1782
|
+
appliance[:status] = 'error' # err.class.to_s.dasherize
|
1783
|
+
appliance[:last_check][:error] = err.message
|
1782
1784
|
end
|
1783
|
-
rescue => err
|
1784
|
-
# should save before raising atleast..sheesh
|
1785
|
-
raise err
|
1786
|
-
app_map[:status] = 'error'
|
1787
|
-
app_map[:last_check][:error] = err.message
|
1788
1785
|
end
|
1789
1786
|
|
1790
|
-
#
|
1791
|
-
|
1792
|
-
|
1793
|
-
|
1794
|
-
|
1795
|
-
# ... class variable returned by Remote.appliances is updated in there too...
|
1796
|
-
save_remote(app_name, app_map)
|
1797
|
-
|
1798
|
-
# return the updated data
|
1799
|
-
return app_map, check_json_response
|
1800
|
-
|
1787
|
+
# save to disk
|
1788
|
+
save_remote(app_name, appliance)
|
1789
|
+
|
1790
|
+
# return map and response
|
1791
|
+
return appliance, json_response
|
1801
1792
|
end
|
1802
1793
|
|
1803
1794
|
def recalculate_variable_map()
|