stratocumulus 0.0.5 → 0.0.6

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.
@@ -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