ey_cloud_server 1.4.61 → 1.5.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.
checksums.yaml CHANGED
@@ -1,15 +1,7 @@
1
1
  ---
2
- !binary "U0hBMQ==":
3
- metadata.gz: !binary |-
4
- ODliZWU4ZDUzNjk1NTExYzdiMTJiMjE3MzUxOGI2Y2VjYmUwNzg4ZQ==
5
- data.tar.gz: !binary |-
6
- OWI2Nzg4YWI5ZDFhNGZiNDcwOGM3ZGFmYTE5OTE4NzM2YzMyOGY3Zg==
2
+ SHA256:
3
+ metadata.gz: bfb2b6fa4059f5c796ba0cedbb4784c6a564a22adf1cd91dcc8efac32d44a1f6
4
+ data.tar.gz: e2dab140765f7438ccb743c40169a186e23f6b72d5acd36d5be5aaf759ca50a0
7
5
  SHA512:
8
- metadata.gz: !binary |-
9
- YzQxNzY3OTE3YWViZTZlMmFkNTc5ZWJiMWZiYTYyN2FmMDNkYTQyYjk5ZWQ4
10
- MGVhOGRmNzVjZDVkMGFjYzFkN2UxMjdlODk3MDczNDVhMjI1MjFjOTg2YmUy
11
- ZDRmY2I3YmU2OTk3N2E1MmU2ODc4NjBiMTQzNWNjNzcyYjNhYjI=
12
- data.tar.gz: !binary |-
13
- YTRlZjdjYmE2ODk5NTQ0YzE1ODkwOTAwYWM1OWZhMDRiMDhhZmYxZWYxZmQ3
14
- ZTkwZWY0ZGRkZTE2MDZlNjU4ZGNlZWRmMzBjNTVmMGUyZmNlOWE2NDZjZjll
15
- NDZmYTI4N2ZjZTdjNWE5MDA4NjAwMGE4NjUwODdlODZiODgzMzc=
6
+ metadata.gz: e0f3941d55b673e5fbe7c3fea6e41ad72447e556cdfcaa7e29ea7226929042ea8e1806bc566bab07f245ad23302b4ad244c4aedde0780c1e3101cda41c4a39e3
7
+ data.tar.gz: 0f9a2d0689d4ba021eef298a7df7786abe731d13aa8aba68a59b9ea0e0e5d6e8dc568723ed97e886c07d9fd875513260d3a44950c93cd054b84e81e7c66348c1
data/bin/eybackup CHANGED
@@ -16,5 +16,6 @@ rescue => e
16
16
  puts "******* Trace *******"
17
17
  puts e.inspect
18
18
  EY.notify_backup_error(e) unless STDOUT.isatty
19
+ exit 1
19
20
  end
20
21
 
@@ -1,3 +1,6 @@
1
+ require 'simplecov'
2
+ SimpleCov.start
3
+
1
4
  require File.dirname(__FILE__) + "/../../lib/ey-flex"
2
5
  require File.dirname(__FILE__) + "/../../lib/ey_backup"
3
6
  require 'fakeweb'
@@ -1,3 +1,5 @@
1
+ require 'shellwords'
2
+
1
3
  module EY
2
4
  module Backup
3
5
  class MysqlEngine < Engine
@@ -45,10 +47,10 @@ module EY
45
47
 
46
48
  def check_if_replica
47
49
  err_msg="ERROR: Target host: '#{host}' is currently: "
48
- err_msg=err_msg + "a replica based on 'show slave status', " if db_replicating?
50
+ err_msg=err_msg + "a replica, " if db_replicating?
49
51
  err_msg=err_msg + "in read_only mode, " if read_only_on?
50
52
  err_msg=err_msg + "restores should be processed against the master."
51
-
53
+
52
54
  EY::Backup.logger.fatal(%Q{#{err_msg}}) if db_replicating? or read_only_on?
53
55
  end
54
56
 
@@ -90,10 +92,50 @@ module EY
90
92
  end
91
93
 
92
94
  def db_replicating?
93
- stdout = %x{mysql #{username_option} #{host_option} -BN -e"show slave status"|wc -l}
94
- stdout.to_i > 0
95
+ statement = replica_status_statement
96
+ stdout = %x(mysql #{username_option} #{host_option} -BN -e #{Shellwords.escape(statement)})
97
+ probe_status = $?
98
+
99
+ unless probe_status.success?
100
+ # The replication-status probe itself failed -- e.g. the statement
101
+ # is unsupported on this server version, or a connection/permission
102
+ # problem. We cannot prove the host is NOT a replica, so fail
103
+ # closed and treat it as a possible replica rather than silently
104
+ # letting the restore proceed (this is how MySQL 8.4's removal of
105
+ # `SHOW SLAVE STATUS` used to defeat this check entirely).
106
+ warn("Unable to determine replication status on '#{host}' via #{statement.inspect}: #{stdout.strip}; treating host as a possible replica.")
107
+ return true
108
+ end
109
+
110
+ !stdout.strip.empty?
95
111
  end
96
-
112
+
113
+ # `SHOW SLAVE STATUS` was deprecated in MySQL 8.0.22 and removed in
114
+ # 8.4, replaced by `SHOW REPLICA STATUS`.
115
+ def replica_status_statement
116
+ mysql_8_4_or_newer? ? "show replica status" : "show slave status"
117
+ end
118
+
119
+ def mysql_8_4_or_newer?
120
+ stdout = %x(mysql #{username_option} #{host_option} -BN -e #{Shellwords.escape('select @@version')})
121
+ return false unless $?.success?
122
+
123
+ version = stdout.strip
124
+ # MariaDB keeps its own version numbering (10.x, 11.x) and retains
125
+ # `SHOW SLAVE STATUS` across all versions, so we must not compare
126
+ # its major.minor against MySQL's 8.4 boundary.
127
+ return false if version =~ /mariadb/i
128
+
129
+ # Anchor at the start of the string so we only inspect the leading
130
+ # version tuple (e.g. "8.4.11-11" → "8.4"), not any later digit-dot-digit
131
+ # pattern in suffixes or build metadata.
132
+ numeric = version[/\A\d+\.\d+/]
133
+ return false unless numeric
134
+
135
+ major, minor = numeric.split('.').map(&:to_i)
136
+ major > 8 || (major == 8 && minor >= 4)
137
+ end
138
+
97
139
  def read_only_on?
98
140
  stdout = %x{mysql #{username_option} #{host_option} -BN -e"select @@global.read_only"}
99
141
  stdout.to_i == 1
@@ -105,13 +147,57 @@ module EY
105
147
  end
106
148
 
107
149
  def cycle_database(database_name)
108
- query = "show create database #{database_name} \\G"
109
- create_cmd = %x(mysql #{username_option} #{host_option} -NB -e "#{query}"|tail -n 1)
110
- create_cmd="Create database #{database_name}" if create_cmd==""
111
-
112
- %x(mysql #{username_option} #{host_option} -e 'DROP DATABASE IF EXISTS #{database_name}')
113
- %x(mysql #{username_option} #{host_option} -e '#{create_cmd}')
114
-
150
+ create_cmd = capture_create_database_statement(database_name)
151
+
152
+ unless create_cmd =~ /\ACREATE\s+DATABASE\b/i
153
+ raise "Refusing to restore '#{database_name}': could not obtain a valid CREATE DATABASE statement (got #{create_cmd.inspect}). The existing database has NOT been touched."
154
+ end
155
+
156
+ drop_database!(database_name)
157
+ recreate_database!(create_cmd, database_name)
158
+ end
159
+
160
+ def capture_create_database_statement(database_name)
161
+ query = "show create database `#{database_name}` \\G"
162
+ raw = %x(mysql #{username_option} #{host_option} -NB -e #{Shellwords.escape(query)})
163
+ capture_status = $?
164
+
165
+ # `-N` strips the field-name labels that `\G` would otherwise print,
166
+ # so the last non-blank line is the CREATE DATABASE statement text.
167
+ create_cmd = raw.to_s.split("\n").map(&:strip).reject(&:empty?).last.to_s
168
+
169
+ if create_cmd.empty? || !capture_status.success?
170
+ # No existing database to read from (e.g. this is the first-ever
171
+ # restore against a fresh target), or the probe itself failed.
172
+ # Fall back to a bare CREATE DATABASE so the restore can still
173
+ # proceed.
174
+ "CREATE DATABASE `#{database_name}`"
175
+ else
176
+ create_cmd
177
+ end
178
+ end
179
+
180
+ def drop_database!(database_name)
181
+ %x(mysql #{username_option} #{host_option} -e #{Shellwords.escape("DROP DATABASE IF EXISTS `#{database_name}`")})
182
+ raise "Failed to drop database '#{database_name}' prior to restore; the existing database was left intact." unless $?.success?
183
+ end
184
+
185
+ def recreate_database!(create_cmd, database_name)
186
+ # Feed the CREATE DATABASE statement to `mysql` on STDIN rather than
187
+ # interpolating it into a quoted shell `-e` argument. From MySQL
188
+ # 8.0.16 onward, `SHOW CREATE DATABASE` output can contain a
189
+ # single-quoted clause (e.g. `/*!80016 DEFAULT ENCRYPTION='N' */`)
190
+ # whose quote would otherwise terminate a single-quoted shell string
191
+ # and truncate the statement mid-SQL -- which is exactly what turned
192
+ # a syntax error into a dropped, never-recreated database.
193
+ IO.popen(['mysql', username_option, host_option], 'w') do |io|
194
+ io.write(create_cmd)
195
+ io.write(";\n")
196
+ end
197
+
198
+ unless $?.success?
199
+ raise "Failed to recreate database '#{database_name}' after DROP -- the database has been dropped and NOT recreated. Statement attempted: #{create_cmd.inspect}"
200
+ end
115
201
  end
116
202
 
117
203
  def suffix
@@ -127,10 +127,27 @@ module EY
127
127
  create_cmd = create_command(database_name).chomp
128
128
  if create_cmd == ''
129
129
  create_database(database_name)
130
+ unless $?.success?
131
+ raise "Failed to create database '#{database_name}' before restore."
132
+ end
130
133
  else
131
134
  check_connections(database_name)
132
135
  drop_database(database_name)
136
+ unless $?.success?
137
+ raise "Failed to drop database '#{database_name}' prior to restore; the existing database was left intact."
138
+ end
139
+ # Note: create_cmd is embedded inside a double-quoted shell argument
140
+ # rather than single-quoted, so the single-quote chars that appear
141
+ # in PostgreSQL CREATE DATABASE output (e.g. ENCODING 'UTF8') are
142
+ # not shell-special within double quotes and do not cause the
143
+ # statement-termination break seen in the MySQL path. The risk class
144
+ # is different but we still check the exit status so that a failed
145
+ # create (permissions, malformed content, etc.) is caught before
146
+ # the missing database causes a load failure.
133
147
  %x{PGPASSWORD='#{password}' psql -U#{username} -h #{host} -t postgres -c "#{create_cmd}"}
148
+ unless $?.success?
149
+ raise "Failed to recreate database '#{database_name}' after DROP -- the database has been dropped and NOT recreated."
150
+ end
134
151
  end
135
152
  end
136
153
 
@@ -1,5 +1,5 @@
1
1
  module EY
2
2
  module CloudServer
3
- VERSION = '1.4.61'
3
+ VERSION = '1.5.1'
4
4
  end
5
5
  end
@@ -0,0 +1,11 @@
1
+ ---
2
+ tmp_dir:
3
+ data_json:
4
+ mysql_user: jenkins
5
+ mysql_password: jenkins
6
+ mysql_host: localhost
7
+ postgresql_user: postgres
8
+ postgresql_password: postgres
9
+ postgresql_host: localhost
10
+ aws_secret_id: 'abcd123.id'
11
+ aws_secret_key: 'abcd123.key'
@@ -0,0 +1,346 @@
1
+ # Unit tests for the two defects fixed in mysql_engine.rb (ey-all#204):
2
+ #
3
+ # A — cycle_database drops the database and never recreates it when MySQL
4
+ # 8.0.16+ injects a `DEFAULT ENCRYPTION='N'` single-quoted clause into
5
+ # `SHOW CREATE DATABASE` output, which broke out of the original
6
+ # single-quoted `-e` shell argument and truncated the SQL mid-statement.
7
+ #
8
+ # B — db_replicating? silently returned false on MySQL 8.4+ because
9
+ # `SHOW SLAVE STATUS` was removed there; it must fail closed (return
10
+ # true) whenever the probe itself errors, on any MySQL version.
11
+ #
12
+ # (Defect C — eybackup exiting 0 after a failed restore — is a one-line fix
13
+ # in bin/eybackup's top-level rescue block; the CLI entrypoint requires the
14
+ # full ey-flex / ey_enzyme dependency chain from the private NextGem gem
15
+ # server, which isn't available in this environment, so it isn't covered by
16
+ # an executable spec here. See the PR description.)
17
+ #
18
+ # Strategy: rather than re-implementing the engine's logic inline (which
19
+ # would test the test, not the code), these specs put a small fake `mysql`
20
+ # executable on PATH and let the REAL, unmodified engine methods run against
21
+ # it. The fake script's behavior (output, exit status) is controlled per
22
+ # example via environment variables, and it echoes back what it was given so
23
+ # we can assert on exactly what the engine sent it (in particular: whether
24
+ # the single-quote-containing CREATE DATABASE statement survives intact).
25
+ #
26
+ # This file intentionally does NOT require lib/ey_backup.rb (which pulls in
27
+ # ey-flex / ey_enzyme from NextGem); it loads only the engine class and its
28
+ # stdlib dependencies, so it runs on any modern Ruby + rspec (verified here
29
+ # under Ruby 3 / rspec 3 via Docker, since the project's pinned Ruby 1.9.3
30
+ # cannot run on this host). It therefore uses modern `expect`/`allow` syntax
31
+ # rather than the legacy suite's `.should`/`stub`, since it is not part of
32
+ # the (currently non-executable-in-this-environment) bundled spec run.
33
+
34
+ require 'forwardable'
35
+ require 'stringio'
36
+ require 'shellwords'
37
+ require 'fileutils'
38
+ require 'tmpdir'
39
+
40
+ # ---- Minimal EY::Backup bootstrap (avoids requiring ey-flex) -------------
41
+
42
+ module EY
43
+ module Backup
44
+ class << self
45
+ attr_accessor :logger, :tmp_dir, :log_dir
46
+ end
47
+
48
+ class Logger
49
+ extend Forwardable
50
+
51
+ attr_reader :stdout, :stderr
52
+
53
+ alias_method :fatal, :abort
54
+ public :fatal
55
+
56
+ def_delegator :stdout, :puts, :puts
57
+
58
+ def initialize(stdout = $stdout, stderr = $stderr)
59
+ @stdout, @stderr = stdout, stderr
60
+ end
61
+
62
+ def info(msg); stdout.puts("#{Time.now} #{msg}"); end
63
+ def warn(msg, db = nil); stdout.puts("#{Time.now} WARNING: #{msg}"); end
64
+ def error(msg, db = nil); stdout.puts("#{Time.now} ERROR: #{msg}"); end
65
+ def verbose(msg); end
66
+ def debug(msg); stdout.puts("#{Time.now} DEBUG: #{msg}"); end
67
+ def say(msg, newline = true); newline ? info(msg) : stdout.print(msg); end
68
+ end
69
+
70
+ module Logging
71
+ extend Forwardable
72
+ def_delegator EY::Backup, :logger
73
+ def_delegators :logger, :fatal, :error, :warn, :info, :verbose, :debug, :say
74
+ end
75
+ end
76
+ end
77
+
78
+ EY::Backup.logger = EY::Backup::Logger.new(StringIO.new, StringIO.new)
79
+
80
+ lib_dir = File.expand_path(File.dirname(__FILE__) + '/../../lib/ey_backup')
81
+ require lib_dir + '/spawner'
82
+ require lib_dir + '/base'
83
+ require lib_dir + '/engine'
84
+ require lib_dir + '/engines/mysql_engine'
85
+
86
+ # ---- Fake `mysql` binary --------------------------------------------------
87
+ #
88
+ # Routes on the `-e` query text (or, absent `-e`, treats the invocation as
89
+ # stdin-fed — exactly what recreate_database! does). Controlled entirely via
90
+ # environment variables so each example can script a distinct scenario.
91
+
92
+ FAKE_MYSQL_SCRIPT = <<~'SCRIPT'
93
+ #!/usr/bin/env bash
94
+ if [ -n "$FAKE_MYSQL_CALL_LOG" ]; then
95
+ printf '%s\n' "$*" >> "$FAKE_MYSQL_CALL_LOG"
96
+ fi
97
+
98
+ query=""
99
+ has_e=0
100
+ for arg in "$@"; do
101
+ if [ "$has_e" = "1" ]; then
102
+ query="$arg"
103
+ break
104
+ fi
105
+ if [ "$arg" = "-e" ]; then
106
+ has_e=1
107
+ fi
108
+ done
109
+
110
+ if [ "$has_e" = "0" ]; then
111
+ # No -e flag => stdin-fed invocation (recreate_database!).
112
+ if [ -n "$FAKE_MYSQL_STDIN_CAPTURE_FILE" ]; then
113
+ cat > "$FAKE_MYSQL_STDIN_CAPTURE_FILE"
114
+ else
115
+ cat > /dev/null
116
+ fi
117
+ exit "${FAKE_MYSQL_STDIN_EXIT:-0}"
118
+ fi
119
+
120
+ case "$query" in
121
+ "select @@version")
122
+ printf '%s' "$FAKE_MYSQL_VERSION"
123
+ exit "${FAKE_MYSQL_VERSION_EXIT:-0}"
124
+ ;;
125
+ "show replica status")
126
+ printf '%s' "$FAKE_MYSQL_REPLICA_OUTPUT"
127
+ exit "${FAKE_MYSQL_REPLICA_EXIT:-0}"
128
+ ;;
129
+ "show slave status")
130
+ printf '%s' "$FAKE_MYSQL_SLAVE_OUTPUT"
131
+ exit "${FAKE_MYSQL_SLAVE_EXIT:-0}"
132
+ ;;
133
+ show\ create\ database*)
134
+ printf '%s' "$FAKE_MYSQL_CREATE_OUTPUT"
135
+ exit "${FAKE_MYSQL_CREATE_EXIT:-0}"
136
+ ;;
137
+ DROP\ DATABASE*)
138
+ exit "${FAKE_MYSQL_DROP_EXIT:-0}"
139
+ ;;
140
+ *)
141
+ exit 0
142
+ ;;
143
+ esac
144
+ SCRIPT
145
+
146
+ RSpec.describe EY::Backup::MysqlEngine do
147
+ around(:each) do |example|
148
+ @fake_bin_dir = Dir.mktmpdir('fake-mysql-bin')
149
+ script_path = File.join(@fake_bin_dir, 'mysql')
150
+ File.write(script_path, FAKE_MYSQL_SCRIPT)
151
+ FileUtils.chmod('+x', script_path)
152
+
153
+ @call_log = File.join(@fake_bin_dir, 'calls.log')
154
+ ENV['FAKE_MYSQL_CALL_LOG'] = @call_log
155
+
156
+ original_path = ENV['PATH']
157
+ ENV['PATH'] = "#{@fake_bin_dir}:#{original_path}"
158
+ begin
159
+ example.run
160
+ ensure
161
+ ENV['PATH'] = original_path
162
+ %w[
163
+ FAKE_MYSQL_CALL_LOG FAKE_MYSQL_VERSION FAKE_MYSQL_VERSION_EXIT
164
+ FAKE_MYSQL_REPLICA_OUTPUT FAKE_MYSQL_REPLICA_EXIT
165
+ FAKE_MYSQL_SLAVE_OUTPUT FAKE_MYSQL_SLAVE_EXIT
166
+ FAKE_MYSQL_CREATE_OUTPUT FAKE_MYSQL_CREATE_EXIT
167
+ FAKE_MYSQL_DROP_EXIT FAKE_MYSQL_STDIN_EXIT
168
+ FAKE_MYSQL_STDIN_CAPTURE_FILE
169
+ ].each { |k| ENV.delete(k) }
170
+ FileUtils.remove_entry(@fake_bin_dir)
171
+ end
172
+ end
173
+
174
+ let(:engine) do
175
+ described_class.new('root', '', 'localhost', nil, true, false, false, false)
176
+ end
177
+
178
+ def call_log
179
+ File.exist?(@call_log) ? File.readlines(@call_log) : []
180
+ end
181
+
182
+ # =========================================================================
183
+ # B — replication-status detection on MySQL 8.4+ (and fail-closed on error)
184
+ # =========================================================================
185
+
186
+ describe '#db_replicating?' do
187
+ context 'on MySQL 8.4+, host is a replica' do
188
+ it 'uses SHOW REPLICA STATUS and returns true' do
189
+ ENV['FAKE_MYSQL_VERSION'] = '8.4.11-11'
190
+ ENV['FAKE_MYSQL_REPLICA_OUTPUT'] = "Source_Host\treplica-source\tSource_Port\t3306\n"
191
+ ENV['FAKE_MYSQL_REPLICA_EXIT'] = '0'
192
+
193
+ expect(engine.db_replicating?).to eq(true)
194
+ expect(call_log.any? { |l| l.include?('show replica status') }).to eq(true)
195
+ expect(call_log.any? { |l| l.include?('show slave status') }).to eq(false)
196
+ end
197
+ end
198
+
199
+ context 'on MySQL 8.4+, host is NOT a replica (plain master)' do
200
+ it 'uses SHOW REPLICA STATUS and returns false' do
201
+ ENV['FAKE_MYSQL_VERSION'] = '8.4.11-11'
202
+ ENV['FAKE_MYSQL_REPLICA_OUTPUT'] = ''
203
+ ENV['FAKE_MYSQL_REPLICA_EXIT'] = '0'
204
+
205
+ expect(engine.db_replicating?).to eq(false)
206
+ end
207
+ end
208
+
209
+ context 'on MySQL 8.0 (below the 8.4 cutover), host is a replica' do
210
+ it 'uses SHOW SLAVE STATUS and returns true' do
211
+ ENV['FAKE_MYSQL_VERSION'] = '8.0.16'
212
+ ENV['FAKE_MYSQL_SLAVE_OUTPUT'] = "Slave_IO_State\tWaiting\n"
213
+ ENV['FAKE_MYSQL_SLAVE_EXIT'] = '0'
214
+
215
+ expect(engine.db_replicating?).to eq(true)
216
+ expect(call_log.any? { |l| l.include?('show slave status') }).to eq(true)
217
+ end
218
+ end
219
+
220
+ context 'the pre-fix bug scenario: MySQL 8.4 but the probe uses the removed statement' do
221
+ it 'fails closed (treats as a possible replica) rather than silently returning false' do
222
+ ENV['FAKE_MYSQL_VERSION'] = '8.4.11-11'
223
+ # Simulate SHOW REPLICA STATUS itself erroring (e.g. permissions, or
224
+ # some future removal) -- the probe fails outright.
225
+ ENV['FAKE_MYSQL_REPLICA_OUTPUT'] = "ERROR 1064 (42000): syntax error"
226
+ ENV['FAKE_MYSQL_REPLICA_EXIT'] = '1'
227
+
228
+ expect(engine.db_replicating?).to eq(true)
229
+ end
230
+ end
231
+
232
+ context 'probe fails for a connectivity reason' do
233
+ it 'fails closed (treats as a possible replica)' do
234
+ ENV['FAKE_MYSQL_VERSION'] = '8.4.0'
235
+ ENV['FAKE_MYSQL_REPLICA_OUTPUT'] = "ERROR 2003 (HY000): Can't connect"
236
+ ENV['FAKE_MYSQL_REPLICA_EXIT'] = '1'
237
+
238
+ expect(engine.db_replicating?).to eq(true)
239
+ end
240
+ end
241
+ end
242
+
243
+ describe '#mysql_8_4_or_newer?' do
244
+ [
245
+ ['8.4.0', true],
246
+ ['8.4.11-11', true],
247
+ ['9.0.0', true],
248
+ ['8.3.9', false],
249
+ ['8.0.16', false],
250
+ ['5.7.36', false],
251
+ ['10.6.12-MariaDB', false],
252
+ ].each do |version, expected|
253
+ it "returns #{expected} for server version #{version}" do
254
+ ENV['FAKE_MYSQL_VERSION'] = version
255
+ ENV['FAKE_MYSQL_VERSION_EXIT'] = '0'
256
+ expect(engine.mysql_8_4_or_newer?).to eq(expected)
257
+ end
258
+ end
259
+
260
+ it 'returns false (safe default) when the version probe itself fails' do
261
+ ENV['FAKE_MYSQL_VERSION'] = ''
262
+ ENV['FAKE_MYSQL_VERSION_EXIT'] = '1'
263
+ expect(engine.mysql_8_4_or_newer?).to eq(false)
264
+ end
265
+ end
266
+
267
+ # =========================================================================
268
+ # A — cycle_database no longer destroys the database on a quoting break
269
+ # =========================================================================
270
+
271
+ describe '#capture_create_database_statement' do
272
+ it 'returns the SHOW CREATE DATABASE output verbatim, including an embedded single quote' do
273
+ stmt = "CREATE DATABASE `myapp` /*!40100 DEFAULT CHARACTER SET utf8mb3 */ /*!80016 DEFAULT ENCRYPTION='N' */"
274
+ ENV['FAKE_MYSQL_CREATE_OUTPUT'] = stmt
275
+ ENV['FAKE_MYSQL_CREATE_EXIT'] = '0'
276
+
277
+ result = engine.capture_create_database_statement('myapp')
278
+ expect(result).to eq(stmt)
279
+ expect(result).to include("ENCRYPTION='N'")
280
+ end
281
+
282
+ it 'falls back to a bare CREATE DATABASE when the probe fails (fresh target, no existing db)' do
283
+ ENV['FAKE_MYSQL_CREATE_OUTPUT'] = ''
284
+ ENV['FAKE_MYSQL_CREATE_EXIT'] = '1'
285
+
286
+ expect(engine.capture_create_database_statement('newdb')).to eq('CREATE DATABASE `newdb`')
287
+ end
288
+
289
+ it 'falls back to a bare CREATE DATABASE when the probe succeeds but returns nothing' do
290
+ ENV['FAKE_MYSQL_CREATE_OUTPUT'] = ''
291
+ ENV['FAKE_MYSQL_CREATE_EXIT'] = '0'
292
+
293
+ expect(engine.capture_create_database_statement('newdb')).to eq('CREATE DATABASE `newdb`')
294
+ end
295
+ end
296
+
297
+ describe '#cycle_database' do
298
+ it 'drops then recreates, delivering the FULL statement (with embedded quote) to mysql via stdin intact' do
299
+ stmt = "CREATE DATABASE `myapp` /*!80016 DEFAULT ENCRYPTION='N' */"
300
+ ENV['FAKE_MYSQL_CREATE_OUTPUT'] = stmt
301
+ ENV['FAKE_MYSQL_CREATE_EXIT'] = '0'
302
+ ENV['FAKE_MYSQL_DROP_EXIT'] = '0'
303
+ ENV['FAKE_MYSQL_STDIN_EXIT'] = '0'
304
+ stdin_capture = File.join(@fake_bin_dir, 'stdin_capture.sql')
305
+ ENV['FAKE_MYSQL_STDIN_CAPTURE_FILE'] = stdin_capture
306
+
307
+ expect { engine.cycle_database('myapp') }.not_to raise_error
308
+
309
+ # The database WAS dropped...
310
+ expect(call_log.any? { |l| l.start_with?('DROP DATABASE') || l.include?('DROP DATABASE') }).to eq(true)
311
+ # ...and the recreate step received the statement UNTRUNCATED, quote and all.
312
+ # This is the crux of the fix: under the old `-e '#{create_cmd}'` code,
313
+ # this content would never have reached mysql intact (the shell would
314
+ # have truncated it at the embedded quote).
315
+ received = File.read(stdin_capture)
316
+ expect(received).to include(stmt)
317
+ expect(received).to include("ENCRYPTION='N'")
318
+ end
319
+
320
+ it 'never drops the database if the captured statement is not a valid CREATE DATABASE' do
321
+ ENV['FAKE_MYSQL_CREATE_OUTPUT'] = 'garbage: mysql client misconfiguration warning text'
322
+ ENV['FAKE_MYSQL_CREATE_EXIT'] = '0'
323
+ ENV['FAKE_MYSQL_DROP_EXIT'] = '0'
324
+
325
+ expect { engine.cycle_database('myapp') }.to raise_error(/Refusing to restore/)
326
+ expect(call_log.any? { |l| l.include?('DROP DATABASE') }).to eq(false)
327
+ end
328
+
329
+ it 'raises (does not swallow the failure) if DROP DATABASE itself fails' do
330
+ ENV['FAKE_MYSQL_CREATE_OUTPUT'] = 'CREATE DATABASE `myapp`'
331
+ ENV['FAKE_MYSQL_CREATE_EXIT'] = '0'
332
+ ENV['FAKE_MYSQL_DROP_EXIT'] = '1'
333
+
334
+ expect { engine.cycle_database('myapp') }.to raise_error(/Failed to drop database/)
335
+ end
336
+
337
+ it 'raises clearly (dropped-but-not-recreated) if the recreate step fails after a successful DROP' do
338
+ ENV['FAKE_MYSQL_CREATE_OUTPUT'] = 'CREATE DATABASE `myapp`'
339
+ ENV['FAKE_MYSQL_CREATE_EXIT'] = '0'
340
+ ENV['FAKE_MYSQL_DROP_EXIT'] = '0'
341
+ ENV['FAKE_MYSQL_STDIN_EXIT'] = '1'
342
+
343
+ expect { engine.cycle_database('myapp') }.to raise_error(/dropped and NOT recreated/)
344
+ end
345
+ end
346
+ end
@@ -0,0 +1,188 @@
1
+ # Regression coverage for postgresql_engine.rb's #cycle_database, added
2
+ # alongside the ey-all#204 MySQL fix (see mysql_engine_spec.rb).
3
+ #
4
+ # postgresql_engine.rb's #cycle_database was audited for the same shell-
5
+ # quoting break as MySQL's (defect A): it also captures a statement
6
+ # (create_command) and interpolates it into a shell -c argument. It is NOT
7
+ # vulnerable to the same trigger, because the captured statement is embedded
8
+ # in a DOUBLE-quoted shell argument while its own internal quoting uses
9
+ # single quotes (`ENCODING 'UTF8'`) -- single quotes are not shell-special
10
+ # inside double quotes, so they cannot terminate the argument early the way
11
+ # they did for MySQL's single-quoted `-e` argument. See the PR description
12
+ # for the full analysis.
13
+ #
14
+ # It DID share the other half of defect A's pattern, though: neither
15
+ # drop_database nor the final recreate call checked $? at all, so a failed
16
+ # recreate after a successful drop would silently leave the database
17
+ # dropped. These specs cover the exit-status hardening added for that.
18
+ #
19
+ # Same loading strategy as mysql_engine_spec.rb: avoids lib/ey_backup.rb's
20
+ # ey-flex/NextGem dependency chain, uses a fake `psql`/`dropdb`/`createdb`
21
+ # on PATH instead of a real PostgreSQL server, and uses modern rspec syntax.
22
+
23
+ require 'forwardable'
24
+ require 'stringio'
25
+ require 'fileutils'
26
+ require 'tmpdir'
27
+
28
+ module EY
29
+ module Backup
30
+ class << self
31
+ attr_accessor :logger, :tmp_dir, :log_dir
32
+ end
33
+
34
+ class Logger
35
+ extend Forwardable
36
+ attr_reader :stdout, :stderr
37
+ alias_method :fatal, :abort
38
+ public :fatal
39
+ def_delegator :stdout, :puts, :puts
40
+
41
+ def initialize(stdout = $stdout, stderr = $stderr)
42
+ @stdout, @stderr = stdout, stderr
43
+ end
44
+
45
+ def info(msg); stdout.puts("#{Time.now} #{msg}"); end
46
+ def warn(msg, db = nil); stdout.puts("#{Time.now} WARNING: #{msg}"); end
47
+ def error(msg, db = nil); stdout.puts("#{Time.now} ERROR: #{msg}"); end
48
+ def verbose(msg); end
49
+ def debug(msg); stdout.puts("#{Time.now} DEBUG: #{msg}"); end
50
+ def say(msg, newline = true); newline ? info(msg) : stdout.print(msg); end
51
+ end
52
+
53
+ module Logging
54
+ extend Forwardable
55
+ def_delegator EY::Backup, :logger
56
+ def_delegators :logger, :fatal, :error, :warn, :info, :verbose, :debug, :say
57
+ end
58
+ end
59
+ end
60
+
61
+ EY::Backup.logger = EY::Backup::Logger.new(StringIO.new, StringIO.new)
62
+
63
+ lib_dir = File.expand_path(File.dirname(__FILE__) + '/../../lib/ey_backup')
64
+ require lib_dir + '/spawner'
65
+ require lib_dir + '/base'
66
+ require lib_dir + '/engine'
67
+ require lib_dir + '/engines/postgresql_engine'
68
+
69
+ # ---- Fake psql / dropdb / createdb ---------------------------------------
70
+
71
+ FAKE_PSQL_SCRIPT = <<~'SCRIPT'
72
+ #!/usr/bin/env bash
73
+ # Route by the -c argument content:
74
+ # - contains "SELECT 'CREATE DATABASE" => the create_command probe
75
+ # - contains "select count(*)" => check_connections probe
76
+ # - otherwise => the final recreate DDL execution
77
+ cflag=""
78
+ has_c=0
79
+ for arg in "$@"; do
80
+ if [ "$has_c" = "1" ]; then
81
+ cflag="$arg"
82
+ break
83
+ fi
84
+ if [ "$arg" = "-c" ]; then
85
+ has_c=1
86
+ fi
87
+ done
88
+
89
+ case "$cflag" in
90
+ *"select count(*)"*)
91
+ printf '%s' "${FAKE_PSQL_CONN_COUNT:-0}"
92
+ exit 0
93
+ ;;
94
+ *"SELECT 'CREATE DATABASE"*)
95
+ printf '%s' "$FAKE_PSQL_CREATE_COMMAND_OUTPUT"
96
+ exit "${FAKE_PSQL_CREATE_COMMAND_EXIT:-0}"
97
+ ;;
98
+ *)
99
+ # Final CREATE DATABASE execution
100
+ exit "${FAKE_PSQL_RECREATE_EXIT:-0}"
101
+ ;;
102
+ esac
103
+ SCRIPT
104
+
105
+ FAKE_DROPDB_SCRIPT = <<~'SCRIPT'
106
+ #!/usr/bin/env bash
107
+ exit "${FAKE_DROPDB_EXIT:-0}"
108
+ SCRIPT
109
+
110
+ FAKE_CREATEDB_SCRIPT = <<~'SCRIPT'
111
+ #!/usr/bin/env bash
112
+ exit "${FAKE_CREATEDB_EXIT:-0}"
113
+ SCRIPT
114
+
115
+ RSpec.describe EY::Backup::Postgresql do
116
+ around(:each) do |example|
117
+ @fake_bin_dir = Dir.mktmpdir('fake-psql-bin')
118
+ { 'psql' => FAKE_PSQL_SCRIPT, 'dropdb' => FAKE_DROPDB_SCRIPT, 'createdb' => FAKE_CREATEDB_SCRIPT }.each do |name, script|
119
+ path = File.join(@fake_bin_dir, name)
120
+ File.write(path, script)
121
+ FileUtils.chmod('+x', path)
122
+ end
123
+
124
+ original_path = ENV['PATH']
125
+ ENV['PATH'] = "#{@fake_bin_dir}:#{original_path}"
126
+ begin
127
+ example.run
128
+ ensure
129
+ ENV['PATH'] = original_path
130
+ %w[
131
+ FAKE_PSQL_CONN_COUNT FAKE_PSQL_CREATE_COMMAND_OUTPUT
132
+ FAKE_PSQL_CREATE_COMMAND_EXIT FAKE_PSQL_RECREATE_EXIT
133
+ FAKE_DROPDB_EXIT FAKE_CREATEDB_EXIT
134
+ ].each { |k| ENV.delete(k) }
135
+ FileUtils.remove_entry(@fake_bin_dir)
136
+ end
137
+ end
138
+
139
+ let(:engine) do
140
+ described_class.new('postgres', 'pw', 'localhost', nil, true, false, false, false)
141
+ end
142
+
143
+ describe '#cycle_database' do
144
+ context 'database does not yet exist (create_command returns empty)' do
145
+ it 'creates it and does not raise when createdb succeeds' do
146
+ ENV['FAKE_PSQL_CREATE_COMMAND_OUTPUT'] = ''
147
+ ENV['FAKE_CREATEDB_EXIT'] = '0'
148
+
149
+ expect { engine.cycle_database('newdb') }.not_to raise_error
150
+ end
151
+
152
+ it 'raises if createdb fails' do
153
+ ENV['FAKE_PSQL_CREATE_COMMAND_OUTPUT'] = ''
154
+ ENV['FAKE_CREATEDB_EXIT'] = '1'
155
+
156
+ expect { engine.cycle_database('newdb') }.to raise_error(/Failed to create database/)
157
+ end
158
+ end
159
+
160
+ context 'database exists (normal restore path)' do
161
+ it 'drops then recreates without raising on success' do
162
+ ENV['FAKE_PSQL_CONN_COUNT'] = '0'
163
+ ENV['FAKE_PSQL_CREATE_COMMAND_OUTPUT'] = "CREATE DATABASE myapp WITH OWNER deploy ENCODING 'UTF8' LC_COLLATE 'en_US.UTF-8' LC_CTYPE 'en_US.UTF-8' CONNECTION LIMIT -1;"
164
+ ENV['FAKE_DROPDB_EXIT'] = '0'
165
+ ENV['FAKE_PSQL_RECREATE_EXIT'] = '0'
166
+
167
+ expect { engine.cycle_database('myapp') }.not_to raise_error
168
+ end
169
+
170
+ it 'raises and does not attempt to recreate if dropdb fails' do
171
+ ENV['FAKE_PSQL_CONN_COUNT'] = '0'
172
+ ENV['FAKE_PSQL_CREATE_COMMAND_OUTPUT'] = "CREATE DATABASE myapp WITH OWNER deploy ENCODING 'UTF8';"
173
+ ENV['FAKE_DROPDB_EXIT'] = '1'
174
+
175
+ expect { engine.cycle_database('myapp') }.to raise_error(/Failed to drop database/)
176
+ end
177
+
178
+ it 'raises clearly (dropped-but-not-recreated) if the final recreate fails after a successful drop' do
179
+ ENV['FAKE_PSQL_CONN_COUNT'] = '0'
180
+ ENV['FAKE_PSQL_CREATE_COMMAND_OUTPUT'] = "CREATE DATABASE myapp WITH OWNER deploy ENCODING 'UTF8';"
181
+ ENV['FAKE_DROPDB_EXIT'] = '0'
182
+ ENV['FAKE_PSQL_RECREATE_EXIT'] = '1'
183
+
184
+ expect { engine.cycle_database('myapp') }.to raise_error(/dropped and NOT recreated/)
185
+ end
186
+ end
187
+ end
188
+ end
data/spec/helpers.rb CHANGED
@@ -18,7 +18,7 @@ module Helpers
18
18
  FakeWeb.register_uri(:post, "http://example.org/api/environments", :body => JSON.generate({
19
19
  @mock_environment_name => {:id => 1}
20
20
  }))
21
-
21
+
22
22
  create_or_clean_dir(tmp_dir)
23
23
  create_or_clean_dir(log_dir)
24
24
 
@@ -29,7 +29,7 @@ module Helpers
29
29
  # end
30
30
  stub_configs
31
31
  end
32
-
32
+
33
33
  def create_or_clean_dir(dir)
34
34
  FileUtils.mkdir_p(dir)
35
35
  Dir.glob("#{dir}/*").each do |f|
@@ -48,6 +48,9 @@ module Helpers
48
48
  end
49
49
 
50
50
  def import_gpg
51
+ # GPG v2.1+ dropped support for the --secret-keyring option (https://lists.gnupg.org/pipermail/gnupg-devel/2014-December/029296.html)
52
+ # This means that we need to import private keys too
53
+ system("gpg --import #{PRIVATE_KEY_PATH}") || raise("Could not import public key")
51
54
  system("gpg --import #{PUBLIC_KEY_PATH}") || raise("Could not import public key")
52
55
  end
53
56
 
@@ -91,7 +94,7 @@ module Helpers
91
94
  def backup_config_file
92
95
  "#{tmp_dir}/spec_backups.yml"
93
96
  end
94
-
97
+
95
98
  def mk_tmp
96
99
  FileUtils.mkdir_p("/tmp")
97
100
  end
@@ -113,7 +116,7 @@ module Helpers
113
116
  write_database_config('mysql', mysql_user, mysql_password, mysql_host, created_mysql_dbs.values, region)
114
117
  db_name
115
118
  end
116
-
119
+
117
120
  def drop_mysql_database(db_name)
118
121
  command = %Q{mysql -u#{mysql_user} -h#{mysql_host} #{mysql_password_option} -e "drop database if exists #{db_name};"}
119
122
  puts "*** MySQL Drop Command: #{command}"
@@ -194,7 +197,7 @@ module Helpers
194
197
  spec_config['tmp_dir'] || File.dirname("./tmp/")
195
198
  end
196
199
  end
197
-
200
+
198
201
  def log_dir
199
202
  if spec_config['log_dir'].nil?
200
203
  File.dirname(__FILE__) + "/log/"
@@ -299,7 +302,7 @@ module Helpers
299
302
  def stdout
300
303
  EY::Backup.logger.stdout.string
301
304
  end
302
-
305
+
303
306
  def stderr
304
307
  EY::Backup.logger.stderr.string
305
308
  end
data/spec/spec_helper.rb CHANGED
@@ -1,5 +1,8 @@
1
1
  require File.dirname(__FILE__) + "/../lib/ey-flex"
2
2
 
3
+ require 'simplecov'
4
+ SimpleCov.start
5
+
3
6
  require 'fakeweb'
4
7
  require 'fakefs/safe'
5
8
  require 'randexp'
metadata CHANGED
@@ -1,179 +1,173 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: ey_cloud_server
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.4.61
4
+ version: 1.5.1
5
5
  platform: ruby
6
6
  authors:
7
7
  - EngineYard
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2017-08-29 00:00:00.000000000 Z
11
+ date: 2026-08-29 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: json
15
15
  requirement: !ruby/object:Gem::Requirement
16
16
  requirements:
17
- - - ! '>='
17
+ - - "~>"
18
18
  - !ruby/object:Gem::Version
19
- version: 1.5.5
19
+ version: 2.6.1
20
20
  type: :runtime
21
21
  prerelease: false
22
22
  version_requirements: !ruby/object:Gem::Requirement
23
23
  requirements:
24
- - - ! '>='
24
+ - - "~>"
25
25
  - !ruby/object:Gem::Version
26
- version: 1.5.5
26
+ version: 2.6.1
27
27
  - !ruby/object:Gem::Dependency
28
28
  name: open4
29
29
  requirement: !ruby/object:Gem::Requirement
30
30
  requirements:
31
- - - ~>
31
+ - - "~>"
32
32
  - !ruby/object:Gem::Version
33
33
  version: 1.3.0
34
34
  type: :runtime
35
35
  prerelease: false
36
36
  version_requirements: !ruby/object:Gem::Requirement
37
37
  requirements:
38
- - - ~>
38
+ - - "~>"
39
39
  - !ruby/object:Gem::Version
40
40
  version: 1.3.0
41
41
  - !ruby/object:Gem::Dependency
42
42
  name: nokogiri
43
43
  requirement: !ruby/object:Gem::Requirement
44
44
  requirements:
45
- - - ! '>='
45
+ - - ">="
46
46
  - !ruby/object:Gem::Version
47
47
  version: 1.6.6.2
48
- - - <=
48
+ - - "<="
49
49
  - !ruby/object:Gem::Version
50
50
  version: 1.6.8.1
51
51
  type: :runtime
52
52
  prerelease: false
53
53
  version_requirements: !ruby/object:Gem::Requirement
54
54
  requirements:
55
- - - ! '>='
55
+ - - ">="
56
56
  - !ruby/object:Gem::Version
57
57
  version: 1.6.6.2
58
- - - <=
58
+ - - "<="
59
59
  - !ruby/object:Gem::Version
60
60
  version: 1.6.8.1
61
61
  - !ruby/object:Gem::Dependency
62
62
  name: mime-types
63
63
  requirement: !ruby/object:Gem::Requirement
64
64
  requirements:
65
- - - ! '>='
65
+ - - ">="
66
66
  - !ruby/object:Gem::Version
67
- version: '1.16'
68
- - - <
69
- - !ruby/object:Gem::Version
70
- version: '3.0'
67
+ version: 3.3.1
71
68
  type: :runtime
72
69
  prerelease: false
73
70
  version_requirements: !ruby/object:Gem::Requirement
74
71
  requirements:
75
- - - ! '>='
76
- - !ruby/object:Gem::Version
77
- version: '1.16'
78
- - - <
72
+ - - ">="
79
73
  - !ruby/object:Gem::Version
80
- version: '3.0'
74
+ version: 3.3.1
81
75
  - !ruby/object:Gem::Dependency
82
76
  name: fog-aws
83
77
  requirement: !ruby/object:Gem::Requirement
84
78
  requirements:
85
- - - ! '>='
79
+ - - ">="
86
80
  - !ruby/object:Gem::Version
87
81
  version: 1.2.1
88
82
  type: :runtime
89
83
  prerelease: false
90
84
  version_requirements: !ruby/object:Gem::Requirement
91
85
  requirements:
92
- - - ! '>='
86
+ - - ">="
93
87
  - !ruby/object:Gem::Version
94
88
  version: 1.2.1
95
89
  - !ruby/object:Gem::Dependency
96
90
  name: ey_enzyme
97
91
  requirement: !ruby/object:Gem::Requirement
98
92
  requirements:
99
- - - ! '>='
93
+ - - "~>"
100
94
  - !ruby/object:Gem::Version
101
- version: 1.1.10
95
+ version: 2.0.7pre1
102
96
  type: :runtime
103
97
  prerelease: false
104
98
  version_requirements: !ruby/object:Gem::Requirement
105
99
  requirements:
106
- - - ! '>='
100
+ - - "~>"
107
101
  - !ruby/object:Gem::Version
108
- version: 1.1.10
102
+ version: 2.0.7pre1
109
103
  - !ruby/object:Gem::Dependency
110
104
  name: ey_instance_api_client
111
105
  requirement: !ruby/object:Gem::Requirement
112
106
  requirements:
113
- - - ~>
107
+ - - "~>"
114
108
  - !ruby/object:Gem::Version
115
109
  version: 0.1.11
116
110
  type: :runtime
117
111
  prerelease: false
118
112
  version_requirements: !ruby/object:Gem::Requirement
119
113
  requirements:
120
- - - ~>
114
+ - - "~>"
121
115
  - !ruby/object:Gem::Version
122
116
  version: 0.1.11
123
117
  - !ruby/object:Gem::Dependency
124
118
  name: rake
125
119
  requirement: !ruby/object:Gem::Requirement
126
120
  requirements:
127
- - - ~>
121
+ - - "~>"
128
122
  - !ruby/object:Gem::Version
129
123
  version: 10.4.2
130
124
  type: :development
131
125
  prerelease: false
132
126
  version_requirements: !ruby/object:Gem::Requirement
133
127
  requirements:
134
- - - ~>
128
+ - - "~>"
135
129
  - !ruby/object:Gem::Version
136
130
  version: 10.4.2
137
131
  - !ruby/object:Gem::Dependency
138
132
  name: rspec
139
133
  requirement: !ruby/object:Gem::Requirement
140
134
  requirements:
141
- - - ~>
135
+ - - "~>"
142
136
  - !ruby/object:Gem::Version
143
137
  version: '2.0'
144
138
  type: :development
145
139
  prerelease: false
146
140
  version_requirements: !ruby/object:Gem::Requirement
147
141
  requirements:
148
- - - ~>
142
+ - - "~>"
149
143
  - !ruby/object:Gem::Version
150
144
  version: '2.0'
151
145
  - !ruby/object:Gem::Dependency
152
146
  name: randexp
153
147
  requirement: !ruby/object:Gem::Requirement
154
148
  requirements:
155
- - - ~>
149
+ - - "~>"
156
150
  - !ruby/object:Gem::Version
157
151
  version: 0.1.7
158
152
  type: :development
159
153
  prerelease: false
160
154
  version_requirements: !ruby/object:Gem::Requirement
161
155
  requirements:
162
- - - ~>
156
+ - - "~>"
163
157
  - !ruby/object:Gem::Version
164
158
  version: 0.1.7
165
159
  - !ruby/object:Gem::Dependency
166
160
  name: cucumber
167
161
  requirement: !ruby/object:Gem::Requirement
168
162
  requirements:
169
- - - ~>
163
+ - - "~>"
170
164
  - !ruby/object:Gem::Version
171
165
  version: 2.4.0
172
166
  type: :development
173
167
  prerelease: false
174
168
  version_requirements: !ruby/object:Gem::Requirement
175
169
  requirements:
176
- - - ~>
170
+ - - "~>"
177
171
  - !ruby/object:Gem::Version
178
172
  version: 2.4.0
179
173
  - !ruby/object:Gem::Dependency
@@ -208,16 +202,30 @@ dependencies:
208
202
  name: bundler
209
203
  requirement: !ruby/object:Gem::Requirement
210
204
  requirements:
211
- - - ~>
205
+ - - "~>"
212
206
  - !ruby/object:Gem::Version
213
207
  version: 1.13.7
214
208
  type: :development
215
209
  prerelease: false
216
210
  version_requirements: !ruby/object:Gem::Requirement
217
211
  requirements:
218
- - - ~>
212
+ - - "~>"
219
213
  - !ruby/object:Gem::Version
220
214
  version: 1.13.7
215
+ - !ruby/object:Gem::Dependency
216
+ name: simplecov
217
+ requirement: !ruby/object:Gem::Requirement
218
+ requirements:
219
+ - - "~>"
220
+ - !ruby/object:Gem::Version
221
+ version: 0.16.1
222
+ type: :development
223
+ prerelease: false
224
+ version_requirements: !ruby/object:Gem::Requirement
225
+ requirements:
226
+ - - "~>"
227
+ - !ruby/object:Gem::Version
228
+ version: 0.16.1
221
229
  description: Miscellaneous EY server utilities
222
230
  email:
223
231
  - engineering@engineyard.com
@@ -267,19 +275,20 @@ files:
267
275
  - lib/ey_cloud_server/version.rb
268
276
  - spec/bucket_minder_spec.rb
269
277
  - spec/config-example.yml
270
- - spec/config.yml
278
+ - spec/config.yml.ci
271
279
  - spec/ey_api_spec.rb
272
280
  - spec/ey_backup/backend_spec.rb
273
281
  - spec/ey_backup/backup_spec.rb
274
282
  - spec/ey_backup/cli_spec.rb
275
283
  - spec/ey_backup/mysql_backups_spec.rb
284
+ - spec/ey_backup/mysql_engine_spec.rb
276
285
  - spec/ey_backup/postgres_backups_spec.rb
286
+ - spec/ey_backup/postgresql_engine_spec.rb
277
287
  - spec/ey_backup/spec_helper.rb
278
288
  - spec/fakefs_hax.rb
279
289
  - spec/gpg.public
280
290
  - spec/gpg.sekrit
281
291
  - spec/helpers.rb
282
- - spec/log/ey_flex_postgresql_db_thecae.sizes
283
292
  - spec/snapshot_minder_spec.rb
284
293
  - spec/spec_helper.rb
285
294
  homepage: http://developer.engineyard.com
@@ -291,36 +300,36 @@ require_paths:
291
300
  - lib
292
301
  required_ruby_version: !ruby/object:Gem::Requirement
293
302
  requirements:
294
- - - ! '>='
303
+ - - ">="
295
304
  - !ruby/object:Gem::Version
296
305
  version: '0'
297
306
  required_rubygems_version: !ruby/object:Gem::Requirement
298
307
  requirements:
299
- - - ! '>='
308
+ - - ">="
300
309
  - !ruby/object:Gem::Version
301
310
  version: '0'
302
311
  requirements: []
303
- rubyforge_project:
304
- rubygems_version: 2.4.5
312
+ rubygems_version: 3.2.33
305
313
  signing_key:
306
314
  specification_version: 4
307
315
  summary: Server side components for Engine Yard's cloud
308
316
  test_files:
309
317
  - spec/bucket_minder_spec.rb
310
318
  - spec/config-example.yml
311
- - spec/config.yml
319
+ - spec/config.yml.ci
312
320
  - spec/ey_api_spec.rb
313
321
  - spec/ey_backup/backend_spec.rb
314
322
  - spec/ey_backup/backup_spec.rb
315
323
  - spec/ey_backup/cli_spec.rb
316
324
  - spec/ey_backup/mysql_backups_spec.rb
325
+ - spec/ey_backup/mysql_engine_spec.rb
317
326
  - spec/ey_backup/postgres_backups_spec.rb
327
+ - spec/ey_backup/postgresql_engine_spec.rb
318
328
  - spec/ey_backup/spec_helper.rb
319
329
  - spec/fakefs_hax.rb
320
330
  - spec/gpg.public
321
331
  - spec/gpg.sekrit
322
332
  - spec/helpers.rb
323
- - spec/log/ey_flex_postgresql_db_thecae.sizes
324
333
  - spec/snapshot_minder_spec.rb
325
334
  - spec/spec_helper.rb
326
335
  - features/downloading_a_mysql_backup.feature
data/spec/config.yml DELETED
@@ -1,12 +0,0 @@
1
- ---
2
- tmp_dir:
3
- log_dir:
4
- data_json:
5
- mysql_user: root
6
- mysql_password:
7
- mysql_host: localhost
8
- postgresql_user: postgres
9
- postgresql_password: grew152
10
- postgresql_host: localhost
11
- aws_secret_id: 'AKIAIDNXVLT3THIWYMNQ'
12
- aws_secret_key: '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'
@@ -1 +0,0 @@
1
- 2017-08-29 15:44:07 -0400 1.7 KB