stratocumulus 0.0.5 → 0.0.6

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: 9965a838bed237de0515bd6dbaed0a4009e5ff24
4
+ data.tar.gz: 5f34c3f98ca10c2dd5c335cd94cc25905df29095
5
+ SHA512:
6
+ metadata.gz: b0c6d21032652a73f2719328eef431173ee94b5bfffc43d6b2ef49f793b2235659fba797e6faaf4126cb3908cc4b17fe7f923777b5876d90c9e0af6385416f97
7
+ data.tar.gz: 4bd5f54807f63d56a86ef91d531b7fdfc7f576e8698d33dab36e2fba65df7e571c7bf9692db30c4da3b97337a1a9fed6fddba139ae56e30d65b01268d23c024a
@@ -1,15 +1,10 @@
1
1
  language: ruby
2
2
  rvm:
3
- - 2.1.2
4
- - 2.0.0
5
- - 1.9.3
6
- before_install:
7
- - source /etc/lsb-release && echo "deb http://download.rethinkdb.com/apt $DISTRIB_CODENAME main" | sudo tee /etc/apt/sources.list.d/rethinkdb.list
8
- - wget -O- http://download.rethinkdb.com/apt/pubkey.gpg | sudo apt-key add -
9
- - sudo apt-get update -qq
10
- install:
11
- - sudo apt-get install -y rethinkdb
12
- - sudo pip install rethinkdb
13
- - sudo cp /etc/rethinkdb/default.conf.sample /etc/rethinkdb/instances.d/instance1.conf
14
- - sudo /etc/init.d/rethinkdb restart
15
- - bundle install
3
+ - 2.3.0
4
+ - 2.2.4
5
+ - 2.1.8
6
+ env: CODECLIMATE_REPO_TOKEN=650676b7530bf62fce4284e263272a8dcab015f4f34fe6dab251ead2ea6b4813
7
+ sudo: false
8
+ services:
9
+ - mysql
10
+ - postgresql
data/Gemfile CHANGED
@@ -1,4 +1,4 @@
1
- source 'https://rubygems.org'
1
+ source "https://rubygems.org"
2
2
 
3
3
  # Specify your gem's dependencies in stratocumulus.gemspec
4
4
  gemspec
data/README.md CHANGED
@@ -1,7 +1,7 @@
1
1
  # Stratocumulus
2
2
  [![Build Status](https://travis-ci.org/reevoo/stratocumulus.svg?branch=master)](https://travis-ci.org/reevoo/stratocumulus)
3
- [![Coverage Status](https://coveralls.io/repos/reevoo/stratocumulus/badge.png)](https://coveralls.io/r/reevoo/stratocumulus)
4
- [![Code Climate](https://codeclimate.com/github/reevoo/stratocumulus.png)](https://codeclimate.com/github/reevoo/stratocumulus)
3
+ [![Test Coverage](https://codeclimate.com/github/reevoo/stratocumulus/badges/coverage.svg)](https://codeclimate.com/github/reevoo/stratocumulus)
4
+ [![Code Climate](https://codeclimate.com/github/reevoo/stratocumulus/badges/gpa.svg)](https://codeclimate.com/github/reevoo/stratocumulus)
5
5
  [![Gem Version](https://badge.fury.io/rb/stratocumulus.svg)](http://badge.fury.io/rb/stratocumulus)
6
6
 
7
7
 
@@ -20,6 +20,7 @@ s3:
20
20
  access_key_id: KEY_ID
21
21
  secret_access_key: SECRET_KEY
22
22
  bucket: database-backups
23
+ folder: staging # optional
23
24
  region: eu-west-1 # defaults to us-east-1
24
25
  databases:
25
26
  -
data/Rakefile CHANGED
@@ -1,9 +1,9 @@
1
1
  # encoding: UTF-8
2
- require 'bundler/gem_tasks'
3
- require 'rubocop/rake_task'
4
- require 'rspec/core/rake_task'
2
+ require "bundler/gem_tasks"
3
+ require "reevoocop/rake_task"
4
+ require "rspec/core/rake_task"
5
5
 
6
- RuboCop::RakeTask.new
6
+ ReevooCop::RakeTask.new(:reevoocop)
7
7
  RSpec::Core::RakeTask.new(:spec)
8
8
 
9
- task default: [:spec, :rubocop]
9
+ task default: [:spec, :reevoocop]
@@ -1,5 +1,5 @@
1
1
  #!/usr/bin/env ruby
2
2
  # encoding: UTF-8
3
- require 'stratocumulus'
3
+ require "stratocumulus"
4
4
 
5
5
  Stratocumulus::Cli.start
@@ -1,7 +1,7 @@
1
1
  # encoding: UTF-8
2
- require 'stratocumulus/version'
3
- require 'stratocumulus/database'
4
- require 'stratocumulus/storage'
5
- require 'stratocumulus/runner'
6
- require 'stratocumulus/retention'
7
- require 'stratocumulus/cli'
2
+ require "stratocumulus/version"
3
+ require "stratocumulus/database"
4
+ require "stratocumulus/storage"
5
+ require "stratocumulus/runner"
6
+ require "stratocumulus/retention"
7
+ require "stratocumulus/cli"
@@ -1,10 +1,10 @@
1
1
  # encoding: UTF-8
2
- require 'thor'
2
+ require "thor"
3
3
 
4
4
  module Stratocumulus
5
5
  class Cli < Thor
6
- desc 'backup CONFIG',
7
- 'runs a stratocumulus backup as specified in the config file'
6
+ desc "backup CONFIG",
7
+ "runs a stratocumulus backup as specified in the config file"
8
8
  def backup(config)
9
9
  Stratocumulus::Runner.new(config).run
10
10
  end
@@ -1,34 +1,32 @@
1
1
  # encoding: UTF-8
2
- require 'stratocumulus/database/pipe_io'
3
- require 'stratocumulus/database/mysql'
4
- require 'stratocumulus/database/postgresql'
5
- require 'stratocumulus/database/rethinkdb'
6
- require 'English'
2
+ require "stratocumulus/database/pipe_io"
3
+ require "stratocumulus/database/mysql"
4
+ require "stratocumulus/database/postgresql"
5
+ require "English"
7
6
 
8
7
  module Stratocumulus
9
8
  class Database
10
9
  def self.build(options = {})
11
- backend_class = backends[options['type']]
12
- fail "#{options['type']} is not a supported database" unless backend_class
10
+ backend_class = backends[options["type"]]
11
+ fail "#{options["type"]} is not a supported database" unless backend_class
13
12
  backend_class.new(options)
14
13
  end
15
14
 
16
15
  def self.backends
17
16
  {
18
- 'psql' => PostgreSQL,
19
- 'mysql' => MySQL,
20
- 'rethinkdb' => RethinkDB
17
+ "psql" => PostgreSQL,
18
+ "mysql" => MySQL,
21
19
  }
22
20
  end
23
21
 
24
22
  def initialize(options = {})
25
23
  check_dependencies
26
- @username = options['username']
27
- @password = options['password']
28
- @name = options['name']
29
- fail 'database name not specified' unless @name
30
- @host = options['host']
31
- @port = options['port']
24
+ @username = options["username"]
25
+ @password = options["password"]
26
+ @name = options["name"]
27
+ fail "database name not specified" unless @name
28
+ @host = options["host"]
29
+ @port = options["port"]
32
30
  end
33
31
 
34
32
  def dump
@@ -36,7 +34,7 @@ module Stratocumulus
36
34
  end
37
35
 
38
36
  def filename
39
- @name + '/' + file
37
+ @name + "/" + file
40
38
  end
41
39
 
42
40
  def success?
@@ -46,7 +44,7 @@ module Stratocumulus
46
44
  end
47
45
 
48
46
  def dependencies
49
- ['gzip']
47
+ ["gzip"]
50
48
  end
51
49
 
52
50
  private
@@ -62,11 +60,11 @@ module Stratocumulus
62
60
  end
63
61
 
64
62
  def suffix
65
- '.sql.gz'
63
+ ".sql.gz"
66
64
  end
67
65
 
68
66
  def pipefail
69
- 'set -o pipefail;'
67
+ "set -o pipefail;"
70
68
  end
71
69
 
72
70
  def socket?
@@ -1,11 +1,11 @@
1
1
  # encoding: UTF-8
2
- require 'stratocumulus/database'
2
+ require "stratocumulus/database"
3
3
 
4
4
  module Stratocumulus
5
5
  class MySQL < Database
6
6
  def command
7
- command = 'mysqldump '
8
- command << '--single-transaction '
7
+ command = "mysqldump "
8
+ command << "--single-transaction "
9
9
  command << "-u#{username} "
10
10
  command << "-h#{host} " unless socket?
11
11
  command << "-P#{port} " unless socket?
@@ -14,17 +14,17 @@ module Stratocumulus
14
14
  end
15
15
 
16
16
  def dependencies
17
- super + ['mysqldump']
17
+ super + ["mysqldump"]
18
18
  end
19
19
 
20
20
  private
21
21
 
22
22
  def username
23
- @username || 'root'
23
+ @username || "root"
24
24
  end
25
25
 
26
26
  def host
27
- @host || 'localhost'
27
+ @host || "localhost"
28
28
  end
29
29
 
30
30
  def port
@@ -1,9 +1,9 @@
1
1
  # encoding: UTF-8
2
2
 
3
- # Rewind is undefined so fog won't try to call rewind on a pipe
4
3
 
5
4
  module Stratocumulus
6
5
  class Database
6
+ # #rewind is undefined so fog won't try to call rewind on a pipe
7
7
  class PipeIO < IO
8
8
  undef rewind
9
9
  end
@@ -1,12 +1,12 @@
1
1
  # encoding: UTF-8
2
- require 'stratocumulus/database'
2
+ require "stratocumulus/database"
3
3
 
4
4
  module Stratocumulus
5
5
  class PostgreSQL < Database
6
6
  def command
7
- command = ''
8
- command << %Q(PGPASSWORD="#{@password}" ) if @password
9
- command << 'pg_dump '
7
+ command = ""
8
+ command << %(PGPASSWORD="#{@password}" ) if @password
9
+ command << "pg_dump "
10
10
  command << "-U#{username} "
11
11
  command << "-h#{host} " unless socket?
12
12
  command << "-p#{port} " unless socket?
@@ -14,17 +14,17 @@ module Stratocumulus
14
14
  end
15
15
 
16
16
  def dependencies
17
- super + ['pg_dump']
17
+ super + ["pg_dump"]
18
18
  end
19
19
 
20
20
  private
21
21
 
22
22
  def username
23
- @username || 'postgres'
23
+ @username || "postgres"
24
24
  end
25
25
 
26
26
  def host
27
- @host || 'localhost'
27
+ @host || "localhost"
28
28
  end
29
29
 
30
30
  def port
@@ -10,10 +10,10 @@ module Stratocumulus
10
10
  return unless expires_in_days
11
11
 
12
12
  {
13
- 'ID' => key,
14
- 'Prefix' => key,
15
- 'Enabled' => true,
16
- 'Days' => expires_in_days
13
+ "ID" => key,
14
+ "Prefix" => key,
15
+ "Enabled" => true,
16
+ "Days" => expires_in_days,
17
17
  }
18
18
  end
19
19
 
@@ -7,21 +7,21 @@ module Stratocumulus
7
7
  end
8
8
 
9
9
  def run
10
- @config['databases'].each do |database_config|
10
+ @config["databases"].each do |database_config|
11
11
  database = Database.build(database_config)
12
- upload(database, database_config['storage'])
12
+ upload(database, database_config["storage"])
13
13
  end
14
14
  end
15
15
 
16
16
  private
17
17
 
18
18
  def upload(database, storage_type)
19
- fail "#{storage_type} is not supported" unless storage_type == 's3'
19
+ fail "#{storage_type} is not supported" unless storage_type == "s3"
20
20
  storage.upload(database)
21
21
  end
22
22
 
23
23
  def storage
24
- Storage.new(@config['s3'])
24
+ Storage.new(@config["s3"])
25
25
  end
26
26
  end
27
27
  end
@@ -1,22 +1,23 @@
1
1
  # encoding: UTF-8
2
- require 'fog'
3
- require 'logger'
2
+ require "fog/aws"
3
+ require "logger"
4
4
 
5
5
  module Stratocumulus
6
6
  class Storage
7
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
- @retention = Retention.new(options['retention'])
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
+ @folder = options["folder"]
13
+ @retention = Retention.new(options["retention"])
13
14
  end
14
15
 
15
16
  def upload(database)
16
17
  return unless @retention.upload_today?
17
18
  file = store_file(database)
18
19
  if database.success?
19
- add_expiry_rule(database.filename)
20
+ add_expiry_rule(destination_path(database.filename))
20
21
  else
21
22
  log.error("there was an error generating #{database.filename}")
22
23
  file.destroy
@@ -27,19 +28,23 @@ module Stratocumulus
27
28
 
28
29
  def store_file(database)
29
30
  files.create(
30
- key: database.filename,
31
+ key: destination_path(database.filename),
31
32
  body: database.dump,
32
33
  multipart_chunk_size: 104_857_600, # 100MB
33
- public: false
34
+ public: false,
34
35
  )
35
36
  end
36
37
 
38
+ def destination_path(filename)
39
+ @folder.nil? ? filename : @folder + "/" + filename
40
+ end
41
+
37
42
  def connection
38
43
  Fog::Storage.new(
39
- provider: 'AWS',
44
+ provider: "AWS",
40
45
  aws_access_key_id: @access_key_id,
41
46
  aws_secret_access_key: @secret_access_key,
42
- region: @region
47
+ region: @region,
43
48
  )
44
49
  end
45
50
 
@@ -56,18 +61,18 @@ module Stratocumulus
56
61
  return unless new_rule
57
62
  directories.service.put_bucket_lifecycle(
58
63
  @bucket,
59
- 'Rules' => current_rules << new_rule
64
+ "Rules" => current_rules << new_rule,
60
65
  )
61
66
  end
62
67
 
63
68
  def current_rules
64
69
  existing_rules.select do |rule|
65
- files.find { |file| file.key == rule['ID'] }
70
+ files.find { |file| file.key == rule["ID"] }
66
71
  end
67
72
  end
68
73
 
69
74
  def existing_rules
70
- directories.service.get_bucket_lifecycle(@bucket).data[:body]['Rules']
75
+ directories.service.get_bucket_lifecycle(@bucket).data[:body]["Rules"]
71
76
  rescue Excon::Errors::NotFound
72
77
  []
73
78
  end
@@ -1,4 +1,4 @@
1
1
  # encoding: UTF-8
2
2
  module Stratocumulus
3
- VERSION = '0.0.5'
3
+ VERSION = "0.0.6"
4
4
  end
@@ -1,93 +1,50 @@
1
1
  # encoding: UTF-8
2
- require 'spec_helper'
3
- require 'zlib'
4
- require 'rubygems/package'
2
+ require "spec_helper"
3
+ require "zlib"
4
+ require "rubygems/package"
5
5
 
6
6
  describe Stratocumulus::Database do
7
-
8
7
  subject do
9
8
  described_class.build(config)
10
9
  end
11
10
 
12
- let('config') do
11
+ let("config") do
13
12
  {
14
- 'name' => 'stratocumulus_test',
15
- 'type' => type
13
+ "name" => "stratocumulus_test",
14
+ "type" => type,
16
15
  }
17
16
  end
18
17
 
19
18
  let(:dump) { Zlib::GzipReader.new(subject.dump).read }
20
19
 
21
- describe '#dump' do
22
- context 'MySQL' do
20
+ describe "#dump" do
21
+ context "MySQL" do
23
22
  before do
24
23
  `mysql -u root < spec/support/mysql.sql`
25
24
  end
26
25
 
27
- let(:type) { 'mysql' }
26
+ let(:type) { "mysql" }
28
27
 
29
- it 'sucessfully dumps a gziped copy of the database' do
30
- expect(dump).to include('CREATE TABLE `widgets`')
28
+ it "sucessfully dumps a gziped copy of the database" do
29
+ expect(dump).to include("CREATE TABLE `widgets`")
31
30
  expect(dump).to include("INSERT INTO `widgets` VALUES (1,'Foo',3,1,2)")
32
31
  expect(subject).to be_success
33
32
  end
34
33
  end
35
34
 
36
- context 'PostgreSQL' do
35
+ context "PostgreSQL" do
37
36
  before do
38
37
  `psql -U postgres < spec/support/psql.sql`
39
38
  end
40
39
 
41
- let(:type) { 'psql' }
40
+ let(:type) { "psql" }
42
41
 
43
- it 'sucessfully dumps a gziped copy of the database' do
44
- expect(dump).to include('CREATE TABLE widgets')
42
+ it "sucessfully dumps a gziped copy of the database" do
43
+ expect(dump).to include("CREATE TABLE widgets")
45
44
  expect(dump).to include(
46
- 'COPY widgets (id, name, leavers, pivots, fulcrums) FROM stdin;'
45
+ "COPY widgets (id, name, leavers, pivots, fulcrums) FROM stdin;",
47
46
  )
48
- expect(dump).to include('1 Foo 3 1 2')
49
- expect(subject).to be_success
50
- end
51
- end
52
-
53
- context 'RethinkDB' do
54
- before do
55
- `rethinkdb restore --force spec/support/rethinkdb.tar.gz`
56
- end
57
-
58
- let(:type) { 'rethinkdb' }
59
-
60
- let(:tarball) { Zlib::GzipReader.new(subject.dump) }
61
-
62
- let(:dump) do
63
- Gem::Package::TarReader.new(tarball).each do |tarfile|
64
- next unless tarfile.full_name =~ /widgets.json/
65
- return JSON.load(tarfile.read)
66
- end
67
- end
68
-
69
- let(:expected_data) do
70
- [
71
- # rubocop:disable Style/LineLength
72
- { 'pivots' => 5, 'fulcrums' => 3, 'leavers' => 8, 'id' => '1c66308d-492e-48ee-bfc5-83de96a15236', 'name' => 'Plugh' },
73
- { 'pivots' => 2, 'fulcrums' => 3, 'leavers' => 1, 'id' => '224ba4b1-2184-4905-b81b-ac6368480f43', 'name' => 'Thud' },
74
- { 'pivots' => 2, 'fulcrums' => 3, 'leavers' => 1, 'id' => '25b68062-7e9f-4fca-92bf-672287961096', 'name' => 'Garply' },
75
- { 'pivots' => 1, 'fulcrums' => 2, 'leavers' => 3, 'id' => '380c2a12-62d8-4faa-968e-79b2919bf9ad', 'name' => 'Foo' },
76
- { 'pivots' => 5, 'fulcrums' => 4, 'leavers' => 8, 'id' => '46cd4d4a-2cca-4ae2-835e-19c94c53ce02', 'name' => 'Quux' },
77
- { 'pivots' => 2, 'fulcrums' => 7, 'leavers' => 8, 'id' => '63441f79-cfe4-4460-8fc7-bda802e93646', 'name' => 'Corge' },
78
- { 'pivots' => 3, 'fulcrums' => 4, 'leavers' => 7, 'id' => '7d83f209-b4b1-4463-9eec-42dbf9217a39', 'name' => 'Grault' },
79
- { 'pivots' => 5, 'fulcrums' => 6, 'leavers' => 4, 'id' => '8e1623c8-e28d-48f9-8d74-dc5bf459cff5', 'name' => 'Qux' },
80
- { 'pivots' => 2, 'fulcrums' => 0, 'leavers' => 2, 'id' => 'a59c4505-c078-4186-a1d5-b0120dba4aa1', 'name' => 'Bar' },
81
- { 'pivots' => 3, 'fulcrums' => 3, 'leavers' => 3, 'id' => 'b535529c-c822-4c08-af65-f3662d981046', 'name' => 'Xyzzy' },
82
- { 'pivots' => 0, 'fulcrums' => 0, 'leavers' => 0, 'id' => 'f47bcc2a-ae2a-4d5f-9bbf-df71c8d81a7a', 'name' => 'Waldo' },
83
- { 'pivots' => 6, 'fulcrums' => 4, 'leavers' => 5, 'id' => 'f6745b27-b0c8-40ca-a472-dbe45310ee19', 'name' => 'Baz' },
84
- { 'pivots' => 1, 'fulcrums' => 1, 'leavers' => 1, 'id' => 'f88a0196-faaa-4695-88f1-808555a68ffa', 'name' => 'Fred' }
85
- # rubocop:enable Style/LineLength
86
- ]
87
- end
88
-
89
- it 'sucessfully dumps a gziped copy of the database' do
90
- expect(dump).to eq expected_data
47
+ expect(dump).to include("1 Foo 3 1 2")
91
48
  expect(subject).to be_success
92
49
  end
93
50
  end