pg_export 1.0.0.rc5 → 1.0.0.rc6
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 +4 -4
- data/.rubocop.yml +19 -4
- data/CHANGELOG.md +7 -5
- data/README.md +46 -24
- data/bin/pg_export +27 -29
- data/lib/pg_export/configuration.rb +70 -18
- data/lib/pg_export/factory.rb +148 -0
- data/lib/pg_export/lib/pg_export/adapters/{bash_adapter.rb → shell_adapter.rb} +1 -1
- data/lib/pg_export/lib/pg_export/entities/dump.rb +22 -10
- data/lib/pg_export/lib/pg_export/factories/cipher_factory.rb +8 -4
- data/lib/pg_export/lib/pg_export/factories/dump_factory.rb +0 -1
- data/lib/pg_export/lib/pg_export/factories/ftp_gateway_factory.rb +7 -4
- data/lib/pg_export/lib/pg_export/factories/ssh_gateway_factory.rb +7 -4
- data/lib/pg_export/lib/pg_export/gateways/ftp.rb +1 -3
- data/lib/pg_export/lib/pg_export/gateways/ssh.rb +2 -6
- data/lib/pg_export/lib/pg_export/listeners/interactive/build_dump.rb +1 -1
- data/lib/pg_export/lib/pg_export/listeners/interactive/close_connection.rb +1 -1
- data/lib/pg_export/lib/pg_export/listeners/interactive/remove_old_dumps.rb +1 -1
- data/lib/pg_export/lib/pg_export/listeners/interactive/restore.rb +1 -1
- data/lib/pg_export/lib/pg_export/listeners/interactive/upload_dump.rb +1 -1
- data/lib/pg_export/lib/pg_export/listeners/interactive_listener.rb +4 -3
- data/lib/pg_export/lib/pg_export/listeners/plain/prepare_params.rb +1 -1
- data/lib/pg_export/lib/pg_export/listeners/plain_listener.rb +11 -5
- data/lib/pg_export/lib/pg_export/operations/decrypt_dump.rb +16 -6
- data/lib/pg_export/lib/pg_export/operations/encrypt_dump.rb +14 -5
- data/lib/pg_export/lib/pg_export/operations/open_connection.rb +14 -5
- data/lib/pg_export/lib/pg_export/operations/remove_old_dumps.rb +14 -6
- data/lib/pg_export/lib/pg_export/repositories/gateway_dump_file_repository.rb +0 -1
- data/lib/pg_export/lib/pg_export/repositories/gateway_dump_repository.rb +2 -7
- data/lib/pg_export/lib/pg_export/transactions/evaluator.rb +59 -0
- data/lib/pg_export/lib/pg_export/transactions/export_dump.rb +27 -21
- data/lib/pg_export/lib/pg_export/transactions/import_dump_interactively.rb +31 -29
- data/lib/pg_export/lib/pg_export/value_objects/dump_file.rb +2 -2
- data/lib/pg_export/lib/pg_export/value_objects/result.rb +49 -0
- data/lib/pg_export/version.rb +1 -1
- data/lib/pg_export.rb +13 -8
- data/pg_export.gemspec +1 -6
- metadata +13 -89
- data/lib/pg_export/container.rb +0 -23
- data/lib/pg_export/import.rb +0 -7
- data/lib/pg_export/lib/pg_export/types.rb +0 -14
- data/lib/pg_export/system/boot/config.rb +0 -27
- data/lib/pg_export/system/boot/ftp.rb +0 -11
- data/lib/pg_export/system/boot/interactive.rb +0 -16
- data/lib/pg_export/system/boot/operations.rb +0 -17
- data/lib/pg_export/system/boot/plain.rb +0 -16
- data/lib/pg_export/system/boot/ssh.rb +0 -11
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: ca033b9c62cc381584bd9696e9607b63d89f52310a5847b714908c7140e755dc
|
4
|
+
data.tar.gz: 755e0fa8760fa1ba6b2d3d8af65532da26b9a8978b5005853d9aaede8131d748
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 01a50e23dff7a059c606aaff6ea744f3ee3da607ffcf5062514c447a0f9413386a7df378ae7467ff9e35745b65d5a78fa96c6e9abf93b6cff2d8dc4fa9be5e55
|
7
|
+
data.tar.gz: a32e7517a57dcc5eee39c40334ea5552709930d2e5bd402eaf55e67c96625b528aa40f99ef2ee5cdbacae8ad052250d2122f87eb83705ab85fa41599a755fff0
|
data/.rubocop.yml
CHANGED
@@ -6,17 +6,32 @@ Metrics/BlockLength:
|
|
6
6
|
- 'bin/pg_export'
|
7
7
|
ExcludedMethods: ['describe', 'context']
|
8
8
|
|
9
|
-
|
10
|
-
Max:
|
9
|
+
Layout/LineLength:
|
10
|
+
Max: 140
|
11
11
|
|
12
12
|
Style/ParallelAssignment:
|
13
13
|
Enabled: false
|
14
14
|
|
15
|
-
Naming/
|
15
|
+
Naming/MethodParameterName:
|
16
16
|
Enabled: false
|
17
17
|
|
18
|
-
Documentation:
|
18
|
+
Style/Documentation:
|
19
19
|
Enabled: false
|
20
20
|
|
21
21
|
Lint/UnusedMethodArgument:
|
22
22
|
Enabled: false
|
23
|
+
|
24
|
+
Metrics/MethodLength:
|
25
|
+
Max: 50
|
26
|
+
|
27
|
+
Metrics/CyclomaticComplexity:
|
28
|
+
Max: 30
|
29
|
+
|
30
|
+
Style/TrailingCommaInHashLiteral:
|
31
|
+
Enabled: false
|
32
|
+
|
33
|
+
Metrics/AbcSize:
|
34
|
+
Max: 30
|
35
|
+
|
36
|
+
Metrics/PerceivedComplexity:
|
37
|
+
Max: 30
|
data/CHANGELOG.md
CHANGED
@@ -1,4 +1,4 @@
|
|
1
|
-
### 1.0.0 -
|
1
|
+
### 1.0.0 - 2022.05.17
|
2
2
|
- Make it compatible with Ruby 3.0
|
3
3
|
- Change configuration envs:
|
4
4
|
- BACKUP_FTP_HOST -> PG_EXPORT_GATEWAY_HOST
|
@@ -7,15 +7,17 @@
|
|
7
7
|
- DUMP_ENCRYPTION_KEY -> PG_EXPORT_ENCRYPTION_KEY
|
8
8
|
- Drop Ruby 2.3 support
|
9
9
|
- Add SSH option
|
10
|
-
- Add
|
10
|
+
- Add `encryption_algorithm` option to interface
|
11
|
+
- Remove dry libraries dependencies
|
12
|
+
- in case of failure bin/pg_export now returns with 1 exit value
|
11
13
|
|
12
14
|
### 0.7.7 - 2020.09.07
|
13
15
|
|
14
|
-
- Upgrade dry-initializer
|
16
|
+
- Upgrade dry-initializer
|
15
17
|
|
16
18
|
### 0.7.6 - 2020.09.05
|
17
19
|
|
18
|
-
- Upgrade dry-types, dry-struct dry-system
|
20
|
+
- Upgrade dry-types, dry-struct dry-system
|
19
21
|
|
20
22
|
### 0.7.0 - 2018.10.18
|
21
23
|
|
@@ -41,7 +43,7 @@
|
|
41
43
|
|
42
44
|
### 0.5.0 - 2017.03.11
|
43
45
|
|
44
|
-
- Add restriction on DUMP_ENCRYPTION_KEY, to be exactly 16 characters length
|
46
|
+
- Add restriction on DUMP_ENCRYPTION_KEY, to be exactly 16 characters length
|
45
47
|
- Make interactive mode more verbose by adding more messages
|
46
48
|
- Fix concurrently opening ftp connection
|
47
49
|
- Add closing ftp connection while importing dump in interactive mode
|
data/README.md
CHANGED
@@ -11,7 +11,7 @@ Can be used for backups or synchronizing databases between production and develo
|
|
11
11
|
Example:
|
12
12
|
|
13
13
|
pg_export --database database_name --keep 5
|
14
|
-
|
14
|
+
|
15
15
|
Above command will perform database dump, encrypt it, upload it to FTP and remove old dumps from FTP, keeping newest 5.
|
16
16
|
|
17
17
|
FTP connection params and encryption key are configured by env variables.
|
@@ -50,20 +50,38 @@ Or install it yourself as:
|
|
50
50
|
|
51
51
|
$ pg_export -h
|
52
52
|
|
53
|
-
|
54
|
-
|
55
|
-
|
56
|
-
|
57
|
-
|
58
|
-
|
59
|
-
|
60
|
-
|
61
|
-
|
62
|
-
|
63
|
-
|
64
|
-
|
65
|
-
|
66
|
-
|
53
|
+
SYNOPSIS
|
54
|
+
pg_export DATABASE [OPTION..]
|
55
|
+
pg_export --interactive DATABASE [OPTION..]
|
56
|
+
|
57
|
+
ARGUMENTS
|
58
|
+
DATABASE - database name to export (when default mode)
|
59
|
+
- phrase to filter database dumps by (when interactive mode)
|
60
|
+
|
61
|
+
OPTIONS
|
62
|
+
-g, --gateway GATEWAY Allowed values: ftp, ssh. Default: ftp. Credentials need to be set via ENVs
|
63
|
+
-s, --ssh Same as "--gateway ssh"
|
64
|
+
-f, --ftp Same as "--gateway ftp"
|
65
|
+
-d, --database DATABASE Alternative way of specifying name of the database to export or phrase to filter by
|
66
|
+
-e, --encryption_key KEY Dumps will be SSL encrypted using this key. Should have exactly 16 characters. Overwrites PG_EXPORT_ENCRYPTION_KEY env
|
67
|
+
-a, --algorithm ALGORITHM Encryption cipher algorithm (default: AES-128-CBC). Overwrites PG_EXPORT_ENCRYPTION_ALGORITHM env. For available option see `$ openssl list -cipher-algorithms`
|
68
|
+
-k, --keep KEEP Number of dump files to keep on FTP (default: 10). Overwrites KEEP_DUMPS env
|
69
|
+
-t, --timestamped Enables log messages with timestamps
|
70
|
+
-m, --muted Mutes log messages (overrides -t option)
|
71
|
+
-i, --interactive Interactive mode, for importing dumps
|
72
|
+
-v, --version Show version
|
73
|
+
-h, --help Show this message
|
74
|
+
|
75
|
+
ENV
|
76
|
+
PG_EXPORT_GATEWAY_HOST required
|
77
|
+
PG_EXPORT_GATEWAY_USER required
|
78
|
+
PG_EXPORT_GATEWAY_PASSWORD optional when eg. authorized key is added
|
79
|
+
PG_EXPORT_ENCRYPTION_KEY required or set by --encryption_key)
|
80
|
+
PG_EXPORT_ENCRYPTION_ALGORITHM required or set by --algorithm)
|
81
|
+
|
82
|
+
TEST RUN
|
83
|
+
-c, --configuration Print the configuration
|
84
|
+
-w, --welcome Try connecting to the gateway (FTP or SSH) to verify the connection
|
67
85
|
|
68
86
|
## How to start
|
69
87
|
|
@@ -73,28 +91,32 @@ __Step 1.__ Prepare ENV variables.
|
|
73
91
|
PG_EXPORT_GATEWAY_HOST=yourftp.example.com
|
74
92
|
PG_EXPORT_GATEWAY_USER=user
|
75
93
|
PG_EXPORT_GATEWAY_PASSWORD=password
|
76
|
-
|
94
|
+
|
77
95
|
/* Encryption key should have exactly 16 characters. */
|
78
96
|
/* Dumps will be SSL(AES-128-CBC) encrypted using this key. */
|
79
97
|
PG_EXPORT_ENCRYPTION_KEY=1234567890abcdef
|
80
|
-
|
98
|
+
|
81
99
|
/* Dumps to be kept on FTP */
|
82
100
|
/* Optional, defaults to 10 */
|
83
101
|
KEEP_DUMPS=5
|
84
|
-
|
85
|
-
Note, that variables cannot include `#` sign, [more info](http://serverfault.com/questions/539730/environment-variable-in-etc-environment-with-pound-hash-sign-in-the-value).
|
102
|
+
|
103
|
+
Note, that variables cannot include `#` sign, [more info](http://serverfault.com/questions/539730/environment-variable-in-etc-environment-with-pound-hash-sign-in-the-value).
|
86
104
|
|
87
105
|
__Step 2.__ Print the configuration to verify if env variables has been loaded properly.
|
88
106
|
|
89
107
|
$ pg_export --configuration
|
90
|
-
=>
|
91
|
-
|
92
|
-
|
108
|
+
=> encryption_key k4***
|
109
|
+
gateway_host yourftp.example.com
|
110
|
+
gateway_user your_gateway_user
|
111
|
+
gateway_password pass***
|
112
|
+
logger_format plain
|
113
|
+
keep_dumps 2
|
114
|
+
|
93
115
|
__Step 3.__ Try connecting to FTP to verify the connection.
|
94
116
|
|
95
117
|
$ pg_export --gateway ftp --welcome
|
96
118
|
=> 230 User your_ftp_user logged in
|
97
|
-
|
119
|
+
|
98
120
|
__Step 4.__ Perform database export.
|
99
121
|
|
100
122
|
$ pg_export -d your_database [-k 5]
|
@@ -103,7 +125,7 @@ __Step 4.__ Perform database export.
|
|
103
125
|
Connect to yourftp.example.com
|
104
126
|
Upload your_database_20181016_121314 (1.34MB) to yourftp.example.com
|
105
127
|
Close FTP
|
106
|
-
|
128
|
+
|
107
129
|
## How to restore a dump?
|
108
130
|
|
109
131
|
Run interactive mode and follow the instructions:
|
data/bin/pg_export
CHANGED
@@ -1,28 +1,27 @@
|
|
1
1
|
#!/usr/bin/env ruby
|
2
2
|
# frozen_string_literal: true
|
3
3
|
|
4
|
-
|
4
|
+
lib = File.expand_path('../lib', __dir__)
|
5
|
+
$LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
|
5
6
|
|
7
|
+
require 'optparse'
|
6
8
|
require 'pg_export'
|
7
|
-
require 'pg_export/version'
|
8
|
-
|
9
|
-
ENV['KEEP_DUMPS'] = ENV['KEEP_DUMPS'] || '10'
|
10
|
-
ENV['GATEWAY'] = 'ftp'
|
11
|
-
ENV['PG_EXPORT_MODE'] = 'plain'
|
12
|
-
ENV['PG_EXPORT_ENCRYPTION_ALGORITHM'] = 'AES-128-CBC'
|
13
9
|
|
14
10
|
database = nil
|
11
|
+
x = nil
|
15
12
|
|
16
13
|
option_parser = OptionParser.new do |opts|
|
17
14
|
opts.banner = <<~TXT
|
18
15
|
NAME
|
19
16
|
pg_export - CLI for exporting/importing PostgreSQL dumps via FTP/SSH
|
20
17
|
|
21
|
-
SYNOPSIS
|
22
|
-
pg_export DATABASE [
|
18
|
+
SYNOPSIS
|
19
|
+
pg_export DATABASE [OPTION..]
|
20
|
+
pg_export --interactive DATABASE [OPTION..]
|
23
21
|
|
24
|
-
|
25
|
-
|
22
|
+
EXIT VALUES
|
23
|
+
0 - Success
|
24
|
+
1 - Error
|
26
25
|
|
27
26
|
ARGUMENTS
|
28
27
|
DATABASE - database name to export (when default mode)
|
@@ -97,18 +96,11 @@ option_parser = OptionParser.new do |opts|
|
|
97
96
|
opts.separator "\nTEST RUN"
|
98
97
|
|
99
98
|
opts.on('-c', '--configuration', 'Print the configuration') do
|
100
|
-
|
101
|
-
PgExport::Container.start(:config)
|
102
|
-
puts PgExport::Container['config'].to_h
|
103
|
-
exit
|
99
|
+
x = -> { puts PgExport.new.config }
|
104
100
|
end
|
105
101
|
|
106
102
|
opts.on('-w', '--welcome', 'Try connecting to the gateway (FTP or SSH) to verify the connection') do
|
107
|
-
|
108
|
-
PgExport::Container.start(ENV['GATEWAY'].to_sym)
|
109
|
-
gateway = PgExport::Container['factories.gateway_factory'].gateway
|
110
|
-
puts gateway.welcome
|
111
|
-
exit
|
103
|
+
x = -> { puts PgExport.new.gateway_welcome }
|
112
104
|
end
|
113
105
|
|
114
106
|
if ARGV.empty?
|
@@ -119,30 +111,36 @@ end
|
|
119
111
|
|
120
112
|
begin
|
121
113
|
option_parser.parse!
|
114
|
+
if x
|
115
|
+
x.call
|
116
|
+
exit
|
117
|
+
end
|
122
118
|
database = ARGV.first unless ARGV.empty?
|
123
119
|
rescue OptionParser::ParseError => e
|
124
120
|
warn e.message.capitalize
|
125
121
|
warn 'Details:'
|
126
122
|
warn option_parser.to_s.split("\n").grep(/ #{e.args.first}/).join("\n")
|
127
123
|
warn 'Type "pg_export" for available options'
|
128
|
-
exit
|
124
|
+
exit 1
|
129
125
|
end
|
130
126
|
|
131
|
-
require 'pg_export/container'
|
132
|
-
|
133
127
|
begin
|
134
|
-
pg_export = PgExport.
|
128
|
+
pg_export = PgExport.new
|
135
129
|
rescue PgExport::InitializationError => e
|
136
130
|
warn 'Unable to initialize PgExport due to invalid configuration. Check you ENVs.'
|
137
131
|
warn "Detailed message: #{e.message}"
|
138
|
-
exit
|
132
|
+
exit 1
|
139
133
|
end
|
140
134
|
|
141
135
|
begin
|
142
|
-
pg_export
|
143
|
-
|
144
|
-
|
145
|
-
|
136
|
+
pg_export
|
137
|
+
.call(database)
|
138
|
+
.on_success { exit 0 }
|
139
|
+
.on_failure do |outcome|
|
140
|
+
warn outcome[:message]
|
141
|
+
exit 1
|
142
|
+
end
|
143
|
+
|
146
144
|
rescue Interrupt
|
147
145
|
puts
|
148
146
|
end
|
@@ -1,19 +1,19 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
-
require 'pg_export/lib/pg_export/types'
|
4
|
-
require 'dry-struct'
|
5
|
-
|
6
3
|
class PgExport
|
7
|
-
class Configuration
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
4
|
+
class Configuration
|
5
|
+
ATTRS = %i[
|
6
|
+
encryption_key
|
7
|
+
encryption_algorithm
|
8
|
+
gateway_host
|
9
|
+
gateway_user
|
10
|
+
gateway_password
|
11
|
+
logger_format
|
12
|
+
keep_dumps
|
13
|
+
gateway mode
|
14
|
+
].freeze
|
15
|
+
|
16
|
+
attr_reader *ATTRS
|
17
17
|
|
18
18
|
def self.build(env)
|
19
19
|
new(
|
@@ -21,14 +21,66 @@ class PgExport
|
|
21
21
|
encryption_algorithm: env['PG_EXPORT_ENCRYPTION_ALGORITHM'],
|
22
22
|
gateway_host: env['PG_EXPORT_GATEWAY_HOST'],
|
23
23
|
gateway_user: env['PG_EXPORT_GATEWAY_USER'],
|
24
|
-
gateway_password: env['PG_EXPORT_GATEWAY_PASSWORD']
|
25
|
-
logger_format: env['LOGGER_FORMAT']
|
26
|
-
keep_dumps: env['KEEP_DUMPS']
|
24
|
+
gateway_password: env['PG_EXPORT_GATEWAY_PASSWORD'],
|
25
|
+
logger_format: env['LOGGER_FORMAT'],
|
26
|
+
keep_dumps: env['KEEP_DUMPS'],
|
27
27
|
gateway: env['GATEWAY'],
|
28
28
|
mode: env['PG_EXPORT_MODE']
|
29
29
|
)
|
30
|
-
|
31
|
-
|
30
|
+
end
|
31
|
+
|
32
|
+
def initialize(
|
33
|
+
encryption_key: nil,
|
34
|
+
encryption_algorithm: nil,
|
35
|
+
gateway_host: nil,
|
36
|
+
gateway_user: nil,
|
37
|
+
gateway_password: nil,
|
38
|
+
logger_format: nil,
|
39
|
+
keep_dumps: nil,
|
40
|
+
gateway: nil,
|
41
|
+
mode: nil
|
42
|
+
)
|
43
|
+
|
44
|
+
@encryption_key = String(encryption_key)
|
45
|
+
raise ArgumentError, 'Encryption key must be 16 chars long' if @encryption_key.length != 16
|
46
|
+
|
47
|
+
@encryption_algorithm = String(encryption_algorithm)
|
48
|
+
@encryption_algorithm = 'AES-128-CBC' if @encryption_algorithm.empty?
|
49
|
+
|
50
|
+
@gateway_host = String(gateway_host)
|
51
|
+
raise ArgumentError, 'Gatway host must not be empty' if @gateway_host.empty?
|
52
|
+
|
53
|
+
@gateway_user = String(gateway_user)
|
54
|
+
raise ArgumentError, 'Gatway user must not be empty' if @gateway_user.empty?
|
55
|
+
|
56
|
+
@gateway_password = nil if gateway_password.nil? || gateway_password.to_s.empty?
|
57
|
+
|
58
|
+
@logger_format = logger_format.to_s.to_sym
|
59
|
+
@logger_format = :plain if @logger_format.empty?
|
60
|
+
raise ArgumentError, 'Logger format must be one of: plain, timestamped, muted' unless %i[plain timestamped muted].include?(@logger_format)
|
61
|
+
|
62
|
+
@keep_dumps = Integer(keep_dumps || 10)
|
63
|
+
raise ArgumentError, 'Keep dumps must greater or equal to 1' unless @keep_dumps >= 1
|
64
|
+
|
65
|
+
@gateway = gateway.to_s.to_sym
|
66
|
+
@gateway = :ftp if @gateway.empty?
|
67
|
+
raise ArgumentError, 'Gateway must be one of: ftp, ssh' unless %i[ftp ssh].include?(@gateway)
|
68
|
+
|
69
|
+
@mode = mode.to_s.to_sym
|
70
|
+
@mode = :plain if @mode.empty?
|
71
|
+
raise ArgumentError, 'Mode must be one of: plain, interactive' unless %i[plain interactive].include?(@mode)
|
72
|
+
end
|
73
|
+
|
74
|
+
def to_s
|
75
|
+
ATTRS.map do |name|
|
76
|
+
value = public_send(name)
|
77
|
+
|
78
|
+
if %i[encryption_key gateway_password].include?(name)
|
79
|
+
" #{name} #{value.nil? ? '' : value[0..2] + '***'}"
|
80
|
+
else
|
81
|
+
" #{name} #{value}"
|
82
|
+
end
|
83
|
+
end.join("\n")
|
32
84
|
end
|
33
85
|
end
|
34
86
|
end
|
@@ -0,0 +1,148 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
class PgExport
|
4
|
+
class Factory
|
5
|
+
attr_reader :config
|
6
|
+
|
7
|
+
def initialize(config:)
|
8
|
+
@config = config
|
9
|
+
end
|
10
|
+
|
11
|
+
def gateway_factory
|
12
|
+
if config.gateway == :ftp
|
13
|
+
require 'pg_export/lib/pg_export/factories/ftp_gateway_factory'
|
14
|
+
|
15
|
+
Factories::FtpGatewayFactory.new(config: config)
|
16
|
+
elsif config.gateway == :ssh
|
17
|
+
require 'pg_export/lib/pg_export/factories/ssh_gateway_factory'
|
18
|
+
|
19
|
+
Factories::SshGatewayFactory.new(config: config)
|
20
|
+
else
|
21
|
+
raise ArgumentError, "Unknown gateway #{config.gateway}"
|
22
|
+
end
|
23
|
+
end
|
24
|
+
|
25
|
+
def transaction
|
26
|
+
require 'pg_export/lib/pg_export/operations/encrypt_dump'
|
27
|
+
require 'pg_export/lib/pg_export/operations/decrypt_dump'
|
28
|
+
require 'pg_export/lib/pg_export/operations/open_connection'
|
29
|
+
require 'pg_export/lib/pg_export/factories/cipher_factory'
|
30
|
+
require 'pg_export/lib/pg_export/factories/dump_factory'
|
31
|
+
require 'pg_export/lib/pg_export/adapters/shell_adapter'
|
32
|
+
require 'pg_export/lib/pg_export/repositories/gateway_dump_repository'
|
33
|
+
require 'pg_export/lib/pg_export/repositories/gateway_dump_file_repository'
|
34
|
+
|
35
|
+
cipher_factory = Factories::CipherFactory.new(
|
36
|
+
encryption_algorithm: config.encryption_algorithm,
|
37
|
+
encryption_key: config.encryption_key
|
38
|
+
)
|
39
|
+
|
40
|
+
gateway_dump_repository = Repositories::GatewayDumpRepository.new
|
41
|
+
gateway_dump_file_repository = Repositories::GatewayDumpFileRepository.new
|
42
|
+
open_connection = Operations::OpenConnection.new(gateway_factory: gateway_factory)
|
43
|
+
bash_adapter = Adapters::ShellAdapter.new
|
44
|
+
|
45
|
+
encrypt_dump = Operations::EncryptDump.new(cipher_factory: cipher_factory)
|
46
|
+
|
47
|
+
if config.mode == :plain
|
48
|
+
require 'pg_export/lib/pg_export/operations/remove_old_dumps'
|
49
|
+
require 'pg_export/lib/pg_export/transactions/export_dump'
|
50
|
+
|
51
|
+
remove_old_dumps = Operations::RemoveOldDumps.new(
|
52
|
+
gateway_dump_repository: gateway_dump_repository,
|
53
|
+
keep: config.keep_dumps
|
54
|
+
)
|
55
|
+
|
56
|
+
PgExport::Transactions::ExportDump.new(
|
57
|
+
dump_factory: Factories::DumpFactory.new,
|
58
|
+
bash_adapter: bash_adapter,
|
59
|
+
encrypt_dump: encrypt_dump,
|
60
|
+
open_connection: open_connection,
|
61
|
+
remove_old_dumps: remove_old_dumps,
|
62
|
+
listeners: plain_listeners
|
63
|
+
)
|
64
|
+
elsif config.mode == :interactive
|
65
|
+
require 'pg_export/lib/pg_export/transactions/import_dump_interactively'
|
66
|
+
require 'pg_export/lib/pg_export/ui/interactive/input'
|
67
|
+
|
68
|
+
decrypt_dump = Operations::DecryptDump.new(cipher_factory: cipher_factory)
|
69
|
+
|
70
|
+
PgExport::Transactions::ImportDumpInteractively.new(
|
71
|
+
input: Ui::Interactive::Input.new,
|
72
|
+
bash_adapter: bash_adapter,
|
73
|
+
gateway_dump_file_repository: gateway_dump_file_repository,
|
74
|
+
gateway_dump_repository: gateway_dump_repository,
|
75
|
+
open_connection: open_connection,
|
76
|
+
decrypt_dump: decrypt_dump,
|
77
|
+
listeners: interactive_listeners
|
78
|
+
)
|
79
|
+
else
|
80
|
+
raise ArgumentError, "Unknown mode #{config.mode}"
|
81
|
+
end
|
82
|
+
end
|
83
|
+
|
84
|
+
private
|
85
|
+
|
86
|
+
def plain_listeners
|
87
|
+
require 'pg_export/lib/pg_export/listeners/plain/prepare_params'
|
88
|
+
require 'pg_export/lib/pg_export/listeners/plain/build_dump'
|
89
|
+
require 'pg_export/lib/pg_export/listeners/plain/close_connection'
|
90
|
+
require 'pg_export/lib/pg_export/listeners/plain/decrypt_dump'
|
91
|
+
require 'pg_export/lib/pg_export/listeners/plain/download_dump'
|
92
|
+
require 'pg_export/lib/pg_export/listeners/plain/encrypt_dump'
|
93
|
+
require 'pg_export/lib/pg_export/listeners/plain/fetch_dumps'
|
94
|
+
require 'pg_export/lib/pg_export/listeners/plain/open_connection'
|
95
|
+
require 'pg_export/lib/pg_export/listeners/plain/remove_old_dumps'
|
96
|
+
require 'pg_export/lib/pg_export/listeners/plain/restore'
|
97
|
+
require 'pg_export/lib/pg_export/listeners/plain/upload_dump'
|
98
|
+
|
99
|
+
logger = build_logger(config.logger_format)
|
100
|
+
|
101
|
+
{
|
102
|
+
prepare_params: Listeners::Plain::PrepareParams.new(logger: logger),
|
103
|
+
build_dump: Listeners::Plain::BuildDump.new(logger: logger),
|
104
|
+
encrypt_dump: Listeners::Plain::EncryptDump.new(logger: logger),
|
105
|
+
open_connection: Listeners::Plain::OpenConnection.new(logger: logger),
|
106
|
+
upload_dump: Listeners::Plain::UploadDump.new(logger: logger),
|
107
|
+
remove_old_dumps: Listeners::Plain::RemoveOldDumps.new(logger: logger),
|
108
|
+
close_connection: Listeners::Plain::CloseConnection.new(logger: logger)
|
109
|
+
}
|
110
|
+
end
|
111
|
+
|
112
|
+
def interactive_listeners
|
113
|
+
require 'pg_export/lib/pg_export/listeners/interactive/open_connection'
|
114
|
+
require 'pg_export/lib/pg_export/listeners/interactive/fetch_dumps'
|
115
|
+
require 'pg_export/lib/pg_export/listeners/interactive/select_dump'
|
116
|
+
require 'pg_export/lib/pg_export/listeners/interactive/download_dump'
|
117
|
+
require 'pg_export/lib/pg_export/listeners/interactive/close_connection'
|
118
|
+
require 'pg_export/lib/pg_export/listeners/interactive/decrypt_dump'
|
119
|
+
require 'pg_export/lib/pg_export/listeners/interactive/select_database'
|
120
|
+
require 'pg_export/lib/pg_export/listeners/interactive/restore'
|
121
|
+
|
122
|
+
{
|
123
|
+
open_connection: Listeners::Interactive::OpenConnection.new,
|
124
|
+
fetch_dumps: Listeners::Interactive::FetchDumps.new,
|
125
|
+
select_dump: Listeners::Interactive::SelectDump.new,
|
126
|
+
download_dump: Listeners::Interactive::DownloadDump.new,
|
127
|
+
close_connection: Listeners::Interactive::CloseConnection.new,
|
128
|
+
decrypt_dump: Listeners::Interactive::DecryptDump.new,
|
129
|
+
select_database: Listeners::Interactive::SelectDatabase.new,
|
130
|
+
restore: Listeners::Interactive::Restore.new,
|
131
|
+
}
|
132
|
+
end
|
133
|
+
|
134
|
+
def build_logger(logger_format)
|
135
|
+
require 'logger'
|
136
|
+
|
137
|
+
formatters = {
|
138
|
+
plain: ->(_, _, _, message) { "#{message}\n" },
|
139
|
+
muted: ->(*) {},
|
140
|
+
timestamped: lambda do |severity, datetime, progname, message|
|
141
|
+
"#{datetime} #{Process.pid} TID-#{Thread.current.object_id.to_s(36)}#{progname} #{severity}: #{message}\n"
|
142
|
+
end
|
143
|
+
}
|
144
|
+
|
145
|
+
Logger.new($stdout, formatter: formatters.fetch(logger_format))
|
146
|
+
end
|
147
|
+
end
|
148
|
+
end
|
@@ -1,17 +1,25 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
-
require 'dry-initializer'
|
4
|
-
require 'pg_export/lib/pg_export/types'
|
5
|
-
|
6
3
|
class PgExport
|
7
4
|
module Entities
|
8
5
|
class Dump
|
9
|
-
|
6
|
+
attr_reader :name, :type, :database, :file
|
7
|
+
|
8
|
+
def initialize(name: nil, type: nil, database: nil, file: nil)
|
9
|
+
@name = String(name)
|
10
|
+
raise ArgumentError, 'Dump name must not be empty' if @name.empty?
|
11
|
+
raise ArgumentError, 'Dump name does not match criteria' unless /.+_20[0-9]{6}_[0-9]{6}\Z/.match?(@name)
|
10
12
|
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
13
|
+
@type = String(type)
|
14
|
+
@type = 'plain' if @type.empty?
|
15
|
+
raise ArgumentError, 'Dump type must be one of: plain, encrypted' unless %w[plain encrypted].include?(@type)
|
16
|
+
|
17
|
+
@database = database
|
18
|
+
|
19
|
+
@file = file
|
20
|
+
@file = ValueObjects::DumpFile.new if @file.nil?
|
21
|
+
raise ArgumentError, "Invalid file type: #{@file.class}" unless @file.is_a?(ValueObjects::DumpFile)
|
22
|
+
end
|
15
23
|
|
16
24
|
def encrypt(cipher_factory:)
|
17
25
|
self.file = file.copy(cipher: cipher_factory.encryptor)
|
@@ -32,13 +40,17 @@ class PgExport
|
|
32
40
|
end
|
33
41
|
|
34
42
|
def file=(f)
|
35
|
-
@file =
|
43
|
+
@file = f
|
44
|
+
|
45
|
+
raise ArgumentError, "Invalid file type: '#{f}'" unless @file.is_a?(ValueObjects::DumpFile)
|
36
46
|
end
|
37
47
|
|
38
48
|
protected
|
39
49
|
|
40
50
|
def type=(t)
|
41
|
-
@type =
|
51
|
+
@type = t.to_s
|
52
|
+
|
53
|
+
raise ArgumentError, "Dump type '#{t}' must be one of: plain, encrypted" unless %w[plain encrypted].include?(@type)
|
42
54
|
end
|
43
55
|
end
|
44
56
|
end
|
@@ -1,12 +1,14 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
3
|
require 'openssl'
|
4
|
-
require 'pg_export/import'
|
5
4
|
|
6
5
|
class PgExport
|
7
6
|
module Factories
|
8
7
|
class CipherFactory
|
9
|
-
|
8
|
+
def initialize(encryption_algorithm:, encryption_key:)
|
9
|
+
@encryption_algorithm = encryption_algorithm
|
10
|
+
@encryption_key = encryption_key
|
11
|
+
end
|
10
12
|
|
11
13
|
def encryptor
|
12
14
|
build_cipher(:encrypt)
|
@@ -18,10 +20,12 @@ class PgExport
|
|
18
20
|
|
19
21
|
private
|
20
22
|
|
23
|
+
attr_reader :encryption_algorithm, :encryption_key
|
24
|
+
|
21
25
|
def build_cipher(type)
|
22
|
-
cipher = OpenSSL::Cipher.new(
|
26
|
+
cipher = OpenSSL::Cipher.new(encryption_algorithm)
|
23
27
|
cipher.public_send(type)
|
24
|
-
cipher.key =
|
28
|
+
cipher.key = encryption_key
|
25
29
|
cipher
|
26
30
|
end
|
27
31
|
end
|