ey_cloud_server 1.4.26 → 1.4.28.pre
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.
- data/bin/binary_log_purge +5 -3
- data/lib/ey_backup/cli.rb +5 -1
- data/lib/ey_backup/engines/mongodb_engine.rb +64 -0
- data/lib/ey_backup/engines/postgresql_engine.rb +4 -4
- data/lib/ey_backup.rb +1 -0
- data/lib/ey_cloud_server/version.rb +1 -1
- data/spec/config-example.yml +3 -0
- data/spec/ey_backup/mongo_backups_spec.rb +106 -0
- data/spec/ey_backup/postgres_backups_spec.rb +1 -1
- data/spec/helpers.rb +43 -1
- metadata +15 -9
data/bin/binary_log_purge
CHANGED
@@ -20,10 +20,12 @@
|
|
20
20
|
# Changelog 0.4 -> 1.0
|
21
21
|
# - Add automatic create user for master to connect to replica
|
22
22
|
|
23
|
-
|
23
|
+
# Changelog 1.0 -> 1.1
|
24
|
+
# - Remove unecessary require of mysql
|
25
|
+
# - Remove -N from mysql command line (drops header row) for compatibility with 5.1 and 5.5
|
24
26
|
|
27
|
+
require 'rubygems'
|
25
28
|
require 'net/smtp'
|
26
|
-
require 'mysql'
|
27
29
|
require 'yaml'
|
28
30
|
require 'open3'
|
29
31
|
require 'getoptlong'
|
@@ -103,7 +105,7 @@ def run_query(host, user, password, query)
|
|
103
105
|
if query == 'show processlist'
|
104
106
|
stdin, stdout, stderr = Open3.popen3("mysql -u#{user} -p#{password} #{options} -h#{host} -N -e\"#{query}\"|grep 'Binlog'")
|
105
107
|
else
|
106
|
-
stdin, stdout, stderr = Open3.popen3("mysql -u#{user} -p#{password} #{options} -h#{host} -
|
108
|
+
stdin, stdout, stderr = Open3.popen3("mysql -u#{user} -p#{password} #{options} -h#{host} -e\"#{query}\"")
|
107
109
|
end
|
108
110
|
query_error = stderr.read
|
109
111
|
if query_error.length > 0
|
data/lib/ey_backup/cli.rb
CHANGED
@@ -46,6 +46,10 @@ module EY
|
|
46
46
|
options[:config] = config
|
47
47
|
end
|
48
48
|
|
49
|
+
opts.on("-b", "--bucket BUCKET", "Override default S3 bucket name. (Be Careful!)") do |bucket|
|
50
|
+
options[:backup_bucket] = bucket
|
51
|
+
end
|
52
|
+
|
49
53
|
opts.on("-t", "--tmp_dir TMPDIR", "Use the given directory for temporary storage.") do |tmp_dir|
|
50
54
|
options[:tmp_dir] = tmp_dir
|
51
55
|
end
|
@@ -57,7 +61,7 @@ module EY
|
|
57
61
|
options[:db] = db
|
58
62
|
end
|
59
63
|
|
60
|
-
opts.on("-e", "--engine DATABASE_ENGINE", "The database engine. ex: mysql, postgres.") do |engine|
|
64
|
+
opts.on("-e", "--engine DATABASE_ENGINE", "The database engine. ex: mysql, postgres, mongodb.") do |engine|
|
61
65
|
options[:engine] = engine
|
62
66
|
end
|
63
67
|
|
@@ -0,0 +1,64 @@
|
|
1
|
+
module EY
|
2
|
+
module Backup
|
3
|
+
class Mongodb < Engine
|
4
|
+
register 'mongodb'
|
5
|
+
|
6
|
+
def dump(database_name, basename)
|
7
|
+
# Mongo dumps in directories. Compressing
|
8
|
+
file = basename
|
9
|
+
|
10
|
+
command = "mongodump --host #{host} -o #{file} --db #{database_name}; tar -cz #{file}"
|
11
|
+
|
12
|
+
if gpg?
|
13
|
+
command << " | " << GPGEncryptor.command_for(key_id)
|
14
|
+
file << GPGEncryptor.extension
|
15
|
+
end
|
16
|
+
|
17
|
+
command << " > #{file}"
|
18
|
+
|
19
|
+
run(command)
|
20
|
+
|
21
|
+
file
|
22
|
+
end
|
23
|
+
|
24
|
+
def load(database_name, file)
|
25
|
+
if database_exists?(database_name)
|
26
|
+
cycle_database(database_name)
|
27
|
+
else
|
28
|
+
create_database(database_name)
|
29
|
+
end
|
30
|
+
|
31
|
+
command = "cat #{file}"
|
32
|
+
|
33
|
+
if gpg?
|
34
|
+
raise "Cannot load a GPG backup"
|
35
|
+
end
|
36
|
+
|
37
|
+
command << " | mongorestore --host #{host} --db #{database_name}"
|
38
|
+
|
39
|
+
run(command)
|
40
|
+
end
|
41
|
+
|
42
|
+
def database_exists?(database_name)
|
43
|
+
runs?("mongo --host #{host} --quiet --eval \"for each(var db in db.runCommand('listDatabases').databases) if(db.sizeOnDisk > 1) print(db.name);\" admin | grep '#{database_name}'")
|
44
|
+
end
|
45
|
+
|
46
|
+
def drop_database(database_name)
|
47
|
+
runs?("mongo --host #{host} #{database_name} --quiet --eval 'printjson(db.dropDatabase());'")
|
48
|
+
end
|
49
|
+
|
50
|
+
def create_database(database_name)
|
51
|
+
runs?("mongo --host #{host} #{database_name} --quiet --eval 'db.createCollection('ey_backup');'")
|
52
|
+
end
|
53
|
+
|
54
|
+
def cycle_database(database_name)
|
55
|
+
drop_database(database_name)
|
56
|
+
create_database(database_name)
|
57
|
+
end
|
58
|
+
|
59
|
+
def suffix
|
60
|
+
/\.(gz)$/
|
61
|
+
end
|
62
|
+
end
|
63
|
+
end
|
64
|
+
end
|
@@ -4,9 +4,9 @@ module EY
|
|
4
4
|
register 'postgresql'
|
5
5
|
|
6
6
|
def dump(database_name, basename)
|
7
|
-
file = basename + '.
|
7
|
+
file = basename + '.dump'
|
8
8
|
|
9
|
-
command = "PGPASSWORD='#{password}' pg_dump -h #{host} --format=c --no-owner --no-privileges -
|
9
|
+
command = "PGPASSWORD='#{password}' pg_dump -h #{host} --format=c --no-owner --no-privileges -Upostgres #{database_name}"
|
10
10
|
|
11
11
|
if gpg?
|
12
12
|
command << " | " << GPGEncryptor.command_for(key_id)
|
@@ -33,7 +33,7 @@ module EY
|
|
33
33
|
raise "Cannot load a GPG backup"
|
34
34
|
end
|
35
35
|
|
36
|
-
command << " | PGPASSWORD='#{password}' pg_restore -h #{host} --format=c --ignore-version -
|
36
|
+
command << " | PGPASSWORD='#{password}' pg_restore -h #{host} --format=c --ignore-version -Upostgres -d #{database_name}"
|
37
37
|
|
38
38
|
run(command)
|
39
39
|
end
|
@@ -56,7 +56,7 @@ module EY
|
|
56
56
|
end
|
57
57
|
|
58
58
|
def suffix
|
59
|
-
|
59
|
+
/\.(dump|gpz)$/
|
60
60
|
end
|
61
61
|
end
|
62
62
|
end
|
data/lib/ey_backup.rb
CHANGED
@@ -126,6 +126,7 @@ require lib_dir + '/backend'
|
|
126
126
|
|
127
127
|
require lib_dir + '/engines/mysql_engine'
|
128
128
|
require lib_dir + '/engines/postgresql_engine'
|
129
|
+
require lib_dir + '/engines/mongodb_engine'
|
129
130
|
|
130
131
|
require lib_dir + '/processors/gzipper'
|
131
132
|
require lib_dir + '/processors/splitter'
|
data/spec/config-example.yml
CHANGED
@@ -0,0 +1,106 @@
|
|
1
|
+
require File.dirname(__FILE__) + '/spec_helper'
|
2
|
+
|
3
|
+
describe "MongoDB Backups" do
|
4
|
+
before(:each) do
|
5
|
+
@db_name = create_mongodb_database('test')
|
6
|
+
end
|
7
|
+
|
8
|
+
it "makes a backup" do
|
9
|
+
EY::Backup.run(["-c", backup_config_file, "-e", "mongodb"])
|
10
|
+
|
11
|
+
reset_logger
|
12
|
+
|
13
|
+
EY::Backup.run(["-c", backup_config_file, "-l", @db_name, "-e", "mongodb"])
|
14
|
+
|
15
|
+
stdout.should match(/0:#{@db_name}/)
|
16
|
+
end
|
17
|
+
|
18
|
+
it "makes a split backup" do
|
19
|
+
EY::Backup.run(["-c", backup_config_file, "-e", "mongodb", "-s", "100"])
|
20
|
+
|
21
|
+
backup = EY::Backup.run(["-c", backup_config_file, "-e", "mongodb", "-l", @db_name]).first
|
22
|
+
backup.parts.should > 1
|
23
|
+
end
|
24
|
+
|
25
|
+
it "makes GPG encrypted backups" do
|
26
|
+
import_gpg
|
27
|
+
|
28
|
+
EY::Backup.run(["-c", backup_config_file, '-e', 'mongodb', '-k', Helpers::PUBLIC_KEY_ID])
|
29
|
+
|
30
|
+
EY::Backup.run(["-c", backup_config_file, '-e', 'mongodb', "-l", @db_name])
|
31
|
+
|
32
|
+
stdout.should match(/0:#{@db_name}/)
|
33
|
+
end
|
34
|
+
|
35
|
+
it "restores a backup" do
|
36
|
+
run_mongocmd("db.foo.save({name: 'John Foo', age: 30});", @db_name).should be_true
|
37
|
+
run_mongocmd("db.bar.save({name: 'John Bar', age: 20});", @db_name).should be_true
|
38
|
+
|
39
|
+
EY::Backup.run(["-c", backup_config_file, '-e', 'mongodb'])
|
40
|
+
|
41
|
+
run_mongocmd("db.bar.drop();", @db_name).should be_true
|
42
|
+
run_mongocmd("db.bar.find();", @db_name).should be_false
|
43
|
+
|
44
|
+
reset_logger
|
45
|
+
|
46
|
+
EY::Backup.run(["-c", backup_config_file, "-l", @db_name, '-e', 'mongodb'])
|
47
|
+
|
48
|
+
stdout.should include("1 backup(s) found")
|
49
|
+
|
50
|
+
EY::Backup.run(["-c", backup_config_file, "-r", "0:#{@db_name}", '-e', 'mongodb'])
|
51
|
+
|
52
|
+
run_mongocmd("db.foo.find();", @db_name).should be_true
|
53
|
+
run_mongocmd("db.bar.find();", @db_name).should be_true
|
54
|
+
end
|
55
|
+
|
56
|
+
it "restores split backups" do
|
57
|
+
run_mongocmd("db.foo.save({name: 'John Foo', age: 30});", @db_name).should be_true
|
58
|
+
run_mongocmd("db.bar.save({name: 'John Bar', age: 20});", @db_name).should be_true
|
59
|
+
|
60
|
+
EY::Backup.run(["-c", backup_config_file, "-e", "MongoDB", "-s", "100"])
|
61
|
+
EY::Backup.run(["-c", backup_config_file, "-e", "MongoDB", "-l", @db_name]).first.parts.should > 1
|
62
|
+
|
63
|
+
run_mongocmd("db.bar.drop();", @db_name).should be_true
|
64
|
+
run_mongocmd("db.bar.find();", @db_name).should be_false
|
65
|
+
|
66
|
+
EY::Backup.run(["-c", backup_config_file, "-l", @db_name, '-e', 'mongodb'])
|
67
|
+
|
68
|
+
stdout.should include("1 backup(s) found")
|
69
|
+
|
70
|
+
EY::Backup.run(["-c", backup_config_file, "-r", "0:#{@db_name}", '-e', 'mongodb'])
|
71
|
+
|
72
|
+
run_mongocmd("db.foo.find();", @db_name).should be_true
|
73
|
+
run_mongocmd("db.bar.find();", @db_name).should be_true
|
74
|
+
end
|
75
|
+
|
76
|
+
it "downloads a split backup to 1 file" do
|
77
|
+
run_mongocmd("db.foo.save({name: 'John Foo', age: 30});", @db_name).should be_true
|
78
|
+
run_mongocmd("db.bar.save({name: 'John Bar', age: 20});", @db_name).should be_true
|
79
|
+
|
80
|
+
EY::Backup.run(["-c", backup_config_file, "-e", "mongodb", "-s", "100"])
|
81
|
+
EY::Backup.run(["-c", backup_config_file, "-e", "mongodb", "-l", @db_name]).first.parts.should > 1
|
82
|
+
EY::Backup.run(["-c", backup_config_file, "-e", 'mongodb', "--download", "0:#{@db_name}"])
|
83
|
+
files = Dir["#{EY::Backup.tmp_dir}/*#{@db_name}*"]
|
84
|
+
|
85
|
+
files.size.should == 1
|
86
|
+
FileUtils.rm(files.first)
|
87
|
+
end
|
88
|
+
|
89
|
+
end
|
90
|
+
|
91
|
+
describe "MongoDB Backups" do
|
92
|
+
before(:each) do
|
93
|
+
@dbs = [create_mongodb_database('first'), create_mongodb_database('second')]
|
94
|
+
end
|
95
|
+
|
96
|
+
it "makes multiple backup" do
|
97
|
+
EY::Backup.run(["-c", backup_config_file, "-e", "mongodb"])
|
98
|
+
|
99
|
+
reset_logger
|
100
|
+
|
101
|
+
@dbs.each do |db_name|
|
102
|
+
EY::Backup.run(["-c", backup_config_file, "-l", db_name, '-e', 'mongodb'])
|
103
|
+
stdout.should match(/0:#{db_name}/)
|
104
|
+
end
|
105
|
+
end
|
106
|
+
end
|
@@ -12,7 +12,7 @@ describe "Postgres Backups" do
|
|
12
12
|
|
13
13
|
EY::Backup.run(["-c", backup_config_file, "-l", @db_name, "-e", "postgresql"])
|
14
14
|
|
15
|
-
stdout.should match(/0:#{@db_name}.*\.
|
15
|
+
stdout.should match(/0:#{@db_name}.*\.dump.gz$/)
|
16
16
|
end
|
17
17
|
|
18
18
|
it "makes a split backup" do
|
data/spec/helpers.rb
CHANGED
@@ -112,7 +112,7 @@ module Helpers
|
|
112
112
|
end
|
113
113
|
|
114
114
|
def create_postgresql_database(db_key, region = 'us-east-1')
|
115
|
-
db_name = generate_database_name('
|
115
|
+
db_name = generate_database_name('mongo')
|
116
116
|
created_postgresql_dbs[db_key] = db_name
|
117
117
|
drop_postgresql_database(db_key)
|
118
118
|
# ssh -F /dev/null -o CheckHostIP=no -o StrictHostKeyChecking=no -i /home/$USER/.ssh/internal root@$DB_HOST "createdb -U postgres -h localhost -O $USER testdbreallytestingweee8"
|
@@ -122,6 +122,28 @@ module Helpers
|
|
122
122
|
write_database_config('postgresql', postgresql_user, postgresql_password, postgresql_host, created_postgresql_dbs.values, region)
|
123
123
|
db_name
|
124
124
|
end
|
125
|
+
|
126
|
+
def drop_mongodb_database(db_key)
|
127
|
+
db_name = created_mongodb_dbs[db_key]
|
128
|
+
command=%Q{ssh -F /dev/null -o CheckHostIP=no -o StrictHostKeyChecking=no -i /home/#{mongodb_user}/.ssh/internal root@#{mongodb_host} "mongo --host localhost #{db_name} --quiet --eval 'printjson(db.dropDatabase());'"}
|
129
|
+
system(command)
|
130
|
+
end
|
131
|
+
|
132
|
+
def check_mongodb_database(db_name)
|
133
|
+
command=%Q{ssh -F /dev/null -o CheckHostIP=no -o StrictHostKeyChecking=no -i /home/#{mongodb_user}/.ssh/internal root@#{mongodb_host} "mongo --host localhost --quiet --eval "for each(var db in db.runCommand('listDatabases').databases) if(db.sizeOnDisk > 1) print(db.name);" admin | grep '#{db_name}'"}
|
134
|
+
system(command) || raise("Could not find db: #{db_name} with command:\n #{command}")
|
135
|
+
db_name
|
136
|
+
end
|
137
|
+
|
138
|
+
def create_mongodb_database(db_key, region = 'us-east-1')
|
139
|
+
db_name = generate_database_name('test')
|
140
|
+
drop_mongodb_database(db_key)
|
141
|
+
command=%Q{ssh -F /dev/null -o CheckHostIP=no -o StrictHostKeyChecking=no -i /home/#{mongodb_user}/.ssh/internal root@#{mongodb_host} "mongo --host localhost #{db_name} --quiet --eval 'db.foo.save({ name : "derp"});'"}
|
142
|
+
system(command) || raise("Could not create db: #{db_name} with command:\n #{command}")
|
143
|
+
write_database_config('mongodb', mongodb_user, mongodb_password, mongodb_host, created_mongodb_dbs.values, region)
|
144
|
+
db_name
|
145
|
+
end
|
146
|
+
|
125
147
|
|
126
148
|
def write_database_config(type, root_user, root_password, host, databases, region)
|
127
149
|
@database_config = {
|
@@ -167,6 +189,10 @@ module Helpers
|
|
167
189
|
system("PGPASSWORD='#{postgresql_password}' psql -c '#{command}' -h #{postgresql_host} -U #{postgresql_user} #{database}")
|
168
190
|
end
|
169
191
|
|
192
|
+
def run_mongocmd(command, database)
|
193
|
+
system("mongo #{database} --quiet --eval \"#{command}\" --quiet")
|
194
|
+
end
|
195
|
+
|
170
196
|
def tmp_dir
|
171
197
|
if spec_config['tmp_dir'].blank?
|
172
198
|
File.dirname(__FILE__) + "/tmp/"
|
@@ -183,6 +209,10 @@ module Helpers
|
|
183
209
|
spec_config['postgresql_user'] || raise("No postgresql user provided")
|
184
210
|
end
|
185
211
|
|
212
|
+
def mongodb_user
|
213
|
+
spec_config['mongodb_user'] || raise("No mongodb user provided")
|
214
|
+
end
|
215
|
+
|
186
216
|
def mysql_password
|
187
217
|
spec_config['mysql_password']
|
188
218
|
end
|
@@ -191,6 +221,10 @@ module Helpers
|
|
191
221
|
spec_config['postgresql_password']
|
192
222
|
end
|
193
223
|
|
224
|
+
def mongodb_password #<- is this really needed? Supported mongo will run in trusted mode
|
225
|
+
spec_config['mongodb_password']
|
226
|
+
end
|
227
|
+
|
194
228
|
def mysql_host
|
195
229
|
spec_config['mysql_host']
|
196
230
|
end
|
@@ -199,6 +233,10 @@ module Helpers
|
|
199
233
|
spec_config['postgresql_host']
|
200
234
|
end
|
201
235
|
|
236
|
+
def mongodb_host
|
237
|
+
spec_config['mongodb_host']
|
238
|
+
end
|
239
|
+
|
202
240
|
def created_mysql_dbs
|
203
241
|
@created_mysql_dbs ||= {}
|
204
242
|
end
|
@@ -207,6 +245,10 @@ module Helpers
|
|
207
245
|
@created_postgresql_dbs ||= {}
|
208
246
|
end
|
209
247
|
|
248
|
+
def created_mongodb_dbs
|
249
|
+
@created_mongodb_dbs ||= {}
|
250
|
+
end
|
251
|
+
|
210
252
|
def spec_config
|
211
253
|
Helpers.spec_config
|
212
254
|
end
|
metadata
CHANGED
@@ -1,13 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: ey_cloud_server
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
hash:
|
5
|
-
prerelease:
|
4
|
+
hash: 961915908
|
5
|
+
prerelease: 7
|
6
6
|
segments:
|
7
7
|
- 1
|
8
8
|
- 4
|
9
|
-
-
|
10
|
-
|
9
|
+
- 28
|
10
|
+
- pre
|
11
|
+
version: 1.4.28.pre
|
11
12
|
platform: ruby
|
12
13
|
authors:
|
13
14
|
- Engine Yard
|
@@ -15,7 +16,7 @@ autorequire:
|
|
15
16
|
bindir: bin
|
16
17
|
cert_chain: []
|
17
18
|
|
18
|
-
date: 2011-
|
19
|
+
date: 2011-12-22 00:00:00 Z
|
19
20
|
dependencies:
|
20
21
|
- !ruby/object:Gem::Dependency
|
21
22
|
name: json
|
@@ -331,6 +332,7 @@ files:
|
|
331
332
|
- lib/ey_backup/database.rb
|
332
333
|
- lib/ey_backup/dumper.rb
|
333
334
|
- lib/ey_backup/engine.rb
|
335
|
+
- lib/ey_backup/engines/mongodb_engine.rb
|
334
336
|
- lib/ey_backup/engines/mysql_engine.rb
|
335
337
|
- lib/ey_backup/engines/postgresql_engine.rb
|
336
338
|
- lib/ey_backup/loader.rb
|
@@ -350,6 +352,7 @@ files:
|
|
350
352
|
- spec/ey_backup/backend_spec.rb
|
351
353
|
- spec/ey_backup/backup_spec.rb
|
352
354
|
- spec/ey_backup/cli_spec.rb
|
355
|
+
- spec/ey_backup/mongo_backups_spec.rb
|
353
356
|
- spec/ey_backup/mysql_backups_spec.rb
|
354
357
|
- spec/ey_backup/postgres_backups_spec.rb
|
355
358
|
- spec/ey_backup/spec_helper.rb
|
@@ -385,12 +388,14 @@ required_ruby_version: !ruby/object:Gem::Requirement
|
|
385
388
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
386
389
|
none: false
|
387
390
|
requirements:
|
388
|
-
- - "
|
391
|
+
- - ">"
|
389
392
|
- !ruby/object:Gem::Version
|
390
|
-
hash:
|
393
|
+
hash: 25
|
391
394
|
segments:
|
392
|
-
-
|
393
|
-
|
395
|
+
- 1
|
396
|
+
- 3
|
397
|
+
- 1
|
398
|
+
version: 1.3.1
|
394
399
|
requirements: []
|
395
400
|
|
396
401
|
rubyforge_project:
|
@@ -406,6 +411,7 @@ test_files:
|
|
406
411
|
- spec/ey_backup/backend_spec.rb
|
407
412
|
- spec/ey_backup/backup_spec.rb
|
408
413
|
- spec/ey_backup/cli_spec.rb
|
414
|
+
- spec/ey_backup/mongo_backups_spec.rb
|
409
415
|
- spec/ey_backup/mysql_backups_spec.rb
|
410
416
|
- spec/ey_backup/postgres_backups_spec.rb
|
411
417
|
- spec/ey_backup/spec_helper.rb
|