manageiq-appliance_console 3.2.0 → 3.3.0

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 4c51a1645cacd16b9f78f45db22f3a1ae65976639e4cf4b350fac41e3cb8e736
4
- data.tar.gz: d8307195379d0abd4d7379aa02ec3d0a9a779845f801b537b62861c63153aed3
3
+ metadata.gz: dab9032437ce55e00eacbd51c230873b67c7c6ebbce41637ecdf167c687f1fb9
4
+ data.tar.gz: 7f3414f814c1afe4764c5a042c0ca4d5243efdaba391039ed34d0838401d57f9
5
5
  SHA512:
6
- metadata.gz: 703481bd2a07952b373444c4e1b2b7b65978341e2d6a9007ecbe66481a98b1b49122593149ce8b7b4109b7f148482e6281f090bae405112debd4c1a372bab4b2
7
- data.tar.gz: 4a9b89883776c42b38861a371d657ffc4be786e9f109bc6a39c9c68b3df88ae4ccf701d4c0720b9dee95d28deada418ce8c2c21a25561760e6bbd3bd985791f5
6
+ metadata.gz: 4b10da6f428508db44d798a4486ffd9b0d19aad3aaf0141dbfd6d5bdb453bc436c2133962446535240e633e70217ec7918893f956c90ab587bafe468e859628d
7
+ data.tar.gz: 8657df612109649196c051e5054e30b9b66ecb599e56170b3746aa302bd7ec98b0b4776541b05a1b7296454feb444a12bc8c078d2b9c2a8ebe2dcab29f5dca77
@@ -1,16 +1,11 @@
1
1
  require 'manageiq/appliance_console/errors'
2
+ require 'uri'
2
3
 
3
4
  module ManageIQ
4
5
  module ApplianceConsole
5
6
  class DatabaseAdmin < HighLine
6
7
  include ManageIQ::ApplianceConsole::Prompts
7
8
 
8
- LOCAL_FILE = "Local file".freeze
9
- NFS_FILE = "Network File System (NFS)".freeze
10
- SMB_FILE = "Samba (SMB)".freeze
11
- S3_FILE = "Amazon S3 (S3)".freeze
12
- FILE_OPTIONS = [LOCAL_FILE, NFS_FILE, SMB_FILE, S3_FILE, CANCEL].freeze
13
-
14
9
  DB_RESTORE_FILE = "/tmp/evm_db.backup".freeze
15
10
  DB_DEFAULT_DUMP_FILE = "/tmp/evm_db.dump".freeze
16
11
  LOCAL_FILE_VALIDATOR = ->(a) { File.exist?(a) }.freeze
@@ -28,7 +23,8 @@ module ManageIQ
28
23
 
29
24
  WARN
30
25
 
31
- attr_reader :action, :backup_type, :task, :task_params, :delete_agree, :uri, :filename
26
+ attr_accessor :uri
27
+ attr_reader :action, :backup_type, :task, :task_params, :delete_agree, :filename
32
28
 
33
29
  def initialize(action = :restore, input = $stdin, output = $stdout)
34
30
  super(input, output)
@@ -37,11 +33,20 @@ module ManageIQ
37
33
  @task_params = []
38
34
  end
39
35
 
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
42
+ end
43
+
40
44
  def ask_questions
41
45
  setting_header
42
46
  say(DB_DUMP_WARNING) if action == :dump
43
47
  ask_file_location
44
48
  ask_for_tables_to_exclude_in_dump
49
+ ask_to_split_up_output
45
50
  end
46
51
 
47
52
  def activate
@@ -53,12 +58,14 @@ module ManageIQ
53
58
  end
54
59
 
55
60
  def ask_file_location
56
- case @backup_type = ask_with_menu(*file_menu_args)
57
- when LOCAL_FILE then ask_local_file_options
58
- when NFS_FILE then ask_nfs_file_options
59
- when SMB_FILE then ask_smb_file_options
60
- when S3_FILE then ask_s3_file_options
61
- when CANCEL then raise MiqSignalError
61
+ @backup_type = ask_with_menu(*file_menu_args) do |menu|
62
+ menu.choice(CANCEL) { |_| raise MiqSignalError }
63
+ end
64
+ if URI(backup_type).scheme
65
+ ask_custom_file_options(backup_type)
66
+ else
67
+ # calling methods like ask_ftp_file_options and ask_s3_file_options
68
+ send("ask_#{backup_type}_file_options")
62
69
  end
63
70
  end
64
71
 
@@ -120,8 +127,75 @@ module ManageIQ
120
127
  @task_params = ["--", params]
121
128
  end
122
129
 
130
+ def ask_ftp_file_options
131
+ @filename = just_ask(*filename_prompt_args) unless action == :restore
132
+ @uri = ask_for_uri(*remote_file_prompt_args_for("ftp"), :optional_path => true)
133
+ user = just_ask(USER_PROMPT)
134
+ pass = ask_for_password("password for #{user}")
135
+
136
+ params = { :uri => uri }
137
+ params[:uri_username] = user if user.present?
138
+ params[:uri_password] = pass if pass.present?
139
+ params[:remote_file_name] = filename if filename
140
+
141
+ @task = "evm:db:#{action}:remote"
142
+ @task_params = ["--", params]
143
+ end
144
+
145
+ def ask_custom_file_options(server_uri)
146
+ hostname = URI(server_uri).host
147
+ @filename = ask_custom_file_prompt(hostname)
148
+ @uri = server_uri
149
+
150
+ params = {:uri => uri, :remote_file_name => filename}
151
+
152
+ if (custom_params = custom_endpoint_config_for(hostname))
153
+ params.merge!(custom_params[:rake_options]) if custom_params[:rake_options]
154
+ end
155
+
156
+ @task = "evm:db:#{action}:remote"
157
+ @task_params = ["--", params]
158
+ end
159
+
160
+ def ask_swift_file_options
161
+ require 'uri'
162
+ swift_user_prompt = <<-PROMPT.strip_heredoc.chomp
163
+ User Name with access to this file.
164
+ Example: 'openstack_user'
165
+ PROMPT
166
+
167
+ @filename = just_ask(*filename_prompt_args) { |q| q.readline = false } unless action == :restore
168
+ @uri = URI(ask_for_uri(*remote_file_prompt_args_for("swift")) { |q| q.readline = false })
169
+ @task = "evm:db:#{action}:remote"
170
+ user = just_ask(swift_user_prompt) { |q| q.readline = false }
171
+ pass = ask_for_password("password for #{user}") { |q| q.readline = false }
172
+ @uri.query = swift_query_elements.join('&').presence
173
+
174
+ params = {
175
+ :uri => @uri.to_s,
176
+ :uri_username => user,
177
+ :uri_password => pass
178
+ }
179
+ params[:remote_file_name] = filename if filename
180
+ @task = "evm:db:#{action}:remote"
181
+ @task_params = ["--", params]
182
+ end
183
+
184
+ def swift_query_elements
185
+ region = just_ask("OpenStack Swift Region") { |q| q.readline = false }
186
+ @uri.port = just_ask("OpenStack Swift Port", "5000") { |q| q.readline = false }
187
+ security_protocol = ask_with_menu(*security_protocol_menu_args)
188
+ api_version = ask_with_menu(*api_version_menu_args) { |q| q.readline = false }
189
+ domain_ident = just_ask("OpenStack V3 Domain Identifier") { |q| q.readline = false } if api_version == "v3"
190
+ query_elements = []
191
+ query_elements << "region=#{region}" if region.present?
192
+ query_elements << "api_version=#{api_version}" if api_version.present?
193
+ query_elements << "domain_id=#{domain_ident}" if domain_ident.present?
194
+ query_elements << "security_protocol=#{security_protocol}" if security_protocol.present?
195
+ end
196
+
123
197
  def ask_to_delete_backup_after_restore
124
- if action == :restore && backup_type == LOCAL_FILE
198
+ if action == :restore && local_backup?
125
199
  say("The local database restore file is located at: '#{uri}'.\n")
126
200
  @delete_agree = agree("Should this file be deleted after completing the restore? (Y/N): ")
127
201
  end
@@ -147,6 +221,12 @@ module ManageIQ
147
221
  end || true
148
222
  end
149
223
 
224
+ def ask_to_split_up_output
225
+ if action == :dump && should_split_output?
226
+ @task_params.last[:byte_count] = ask_for_string("byte size to split by", "500M")
227
+ end || true
228
+ end
229
+
150
230
  def confirm_and_execute
151
231
  if allowed_to_execute?
152
232
  processing_message
@@ -157,15 +237,46 @@ module ManageIQ
157
237
 
158
238
  def allowed_to_execute?
159
239
  return true unless action == :restore
240
+
160
241
  say("\nNote: A database restore cannot be undone. The restore will use the file: #{uri}.\n")
161
242
  agree("Are you sure you would like to restore the database? (Y/N): ")
162
243
  end
163
244
 
245
+ def file_options
246
+ @file_options ||= I18n.t("database_admin.menu_order").each_with_object({}) do |file_option, h|
247
+ # special anonymous ftp sites are defined by uri
248
+ uri = URI(file_option)
249
+ if uri.scheme
250
+ h["#{uri.scheme} to #{uri.host}"] = file_option unless skip_file_location?(uri.host)
251
+ else
252
+ h[I18n.t("database_admin.#{file_option}")] = file_option
253
+ end
254
+ end
255
+ end
256
+
257
+ def api_version_menu_args
258
+ [
259
+ "OpenStack API Version",
260
+ [["Keystone v2".freeze, "v2".freeze], ["Keystone v3".freeze, "v3".freeze], ["None".freeze, nil]].freeze,
261
+ ["Keystone v2".freeze, "v2".freeze],
262
+ nil
263
+ ]
264
+ end
265
+
164
266
  def file_menu_args
165
267
  [
166
268
  action == :restore ? "Restore Database File" : "#{action.capitalize} Output File Name",
167
- FILE_OPTIONS,
168
- LOCAL_FILE,
269
+ file_options,
270
+ "local",
271
+ nil
272
+ ]
273
+ end
274
+
275
+ def security_protocol_menu_args
276
+ [
277
+ "OpenStack Security Protocol",
278
+ [["SSL without validation".freeze, "ssl".freeze], ["SSL".freeze, "ssl-with-validation".freeze], ["Non-SSL".freeze, "non-ssl".freeze], ["None".freeze, nil]].freeze,
279
+ ["Non-SSL".freeze, "non-ssl".freeze],
169
280
  nil
170
281
  ]
171
282
  end
@@ -176,24 +287,53 @@ module ManageIQ
176
287
 
177
288
  private
178
289
 
290
+ def ask_custom_file_prompt(hostname)
291
+ prompts = custom_endpoint_config_for(hostname)
292
+ prompt_text = prompts && prompts[:filename_text] || "Target filename for backup".freeze
293
+ prompt_regex = prompts && prompts[:filename_validator]
294
+ validator = prompt_regex ? ->(x) { x.to_s =~ /#{prompt_regex}/ } : ->(x) { x.to_s.present? }
295
+ just_ask(prompt_text, nil, validator)
296
+ end
297
+
298
+ def skip_file_location?(hostname)
299
+ config = custom_endpoint_config_for(hostname)
300
+ return false unless config && config[:enabled_for].present?
301
+ !Array(config[:enabled_for]).include?(action.to_s)
302
+ end
303
+
304
+ def custom_endpoint_config_for(hostname)
305
+ # hostname has a period in it, so we need to look it up by [] instead of the traditional i18n method
306
+ I18n.t("database_admin.prompts", :default => {})[hostname.to_sym]
307
+ end
308
+
179
309
  def should_exclude_tables?
180
310
  ask_yn?("Would you like to exclude tables in the dump") do |q|
181
311
  q.readline = true
182
312
  end
183
313
  end
184
314
 
185
- def filename_prompt_args
186
- default = action == :dump ? DB_DEFAULT_DUMP_FILE : DB_RESTORE_FILE
187
- validator = LOCAL_FILE_VALIDATOR if action == :restore && backup_type == LOCAL_FILE
188
- [local_file_prompt, default, validator, "file that exists"]
315
+ def should_split_output?
316
+ ask_yn?("Would you like to split the #{action} output into multiple parts") do |q|
317
+ q.readline = true
318
+ end
189
319
  end
190
320
 
191
- def local_file_prompt
192
- if action == :restore
193
- "location of the local restore file"
194
- else
195
- "location to save the #{action} file to"
321
+ def filename_prompt_args
322
+ return restore_prompt_args if action == :restore
323
+ default = action == :dump ? DB_DEFAULT_DUMP_FILE : DB_RESTORE_FILE
324
+ prompt = "location to save the #{action} file to"
325
+ if object_store_backup?
326
+ prompt = "name for the remote #{action} file"
327
+ default = File.basename(default)
196
328
  end
329
+ [prompt, default, nil, "file that exists"]
330
+ end
331
+
332
+ def restore_prompt_args
333
+ default = DB_RESTORE_FILE
334
+ validator = LOCAL_FILE_VALIDATOR if local_backup?
335
+ prompt = "location of the local restore file"
336
+ [prompt, default, validator, "file that exists"]
197
337
  end
198
338
 
199
339
  def remote_file_prompt_args_for(remote_type)
@@ -202,10 +342,14 @@ module ManageIQ
202
342
  else
203
343
  "location to save the remote #{action} file to"
204
344
  end
205
- prompt += "\nExample: #{SAMPLE_URLS[remote_type]}"
345
+ prompt += "\nExample: #{sample_url(remote_type)}"
206
346
  [prompt, remote_type]
207
347
  end
208
348
 
349
+ def sample_url(scheme)
350
+ I18n.t("database_admin.sample_url.#{scheme}")
351
+ end
352
+
209
353
  def processing_message
210
354
  msg = if action == :restore
211
355
  "\nRestoring the database..."
@@ -15,16 +15,6 @@ module ApplianceConsole
15
15
  NONE_REGEXP = /^('?NONE'?)?$/i.freeze
16
16
  HOSTNAME_REGEXP = /^(([a-zA-Z]|[a-zA-Z][a-zA-Z0-9\-]*[a-zA-Z0-9])\.)*([A-Za-z]|[A-Za-z][A-Za-z0-9\-]*[A-Za-z0-9])$/
17
17
 
18
- SAMPLE_URLS = {
19
- 'nfs' => 'nfs://host.mydomain.com/exported/my_exported_folder/db.backup',
20
- 'smb' => 'smb://host.mydomain.com/my_share/daily_backup/db.backup',
21
- 's3' => 's3://mybucket/my_subdirectory/daily_backup/db.backup',
22
- }
23
-
24
- def sample_url(scheme)
25
- SAMPLE_URLS[scheme]
26
- end
27
-
28
18
  def ask_for_uri(prompt, expected_scheme, opts = {})
29
19
  require 'uri'
30
20
  just_ask(prompt, nil, nil, 'a valid URI') do |q|
@@ -38,6 +28,7 @@ module ApplianceConsole
38
28
  (u.host =~ HOSTNAME_REGEXP || u.hostname =~ IP_REGEXP) &&
39
29
  (opts[:optional_path] || !u.path.empty?)
40
30
  end
31
+ yield q if block_given?
41
32
  end
42
33
  end
43
34
 
@@ -1,5 +1,5 @@
1
1
  module ManageIQ
2
2
  module ApplianceConsole
3
- VERSION = '3.2.0'.freeze
3
+ VERSION = '3.3.0'.freeze
4
4
  end
5
5
  end
@@ -42,3 +42,23 @@ en:
42
42
  shutdown: Shut Down Appliance
43
43
  summary: Summary Information
44
44
  quit: Quit
45
+ database_admin:
46
+ menu_order:
47
+ - local
48
+ - nfs
49
+ - smb
50
+ - s3
51
+ - ftp
52
+ - swift
53
+ local: Local file
54
+ nfs: Network File System (NFS)
55
+ smb: Samba (SMB)
56
+ s3: Amazon S3 (S3)
57
+ ftp: File Transfer Protocol (FTP)
58
+ swift: OpenStack Swift (Swift)
59
+ sample_url:
60
+ nfs: nfs://host.mydomain.com/exported/my_exported_folder/db.backup
61
+ smb: smb://host.mydomain.com/my_share/daily_backup/db.backup
62
+ s3: s3://mybucket/my_subdirectory/daily_backup/db.backup
63
+ ftp: ftp://host.mydomain.com/path/to/daily_backup/db.backup
64
+ swift: swift://host.mydomain.com/path/to/daily_backup/db.backup
@@ -26,7 +26,7 @@ Gem::Specification.new do |spec|
26
26
  spec.add_runtime_dependency "bcrypt", "~> 3.1.10"
27
27
  spec.add_runtime_dependency "highline", "~> 1.6.21"
28
28
  spec.add_runtime_dependency "i18n", "~> 0.7"
29
- spec.add_runtime_dependency "linux_admin", "~> 1.0"
29
+ spec.add_runtime_dependency "linux_admin", ["~> 1.0", ">=1.2.2"]
30
30
  spec.add_runtime_dependency "pg"
31
31
  spec.add_runtime_dependency "trollop", "~> 2.0"
32
32
 
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: manageiq-appliance_console
3
3
  version: !ruby/object:Gem::Version
4
- version: 3.2.0
4
+ version: 3.3.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - ManageIQ Developers
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2018-08-23 00:00:00.000000000 Z
11
+ date: 2018-11-05 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: activerecord
@@ -101,6 +101,9 @@ dependencies:
101
101
  - - "~>"
102
102
  - !ruby/object:Gem::Version
103
103
  version: '1.0'
104
+ - - ">="
105
+ - !ruby/object:Gem::Version
106
+ version: 1.2.2
104
107
  type: :runtime
105
108
  prerelease: false
106
109
  version_requirements: !ruby/object:Gem::Requirement
@@ -108,6 +111,9 @@ dependencies:
108
111
  - - "~>"
109
112
  - !ruby/object:Gem::Version
110
113
  version: '1.0'
114
+ - - ">="
115
+ - !ruby/object:Gem::Version
116
+ version: 1.2.2
111
117
  - !ruby/object:Gem::Dependency
112
118
  name: pg
113
119
  requirement: !ruby/object:Gem::Requirement