manageiq-appliance_console 5.5.0 → 7.0.1
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/.codeclimate.yml +24 -25
- data/.rspec_ci +2 -0
- data/.rubocop.yml +3 -3
- data/.rubocop_cc.yml +3 -4
- data/.rubocop_local.yml +1 -1
- data/.travis.yml +4 -3
- data/Gemfile +1 -3
- data/README.md +1 -2
- data/Rakefile +20 -1
- data/bin/appliance_console +30 -6
- data/lib/manageiq/appliance_console/certificate_authority.rb +1 -1
- data/lib/manageiq/appliance_console/cli.rb +166 -70
- data/lib/manageiq/appliance_console/database_admin.rb +35 -206
- data/lib/manageiq/appliance_console/database_configuration.rb +10 -2
- data/lib/manageiq/appliance_console/database_replication.rb +1 -1
- data/lib/manageiq/appliance_console/database_replication_standby.rb +1 -1
- data/lib/manageiq/appliance_console/external_auth_options.rb +3 -13
- data/lib/manageiq/appliance_console/internal_database_configuration.rb +4 -12
- data/lib/manageiq/appliance_console/key_configuration.rb +8 -1
- data/lib/manageiq/appliance_console/logfile_configuration.rb +2 -2
- data/lib/manageiq/appliance_console/manageiq_user_mixin.rb +15 -0
- data/lib/manageiq/appliance_console/message_configuration.rb +205 -0
- data/lib/manageiq/appliance_console/message_configuration_client.rb +98 -0
- data/lib/manageiq/appliance_console/message_configuration_server.rb +321 -0
- data/lib/manageiq/appliance_console/oidc_authentication.rb +27 -1
- data/lib/manageiq/appliance_console/postgres_admin.rb +412 -0
- data/lib/manageiq/appliance_console/utilities.rb +61 -2
- data/lib/manageiq/appliance_console/version.rb +1 -1
- data/lib/manageiq-appliance_console.rb +2 -6
- data/locales/appliance/en.yml +0 -16
- data/manageiq-appliance_console.gemspec +4 -3
- metadata +54 -24
- data/lib/manageiq/appliance_console/messaging_configuration.rb +0 -92
@@ -23,22 +23,17 @@ module ManageIQ
|
|
23
23
|
|
24
24
|
WARN
|
25
25
|
|
26
|
-
|
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
|
33
|
-
@
|
31
|
+
@action = action
|
32
|
+
@database_opts = {:dbname => DatabaseConfiguration.database_name}
|
34
33
|
end
|
35
34
|
|
36
|
-
def
|
37
|
-
|
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
|
-
@
|
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
|
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
|
-
@
|
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
|
-
|
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
|
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
|
161
|
+
prompt += "\nExample: #{sample_url}"
|
351
162
|
[prompt, remote_type]
|
352
163
|
end
|
353
164
|
|
354
|
-
def sample_url
|
355
|
-
I18n.t("database_admin.sample_url
|
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
|
368
|
-
|
369
|
-
if
|
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 !
|
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
|
-
|
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.
|
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)
|
@@ -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
|
-
|
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 "
|
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
|