morpheus-cli 2.10.3 → 2.11.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/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
|