manageiq-appliance_console 5.5.0 → 7.0.1

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 (34) hide show
  1. checksums.yaml +4 -4
  2. data/.codeclimate.yml +24 -25
  3. data/.rspec_ci +2 -0
  4. data/.rubocop.yml +3 -3
  5. data/.rubocop_cc.yml +3 -4
  6. data/.rubocop_local.yml +1 -1
  7. data/.travis.yml +4 -3
  8. data/Gemfile +1 -3
  9. data/README.md +1 -2
  10. data/Rakefile +20 -1
  11. data/bin/appliance_console +30 -6
  12. data/lib/manageiq/appliance_console/certificate_authority.rb +1 -1
  13. data/lib/manageiq/appliance_console/cli.rb +166 -70
  14. data/lib/manageiq/appliance_console/database_admin.rb +35 -206
  15. data/lib/manageiq/appliance_console/database_configuration.rb +10 -2
  16. data/lib/manageiq/appliance_console/database_replication.rb +1 -1
  17. data/lib/manageiq/appliance_console/database_replication_standby.rb +1 -1
  18. data/lib/manageiq/appliance_console/external_auth_options.rb +3 -13
  19. data/lib/manageiq/appliance_console/internal_database_configuration.rb +4 -12
  20. data/lib/manageiq/appliance_console/key_configuration.rb +8 -1
  21. data/lib/manageiq/appliance_console/logfile_configuration.rb +2 -2
  22. data/lib/manageiq/appliance_console/manageiq_user_mixin.rb +15 -0
  23. data/lib/manageiq/appliance_console/message_configuration.rb +205 -0
  24. data/lib/manageiq/appliance_console/message_configuration_client.rb +98 -0
  25. data/lib/manageiq/appliance_console/message_configuration_server.rb +321 -0
  26. data/lib/manageiq/appliance_console/oidc_authentication.rb +27 -1
  27. data/lib/manageiq/appliance_console/postgres_admin.rb +412 -0
  28. data/lib/manageiq/appliance_console/utilities.rb +61 -2
  29. data/lib/manageiq/appliance_console/version.rb +1 -1
  30. data/lib/manageiq-appliance_console.rb +2 -6
  31. data/locales/appliance/en.yml +0 -16
  32. data/manageiq-appliance_console.gemspec +4 -3
  33. metadata +54 -24
  34. data/lib/manageiq/appliance_console/messaging_configuration.rb +0 -92
@@ -23,22 +23,17 @@ module ManageIQ
23
23
 
24
24
  WARN
25
25
 
26
- attr_accessor :uri
27
- attr_reader :action, :backup_type, :task, :task_params, :delete_agree, :filename
26
+ attr_reader :action, :backup_type, :database_opts, :delete_agree, :filename
28
27
 
29
28
  def initialize(action = :restore, input = $stdin, output = $stdout)
30
29
  super(input, output)
31
30
 
32
- @action = action
33
- @task_params = []
31
+ @action = action
32
+ @database_opts = {:dbname => DatabaseConfiguration.database_name}
34
33
  end
35
34
 
36
- def local_backup?
37
- backup_type == "local".freeze
38
- end
39
-
40
- def object_store_backup?
41
- backup_type == "s3".freeze || backup_type == "swift".freeze
35
+ def uri
36
+ @database_opts[:local_file]
42
37
  end
43
38
 
44
39
  def ask_questions
@@ -51,7 +46,6 @@ module ManageIQ
51
46
  say(DB_DUMP_WARNING) if action == :dump
52
47
  ask_file_location
53
48
  ask_for_tables_to_exclude_in_dump
54
- ask_to_split_up_output
55
49
  end
56
50
 
57
51
  def activate
@@ -63,144 +57,11 @@ module ManageIQ
63
57
  end
64
58
 
65
59
  def ask_file_location
66
- @backup_type = ask_with_menu(*file_menu_args) do |menu|
67
- menu.choice(CANCEL) { |_| raise MiqSignalError }
68
- end
69
- if URI(backup_type).scheme
70
- ask_custom_file_options(backup_type)
71
- else
72
- # calling methods like ask_ftp_file_options and ask_s3_file_options
73
- send("ask_#{backup_type}_file_options")
74
- end
75
- end
76
-
77
- def ask_local_file_options
78
- @uri = just_ask(*filename_prompt_args)
79
- @task = "evm:db:#{action}:local"
80
- @task_params = ["--", {:local_file => uri}]
81
- end
82
-
83
- def ask_nfs_file_options
84
- @filename = just_ask(*filename_prompt_args) unless action == :restore
85
- @uri = ask_for_uri(*remote_file_prompt_args_for("nfs"))
86
- @task = "evm:db:#{action}:remote"
87
-
88
- params = {:uri => uri}
89
- params[:remote_file_name] = filename if filename
90
-
91
- @task_params = ["--", params]
92
- end
93
-
94
- def ask_smb_file_options
95
- @filename = just_ask(*filename_prompt_args) unless action == :restore
96
- @uri = ask_for_uri(*remote_file_prompt_args_for("smb"))
97
- user = just_ask(USER_PROMPT)
98
- pass = ask_for_password("password for #{user}")
99
-
100
- params = {
101
- :uri => uri,
102
- :uri_username => user,
103
- :uri_password => pass
104
- }
105
- params[:remote_file_name] = filename if filename
106
-
107
- @task = "evm:db:#{action}:remote"
108
- @task_params = ["--", params]
109
- end
110
-
111
- def ask_s3_file_options
112
- access_key_prompt = <<-PROMPT.strip_heredoc.chomp
113
- Access Key ID with access to this file.
114
- Example: 'amazon_aws_user'
115
- PROMPT
116
-
117
- @filename = just_ask(*filename_prompt_args) unless action == :restore
118
- @uri = ask_for_uri(*remote_file_prompt_args_for("s3"), :optional_path => true)
119
- region = just_ask("Amazon Region for database file", "us-east-1")
120
- user = just_ask(access_key_prompt)
121
- pass = ask_for_password("Secret Access Key for #{user}")
122
-
123
- params = {
124
- :uri => uri,
125
- :uri_username => user,
126
- :uri_password => pass,
127
- :aws_region => region
128
- }
129
- params[:remote_file_name] = filename if filename
130
-
131
- @task = "evm:db:#{action}:remote"
132
- @task_params = ["--", params]
133
- end
134
-
135
- def ask_ftp_file_options
136
- @filename = just_ask(*filename_prompt_args) unless action == :restore
137
- @uri = ask_for_uri(*remote_file_prompt_args_for("ftp"), :optional_path => true)
138
- user = just_ask(USER_PROMPT)
139
- pass = ask_for_password("password for #{user}")
140
-
141
- params = { :uri => uri }
142
- params[:uri_username] = user if user.present?
143
- params[:uri_password] = pass if pass.present?
144
- params[:remote_file_name] = filename if filename
145
-
146
- @task = "evm:db:#{action}:remote"
147
- @task_params = ["--", params]
148
- end
149
-
150
- def ask_custom_file_options(server_uri)
151
- hostname = URI(server_uri).host
152
- @filename = ask_custom_file_prompt(hostname)
153
- @uri = server_uri
154
-
155
- params = {:uri => uri, :remote_file_name => filename}
156
-
157
- if (custom_params = custom_endpoint_config_for(hostname))
158
- params.merge!(custom_params[:rake_options]) if custom_params[:rake_options]
159
- end
160
-
161
- @task = "evm:db:#{action}:remote"
162
- @task_params = ["--", params]
163
- end
164
-
165
- def ask_swift_file_options
166
- require 'uri'
167
- swift_user_prompt = <<-PROMPT.strip_heredoc.chomp
168
- User Name with access to this file.
169
- Example: 'openstack_user'
170
- PROMPT
171
-
172
- @filename = just_ask(*filename_prompt_args) { |q| q.readline = false } unless action == :restore
173
- @uri = URI(ask_for_uri(*remote_file_prompt_args_for("swift")) { |q| q.readline = false })
174
- @task = "evm:db:#{action}:remote"
175
- user = just_ask(swift_user_prompt) { |q| q.readline = false }
176
- pass = ask_for_password("password for #{user}") { |q| q.readline = false }
177
- @uri.query = swift_query_elements.join('&').presence
178
-
179
- params = {
180
- :uri => @uri.to_s,
181
- :uri_username => user,
182
- :uri_password => pass
183
- }
184
- params[:remote_file_name] = filename if filename
185
- @task = "evm:db:#{action}:remote"
186
- @task_params = ["--", params]
187
- end
188
-
189
- def swift_query_elements
190
- region = just_ask("OpenStack Swift Region") { |q| q.readline = false }
191
- @uri.port = just_ask("OpenStack Swift Port", "5000") { |q| q.readline = false }
192
- security_protocol = ask_with_menu(*security_protocol_menu_args)
193
- api_version = ask_with_menu(*api_version_menu_args) { |q| q.readline = false }
194
- domain_ident = just_ask("OpenStack V3 Domain Identifier") { |q| q.readline = false } if api_version == "v3"
195
- query_elements = []
196
- query_elements << "region=#{region}" if region.present?
197
- query_elements << "api_version=#{api_version}" if api_version.present?
198
- query_elements << "domain_id=#{domain_ident}" if domain_ident.present?
199
- query_elements << "security_protocol=#{security_protocol}" if security_protocol.present?
60
+ @database_opts[:local_file] = just_ask(*filename_prompt_args)
200
61
  end
201
62
 
202
63
  def ask_to_delete_backup_after_restore
203
- if action == :restore && local_backup?
64
+ if action == :restore
204
65
  say("The local database restore file is located at: '#{uri}'.\n")
205
66
  @delete_agree = agree("Should this file be deleted after completing the restore? (Y/N): ")
206
67
  end
@@ -222,20 +83,14 @@ module ManageIQ
222
83
  255,
223
84
  Float::INFINITY)
224
85
 
225
- @task_params.last[:"exclude-table-data"] = table_excludes
226
- end || true
227
- end
228
-
229
- def ask_to_split_up_output
230
- if action == :dump && should_split_output?
231
- @task_params.last[:byte_count] = ask_for_string("byte size to split by", "500M")
86
+ @database_opts[:exclude_table_data] = table_excludes
232
87
  end || true
233
88
  end
234
89
 
235
90
  def confirm_and_execute
236
91
  if allowed_to_execute?
237
92
  processing_message
238
- run_rake
93
+ run_action
239
94
  end
240
95
  press_any_key
241
96
  end
@@ -259,58 +114,18 @@ module ManageIQ
259
114
  end
260
115
  end
261
116
 
262
- def api_version_menu_args
263
- [
264
- "OpenStack API Version",
265
- [["Keystone v2".freeze, "v2".freeze], ["Keystone v3".freeze, "v3".freeze], ["None".freeze, nil]].freeze,
266
- ["Keystone v2".freeze, "v2".freeze],
267
- nil
268
- ]
269
- end
270
-
271
- def file_menu_args
272
- [
273
- action == :restore ? "Restore Database File Source" : "#{action.capitalize} Output File Destination",
274
- file_options,
275
- "local",
276
- nil
277
- ]
278
- end
279
-
280
- def security_protocol_menu_args
281
- [
282
- "OpenStack Security Protocol",
283
- [["SSL without validation".freeze, "ssl".freeze], ["SSL".freeze, "ssl-with-validation".freeze], ["Non-SSL".freeze, "non-ssl".freeze], ["None".freeze, nil]].freeze,
284
- ["Non-SSL".freeze, "non-ssl".freeze],
285
- nil
286
- ]
287
- end
288
-
289
117
  def setting_header
290
118
  say("#{I18n.t("advanced_settings.db#{action}")}\n\n")
291
119
  end
292
120
 
293
121
  private
294
122
 
295
- def ask_custom_file_prompt(hostname)
296
- prompts = custom_endpoint_config_for(hostname)
297
- prompt_text = prompts && prompts[:filename_text] || "Target filename for backup".freeze
298
- prompt_regex = prompts && prompts[:filename_validator]
299
- validator = prompt_regex ? ->(x) { x.to_s =~ /#{prompt_regex}/ } : ->(x) { x.to_s.present? }
300
- just_ask(prompt_text, nil, validator)
301
- end
302
-
303
123
  def skip_file_location?(hostname)
304
124
  config = custom_endpoint_config_for(hostname)
305
125
  return false unless config && config[:enabled_for].present?
306
126
  !Array(config[:enabled_for]).include?(action.to_s)
307
127
  end
308
128
 
309
- def custom_endpoint_config_for(hostname)
310
- # hostname has a period in it, so we need to look it up by [] instead of the traditional i18n method
311
- I18n.t("database_admin.prompts", :default => {})[hostname.to_sym]
312
- end
313
-
314
129
  def should_exclude_tables?
315
130
  ask_yn?("Would you like to exclude tables in the dump") do |q|
316
131
  q.readline = true
@@ -327,16 +142,12 @@ module ManageIQ
327
142
  return restore_prompt_args if action == :restore
328
143
  default = action == :dump ? DB_DEFAULT_DUMP_FILE : DB_RESTORE_FILE
329
144
  prompt = "location to save the #{action} file to"
330
- if object_store_backup?
331
- prompt = "name for the remote #{action} file"
332
- default = File.basename(default)
333
- end
334
145
  [prompt, default, nil, "file that exists"]
335
146
  end
336
147
 
337
148
  def restore_prompt_args
338
149
  default = DB_RESTORE_FILE
339
- validator = LOCAL_FILE_VALIDATOR if local_backup?
150
+ validator = LOCAL_FILE_VALIDATOR
340
151
  prompt = "location of the local restore file"
341
152
  [prompt, default, validator, "file that exists"]
342
153
  end
@@ -347,12 +158,12 @@ module ManageIQ
347
158
  else
348
159
  "location to save the remote #{action} file to"
349
160
  end
350
- prompt += "\nExample: #{sample_url(remote_type)}"
161
+ prompt += "\nExample: #{sample_url}"
351
162
  [prompt, remote_type]
352
163
  end
353
164
 
354
- def sample_url(scheme)
355
- I18n.t("database_admin.sample_url.#{scheme}")
165
+ def sample_url
166
+ I18n.t("database_admin.sample_url.nfs")
356
167
  end
357
168
 
358
169
  def processing_message
@@ -364,15 +175,33 @@ module ManageIQ
364
175
  say(msg)
365
176
  end
366
177
 
367
- def run_rake
368
- rake_success = ManageIQ::ApplianceConsole::Utilities.rake(task, task_params)
369
- if rake_success && action == :restore && delete_agree
178
+ def run_action
179
+ success = send(action)
180
+ if success && action == :restore && delete_agree
370
181
  say("\nRemoving the database restore file #{uri}...")
371
182
  File.delete(uri)
372
- elsif !rake_success
183
+ elsif !success
373
184
  say("\nDatabase #{action} failed. Check the logs for more information")
374
185
  end
375
186
  end
187
+
188
+ def backup
189
+ result = PostgresAdmin.backup(database_opts)
190
+ ManageIQ::ApplianceConsole.logger.info("[#{@database_opts[:dbname]}] database has been backed up to file: [#{uri}]")
191
+ result
192
+ end
193
+
194
+ def dump
195
+ result = PostgresAdmin.backup_pg_dump(database_opts)
196
+ ManageIQ::ApplianceConsole.logger.info("[#{@database_opts[:dbname]}] database has been dumped up to file: [#{uri}]")
197
+ result
198
+ end
199
+
200
+ def restore
201
+ result = PostgresAdmin.restore(database_opts.merge(:backup_type => backup_type))
202
+ ManageIQ::ApplianceConsole.logger.info("[#{@database_opts[:dbname]}] database has been restored from file: [#{uri}]")
203
+ result
204
+ end
376
205
  end
377
206
  end
378
207
  end
@@ -5,10 +5,15 @@ require 'manageiq-password'
5
5
  require 'pathname'
6
6
  require 'fileutils'
7
7
 
8
+ require_relative './manageiq_user_mixin'
9
+
8
10
  module ManageIQ
9
11
  module ApplianceConsole
10
12
  class DatabaseConfiguration
11
- attr_accessor :adapter, :host, :username, :database, :password, :port, :region
13
+ include ManageIQ::ApplianceConsole::ManageiqUserMixin
14
+
15
+ attr_accessor :adapter, :host, :username, :database, :port, :region
16
+ attr_reader :password
12
17
 
13
18
  class ModelWithNoBackingTable < ActiveRecord::Base
14
19
  end
@@ -274,7 +279,10 @@ FRIENDLY
274
279
 
275
280
  def do_save(settings)
276
281
  require 'yaml'
277
- File.write(DB_YML, YAML.dump(settings))
282
+ File.open(DB_YML, "w") do |f|
283
+ f.write(YAML.dump(settings))
284
+ f.chown(manageiq_uid, manageiq_gid)
285
+ end
278
286
  end
279
287
 
280
288
  def initialize_from_hash(hash)
@@ -1,6 +1,6 @@
1
1
  require 'pg'
2
2
  require 'English'
3
- require 'util/postgres_admin'
3
+ require 'manageiq/appliance_console/postgres_admin'
4
4
 
5
5
  module ManageIQ
6
6
  module ApplianceConsole
@@ -1,4 +1,4 @@
1
- require 'util/postgres_admin'
1
+ require 'manageiq/appliance_console/postgres_admin'
2
2
  require 'fileutils'
3
3
  require 'linux_admin'
4
4
 
@@ -82,8 +82,7 @@ module ApplianceConsole
82
82
  say("\nUpdating external authentication options on appliance ...")
83
83
  params = update_hash.collect { |key, value| "#{key}=#{value}" }
84
84
  params = configure_provider_type!(params)
85
- result = ManageIQ::ApplianceConsole::Utilities.rake_run("evm:settings:set", params)
86
- raise parse_errors(result).join(', ') if result.failure?
85
+ ManageIQ::ApplianceConsole::Utilities.rake_run!("evm:settings:set", params)
87
86
  end
88
87
  end
89
88
 
@@ -152,17 +151,8 @@ module ApplianceConsole
152
151
 
153
152
  def load_current
154
153
  say("\nFetching external authentication options from appliance ...")
155
- result = ManageIQ::ApplianceConsole::Utilities.rake_run("evm:settings:get", EXT_AUTH_OPTIONS.keys)
156
-
157
- if result.success?
158
- return parse_response(result)
159
- else
160
- raise parse_errors(result).join(', ')
161
- end
162
- end
163
-
164
- def parse_errors(result)
165
- result.error.split("\n").collect { |line| line if line =~ /^error: /i }.compact
154
+ result = ManageIQ::ApplianceConsole::Utilities.rake_run!("evm:settings:get", EXT_AUTH_OPTIONS.keys)
155
+ parse_response(result)
166
156
  end
167
157
 
168
158
  def normalize_key(key)
@@ -1,6 +1,5 @@
1
1
  require "pathname"
2
- require "util/postgres_admin"
3
- require "pg"
2
+ require "manageiq/appliance_console/postgres_admin"
4
3
  require "linux_admin"
5
4
 
6
5
  module ManageIQ
@@ -149,14 +148,14 @@ module ApplianceConsole
149
148
  end
150
149
 
151
150
  def create_postgres_root_user
152
- with_pg_connection do |conn|
151
+ PostgresAdmin.with_pg_connection do |conn|
153
152
  esc_pass = conn.escape_string(password)
154
153
  conn.exec("CREATE ROLE #{username} WITH LOGIN CREATEDB SUPERUSER PASSWORD '#{esc_pass}'")
155
154
  end
156
155
  end
157
156
 
158
157
  def create_postgres_database
159
- with_pg_connection do |conn|
158
+ PostgresAdmin.with_pg_connection do |conn|
160
159
  conn.exec("CREATE DATABASE #{database} OWNER #{username} ENCODING 'utf8'")
161
160
  end
162
161
  end
@@ -165,16 +164,9 @@ module ApplianceConsole
165
164
  AwesomeSpawn.run!("/sbin/restorecon -R -v #{mount_point}")
166
165
  end
167
166
 
168
- def with_pg_connection
169
- conn = PG.connect(:user => "postgres", :dbname => "postgres")
170
- yield conn
171
- ensure
172
- conn.close
173
- end
174
-
175
167
  def apply_initial_configuration
176
168
  shared_buffers = run_as_evm_server ? SHARED_DB_SHARED_BUFFERS : DEDICATED_DB_SHARED_BUFFERS
177
- with_pg_connection { |conn| conn.exec("ALTER SYSTEM SET shared_buffers TO #{shared_buffers}") }
169
+ PostgresAdmin.with_pg_connection { |conn| conn.exec("ALTER SYSTEM SET shared_buffers TO #{shared_buffers}") }
178
170
 
179
171
  restart_postgres
180
172
  end