morpheus-cli 4.2.8 → 4.2.10

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
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()