morpheus-cli 2.10.3 → 2.11.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/bin/morpheus +5 -96
- data/lib/morpheus/api/api_client.rb +23 -1
- data/lib/morpheus/api/checks_interface.rb +106 -0
- data/lib/morpheus/api/incidents_interface.rb +102 -0
- data/lib/morpheus/api/monitoring_apps_interface.rb +47 -0
- data/lib/morpheus/api/monitoring_contacts_interface.rb +47 -0
- data/lib/morpheus/api/monitoring_groups_interface.rb +47 -0
- data/lib/morpheus/api/monitoring_interface.rb +36 -0
- data/lib/morpheus/api/option_type_lists_interface.rb +47 -0
- data/lib/morpheus/api/option_types_interface.rb +47 -0
- data/lib/morpheus/api/roles_interface.rb +0 -1
- data/lib/morpheus/api/setup_interface.rb +19 -9
- data/lib/morpheus/cli.rb +20 -1
- data/lib/morpheus/cli/accounts.rb +8 -3
- data/lib/morpheus/cli/app_templates.rb +19 -11
- data/lib/morpheus/cli/apps.rb +52 -37
- data/lib/morpheus/cli/cli_command.rb +229 -53
- data/lib/morpheus/cli/cli_registry.rb +48 -40
- data/lib/morpheus/cli/clouds.rb +55 -26
- data/lib/morpheus/cli/command_error.rb +12 -0
- data/lib/morpheus/cli/credentials.rb +68 -26
- data/lib/morpheus/cli/curl_command.rb +98 -0
- data/lib/morpheus/cli/dashboard_command.rb +2 -7
- data/lib/morpheus/cli/deployments.rb +4 -4
- data/lib/morpheus/cli/deploys.rb +1 -2
- data/lib/morpheus/cli/dot_file.rb +5 -8
- data/lib/morpheus/cli/error_handler.rb +179 -15
- data/lib/morpheus/cli/groups.rb +21 -13
- data/lib/morpheus/cli/hosts.rb +220 -110
- data/lib/morpheus/cli/instance_types.rb +2 -2
- data/lib/morpheus/cli/instances.rb +257 -167
- data/lib/morpheus/cli/key_pairs.rb +15 -9
- data/lib/morpheus/cli/library.rb +673 -27
- data/lib/morpheus/cli/license.rb +2 -2
- data/lib/morpheus/cli/load_balancers.rb +4 -4
- data/lib/morpheus/cli/log_level_command.rb +6 -4
- data/lib/morpheus/cli/login.rb +17 -3
- data/lib/morpheus/cli/logout.rb +25 -11
- data/lib/morpheus/cli/man_command.rb +388 -0
- data/lib/morpheus/cli/mixins/accounts_helper.rb +1 -1
- data/lib/morpheus/cli/mixins/monitoring_helper.rb +434 -0
- data/lib/morpheus/cli/mixins/print_helper.rb +620 -112
- data/lib/morpheus/cli/mixins/provisioning_helper.rb +1 -1
- data/lib/morpheus/cli/monitoring_apps_command.rb +29 -0
- data/lib/morpheus/cli/monitoring_checks_command.rb +427 -0
- data/lib/morpheus/cli/monitoring_contacts_command.rb +373 -0
- data/lib/morpheus/cli/monitoring_groups_command.rb +29 -0
- data/lib/morpheus/cli/monitoring_incidents_command.rb +711 -0
- data/lib/morpheus/cli/option_types.rb +10 -1
- data/lib/morpheus/cli/recent_activity_command.rb +2 -5
- data/lib/morpheus/cli/remote.rb +874 -134
- data/lib/morpheus/cli/roles.rb +54 -27
- data/lib/morpheus/cli/security_group_rules.rb +2 -2
- data/lib/morpheus/cli/security_groups.rb +23 -19
- data/lib/morpheus/cli/set_prompt_command.rb +50 -0
- data/lib/morpheus/cli/shell.rb +222 -157
- data/lib/morpheus/cli/tasks.rb +19 -15
- data/lib/morpheus/cli/users.rb +27 -17
- data/lib/morpheus/cli/version.rb +1 -1
- data/lib/morpheus/cli/virtual_images.rb +28 -13
- data/lib/morpheus/cli/whoami.rb +131 -52
- data/lib/morpheus/cli/workflows.rb +24 -9
- data/lib/morpheus/formatters.rb +195 -3
- data/lib/morpheus/logging.rb +86 -0
- data/lib/morpheus/terminal.rb +371 -0
- data/scripts/generate_morpheus_commands_help.morpheus +60 -0
- metadata +21 -2
@@ -32,6 +32,10 @@ module Morpheus
|
|
32
32
|
end
|
33
33
|
end
|
34
34
|
|
35
|
+
def self.no_prompt(option_types, options={}, api_client=nil,api_params={})
|
36
|
+
prompt(option_types, options, api_client, api_params, true)
|
37
|
+
end
|
38
|
+
|
35
39
|
def self.prompt(option_types, options={}, api_client=nil,api_params={}, no_prompt=false)
|
36
40
|
results = {}
|
37
41
|
options = options || {}
|
@@ -210,7 +214,12 @@ module Morpheus
|
|
210
214
|
select_options = option_type['selectOptions']
|
211
215
|
# remote optionSource aka /api/options/$optionSource?
|
212
216
|
elsif option_type['optionSource']
|
213
|
-
|
217
|
+
# /api/options/list is a special action for custom OptionTypeLists, just need to pass the optionTypeId parameter
|
218
|
+
if option_type['optionSource'] == 'list'
|
219
|
+
select_options = load_source_options(option_type['optionSource'], api_client, {'optionTypeId' => option_type['id']})
|
220
|
+
else
|
221
|
+
select_options = load_source_options(option_type['optionSource'], api_client, api_params)
|
222
|
+
end
|
214
223
|
else
|
215
224
|
raise "select_prompt() requires selectOptions or optionSource!"
|
216
225
|
end
|
@@ -60,12 +60,9 @@ class Morpheus::Cli::RecentActivityCommand
|
|
60
60
|
|
61
61
|
# todo: impersonate command and show that info here
|
62
62
|
|
63
|
-
|
63
|
+
print_h1 "Recent Activity"
|
64
64
|
print cyan
|
65
|
-
|
66
|
-
puts "Coming soon.... see --json"
|
67
|
-
print "\n"
|
68
|
-
|
65
|
+
puts "Coming soon... see --json"
|
69
66
|
print reset,"\n"
|
70
67
|
|
71
68
|
end
|
data/lib/morpheus/cli/remote.rb
CHANGED
@@ -1,7 +1,9 @@
|
|
1
1
|
require 'fileutils'
|
2
|
+
require 'ostruct'
|
2
3
|
require 'yaml'
|
3
4
|
require 'io/console'
|
4
5
|
require 'rest_client'
|
6
|
+
require 'net/https'
|
5
7
|
require 'optparse'
|
6
8
|
require 'morpheus/cli/cli_command'
|
7
9
|
|
@@ -9,7 +11,7 @@ require 'morpheus/cli/cli_command'
|
|
9
11
|
class Morpheus::Cli::Remote
|
10
12
|
include Morpheus::Cli::CliCommand
|
11
13
|
|
12
|
-
register_subcommands :list, :add, :remove, :use, :unuse,
|
14
|
+
register_subcommands :list, :add, :get, :update, :remove, :use, :unuse, :current, :setup, :check
|
13
15
|
set_default_subcommand :list
|
14
16
|
|
15
17
|
def initialize()
|
@@ -17,197 +19,592 @@ class Morpheus::Cli::Remote
|
|
17
19
|
end
|
18
20
|
|
19
21
|
def handle(args)
|
20
|
-
if args.count == 0
|
21
|
-
|
22
|
-
else
|
23
|
-
|
24
|
-
end
|
22
|
+
# if args.count == 0
|
23
|
+
# list(args)
|
24
|
+
# else
|
25
|
+
# handle_subcommand(args)
|
26
|
+
# end
|
27
|
+
handle_subcommand(args)
|
25
28
|
end
|
26
29
|
|
27
30
|
def list(args)
|
28
31
|
options = {}
|
32
|
+
show_all_activity = false
|
29
33
|
optparse = Morpheus::Cli::OptionParser.new do|opts|
|
30
34
|
opts.banner = subcommand_usage()
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
+
opts.on("-a",'--all', "Show all the appliance activity details") do
|
36
|
+
show_all_activity = true
|
37
|
+
end
|
38
|
+
build_common_options(opts, options, [:json, :csv, :fields])
|
39
|
+
opts.footer = <<-EOT
|
40
|
+
This outputs a list of the configured remote appliances. It also indicates
|
41
|
+
the current appliance. The current appliance is where morpheus will send
|
42
|
+
its commands by default. That is, in absence of the '--remote' option.
|
43
|
+
EOT
|
35
44
|
end
|
36
45
|
optparse.parse!(args)
|
37
|
-
|
38
|
-
|
39
|
-
|
46
|
+
if args.count > 0
|
47
|
+
raise ::OptionParser::NeedlessArgument.new("#{args.join(' ')}")
|
48
|
+
end
|
49
|
+
@appliance_name, @appliance_url = Morpheus::Cli::Remote.active_appliance
|
50
|
+
appliances = ::Morpheus::Cli::Remote.load_all_remotes({})
|
51
|
+
# if appliances.empty?
|
52
|
+
# raise_command_error "You have no appliances configured. See the `remote add` command."
|
53
|
+
# end
|
54
|
+
|
55
|
+
if options[:json]
|
56
|
+
json_response = {"appliances" => appliances} # mock payload
|
57
|
+
if options[:include_fields]
|
58
|
+
json_response = {"appliances" => filter_data(appliances, options[:include_fields]) }
|
59
|
+
end
|
60
|
+
puts as_json(json_response, options)
|
61
|
+
return 0
|
62
|
+
end
|
63
|
+
if options[:csv]
|
64
|
+
puts records_as_csv(appliances, options)
|
65
|
+
return 0
|
66
|
+
end
|
67
|
+
|
68
|
+
print_h1 "Morpheus Appliances"
|
69
|
+
if appliances.empty?
|
70
|
+
print yellow
|
71
|
+
puts "You have no appliances configured. See the `remote add` command."
|
72
|
+
print reset, "\n"
|
40
73
|
else
|
41
|
-
rows = @appliances.collect do |app_name, v|
|
42
|
-
{
|
43
|
-
active: (v[:active] ? "=>" : ""),
|
44
|
-
name: app_name,
|
45
|
-
host: v[:host]
|
46
|
-
}
|
47
|
-
end
|
48
|
-
print "\n" ,cyan, bold, "Morpheus Appliances\n","==================", reset, "\n\n"
|
49
74
|
print cyan
|
50
|
-
tp rows, {:active => {:display_name => ""}}, {:name => {:width => 16}}, {:host => {:width => 40}}
|
75
|
+
#tp rows, {:active => {:display_name => ""}}, {:name => {:width => 16}}, {:host => {:width => 40}}
|
76
|
+
columns = [
|
77
|
+
{:active => {:display_name => "", :display_method => lambda {|it| it[:active] ? "=>" : "" } } },
|
78
|
+
{:name => {:width => 16} },
|
79
|
+
{:host => {:width => 40} },
|
80
|
+
{:version => lambda {|it| it[:build_version] } },
|
81
|
+
{:status => lambda {|it| format_appliance_status(it, cyan) } },
|
82
|
+
:username,
|
83
|
+
# {:session => {display_method: lambda {|it| get_appliance_session_blurbs(it).join(' ') }, max_width: 24} }
|
84
|
+
{:activity => {display_method: lambda {|it| show_all_activity ? get_appliance_session_blurbs(it).join("\t") : get_appliance_session_blurbs(it).first } } }
|
85
|
+
]
|
86
|
+
print as_pretty_table(appliances, columns, options)
|
51
87
|
print reset
|
52
88
|
if @appliance_name
|
53
|
-
#unless
|
89
|
+
#unless appliances.keys.size == 1
|
54
90
|
print cyan, "\n# => Currently using #{@appliance_name}\n", reset
|
55
91
|
#end
|
56
92
|
else
|
57
|
-
print "\n# => No
|
93
|
+
print "\n# => No current remote appliance, see `remote use`\n", reset
|
58
94
|
end
|
59
|
-
print "\n"
|
95
|
+
print reset, "\n"
|
60
96
|
end
|
97
|
+
return 0, nil
|
61
98
|
end
|
62
99
|
|
63
100
|
def add(args)
|
101
|
+
exit_code, err = 0, nil
|
64
102
|
options = {}
|
103
|
+
params = {}
|
104
|
+
new_appliance_map = {}
|
65
105
|
use_it = false
|
106
|
+
is_insecure = nil
|
66
107
|
optparse = Morpheus::Cli::OptionParser.new do|opts|
|
67
|
-
|
68
|
-
|
108
|
+
banner = subcommand_usage("[name] [url]")
|
109
|
+
banner_args = <<-EOT
|
110
|
+
[name] The name for your appliance. eg. mymorph
|
111
|
+
[url] The url of your appliance eg. https://morpheus.mycompany.com
|
112
|
+
EOT
|
113
|
+
opts.banner = banner + "\n" + banner_args
|
114
|
+
opts.on(nil, '--use', "Make this the current appliance" ) do
|
69
115
|
use_it = true
|
116
|
+
new_appliance_map[:active] = true
|
70
117
|
end
|
71
118
|
# let's free up the -d switch for global options, maybe?
|
72
119
|
opts.on( '-d', '--default', "Does the same thing as --use" ) do
|
73
120
|
use_it = true
|
121
|
+
new_appliance_map[:active] = true
|
122
|
+
end
|
123
|
+
opts.on(nil, "--secure", "Prevent insecure HTTPS communication. This is enabled by default.") do
|
124
|
+
params[:secure] = true
|
125
|
+
end
|
126
|
+
opts.on(nil, "--insecure", "Allow insecure HTTPS communication. i.e. Ignore SSL errors.") do
|
127
|
+
params[:insecure] = true
|
74
128
|
end
|
75
|
-
# todo: use Morpheus::Cli::OptionParser < OptionParser
|
76
|
-
# opts.on('-h', '--help', "Prints this help" ) do
|
77
|
-
# hidden_switches = ["--default"]
|
78
|
-
# good_opts = opts.to_s.split("\n").delete_if { |line| hidden_switches.find {|it| line =~ /#{Regexp.escape(it)}/ } }.join("\n")
|
79
|
-
# puts good_opts
|
80
|
-
# exit
|
81
|
-
# end
|
82
129
|
build_common_options(opts, options, [:quiet])
|
83
|
-
opts.footer =
|
84
|
-
|
130
|
+
opts.footer = <<-EOT
|
131
|
+
This will add a new remote appliance to your morpheus client configuration.
|
132
|
+
If the new remote is your one and only, --use is automatically applied and
|
133
|
+
it will be made the current remote appliance.
|
134
|
+
This command will prompt you to login and/or setup a fresh appliance.
|
135
|
+
Prompting can be skipped with use of the --quiet option.
|
136
|
+
EOT
|
85
137
|
end
|
86
138
|
optparse.parse!(args)
|
87
139
|
if args.count < 2
|
88
|
-
|
89
|
-
|
140
|
+
print_error Morpheus::Terminal.angry_prompt
|
141
|
+
puts_error "#{command_name} add expects 2 arguments: [name] [url]"
|
142
|
+
puts_error optparse
|
143
|
+
return 1
|
90
144
|
end
|
91
|
-
|
145
|
+
|
146
|
+
# load current appliances
|
147
|
+
appliances = ::Morpheus::Cli::Remote.appliances
|
148
|
+
|
149
|
+
# always use the first one
|
150
|
+
if appliances.empty?
|
151
|
+
new_appliance_map[:active] = true
|
152
|
+
end
|
153
|
+
|
154
|
+
# validate options
|
155
|
+
# construct new appliance map
|
156
|
+
# and save it in the config file
|
92
157
|
new_appliance_name = args[0].to_sym
|
158
|
+
|
159
|
+
# for the sake of sanity
|
160
|
+
if [:current, :all].include?(new_appliance_name)
|
161
|
+
raise_command_error "The specified appliance name is invalid: '#{args[0]}'"
|
162
|
+
end
|
163
|
+
# unique name
|
164
|
+
if appliances[new_appliance_name] != nil
|
165
|
+
raise_command_error "Remote appliance already configured with the name '#{args[0]}'"
|
166
|
+
end
|
167
|
+
new_appliance_map[:name] = new_appliance_name
|
168
|
+
|
169
|
+
if params[:insecure]
|
170
|
+
new_appliance_map[:insecure] = true
|
171
|
+
elsif params[:secure]
|
172
|
+
new_appliance_map.delete(:insecure)
|
173
|
+
end
|
174
|
+
if params[:url] || params[:host]
|
175
|
+
url = params[:url] || params[:host]
|
176
|
+
end
|
177
|
+
|
93
178
|
url = args[1]
|
94
|
-
if url !~ /^https
|
95
|
-
|
96
|
-
puts optparse
|
97
|
-
|
179
|
+
if url !~ /^https?\:\/\/.+/
|
180
|
+
raise_command_error "The specified appliance url is invalid: '#{args[1]}'"
|
181
|
+
#puts optparse
|
182
|
+
return 1
|
98
183
|
end
|
99
|
-
|
100
|
-
|
101
|
-
|
102
|
-
|
184
|
+
new_appliance_map[:host] = url
|
185
|
+
|
186
|
+
# save it
|
187
|
+
appliance = ::Morpheus::Cli::Remote.save_remote(new_appliance_name, new_appliance_map)
|
188
|
+
|
189
|
+
if !options[:quiet]
|
190
|
+
# print_green_success "Added remote #{new_appliance_name}"
|
191
|
+
print_green_success "Added remote #{new_appliance_name}"
|
103
192
|
end
|
104
|
-
|
105
|
-
|
106
|
-
|
107
|
-
|
108
|
-
|
109
|
-
|
110
|
-
|
111
|
-
|
112
|
-
|
113
|
-
|
114
|
-
|
115
|
-
|
193
|
+
|
194
|
+
# hit check api and store version and other info
|
195
|
+
if !options[:quiet]
|
196
|
+
print cyan
|
197
|
+
puts "Inspecting remote appliance url: #{appliance[:host]} ..."
|
198
|
+
end
|
199
|
+
appliance = ::Morpheus::Cli::Remote.refresh_remote(new_appliance_name)
|
200
|
+
if !options[:quiet]
|
201
|
+
print cyan
|
202
|
+
puts "Status is: #{format_appliance_status(appliance)}"
|
203
|
+
end
|
204
|
+
# puts "refreshed appliance #{appliance.inspect}"
|
205
|
+
# determine command exit_code and err
|
206
|
+
exit_code = (appliance[:status] == 'ready' || appliance[:status] == 'fresh') ? 0 : 1
|
207
|
+
|
208
|
+
if exit_code == 0
|
209
|
+
if appliance[:error]
|
210
|
+
exit_code = 1
|
211
|
+
err = "Check Failed: #{appliance[:error]}"
|
116
212
|
end
|
117
213
|
end
|
118
|
-
|
119
|
-
if options[:quiet]
|
120
|
-
return
|
214
|
+
|
215
|
+
if options[:quiet]
|
216
|
+
return exit_code, err
|
121
217
|
end
|
218
|
+
|
219
|
+
# check_cmd_result = check_appliance([new_appliance_name, "--quiet"])
|
220
|
+
# check_cmd_result = check_appliance([new_appliance_name])
|
221
|
+
|
222
|
+
if appliance[:status] == 'fresh' # || appliance[:setup_needed] == true
|
223
|
+
print cyan
|
224
|
+
puts "It looks like this appliance needs to be setup. Starting setup ..."
|
225
|
+
return setup([new_appliance_name])
|
226
|
+
# no need to login, setup() handles that
|
227
|
+
end
|
228
|
+
|
122
229
|
|
123
|
-
#
|
124
|
-
#
|
125
|
-
|
126
|
-
|
230
|
+
# only login if you are using this remote
|
231
|
+
# maybe remote use should do the login prompting eh?
|
232
|
+
# if appliance[:active] && appliance[:status] == 'ready'
|
233
|
+
if appliance[:status] == 'ready'
|
234
|
+
print reset
|
235
|
+
if ::Morpheus::Cli::OptionTypes::confirm("Would you like to login now?", options.merge({default: true}))
|
236
|
+
login_result = ::Morpheus::Cli::Login.new.handle(["--remote", appliance[:name].to_s])
|
237
|
+
keep_trying = true
|
238
|
+
while keep_trying do
|
239
|
+
if ::Morpheus::Cli::OptionTypes::confirm("Login was unsuccessful. Would you like to try again?", options.merge({default: true}))
|
240
|
+
login_result = ::Morpheus::Cli::Login.new.handle(["--remote", appliance[:name].to_s])
|
241
|
+
if login_result == 0
|
242
|
+
keep_trying = false
|
243
|
+
end
|
244
|
+
else
|
245
|
+
keep_trying = false
|
246
|
+
end
|
247
|
+
end
|
248
|
+
|
249
|
+
end
|
250
|
+
else
|
251
|
+
#puts "Status is #{format_appliance_status(appliance)}"
|
252
|
+
end
|
253
|
+
|
254
|
+
# print new appliance details
|
255
|
+
_get(appliance[:name], {})
|
256
|
+
|
257
|
+
return exit_code, err
|
258
|
+
end
|
259
|
+
|
260
|
+
def refresh(args)
|
261
|
+
check_appliance(args)
|
262
|
+
end
|
263
|
+
|
264
|
+
def check(args)
|
265
|
+
options = {}
|
266
|
+
checkall = false
|
267
|
+
optparse = Morpheus::Cli::OptionParser.new do|opts|
|
268
|
+
opts.banner = subcommand_usage("[name]")
|
269
|
+
opts.on("-a",'--all', "Refresh all appliances") do
|
270
|
+
checkall = true
|
271
|
+
end
|
272
|
+
build_common_options(opts, options, [:quiet])
|
273
|
+
opts.footer = <<-EOT
|
274
|
+
This can be used to refresh a remote appliance status.
|
275
|
+
It makes an api request to the configured appliance url, and stores the status
|
276
|
+
of the server and other info, e.g. version, in the local morpheus cli configuration.
|
277
|
+
EOT
|
278
|
+
end
|
279
|
+
optparse.parse!(args)
|
280
|
+
id_list = nil
|
281
|
+
checkall = true if args[0] == "all" and args.size == 1 # sure, why not
|
282
|
+
if checkall
|
283
|
+
# id_list = ::Morpheus::Cli::Remote.appliances.keys # sort ?
|
284
|
+
return _check_all_appliances()
|
285
|
+
elsif args.count < 1
|
286
|
+
print_error Morpheus::Terminal.angry_prompt
|
287
|
+
puts_error "#{command_name} update expects argument [name] or option --all"
|
288
|
+
puts_error optparse
|
289
|
+
return 1
|
290
|
+
else
|
291
|
+
id_list = parse_id_list(args)
|
292
|
+
end
|
293
|
+
#connect(options)
|
294
|
+
return run_command_for_each_arg(id_list) do |arg|
|
295
|
+
_check_appliance(arg, options)
|
296
|
+
end
|
297
|
+
end
|
298
|
+
|
299
|
+
def _check_all_appliances()
|
300
|
+
# reresh all appliances and then display the list view
|
301
|
+
id_list = ::Morpheus::Cli::Remote.appliances.keys # sort ?
|
302
|
+
if id_list.size > 1
|
303
|
+
print cyan
|
304
|
+
print "Checking #{id_list.size} appliances "
|
305
|
+
end
|
306
|
+
id_list.each do |appliance_name|
|
307
|
+
print "."
|
308
|
+
::Morpheus::Cli::Remote.refresh_remote(appliance_name)
|
309
|
+
end
|
310
|
+
print "\n"
|
311
|
+
list([])
|
312
|
+
|
313
|
+
end
|
314
|
+
|
315
|
+
def _check_appliance(appliance_name, options)
|
127
316
|
begin
|
128
|
-
|
129
|
-
if
|
130
|
-
|
317
|
+
appliance = nil
|
318
|
+
if appliance_name == "current"
|
319
|
+
appliance = ::Morpheus::Cli::Remote.load_active_remote()
|
320
|
+
if !appliance
|
321
|
+
raise_command_error "No current appliance, see `remote use`."
|
322
|
+
end
|
323
|
+
appliance_name = appliance[:name]
|
324
|
+
else
|
325
|
+
appliance = ::Morpheus::Cli::Remote.load_remote(appliance_name)
|
326
|
+
if !appliance
|
327
|
+
raise_command_error "Remote appliance not found by the name '#{appliance_name}'"
|
328
|
+
end
|
131
329
|
end
|
132
|
-
|
330
|
+
|
331
|
+
# found appliance
|
332
|
+
# now refresh it
|
333
|
+
|
334
|
+
start_time = Time.now
|
335
|
+
|
336
|
+
Morpheus::Logging::DarkPrinter.puts "checking remote appliance url: #{appliance[:host]} ..." if Morpheus::Logging.debug?
|
337
|
+
|
338
|
+
appliance = ::Morpheus::Cli::Remote.refresh_remote(appliance_name)
|
339
|
+
|
340
|
+
took_sec = (Time.now - start_time)
|
341
|
+
|
342
|
+
if options[:quiet]
|
343
|
+
return 0
|
344
|
+
end
|
345
|
+
|
346
|
+
Morpheus::Logging::DarkPrinter.puts "remote appliance check completed in #{took_sec.round(3)}s" if Morpheus::Logging.debug?
|
347
|
+
|
348
|
+
# puts "remote #{appliance[:name]} status: #{format_appliance_status(appliance)}"
|
349
|
+
|
350
|
+
# if options[:json]
|
351
|
+
# print JSON.pretty_generate(json_response), "\n"
|
352
|
+
# return
|
353
|
+
# end
|
354
|
+
|
355
|
+
# show user latest info
|
356
|
+
return _get(appliance[:name], {})
|
357
|
+
|
133
358
|
rescue RestClient::Exception => e
|
134
|
-
|
135
|
-
|
136
|
-
print cyan,"Appliance is ready.\n", reset
|
359
|
+
print_rest_exception(e, options)
|
360
|
+
exit 1
|
137
361
|
end
|
362
|
+
end
|
138
363
|
|
139
|
-
|
140
|
-
|
141
|
-
|
364
|
+
def update(args)
|
365
|
+
options = {}
|
366
|
+
params = {}
|
367
|
+
use_it = false
|
368
|
+
is_insecure = nil
|
369
|
+
optparse = Morpheus::Cli::OptionParser.new do|opts|
|
370
|
+
opts.banner = subcommand_usage("[name]")
|
371
|
+
# opts.on(nil, "--name STRING", "Update the name of your remote appliance") do |val|
|
372
|
+
# params['name'] = val
|
373
|
+
# end
|
374
|
+
opts.on("--url URL", String, "Update the url of your remote appliance") do |val|
|
375
|
+
params[:host] = val
|
376
|
+
end
|
377
|
+
opts.on(nil, "--secure", "Prevent insecure HTTPS communication. This is enabled by default") do
|
378
|
+
params[:secure] = true
|
142
379
|
end
|
380
|
+
opts.on(nil, "--insecure", "Allow insecure HTTPS communication. i.e. Ignore SSL errors.") do
|
381
|
+
params[:insecure] = true
|
382
|
+
end
|
383
|
+
opts.on(nil, '--use', "Make this the current appliance" ) do
|
384
|
+
use_it = true
|
385
|
+
params[:active] = true
|
386
|
+
end
|
387
|
+
build_common_options(opts, options, [:quiet])
|
388
|
+
opts.footer = "This can be used to update remote appliance settings.\n"
|
389
|
+
end
|
390
|
+
optparse.parse!(args)
|
391
|
+
puts "args is #{args.inspect}"
|
392
|
+
if args.count != 1
|
393
|
+
print_error Morpheus::Terminal.angry_prompt
|
394
|
+
puts_error "#{command_name} update expects argument [name]."
|
395
|
+
puts_error optparse
|
396
|
+
return 1
|
143
397
|
end
|
144
398
|
|
145
|
-
|
399
|
+
appliance_name = args[0].to_sym
|
400
|
+
appliance = ::Morpheus::Cli::Remote.load_remote(appliance_name)
|
401
|
+
if !appliance
|
402
|
+
raise_command_error "Remote appliance not found by the name '#{appliance_name}'"
|
403
|
+
end
|
404
|
+
|
405
|
+
# params[:url] = args[1] if args[1]
|
406
|
+
|
407
|
+
if params.empty?
|
408
|
+
print_error Morpheus::Terminal.angry_prompt
|
409
|
+
puts_error "Specify atleast one option to update"
|
410
|
+
puts_error optparse
|
411
|
+
return 1
|
412
|
+
end
|
413
|
+
|
414
|
+
if params[:insecure]
|
415
|
+
appliance[:insecure] = true
|
416
|
+
elsif params[:secure]
|
417
|
+
appliance.delete(:insecure)
|
418
|
+
end
|
419
|
+
if params[:url] || params[:host]
|
420
|
+
appliance[:host] = params[:url] || params[:host]
|
421
|
+
end
|
422
|
+
|
423
|
+
::Morpheus::Cli::Remote.save_remote(appliance_name, appliance)
|
424
|
+
|
425
|
+
print_green_success "Updated remote #{appliance_name}"
|
426
|
+
# todo: just go ahead and refresh it now...
|
427
|
+
# _check(appliance_name, {:quiet => true})
|
428
|
+
appliance = ::Morpheus::Cli::Remote.refresh_remote(appliance_name)
|
429
|
+
# print new appliance details
|
430
|
+
_get(appliance[:name], {})
|
431
|
+
return 0, nil
|
432
|
+
end
|
433
|
+
|
434
|
+
def get(args)
|
435
|
+
options = {}
|
436
|
+
optparse = OptionParser.new do|opts|
|
437
|
+
opts.banner = subcommand_usage("[name]")
|
438
|
+
build_common_options(opts, options, [:json,:csv, :fields, :quiet])
|
439
|
+
end
|
440
|
+
optparse.parse!(args)
|
441
|
+
if args.count < 1
|
442
|
+
print_error Morpheus::Terminal.angry_prompt
|
443
|
+
puts_error "#{command_name} get expects argument [name]."
|
444
|
+
puts_error optparse
|
445
|
+
return 1
|
446
|
+
end
|
447
|
+
#connect(options)
|
448
|
+
id_list = parse_id_list(args)
|
449
|
+
return run_command_for_each_arg(id_list) do |arg|
|
450
|
+
_get(arg, options)
|
451
|
+
end
|
452
|
+
end
|
453
|
+
|
454
|
+
def _get(appliance_name, options)
|
455
|
+
begin
|
456
|
+
appliance = nil
|
457
|
+
if appliance_name == "current"
|
458
|
+
appliance = ::Morpheus::Cli::Remote.load_active_remote()
|
459
|
+
if !appliance
|
460
|
+
raise_command_error "No current appliance, see `remote use`."
|
461
|
+
end
|
462
|
+
appliance_name = appliance[:name]
|
463
|
+
else
|
464
|
+
appliance = ::Morpheus::Cli::Remote.load_remote(appliance_name)
|
465
|
+
if !appliance
|
466
|
+
raise_command_error "Remote appliance not found by the name '#{appliance_name}'"
|
467
|
+
end
|
468
|
+
end
|
469
|
+
|
470
|
+
if options[:json]
|
471
|
+
json_response = {remote_appliance: appliance} # mock payload
|
472
|
+
puts as_json(json_response, options)
|
473
|
+
return
|
474
|
+
end
|
475
|
+
|
476
|
+
# expando
|
477
|
+
# appliance = OStruct.new(appliance)
|
478
|
+
|
479
|
+
# todo: just go ahead and refresh it now...
|
480
|
+
# _check(appliance_name, {:quiet => true})
|
481
|
+
# appliance = ::Morpheus::Cli::Remote.refresh_remote(appliance_name)
|
482
|
+
|
483
|
+
if appliance[:active]
|
484
|
+
# print_h1 "Current Remote Appliance: #{appliance[:name]}"
|
485
|
+
print_h1 "Remote Appliance: #{appliance[:name]}"
|
486
|
+
else
|
487
|
+
print_h1 "Remote Appliance: #{appliance[:name]}"
|
488
|
+
end
|
489
|
+
print cyan
|
490
|
+
description_cols = {
|
491
|
+
"Name" => :name,
|
492
|
+
"Url" => :host,
|
493
|
+
"Secure" => lambda {|it| format_appliance_secure(it) },
|
494
|
+
"Version" => lambda {|it| it[:build_version] ? "#{it[:build_version]}" : 'unknown' },
|
495
|
+
"Status" => lambda {|it| format_appliance_status(it, cyan) },
|
496
|
+
"Username" => :username,
|
497
|
+
# "Authenticated" => lambda {|it| format_boolean it[:authenticated] },
|
498
|
+
# todo: fix this layout, obv
|
499
|
+
"Activity" => lambda {|it| get_appliance_session_blurbs(it).join("\n" + (' '*10)) }
|
500
|
+
}
|
501
|
+
print cyan
|
502
|
+
puts as_description_list(appliance, description_cols)
|
503
|
+
|
504
|
+
# if appliance[:insecure]
|
505
|
+
# puts " Ignore SSL Errors: Yes"
|
506
|
+
# else
|
507
|
+
# puts " Ignore SSL Errors: No"
|
508
|
+
# end
|
509
|
+
|
510
|
+
if appliance[:active]
|
511
|
+
# print cyan
|
512
|
+
print cyan, "\n", " => This is the current appliance.", "\n"
|
513
|
+
end
|
514
|
+
|
515
|
+
print reset, "\n"
|
516
|
+
|
517
|
+
rescue RestClient::Exception => e
|
518
|
+
print_rest_exception(e, options)
|
519
|
+
exit 1
|
520
|
+
end
|
146
521
|
end
|
147
522
|
|
148
523
|
def remove(args)
|
149
524
|
options = {}
|
150
525
|
optparse = Morpheus::Cli::OptionParser.new do|opts|
|
151
526
|
opts.banner = subcommand_usage("[name]")
|
152
|
-
opts.on( '-
|
153
|
-
|
154
|
-
end
|
527
|
+
# opts.on( '-f', '--force', "Remote appliance anyway??" ) do
|
528
|
+
# options[:default] = true
|
529
|
+
# end
|
155
530
|
opts.footer = "This will delete an appliance from your list."
|
156
|
-
build_common_options(opts, options, [:auto_confirm])
|
531
|
+
build_common_options(opts, options, [:auto_confirm, :quiet])
|
157
532
|
end
|
158
533
|
optparse.parse!(args)
|
159
|
-
if args.
|
160
|
-
|
161
|
-
|
534
|
+
if args.count < 1
|
535
|
+
#raise_command_error "#{command_name} remove requires argument [name].", optparse
|
536
|
+
print_error Morpheus::Terminal.angry_prompt
|
537
|
+
puts_error "#{command_name} remove requires argument [name]."
|
538
|
+
puts_error optparse
|
539
|
+
return 1, nil
|
162
540
|
end
|
163
|
-
@appliances = ::Morpheus::Cli::Remote.appliances
|
164
541
|
appliance_name = args[0].to_sym
|
165
|
-
|
166
|
-
|
167
|
-
|
168
|
-
|
169
|
-
|
170
|
-
|
171
|
-
|
172
|
-
|
173
|
-
|
174
|
-
|
175
|
-
|
176
|
-
|
177
|
-
|
178
|
-
|
542
|
+
appliance = ::Morpheus::Cli::Remote.load_remote(appliance_name)
|
543
|
+
if !appliance
|
544
|
+
raise_command_error "Remote appliance not found by the name '#{appliance_name}'"
|
545
|
+
end
|
546
|
+
unless options[:yes] || ::Morpheus::Cli::OptionTypes::confirm("Are you sure you would like to delete '#{appliance_name}' from your list of remote appliances?", options)
|
547
|
+
return 9, "aborted command" # new exit code for aborting confirmation
|
548
|
+
end
|
549
|
+
|
550
|
+
# ok, delete it
|
551
|
+
::Morpheus::Cli::Remote.delete_remote(appliance_name)
|
552
|
+
|
553
|
+
# return result
|
554
|
+
if options[:quiet]
|
555
|
+
return 0, nil
|
556
|
+
end
|
557
|
+
print_green_success "Deleted remote #{appliance_name}"
|
558
|
+
list([])
|
559
|
+
# recalculate shell prompt after this change
|
560
|
+
if Morpheus::Cli::Shell.instance
|
561
|
+
Morpheus::Cli::Shell.instance.reinitialize()
|
179
562
|
end
|
563
|
+
return 0, nil
|
180
564
|
end
|
181
565
|
|
182
566
|
def use(args)
|
183
567
|
options = {}
|
184
568
|
optparse = Morpheus::Cli::OptionParser.new do|opts|
|
185
569
|
opts.banner = subcommand_usage("[name]")
|
186
|
-
build_common_options(opts, options, [])
|
187
|
-
opts.footer = "
|
570
|
+
build_common_options(opts, options, [:quiet])
|
571
|
+
opts.footer = "Make an appliance the current remote appliance.\n" +
|
188
572
|
"This allows you to switch between your different appliances.\n" +
|
189
573
|
"You may override this with the --remote option in your commands."
|
190
574
|
end
|
191
575
|
optparse.parse!(args)
|
192
576
|
if args.count < 1
|
193
|
-
|
194
|
-
|
577
|
+
print_error Morpheus::Terminal.angry_prompt
|
578
|
+
puts_error "#{command_name} use expects argument [name]."
|
579
|
+
puts_error optparse
|
580
|
+
return 1
|
195
581
|
end
|
196
|
-
|
197
|
-
|
198
|
-
if
|
199
|
-
|
200
|
-
|
201
|
-
|
202
|
-
|
203
|
-
|
204
|
-
|
205
|
-
|
206
|
-
@appliance_name, @appliance_url = Morpheus::Cli::Remote.active_appliance
|
207
|
-
#print cyan,"Switched to using appliance #{args[0]}","\n",reset
|
208
|
-
#list([])
|
582
|
+
appliance_name = args[0].to_sym
|
583
|
+
appliance = ::Morpheus::Cli::Remote.load_remote(appliance_name)
|
584
|
+
if !appliance
|
585
|
+
raise_command_error "Remote appliance not found by the name '#{appliance_name}'"
|
586
|
+
end
|
587
|
+
|
588
|
+
if appliance[:active] == true
|
589
|
+
if !options[:quiet]
|
590
|
+
print cyan
|
591
|
+
puts "Using remote #{appliance_name} (still)"
|
209
592
|
end
|
593
|
+
return true
|
210
594
|
end
|
595
|
+
# appliance = ::Morpheus::Cli::Remote.set_active_appliance(appliance_name)
|
596
|
+
appliance[:active] = true
|
597
|
+
appliance = ::Morpheus::Cli::Remote.save_remote(appliance_name, appliance)
|
598
|
+
|
599
|
+
# recalculate shell prompt after this change
|
600
|
+
if Morpheus::Cli::Shell.instance
|
601
|
+
Morpheus::Cli::Shell.instance.reinitialize()
|
602
|
+
end
|
603
|
+
|
604
|
+
if !options[:quiet]
|
605
|
+
puts "#{cyan}Using remote #{appliance_name}#{reset}"
|
606
|
+
end
|
607
|
+
return true
|
211
608
|
end
|
212
609
|
|
213
610
|
def unuse(args)
|
@@ -215,18 +612,49 @@ class Morpheus::Cli::Remote
|
|
215
612
|
optparse = Morpheus::Cli::OptionParser.new do|opts|
|
216
613
|
opts.banner = subcommand_usage()
|
217
614
|
opts.footer = "" +
|
218
|
-
"This clears the current
|
615
|
+
"This clears the current remote appliance.\n" +
|
219
616
|
"You will need to use an appliance, or pass the --remote option to your commands."
|
220
617
|
build_common_options(opts, options, [])
|
221
618
|
end
|
222
619
|
optparse.parse!(args)
|
223
620
|
@appliance_name, @appliance_url = Morpheus::Cli::Remote.active_appliance
|
621
|
+
if !@appliance_name
|
622
|
+
puts "You are not using any appliance"
|
623
|
+
return false
|
624
|
+
end
|
625
|
+
Morpheus::Cli::Remote.clear_active_appliance()
|
626
|
+
puts "You are no longer using the appliance #{@appliance_name}"
|
627
|
+
# recalculate shell prompt after this change
|
628
|
+
if Morpheus::Cli::Shell.instance
|
629
|
+
Morpheus::Cli::Shell.instance.reinitialize()
|
630
|
+
end
|
631
|
+
return true
|
632
|
+
end
|
633
|
+
|
634
|
+
def current(args)
|
635
|
+
options = {}
|
636
|
+
name_only = false
|
637
|
+
optparse = Morpheus::Cli::OptionParser.new do|opts|
|
638
|
+
opts.banner = subcommand_usage()
|
639
|
+
opts.on( '-n', '--name', "Print only the name." ) do
|
640
|
+
name_only = true
|
641
|
+
end
|
642
|
+
build_common_options(opts, options, [])
|
643
|
+
opts.footer = "Print details about the current remote appliance." +
|
644
|
+
"The default behavior is the same as 'remote get current'."
|
645
|
+
end
|
646
|
+
optparse.parse!(args)
|
647
|
+
|
648
|
+
if name_only
|
649
|
+
return print_current(args)
|
650
|
+
else
|
651
|
+
return _get("current", {})
|
652
|
+
end
|
653
|
+
|
224
654
|
if @appliance_name
|
225
|
-
|
226
|
-
@appliance_name, @appliance_url = nil, nil
|
227
|
-
return true
|
655
|
+
print cyan, @appliance_name,"\n",reset
|
228
656
|
else
|
229
|
-
|
657
|
+
print yellow, "No active appliance, see `remote use`\n", reset
|
230
658
|
return false
|
231
659
|
end
|
232
660
|
end
|
@@ -235,7 +663,7 @@ class Morpheus::Cli::Remote
|
|
235
663
|
options = {}
|
236
664
|
optparse = Morpheus::Cli::OptionParser.new do|opts|
|
237
665
|
opts.banner = subcommand_usage()
|
238
|
-
build_common_options(opts, options, [
|
666
|
+
build_common_options(opts, options, [])
|
239
667
|
opts.footer = "Prints the name of the current remote appliance"
|
240
668
|
end
|
241
669
|
optparse.parse!(args)
|
@@ -300,7 +728,7 @@ class Morpheus::Cli::Remote
|
|
300
728
|
# end
|
301
729
|
return false
|
302
730
|
else
|
303
|
-
|
731
|
+
print_h1 "Morpheus Appliance Setup"
|
304
732
|
|
305
733
|
puts "It looks like you're the first one here."
|
306
734
|
puts "Let's initialize your remote appliance at #{@appliance_url}"
|
@@ -308,7 +736,7 @@ class Morpheus::Cli::Remote
|
|
308
736
|
|
309
737
|
|
310
738
|
# Master Account
|
311
|
-
|
739
|
+
print_h2 "Create Master Account"
|
312
740
|
account_option_types = [
|
313
741
|
{'fieldName' => 'accountName', 'fieldLabel' => 'Master Account Name', 'type' => 'text', 'required' => true, 'displayOrder' => 1},
|
314
742
|
]
|
@@ -316,7 +744,7 @@ class Morpheus::Cli::Remote
|
|
316
744
|
payload.merge!(v_prompt)
|
317
745
|
|
318
746
|
# Master User
|
319
|
-
|
747
|
+
print_h2 "Create Master User"
|
320
748
|
user_option_types = [
|
321
749
|
{'fieldName' => 'firstName', 'fieldLabel' => 'First Name', 'type' => 'text', 'required' => false, 'displayOrder' => 1},
|
322
750
|
{'fieldName' => 'lastName', 'fieldLabel' => 'Last Name', 'type' => 'text', 'required' => false, 'displayOrder' => 2},
|
@@ -339,7 +767,7 @@ class Morpheus::Cli::Remote
|
|
339
767
|
payload.merge!(v_prompt)
|
340
768
|
|
341
769
|
# Extra settings
|
342
|
-
|
770
|
+
print_h2 "Initial Setup"
|
343
771
|
extra_option_types = [
|
344
772
|
{'fieldName' => 'applianceName', 'fieldLabel' => 'Appliance Name', 'type' => 'text', 'required' => true, 'defaultValue' => nil},
|
345
773
|
{'fieldName' => 'applianceUrl', 'fieldLabel' => 'Appliance URL', 'type' => 'text', 'required' => true, 'defaultValue' => appliance_status_json['applianceUrl']},
|
@@ -401,6 +829,107 @@ class Morpheus::Cli::Remote
|
|
401
829
|
end
|
402
830
|
end
|
403
831
|
|
832
|
+
def format_appliance_status(app_map, return_color=cyan)
|
833
|
+
return "" if !app_map
|
834
|
+
status_str = app_map[:status] || app_map['status'] || "unknown" # get_object_value(app_map, :status)
|
835
|
+
status_str = status_str.empty? ? "unknown" : status_str.to_s.downcase
|
836
|
+
out = ""
|
837
|
+
if status_str == "new"
|
838
|
+
out << "#{cyan}#{status_str.upcase}#{return_color}"
|
839
|
+
elsif status_str == "ready"
|
840
|
+
out << "#{green}#{status_str.upcase}#{return_color}"
|
841
|
+
elsif status_str == "unreachable"
|
842
|
+
out << "#{red}#{status_str.upcase}#{return_color}"
|
843
|
+
elsif status_str.include?("error")
|
844
|
+
out << "#{red}#{status_str.upcase}#{return_color}"
|
845
|
+
# elsif status_str == "unknown"
|
846
|
+
# out << "#{yellow}#{status_str}#{return_color}"
|
847
|
+
elsif status_str == "fresh"
|
848
|
+
# cold appliance, needs setup
|
849
|
+
out << "#{magenta}#{status_str.upcase}#{return_color}"
|
850
|
+
else
|
851
|
+
# dunno
|
852
|
+
out << "#{status_str}"
|
853
|
+
end
|
854
|
+
out
|
855
|
+
end
|
856
|
+
|
857
|
+
def format_appliance_secure(app_map, return_color=cyan)
|
858
|
+
return "" if !app_map
|
859
|
+
out = ""
|
860
|
+
is_ssl = app_map[:host].to_s =~ /^https/
|
861
|
+
if !is_ssl
|
862
|
+
out << "No (no SSL)"
|
863
|
+
else
|
864
|
+
if app_map[:insecure]
|
865
|
+
out << "No (Ignore SSL Errors)"
|
866
|
+
else
|
867
|
+
# should have a flag that gets set when everything actually looks good..
|
868
|
+
out << "Yes"
|
869
|
+
end
|
870
|
+
end
|
871
|
+
out
|
872
|
+
end
|
873
|
+
|
874
|
+
# get display info about the current and past sessions
|
875
|
+
#
|
876
|
+
def get_appliance_session_blurbs(app_map)
|
877
|
+
# app_map = OStruct.new(app_map)
|
878
|
+
blurbs = []
|
879
|
+
# Current User
|
880
|
+
#
|
881
|
+
username = app_map[:username]
|
882
|
+
# creds = app_map[:access_token]
|
883
|
+
#creds = Morpheus::Cli::Credentials.new(app_map[:name], app_map[:host]).load_saved_credentials()
|
884
|
+
|
885
|
+
|
886
|
+
|
887
|
+
if app_map[:status] == 'ready'
|
888
|
+
|
889
|
+
if app_map[:authenticated]
|
890
|
+
#blurbs << app_map[:username] ? "Authenticated as #{app_map[:username]}" : "Authenticated"
|
891
|
+
blurbs << "Authenticated."
|
892
|
+
if app_map[:last_login_at]
|
893
|
+
blurbs << "Logged in #{format_duration(app_map[:last_login_at])} ago."
|
894
|
+
end
|
895
|
+
else
|
896
|
+
if app_map[:last_logout_at]
|
897
|
+
blurbs << "Logged out #{format_duration(app_map[:last_logout_at])} ago."
|
898
|
+
else
|
899
|
+
blurbs << "Logged out."
|
900
|
+
end
|
901
|
+
if app_map[:last_login_at]
|
902
|
+
blurbs << "Last login at #{format_local_dt(app_map[:last_login_at])}."
|
903
|
+
end
|
904
|
+
end
|
905
|
+
|
906
|
+
if app_map[:last_success_at]
|
907
|
+
blurbs << "Last success at #{format_local_dt(app_map[:last_success_at])}"
|
908
|
+
end
|
909
|
+
|
910
|
+
else
|
911
|
+
|
912
|
+
if app_map[:last_check]
|
913
|
+
if app_map[:last_check][:timestamp]
|
914
|
+
blurbs << "Last checked #{format_duration(app_map[:last_check][:timestamp])} ago."
|
915
|
+
end
|
916
|
+
if app_map[:last_check][:error]
|
917
|
+
blurbs << "Error: #{app_map[:last_check][:error]}"
|
918
|
+
end
|
919
|
+
if app_map[:last_check][:http_status]
|
920
|
+
blurbs << "HTTP #{app_map[:last_check][:http_status]}"
|
921
|
+
end
|
922
|
+
end
|
923
|
+
|
924
|
+
if app_map[:last_success_at]
|
925
|
+
blurbs << "Last Success: #{format_local_dt(app_map[:last_success_at])}"
|
926
|
+
end
|
927
|
+
|
928
|
+
end
|
929
|
+
|
930
|
+
return blurbs
|
931
|
+
end
|
932
|
+
|
404
933
|
class << self
|
405
934
|
include Term::ANSIColor
|
406
935
|
|
@@ -408,9 +937,6 @@ class Morpheus::Cli::Remote
|
|
408
937
|
# it is structured like :appliance_name => {:host => "htt[://api.gomorpheus.com", :active => true}
|
409
938
|
# not named @@appliances to avoid confusion with the instance variable . This is also a command class...
|
410
939
|
@@appliance_config = nil
|
411
|
-
#@@current_appliance = nil
|
412
|
-
|
413
|
-
|
414
940
|
|
415
941
|
def appliances
|
416
942
|
self.appliance_config
|
@@ -433,23 +959,87 @@ class Morpheus::Cli::Remote
|
|
433
959
|
end
|
434
960
|
end
|
435
961
|
|
436
|
-
|
962
|
+
# Returns all the appliances in the configuration
|
963
|
+
# @param params [Hash] not used right now
|
964
|
+
# @return [Array] of appliances, all of them.
|
965
|
+
def load_all_remotes(params={})
|
966
|
+
if self.appliances.empty?
|
967
|
+
return []
|
968
|
+
end
|
969
|
+
all_appliances = self.appliances.collect do |app_name, app_map|
|
970
|
+
row = app_map.clone # OStruct.new(app_map) tempting
|
971
|
+
row[:name] = app_name
|
972
|
+
row
|
973
|
+
# {
|
974
|
+
# active: v[:active],
|
975
|
+
# name: app_name,
|
976
|
+
# host: v[:host], # || v[:url],
|
977
|
+
# #"LICENSE": v[:licenseIsInstalled] ? "Installed" : "(unknown)" # never return a license key from the server, ever!
|
978
|
+
# status: v[:status],
|
979
|
+
# username: v[:username],
|
980
|
+
# last_check: v[:last_check],
|
981
|
+
# last_whoami: v[:last_whoami],
|
982
|
+
# last_api_request: v[:last_api_request],
|
983
|
+
# last_api_result: v[:last_api_result],
|
984
|
+
# last_command: v[:last_command],
|
985
|
+
# last_command_result: v[:last_command_result]
|
986
|
+
# }
|
987
|
+
end
|
988
|
+
return all_appliances
|
989
|
+
end
|
990
|
+
|
991
|
+
# @return Hash info about the active appliance
|
992
|
+
def load_active_remote()
|
993
|
+
# todo: use this in favor of Remote.active_appliance perhaps?
|
994
|
+
if self.appliances.empty?
|
995
|
+
return nil
|
996
|
+
end
|
997
|
+
result = nil
|
998
|
+
app_name, app_map = self.appliances.find {|k,v| v[:active] == true }
|
999
|
+
if app_map
|
1000
|
+
result = app_map
|
1001
|
+
result[:name] = app_name # app_name.to_s to be more consistant with other display values
|
1002
|
+
end
|
1003
|
+
return result
|
1004
|
+
end
|
1005
|
+
|
1006
|
+
# @param [String or Symbol] name of the remote to load (converted to symbol)
|
1007
|
+
# @return [Hash] info about the appliance
|
1008
|
+
def load_remote(app_name)
|
1009
|
+
if self.appliances.empty? || app_name.nil?
|
1010
|
+
return nil
|
1011
|
+
end
|
1012
|
+
result = nil
|
1013
|
+
app_map = self.appliances[app_name.to_sym]
|
1014
|
+
if app_map
|
1015
|
+
result = app_map
|
1016
|
+
result[:name] = app_name # .to_s probably better
|
1017
|
+
end
|
1018
|
+
return result
|
1019
|
+
end
|
1020
|
+
|
1021
|
+
def set_active_appliance(app_name)
|
1022
|
+
app_name = app_name.to_sym
|
437
1023
|
new_appliances = self.appliances
|
438
1024
|
new_appliances.each do |k,v|
|
439
|
-
is_match = (
|
1025
|
+
is_match = (app_name ? (k == app_name) : false)
|
440
1026
|
if is_match
|
441
1027
|
v[:active] = true
|
442
1028
|
else
|
443
|
-
v
|
1029
|
+
v.delete(:active)
|
1030
|
+
# v.delete('active')
|
1031
|
+
# v[:active] = false
|
444
1032
|
end
|
445
1033
|
end
|
446
1034
|
save_appliances(new_appliances)
|
1035
|
+
return load_remote(app_name)
|
447
1036
|
end
|
448
1037
|
|
449
1038
|
def clear_active_appliance
|
1039
|
+
#return set_active_appliance(nil)
|
450
1040
|
new_appliances = self.appliances
|
451
1041
|
new_appliances.each do |k,v|
|
452
|
-
v
|
1042
|
+
v.delete(:active)
|
453
1043
|
end
|
454
1044
|
save_appliances(new_appliances)
|
455
1045
|
end
|
@@ -457,7 +1047,7 @@ class Morpheus::Cli::Remote
|
|
457
1047
|
def load_appliance_file
|
458
1048
|
fn = appliances_file_path
|
459
1049
|
if File.exist? fn
|
460
|
-
|
1050
|
+
Morpheus::Logging::DarkPrinter.puts "loading appliances file #{fn}" if Morpheus::Logging.debug?
|
461
1051
|
return YAML.load_file(fn)
|
462
1052
|
else
|
463
1053
|
return {}
|
@@ -485,6 +1075,156 @@ class Morpheus::Cli::Remote
|
|
485
1075
|
@@appliance_config = new_config
|
486
1076
|
end
|
487
1077
|
|
1078
|
+
# save_remote updates the appliance info
|
1079
|
+
# @param app_name [Symbol] name and key for the appliance
|
1080
|
+
# @param app_map [Hash] appliance configuration data :url, :insecure, :active, :etc
|
1081
|
+
# @return [Hash] updated appliance config data
|
1082
|
+
def save_remote(app_name, app_map)
|
1083
|
+
app_name = app_name.to_sym
|
1084
|
+
# it's probably better to use load_appliance_file() here instead
|
1085
|
+
cur_appliances = self.appliances #.clone
|
1086
|
+
cur_appliances[app_name] = app_map
|
1087
|
+
cur_appliances[app_name] ||= {:status => "unknown", :error => "Bad configuration. Missing url. See 'remote update --url'" }
|
1088
|
+
|
1089
|
+
# this is the new set_active_appliance(), instead just pass :active => true
|
1090
|
+
# remove active flag from others
|
1091
|
+
if app_map[:active]
|
1092
|
+
cur_appliances.each do |k,v|
|
1093
|
+
is_match = (app_name ? (k == app_name) : false)
|
1094
|
+
if is_match
|
1095
|
+
v[:active] = true
|
1096
|
+
else
|
1097
|
+
v.delete(:active)
|
1098
|
+
# v.delete('active')
|
1099
|
+
# v[:active] = false
|
1100
|
+
end
|
1101
|
+
end
|
1102
|
+
end
|
1103
|
+
|
1104
|
+
# persist all appliances
|
1105
|
+
save_appliances(cur_appliances)
|
1106
|
+
|
1107
|
+
return app_map
|
1108
|
+
end
|
1109
|
+
|
1110
|
+
def delete_remote(app_name)
|
1111
|
+
app_name = app_name.to_sym
|
1112
|
+
cur_appliances = self.appliances #.clone
|
1113
|
+
app_map = cur_appliances[app_name]
|
1114
|
+
if !app_map
|
1115
|
+
return nil
|
1116
|
+
end
|
1117
|
+
# remove it from config and delete credentials
|
1118
|
+
cur_appliances.delete(app_name)
|
1119
|
+
::Morpheus::Cli::Remote.save_appliances(cur_appliances)
|
1120
|
+
# this should be a class method too
|
1121
|
+
::Morpheus::Cli::Credentials.new(app_name, nil).clear_saved_credentials(app_name)
|
1122
|
+
# delete from groups too..
|
1123
|
+
::Morpheus::Cli::Groups.clear_active_group(app_name)
|
1124
|
+
# return the deleted value
|
1125
|
+
return app_map
|
1126
|
+
end
|
1127
|
+
|
1128
|
+
# refresh_remote makes an api request to the configured appliance url
|
1129
|
+
# and updates the appliance's build version, status and last_check attributes
|
1130
|
+
def refresh_remote(app_name)
|
1131
|
+
# this might be better off staying in the CliCommands themselves
|
1132
|
+
# todo: public api /api/setup/check should move to /api/version or /api/server-info
|
1133
|
+
app_name = app_name.to_sym
|
1134
|
+
cur_appliances = self.appliances
|
1135
|
+
app_map = cur_appliances[app_name] || {}
|
1136
|
+
app_url = app_map[:host] # || app_map[:url] maybe??
|
1137
|
+
|
1138
|
+
if !app_url
|
1139
|
+
raise "appliance config is missing url!" # should not need this
|
1140
|
+
end
|
1141
|
+
|
1142
|
+
# todo: this insecure flag needs to applied everywhere now tho..
|
1143
|
+
Morpheus::RestClient.enable_ssl_verification = app_map[:insecure].to_s == 'true'
|
1144
|
+
# Morpheus::RestClient.enable_http = app_map[:insecure].to_s == 'true'
|
1145
|
+
setup_interface = Morpheus::SetupInterface.new(app_url)
|
1146
|
+
begin
|
1147
|
+
now = Time.now.to_i
|
1148
|
+
app_map[:last_check] = {}
|
1149
|
+
app_map[:last_check][:success] = false
|
1150
|
+
app_map[:last_check][:timestamp] = Time.now.to_i
|
1151
|
+
# todo: move /api/setup/check to /api/version or /api/server-info
|
1152
|
+
check_json_response = setup_interface.check()
|
1153
|
+
# puts "REMOTE CHECK RESPONSE:"
|
1154
|
+
# puts JSON.pretty_generate(check_json_response), "\n"
|
1155
|
+
app_map[:last_check][:http_status] = 200
|
1156
|
+
app_map[:build_version] = check_json_response['buildVersion'] # || check_json_response['build_version']
|
1157
|
+
#app_map[:last_check][:success] = true
|
1158
|
+
if check_json_response['success'] == true
|
1159
|
+
app_map[:status] = 'ready'
|
1160
|
+
app_map[:last_check][:success] = true
|
1161
|
+
# consider bumping this after every successful api command
|
1162
|
+
app_map[:last_success_at] = Time.now.to_i
|
1163
|
+
app_map.delete(:error)
|
1164
|
+
end
|
1165
|
+
if check_json_response['setupNeeded'] == true
|
1166
|
+
app_map[:setup_needed] = true
|
1167
|
+
app_map[:status] = 'fresh'
|
1168
|
+
else
|
1169
|
+
app_map.delete(:setup_needed)
|
1170
|
+
end
|
1171
|
+
|
1172
|
+
rescue SocketError => err
|
1173
|
+
app_map[:status] = 'unreachable'
|
1174
|
+
app_map[:last_check][:http_status] = nil
|
1175
|
+
app_map[:last_check][:error] = err.message
|
1176
|
+
rescue RestClient::Exceptions::Timeout => err
|
1177
|
+
# print_rest_exception(e, options)
|
1178
|
+
# exit 1
|
1179
|
+
app_map[:status] = 'http-timeout'
|
1180
|
+
app_map[:last_check][:http_status] = nil
|
1181
|
+
rescue Errno::ECONNREFUSED => err
|
1182
|
+
app_map[:status] = 'net-error'
|
1183
|
+
app_map[:last_check][:error] = err.message
|
1184
|
+
rescue OpenSSL::SSL::SSLError => err
|
1185
|
+
app_map[:status] = 'ssl-error'
|
1186
|
+
app_map[:last_check][:error] = err.message
|
1187
|
+
rescue RestClient::Exception => err
|
1188
|
+
app_map[:status] = 'http-error'
|
1189
|
+
app_map[:http_status] = err.response ? err.response.code : nil
|
1190
|
+
app_map[:last_check][:error] = err.message
|
1191
|
+
# fallback to /ping for older appliance versions (pre 2.10.5)
|
1192
|
+
begin
|
1193
|
+
Morpheus::Logging::DarkPrinter.puts "falling back to remote check via /ping ..." if Morpheus::Logging.debug?
|
1194
|
+
setup_interface.ping()
|
1195
|
+
app_map[:last_check][:ping_fallback] = true
|
1196
|
+
app_map[:last_check][:http_status] = 200
|
1197
|
+
app_map[:last_check][:success] = true
|
1198
|
+
app_map[:last_check][:ping_fallback] = true
|
1199
|
+
app_map[:build_version] = "" # unknown until whoami is executed..
|
1200
|
+
app_map[:status] = 'ready'
|
1201
|
+
# consider bumping this after every successful api command
|
1202
|
+
app_map[:last_success_at] = Time.now.to_i
|
1203
|
+
app_map.delete(:error)
|
1204
|
+
rescue => ping_err
|
1205
|
+
Morpheus::Logging::DarkPrinter.puts "/ping failed too: #{ping_err.message} ..." if Morpheus::Logging.debug?
|
1206
|
+
end
|
1207
|
+
rescue => err
|
1208
|
+
# should save before raising atleast..sheesh
|
1209
|
+
raise err
|
1210
|
+
# Morpheus::Cli::ErrorHandler.new.handle_error(e)
|
1211
|
+
app_map[:status] = 'error'
|
1212
|
+
app_map[:last_check][:error] = err.message
|
1213
|
+
end
|
1214
|
+
|
1215
|
+
# if app_map[:status] == 'ready'
|
1216
|
+
# app_map.delete(:error)
|
1217
|
+
# end
|
1218
|
+
|
1219
|
+
# save changes to disk ... and
|
1220
|
+
# ... class variable returned by Remote.appliances is updated in there too...
|
1221
|
+
save_remote(app_name, app_map)
|
1222
|
+
|
1223
|
+
# return the updated data
|
1224
|
+
return app_map
|
1225
|
+
|
1226
|
+
end
|
1227
|
+
|
488
1228
|
end
|
489
1229
|
|
490
1230
|
end
|