manageiq-appliance_console 3.2.0 → 3.3.0

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.
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