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.
Files changed (68) hide show
  1. checksums.yaml +4 -4
  2. data/bin/morpheus +5 -96
  3. data/lib/morpheus/api/api_client.rb +23 -1
  4. data/lib/morpheus/api/checks_interface.rb +106 -0
  5. data/lib/morpheus/api/incidents_interface.rb +102 -0
  6. data/lib/morpheus/api/monitoring_apps_interface.rb +47 -0
  7. data/lib/morpheus/api/monitoring_contacts_interface.rb +47 -0
  8. data/lib/morpheus/api/monitoring_groups_interface.rb +47 -0
  9. data/lib/morpheus/api/monitoring_interface.rb +36 -0
  10. data/lib/morpheus/api/option_type_lists_interface.rb +47 -0
  11. data/lib/morpheus/api/option_types_interface.rb +47 -0
  12. data/lib/morpheus/api/roles_interface.rb +0 -1
  13. data/lib/morpheus/api/setup_interface.rb +19 -9
  14. data/lib/morpheus/cli.rb +20 -1
  15. data/lib/morpheus/cli/accounts.rb +8 -3
  16. data/lib/morpheus/cli/app_templates.rb +19 -11
  17. data/lib/morpheus/cli/apps.rb +52 -37
  18. data/lib/morpheus/cli/cli_command.rb +229 -53
  19. data/lib/morpheus/cli/cli_registry.rb +48 -40
  20. data/lib/morpheus/cli/clouds.rb +55 -26
  21. data/lib/morpheus/cli/command_error.rb +12 -0
  22. data/lib/morpheus/cli/credentials.rb +68 -26
  23. data/lib/morpheus/cli/curl_command.rb +98 -0
  24. data/lib/morpheus/cli/dashboard_command.rb +2 -7
  25. data/lib/morpheus/cli/deployments.rb +4 -4
  26. data/lib/morpheus/cli/deploys.rb +1 -2
  27. data/lib/morpheus/cli/dot_file.rb +5 -8
  28. data/lib/morpheus/cli/error_handler.rb +179 -15
  29. data/lib/morpheus/cli/groups.rb +21 -13
  30. data/lib/morpheus/cli/hosts.rb +220 -110
  31. data/lib/morpheus/cli/instance_types.rb +2 -2
  32. data/lib/morpheus/cli/instances.rb +257 -167
  33. data/lib/morpheus/cli/key_pairs.rb +15 -9
  34. data/lib/morpheus/cli/library.rb +673 -27
  35. data/lib/morpheus/cli/license.rb +2 -2
  36. data/lib/morpheus/cli/load_balancers.rb +4 -4
  37. data/lib/morpheus/cli/log_level_command.rb +6 -4
  38. data/lib/morpheus/cli/login.rb +17 -3
  39. data/lib/morpheus/cli/logout.rb +25 -11
  40. data/lib/morpheus/cli/man_command.rb +388 -0
  41. data/lib/morpheus/cli/mixins/accounts_helper.rb +1 -1
  42. data/lib/morpheus/cli/mixins/monitoring_helper.rb +434 -0
  43. data/lib/morpheus/cli/mixins/print_helper.rb +620 -112
  44. data/lib/morpheus/cli/mixins/provisioning_helper.rb +1 -1
  45. data/lib/morpheus/cli/monitoring_apps_command.rb +29 -0
  46. data/lib/morpheus/cli/monitoring_checks_command.rb +427 -0
  47. data/lib/morpheus/cli/monitoring_contacts_command.rb +373 -0
  48. data/lib/morpheus/cli/monitoring_groups_command.rb +29 -0
  49. data/lib/morpheus/cli/monitoring_incidents_command.rb +711 -0
  50. data/lib/morpheus/cli/option_types.rb +10 -1
  51. data/lib/morpheus/cli/recent_activity_command.rb +2 -5
  52. data/lib/morpheus/cli/remote.rb +874 -134
  53. data/lib/morpheus/cli/roles.rb +54 -27
  54. data/lib/morpheus/cli/security_group_rules.rb +2 -2
  55. data/lib/morpheus/cli/security_groups.rb +23 -19
  56. data/lib/morpheus/cli/set_prompt_command.rb +50 -0
  57. data/lib/morpheus/cli/shell.rb +222 -157
  58. data/lib/morpheus/cli/tasks.rb +19 -15
  59. data/lib/morpheus/cli/users.rb +27 -17
  60. data/lib/morpheus/cli/version.rb +1 -1
  61. data/lib/morpheus/cli/virtual_images.rb +28 -13
  62. data/lib/morpheus/cli/whoami.rb +131 -52
  63. data/lib/morpheus/cli/workflows.rb +24 -9
  64. data/lib/morpheus/formatters.rb +195 -3
  65. data/lib/morpheus/logging.rb +86 -0
  66. data/lib/morpheus/terminal.rb +371 -0
  67. data/scripts/generate_morpheus_commands_help.morpheus +60 -0
  68. 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
- select_options = load_source_options(option_type['optionSource'],api_client,api_params)
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
- print "\n" ,cyan, bold, "Dashboard\n","==================", reset, "\n\n"
63
+ print_h1 "Recent Activity"
64
64
  print cyan
65
- print "\n"
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
@@ -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, {:current => :print_current}, :setup
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
- list(args)
22
- else
23
- handle_subcommand(args)
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
- build_common_options(opts, options, [])
32
- opts.footer = "This outputs a list of the remote appliances.\n" +
33
- "It also displays the current active appliance.\n" +
34
- "The shortcut `remote` can be used instead of `remote list`."
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
- @appliances = ::Morpheus::Cli::Remote.appliances
38
- if @appliances == nil || @appliances.empty?
39
- print yellow,"No remote appliances configured, see `remote add`",reset,"\n"
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 @appliances.keys.size == 1
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 active remote appliance, see `remote use`\n", reset
93
+ print "\n# => No current remote appliance, see `remote use`\n", reset
58
94
  end
59
- print "\n" # meh
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
- opts.banner = subcommand_usage("[name] [url]")
68
- opts.on( '--use', '--use', "Make this the current remote appliance" ) do
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 = "This will add a new appliance to your list.\n" +
84
- "If it's first one, it will be made the current active appliance."
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
- puts optparse
89
- exit 1
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
- print red, "The specified appliance url is invalid: '#{args[1]}'", reset, "\n"
96
- puts optparse
97
- exit 1
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
- # maybe a ping here would be cool
100
- @appliances = ::Morpheus::Cli::Remote.appliances
101
- if @appliances.keys.empty?
102
- use_it = true
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
- if @appliances[new_appliance_name] != nil
105
- print red, "Remote appliance already configured with the name '#{args[0]}'", reset, "\n"
106
- return false
107
- else
108
- @appliances[new_appliance_name] = {
109
- host: url,
110
- active: use_it
111
- }
112
- ::Morpheus::Cli::Remote.save_appliances(@appliances)
113
- if use_it
114
- Morpheus::Cli::Remote.set_active_appliance(new_appliance_name)
115
- @appliance_name, @appliance_url = Morpheus::Cli::Remote.active_appliance
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] || options[:no_prompt]
120
- return true
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
- # check to see if this is a fresh appliance.
124
- # GET /api/setup only returns 200 if it can still be initialized, else 400
125
- @setup_interface = Morpheus::SetupInterface.new(@appliance_url)
126
- appliance_status_json = nil
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
- appliance_status_json = @setup_interface.get()
129
- if appliance_status_json['success'] == true
130
- return setup([new_appliance_name])
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
- # should not get here
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
- #print_rest_exception(e, options)
135
- # laff, treating any non - 200 as meaning it is good ...is bad.. could be at the wrong site.. sending credentials..
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
- if use_it
140
- if ::Morpheus::Cli::OptionTypes::confirm("Would you like to login now?", options.merge({default: true}))
141
- return ::Morpheus::Cli::Login.new.handle([new_appliance_name])
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
- return true
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( '-d', '--default', "Make this the default remote appliance" ) do
153
- options[:default] = true
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.empty?
160
- puts optparse
161
- exit 1
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
- if @appliances[appliance_name] == nil
166
- print red, "Remote appliance not found by the name '#{args[0]}'", reset, "\n"
167
- else
168
- unless options[:yes] || ::Morpheus::Cli::OptionTypes::confirm("Are you sure you would like to remove this remote appliance '#{appliance_name}'?", options)
169
- exit 1
170
- end
171
- @appliances.delete(appliance_name)
172
- ::Morpheus::Cli::Remote.save_appliances(@appliances)
173
- # todo: also delete credentials and groups[appliance_name]
174
- ::Morpheus::Cli::Groups.clear_active_group(appliance_name) # rescue nil
175
- # this should be a class method too
176
- #::Morpheus::Cli::Credentials.clear_saved_credentials(appliance_name)
177
- ::Morpheus::Cli::Credentials.new(appliance_name, nil).clear_saved_credentials(appliance_name) # rescue nil
178
- #list([])
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 = "This sets the current active appliance.\n" +
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
- puts optparse
194
- exit 1
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
- new_appliance_name = args[0].to_sym
197
- @appliances = ::Morpheus::Cli::Remote.appliances
198
- if @appliance_name && @appliance_name.to_s == new_appliance_name.to_s
199
- print reset,"Already using the appliance '#{args[0]}'","\n",reset
200
- else
201
- if @appliances[new_appliance_name] == nil
202
- print red, "Remote appliance not found by the name '#{args[0]}'", reset, "\n"
203
- return false
204
- else
205
- Morpheus::Cli::Remote.set_active_appliance(new_appliance_name)
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 active appliance.\n" +
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
- Morpheus::Cli::Remote.clear_active_appliance()
226
- @appliance_name, @appliance_url = nil, nil
227
- return true
655
+ print cyan, @appliance_name,"\n",reset
228
656
  else
229
- puts "You are not using any appliance"
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, [:json])
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
- print "\n" ,cyan, bold, "Morpheus Appliance Setup", "\n", "==================", reset, "\n\n"
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
- print "\n" ,cyan, bold, "Create Master account", "\n", "==================", reset, "\n\n"
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
- print "\n" ,cyan, bold, "Create Master User", "\n", "==================", reset, "\n\n"
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
- print "\n" ,cyan, bold, "Initial Setup", "\n", "==================", reset, "\n\n"
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
- def set_active_appliance(name)
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 = (name ? (k == name.to_sym) : false)
1025
+ is_match = (app_name ? (k == app_name) : false)
440
1026
  if is_match
441
1027
  v[:active] = true
442
1028
  else
443
- v[:active] = false
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[:active] = false
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
- print "#{dark} #=> loading appliances file #{fn}#{reset}\n" if Morpheus::Logging.debug?
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