stratocumulus 0.0.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.
- data/.gitignore +17 -0
- data/.rspec +1 -0
- data/.rubocop.yml +6 -0
- data/.travis.yml +5 -0
- data/Gemfile +4 -0
- data/LICENSE.txt +22 -0
- data/README.md +19 -0
- data/Rakefile +9 -0
- data/bin/stratocumulus +17 -0
- data/lib/stratocumulus/database.rb +47 -0
- data/lib/stratocumulus/ext/io.rb +8 -0
- data/lib/stratocumulus/runner.rb +27 -0
- data/lib/stratocumulus/storage.rb +38 -0
- data/lib/stratocumulus/version.rb +4 -0
- data/lib/stratocumulus.rb +5 -0
- data/spec/ext/io_spec.rb +12 -0
- data/spec/intergration/database_spec.rb +29 -0
- data/spec/spec_helper.rb +24 -0
- data/spec/support/test.sql +15 -0
- data/spec/support/test_config_file.yml +18 -0
- data/spec/unit/database_spec.rb +185 -0
- data/spec/unit/runner_spec.rb +57 -0
- data/spec/unit/storage_spec.rb +59 -0
- data/stratocumulus.gemspec +26 -0
- metadata +165 -0
data/.gitignore
ADDED
data/.rspec
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
--color
|
data/.rubocop.yml
ADDED
data/.travis.yml
ADDED
data/Gemfile
ADDED
data/LICENSE.txt
ADDED
@@ -0,0 +1,22 @@
|
|
1
|
+
Copyright (c) 2014 Reevoo Developers
|
2
|
+
|
3
|
+
MIT License
|
4
|
+
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining
|
6
|
+
a copy of this software and associated documentation files (the
|
7
|
+
"Software"), to deal in the Software without restriction, including
|
8
|
+
without limitation the rights to use, copy, modify, merge, publish,
|
9
|
+
distribute, sublicense, and/or sell copies of the Software, and to
|
10
|
+
permit persons to whom the Software is furnished to do so, subject to
|
11
|
+
the following conditions:
|
12
|
+
|
13
|
+
The above copyright notice and this permission notice shall be
|
14
|
+
included in all copies or substantial portions of the Software.
|
15
|
+
|
16
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
17
|
+
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
18
|
+
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
19
|
+
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
20
|
+
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
21
|
+
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
22
|
+
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
data/README.md
ADDED
@@ -0,0 +1,19 @@
|
|
1
|
+
# Stratocumulus
|
2
|
+
|
3
|
+
Stratocumulus is for backing up databases to cloud storage
|
4
|
+
|
5
|
+
## Installation
|
6
|
+
|
7
|
+
$ gem install stratocumulus
|
8
|
+
|
9
|
+
## Usage
|
10
|
+
|
11
|
+
TODO: Write usage instructions here
|
12
|
+
|
13
|
+
## Contributing
|
14
|
+
|
15
|
+
1. Fork it ( http://github.com/reevoo/stratocumulus/fork )
|
16
|
+
2. Create your feature branch (`git checkout -b my-new-feature`)
|
17
|
+
3. Commit your changes (`git commit -am 'Add some feature'`)
|
18
|
+
4. Push to the branch (`git push origin my-new-feature`)
|
19
|
+
5. Create new Pull Request
|
data/Rakefile
ADDED
data/bin/stratocumulus
ADDED
@@ -0,0 +1,17 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
# encoding: UTF-8
|
3
|
+
|
4
|
+
require 'thor'
|
5
|
+
require 'stratocumulus'
|
6
|
+
|
7
|
+
module Stratocumulus
|
8
|
+
class Cli < Thor
|
9
|
+
desc 'backup CONFIG',
|
10
|
+
'runs a stratocumulus backup as specified in the config file'
|
11
|
+
def backup(config)
|
12
|
+
Stratocumulus::Runner.new(config).run
|
13
|
+
end
|
14
|
+
end
|
15
|
+
end
|
16
|
+
|
17
|
+
Stratocumulus::Cli.start
|
@@ -0,0 +1,47 @@
|
|
1
|
+
# encoding: UTF-8
|
2
|
+
|
3
|
+
module Stratocumulus
|
4
|
+
class Database
|
5
|
+
def initialize(options = {})
|
6
|
+
@username = options['username'] || 'root'
|
7
|
+
@password = options['password']
|
8
|
+
@name = options['name']
|
9
|
+
|
10
|
+
@host = options['host'] || 'localhost'
|
11
|
+
@port = options['port'] || 3306
|
12
|
+
|
13
|
+
check_dependencies(options['type'])
|
14
|
+
end
|
15
|
+
|
16
|
+
def dump
|
17
|
+
IO.popen("bash -c '#{pipefail} #{mysqldump_command} | gzip'")
|
18
|
+
end
|
19
|
+
|
20
|
+
def filename
|
21
|
+
"#{@name}/#{@name}.#{Time.now.utc.strftime('%Y%m%d%H%M')}.sql.gz"
|
22
|
+
end
|
23
|
+
|
24
|
+
private
|
25
|
+
|
26
|
+
def mysqldump_command
|
27
|
+
command = 'mysqldump '
|
28
|
+
command << '--single-transaction '
|
29
|
+
command << "-u#{@username} "
|
30
|
+
command << "-h#{@host} "
|
31
|
+
command << "-P#{@port} "
|
32
|
+
command << "-p#{@password} " if @password
|
33
|
+
command << @name
|
34
|
+
end
|
35
|
+
|
36
|
+
def pipefail
|
37
|
+
'set -o pipefail;'
|
38
|
+
end
|
39
|
+
|
40
|
+
def check_dependencies(type)
|
41
|
+
fail 'database name not specified' unless @name
|
42
|
+
fail "#{type} is not a supported database" unless type == 'mysql'
|
43
|
+
fail 'mysqldump not available' unless system('which mysqldump >/dev/null')
|
44
|
+
fail 'gzip not available' unless system('which gzip >/dev/null')
|
45
|
+
end
|
46
|
+
end
|
47
|
+
end
|
@@ -0,0 +1,27 @@
|
|
1
|
+
# encoding: UTF-8
|
2
|
+
|
3
|
+
module Stratocumulus
|
4
|
+
class Runner
|
5
|
+
def initialize(config_path)
|
6
|
+
@config = YAML.load(File.read(config_path))
|
7
|
+
end
|
8
|
+
|
9
|
+
def run
|
10
|
+
@config['databases'].each do |database_config|
|
11
|
+
database = Database.new(database_config)
|
12
|
+
upload(database, database_config['storage'])
|
13
|
+
end
|
14
|
+
end
|
15
|
+
|
16
|
+
private
|
17
|
+
|
18
|
+
def upload(database, storage_type)
|
19
|
+
fail "#{storage_type} is not supported" unless storage_type == 's3'
|
20
|
+
storage.upload(database)
|
21
|
+
end
|
22
|
+
|
23
|
+
def storage
|
24
|
+
@storage ||= Storage.new(@config['s3'])
|
25
|
+
end
|
26
|
+
end
|
27
|
+
end
|
@@ -0,0 +1,38 @@
|
|
1
|
+
# encoding: UTF-8
|
2
|
+
require 'fog'
|
3
|
+
require 'stratocumulus/ext/io'
|
4
|
+
|
5
|
+
module Stratocumulus
|
6
|
+
class Storage
|
7
|
+
def initialize(options = {})
|
8
|
+
@access_key_id = options.fetch('access_key_id')
|
9
|
+
@secret_access_key = options.fetch('secret_access_key')
|
10
|
+
@region = options['region']
|
11
|
+
@bucket = options.fetch('bucket')
|
12
|
+
end
|
13
|
+
|
14
|
+
def upload(database)
|
15
|
+
files.create(
|
16
|
+
key: database.filename,
|
17
|
+
body: database.dump,
|
18
|
+
multipart_chunk_size: 104_857_600, # 100MB
|
19
|
+
public: false
|
20
|
+
)
|
21
|
+
end
|
22
|
+
|
23
|
+
private
|
24
|
+
|
25
|
+
def connection
|
26
|
+
Fog::Storage.new(
|
27
|
+
provider: 'AWS',
|
28
|
+
aws_access_key_id: @access_key_id,
|
29
|
+
aws_secret_access_key: @secret_access_key,
|
30
|
+
region: @region
|
31
|
+
)
|
32
|
+
end
|
33
|
+
|
34
|
+
def files
|
35
|
+
connection.directories.get(@bucket).files
|
36
|
+
end
|
37
|
+
end
|
38
|
+
end
|
data/spec/ext/io_spec.rb
ADDED
@@ -0,0 +1,29 @@
|
|
1
|
+
# encoding: UTF-8
|
2
|
+
require 'spec_helper'
|
3
|
+
|
4
|
+
describe Stratocumulus::Database do
|
5
|
+
|
6
|
+
subject do
|
7
|
+
described_class.new(config)
|
8
|
+
end
|
9
|
+
|
10
|
+
let('config') do
|
11
|
+
{
|
12
|
+
'name' => 'stratocumulus_test',
|
13
|
+
'type' => 'mysql'
|
14
|
+
}
|
15
|
+
end
|
16
|
+
|
17
|
+
describe '#dump' do
|
18
|
+
before do
|
19
|
+
system('mysql -u root < spec/support/test.sql')
|
20
|
+
end
|
21
|
+
|
22
|
+
let(:dump) { Zlib::GzipReader.new(subject.dump).read }
|
23
|
+
|
24
|
+
it 'dumps a gziped copy of the database' do
|
25
|
+
expect(dump).to include('CREATE TABLE `widgets`')
|
26
|
+
expect(dump).to include("INSERT INTO `widgets` VALUES (1,'Foo',3,1,2)")
|
27
|
+
end
|
28
|
+
end
|
29
|
+
end
|
data/spec/spec_helper.rb
ADDED
@@ -0,0 +1,24 @@
|
|
1
|
+
# encoding: UTF-8
|
2
|
+
|
3
|
+
require 'bundler/setup'
|
4
|
+
Bundler.setup
|
5
|
+
|
6
|
+
require 'stratocumulus'
|
7
|
+
Fog.mock!
|
8
|
+
|
9
|
+
RSpec.configure do |config|
|
10
|
+
config.default_formatter = 'doc' if config.files_to_run.one?
|
11
|
+
|
12
|
+
config.profile_examples = 10
|
13
|
+
config.order = :random
|
14
|
+
Kernel.srand config.seed
|
15
|
+
|
16
|
+
config.expect_with :rspec do |expectations|
|
17
|
+
expectations.syntax = :expect
|
18
|
+
end
|
19
|
+
|
20
|
+
config.mock_with :rspec do |mocks|
|
21
|
+
mocks.syntax = :expect
|
22
|
+
mocks.verify_partial_doubles = true
|
23
|
+
end
|
24
|
+
end
|
@@ -0,0 +1,15 @@
|
|
1
|
+
DROP DATABASE IF EXISTS `stratocumulus_test`;
|
2
|
+
CREATE DATABASE `stratocumulus_test`;
|
3
|
+
USE `stratocumulus_test`;
|
4
|
+
DROP TABLE IF EXISTS `widgets`;
|
5
|
+
CREATE TABLE `widgets` (
|
6
|
+
`id` int(11) unsigned NOT NULL AUTO_INCREMENT,
|
7
|
+
`name` varchar(256) DEFAULT NULL,
|
8
|
+
`leavers` int(11) DEFAULT NULL,
|
9
|
+
`pivots` int(11) DEFAULT NULL,
|
10
|
+
`fulcrums` int(11) DEFAULT NULL,
|
11
|
+
PRIMARY KEY (`id`)
|
12
|
+
) ENGINE=InnoDB AUTO_INCREMENT=14 DEFAULT CHARSET=utf8;
|
13
|
+
LOCK TABLES `widgets` WRITE;
|
14
|
+
INSERT INTO `widgets` VALUES (1,'Foo',3,1,2),(2,'Bar',2,2,0),(3,'Baz',5,6,4),(4,'Qux',4,5,6),(5,'Quux',8,5,4),(6,'Corge',8,2,7),(7,'Grault',7,3,4),(8,'Garply',1,2,3),(9,'Waldo',0,0,0),(10,'Fred',1,1,1),(11,'Plugh',8,5,3),(12,'Xyzzy',3,3,3),(13,'Thud',1,2,3);
|
15
|
+
UNLOCK TABLES;
|
@@ -0,0 +1,18 @@
|
|
1
|
+
s3:
|
2
|
+
access_key_id: I_AM_THE_KEY_ID
|
3
|
+
secret_access_key: IamTHESekret
|
4
|
+
bucket: stratocumulus-test
|
5
|
+
region: eu-west1
|
6
|
+
databases:
|
7
|
+
-
|
8
|
+
type: mysql
|
9
|
+
name: stratocumulus_test
|
10
|
+
storage: s3
|
11
|
+
username: root
|
12
|
+
password: sekret
|
13
|
+
host: db1.example.com
|
14
|
+
port: 3307
|
15
|
+
-
|
16
|
+
type: mysql
|
17
|
+
name: stratocumulus_test_2
|
18
|
+
storage: s3
|
@@ -0,0 +1,185 @@
|
|
1
|
+
# encoding: UTF-8
|
2
|
+
require 'spec_helper'
|
3
|
+
|
4
|
+
describe Stratocumulus::Database do
|
5
|
+
|
6
|
+
subject do
|
7
|
+
described_class.new(config)
|
8
|
+
end
|
9
|
+
|
10
|
+
let(:config) { base_config }
|
11
|
+
|
12
|
+
let(:base_config) do
|
13
|
+
{
|
14
|
+
'name' => 'stratocumulus_test',
|
15
|
+
'type' => 'mysql'
|
16
|
+
}
|
17
|
+
end
|
18
|
+
|
19
|
+
before do
|
20
|
+
allow_any_instance_of(described_class).to receive(:system).and_return(true)
|
21
|
+
end
|
22
|
+
|
23
|
+
describe '.new' do
|
24
|
+
context 'the database type is not mysql' do
|
25
|
+
let(:config) { base_config.merge('type' => 'nosqlioid') }
|
26
|
+
|
27
|
+
it 'thows an error unless the type is mysql' do
|
28
|
+
expect { subject }.to raise_error(
|
29
|
+
RuntimeError,
|
30
|
+
'nosqlioid is not a supported database'
|
31
|
+
)
|
32
|
+
end
|
33
|
+
end
|
34
|
+
|
35
|
+
it 'throws an error if mysqldump is not installed' do
|
36
|
+
allow_any_instance_of(described_class)
|
37
|
+
.to receive(:system).with(/which mysqldump/)
|
38
|
+
|
39
|
+
expect { subject }.to raise_error(
|
40
|
+
RuntimeError,
|
41
|
+
'mysqldump not available'
|
42
|
+
)
|
43
|
+
end
|
44
|
+
|
45
|
+
it 'throws an error if gzip is not installed' do
|
46
|
+
allow_any_instance_of(described_class)
|
47
|
+
.to receive(:system).with(/which gzip/)
|
48
|
+
|
49
|
+
expect { subject }.to raise_error(
|
50
|
+
RuntimeError,
|
51
|
+
'gzip not available'
|
52
|
+
)
|
53
|
+
end
|
54
|
+
|
55
|
+
context 'when no database name is provided' do
|
56
|
+
|
57
|
+
let(:config) do
|
58
|
+
{ 'type' => 'mysql' }
|
59
|
+
end
|
60
|
+
|
61
|
+
it 'throws an error' do
|
62
|
+
expect { subject }.to raise_error(
|
63
|
+
RuntimeError,
|
64
|
+
'database name not specified'
|
65
|
+
)
|
66
|
+
end
|
67
|
+
|
68
|
+
end
|
69
|
+
end
|
70
|
+
|
71
|
+
describe 'dump' do
|
72
|
+
|
73
|
+
after do
|
74
|
+
subject.dump
|
75
|
+
end
|
76
|
+
|
77
|
+
describe 'username' do
|
78
|
+
context 'default' do
|
79
|
+
it 'uses root' do
|
80
|
+
expect(IO).to receive(:popen) do |command|
|
81
|
+
expect(command).to include(' -uroot ')
|
82
|
+
end
|
83
|
+
end
|
84
|
+
end
|
85
|
+
|
86
|
+
context 'setting the username' do
|
87
|
+
let(:config) { base_config.merge('username' => 'susan') }
|
88
|
+
|
89
|
+
it 'uses the correct username' do
|
90
|
+
expect(IO).to receive(:popen) do |command|
|
91
|
+
expect(command).to include(' -ususan ')
|
92
|
+
end
|
93
|
+
end
|
94
|
+
end
|
95
|
+
end
|
96
|
+
|
97
|
+
describe 'password' do
|
98
|
+
context 'default' do
|
99
|
+
it 'uses no password' do
|
100
|
+
expect(IO).to receive(:popen) do |command|
|
101
|
+
expect(command).to_not include('-p')
|
102
|
+
end
|
103
|
+
end
|
104
|
+
end
|
105
|
+
|
106
|
+
context 'setting the passsword' do
|
107
|
+
let(:config) { base_config.merge('password' => 'sekret') }
|
108
|
+
|
109
|
+
it 'uses the correct password' do
|
110
|
+
expect(IO).to receive(:popen) do |command|
|
111
|
+
expect(command).to include(' -psekret ')
|
112
|
+
end
|
113
|
+
end
|
114
|
+
end
|
115
|
+
end
|
116
|
+
|
117
|
+
describe 'host' do
|
118
|
+
context 'default' do
|
119
|
+
it 'uses localhost' do
|
120
|
+
expect(IO).to receive(:popen) do |command|
|
121
|
+
expect(command).to include(' -hlocalhost ')
|
122
|
+
end
|
123
|
+
end
|
124
|
+
end
|
125
|
+
|
126
|
+
context 'setting the host' do
|
127
|
+
let(:config) { base_config.merge('host' => 'db.awesome-server.net') }
|
128
|
+
|
129
|
+
it 'uses the correct hostname' do
|
130
|
+
expect(IO).to receive(:popen) do |command|
|
131
|
+
expect(command).to include(' -hdb.awesome-server.net ')
|
132
|
+
end
|
133
|
+
end
|
134
|
+
end
|
135
|
+
end
|
136
|
+
|
137
|
+
describe 'port' do
|
138
|
+
context 'default' do
|
139
|
+
it 'uses 3306' do
|
140
|
+
expect(IO).to receive(:popen) do |command|
|
141
|
+
expect(command).to include(' -P3306 ')
|
142
|
+
end
|
143
|
+
end
|
144
|
+
end
|
145
|
+
|
146
|
+
context 'setting the port' do
|
147
|
+
let(:config) { base_config.merge('port' => '4306') }
|
148
|
+
|
149
|
+
it 'uses the correct port' do
|
150
|
+
expect(IO).to receive(:popen) do |command|
|
151
|
+
expect(command).to include(' -P4306 ')
|
152
|
+
end
|
153
|
+
end
|
154
|
+
end
|
155
|
+
end
|
156
|
+
|
157
|
+
describe 'the dump command' do
|
158
|
+
it 'sets pipefail' do
|
159
|
+
expect(IO).to receive(:popen) do |command|
|
160
|
+
expect(command).to include("bash -c 'set -o pipefail;")
|
161
|
+
end
|
162
|
+
end
|
163
|
+
|
164
|
+
it 'uses mysqldump --single-transaction option to not lock tables' do
|
165
|
+
expect(IO).to receive(:popen) do |command|
|
166
|
+
expect(command).to include(' mysqldump --single-transaction ')
|
167
|
+
end
|
168
|
+
end
|
169
|
+
|
170
|
+
it 'pipes the output of mysql to gzip' do
|
171
|
+
expect(IO).to receive(:popen) do |command|
|
172
|
+
expect(command).to match(/.*mysqldump.*\| gzip/)
|
173
|
+
end
|
174
|
+
end
|
175
|
+
end
|
176
|
+
end
|
177
|
+
|
178
|
+
describe '#filename' do
|
179
|
+
it 'calculates a filename based on the name and timestamp' do
|
180
|
+
timestamp = Time.now.utc.strftime('%Y%m%d%H%M')
|
181
|
+
filename = "stratocumulus_test/stratocumulus_test.#{timestamp}.sql.gz"
|
182
|
+
expect(subject.filename).to eq filename
|
183
|
+
end
|
184
|
+
end
|
185
|
+
end
|
@@ -0,0 +1,57 @@
|
|
1
|
+
# encoding: UTF-8
|
2
|
+
require 'spec_helper'
|
3
|
+
|
4
|
+
describe Stratocumulus::Runner do
|
5
|
+
subject { described_class.new('spec/support/test_config_file.yml') }
|
6
|
+
let(:storage) { double(upload: true) }
|
7
|
+
let(:database) { double }
|
8
|
+
let(:database2) { double }
|
9
|
+
|
10
|
+
before do
|
11
|
+
allow(Stratocumulus::Storage).to receive(:new).and_return(storage)
|
12
|
+
end
|
13
|
+
|
14
|
+
after do
|
15
|
+
subject.run
|
16
|
+
end
|
17
|
+
|
18
|
+
it 'passes the correct config to Storage' do
|
19
|
+
expect(Stratocumulus::Storage).to receive(:new).once.with(
|
20
|
+
'access_key_id' => 'I_AM_THE_KEY_ID',
|
21
|
+
'secret_access_key' => 'IamTHESekret',
|
22
|
+
'bucket' => 'stratocumulus-test',
|
23
|
+
'region' => 'eu-west1'
|
24
|
+
).and_return(storage)
|
25
|
+
end
|
26
|
+
|
27
|
+
it 'passes each database config to instances of Database' do
|
28
|
+
expect(Stratocumulus::Database).to receive(:new).once.with(
|
29
|
+
'type' => 'mysql',
|
30
|
+
'name' => 'stratocumulus_test',
|
31
|
+
'storage' => 's3',
|
32
|
+
'username' => 'root',
|
33
|
+
'password' => 'sekret',
|
34
|
+
'host' => 'db1.example.com',
|
35
|
+
'port' => 3307
|
36
|
+
)
|
37
|
+
|
38
|
+
expect(Stratocumulus::Database).to receive(:new).once.with(
|
39
|
+
'type' => 'mysql',
|
40
|
+
'name' => 'stratocumulus_test_2',
|
41
|
+
'storage' => 's3'
|
42
|
+
)
|
43
|
+
end
|
44
|
+
|
45
|
+
it 'uploads each database to storage' do
|
46
|
+
allow(Stratocumulus::Database).to receive(:new).once.with(
|
47
|
+
hash_including('name' => 'stratocumulus_test')
|
48
|
+
).and_return(database)
|
49
|
+
|
50
|
+
allow(Stratocumulus::Database).to receive(:new).once.with(
|
51
|
+
hash_including('name' => 'stratocumulus_test_2')
|
52
|
+
).and_return(database2)
|
53
|
+
|
54
|
+
expect(storage).to receive(:upload).once.with(database)
|
55
|
+
expect(storage).to receive(:upload).once.with(database2)
|
56
|
+
end
|
57
|
+
end
|
@@ -0,0 +1,59 @@
|
|
1
|
+
# encoding: UTF-8
|
2
|
+
require 'spec_helper'
|
3
|
+
|
4
|
+
describe Stratocumulus::Storage do
|
5
|
+
let(:config) do
|
6
|
+
{
|
7
|
+
'access_key_id' => 'IM_A_ID',
|
8
|
+
'secret_access_key' => 'IM_A_SEKRET_KEY',
|
9
|
+
'region' => 'eu-west-1',
|
10
|
+
'bucket' => 'stratocumulus-test'
|
11
|
+
}
|
12
|
+
end
|
13
|
+
|
14
|
+
subject { described_class.new(config) }
|
15
|
+
|
16
|
+
describe '#upload' do
|
17
|
+
let(:connection) { double(:fog_conn, directories: directories) }
|
18
|
+
let(:directories) { double(:fog_dirs, get: double(files: files)) }
|
19
|
+
let(:files) { double(:fog_files, create: true) }
|
20
|
+
|
21
|
+
let(:database) do
|
22
|
+
double(:database, filename: 'foo.sql.gz', dump: :database_dump)
|
23
|
+
end
|
24
|
+
|
25
|
+
before do
|
26
|
+
allow(Fog::Storage).to receive(:new).and_return(connection)
|
27
|
+
end
|
28
|
+
|
29
|
+
after do
|
30
|
+
subject.upload(database)
|
31
|
+
end
|
32
|
+
|
33
|
+
it 'uploads the dump to s3' do
|
34
|
+
expect(files).to receive(:create).with(
|
35
|
+
key: 'foo.sql.gz',
|
36
|
+
body: :database_dump,
|
37
|
+
multipart_chunk_size: 104_857_600,
|
38
|
+
public: false
|
39
|
+
)
|
40
|
+
end
|
41
|
+
|
42
|
+
it 'uploads to the correct s3 bucket' do
|
43
|
+
expect(directories).to receive(:get).with('stratocumulus-test')
|
44
|
+
end
|
45
|
+
|
46
|
+
describe 'the fog connection' do
|
47
|
+
it 'is setup corectly' do
|
48
|
+
expect(Fog::Storage).to receive(:new)
|
49
|
+
.with(
|
50
|
+
provider: 'AWS',
|
51
|
+
aws_access_key_id: 'IM_A_ID',
|
52
|
+
aws_secret_access_key: 'IM_A_SEKRET_KEY',
|
53
|
+
region: 'eu-west-1'
|
54
|
+
).and_return(connection)
|
55
|
+
end
|
56
|
+
end
|
57
|
+
end
|
58
|
+
|
59
|
+
end
|
@@ -0,0 +1,26 @@
|
|
1
|
+
# coding: utf-8
|
2
|
+
lib = File.expand_path('../lib', __FILE__)
|
3
|
+
$LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
|
4
|
+
require 'stratocumulus/version'
|
5
|
+
|
6
|
+
Gem::Specification.new do |spec|
|
7
|
+
spec.name = 'stratocumulus'
|
8
|
+
spec.version = Stratocumulus::VERSION
|
9
|
+
spec.authors = ['Ed Robinson']
|
10
|
+
spec.email = ['ed.robinson@reevoo.com']
|
11
|
+
spec.summary = %q(Backup Databases to Cloud Storage)
|
12
|
+
spec.description = %q(Backup Databases to Cloud Storage)
|
13
|
+
spec.homepage = 'https://github.com/reevoo/stratocumulus'
|
14
|
+
spec.license = 'MIT'
|
15
|
+
|
16
|
+
spec.files = `git ls-files -z`.split("\x0")
|
17
|
+
spec.executables = ['stratocumulus']
|
18
|
+
spec.test_files = spec.files.grep(/^(test|spec|features)\//)
|
19
|
+
spec.require_paths = ['lib']
|
20
|
+
|
21
|
+
spec.add_dependency 'fog', '~> 1.22'
|
22
|
+
spec.add_development_dependency 'bundler', '~> 1.5'
|
23
|
+
spec.add_development_dependency 'rake'
|
24
|
+
spec.add_development_dependency 'rubocop'
|
25
|
+
spec.add_development_dependency 'rspec', '~> 3.0'
|
26
|
+
end
|
metadata
ADDED
@@ -0,0 +1,165 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: stratocumulus
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.0.1
|
5
|
+
prerelease:
|
6
|
+
platform: ruby
|
7
|
+
authors:
|
8
|
+
- Ed Robinson
|
9
|
+
autorequire:
|
10
|
+
bindir: bin
|
11
|
+
cert_chain: []
|
12
|
+
date: 2014-06-17 00:00:00.000000000 Z
|
13
|
+
dependencies:
|
14
|
+
- !ruby/object:Gem::Dependency
|
15
|
+
name: fog
|
16
|
+
requirement: !ruby/object:Gem::Requirement
|
17
|
+
none: false
|
18
|
+
requirements:
|
19
|
+
- - ~>
|
20
|
+
- !ruby/object:Gem::Version
|
21
|
+
version: '1.22'
|
22
|
+
type: :runtime
|
23
|
+
prerelease: false
|
24
|
+
version_requirements: !ruby/object:Gem::Requirement
|
25
|
+
none: false
|
26
|
+
requirements:
|
27
|
+
- - ~>
|
28
|
+
- !ruby/object:Gem::Version
|
29
|
+
version: '1.22'
|
30
|
+
- !ruby/object:Gem::Dependency
|
31
|
+
name: bundler
|
32
|
+
requirement: !ruby/object:Gem::Requirement
|
33
|
+
none: false
|
34
|
+
requirements:
|
35
|
+
- - ~>
|
36
|
+
- !ruby/object:Gem::Version
|
37
|
+
version: '1.5'
|
38
|
+
type: :development
|
39
|
+
prerelease: false
|
40
|
+
version_requirements: !ruby/object:Gem::Requirement
|
41
|
+
none: false
|
42
|
+
requirements:
|
43
|
+
- - ~>
|
44
|
+
- !ruby/object:Gem::Version
|
45
|
+
version: '1.5'
|
46
|
+
- !ruby/object:Gem::Dependency
|
47
|
+
name: rake
|
48
|
+
requirement: !ruby/object:Gem::Requirement
|
49
|
+
none: false
|
50
|
+
requirements:
|
51
|
+
- - ! '>='
|
52
|
+
- !ruby/object:Gem::Version
|
53
|
+
version: '0'
|
54
|
+
type: :development
|
55
|
+
prerelease: false
|
56
|
+
version_requirements: !ruby/object:Gem::Requirement
|
57
|
+
none: false
|
58
|
+
requirements:
|
59
|
+
- - ! '>='
|
60
|
+
- !ruby/object:Gem::Version
|
61
|
+
version: '0'
|
62
|
+
- !ruby/object:Gem::Dependency
|
63
|
+
name: rubocop
|
64
|
+
requirement: !ruby/object:Gem::Requirement
|
65
|
+
none: false
|
66
|
+
requirements:
|
67
|
+
- - ! '>='
|
68
|
+
- !ruby/object:Gem::Version
|
69
|
+
version: '0'
|
70
|
+
type: :development
|
71
|
+
prerelease: false
|
72
|
+
version_requirements: !ruby/object:Gem::Requirement
|
73
|
+
none: false
|
74
|
+
requirements:
|
75
|
+
- - ! '>='
|
76
|
+
- !ruby/object:Gem::Version
|
77
|
+
version: '0'
|
78
|
+
- !ruby/object:Gem::Dependency
|
79
|
+
name: rspec
|
80
|
+
requirement: !ruby/object:Gem::Requirement
|
81
|
+
none: false
|
82
|
+
requirements:
|
83
|
+
- - ~>
|
84
|
+
- !ruby/object:Gem::Version
|
85
|
+
version: '3.0'
|
86
|
+
type: :development
|
87
|
+
prerelease: false
|
88
|
+
version_requirements: !ruby/object:Gem::Requirement
|
89
|
+
none: false
|
90
|
+
requirements:
|
91
|
+
- - ~>
|
92
|
+
- !ruby/object:Gem::Version
|
93
|
+
version: '3.0'
|
94
|
+
description: Backup Databases to Cloud Storage
|
95
|
+
email:
|
96
|
+
- ed.robinson@reevoo.com
|
97
|
+
executables:
|
98
|
+
- stratocumulus
|
99
|
+
extensions: []
|
100
|
+
extra_rdoc_files: []
|
101
|
+
files:
|
102
|
+
- .gitignore
|
103
|
+
- .rspec
|
104
|
+
- .rubocop.yml
|
105
|
+
- .travis.yml
|
106
|
+
- Gemfile
|
107
|
+
- LICENSE.txt
|
108
|
+
- README.md
|
109
|
+
- Rakefile
|
110
|
+
- bin/stratocumulus
|
111
|
+
- lib/stratocumulus.rb
|
112
|
+
- lib/stratocumulus/database.rb
|
113
|
+
- lib/stratocumulus/ext/io.rb
|
114
|
+
- lib/stratocumulus/runner.rb
|
115
|
+
- lib/stratocumulus/storage.rb
|
116
|
+
- lib/stratocumulus/version.rb
|
117
|
+
- spec/ext/io_spec.rb
|
118
|
+
- spec/intergration/database_spec.rb
|
119
|
+
- spec/spec_helper.rb
|
120
|
+
- spec/support/test.sql
|
121
|
+
- spec/support/test_config_file.yml
|
122
|
+
- spec/unit/database_spec.rb
|
123
|
+
- spec/unit/runner_spec.rb
|
124
|
+
- spec/unit/storage_spec.rb
|
125
|
+
- stratocumulus.gemspec
|
126
|
+
homepage: https://github.com/reevoo/stratocumulus
|
127
|
+
licenses:
|
128
|
+
- MIT
|
129
|
+
post_install_message:
|
130
|
+
rdoc_options: []
|
131
|
+
require_paths:
|
132
|
+
- lib
|
133
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
134
|
+
none: false
|
135
|
+
requirements:
|
136
|
+
- - ! '>='
|
137
|
+
- !ruby/object:Gem::Version
|
138
|
+
version: '0'
|
139
|
+
segments:
|
140
|
+
- 0
|
141
|
+
hash: 138837949787604708
|
142
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
143
|
+
none: false
|
144
|
+
requirements:
|
145
|
+
- - ! '>='
|
146
|
+
- !ruby/object:Gem::Version
|
147
|
+
version: '0'
|
148
|
+
segments:
|
149
|
+
- 0
|
150
|
+
hash: 138837949787604708
|
151
|
+
requirements: []
|
152
|
+
rubyforge_project:
|
153
|
+
rubygems_version: 1.8.25
|
154
|
+
signing_key:
|
155
|
+
specification_version: 3
|
156
|
+
summary: Backup Databases to Cloud Storage
|
157
|
+
test_files:
|
158
|
+
- spec/ext/io_spec.rb
|
159
|
+
- spec/intergration/database_spec.rb
|
160
|
+
- spec/spec_helper.rb
|
161
|
+
- spec/support/test.sql
|
162
|
+
- spec/support/test_config_file.yml
|
163
|
+
- spec/unit/database_spec.rb
|
164
|
+
- spec/unit/runner_spec.rb
|
165
|
+
- spec/unit/storage_spec.rb
|