morpheus-cli 4.2.8 → 4.2.10

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